* Split the graphics loader into a frontend and a backend.

* Add frontend code to generate and display the pixmap to InsetGraphics.
* Add (much simpler) frontend code to the LyXScreen to show the splash screen
once more.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4480 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Angus Leeming 2002-06-25 15:59:10 +00:00
parent 254272868f
commit 514156adbb
17 changed files with 557 additions and 839 deletions

View File

@ -1,3 +1,10 @@
2002-06-25 Angus Leeming <leeming@lyx.org>
* 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 <larsbj@birdstep.com>
* text2.C: layout as layout

View File

@ -1,3 +1,8 @@
2002-06-25 Angus Leeming <leeming@lyx.org>
* ControlGraphics.C (readBB): Channges associated with the changed
interface to the graphics cache.
2002-06-24 Lars Gullik Bjønnes <larsbj@birdstep.com>
* ControlParagraph.C: layout as layout

View File

@ -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));
}

View File

@ -4,6 +4,8 @@
* Read the file COPYING
*
* \author John Levon <moz@compsoc.man.ac.uk>
*
* 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 <boost/utility.hpp>
#include <boost/bind.hpp>
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
}

View File

@ -1,3 +1,10 @@
2002-06-25 Angus Leeming <leeming@lyx.org>
* 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 <larsbj@birdstep.com>
* Toolbar_pimpl.C: layout as layout

View File

@ -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
}

View File

@ -1,3 +1,15 @@
2002-06-25 Angus Leeming <leeming@lyx.org>
* 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 <leeming@lyx.org>
* GraphicsConverter.C: add using std::endl directive.

View File

@ -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<string> 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<string> GCache::loadableFormats() const {
return GImage::loadableFormats();
}
} // namespace grfx

View File

@ -27,74 +27,64 @@
#include <vector>
#include <boost/utility.hpp>
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<string> 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<GCacheItem> 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<string, CacheItemType> CacheType;
/// Search the cache by inset.
CacheType::const_iterator find(InsetGraphics const &) const;
///
CacheType::iterator find(InsetGraphics const &);
typedef std::map<string, GraphicPtr> CacheType;
/** Store a pointer to the cache so that we can forward declare
* GCacheItem.

View File

@ -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 <boost/bind.hpp>
// 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<InsetGraphics *>(*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<InsetGraphics *>(*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

View File

@ -39,65 +39,37 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/signals/signal0.hpp>
#include <boost/signals/signal1.hpp>
#include <boost/signals/connection.hpp>
#include <boost/signals/trackable.hpp>
#include <list>
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<ModifiedItem> 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<void> 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<ModifiedItemPtr> 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<ModifiedItem> changeDisplay();
///
typedef std::list<InsetGraphics const *> 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<GParams> p_;
};
} // namespace grfx

View File

@ -20,7 +20,8 @@
namespace grfx {
GParams::GParams()
: width(0),
: display(COLOR),
width(0),
height(0),
scale(0),
angle(0)

View File

@ -26,6 +26,10 @@ namespace grfx {
class GImage;
///
typedef boost::shared_ptr<GImage> ImagePtr;
///
class GCacheItem;
/// The cache contains data of this type.
typedef boost::shared_ptr<GCacheItem> GraphicPtr;
/// The status of the loading process
enum ImageStatus {

View File

@ -1,3 +1,10 @@
2002-06-25 Angus Leeming <leeming@lyx.org>
* 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 <larsbj@birdstep.com>
* insettext.C: layout as layout

View File

@ -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 <boost/bind.hpp>
#include <algorithm> // 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;

View File

@ -27,6 +27,8 @@
#include <boost/signals/signal0.hpp>
#include <boost/signals/trackable.hpp>
#include <memory> // auto_ptr
class Dialogs;
class LaTeXFeatures;
@ -98,18 +100,19 @@ public:
boost::signal0<void> 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<Cache> const cache_;
};
#endif

View File

@ -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();