diff --git a/src/ChangeLog b/src/ChangeLog index 1b090341ed..918ad1ceb9 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2002-06-25 Angus Leeming + + * lyxfunc.C (dispatch): Comment out the call to + grfx::GCache::changeDisplay. The method no longer exists now that the + pixmap generation part of the graphics loader has been moved into + InsetGraphics. + 2002-06-24 Lars Gullik Bjønnes * text2.C: layout as layout diff --git a/src/frontends/controllers/ChangeLog b/src/frontends/controllers/ChangeLog index 57e04375b7..c9b0953661 100644 --- a/src/frontends/controllers/ChangeLog +++ b/src/frontends/controllers/ChangeLog @@ -1,3 +1,8 @@ +2002-06-25 Angus Leeming + + * ControlGraphics.C (readBB): Channges associated with the changed + interface to the graphics cache. + 2002-06-24 Lars Gullik Bjønnes * ControlParagraph.C: layout as layout diff --git a/src/frontends/controllers/ControlGraphics.C b/src/frontends/controllers/ControlGraphics.C index e8e34ebce3..6bc9979f82 100644 --- a/src/frontends/controllers/ControlGraphics.C +++ b/src/frontends/controllers/ControlGraphics.C @@ -32,6 +32,7 @@ #include "graphics/GraphicsCache.h" #include "graphics/GraphicsConverter.h" +#include "graphics/GraphicsImage.h" #include "insets/insetgraphics.h" #include "insets/insetgraphicsParams.h" @@ -110,10 +111,18 @@ string const ControlGraphics::readBB(string const & file) return readBB_from_PSFile(abs_file); // we don't, so ask the Graphics Cache if it has loaded the file + int width = 0; + int height = 0; + grfx::GCache & gc = grfx::GCache::get(); - return ("0 0 " + - tostr(gc.raw_width(abs_file)) + ' ' + - tostr(gc.raw_height(abs_file))); + grfx::ImagePtr const image = gc.image(abs_file); + + if (image.get()) { + width = image->getWidth(); + height = image->getHeight(); + } + + return ("0 0 " + tostr(width) + ' ' + tostr(height)); } diff --git a/src/frontends/screen.C b/src/frontends/screen.C index b9720d3be5..ce174f8f48 100644 --- a/src/frontends/screen.C +++ b/src/frontends/screen.C @@ -4,6 +4,8 @@ * Read the file COPYING * * \author John Levon + * + * Splash screen code added by Angus Leeming */ #ifdef __GNUG__ @@ -23,14 +25,152 @@ #include "language.h" #include "debug.h" +// Splash screen-specific stuff +#include "lyxfont.h" +#include "version.h" + +#include "graphics/GraphicsCache.h" +#include "graphics/GraphicsCacheItem.h" +#include "graphics/GraphicsImage.h" +#include "graphics/GraphicsParams.h" + +#include "support/filetools.h" // LibFileSearch + +#include +#include + using std::min; using std::max; using std::endl; +namespace { + +class SplashScreen : boost::noncopyable { +public: + /// This is a singleton class. Get the instance. + static SplashScreen const & get(); + /// + grfx::GImage const * image() const { return image_.get(); } + /// + string const & text() const { return text_; } + /// + LyXFont const & font() const { return font_; } + +private: + /** Make the c-tor, d-tor private so we can control how many objects + * are instantiated. + */ + SplashScreen(); + /// + ~SplashScreen(); + + /** Connected to grfx::GCacheItem::statusChanged, so will generate the + * pixmap as soon as the file is loaded into memory. + */ + void createPixmap(); + + /** Must store a copy of the cached item to ensure that it is not + * erased unexpectedly by the cache itself. + */ + grfx::GraphicPtr graphic_; + /** We generate a pixmap from a copy of the grfx::GImage * stored in + * the cache. + */ + grfx::ImagePtr image_; + /// The loading status of the image. + grfx::ImageStatus status_; + /// The text to be written on top of the pixmap + string const text_; + /// in this font... + LyXFont font_; +}; + + +SplashScreen const & SplashScreen::get() +{ + static SplashScreen singleton; + return singleton; +} + + +SplashScreen::SplashScreen() + : status_(grfx::WaitingToLoad), + text_(lyx_version ? lyx_version : "unknown") +{ + string const file = LibFileSearch("images", "banner", "xpm"); + if (file.empty()) + return; + + // The font used to display the version info + font_.setFamily(LyXFont::SANS_FAMILY); + font_.setSeries(LyXFont::BOLD_SERIES); + font_.setSize(LyXFont::SIZE_NORMAL); + font_.setColor(LColor::yellow); + + // Load up the graphics file + grfx::GCache & gc = grfx::GCache::get(); + if (!gc.inCache(file)) + gc.add(file); + // We /must/ make a local copy of this. + graphic_ = gc.graphic(file); + + if (graphic_->status() == grfx::Loaded) { + createPixmap(); + } else { + graphic_->statusChanged.connect( + boost::bind(&SplashScreen::createPixmap, this)); + graphic_->startLoading(); + } +} + + +SplashScreen::~SplashScreen() +{ + if (!graphic_.get()) + return; + + string const file = graphic_->filename(); + graphic_.reset(); + + // If only the cache itself now references this item, then it will be + // removed. + grfx::GCache::get().remove(file); +} + + +void SplashScreen::createPixmap() +{ + if (!graphic_.get() || image_.get()) + return; + + if (graphic_->status() != grfx::Loaded) + return; + + if (status_ != grfx::WaitingToLoad) + return; + + // Strictly speaking, we need to create a copy only if we're going to + // modify the image (scale, etc). + image_.reset(graphic_->image()->clone()); + + bool const success = image_->setPixmap(grfx::GParams()); + + if (success) { + status_ = grfx::Loaded; + } else { + image_.reset(); + status_ = grfx::ErrorScalingEtc; + } +} + +} // namespace anon + LyXScreen::LyXScreen() : force_clear_(true), cursor_visible_(false) { + // Start loading the pixmap as soon as possible + SplashScreen::get(); } @@ -297,42 +437,26 @@ void LyXScreen::greyOut() workarea().workHeight(), LColor::bottomarea); -// FIXME: pending GUIIzation / cleanup of graphics cache. -// We should be using something like this. -#if 0 - static bool first = true; - if (first) { - first = false; - - splash_file_ = (lyxrc.show_banner) ? - LibFileSearch("images", "banner", "xpm") : string(); - if (splash_file_) { - grfx::GCache & gc = grfx::GCache::get(); - gc.add(splash_file_); - gc.startLoading(splash_file_); - } - } - // Add a splash screen to the centre of the work area - grfx::GCache & gc = grfx::GCache::get(); - grfx::ImagePtr const splash = gc.image(splash_file_); - if (splash.get()) { - int const w = splash->getWidth(); - int const h = splash->getHeight(); + SplashScreen const & splash = SplashScreen::get(); + grfx::GImage const * const splash_image = splash.image(); + if (splash_image) { + int const w = splash_image->getWidth(); + int const h = splash_image->getHeight(); - int const x = 0.5 * (workarea().workWidth() - w); - int const y = 0.5 * (workarea().workHeight() - h); + int x = 0.5 * (workarea().workWidth() - w); + int y = 0.5 * (workarea().workHeight() - h); - workarea().getPainter().image(x, y, w, h, splash->getPixmap()); + workarea().getPainter().image(x, y, w, h, *splash_image); + + string const & splash_text = splash.text(); + LyXFont const & splash_font = splash.font(); + + x += 260; + y += 265; + + workarea().getPainter().text(x, y, splash_text, splash_font); } -#endif -// Alternatively, we should compile this into the code. -// I think that that is better here (so that the pixmap is displayed on -// start-up). -// Would need a new method -// virtual Pixmap splashPixmap() = 0; -// or some such. -// Angus 21 June 2002 } diff --git a/src/frontends/xforms/ChangeLog b/src/frontends/xforms/ChangeLog index 2cdcf58bc4..7c468942c7 100644 --- a/src/frontends/xforms/ChangeLog +++ b/src/frontends/xforms/ChangeLog @@ -1,3 +1,10 @@ +2002-06-25 Angus Leeming + + * FormPreferences.C (LnFmisc::apply): Comment out the call to + grfx::GCache::changeDisplay. The method no longer exists now that the + pixmap generation part of the graphics loader has been moved into + InsetGraphics. + 2002-06-24 Lars Gullik Bjønnes * Toolbar_pimpl.C: layout as layout diff --git a/src/frontends/xforms/FormPreferences.C b/src/frontends/xforms/FormPreferences.C index 40ae2a5ecf..855bfe5b85 100644 --- a/src/frontends/xforms/FormPreferences.C +++ b/src/frontends/xforms/FormPreferences.C @@ -1842,10 +1842,16 @@ void FormPreferences::LnFmisc::apply() const } else { lyxrc.display_graphics = "no"; } + +#ifdef WITH_WARNINGS +#warning FIXME!! The graphics cache no longer has a changeDisplay method. +#endif +#if 0 if (old_value != lyxrc.display_graphics) { grfx::GCache & gc = grfx::GCache::get(); gc.changeDisplay(); } +#endif } diff --git a/src/graphics/ChangeLog b/src/graphics/ChangeLog index 6753d23671..f2a72c6a47 100644 --- a/src/graphics/ChangeLog +++ b/src/graphics/ChangeLog @@ -1,3 +1,15 @@ +2002-06-25 Angus Leeming + + * GraphicsCache.[Ch]: + * GraphicsCacheItem.[Ch]: + * GraphicsTypes.h: rewrite the graphics cache to just load a graphics + file into memory. The cache no longer controls the generation of the + pixmap. Instead, it just emits a signal when the loading status of an + image changes. + The cache no longer stores InsetGraphics pointers and nor does it + assume responsibility for modifying an image (scaling, rotating etc). + Instead, that must now be performed elsewhere. + 2002-06-19 Angus Leeming * GraphicsConverter.C: add using std::endl directive. diff --git a/src/graphics/GraphicsCache.C b/src/graphics/GraphicsCache.C index 1b3c70c4a1..16a3e2aa93 100644 --- a/src/graphics/GraphicsCache.C +++ b/src/graphics/GraphicsCache.C @@ -16,8 +16,11 @@ #include "GraphicsCache.h" #include "GraphicsCacheItem.h" #include "GraphicsImage.h" -#include "GraphicsParams.h" -#include "insets/insetgraphics.h" + +#include "debug.h" + +#include "support/filetools.h" + #include "frontends/lyx_gui.h" namespace grfx { @@ -49,145 +52,74 @@ GCache::~GCache() } -void GCache::update(InsetGraphics const & inset, string const & filepath) +std::vector GCache::loadableFormats() const { - // A subset only of InsetGraphicsParams is needed for display purposes. - // The GraphicsParams c-tor also interrogates lyxrc to ascertain whether - // to display or not. - GParams params = inset.params().asGParams(filepath); - - // Each inset can reference only one file, so check the cache for any - // graphics files referenced by inset. If the name of this file is - // different from that in params, then remove the reference. - CacheType::iterator it = find(inset); - - if (it != cache->end()) { - CacheItemType item = it->second; - if (item->filename() != params.filename) { - item->remove(inset); - if (item->empty()) - cache->erase(it); - } - } - - // Are we adding a new file or modifying the display of an existing one? - it = cache->find(params.filename); - - if (it != cache->end()) { - it->second->modify(inset, params); - return; - } - - CacheItemType item(new GCacheItem(inset, params)); - if (item.get() != 0) - (*cache)[params.filename] = item; + return GImage::loadableFormats(); } -void GCache::remove(InsetGraphics const & inset) +void GCache::add(string const & file) { - CacheType::iterator it = find(inset); + if (!AbsolutePath(file)) { + lyxerr << "GCacheItem::add(" << file << "):\n" + << "The file must be have an absolute path." + << std::endl; + return; + } + + // Is the file in the cache already? + if (inCache(file)) { + lyxerr[Debug::GRAPHICS] << "GCache::add(" << file << "):\n" + << "The file is already in the cache." + << std::endl; + return; + } + + + (*cache)[file] = GraphicPtr(new GCacheItem(file)); +} + + +void GCache::remove(string const & file) +{ + CacheType::iterator it = cache->find(file); if (it == cache->end()) return; - CacheItemType item = it->second; - item->remove(inset); - if (item->empty()) { + GraphicPtr item = it->second; + + if (item.use_count() == 1) { + // The graphics file is in the cache, but nothing else + // references it. cache->erase(it); } } -void GCache::startLoading(InsetGraphics const & inset) +bool GCache::inCache(string const & file) const { - CacheType::iterator it = find(inset); - if (it == cache->end()) - return; - - it->second->startLoading(inset); + return cache->find(file) != cache->end(); } -ImagePtr const GCache::image(InsetGraphics const & inset) const +GraphicPtr const GCache::graphic(string const & file) const { - CacheType::const_iterator it = find(inset); + CacheType::const_iterator it = cache->find(file); + if (it == cache->end()) + return GraphicPtr(); + + return it->second; +} + + +ImagePtr const GCache::image(string const & file) const +{ + CacheType::const_iterator it = cache->find(file); if (it == cache->end()) return ImagePtr(); - return it->second->image(inset); + return it->second->image(); } -ImageStatus GCache::status(InsetGraphics const & inset) const -{ - CacheType::const_iterator it = find(inset); - if (it == cache->end()) - return ErrorUnknown; - - return it->second->status(inset); -} - - -void GCache::changeDisplay(bool changed_background) -{ - CacheType::iterator it = cache->begin(); - CacheType::iterator end = cache->end(); - for(; it != end; ++it) - it->second->changeDisplay(changed_background); -} - - -GCache::CacheType::iterator -GCache::find(InsetGraphics const & inset) -{ - CacheType::iterator it = cache->begin(); - CacheType::iterator end = cache->end(); - for (; it != end; ++it) { - if (it->second->referencedBy(inset)) - return it; - } - - return cache->end(); -} - - -GCache::CacheType::const_iterator -GCache::find(InsetGraphics const & inset) const -{ - CacheType::const_iterator it = cache->begin(); - CacheType::const_iterator end = cache->end(); - for (; it != end; ++it) { - if (it->second->referencedBy(inset)) - return it; - } - - return cache->end(); -} - - -unsigned int GCache::raw_width(string const & filename) const -{ - CacheType::const_iterator it = cache->find(filename); - if (it == cache->end()) - return 0; - - return it->second->raw_width(); -} - - -unsigned int GCache::raw_height(string const & filename) const -{ - CacheType::const_iterator it = cache->find(filename); - if (it == cache->end()) - return 0; - - return it->second->raw_height(); -} - - -std::vector GCache::loadableFormats() const { - return GImage::loadableFormats(); -} - } // namespace grfx - diff --git a/src/graphics/GraphicsCache.h b/src/graphics/GraphicsCache.h index 422d3eba3b..3c90ee312f 100644 --- a/src/graphics/GraphicsCache.h +++ b/src/graphics/GraphicsCache.h @@ -27,74 +27,64 @@ #include #include -class InsetGraphics; - namespace grfx { -class GCacheItem; - class GCache : boost::noncopyable { public: /// This is a singleton class. Get the instance. static GCache & get(); - /// - ~GCache(); - - /// Add a file to the cache (or modify an existing image). - void update(InsetGraphics const &, string const & filepath); - - /** Remove the data associated with this inset. - * Called from the InsetGraphics d-tor. + /** Which graphics formats can be loaded directly by the image loader. + * Other formats can be loaded if a converter to a loadable format + * can be defined. */ - void remove(InsetGraphics const &); - - /** No processing of the image will take place until this call is - * received. - */ - void startLoading(InsetGraphics const &); - - /** If (changed_background == true), then the background color of the - * graphics inset has changed. Update all images. - * Else, the preferred display type has changed. - * Update the view of all insets whose display type is DEFAULT. - */ - void changeDisplay(bool changed_background = false); - - /// Get the image referenced by a particular inset. - ImagePtr const image(InsetGraphics const &) const; - - /// How far have we got in loading the image? - ImageStatus status(InsetGraphics const &) const; - - // Used to ascertain the Bounding Box of non (e)ps files. - unsigned int raw_width(string const & filename) const; - /// - unsigned int raw_height(string const & filename) const; - /// std::vector loadableFormats() const; - + + /// Add a graphics file to the cache. + void add(string const & file); + + /** Remove a file from the cache. + * Called from the InsetGraphics d-tor. + * If we use reference counting, then this may become redundant. + */ + void remove(string const & file); + + /// Returns \c true if the file is in the cache. + bool inCache(string const & file) const; + + /** Get the cache item associated with file. + * Returns an empty container if there is no such item. + * + * IMPORTANT: whatever uses an image must make a local copy of this + * GraphicPtr. The boost::shared_ptr<>::use_count() function is + * used to ascertain whether or not to remove the item from the cache + * when remove(file) is called. + * + * You have been warned! + */ + GraphicPtr const graphic(string const & file) const; + + /** Get the image associated with file. + If the image is not yet loaded, (or is not in the cache!) return + an empty container. + */ + ImagePtr const image(string const & file) const; + private: - /** Make the c-tor private so we can control how many objects + /** Make the c-tor, d-tor private so we can control how many objects * are instantiated. */ GCache(); - - /// The cache contains data of this type. - typedef boost::shared_ptr CacheItemType; + /// + ~GCache(); /** The cache contains one item per file, so use a map to find the * cache item quickly by filename. * Note that each cache item can have multiple views, potentially one * per inset that references the original file. */ - typedef std::map CacheType; - - /// Search the cache by inset. - CacheType::const_iterator find(InsetGraphics const &) const; - /// - CacheType::iterator find(InsetGraphics const &); + typedef std::map CacheType; /** Store a pointer to the cache so that we can forward declare * GCacheItem. diff --git a/src/graphics/GraphicsCacheItem.C b/src/graphics/GraphicsCacheItem.C index 020cc1ec2b..833f29b169 100644 --- a/src/graphics/GraphicsCacheItem.C +++ b/src/graphics/GraphicsCacheItem.C @@ -14,311 +14,44 @@ #pragma implementation #endif -#include "graphics/GraphicsCache.h" #include "graphics/GraphicsCacheItem.h" #include "graphics/GraphicsImage.h" -#include "graphics/GraphicsParams.h" #include "graphics/GraphicsConverter.h" -#include "insets/insetgraphics.h" - -#include "BufferView.h" #include "debug.h" -#include "gettext.h" -#include "lyx_main.h" // for global dispatch method #include "support/LAssert.h" #include "support/filetools.h" #include -// Very, Very UGLY! -extern BufferView * current_view; - using std::endl; namespace grfx { -GCacheItem::GCacheItem(InsetGraphics const & inset, GParams const & params) - : filename_(params.filename), zipped_(false), +GCacheItem::GCacheItem(string const & file) + : filename_(file), zipped_(false), remove_loaded_file_(false), status_(WaitingToLoad) -{ - ModifiedItemPtr item(new ModifiedItem(inset, params, image_)); - modified_images.push_back(item); -} +{} -namespace { - -typedef GCacheItem::ModifiedItemPtr ModifiedItemPtr; - -class Compare_Params { -public: - Compare_Params(GParams const & p) : p_(p) {} - - bool operator()(ModifiedItemPtr const & ptr) - { - if (!ptr.get()) - return false; - return ptr->params() == p_; - } - -private: - GParams const & p_; -}; - -class Find_Inset { -public: - Find_Inset(InsetGraphics const & i) : i_(i) {} - - bool operator()(ModifiedItemPtr const & ptr) - { - if (!ptr.get()) - return false; - return ptr->referencedBy(i_); - } - -private: - InsetGraphics const & i_; -}; - -} // namespace anon - - -void GCacheItem::modify(InsetGraphics const & inset, GParams const & params) -{ - // Does this inset currently reference an existing ModifiedItem with - // different params? - // If so, remove the inset from the ModifiedItem's internal list - // of insets - ListType::iterator begin = modified_images.begin(); - ListType::iterator end = modified_images.end(); - ListType::iterator it = begin; - while (it != end) { - it = std::find_if(it, end, Find_Inset(inset)); - if (it == end) - break; - if ((*it)->params() != params) { - (*it)->remove(inset); - if ((*it)->empty()) - it = modified_images.erase(it); - } - ++it; - } - - // Is there an existing ModifiedItem with these params? - // If so, add inset to the list of insets referencing this ModifiedItem - begin = modified_images.begin(); - end = modified_images.end(); - it = std::find_if(begin, end, Compare_Params(params)); - if (it != end) { - (*it)->add(inset); - return; - } - - // If no ModifiedItem exists with these params, then create one. - ModifiedItemPtr item(new ModifiedItem(inset, params, image_)); - modified_images.push_back(item); - - return; -} - - -void GCacheItem::remove(InsetGraphics const & inset) -{ - // search the list of ModifiedItems for one referenced by this inset. - // If it is found, remove the reference. - // If the ModifiedItem is now referenced by no insets, remove it. - ListType::iterator begin = modified_images.begin(); - ListType::iterator end = modified_images.end(); - ListType::iterator it = std::find_if(begin, end, Find_Inset(inset)); - - if (it == end) - return; - - (*it)->remove(inset); - if ((*it)->empty()) { - modified_images.clear(); - } -} - - -void GCacheItem::startLoading(InsetGraphics const & inset) +void GCacheItem::startLoading() { if (status() != WaitingToLoad) return; - // Check that the image is referenced by this inset - ListType::const_iterator begin = modified_images.begin(); - ListType::const_iterator end = modified_images.end(); - ListType::const_iterator it = - std::find_if(begin, end, Find_Inset(inset)); - - if (it == end) - return; - - if ((*it)->params().display == GParams::NONE) - return; - convertToDisplayFormat(); } -bool GCacheItem::empty() const -{ - return modified_images.empty(); -} - - -bool GCacheItem::referencedBy(InsetGraphics const & inset) const -{ - // Is one of the list of ModifiedItems referenced by this inset? - ListType::const_iterator begin = modified_images.begin(); - ListType::const_iterator end = modified_images.end(); - return std::find_if(begin, end, Find_Inset(inset)) != end; -} - - -string const & GCacheItem::filename() const -{ - return filename_; -} - - -ImagePtr const GCacheItem::image(InsetGraphics const & inset) const -{ - // find a ModifiedItem that is referenced by this inset. - ListType::const_iterator begin = modified_images.begin(); - ListType::const_iterator end = modified_images.end(); - ListType::const_iterator it = - std::find_if(begin, end, Find_Inset(inset)); - - // Someone's being daft. - if (it == end) - return ImagePtr(); - - // We are expressly requested to not render the image - if ((*it)->params().display == GParams::NONE) - return ImagePtr(); - - // If the original image has been loaded, return what's going on - // in the ModifiedItem - if (status() == Loaded) - return (*it)->image(); - - return ImagePtr(); -} - - -ImageStatus GCacheItem::status(InsetGraphics const & inset) const -{ - // find a ModifiedItem that is referenced by this inset. - ListType::const_iterator begin = modified_images.begin(); - ListType::const_iterator end = modified_images.end(); - ListType::const_iterator it = - std::find_if(begin, end, Find_Inset(inset)); - - // Someone's being daft. - if (it == end) - return ErrorUnknown; - - if (status() == Loaded) - return (*it)->status(); - - return status(); -} - - -// Called internally only. Use to ascertain the status of the loading of the -// original image. No scaling etc. -ImageStatus GCacheItem::status() const -{ - return status_; -} - - void GCacheItem::setStatus(ImageStatus new_status) { + if (status_ == new_status) + return; + status_ = new_status; - - // Loop over all insets and tell the BufferView that it has changed. - typedef ModifiedItem::ListType::const_iterator inset_iterator; - - ListType::const_iterator it = modified_images.begin(); - ListType::const_iterator end = modified_images.end(); - for (; it != end; ++it) { - inset_iterator it2 = (*it)->insets.begin(); - inset_iterator end2 = (*it)->insets.end(); - - for (; it2 != end2; ++it2) { - InsetGraphics * inset = - const_cast(*it2); - - // Use of current_view is very, very Evil!! - current_view->updateInset(inset, false); - } - } -} - - -void GCacheItem::changeDisplay(bool changed_background) -{ - ListType::iterator begin = modified_images.begin(); - ListType::iterator end = modified_images.end(); - - // The background has changed. Change all modified images. - if (changed_background) { - for (ListType::iterator it = begin; it != end; ++it) { - (*it)->setPixmap(); - } - return; - } - - ListType temp_list; - - for (ListType::iterator it = begin; it != end; ++it) { - // ModifiedItem::changeDisplay returns a full - // ModifiedItemPtr if any of the insets have display=DEFAULT - // and if that DEFAULT value has changed - ModifiedItemPtr new_item = (*it)->changeDisplay(); - if (!new_item.get()) - continue; - - temp_list.push_back(new_item); - - // The original store may now be empty - if ((*it)->insets.empty()) { - it = modified_images.erase(it); - } - } - - if (temp_list.empty()) - return; - - // Recombine new_list and modified_images. - begin = modified_images.begin(); - end = modified_images.end(); - - ListType::const_iterator tbegin = temp_list.begin(); - ListType::const_iterator tend = temp_list.end(); - - ListType append_list; - - for (ListType::const_iterator tit = tbegin; tit != tend; ++tit) { - GParams const & params = (*tit)->params(); - ListType::iterator it = - std::find_if(begin, end, Compare_Params(params)); - if (it == end) - append_list.push_back(*tit); - else - (*it)->insets.merge((*tit)->insets); - } - - if (append_list.empty()) - return; - - modified_images.splice(modified_images.end(), append_list); + statusChanged(); } @@ -386,31 +119,6 @@ void GCacheItem::imageLoaded(bool success) } setStatus(Loaded); - - // Loop over the list of modified images and create them. - ListType::iterator it = modified_images.begin(); - ListType::iterator end = modified_images.end(); - for (; it != end; ++it) { - (*it)->modify(image_); - } -} - - -unsigned int GCacheItem::raw_width() const -{ - if (!image_.get()) - return 0; - - return image_->getWidth(); -} - - -unsigned int GCacheItem::raw_height() const -{ - if (!image_.get()) - return 0; - - return image_->getHeight(); } @@ -512,159 +220,4 @@ void GCacheItem::convertToDisplayFormat() graphics_converter.convert(filename, to_file_base, from, to, on_finish); } - -ModifiedItem::ModifiedItem(InsetGraphics const & new_inset, - GParams const & new_params, - ImagePtr const & new_image) - : status_(ScalingEtc) -{ - p_.reset(new GParams(new_params)); - insets.push_back(&new_inset); - modify(new_image); -} - - -void ModifiedItem::add(InsetGraphics const & inset) -{ - insets.push_back(&inset); - insets.sort(); -} - - -void ModifiedItem::remove(InsetGraphics const & inset) -{ - ListType::iterator begin = insets.begin(); - ListType::iterator end = insets.end(); - ListType::iterator it = std::remove(begin, end, &inset); - insets.erase(it, end); -} - - -bool ModifiedItem::referencedBy(InsetGraphics const & inset) const -{ - ListType::const_iterator begin = insets.begin(); - ListType::const_iterator end = insets.end(); - return std::find(begin, end, &inset) != end; -} - - -ImagePtr const ModifiedItem::image() const -{ - if (modified_image_.get()) - return modified_image_; - - return original_image_; -} - - -void ModifiedItem::modify(ImagePtr const & new_image) -{ - if (!new_image.get()) - return; - - original_image_ = new_image; - modified_image_.reset(original_image_->clone()); - - if (params().display == GParams::NONE) { - setStatus(Loaded); - return; - } - - setStatus(ScalingEtc); - modified_image_->clip(params()); - modified_image_->rotate(params()); - modified_image_->scale(params()); - setPixmap(); -} - - -void ModifiedItem::setPixmap() -{ - if (!modified_image_.get()) - return; - - if (params().display == GParams::NONE) { - setStatus(Loaded); - return; - } - - bool const success = modified_image_->setPixmap(params()); - - if (success) { - setStatus(Loaded); - } else { - modified_image_.reset(); - setStatus(ErrorScalingEtc); - } -} - - -void ModifiedItem::setStatus(ImageStatus new_status) -{ - status_ = new_status; - - // Tell the BufferView that the inset has changed. - // Very, Very Ugly!! - ListType::const_iterator it = insets.begin(); - ListType::const_iterator end = insets.end(); - for (; it != end; ++it) { - InsetGraphics * inset = const_cast(*it); - current_view->updateInset(inset, false); - } -} - - -namespace { - -struct Params_Changed { - - Params_Changed(GParams const & p) : p_(p) {} - - bool operator()(InsetGraphics const * inset) - { - string const path = OnlyPath(p_.filename); - return inset->params().asGParams(path) != p_; - } - -private: - GParams p_; -}; - -} // namespace anon - -// changeDisplay returns an initialised ModifiedItem if any of the insets -// have display == DEFAULT and if that DEFAULT value has changed. -// If this occurs, then (this) has these insets removed. -ModifiedItemPtr ModifiedItem::changeDisplay() -{ - // Loop over the list of insets. Compare the updated params for each - // with params(). If different, move into a new list. - ListType::iterator begin = insets.begin(); - ListType::iterator end = insets.end(); - ListType::iterator it = - std::remove_if(begin, end, Params_Changed(params())); - - if (it == end) { - // No insets have changed params - return ModifiedItemPtr(); - } - - // it -> end have params that are changed. Move to the new list. - ListType new_insets; - new_insets.insert(new_insets.begin(), it, end); - insets.erase(it, end); - - // Create a new ModifiedItem with these new params. Note that - // the only params that have changed are the display ones, - // so we don't need to crop, rotate, scale. - string const path = OnlyPath(p_->filename); - - ModifiedItemPtr new_item(new ModifiedItem(*this)); - new_item->insets = new_insets; - *(new_item->p_) = (*new_insets.begin())->params().asGParams(path); - - new_item->setPixmap(); - return new_item; -} - } // namespace grfx diff --git a/src/graphics/GraphicsCacheItem.h b/src/graphics/GraphicsCacheItem.h index fee78eb1a7..cbecced481 100644 --- a/src/graphics/GraphicsCacheItem.h +++ b/src/graphics/GraphicsCacheItem.h @@ -39,65 +39,37 @@ #include #include +#include #include #include #include -#include - class InsetGraphics; namespace grfx { -class GParams; -class ModifiedItem; - /// A grfx::GCache item holder. class GCacheItem : boost::noncopyable, public boost::signals::trackable { public: - /// the GCacheItem contains data of this type. - typedef boost::shared_ptr ModifiedItemPtr; - /// - GCacheItem(InsetGraphics const &, GParams const &); - - /// The params have changed (but still refer to this file). - void modify(InsetGraphics const &, GParams const &); - - /// Remove the reference to this inset. - void remove(InsetGraphics const &); + GCacheItem(string const & file); /// It's in the cache. Now start the loading process. - void startLoading(InsetGraphics const &); + void startLoading(); - /// Is the cache item referenced by any insets at all? - bool empty() const; - - /// The name of the original image file. - string const & filename() const; - - /// Is this image file referenced by this inset? - bool referencedBy(InsetGraphics const &) const; - - /** Returns the image referenced by this inset (or an empty container - * if it's not yet loaded. + /** Get the image associated with filename_. + If the image is not yet loaded, return a null pointer. */ - ImagePtr const image(InsetGraphics const &) const; + ImagePtr const image() const { return image_; } - /// The loading status of the image referenced by this inset. - ImageStatus status(InsetGraphics const &) const; + /// How far have we got in loading the image? + ImageStatus status() const { return status_; } - /** If (changed_background == true), then the background color of the - * graphics inset has changed. Update all images. - * Else, the preferred display type has changed. - * Update the view of all insets whose display type is DEFAULT. - */ - void changeDisplay(bool changed_background); + /// This signal is emitted when the image loading status changes. + boost::signal0 statusChanged; - /// Used to ascertain the Bounding Box of non (e)ps files. - unsigned int raw_width() const; /// - unsigned int raw_height() const; + string const & filename() const { return filename_; } private: /** Start the image conversion process, checking first that it is @@ -132,9 +104,6 @@ private: */ void imageLoaded(bool); - /// How far have we got in loading the original, unmodified image? - ImageStatus status() const; - /** Sets the status of the loading process. Also notifies * listeners that the status has chacnged. */ @@ -153,7 +122,7 @@ private: */ bool remove_loaded_file_; - /// The original, unmodified image and its loading status. + /// The image and its loading status. ImagePtr image_; /// ImageStatus status_; @@ -163,7 +132,7 @@ private: * When the image has been loaded, the signal is emitted. * * We pass a shared_ptr because it is eminently possible for the - * ModifiedItem to be destructed before the loading is complete and + * GCacheItem to be destructed before the loading is complete and * the signal must remain in scope. It doesn't matter if the slot * disappears, SigC takes care of that. */ @@ -186,76 +155,6 @@ private: /// The connection of the signal passed to GConverter::convert. boost::signals::connection cc_; - - /// The list of all modified images. - typedef std::list ListType; - /// - ListType modified_images; -}; - - -/// -class ModifiedItem { -public: - /// - ModifiedItem(InsetGraphics const &, GParams const &, ImagePtr const &); - - /// - GParams const & params() { return *p_.get(); } - - /// Add inset to the list of insets. - void add(InsetGraphics const & inset); - - /// Remove inset from the list of insets. - void remove(InsetGraphics const & inset); - - /// - bool empty() const { return insets.empty(); } - - /// Is this ModifiedItem referenced by inset? - bool referencedBy(InsetGraphics const & inset) const; - - /// - ImagePtr const image() const; - - /// How far have we got in loading the modified image? - ImageStatus status() const { return status_; } - - /** Called from GCacheItem once the raw image is loaded. - * Modifies the image in accord with p_. - */ - void modify(ImagePtr const &); - - /// Updates the pixmap. - void setPixmap(); - - /** changeDisplay returns a full ModifiedItemPtr if any of the - * insets have display=DEFAULT and if that DEFAULT value has - * changed. - * If this occurs, then this has these insets removed. - */ - boost::shared_ptr changeDisplay(); - - /// - typedef std::list ListType; - - /// Make these accessible for changeDisplay. - ListType insets; - -private: - /** Sets the status of the loading process. Also notifies - * listeners that the status has changed. - */ - void setStatus(ImageStatus new_status); - - /// The original and modified images and its loading status. - ImagePtr original_image_; - /// - ImagePtr modified_image_; - /// - ImageStatus status_; - /// - boost::shared_ptr p_; }; } // namespace grfx diff --git a/src/graphics/GraphicsParams.C b/src/graphics/GraphicsParams.C index a4481d7c46..7245cd076e 100644 --- a/src/graphics/GraphicsParams.C +++ b/src/graphics/GraphicsParams.C @@ -20,7 +20,8 @@ namespace grfx { GParams::GParams() - : width(0), + : display(COLOR), + width(0), height(0), scale(0), angle(0) diff --git a/src/graphics/GraphicsTypes.h b/src/graphics/GraphicsTypes.h index c99187f8cb..fecd1e5352 100644 --- a/src/graphics/GraphicsTypes.h +++ b/src/graphics/GraphicsTypes.h @@ -26,6 +26,10 @@ namespace grfx { class GImage; /// typedef boost::shared_ptr ImagePtr; + /// + class GCacheItem; + /// The cache contains data of this type. + typedef boost::shared_ptr GraphicPtr; /// The status of the loading process enum ImageStatus { diff --git a/src/insets/ChangeLog b/src/insets/ChangeLog index d60be2f84a..476a85d44c 100644 --- a/src/insets/ChangeLog +++ b/src/insets/ChangeLog @@ -1,3 +1,10 @@ +2002-06-25 Angus Leeming + + * insetgraphics.[Ch]: The inset now assumes the responsibility for + generating a pixmap once the graphics file is loaded into memory. + The current_view ugliness that was in grfx::ModifiedImage has been + moved here now that grfx::ModifiedImage is no more. + 2002-06-24 Lars Gullik Bjønnes * insettext.C: layout as layout diff --git a/src/insets/insetgraphics.C b/src/insets/insetgraphics.C index 4ace559e77..5c2f2bbc6c 100644 --- a/src/insets/insetgraphics.C +++ b/src/insets/insetgraphics.C @@ -79,6 +79,7 @@ TODO Before initial production release: #include "insets/insetgraphicsParams.h" #include "graphics/GraphicsCache.h" +#include "graphics/GraphicsCacheItem.h" #include "graphics/GraphicsImage.h" #include "frontends/LyXView.h" @@ -103,8 +104,13 @@ TODO Before initial production release: #include "support/path.h" #include "support/systemcall.h" +#include + #include // For the std::max +// Very, Very UGLY! +extern BufferView * current_view; + extern string system_tempdir; using std::ostream; @@ -143,10 +149,173 @@ string const uniqueID() } // namespace anon +struct InsetGraphics::Cache +{ + /// + Cache(InsetGraphics &); + /// + ~Cache(); + /// + void reset(grfx::GraphicPtr const &); + /// + bool empty() const { return !graphic_.get(); } + /// + grfx::ImageStatus status() const; + /// + void setStatus(grfx::ImageStatus); + /// + grfx::GImage * image() const; + /// + string const filename() const; + /// + void update(string const & file_with_path); + /// + void modify(); + + /// + int old_ascent; + /// + grfx::GraphicPtr graphic_; + +private: + /// The connection to cache_->statusChanged. + boost::signals::connection cc_; + /// + grfx::ImageStatus status_; + /// + grfx::GParams params_; + /// + grfx::ImagePtr modified_image_; + /// + InsetGraphics & parent_; +}; + + +InsetGraphics::Cache::Cache(InsetGraphics & p) + : old_ascent(0), status_(grfx::ErrorUnknown), parent_(p) +{} + + +InsetGraphics::Cache::~Cache() +{ + string const old_file = filename(); + graphic_.reset(); + + if (!old_file.empty()) { + grfx::GCache & gc = grfx::GCache::get(); + gc.remove(old_file); + } +} + + +void InsetGraphics::Cache::reset(grfx::GraphicPtr const & graphic) +{ + string const old_file = filename(); + string const new_file = graphic.get() ? graphic->filename() : string(); + if (old_file == new_file) + return; + + graphic_ = graphic; + + if (!old_file.empty()) { + grfx::GCache & gc = grfx::GCache::get(); + gc.remove(old_file); + } +} + + +grfx::ImageStatus InsetGraphics::Cache::status() const +{ + return status_; +} + + +void InsetGraphics::Cache::setStatus(grfx::ImageStatus new_status) +{ + status_ = new_status; +} + + +grfx::GImage * InsetGraphics::Cache::image() const +{ + return modified_image_.get(); +} + + +string const InsetGraphics::Cache::filename() const +{ + return empty() ? string() : graphic_->filename(); +} + + +void InsetGraphics::Cache::update(string const & file_with_path) +{ + lyx::Assert(!file_with_path.empty()); + + // Check whether the file has changed. + string current_file = filename(); + + if (current_file == file_with_path) { + modify(); + return; + } + + // It /has/ changed. + // Remove the connection to any previous grfx::CacheItems + grfx::GCache & gc = grfx::GCache::get(); + if (!current_file.empty() && gc.inCache(current_file)) { + graphic_.reset(); + gc.remove(current_file); + cc_.disconnect(); + } + + // Update the cache to point to the new file + if (!gc.inCache(file_with_path)) + gc.add(file_with_path); + + graphic_ = gc.graphic(file_with_path); + cc_ = graphic_->statusChanged.connect( + boost::bind(&InsetGraphics::statusChanged, &parent_)); + + setStatus(graphic_->status()); + if (status() == grfx::Loaded) + modify(); +} + + +void InsetGraphics::Cache::modify() +{ + // The image has not been loaded from file + if (!graphic_->image().get()) + return; + + string const path = OnlyPath(filename()); + grfx::GParams params = parent_.params().asGParams(path); + + if (params == params_) + return; + + params_ = params; + setStatus(grfx::ScalingEtc); + modified_image_.reset(graphic_->image()->clone()); + modified_image_->clip(params); + modified_image_->rotate(params); + modified_image_->scale(params); + + bool const success = modified_image_->setPixmap(params); + + if (success) { + setStatus(grfx::Loaded); + } else { + modified_image_.reset(); + setStatus(grfx::ErrorScalingEtc); + } +} + + InsetGraphics::InsetGraphics() : graphic_label(uniqueID()), - cached_status_(grfx::ErrorUnknown), cache_filled_(false), old_asc(0) - + cache_(new Cache(*this)) {} @@ -155,7 +324,7 @@ InsetGraphics::InsetGraphics(InsetGraphics const & ig, bool same_id) : Inset(ig, same_id), graphic_label(uniqueID()), - cached_status_(grfx::ErrorUnknown), cache_filled_(false), old_asc(0) + cache_(new Cache(*this)) { setParams(ig.params(), filepath); } @@ -163,10 +332,7 @@ InsetGraphics::InsetGraphics(InsetGraphics const & ig, InsetGraphics::~InsetGraphics() { - cached_image_.reset(); - grfx::GCache & gc = grfx::GCache::get(); - gc.remove(*this); - + cache_->reset(grfx::GraphicPtr()); // Emits the hide signal to the dialog connected (if any) hideDialog(); } @@ -176,7 +342,7 @@ string const InsetGraphics::statusMessage() const { string msg; - switch (cached_status_) { + switch (cache_->status()) { case grfx::WaitingToLoad: msg = _("Waiting for draw request to start loading..."); break; @@ -187,7 +353,10 @@ string const InsetGraphics::statusMessage() const msg = _("Converting to loadable format..."); break; case grfx::ScalingEtc: - msg = _("Loaded. Scaling etc..."); + msg = _("Scaling etc..."); + break; + case grfx::Loaded: + msg = _("Loaded."); break; case grfx::ErrorNoFile: msg = _("No file found!"); @@ -204,43 +373,27 @@ string const InsetGraphics::statusMessage() const case grfx::ErrorUnknown: msg = _("No image"); break; - case grfx::Loaded: - msg = _("Loaded but not displaying"); - break; } return msg; } -void InsetGraphics::setCache() const +bool InsetGraphics::imageIsDrawable() const { - if (cache_filled_) - return; + if (!cache_->image() || cache_->status() != grfx::Loaded) + return false; - grfx::GCache & gc = grfx::GCache::get(); - cached_status_ = gc.status(*this); - cached_image_ = gc.image(*this); -} - - -bool InsetGraphics::drawImage() const -{ - setCache(); - Pixmap const pixmap = - (cached_status_ == grfx::Loaded && cached_image_.get() != 0) ? - cached_image_->getPixmap() : 0; - - return pixmap != 0; + return cache_->image()->getPixmap() != 0; } int InsetGraphics::ascent(BufferView *, LyXFont const &) const { - old_asc = 50; - if (drawImage()) - old_asc = cached_image_->getHeight(); - return old_asc; + cache_->old_ascent = 50; + if (imageIsDrawable()) + cache_->old_ascent = cache_->image()->getHeight(); + return cache_->old_ascent; } @@ -252,8 +405,8 @@ int InsetGraphics::descent(BufferView *, LyXFont const &) const int InsetGraphics::width(BufferView *, LyXFont const & font) const { - if (drawImage()) - return cached_image_->getWidth(); + if (imageIsDrawable()) + return cache_->image()->getWidth(); else { int font_width = 0; @@ -281,8 +434,7 @@ int InsetGraphics::width(BufferView *, LyXFont const & font) const void InsetGraphics::draw(BufferView * bv, LyXFont const & font, int baseline, float & x, bool) const { - int oasc = old_asc; - grfx::ImageStatus old_status_ = cached_status_; + int oasc = cache_->old_ascent; int ldescent = descent(bv, font); int lascent = ascent(bv, font); @@ -301,20 +453,18 @@ void InsetGraphics::draw(BufferView * bv, LyXFont const & font, int old_x = int(x); x += lwidth; - // Initiate the loading of the graphics file - if (cached_status_ == grfx::WaitingToLoad) { - grfx::GCache & gc = grfx::GCache::get(); - gc.startLoading(*this); + if (cache_->status() == grfx::WaitingToLoad) { + cache_->graphic_->startLoading(); } // This will draw the graphics. If the graphics has not been loaded yet, // we draw just a rectangle. Painter & paint = bv->painter(); - if (drawImage()) { + if (imageIsDrawable()) { paint.image(old_x + 2, baseline - lascent, lwidth - 4, lascent + ldescent, - *cached_image_.get()); + *cache_->image()); } else { @@ -343,24 +493,18 @@ void InsetGraphics::draw(BufferView * bv, LyXFont const & font, // the status message may mean we changed size, so indicate // we need a row redraw +#if 0 if (old_status_ != grfx::ErrorUnknown && old_status_ != cached_status_) { bv->getLyXText()->status(bv, LyXText::CHANGED_IN_DRAW); } +#endif // Reset the cache, ready for the next draw request +#if 0 cached_status_ = grfx::ErrorUnknown; cached_image_.reset(); cache_filled_ = false; -} - - -// Update the inset after parameters changed (read from file or changed in -// dialog. The grfx::GCache makes the decisions about whether or not to draw -// (interogates lyxrc, ascertains whether file exists etc) -void InsetGraphics::updateInset(string const & filepath) const -{ - grfx::GCache & gc = grfx::GCache::get(); - gc.update(*this, filepath); +#endif } @@ -400,7 +544,7 @@ void InsetGraphics::read(Buffer const * buf, LyXLex & lex) else lyxerr[Debug::GRAPHICS] << "Not a Graphics or Figure inset!\n"; - updateInset(buf->filePath()); + cache_->update(MakeAbsPath(params().filename, buf->filePath())); } @@ -864,6 +1008,16 @@ void InsetGraphics::validate(LaTeXFeatures & features) const } +void InsetGraphics::statusChanged() +{ + cache_->setStatus(cache_->graphic_->status()); + if (cache_->status() == grfx::Loaded) + cache_->modify(); + + current_view->updateInset(this, false); +} + + bool InsetGraphics::setParams(InsetGraphicsParams const & p, string const & filepath) { @@ -876,7 +1030,7 @@ bool InsetGraphics::setParams(InsetGraphicsParams const & p, params_ = p; // Update the inset with the new parameters. - updateInset(filepath); + cache_->update(MakeAbsPath(params().filename, filepath)); // We have changed data, report it. return true; diff --git a/src/insets/insetgraphics.h b/src/insets/insetgraphics.h index 7aa5967d37..9bcbcf2e95 100644 --- a/src/insets/insetgraphics.h +++ b/src/insets/insetgraphics.h @@ -27,6 +27,8 @@ #include #include +#include // auto_ptr + class Dialogs; class LaTeXFeatures; @@ -98,18 +100,19 @@ public: boost::signal0 hideDialog; private: - /// Set the cached variables - void setCache() const; /// Is the image ready to draw, or should we display a message instead? - bool drawImage() const; + bool imageIsDrawable() const; + + /** This method is connected to cache_->statusChanged, so we are + informed when the image has been loaded. + */ + void statusChanged(); /// Read the inset native format void readInsetGraphics(LyXLex & lex); /// Read the FigInset file format void readFigInset(LyXLex & lex); - /// Update the inset after parameter change. - void updateInset(string const & filepath) const; /// Get the status message, depends on the image loading status. string const statusMessage() const; /// Create the options for the latex command. @@ -124,13 +127,13 @@ private: string const graphic_label; /// The cached variables - mutable grfx::ImageStatus cached_status_; - /// - mutable grfx::ImagePtr cached_image_; - /// - mutable bool cache_filled_; - /// - mutable int old_asc; + class Cache; + friend class Cache; + /** Can change the contents of the cache, but not the pointer. + * Use std::auto_ptr not boost::scoped_ptr so we do not have to define + * Cache in advance. + */ + std::auto_ptr const cache_; }; #endif diff --git a/src/lyxfunc.C b/src/lyxfunc.C index 13ec8c88e7..6b722a70b7 100644 --- a/src/lyxfunc.C +++ b/src/lyxfunc.C @@ -1634,8 +1634,13 @@ string const LyXFunc::dispatch(kb_action action, string argument) lyxColorHandler->updateColor(lcolor.getFromLyXName(lyx_name)); if (graphicsbg_changed) { +#ifdef WITH_WARNINGS +#warning FIXME!! The graphics cache no longer has a changeDisplay method. +#endif +#if 0 grfx::GCache & gc = grfx::GCache::get(); gc.changeDisplay(true); +#endif } owner->view()->repaint();