]> git.lyx.org Git - features.git/commitdiff
Smart loading of image files for previews and for the graphics inset.
authorAngus Leeming <leeming@lyx.org>
Mon, 15 Jul 2002 11:08:46 +0000 (11:08 +0000)
committerAngus Leeming <leeming@lyx.org>
Mon, 15 Jul 2002 11:08:46 +0000 (11:08 +0000)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4638 a592a061-630c-0410-9148-cb99ea01b6c8

13 files changed:
src/graphics/ChangeLog
src/graphics/GraphicsLoader.C
src/graphics/GraphicsLoader.h
src/graphics/GraphicsSupport.C [new file with mode: 0644]
src/graphics/GraphicsSupport.h [new file with mode: 0644]
src/graphics/Makefile.am
src/graphics/PreviewImage.C
src/graphics/PreviewImage.h
src/graphics/PreviewLoader.C
src/insets/ChangeLog
src/insets/insetgraphics.C
src/mathed/ChangeLog
src/mathed/formula.C

index 23cf06e79046f6c04aaa97b0b0be443f2eb1b375..6bb09a92717c209fdb7e16aff4977ebef51d4974 100644 (file)
@@ -1,3 +1,18 @@
+2002-07-12  Angus Leeming  <leeming@lyx.org>
+
+       * GraphicsLoader.[Ch]: smart loading of images. Images are loaded only
+       if visible 2 secs after the call to load them is first made.
+
+       * GraphicsSupport.[Ch]: new files. isInsetVisible interrogates the
+       BufferView to ascertain whether the inset is visible or not.
+
+       * Makefile.am: added GraphicsSupport.[Ch].
+
+       * PreviewImage.[Ch]: use this smart loader.
+
+       * PreviewLoader.C: don't load generated image files indiscimminantly.
+       Instead emit the imageReady signal and allow the image owner to decide.
+
 2002-07-12  John Levon  <moz@compsoc.man.ac.uk>
 
        * GraphicsCache.C: remove init_graphics()
index 9464960690d1dc5a3e417065bbcd87ba675a3390..9644c5f2453e376f8b9e2fc0759ba09a8498ed0f 100644 (file)
 #include "GraphicsCacheItem.h"
 #include "GraphicsImage.h"
 #include "GraphicsParams.h"
+#include "GraphicsSupport.h"
+
+#include "frontends/Timeout.h"
 
 #include <boost/bind.hpp>
 #include <boost/signals/trackable.hpp>
 
