X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fgraphics%2FGraphicsLoader.C;h=f78bcd7f89dd73e049d997128f6ca4837ded1a6e;hb=3aa7e91a827fa15b3e0906b975c4755a2dcdb76d;hp=d0c582ce06f2e5b49f407fbe8983b570416d198f;hpb=a31eb3b2df2ceb8c02d69cc59c75aa7e1d457978;p=lyx.git diff --git a/src/graphics/GraphicsLoader.C b/src/graphics/GraphicsLoader.C index d0c582ce06..f78bcd7f89 100644 --- a/src/graphics/GraphicsLoader.C +++ b/src/graphics/GraphicsLoader.C @@ -1,9 +1,10 @@ -/* +/** * \file GraphicsLoader.C - * Copyright 2002 the LyX Team * Read the file COPYING * - * \author Angus Leeming + * \author Angus Leeming + * + * Full author contact details available in file CREDITS */ #include @@ -13,206 +14,339 @@ #endif #include "GraphicsLoader.h" + +#include "BufferView.h" + #include "GraphicsCache.h" #include "GraphicsCacheItem.h" #include "GraphicsImage.h" #include "GraphicsParams.h" +#include "GraphicsSupport.h" +#include "frontends/LyXView.h" +#include "frontends/Timeout.h" + +#include #include +#include + +#include namespace grfx { -struct Loader::Impl { +struct Loader::Impl : boost::signals::trackable { /// - Impl(Loader &, GParams const &); + Impl(Params const &); /// ~Impl(); /// - void setFile(string const & file); + void resetFile(string const &); /// - void unsetOldFile(); + void resetParams(Params const &); /// void createPixmap(); - /// - void statusChanged(); /// - Loader & parent_; + void startLoading(Inset const &, BufferView const &); + /// The loading status of the image. ImageStatus status_; /** Must store a copy of the cached item to ensure that it is not * erased unexpectedly by the cache itself. */ - GraphicPtr graphic_; - /// - GParams params_; + Cache::ItemPtr cached_item_; /// We modify a local copy of the image once it is loaded. - ImagePtr image_; + Image::ImagePtr image_; + /// This signal is emitted when the image loading status changes. + boost::signal0 signal_; + +private: + /// + void statusChanged(); + /// + void checkedLoading(); + + /// + Params params_; + + /// + Timeout timer; + // Multiple Insets can share the same image + typedef std::list InsetList; + /// + InsetList insets; + /// + boost::weak_ptr view; }; -Loader::Impl::Impl(Loader & parent, GParams const & params) - : parent_(parent), status_(WaitingToLoad), params_(params) +Loader::Loader() + : pimpl_(new Impl(Params())) {} -Loader::Impl::~Impl() +Loader::Loader(string const & file, DisplayType type) + : pimpl_(new Impl(Params())) { - unsetOldFile(); + reset(file, type); } -void Loader::Impl::setFile(string const & file) +Loader::Loader(string const & file, Params const & params) + : pimpl_(new Impl(params)) { - if (file.empty()) - return; + reset(file, params); +} - GCache & gc = GCache::get(); - if (!gc.inCache(file)) - gc.add(file); - // We /must/ make a local copy of this. - graphic_ = gc.graphic(file); - status_ = graphic_->status(); +Loader::~Loader() +{} - if (status_ == Loaded) { - createPixmap(); - } - // It's easiest to do this without checking - parent_.statusChanged(); +void Loader::reset(string const & file, DisplayType type) const +{ + Params params; + params.display = type; + pimpl_->resetParams(params); + + pimpl_->resetFile(file); + pimpl_->createPixmap(); } -void Loader::Impl::unsetOldFile() +void Loader::reset(string const & file, Params const & params) const { - if (!graphic_.get()) - return; + pimpl_->resetParams(params); + pimpl_->resetFile(file); + pimpl_->createPixmap(); +} - string const old_file = graphic_->filename(); - graphic_.reset(); - GCache::get().remove(old_file); - status_ = WaitingToLoad; - params_ = GParams(); - image_.reset(); +void Loader::reset(Params const & params) const +{ + pimpl_->resetParams(params); + pimpl_->createPixmap(); } -void Loader::Impl::statusChanged() +void Loader::startLoading() const { - status_ = graphic_->status(); - if (status_ == Loaded) - createPixmap(); + if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get()) + return; + pimpl_->cached_item_->startLoading(); +} + - parent_.statusChanged(); +void Loader::startLoading(Inset const & inset, BufferView const & bv) const +{ + if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get()) + return; + pimpl_->startLoading(inset, bv); } -void Loader::Impl::createPixmap() +void Loader::startMonitoring() const { - if (!graphic_.get() || image_.get() || - params_.display == NoDisplay || status_ != Loaded) + if (!pimpl_->cached_item_.get()) return; - image_.reset(graphic_->image()->clone()); + pimpl_->cached_item_->startMonitoring(); +} - // These do nothing if there's nothing to do - image_->clip(params_); - image_->rotate(params_); - image_->scale(params_); - bool const success = image_->setPixmap(params_); +bool Loader::monitoring() const +{ + if (!pimpl_->cached_item_.get()) + return false; - if (success) { - status_ = Ready; - } else { - image_.reset(); - status_ = ErrorGeneratingPixmap; - } + return pimpl_->cached_item_->monitoring(); } -Loader::Loader() - : pimpl_(new Impl(*this, GParams())) -{} +unsigned long Loader::checksum() const +{ + if (!pimpl_->cached_item_.get()) + return 0; + return pimpl_->cached_item_->checksum(); +} -Loader::Loader(string const & file, DisplayType type) - : pimpl_(new Impl(*this, GParams())) + +string const & Loader::filename() const { - pimpl_->params_.display = type; - pimpl_->setFile(file); + static string const empty; + return pimpl_->cached_item_.get() ? + pimpl_->cached_item_->filename() : empty; } -Loader::Loader(string const & file, GParams const & params) - : pimpl_(new Impl(*this, params)) +ImageStatus Loader::status() const { - pimpl_->setFile(file); + return pimpl_->status_; } -Loader::~Loader() -{} +boost::signals::connection Loader::connect(slot_type const & slot) const +{ + return pimpl_->signal_.connect(slot); +} -void Loader::reset(string const & file, DisplayType type) +Image const * Loader::image() const { - pimpl_->unsetOldFile(); - - pimpl_->params_ = GParams(); - pimpl_->params_.display = type; - pimpl_->setFile(file); + return pimpl_->image_.get(); } -void Loader::reset(string const & file, GParams const & params) +Loader::Impl::Impl(Params const & params) + : status_(WaitingToLoad), params_(params), + timer(2000, Timeout::ONETIME) { - pimpl_->unsetOldFile(); + timer.timeout.connect(boost::bind(&Impl::checkedLoading, this)); +} + - pimpl_->params_ = params; - pimpl_->setFile(file); +Loader::Impl::~Impl() +{ + resetFile(string()); } -void Loader::reset(GParams const & params) +void Loader::Impl::resetFile(string const & file) { - pimpl_->params_ = params; + string const old_file = cached_item_.get() ? + cached_item_->filename() : string(); + + if (file == old_file) + return; - if (pimpl_->status_ == Loaded) - pimpl_->createPixmap(); + // If monitoring() the current file, should continue to monitor the + // new file. + bool continue_monitoring = false; + + if (!old_file.empty()) { + continue_monitoring = cached_item_->monitoring(); + cached_item_.reset(); + Cache::get().remove(old_file); + } + + status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; + image_.reset(); + + if (cached_item_.get() || file.empty()) + return; + + Cache & gc = Cache::get(); + if (!gc.inCache(file)) + gc.add(file); + + // We /must/ make a local copy of this. + cached_item_ = gc.item(file); + status_ = cached_item_->status(); + + if (continue_monitoring && !cached_item_->monitoring()) + cached_item_->startMonitoring(); + + cached_item_->connect(boost::bind(&Impl::statusChanged, this)); } -void Loader::startLoading() +void Loader::Impl::resetParams(Params const & params) { - if (pimpl_->status_ != WaitingToLoad || !pimpl_->graphic_.get()) + if (params == params_) return; - pimpl_->graphic_->statusChanged.connect( - boost::bind(&Loader::Impl::statusChanged, - pimpl_.get())); - pimpl_->graphic_->startLoading(); + params_ = params; + status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; + image_.reset(); } -string const & Loader::filename() const +void Loader::Impl::statusChanged() { - static string const empty; - return pimpl_->graphic_.get() ? pimpl_->graphic_->filename() : empty; + status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad; + createPixmap(); + signal_(); } -ImageStatus Loader::status() const +void Loader::Impl::createPixmap() { - return pimpl_->status_; + if (!cached_item_.get() || + params_.display == NoDisplay || status_ != Loaded) + return; + + image_.reset(cached_item_->image()->clone()); + + // These do nothing if there's nothing to do + image_->clip(params_); + image_->rotate(params_); + image_->scale(params_); + + bool const success = image_->setPixmap(params_); + + if (success) { + status_ = Ready; + } else { + image_.reset(); + status_ = ErrorGeneratingPixmap; + } } -GImage const * Loader::image() const +void Loader::Impl::startLoading(Inset const & inset, BufferView const & bv) { - return pimpl_->image_.get(); + if (status_ != WaitingToLoad || timer.running()) + return; + + InsetList::const_iterator it = insets.begin(); + InsetList::const_iterator end = insets.end(); + it = std::find(it, end, &inset); + if (it == end) + insets.push_back(&inset); + view = bv.owner()->view(); + + timer.start(); +} + + +namespace { + +struct FindVisibleInset { + + FindVisibleInset(std::list const & vps) : vps_(vps) {} + + bool operator()(Inset const * inset_ptr) + { + if (!inset_ptr) + return false; + return isInsetVisible(*inset_ptr, vps_); + } + +private: + std::list const & vps_; +}; + +} // namespace anon + + +void Loader::Impl::checkedLoading() +{ + if (insets.empty() || !view.get()) + return; + + std::list const vps = + getVisibleParagraphs(*view.get()); + + InsetList::const_iterator it = insets.begin(); + InsetList::const_iterator end = insets.end(); + + it = std::find_if(it, end, FindVisibleInset(vps)); + + // One of the insets is visible, so start loading the image. + if (it != end) + cached_item_->startLoading(); } + } // namespace grfx