]> git.lyx.org Git - lyx.git/blobdiff - src/graphics/GraphicsLoader.C
Modify the headers of files in src/graphics as discussed on the list.
[lyx.git] / src / graphics / GraphicsLoader.C
index d0c582ce06f2e5b49f407fbe8983b570416d198f..f78bcd7f89dd73e049d997128f6ca4837ded1a6e 100644 (file)
@@ -1,9 +1,10 @@
-/*
+/**
  * \file GraphicsLoader.C
- * Copyright 2002 the LyX Team
  * Read the file COPYING
  *
- * \author Angus Leeming <leeming@lyx.org>
+ * \author Angus Leeming 
+ *
+ * Full author contact details available in file CREDITS
  */
 
 #include <config.h>
 #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 <boost/weak_ptr.hpp>
 #include <boost/bind.hpp>
+#include <boost/signals/trackable.hpp>
+
+#include <list>
 
 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<void> signal_;
+
+private:
+       ///
+       void statusChanged();
+       ///
+       void checkedLoading();
+
+       ///
+       Params params_;
+
+       ///
+       Timeout timer;
+       // Multiple Insets can share the same image
+       typedef std::list<Inset const *> InsetList;
+       ///
+       InsetList insets;
+       ///
+       boost::weak_ptr<BufferView const> 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<VisibleParagraph> const & vps) : vps_(vps) {}
+
+       bool operator()(Inset const * inset_ptr)
+       {
+               if (!inset_ptr)
+                       return false;
+               return isInsetVisible(*inset_ptr, vps_);
+       }
+
+private:
+       std::list<VisibleParagraph> const & vps_;
+};
+
+} // namespace anon
+
+
+void Loader::Impl::checkedLoading()
+{
+       if (insets.empty() || !view.get())
+               return;
+
+       std::list<VisibleParagraph> 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