+#include <list>
+
 namespace grfx {
 
 struct Loader::Impl : boost::signals::trackable {
@@ -35,6 +40,9 @@ struct Loader::Impl : boost::signals::trackable {
        ///
        void createPixmap();
 
+       ///
+       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
@@ -47,19 +55,118 @@ struct Loader::Impl : boost::signals::trackable {
 private:
        ///
        void statusChanged();
+       ///
+       void checkedLoading();
        
        ///
        Params params_;
        ///
        Loader & parent_;
+
+       ///
+       Timeout timer;
+       // Multiple Insets can share the same image
+       typedef std::list<Inset const *> InsetList;
+       ///
+       InsetList insets;
+       ///
+       BufferView const * view;
 };
 
 
-Loader::Impl::Impl(Loader & parent, Params const & params)
-       : status_(WaitingToLoad), params_(params), parent_(parent)
+Loader::Loader()
+       : pimpl_(new Impl(*this, Params()))
 {}
 
 
+Loader::Loader(string const & file, DisplayType type)
+       : pimpl_(new Impl(*this, Params()))
+{
+       reset(file, type);
+}
+
+
+Loader::Loader(string const & file, Params const & params)
+       : pimpl_(new Impl(*this, params))
+{
+       reset(file, params);
+}
+
+
+Loader::~Loader()
+{}
+
+
+void Loader::reset(string const & file, DisplayType type)
+{
+       Params params;
+       params.display = type;
+       pimpl_->resetParams(params);
+
+       pimpl_->resetFile(file);
+       pimpl_->createPixmap();
+}
+
+
+void Loader::reset(string const & file, Params const & params)
+{
+       pimpl_->resetParams(params);
+       pimpl_->resetFile(file);
+       pimpl_->createPixmap();
+}
+
+
+void Loader::reset(Params const & params)
+{
+       pimpl_->resetParams(params);
+       pimpl_->createPixmap();
+}
+
+
+void Loader::startLoading()
+{
+       if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
+               return;
+       pimpl_->cached_item_->startLoading();
+}
+
+
+void Loader::startLoading(Inset const & inset, BufferView const & bv)
+{
+       if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
+               return;
+       pimpl_->startLoading(inset, bv);
+}
+
+
+string const & Loader::filename() const
+{
+       static string const empty;
+       return pimpl_->cached_item_.get() ?
+               pimpl_->cached_item_->filename() : empty;
+}
+
+
+ImageStatus Loader::status() const
+{
+       return pimpl_->status_;
+}
+
+
+Image const * Loader::image() const
+{
+       return pimpl_->image_.get();
+}
+
+
+Loader::Impl::Impl(Loader & parent, Params const & params)
+       : status_(WaitingToLoad), params_(params), parent_(parent),
+         timer(2000, Timeout::ONETIME), view(0)
+{
+       timer.timeout.connect(boost::bind(&Impl::checkedLoading, this));
+}
+
+
 Loader::Impl::~Impl()
 {
        resetFile(string());
@@ -141,80 +248,58 @@ void Loader::Impl::createPixmap()
 }
 
 
-Loader::Loader()
-       : pimpl_(new Impl(*this, Params()))
-{}
-
-
-Loader::Loader(string const & file, DisplayType type)
-       : pimpl_(new Impl(*this, Params()))
+void Loader::Impl::startLoading(Inset const & inset, BufferView const & bv)
 {
-       reset(file, type);
-}
+       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;
 
-Loader::Loader(string const & file, Params const & params)
-       : pimpl_(new Impl(*this, params))
-{
-       reset(file, params);
+       timer.start();
 }
 
 
-Loader::~Loader()
-{}
+namespace {
 
+struct FindVisibleInset {
 
-void Loader::reset(string const & file, DisplayType type)
-{
-       Params params;
-       params.display = type;
-       pimpl_->resetParams(params);
-
-       pimpl_->resetFile(file);
-       pimpl_->createPixmap();
-}
-
-
-void Loader::reset(string const & file, Params const & params)
-{
-       pimpl_->resetParams(params);
-       pimpl_->resetFile(file);
-       pimpl_->createPixmap();
-}
+       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_;
+};
 
-void Loader::reset(Params const & params)
-{
-       pimpl_->resetParams(params);
-       pimpl_->createPixmap();
-}
+} // namespace anon
 
 
-void Loader::startLoading()
+void Loader::Impl::checkedLoading()
 {
-       if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
+       if (insets.empty() || !view)
                return;
-       pimpl_->cached_item_->startLoading();
-}
 
+       std::list<VisibleParagraph> const vps = getVisibleParagraphs(*view);
 
-string const & Loader::filename() const
-{
-       static string const empty;
-       return pimpl_->cached_item_.get() ?
-               pimpl_->cached_item_->filename() : empty;
-}
+       InsetList::const_iterator it  = insets.begin();
+       InsetList::const_iterator end = insets.end();
 
+       it = std::find_if(it, end, FindVisibleInset(vps));
 
-ImageStatus Loader::status() const
-{
-       return pimpl_->status_;
+       // One of the insets is visible, so start loading the image.
+       if (it != end)
+               cached_item_->startLoading();
 }
 
 
-Image const * Loader::image() const
-{
-       return pimpl_->image_.get();
-}
-
 } // namespace grfx
index 3054b8cbaf098859b23db26e31ee6739844900df..569e3298647e879a6978bd0e0130a6f4400cb32d 100644 (file)
@@ -31,6 +31,9 @@
 #include <boost/signals/signal0.hpp>
 #include <boost/scoped_ptr.hpp>
 
+class Inset;
+class BufferView;
+
 namespace grfx {
 
 class Image;
@@ -63,6 +66,11 @@ public:
        /// We are explicit about when we begin the loading process.
        void startLoading();
 
+       /** starting loading of the image is conditional upon the
+        *  inset being visible or not.
+        */
+       void startLoading(Inset const &, BufferView const &);
+
        /// How far have we got in loading the image?
        ImageStatus status() const;
 
diff --git a/src/graphics/GraphicsSupport.C b/src/graphics/GraphicsSupport.C
new file mode 100644 (file)
index 0000000..de8cccd
--- /dev/null
@@ -0,0 +1,102 @@
+/**
+ *  \file GraphicsSupport.C
+ *  Copyright 2002 the LyX Team
+ *  Read the file COPYING
+ *
+ * \author Angus Leeming <leeming@lyx.org>
+ */
+
+#include <config.h>
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "GraphicsSupport.h"
+
+#include "BufferView.h"
+#include "lyxtext.h"
+#include "lyxrow.h"
+#include "paragraph.h"
+#include "frontends/Painter.h"
+
+
+typedef std::list<VisibleParagraph> VPList;
+
+
+VPList const getVisibleParagraphs(BufferView const & bv)
+{
+       // top_y is not const because it's reset by getRowNearY.
+       int top_y = bv.text->first_y;
+       Row const * row = bv.text->getRowNearY(top_y);
+
+       int const bv_height = bv.painter().paperHeight();
+
+       VPList vps;
+       Row const * last_row = 0;
+
+       for (int height = 0; row && height < bv_height; row = row->next()) {
+               height += row->height();
+
+               if (vps.empty() || vps.back().par != row->par()) {
+                       vps.push_back(VisibleParagraph(row->par(),
+                                                      row->pos(),
+                                                      row->par()->size()));
+               }
+
+               last_row = row;
+       }
+
+       // If the end of the final paragraph is not visble,
+       // update vps.back().end
+       if (last_row && last_row->next() &&
+           last_row->par() == last_row->next()->par()) {
+               vps.back().end = last_row->next()->pos();
+       }
+
+       return vps;
+}
+
+
+namespace {
+
+struct InsetVisibleInParagraph {
+       InsetVisibleInParagraph(Inset const & inset) : inset_(inset) {}
+       bool operator()(VisibleParagraph const & vp)
+       {
+               Paragraph * par = vp.par;
+               Paragraph::inset_iterator it  = par->inset_iterator_begin();
+               Paragraph::inset_iterator end = par->inset_iterator_end();
+
+               // Can't refactor this as a functor because we rely on the
+               // inset_iterator member function getPos().
+               for (; it != end; ++it) {
+                       lyx::pos_type const pos = it.getPos();
+                       if (pos >= vp.start && pos <= vp.end) {
+                               if (*it == &inset_ ||
+                                   it->getInsetFromID(inset_.id()) != 0)
+                                       return true;
+                       }
+               }
+               return false;
+       }
+
+private:
+       Inset const & inset_;
+};
+
+} // namespace anon
+
+
+bool isInsetVisible(Inset const & inset, VPList const & vps)
+{
+       if (vps.empty())
+               return false;
+
+       VPList::const_iterator it  = vps.begin();
+       VPList::const_iterator end = vps.end();
+
+       it = std::find_if(it, end, InsetVisibleInParagraph(inset));
+
+       return it != end;
+}
diff --git a/src/graphics/GraphicsSupport.h b/src/graphics/GraphicsSupport.h
new file mode 100644 (file)
index 0000000..72257b1
--- /dev/null
@@ -0,0 +1,50 @@
+// -*- C++ -*-
+/**
+ *  \file GraphicsSupport.h
+ *  Copyright 2002 the LyX Team
+ *  Read the file COPYING
+ *
+ * \author Angus Leeming <leeming@lyx.org>
+ */
+
+#ifndef GRAPHICSSUPPORT_H
+#define GRAPHICSSUPPORT_H
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include "support/types.h"
+#include <list>
+
+class BufferView;
+class Inset;
+class Paragraph;
+
+/** A Paragraph * together with delimiters for the start and end positions
+    of visibility.
+ */
+struct VisibleParagraph {
+       ///
+       VisibleParagraph() : par(0), start(0), end(0) {}
+       ///
+       VisibleParagraph(Paragraph * p, lyx::pos_type s, lyx::pos_type e)
+               : par(p), start(s), end(e) {}
+       ///
+       Paragraph * par;
+       ///
+       lyx::pos_type start;
+       ///
+       lyx::pos_type end;
+};
+
+
+/// Returns a list of all Paragraphs currently visible in bv.
+std::list<VisibleParagraph> const getVisibleParagraphs(BufferView const & bv);
+
+/** Given this data, check whether inset lies within it and is, therefore,
+ *  visible.
+ */
+bool isInsetVisible(Inset const & inset, std::list<VisibleParagraph> const &);
+
+#endif // GRAPHICSSUPPORT_H
index 6c1c4c1afea715595d0711202800a01b0beccd21..01e377553e6ff18c6f55cb2647201c416736b878 100644 (file)
@@ -23,6 +23,8 @@ libgraphics_la_SOURCES = \
        GraphicsLoader.C \
        $(GRAPHICSIMAGEXPM) GraphicsParams.C \
        GraphicsParams.h \
+       GraphicsSupport.h \
+       GraphicsSupport.C \
        GraphicsTypes.h \
        PreviewImage.h \
        PreviewImage.C \
index 9bc6ba88c2d587a35bd224438224383db3ba24f5..4be278aa619c0c22ee4f0a6800419d82dcdf2d51 100644 (file)
@@ -3,7 +3,7 @@
  *  Copyright 2002 the LyX Team
  *  Read the file COPYING
  *
- * \author Angus Leeming <a.leeming@ic.ac.uk>
+ * \author Angus Leeming <leeming@lyx.org>
  */
 
 #include <config.h>
@@ -17,8 +17,6 @@
 #include "GraphicsImage.h"
 #include "GraphicsLoader.h"
 
-#include "debug.h"
-
 #include "support/lyxlib.h"
 
 #include <boost/bind.hpp>
@@ -34,9 +32,7 @@ struct PreviewImage::Impl : public boost::signals::trackable {
        ///
        ~Impl();
        ///
-       void startLoading();    
-       ///
-       Image const * image();
+       Image const * image(Inset const &, BufferView const &);
        ///
        void statusChanged();
 
@@ -45,7 +41,7 @@ struct PreviewImage::Impl : public boost::signals::trackable {
        ///
        PreviewLoader & ploader_;
        ///
-       boost::scoped_ptr<Loader> const iloader_;
+       Loader iloader_;
        ///
        string const snippet_;
        ///
@@ -65,20 +61,15 @@ PreviewImage::~PreviewImage()
 {}
 
 
-void PreviewImage::startLoading()
-{
-       return pimpl_->startLoading();
-}
-
-
 string const & PreviewImage::snippet() const
 {
        return pimpl_->snippet_;
 }
 
+
 int PreviewImage::ascent() const
 {
-       Image const * const image = pimpl_->image();
+       Image const * const image = pimpl_->iloader_.image();
        if (!image)
                return 0;
 
@@ -88,7 +79,7 @@ int PreviewImage::ascent() const
 
 int PreviewImage::descent() const
 {
-       Image const * const image = pimpl_->image();
+       Image const * const image = pimpl_->iloader_.image();
        if (!image)
                return 0;
 
@@ -99,14 +90,15 @@ int PreviewImage::descent() const
 
 int PreviewImage::width() const
 {
-       Image const * const image = pimpl_->image();
+       Image const * const image = pimpl_->iloader_.image();
        return image ? image->getWidth() : 0;
 }
 
 
-Image const * PreviewImage::image() const
+Image const * PreviewImage::image(Inset const & inset,
+                                 BufferView const & bv) const
 {
-       return pimpl_->image();
+       return pimpl_->image(inset, bv);
 }
 
 
@@ -114,37 +106,33 @@ PreviewImage::Impl::Impl(PreviewImage & p, PreviewLoader & l,
                         string const & s,
                         string const & bf,
                         double af)
-       : parent_(p), ploader_(l), iloader_(new Loader(bf)),
+       : parent_(p), ploader_(l), iloader_(bf),
          snippet_(s), ascent_frac_(af)
-{}
+{
+       iloader_.statusChanged.connect(
+               boost::bind(&Impl::statusChanged, this));
+}
 
 
 PreviewImage::Impl::~Impl()
 {
-       lyx::unlink(iloader_->filename());
+       lyx::unlink(iloader_.filename());
 }
 
 
-void PreviewImage::Impl::startLoading()
+Image const * PreviewImage::Impl::image(Inset const & inset,
+                                       BufferView const & bv)
 {
-       if (iloader_->status() != WaitingToLoad)
-               return;
+       if (iloader_.status() == WaitingToLoad)
+               iloader_.startLoading(inset, bv);
 
-       iloader_->statusChanged.connect(
-               boost::bind(&Impl::statusChanged, this));
-       iloader_->startLoading();
+       return iloader_.image();
 }
 
 
-Image const * PreviewImage::Impl::image()
-{
-//     startLoading();
-       return iloader_->image();
-}
-
 void PreviewImage::Impl::statusChanged()
 {
-       switch (iloader_->status()) {
+       switch (iloader_.status()) {
        case WaitingToLoad:
        case Loading:
        case Converting:
@@ -157,12 +145,12 @@ void PreviewImage::Impl::statusChanged()
        case ErrorLoading:
        case ErrorGeneratingPixmap:
        case ErrorUnknown:
-               //lyx::unlink(iloader_->filename());
+               //lyx::unlink(iloader_.filename());
                ploader_.remove(snippet_);
                break;
 
        case Ready:
-               lyx::unlink(iloader_->filename());
+               lyx::unlink(iloader_.filename());
                ploader_.imageReady(parent_);
                break;
        }
index 67b67ed856cb84472f32dfc53201637bfcce3e38..d0f2533f417435c4869850914cdf2760a6d43104 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright 2002 the LyX Team
  *  Read the file COPYING
  *
- * \author Angus Leeming <a.leeming@ic.ac.uk>
+ * \author Angus Leeming <leeming@lyx.org>
  */
 
 #ifndef PREVIEWIMAGE_H
@@ -17,6 +17,9 @@
 #include "LString.h"
 #include <boost/scoped_ptr.hpp>
 
+class Inset;
+class BufferView;
+
 namespace grfx {
 
 class PreviewLoader;
@@ -34,9 +37,6 @@ public:
        ///
        ~PreviewImage();
 
-       /// We are explicit about when we begin the loading process.
-       void startLoading();
-
        ///
        string const & snippet() const;
        ///
@@ -45,8 +45,13 @@ public:
        int descent() const;
        ///
        int width() const;
-       ///
-       Image const * image() const;
+
+       /** If the image is not yet loaded (WaitingToLoad), then this method
+        *  triggers that.
+        *  inset and bv are passed so we can choose to load only
+        *  those insets that are visible.
+        */
+       Image const * image(Inset const & inset, BufferView const & bv) const;
 
 private:
        /// Use the Pimpl idiom to hide the internals.
index 79e6d866a459c20afa712ecf6a8971cabd1d1826..887b7ccb92218f7ec32fcff2d46761c10b256e95 100644 (file)
@@ -3,7 +3,7 @@
  *  Copyright 2002 the LyX Team
  *  Read the file COPYING
  *
- * \author Angus Leeming <a.leeming@ic.ac.uk>
+ * \author Angus Leeming <leeming@lyx.org>
  */
 
 #include <config.h>
@@ -444,6 +444,7 @@ void PreviewLoader::Impl::finishedGenerating(string const & command,
        if (retval > 0)
                return;
 
+       // Paranoia check!
        InProgressMap::iterator git = in_progress_.find(command);
        if (git == in_progress_.end()) {
                lyxerr << "PreviewLoader::finishedGenerating(): unable to find "
@@ -461,6 +462,8 @@ void PreviewLoader::Impl::finishedGenerating(string const & command,
        InProgressStore::const_iterator it  = git->second.snippets.begin();
        InProgressStore::const_iterator end = git->second.snippets.end();
 
+       std::list<PreviewImagePtr> newimages;
+
        int metrics_counter = 0;
        for (; it != end; ++it, ++metrics_counter) {
                string const & snip = it->first;
@@ -470,11 +473,18 @@ void PreviewLoader::Impl::finishedGenerating(string const & command,
                PreviewImagePtr ptr(new PreviewImage(parent_, snip, file, af));
                cache_[snip] = ptr;
 
-               ptr->startLoading();
+               newimages.push_back(ptr);
        }
 
        // Remove the item from the list of still-executing processes.
        in_progress_.erase(git);
+
+       // Tell the outside world
+       std::list<PreviewImagePtr>::const_iterator nit  = newimages.begin();
+       std::list<PreviewImagePtr>::const_iterator nend = newimages.end();
+       for (; nit != nend; ++nit) {
+               parent_.imageReady(*nit->get());
+       }
 }
 
 
index 2cea2be72b1a10ca5ece38d750d7e7937d771265..098c4d382be408d91b0d76c49c5deb540ddbe31b 100644 (file)
@@ -1,3 +1,8 @@
+2002-07-12  Angus Leeming  <leeming@lyx.org>
+
+       * insetgraphics.C: use the new smart loading capabilities of the image
+       loader.
+
 2002-07-13  Dekel Tsur  <dekelts@tau.ac.il>
 
        * insettabular.C (edit): Move into correct cell when entering a
index efa3112dd8d4905937bd5b60294d9b1475d1cdf8..518924a72e31ed0e454e6603d69590397c8a70c5 100644 (file)
@@ -329,7 +329,7 @@ void InsetGraphics::draw(BufferView * bv, LyXFont const & font,
        x += lwidth;
 
        if (cache_->loader.status() == grfx::WaitingToLoad) {
-               cache_->loader.startLoading();
+               cache_->loader.startLoading(*this, *bv);
        }
 
        // This will draw the graphics. If the graphics has not been loaded yet,
index 38092b2a293d4c599cfa37ccc3dbcfab9dfb0752..c814dfc410cecea2055f3f8d90104d102c6ba34b 100644 (file)
@@ -1,3 +1,7 @@
+2002-07-12  Angus Leeming  <leeming@lyx.org>
+
+       * formula.C: use the new smart loading capabilities of the image loader.
+
 2002-07-14  John Levon  <moz@compsoc.man.ac.uk>
 
        * mathformula.C: use Lsstream.h not sstream
index d59738046078622ecb8b753f0c13650cd704f70a..67108d39bee14eb38a33db815487bf7d0ad3d8a2 100644 (file)
@@ -214,6 +214,10 @@ void InsetFormula::read(Buffer const *, LyXLex & lex)
 void InsetFormula::draw(BufferView * bv, LyXFont const & font,
                        int y, float & xx, bool) const
 {
+       // This initiates the loading of the preview, so should come
+       // before the metrics are computed.
+       bool const use_preview = preview_->usePreview();
+
        int const x = int(xx);
        int const w = width(bv, font);
        int const d = descent(bv, font);
@@ -222,9 +226,9 @@ void InsetFormula::draw(BufferView * bv, LyXFont const & font,
 
        MathPainterInfo pi(bv->painter());
 
-       if (preview_->usePreview()) {
+       if (use_preview) {
                pi.pain.image(x + 1, y - a + 1, w - 2, h - 2, 
-                             *(preview_->pimage_->image()));
+                             *(preview_->pimage_->image(*this, *bv)));
        } else {
                //pi.base.style = display() ? LM_ST_DISPLAY : LM_ST_TEXT;
                pi.base.style = LM_ST_TEXT;
@@ -524,7 +528,7 @@ bool InsetFormula::PreviewImpl::usePreview() const
        if (!pimage_)
                return false;
 
-       return pimage_->image();
+       return pimage_->image(parent_, *view);
 }