Asymptotic approach to a well-designed graphics loader.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4502 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Angus Leeming 2002-06-28 11:22:56 +00:00
parent c3a3e12319
commit 888532c465
37 changed files with 804 additions and 762 deletions

View File

@ -1,3 +1,9 @@
2002-06-28 Angus Leeming <leeming@lyx.org>
* Painter.h:
* screen.C: changes associated with the name change grfx::GImage ->
grfx::Image.
2002-06-26 Angus Leeming <leeming@lyx.org>
* screen.C: moved the image loading stuff into a new class grfx::Loader.

View File

@ -21,7 +21,7 @@
class LyXFont;
namespace grfx {
class GImage;
class Image;
}
/**
@ -133,7 +133,7 @@ public:
/// draw an image from the image cache
virtual Painter & image(int x, int y,
int w, int h,
grfx::GImage const & image) = 0;
grfx::Image const & image) = 0;
/// draw a string at position x, y (y is the baseline)
virtual Painter & text(int x, int y,

View File

@ -1,3 +1,8 @@
2002-06-28 Angus Leeming <leeming@lyx.org>
* ControlGraphics.C: changes associated with the name changes
grfx::GCache -> grfx::Cache and grfx::GImage -> grfx::Image.
2002-06-25 Angus Leeming <leeming@lyx.org>
* ControlGraphics.C (readBB): Channges associated with the changed

View File

@ -31,7 +31,7 @@
#include "lyxrc.h"
#include "graphics/GraphicsCache.h"
#include "graphics/GraphicsConverter.h"
#include "graphics/GraphicsCacheItem.h"
#include "graphics/GraphicsImage.h"
#include "insets/insetgraphics.h"
@ -114,12 +114,14 @@ string const ControlGraphics::readBB(string const & file)
int width = 0;
int height = 0;
grfx::GCache & gc = grfx::GCache::get();
grfx::ImagePtr const image = gc.image(abs_file);
grfx::Cache & gc = grfx::Cache::get();
if (gc.inCache(abs_file)) {
grfx::Image const * image = gc.item(abs_file)->image();
if (image.get()) {
width = image->getWidth();
height = image->getHeight();
if (image) {
width = image->getWidth();
height = image->getHeight();
}
}
return ("0 0 " + tostr(width) + ' ' + tostr(height));

View File

@ -1,3 +1,8 @@
2002-06-28 Angus Leeming <leeming@lyx.org>
* QLPainter.[Ch]: changes associated with the name change
grfx::GImage -> grfx::Image.
2002-06-21 Angus Leeming <leeming@lyx.org>
* Menubar_pimpl.C (c-tor): rename MenuBackend const & mb argument to

View File

@ -186,7 +186,7 @@ Painter & QLPainter::arc(int x, int y,
Painter & QLPainter::image(int , int ,
int , int ,
grfx::GImage const & )
grfx::Image const & )
{
#if 0 // FIXME
XGCValues val;

View File

@ -101,7 +101,7 @@ public:
/// draw an image from the image cache
virtual Painter & image(int x, int y,
int w, int h,
grfx::GImage const & image);
grfx::Image const & image);
/// draw a string at position x, y (y is the baseline)
virtual Painter & text(int x, int y,

View File

@ -49,7 +49,7 @@ public:
/// This is a singleton class. Get the instance.
static SplashScreen const & get();
///
grfx::GImage const * image() const { return loader_.image(); }
grfx::Image const * image() const { return loader_.image(); }
///
string const & text() const { return text_; }
///
@ -376,7 +376,7 @@ void LyXScreen::greyOut()
// Add a splash screen to the centre of the work area
SplashScreen const & splash = SplashScreen::get();
grfx::GImage const * const splash_image = splash.image();
grfx::Image const * const splash_image = splash.image();
if (splash_image) {
int const w = splash_image->getWidth();
int const h = splash_image->getHeight();

View File

@ -1,3 +1,14 @@
2002-06-28 Angus Leeming <leeming@lyx.org>
* XPainter.[Ch]: changes associated with the name change
grfx::GImage -> grfx::Image.
* xformsGImage.[Ch]: deleted.
* xformsImage.[Ch]: new files, reflecting changed class name.
* Makefile.am:
* lyx_gui.C: associated changes.
2002-06-27 Juergen Spitzmueller <j.spitzmueller@gmx.de>
* FormPreferences.C

View File

@ -9,11 +9,11 @@ INCLUDES = -I$(top_srcdir)/images -I$(top_srcdir)/src/ \
SUBDIRS = forms
EXTRA_DIST = xformsGImage.C xformsGImage.h
EXTRA_DIST = xformsImage.C xformsImage.h
if USE_BASIC_IMAGE_LOADER
else
XFORMSGIMAGE = xformsGImage.C xformsGImage.h
XFORMSIMAGE = xformsImage.C xformsImage.h
endif
# Alphabetical order please. It makes it easier to figure out what's missing.
@ -38,7 +38,7 @@ libxforms_la_SOURCES = \
xforms_helpers.h \
xforms_resize.C \
xforms_resize.h \
$(XFORMSGIMAGE) xformsBC.C \
$(XFORMSIMAGE) xformsBC.C \
xformsBC.h \
xscreen.C \
xscreen.h \

View File

@ -150,7 +150,7 @@ Painter & XPainter::arc(int x, int y,
Painter & XPainter::image(int x, int y,
int w, int h,
grfx::GImage const & image)
grfx::Image const & image)
{
XGCValues val;
val.function = GXcopy;

View File

@ -96,7 +96,7 @@ public:
/// draw an image from the image cache
virtual Painter & image(int x, int y,
int w, int h,
grfx::GImage const & image);
grfx::Image const & image);
/// draw a string at position x, y (y is the baseline)
virtual Painter & text(int x, int y,

View File

@ -32,7 +32,7 @@
#include "ColorHandler.h"
#include "xforms_helpers.h"
#ifdef USE_XFORMS_IMAGE_LOADER
#include "xformsGImage.h"
#include "xformsImage.h"
#else
#include "graphics/GraphicsImageXPM.h"
#endif
@ -300,11 +300,11 @@ void lyx_gui::init_graphics()
#ifdef USE_XFORMS_IMAGE_LOADER
// connect the image loader based on the xforms library
GImage::newImage.connect(boost::bind(&xformsGImage::newImage));
GImage::loadableFormats.connect(boost::bind(&xformsGImage::loadableFormats));
Image::newImage.connect(boost::bind(&xformsImage::newImage));
Image::loadableFormats.connect(boost::bind(&xformsImage::loadableFormats));
#else
// connect the image loader based on the XPM library
GImage::newImage.connect(boost::bind(&GImageXPM::newImage));
GImage::loadableFormats.connect(boost::bind(&GImageXPM::loadableFormats));
Image::newImage.connect(boost::bind(&ImageXPM::newImage));
Image::loadableFormats.connect(boost::bind(&ImageXPM::loadableFormats));
#endif
}

View File

@ -1,5 +1,5 @@
/*
* \file xformsGImage.C
* \file xformsImage.C
* Copyright 2002 the LyX Team
* Read the file COPYING
*
@ -12,7 +12,7 @@
#pragma implementation
#endif
#include "xformsGImage.h"
#include "xformsImage.h"
#include "graphics/GraphicsParams.h"
#include "LColor.h"
#include "converter.h" // formats
@ -44,18 +44,18 @@ unsigned int packedcolor(LColor::color c);
namespace grfx {
/// Access to this class is through this static method.
ImagePtr xformsGImage::newImage()
Image::ImagePtr xformsImage::newImage()
{
init_graphics();
ImagePtr ptr;
ptr.reset(new xformsGImage);
ptr.reset(new xformsImage);
return ptr;
}
/// Return the list of loadable formats.
GImage::FormatList xformsGImage::loadableFormats()
Image::FormatList xformsImage::loadableFormats()
{
static FormatList fmts;
if (!fmts.empty())
@ -111,15 +111,15 @@ GImage::FormatList xformsGImage::loadableFormats()
}
xformsGImage::xformsGImage()
xformsImage::xformsImage()
: image_(0),
pixmap_(0),
pixmap_status_(PIXMAP_UNINITIALISED)
{}
xformsGImage::xformsGImage(xformsGImage const & other)
: GImage(other),
xformsImage::xformsImage(xformsImage const & other)
: Image(other),
image_(0),
pixmap_(0),
pixmap_status_(PIXMAP_UNINITIALISED)
@ -131,7 +131,7 @@ xformsGImage::xformsGImage(xformsGImage const & other)
}
xformsGImage::~xformsGImage()
xformsImage::~xformsImage()
{
if (image_)
flimage_free(image_);
@ -140,13 +140,13 @@ xformsGImage::~xformsGImage()
}
GImage * xformsGImage::clone() const
Image * xformsImage::clone() const
{
return new xformsGImage(*this);
return new xformsImage(*this);
}
unsigned int xformsGImage::getWidth() const
unsigned int xformsImage::getWidth() const
{
if (!image_)
return 0;
@ -154,7 +154,7 @@ unsigned int xformsGImage::getWidth() const
}
unsigned int xformsGImage::getHeight() const
unsigned int xformsImage::getHeight() const
{
if (!image_)
return 0;
@ -162,7 +162,7 @@ unsigned int xformsGImage::getHeight() const
}
Pixmap xformsGImage::getPixmap() const
Pixmap xformsImage::getPixmap() const
{
if (!pixmap_status_ == PIXMAP_SUCCESS)
return 0;
@ -170,12 +170,12 @@ Pixmap xformsGImage::getPixmap() const
}
void xformsGImage::load(string const & filename, SignalTypePtr on_finish)
void xformsImage::load(string const & filename)
{
if (image_) {
lyxerr[Debug::GRAPHICS]
<< "Image is loaded already!" << std::endl;
on_finish->operator()(false);
finishedLoading(false);
return;
}
@ -183,13 +183,10 @@ void xformsGImage::load(string const & filename, SignalTypePtr on_finish)
if (!image_) {
lyxerr[Debug::GRAPHICS]
<< "Unable to open image" << std::endl;
on_finish->operator()(false);
finishedLoading(false);
return;
}
// Store the Signal that will be emitted once the image is loaded.
on_finish_ = on_finish;
// Set this now and we won't need to bother again.
image_->fill_color = packedcolor(LColor::graphicsbg);
@ -201,7 +198,7 @@ void xformsGImage::load(string const & filename, SignalTypePtr on_finish)
}
bool xformsGImage::setPixmap(GParams const & params)
bool xformsImage::setPixmap(Params const & params)
{
if (!image_ || params.display == NoDisplay)
return false;
@ -248,7 +245,7 @@ bool xformsGImage::setPixmap(GParams const & params)
}
void xformsGImage::clip(GParams const & params)
void xformsImage::clip(Params const & params)
{
if (!image_)
return;
@ -279,7 +276,7 @@ void xformsGImage::clip(GParams const & params)
}
void xformsGImage::rotate(GParams const & params)
void xformsImage::rotate(Params const & params)
{
if (!image_)
return ;
@ -303,7 +300,7 @@ void xformsGImage::rotate(GParams const & params)
}
void xformsGImage::scale(GParams const & params)
void xformsImage::scale(Params const & params)
{
if (!image_)
return;
@ -322,9 +319,9 @@ void xformsGImage::scale(GParams const & params)
}
void xformsGImage::statusCB(string const & status_message)
void xformsImage::statusCB(string const & status_message)
{
if (status_message.empty() || !on_finish_.get())
if (status_message.empty())
return;
if (prefixIs(status_message, "Done Reading")) {
@ -332,27 +329,21 @@ void xformsGImage::statusCB(string const & status_message)
flimage_close(image_);
}
if (on_finish_.get()) {
on_finish_->operator()(true);
on_finish_.reset();
}
finishedLoading(true);
}
}
void xformsGImage::errorCB(string const & error_message)
void xformsImage::errorCB(string const & error_message)
{
if (error_message.empty() || !on_finish_.get())
if (error_message.empty())
return;
if (image_) {
flimage_close(image_);
}
if (on_finish_.get()) {
on_finish_->operator()(false);
on_finish_.reset();
}
finishedLoading(false);
}
} // namespace grfx
@ -373,8 +364,8 @@ int status_report(FL_IMAGE * ob, const char *s)
lyxerr[Debug::GRAPHICS]
<< "xforms image loader. Status : " << str << std::endl;
grfx::xformsGImage * ptr =
static_cast<grfx::xformsGImage *>(ob->u_vdata);
grfx::xformsImage * ptr =
static_cast<grfx::xformsImage *>(ob->u_vdata);
ptr->statusCB(str);
return 0;
@ -392,8 +383,8 @@ static void error_report(FL_IMAGE * ob, const char *s)
lyxerr[Debug::GRAPHICS]
<< "xforms image loader. Error : " << str << std::endl;
grfx::xformsGImage * ptr =
static_cast<grfx::xformsGImage *>(ob->u_vdata);
grfx::xformsImage * ptr =
static_cast<grfx::xformsImage *>(ob->u_vdata);
ptr->errorCB(str);
}

View File

@ -1,18 +1,18 @@
// -*- C++ -*-
/**
* \file xformsGImage.h
* \file xformsImage.h
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* \author Angus Leeming, a.leeming@ic.ac.uk
*/
/* An instantiation of GImage that makes use of the xforms lirary routines
/* An instantiation of Image that makes use of the xforms lirary routines
* to load and store the image in memory.
*/
#ifndef XFORMS_GRAPHICSIMAGE_H
#define XFORMS_GRAPHICSIMAGE_H
#ifndef XFORMSIMAGE_H
#define XFORMSIMAGE_H
#ifdef __GNUG__
#pragma interface
@ -25,7 +25,7 @@ typedef flimage_ FL_IMAGE;
namespace grfx {
class xformsGImage : public GImage
class xformsImage : public Image
{
public:
/// Access to this class is through this static method.
@ -35,10 +35,10 @@ public:
static FormatList loadableFormats();
///
~xformsGImage();
~xformsImage();
/// Create a copy
GImage * clone() const;
Image * clone() const;
///
Pixmap getPixmap() const;
@ -50,26 +50,26 @@ public:
unsigned int getHeight() const;
/** Load the image file into memory.
* The process is asynchronous, so this method starts the loading
* and saves the signal. It is emitted once loading is finished.
* The process is asynchronous, so this method starts the loading.
* When finished, the Image::finishedLoading signal is emitted.
*/
void load(string const & filename, SignalTypePtr);
void load(string const & filename);
/** Generate the pixmap, based on the current state of
* image_ (clipped, rotated, scaled etc).
* Uses the params to decide on color, grayscale etc.
* Returns true if the pixmap is created.
*/
bool setPixmap(GParams const & params);
bool setPixmap(Params const & params);
/// Clip the image using params.
void clip(GParams const & params);
void clip(Params const & params);
/// Rotate the image using params.
void rotate(GParams const & params);
void rotate(Params const & params);
/// Scale the image using params.
void scale(GParams const & params);
void scale(Params const & params);
/// Internal callbacks.
void statusCB(string const &);
@ -78,9 +78,9 @@ public:
private:
/// Access to the class is through newImage() and clone.
xformsGImage();
xformsImage();
///
xformsGImage(xformsGImage const &);
xformsImage(xformsImage const &);
/// The xforms container.
FL_IMAGE * image_;
@ -99,11 +99,8 @@ private:
};
PixmapStatus pixmap_status_;
/// Emit this signal when the loading process is finished.
GImage::SignalTypePtr on_finish_;
};
} // namespace grfx
#endif // XFORMS_GRAPHICSIMAGE_H
#endif // XFORMSIMAGE_H

View File

@ -1,3 +1,38 @@
2002-06-28 Angus Leeming <leeming@lyx.org>
* GraphicsCacheItem.[Ch]: refactor some of the more convoluted logic
by moving those SignalPtrs into the grfx::Image and grfx::Converter
classes where they really belong.
Use the Pimpl idiom to hide the class internals from public view.
* GraphicsTypes: remove the typedefs, leaving only the enums.
* GraphicsImage.h: now has a finishedLoading signal, as opposed to being
passed a reference to one in the load() method.
* GraphicsConverter.[Ch]: totally refactored. An instance of
grfx::Converter now represents a single conversion process.
Thus grfx::CachItem now has a grfx::Converter * that is set when the
conversion is initiated and destroyed on completion.
* GraphicsCache.[Ch]:
* GraphicsCacheItem.[Ch]:
* GraphicsConverter.[Ch]:
* GraphicsLoader.[Ch]: use the Pimpl idiom to hide the class internals
from public view.
Note that I have done this only after making the above changes,
so not only should we have a clean, minimal and well documented
interface to these classes in the header files, but the class internals
should be much clearer too.
* Renamed classes
grfx::GCache -> grfx::Cache,
grfx::GCacheItem -> grfx::CacheItem,
grfx::GConverter -> grfx::Converter,
grfx::GImage -> grfx::Image,
grfx::GImageXPM -> grfx::ImageXPM,
grfx::GParams -> grfx::Params.
2002-06-26 Angus Leeming <leeming@lyx.org>
* GraphicsLoader.[Ch]: use boost::scoped_ptr in preference to

View File

@ -23,9 +23,22 @@
#include "frontends/lyx_gui.h"
#include <map>
namespace grfx {
GCache & GCache::get()
/** The cache contains one item per file, so use a map to find the
* cache item quickly by filename.
*/
typedef std::map<string, Cache::ItemPtr> CacheType;
struct Cache::Impl {
///
CacheType cache;
};
Cache & Cache::get()
{
static bool start = true;
if (start) {
@ -34,92 +47,76 @@ GCache & GCache::get()
}
// Now return the cache
static GCache singleton;
static Cache singleton;
return singleton;
}
GCache::GCache()
Cache::Cache()
: pimpl_(new Impl())
{}
Cache::~Cache()
{}
std::vector<string> Cache::loadableFormats() const
{
cache = new CacheType;
return Image::loadableFormats();
}
// all elements are destroyed by the shared_ptr's in the map.
GCache::~GCache()
{
delete cache;
}
std::vector<string> GCache::loadableFormats() const
{
return GImage::loadableFormats();
}
void GCache::add(string const & file)
void Cache::add(string const & file)
{
if (!AbsolutePath(file)) {
lyxerr << "GCacheItem::add(" << file << "):\n"
lyxerr << "Cache::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"
lyxerr[Debug::GRAPHICS] << "Cache::add(" << file << "):\n"
<< "The file is already in the cache."
<< std::endl;
return;
}
(*cache)[file] = GraphicPtr(new GCacheItem(file));
pimpl_->cache[file] = ItemPtr(new CacheItem(file));
}
void GCache::remove(string const & file)
void Cache::remove(string const & file)
{
CacheType::iterator it = cache->find(file);
if (it == cache->end())
CacheType::iterator it = pimpl_->cache.find(file);
if (it == pimpl_->cache.end())
return;
GraphicPtr item = it->second;
ItemPtr & item = it->second;
if (item.use_count() == 1) {
// The graphics file is in the cache, but nothing else
// references it.
cache->erase(it);
pimpl_->cache.erase(it);
}
}
bool GCache::inCache(string const & file) const
bool Cache::inCache(string const & file) const
{
return cache->find(file) != cache->end();
return pimpl_->cache.find(file) != pimpl_->cache.end();
}
GraphicPtr const GCache::graphic(string const & file) const
Cache::ItemPtr const Cache::item(string const & file) const
{
CacheType::const_iterator it = cache->find(file);
if (it == cache->end())
return GraphicPtr();
CacheType::const_iterator it = pimpl_->cache.find(file);
if (it == pimpl_->cache.end())
return ItemPtr();
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();
}
} // namespace grfx

View File

@ -7,10 +7,10 @@
* \author Baruch Even <baruch.even@writeme.com>
* \author Angus Leeming <a.leeming@ic.ac.uk>
*
* grfx::GCache is the manager of the image cache.
* It is responsible for creating the grfx::GCacheItem's and maintaining them.
* grfx::Cache is the manager of the image cache.
* It is responsible for creating the grfx::CacheItem's and maintaining them.
*
* grfx::GCache is a singleton class. It is possible to have only one
* grfx::Cache is a singleton class. It is possible to have only one
* instance of it at any moment.
*/
@ -22,18 +22,21 @@
#endif
#include "LString.h"
#include "GraphicsTypes.h"
#include <map>
#include <vector>
#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
namespace grfx {
class GCache : boost::noncopyable {
class CacheItem;
class Cache : boost::noncopyable {
public:
/// This is a singleton class. Get the instance.
static GCache & get();
static Cache & get();
/** Which graphics formats can be loaded directly by the image loader.
* Other formats can be loaded if a converter to a loadable format
@ -44,10 +47,7 @@ public:
/// 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.
*/
/// Remove a file from the cache.
void remove(string const & file);
/// Returns \c true if the file is in the cache.
@ -63,36 +63,24 @@ public:
*
* 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;
typedef boost::shared_ptr<CacheItem> ItemPtr;
///
ItemPtr const item(string const & file) const;
private:
/** Make the c-tor, d-tor private so we can control how many objects
* are instantiated.
*/
GCache();
Cache();
///
~GCache();
~Cache();
/** 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, GraphicPtr> CacheType;
/** Store a pointer to the cache so that we can forward declare
* GCacheItem.
*/
CacheType * cache;
/// Use the Pimpl idiom to hide the internals.
class Impl;
/// The pointer never changes although *pimpl_'s contents may.
boost::scoped_ptr<Impl> const pimpl_;
};
} // namespace grfx
#endif // GRAPHICSCACHE_H

View File

@ -23,46 +23,159 @@
#include "support/LAssert.h"
#include "support/filetools.h"
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/signals/connection.hpp>
#include <boost/signals/trackable.hpp>
using std::endl;
namespace grfx {
GCacheItem::GCacheItem(string const & file)
: filename_(file), zipped_(false),
struct CacheItem::Impl : public boost::signals::trackable {
///
Impl(CacheItem &, string const & file);
/** Start the image conversion process, checking first that it is
* necessary. If it is necessary, then a conversion task is started.
* CacheItem asumes that the conversion is asynchronous and so
* passes a Signal to the converting routine. When the conversion
* is finished, this Signal is emitted, returning the converted
* file to this->imageConverted.
*
* If no file conversion is needed, then convertToDisplayFormat() calls
* loadImage() directly.
*
* convertToDisplayFormat() will set the loading status flag as
* approriate through calls to setStatus().
*/
void convertToDisplayFormat();
/** Load the image into memory. This is called either from
* convertToDisplayFormat() direct or from imageConverted().
*/
void loadImage();
/** Get a notification when the image conversion is done.
* Connected to a signal on_finish_ which is passed to
* Converter::convert.
*/
void imageConverted(bool);
/** Get a notification when the image loading is done.
* Connected to a signal on_finish_ which is passed to
* grfx::Image::loadImage.
*/
void imageLoaded(bool);
/** Sets the status of the loading process. Also notifies
* listeners that the status has chacnged.
*/
void setStatus(ImageStatus new_status);
///
CacheItem & parent_;
/// The filename we refer too.
string filename_;
/// Is the file compressed?
bool zipped_;
/// If so, store the uncompressed file in this temporary file.
string unzipped_filename_;
/// What file are we trying to load?
string file_to_load_;
/** Should we delete the file after loading? True if the file is
* the result of a conversion process.
*/
bool remove_loaded_file_;
/// The image and its loading status.
boost::shared_ptr<Image> image_;
///
ImageStatus status_;
/// The connection to the signal Image::finishedLoading
boost::signals::connection cl_;
/// The connection of the signal ConvProcess::finishedConversion,
boost::signals::connection cc_;
///
boost::scoped_ptr<Converter> converter_;
};
CacheItem::CacheItem(string const & file)
: pimpl_(new Impl(*this, file))
{}
CacheItem::~CacheItem()
{}
string const & CacheItem::filename() const
{
return pimpl_->filename_;
}
void CacheItem::startLoading()
{
if (pimpl_->status_ != WaitingToLoad)
return;
pimpl_->convertToDisplayFormat();
}
Image const * CacheItem::image() const
{
return pimpl_->image_.get();
}
ImageStatus CacheItem::status() const
{
return pimpl_->status_;
}
//------------------------------
// Implementation details follow
//------------------------------
CacheItem::Impl::Impl(CacheItem & p, string const & file)
: parent_(p), filename_(file), zipped_(false),
remove_loaded_file_(false), status_(WaitingToLoad)
{}
void GCacheItem::startLoading()
{
if (status() != WaitingToLoad)
return;
convertToDisplayFormat();
}
void GCacheItem::setStatus(ImageStatus new_status)
void CacheItem::Impl::setStatus(ImageStatus new_status)
{
if (status_ == new_status)
return;
status_ = new_status;
statusChanged();
parent_.statusChanged();
}
void GCacheItem::imageConverted(string const & file_to_load)
void CacheItem::Impl::imageConverted(bool success)
{
bool const success =
(!file_to_load.empty() && IsFileReadable(file_to_load));
string const text = success ? "succeeded" : "failed";
lyxerr[Debug::GRAPHICS] << "Image conversion " << text << "." << endl;
file_to_load_ = converter_.get() ?
converter_->convertedFile() : string();
converter_.reset();
cc_.disconnect();
success = !file_to_load_.empty() && IsFileReadable(file_to_load_);
lyxerr[Debug::GRAPHICS] << "Unable to find converted file!" << endl;
if (!success) {
setStatus(ErrorConverting);
@ -72,34 +185,27 @@ void GCacheItem::imageConverted(string const & file_to_load)
return;
}
cc_.disconnect();
// Do the actual image loading from file to memory.
file_to_load_ = file_to_load;
loadImage();
}
// This function gets called from the callback after the image has been
// converted successfully.
void GCacheItem::loadImage()
void CacheItem::Impl::loadImage()
{
setStatus(Loading);
lyxerr[Debug::GRAPHICS] << "Loading image." << endl;
// Connect a signal to this->imageLoaded and pass this signal to
// GImage::loadImage.
SignalLoadTypePtr on_finish;
on_finish.reset(new SignalLoadType);
cl_ = on_finish->connect(boost::bind(&GCacheItem::imageLoaded, this, _1));
image_ = Image::newImage();
image_ = GImage::newImage();
image_->load(file_to_load_, on_finish);
cl_.disconnect();
cl_ = image_->finishedLoading.connect(
boost::bind(&Impl::imageLoaded, this, _1));
image_->load(file_to_load_);
}
void GCacheItem::imageLoaded(bool success)
void CacheItem::Impl::imageLoaded(bool success)
{
string const text = success ? "succeeded" : "failed";
lyxerr[Debug::GRAPHICS] << "Image loading " << text << "." << endl;
@ -121,19 +227,21 @@ void GCacheItem::imageLoaded(bool success)
setStatus(Loaded);
}
} // namespace grfx
namespace {
string const findTargetFormat(string const & from)
{
typedef GImage::FormatList FormatList;
FormatList const formats = GImage::loadableFormats();
typedef grfx::Image::FormatList FormatList;
FormatList const formats = grfx::Image::loadableFormats();
// There must be a format to load from.
lyx::Assert(!formats.empty());
// First ascertain if we can load directly with no conversion
FormatList::const_iterator it1 = formats.begin();
FormatList::const_iterator it1 = formats.begin();
FormatList::const_iterator end = formats.end();
for (; it1 != end; ++it1) {
if (from == *it1)
@ -141,11 +249,9 @@ string const findTargetFormat(string const & from)
}
// So, we have to convert to a loadable format. Can we?
grfx::GConverter const & graphics_converter = grfx::GConverter::get();
FormatList::const_iterator it2 = formats.begin();
FormatList::const_iterator it2 = formats.begin();
for (; it2 != end; ++it2) {
if (graphics_converter.isReachable(from, *it2))
if (grfx::Converter::isReachable(from, *it2))
return *it2;
}
@ -157,7 +263,9 @@ string const findTargetFormat(string const & from)
} // anon namespace
void GCacheItem::convertToDisplayFormat()
namespace grfx {
void CacheItem::Impl::convertToDisplayFormat()
{
setStatus(Converting);
// Make a local copy in case we unzip it
@ -187,7 +295,7 @@ void GCacheItem::convertToDisplayFormat()
} else
lyxerr[Debug::GRAPHICS]
<< "\n\tThe file contains " << from << " format data." << endl;
string const to = grfx::findTargetFormat(from);
string const to = findTargetFormat(from);
if (from == to) {
// No conversion needed!
@ -212,12 +320,10 @@ void GCacheItem::convertToDisplayFormat()
// Connect a signal to this->imageConverted and pass this signal to
// the graphics converter so that we can load the modified file
// on completion of the conversion process.
SignalConvertTypePtr on_finish;
on_finish.reset(new SignalConvertType);
cc_ = on_finish->connect(boost::bind(&GCacheItem::imageConverted, this, _1));
GConverter & graphics_converter = GConverter::get();
graphics_converter.convert(filename, to_file_base, from, to, on_finish);
converter_.reset(new Converter(filename, to_file_base, from, to));
converter_->finishedConversion.connect(
boost::bind(&Impl::imageConverted, this, _1));
converter_->startConversion();
}
} // namespace grfx

View File

@ -7,18 +7,20 @@
* \author Baruch Even <baruch.even@writeme.com>
* \author Angus Leeming <a.leeming@ic.ac.uk>
*
* The graphics cache is a container of GCacheItems. Each GCacheItem, defined
* here represents a separate image file. The routines here can be used to
* load the graphics file into memory at which point (status() == grfx::Loaded).
* The user is then free to access image() in order to transform the image
* (rotate, scale, clip) and to generate the pixmap.
* The graphics cache is a container of grfx::CacheItems.
* Each grfx::CacheItem, definedhere represents a separate image file.
*
* The routines here can be used to load the graphics file into memory at
* which point (status() == grfx::Loaded).
* The user is then free to access image() in order to copy it and to then
* transform the copy (rotate, scale, clip) and to generate the pixmap.
*
* The graphics cache supports fully asynchronous:
* file conversion to a loadable format;
* file loading.
*
* Whether you get that, of course, depends on grfx::GConverter and on the
* grfx::GImage-derived image class.
* Whether you get that, of course, depends on grfx::Converter and on the
* grfx::Image-derived image class.
*/
#ifndef GRAPHICSCACHEITEM_H
@ -32,124 +34,50 @@
#include "LString.h"
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/signals/signal0.hpp>
#include <boost/signals/signal1.hpp>
#include <boost/signals/connection.hpp>
#include <boost/signals/trackable.hpp>
class InsetGraphics;
namespace grfx {
/// A grfx::GCache item holder.
class GCacheItem : boost::noncopyable, public boost::signals::trackable {
class Image;
class Converter;
/// A grfx::Cache item holder.
class CacheItem : boost::noncopyable {
public:
///
GCacheItem(string const & file);
CacheItem(string const & file);
/// Define an empty d-tor out-of-line to keep boost::scoped_ptr happy.
~CacheItem();
///
string const & filename() const;
/// It's in the cache. Now start the loading process.
void startLoading();
/** Get the image associated with filename_.
If the image is not yet loaded, return a null pointer.
* If the image is not yet loaded, returns 0.
* This routine returns a pointer to const; if you want to modify it,
* create a copy and modify that.
*/
ImagePtr const image() const { return image_; }
Image const * image() const;
/// How far have we got in loading the image?
ImageStatus status() const { return status_; }
ImageStatus status() const;
/// This signal is emitted when the image loading status changes.
boost::signal0<void> statusChanged;
///
string const & filename() const { return filename_; }
private:
/** Start the image conversion process, checking first that it is
* necessary. If it is necessary, then a conversion task is started.
* GCacheItem asumes that the conversion is asynchronous and so
* passes a Signal to the converting routine. When the conversion
* is finished, this Signal is emitted, returning the converted
* file to this->imageConverted.
*
* If no file conversion is needed, then convertToDisplayFormat() calls
* loadImage() directly.
*
* convertToDisplayFormat() will set the loading status flag as
* approriate through calls to setStatus().
*/
void convertToDisplayFormat();
/// Use the Pimpl idiom to hide the internals.
class Impl;
/** Load the image into memory. This is called either from
* convertToDisplayFormat() direct or from imageConverted().
*/
void loadImage();
/** Get a notification when the image conversion is done.
* Connected to a signal on_finish_ which is passed to
* GConverter::convert.
*/
void imageConverted(string const & file_to_load);
/** Get a notification when the image loading is done.
* Connected to a signal on_finish_ which is passed to
* GImage::loadImage.
*/
void imageLoaded(bool);
/** Sets the status of the loading process. Also notifies
* listeners that the status has chacnged.
*/
void setStatus(ImageStatus new_status);
/// The filename we refer too.
string filename_;
/// Is the file compressed?
bool zipped_;
/// If so, store the uncompressed file in this temporary file.
string unzipped_filename_;
/// What file are we trying to load?
string file_to_load_;
/** Should we delete the file after loading? True if the file is
* the result of a conversion process.
*/
bool remove_loaded_file_;
/// The image and its loading status.
ImagePtr image_;
///
ImageStatus status_;
/** A SignalLoadTypePtr is connected to this->imageLoaded and
* then passed to ImagePtr::load.
* When the image has been loaded, the signal is emitted.
*
* We pass a shared_ptr because it is eminently possible for the
* 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.
*/
typedef boost::signal1<void, bool> SignalLoadType;
///
typedef boost::shared_ptr<SignalLoadType> SignalLoadTypePtr;
/// The connection of the signal passed to ImagePtr::loadImage.
boost::signals::connection cl_;
/** A SignalConvertTypePtr is connected to this->imageConverted and
* then passed to GConverter::convert.
* When the image has been converted to a loadable format, the signal
* is emitted, returning the name of the loadable file to
* imageConverted.
*/
typedef boost::signal1<void, string const &> SignalConvertType;
///
typedef boost::shared_ptr<SignalConvertType> SignalConvertTypePtr;
/// The connection of the signal passed to GConverter::convert.
boost::signals::connection cc_;
/// The pointer never changes although *pimpl_'s contents may.
boost::scoped_ptr<Impl> const pimpl_;
};
} // namespace grfx

View File

@ -1,9 +1,9 @@
/*
* \file GraphicsConverter.C
* Copyright 2002 the LyX Team
* Read the file COPYING
/**
* \file GraphicsConverter.C
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* \author Angus Leeming <a.leeming@ic.ac.uk>
* \author Angus Leeming <a.leeming@ic.ac.uk>
*/
#include <config.h>
@ -16,18 +16,198 @@
#include "converter.h"
#include "debug.h"
#include "gettext.h"
#include "support/filetools.h"
#include "support/forkedcall.h"
#include "support/path.h"
#include "support/lyxlib.h"
#include <boost/bind.hpp>
#include <boost/signals/trackable.hpp>
#include "Lsstream.h"
#include <fstream>
#include <sys/types.h> // needed for pid_t
using std::endl;
namespace grfx {
struct Converter::Impl : public boost::signals::trackable {
///
Impl(Converter &,
string const &, string const &, string const &, string const &);
///
void startConversion();
/** This method is connected to a signal passed to the forked call
* class, passing control back here when the conversion is completed.
* Cleans-up the temporary files, emits the finishedConversion
* signal and removes the Converter from the list of all processes.
*/
void converted(string const & cmd, pid_t pid, int retval);
///
string script_command_;
///
string script_file_;
///
string to_file_;
///
Converter & parent_;
///
bool valid_process_;
///
bool finished_;
};
Converter::Converter(string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format)
: pimpl_(new Impl(*this,
from_file, to_file_base, from_format, to_format))
{}
Converter::~Converter()
{}
void Converter::startConversion()
{
pimpl_->startConversion();
}
bool Converter::isReachable(string const & from_format_name,
string const & to_format_name)
{
return converters.isReachable(from_format_name, to_format_name);
}
string const & Converter::convertedFile() const
{
static string const empty;
return pimpl_->finished_ ? pimpl_->to_file_ : empty;
}
} // namespace grfx
//------------------------------
// Implementation details follow
//------------------------------
namespace {
/** Build the conversion script, returning true if able to build it.
* The script is output to the ostringstream 'script'.
*/
bool build_script(string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format,
ostringstream & script);
} // namespace anon
namespace grfx {
Converter::Impl::Impl(Converter & p,
string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format)
: parent_(p), valid_process_(false), finished_(false)
{
lyxerr[Debug::GRAPHICS] << "Converter c-tor:\n"
<< "\tfrom_file: " << from_file
<< "\n\tto_file_base: " << to_file_base
<< "\n\tfrom_format: " << from_format
<< "\n\tto_format: " << to_format << endl;
// The conversion commands are stored in a stringstream
ostringstream script;
script << "#!/bin/sh\n";
bool const success = build_script(from_file, to_file_base,
from_format, to_format, script);
if (!success)
return;
lyxerr[Debug::GRAPHICS] << "\tConversion script:"
<< "\n--------------------------------------\n"
<< script.str().c_str()
<< "\n--------------------------------------\n";
// Output the script to file.
static int counter = 0;
script_file_ = OnlyPath(to_file_base) + "lyxconvert" +
tostr(counter++) + ".sh";
std::ofstream fs(script_file_.c_str());
if (!fs.good())
return;
fs << script.str().c_str();
fs.close();
// The converted image is to be stored in this file
to_file_ = ChangeExtension(to_file_base, formats.extension(to_format));
// The command needed to run the conversion process
// We create a dummy command for ease of understanding of the
// list of forked processes.
// Note that 'sh ' is absolutely essential, or execvp will fail.
script_command_ = "sh " + script_file_ + " " +
OnlyFilename(from_file) + " " + to_format;
// All is ready to go
valid_process_ = true;
}
void Converter::Impl::startConversion()
{
if (!valid_process_) {
converted(string(), 0, 1);
return;
}
// Initiate the conversion
Forkedcall::SignalTypePtr convert_ptr;
convert_ptr.reset(new Forkedcall::SignalType);
convert_ptr->connect(
boost::bind(&Impl::converted, this, _1, _2, _3));
Forkedcall call;
int retval = call.startscript(script_command_, convert_ptr);
if (retval > 0) {
// Unable to even start the script, so clean-up the mess!
converted(string(), 0, 1);
}
}
void Converter::Impl::converted(string const & /* cmd */,
pid_t /* pid */, int retval)
{
if (finished_)
// We're done already!
return;
finished_ = true;
// Clean-up behind ourselves
lyx::unlink(script_file_);
if (retval > 0) {
lyx::unlink(to_file_);
to_file_.erase();
parent_.finishedConversion(false);
} else {
parent_.finishedConversion(true);
}
}
} // namespace grfx
namespace {
@ -51,135 +231,13 @@ string const move_file(string const & from_file, string const & to_file)
return command.str().c_str();
}
} // namespace anon
namespace grfx {
GConverter & GConverter::get()
bool build_script(string const & from_file,
string const & to_file_base,
string const & from_format,
string const & to_format,
ostringstream & script)
{
static GConverter singleton;
return singleton;
}
bool GConverter::isReachable(string const & from_format_name,
string const & to_format_name) const
{
return converters.isReachable(from_format_name, to_format_name);
}
void GConverter::convert(string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format,
SignalTypePtr on_finish)
{
lyxerr[Debug::GRAPHICS] << "[GraphicsConverter::convert]\n"
<< "\tfrom_file: " << from_file
<< "\n\tto_file_base: " << to_file_base
<< "\n\tfrom_format: " << from_format
<< "\n\tto_format: " << to_format << endl;
// The conversion commands are stored in a stringstream
ostringstream script;
script << "#!/bin/sh\n";
string script_command;
string script_file;
bool success = build_script(from_file, to_file_base,
from_format, to_format, script);
if (success) {
lyxerr[Debug::GRAPHICS] << "\tConversion script:\n"
<< "--------------------------------------\n"
<< script.str().c_str()
<< "\n--------------------------------------\n";
// Output the script to file.
static int counter = 0;
script_file = OnlyPath(to_file_base) + "lyxconvert" +
tostr(counter++) + ".sh";
std::ofstream fs(script_file.c_str());
if (!fs.good()) {
// Unable to output the conversion script to file.
success = false;
} else {
fs << script.str().c_str();
fs.close();
// Create a dummy command for ease of understanding of the
// list of forked processes.
// Note that 'sh ' is absolutely essential, or execvp will fail.
script_command =
"sh " + script_file + " " +
OnlyFilename(from_file) + " " + to_format;
}
}
string const to_file =
ChangeExtension(to_file_base, formats.extension(to_format));
if (!success) {
script_file = string();
script_command =
"convert -depth 8 " +
from_format + ':' + from_file + ' ' +
to_format + ':' + to_file;
lyxerr[Debug::GRAPHICS]
<< "\tNo converter defined! I use convert from ImageMagic:\n\t"
<< script_command << endl;
}
// Launch the conversion process.
ConvProcessPtr shared_ptr;
shared_ptr.reset(new ConvProcess(script_file, script_command,
to_file, on_finish));
all_processes_.push_back(shared_ptr);
}
namespace {
typedef boost::shared_ptr<ConvProcess> ConvProcessPtr;
class Find_Ptr {
public:
Find_Ptr(ConvProcess * ptr) : ptr_(ptr) {}
bool operator()(ConvProcessPtr const & ptr)
{
return ptr.get() == ptr_;
}
private:
ConvProcess * ptr_;
};
} // namespace anon
void GConverter::erase(ConvProcess * process)
{
std::list<ConvProcessPtr>::iterator begin = all_processes_.begin();
std::list<ConvProcessPtr>::iterator end = all_processes_.end();
std::list<ConvProcessPtr>::iterator it =
std::find_if(begin, end, Find_Ptr(process));
if (it == end)
return;
all_processes_.erase(it);
}
bool GConverter::build_script(string const & from_file,
string const & to_file_base,
string const & from_format,
string const & to_format,
ostringstream & script) const
{
lyxerr[Debug::GRAPHICS] << "[GraphicsConverter::build_script] ... ";
lyxerr[Debug::GRAPHICS] << "build_script ... ";
typedef Converters::EdgePath EdgePath;
string const to_file = ChangeExtension(to_file_base,
@ -216,7 +274,7 @@ bool GConverter::build_script(string const & from_file,
EdgePath::const_iterator it = edgepath.begin();
EdgePath::const_iterator end = edgepath.end();
for (; it != end; ++it) {
Converter const & conv = converters.get(*it);
::Converter const & conv = converters.get(*it);
// Build the conversion command
string const infile = outfile;
@ -269,44 +327,5 @@ bool GConverter::build_script(string const & from_file,
return true;
}
ConvProcess::ConvProcess(string const & script_file,
string const & script_command,
string const & to_file, SignalTypePtr on_finish)
: script_file_(script_file), to_file_(to_file), on_finish_(on_finish)
{
Forkedcall::SignalTypePtr convert_ptr;
convert_ptr.reset(new Forkedcall::SignalType);
convert_ptr->connect(boost::bind(&ConvProcess::converted, this, _1, _2, _3));
Forkedcall call;
int retval = call.startscript(script_command, convert_ptr);
if (retval > 0) {
// Unable to even start the script, so clean-up the mess!
converted(string(), 0, 1);
}
}
void ConvProcess::converted(string const &/* cmd */,
pid_t /* pid */, int retval)
{
// Clean-up behind ourselves
lyx::unlink(script_file_);
if (retval > 0) {
lyx::unlink(to_file_);
to_file_.erase();
}
if (on_finish_.get()) {
on_finish_->operator()(to_file_);
}
grfx::GConverter::get().erase(this);
}
} // namespace grfx
} // namespace anon

View File

@ -1,129 +1,72 @@
// -*- C++ -*-
/*
* \file GraphicsConverter.h
* Copyright 2002 the LyX Team
* Read the file COPYING
/**
* \file GraphicsConverter.h
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* \author Angus Leeming <a.leeming@ic.ac.uk>
* \author Angus Leeming <a.leeming@ic.ac.uk>
*
* class grfx::GConverter enables graphics files to be converted asynchronously
* to a loadable format. It does this by building a shell script of all
* the conversion commands needed for the transformation. This script is then
* sent to the forked calls controller for non-blocking execution. When it
* is finished a signal is emitted, thus informing us to proceed with the
* loading of the image.
*
* Ultimately, this class should be wrapped back into Dekel's converter class.
* The controller of a conversion process from file AA of format A to
* file BB of format B.
* Once finished, the signal finishdConversion is emitted to inform the
* instigator where to find file BB.
* If the conversion is unsuccessful, then finishedConversion will pass
* an empty string.
*/
#ifndef GRAPHICSCONVERTER_H
#define GRAPHICSCONVERTER_H
#include "LString.h"
#include "Lsstream.h"
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/signals/signal1.hpp>
#include <boost/signals/trackable.hpp>
#include <list>
#include <sys/types.h> // needed for pid_t
#ifdef __GNUG__
#pragma interface
#endif
#include "LString.h"
#include <boost/signals/signal1.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>
namespace grfx {
class ConvProcess;
class GConverter : boost::noncopyable {
class Converter : boost::noncopyable {
public:
/// This is a singleton class. Get the instance.
static GConverter & get();
/// Can the conversion be performed?
bool isReachable(string const & from_format_name,
string const & to_format_name) const;
static bool isReachable(string const & from_format_name,
string const & to_format_name);
/** Convert the file and at the end return it by emitting this signal
* If successful, the returned string will be the name of the
* converted file (to_file_base + extension(to_format_name)).
* If unsuccessful, the string will be empty.
/** One Converter per conversion ensures that finishedConversion
* is always connected to the expected slot.
*/
typedef boost::signal1<void, string const &> SignalType;
Converter(string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format);
/// Define an empty d-tor out-of-line to keep boost::scoped_ptr happy.
~Converter();
/// We are explicit about when we begin the conversion process.
void startConversion();
/** At the end of the conversion process inform the outside world
* by emitting a signal.
*/
typedef boost::signal1<void, bool> SignalType;
///
typedef boost::shared_ptr<SignalType> SignalTypePtr;
///
void convert(string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format,
SignalTypePtr on_finish);
SignalType finishedConversion;
/** If the convsion is succesful (finishedConversion returns \c true),
* this returns the name of the resulting file.
* If conversion fails, however, it returns an empty string.
*/
string const & convertedFile() const;
private:
/** Make the c-tor private so we can control how many objects
* are instantiated.
*/
GConverter() {}
/// Use the Pimpl idiom to hide the internals.
class Impl;
/** Build the conversion script, returning true if able to build it.
* The script is output to the ostringstream 'script'.
*/
bool build_script(string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format,
ostringstream & script) const;
/** Remove the ConvProcess from the list of all processes.
* Called by ConvProcess::converted.
*/
friend class ConvProcess;
///
void erase(ConvProcess *);
/// The list of all conversion processs
typedef boost::shared_ptr<ConvProcess> ConvProcessPtr;
///
std::list<ConvProcessPtr> all_processes_;
/// The pointer never changes although *pimpl_'s contents may.
boost::scoped_ptr<Impl> const pimpl_;
};
/// Each ConvProcess represents a single conversion process.
struct ConvProcess : public boost::signals::trackable
{
///
typedef GConverter::SignalTypePtr SignalTypePtr;
/** Each ConvProcess represents a single conversion process.
* It is passed :
* 1. The name of the script_file, which it deletes once the
* conversion is comlpeted;
* 2. The script command itself, which it passes on to the forked
* call process;
* 3. The name of the output file, which it returns to the calling
* process on successfull completion, by emitting
* 4. The signal on_finish.
*/
ConvProcess(string const & script_file, string const & script_command,
string const & to_file, SignalTypePtr on_finish);
/** This method is connected to a signal passed to the forked call
* class, passing control back here when the conversion is completed.
* Cleans-up the temporary files, emits the on_finish signal and
* removes the ConvProcess from the list of all processes.
*/
void converted(string const & cmd, pid_t pid, int retval);
///
string script_file_;
///
string to_file_;
///
SignalTypePtr on_finish_;
};
} // namespace grfx
#endif // GRAPHICSCONVERTER_H

View File

@ -18,15 +18,15 @@
namespace grfx {
// This will be connected to a function that will return whichever
// whichever derived class we desire.
boost::signal0<ImagePtr> GImage::newImage;
// This is to be connected to a function that will return a new
// instance of a viable derived class.
boost::signal0<Image::ImagePtr> Image::newImage;
/// Return the list of loadable formats.
boost::signal0<GImage::FormatList> GImage::loadableFormats;
boost::signal0<Image::FormatList> Image::loadableFormats;
std::pair<unsigned int, unsigned int>
GImage::getScaledDimensions(GParams const & params) const
Image::getScaledDimensions(Params const & params) const
{
if (params.scale == 0 && params.width == 0 && params.height == 0)
// No scaling

View File

@ -23,14 +23,12 @@
#define GRAPHICSIMAGE_H
#include "LString.h"
#include "GraphicsTypes.h"
#include <boost/shared_ptr.hpp>
#include <boost/signals/signal0.hpp>
#include <boost/signals/signal1.hpp>
#include <X11/X.h>
#include <X11/X.h> // for Pixmap :-(
#include <vector>
#include <utility>
@ -41,26 +39,31 @@
namespace grfx {
class GParams;
class Params;
class GImage
{
class Image {
public:
/// A list of supported formats.
typedef std::vector<string> FormatList;
/** This will be connected to a function that will return whichever
* derived class we desire.
/** This is to be connected to a function that will return a new
* instance of a viable derived class.
*/
typedef boost::shared_ptr<Image> ImagePtr;
///
static boost::signal0<ImagePtr> newImage;
/// Return the list of loadable formats.
typedef std::vector<string> FormatList;
///
static boost::signal0<FormatList> loadableFormats;
/// Must define default c-tor explicitly as we define a copy c-tor.
Image() {}
/// Don't copy the signal finishedLoading
Image(Image const &) {}
///
virtual ~GImage() {}
virtual ~Image() {}
/// Create a copy
virtual GImage * clone() const = 0;
virtual Image * clone() const = 0;
///
virtual Pixmap getPixmap() const = 0;
@ -71,37 +74,41 @@ public:
/// Get the image height
virtual unsigned int getHeight() const = 0;
/** At the end of the loading or modification process, return the new
* image by emitting this signal */
/** At the end of the loading process inform the outside world
* by emitting a signal.
*/
typedef boost::signal1<void, bool> SignalType;
///
typedef boost::shared_ptr<SignalType> SignalTypePtr;
SignalType finishedLoading;
/// Start loading the image file.
virtual void load(string const & filename, SignalTypePtr) = 0;
/** Start loading the image file.
* The caller should expect this process to be asynchronous and
* so should connect to the "finished" signal above.
*/
virtual void load(string const & filename) = 0;
/** Generate the pixmap.
* Uses the params to decide on color, grayscale etc.
* Returns true if the pixmap is created.
*/
virtual bool setPixmap(GParams const & params) = 0;
virtual bool setPixmap(Params const & params) = 0;
/// Clip the image using params.
virtual void clip(GParams const & params) = 0;
virtual void clip(Params const & params) = 0;
/// Rotate the image using params.
virtual void rotate(GParams const & params) = 0;
virtual void rotate(Params const & params) = 0;
/// Scale the image using params.
virtual void scale(GParams const & params) = 0;
virtual void scale(Params const & params) = 0;
protected:
/** Uses the params to ascertain the dimensions of the scaled image.
* Returned as make_pair(width, height).
* If something geso wrong, returns make_pair(getWidth(), getHeight())
* If something goes wrong, returns make_pair(getWidth(), getHeight())
*/
std::pair<unsigned int, unsigned int>
getScaledDimensions(GParams const & params) const;
getScaledDimensions(Params const & params) const;
};
} // namespace grfx

View File

@ -37,16 +37,16 @@ using std::strlen;
namespace grfx {
/// Access to this class is through this static method.
ImagePtr GImageXPM::newImage()
Image::ImagePtr ImageXPM::newImage()
{
ImagePtr ptr;
ptr.reset(new GImageXPM);
ptr.reset(new ImageXPM);
return ptr;
}
/// Return the list of loadable formats.
GImage::FormatList GImageXPM::loadableFormats()
Image::FormatList ImageXPM::loadableFormats()
{
FormatList formats(1);
formats[0] = "xpm";
@ -54,46 +54,46 @@ GImage::FormatList GImageXPM::loadableFormats()
}
GImageXPM::GImageXPM()
ImageXPM::ImageXPM()
: pixmap_(0),
pixmap_status_(PIXMAP_UNINITIALISED)
{}
GImageXPM::GImageXPM(GImageXPM const & other)
: GImage(other),
ImageXPM::ImageXPM(ImageXPM const & other)
: Image(other),
image_(other.image_),
pixmap_(0),
pixmap_status_(PIXMAP_UNINITIALISED)
{}
GImageXPM::~GImageXPM()
ImageXPM::~ImageXPM()
{
if (pixmap_)
XFreePixmap(fl_get_display(), pixmap_);
}
GImage * GImageXPM::clone() const
Image * ImageXPM::clone() const
{
return new GImageXPM(*this);
return new ImageXPM(*this);
}
unsigned int GImageXPM::getWidth() const
unsigned int ImageXPM::getWidth() const
{
return image_.width();
}
unsigned int GImageXPM::getHeight() const
unsigned int ImageXPM::getHeight() const
{
return image_.height();
}
Pixmap GImageXPM::getPixmap() const
Pixmap ImageXPM::getPixmap() const
{
if (!pixmap_status_ == PIXMAP_SUCCESS)
return 0;
@ -101,17 +101,17 @@ Pixmap GImageXPM::getPixmap() const
}
void GImageXPM::load(string const & filename, GImage::SignalTypePtr on_finish)
void ImageXPM::load(string const & filename)
{
if (filename.empty()) {
on_finish->operator()(false);
finishedLoading(false);
return;
}
if (!image_.empty()) {
lyxerr[Debug::GRAPHICS]
<< "Image is loaded already!" << std::endl;
on_finish->operator()(false);
finishedLoading(false);
return;
}
@ -151,11 +151,11 @@ void GImageXPM::load(string const & filename, GImage::SignalTypePtr on_finish)
image_.reset(*xpm_image);
}
on_finish->operator()(success == XpmSuccess);
finishedLoading(success == XpmSuccess);
}
bool GImageXPM::setPixmap(GParams const & params)
bool ImageXPM::setPixmap(Params const & params)
{
if (image_.empty() || params.display == NoDisplay) {
return false;
@ -235,7 +235,7 @@ bool GImageXPM::setPixmap(GParams const & params)
}
void GImageXPM::clip(GParams const & params)
void ImageXPM::clip(Params const & params)
{
if (image_.empty())
return;
@ -279,7 +279,7 @@ void GImageXPM::clip(GParams const & params)
}
void GImageXPM::rotate(GParams const & params)
void ImageXPM::rotate(Params const & params)
{
if (image_.empty())
return ;
@ -349,7 +349,7 @@ void GImageXPM::rotate(GParams const & params)
}
void GImageXPM::scale(GParams const & params)
void ImageXPM::scale(Params const & params)
{
if (image_.empty())
return;
@ -419,19 +419,19 @@ void mapcolor(char const * c_color, char ** g_color_ptr, char ** m_color_ptr);
namespace grfx {
GImageXPM::Data::Data()
ImageXPM::Data::Data()
: width_(0), height_(0), cpp_(0), ncolors_(0)
{}
GImageXPM::Data::~Data()
ImageXPM::Data::~Data()
{
if (colorTable_.unique())
free_color_table(colorTable_.get(), ncolors_);
}
void GImageXPM::Data::reset(XpmImage & image)
void ImageXPM::Data::reset(XpmImage & image)
{
width_ = image.width;
height_ = image.height;
@ -511,7 +511,7 @@ void GImageXPM::Data::reset(XpmImage & image)
}
XpmImage GImageXPM::Data::get() const
XpmImage ImageXPM::Data::get() const
{
XpmImage image;
image.width = width_;
@ -524,7 +524,7 @@ XpmImage GImageXPM::Data::get() const
}
void GImageXPM::Data::resetData(int w, int h, unsigned int * d)
void ImageXPM::Data::resetData(int w, int h, unsigned int * d)
{
width_ = w;
height_ = h;
@ -532,7 +532,7 @@ void GImageXPM::Data::resetData(int w, int h, unsigned int * d)
}
unsigned int * GImageXPM::Data::initialisedData(int w, int h) const
unsigned int * ImageXPM::Data::initialisedData(int w, int h) const
{
size_t const data_size = w * h;
@ -546,7 +546,7 @@ unsigned int * GImageXPM::Data::initialisedData(int w, int h) const
}
unsigned int GImageXPM::Data::color_none_id() const
unsigned int ImageXPM::Data::color_none_id() const
{
XpmColor * table = colorTable_.get();
for (size_t i = 0; i < ncolors_; ++i) {

View File

@ -7,7 +7,7 @@
* \author Baruch Even <baruch.even@writeme.com>
* \author Angus Leeming <a.leeming@ic.ac.uk>
*
* An instantiation of GImage that makes use of libXPM to load and store
* An instantiation of Image that makes use of libXPM to load and store
* the image in memory.
*/
@ -24,7 +24,7 @@
namespace grfx {
class GImageXPM : public GImage
class ImageXPM : public Image
{
public:
/// Access to this class is through this static method.
@ -34,10 +34,10 @@ public:
static FormatList loadableFormats();
///
~GImageXPM();
~ImageXPM();
/// Create a copy
GImage * clone() const;
Image * clone() const;
///
Pixmap getPixmap() const;
@ -49,31 +49,31 @@ public:
unsigned int getHeight() const;
/** Load the image file into memory.
* In this case (GImageXPM), the process is blocking.
* In this case (ImageXPM), the process is blocking.
*/
void load(string const & filename, SignalTypePtr);
void load(string const & filename);
/** Generate the pixmap, based on the current state of the
* xpm_image_ (clipped, rotated, scaled etc).
* Uses the params to decide on color, grayscale etc.
* Returns true if the pixmap is created.
*/
bool setPixmap(GParams const & params);
bool setPixmap(Params const & params);
/// Clip the image using params.
void clip(GParams const & params);
void clip(Params const & params);
/// Rotate the image using params.
void rotate(GParams const & params);
void rotate(Params const & params);
/// Scale the image using params.
void scale(GParams const & params);
void scale(Params const & params);
private:
/// Access to the class is through newImage() and clone.
GImageXPM();
ImageXPM();
///
GImageXPM(GImageXPM const &);
ImageXPM(ImageXPM const &);
/** Contains the data read from file.
* This class is a wrapper for a XpmImage struct, but all views

View File

@ -19,103 +19,111 @@
#include "GraphicsParams.h"
#include <boost/bind.hpp>
#include <boost/signals/trackable.hpp>
namespace grfx {
struct Loader::Impl {
struct Loader::Impl : boost::signals::trackable {
///
Impl(Loader &, GParams const &);
Impl(Loader &, Params const &);
///
~Impl();
///
void setFile(string const & file);
void resetFile(string const &);
///
void unsetOldFile();
void resetParams(Params const &);
///
void createPixmap();
///
void statusChanged();
///
Loader & parent_;
/// The loading status of the image.
ImageStatus status_;
/** Must store a copy of the cached item to ensure that it is not
* erased unexpectedly by the cache itself.
*/
GraphicPtr graphic_;
///
GParams params_;
Cache::ItemPtr cached_item_;
/// We modify a local copy of the image once it is loaded.
ImagePtr image_;
Image::ImagePtr image_;
private:
///
void statusChanged();
///
Params params_;
///
Loader & parent_;
};
Loader::Impl::Impl(Loader & parent, GParams const & params)
: parent_(parent), status_(WaitingToLoad), params_(params)
Loader::Impl::Impl(Loader & parent, Params const & params)
: status_(WaitingToLoad), params_(params), parent_(parent)
{}
Loader::Impl::~Impl()
{
unsetOldFile();
resetFile(string());
}
void Loader::Impl::setFile(string const & file)
void Loader::Impl::resetFile(string const & file)
{
if (file.empty())
string const old_file = cached_item_.get() ?
cached_item_->filename() : string();
if (file == old_file)
return;
GCache & gc = GCache::get();
if (!old_file.empty()) {
cached_item_.reset();
Cache::get().remove(old_file);
}
status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
image_.reset();
if (cached_item_.get() || file.empty())
return;
Cache & gc = Cache::get();
if (!gc.inCache(file))
gc.add(file);
// We /must/ make a local copy of this.
graphic_ = gc.graphic(file);
status_ = graphic_->status();
cached_item_ = gc.item(file);
status_ = cached_item_->status();
if (status_ == Loaded) {
createPixmap();
}
// It's easiest to do this without checking
parent_.statusChanged();
cached_item_->statusChanged.connect(
boost::bind(&Impl::statusChanged, this));
}
void Loader::Impl::unsetOldFile()
void Loader::Impl::resetParams(Params const & params)
{
if (!graphic_.get())
if (params == params_)
return;
string const old_file = graphic_->filename();
graphic_.reset();
GCache::get().remove(old_file);
status_ = WaitingToLoad;
params_ = GParams();
params_ = params;
status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
image_.reset();
}
void Loader::Impl::statusChanged()
{
status_ = graphic_->status();
if (status_ == Loaded)
createPixmap();
status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
createPixmap();
parent_.statusChanged();
}
void Loader::Impl::createPixmap()
{
if (!graphic_.get() || image_.get() ||
if (!cached_item_.get() || image_.get() ||
params_.display == NoDisplay || status_ != Loaded)
return;
image_.reset(graphic_->image()->clone());
image_.reset(cached_item_->image()->clone());
// These do nothing if there's nothing to do
image_->clip(params_);
@ -134,22 +142,21 @@ void Loader::Impl::createPixmap()
Loader::Loader()
: pimpl_(new Impl(*this, GParams()))
: pimpl_(new Impl(*this, Params()))
{}
Loader::Loader(string const & file, DisplayType type)
: pimpl_(new Impl(*this, GParams()))
: pimpl_(new Impl(*this, Params()))
{
pimpl_->params_.display = type;
pimpl_->setFile(file);
reset(file, type);
}
Loader::Loader(string const & file, GParams const & params)
Loader::Loader(string const & file, Params const & params)
: pimpl_(new Impl(*this, params))
{
pimpl_->setFile(file);
reset(file, params);
}
@ -159,48 +166,43 @@ Loader::~Loader()
void Loader::reset(string const & file, DisplayType type)
{
pimpl_->unsetOldFile();
Params params;
params.display = type;
pimpl_->resetParams(params);
pimpl_->params_ = GParams();
pimpl_->params_.display = type;
pimpl_->setFile(file);
pimpl_->resetFile(file);
pimpl_->createPixmap();
}
void Loader::reset(string const & file, GParams const & params)
void Loader::reset(string const & file, Params const & params)
{
pimpl_->unsetOldFile();
pimpl_->params_ = params;
pimpl_->setFile(file);
pimpl_->resetParams(params);
pimpl_->resetFile(file);
pimpl_->createPixmap();
}
void Loader::reset(GParams const & params)
void Loader::reset(Params const & params)
{
pimpl_->params_ = params;
if (pimpl_->status_ == Loaded)
pimpl_->createPixmap();
pimpl_->resetParams(params);
pimpl_->createPixmap();
}
void Loader::startLoading()
{
if (pimpl_->status_ != WaitingToLoad || !pimpl_->graphic_.get())
if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
return;
pimpl_->graphic_->statusChanged.connect(
boost::bind(&Loader::Impl::statusChanged,
pimpl_.get()));
pimpl_->graphic_->startLoading();
pimpl_->cached_item_->startLoading();
}
string const & Loader::filename() const
{
static string const empty;
return pimpl_->graphic_.get() ? pimpl_->graphic_->filename() : empty;
return pimpl_->cached_item_.get() ?
pimpl_->cached_item_->filename() : empty;
}
@ -210,7 +212,7 @@ ImageStatus Loader::status() const
}
GImage const * Loader::image() const
Image const * Loader::image() const
{
return pimpl_->image_.get();
}

View File

@ -6,7 +6,8 @@
*
* \author Angus Leeming <leeming@lyx.org>
*
* The public view of the graphics cache.
* The public face of the graphics cache.
*
* * The user supplies an image file and the display parameters.
* * He can change the file or the display parameters through a reset() method.
* * He must start the loading process explicitly with startLoading().
@ -32,11 +33,9 @@
namespace grfx {
class GParams;
class Image;
class Params;
/** One image, one instance of grfx::Loader, although the image can be
* changed.
*/
class Loader {
public:
/// Must use the reset methods to make this instance usable.
@ -44,7 +43,7 @@ public:
/// The image is not transformed, just displayed as-is.
Loader(string const & file_with_path, DisplayType = ColorDisplay);
/// The image is transformed before display.
Loader(string const & file_with_path, GParams const &);
Loader(string const & file_with_path, Params const &);
/// Define an empty d-tor out-of-line to keep boost::scoped_ptr happy.
~Loader();
@ -52,9 +51,9 @@ public:
/// The file can be changed, or the display params, or both.
void reset(string const & file_with_path, DisplayType = ColorDisplay);
///
void reset(string const & file_with_path, GParams const &);
void reset(string const & file_with_path, Params const &);
///
void reset(GParams const &);
void reset(Params const &);
/// Returns the absolute path of the loaded (loading?) file.
string const & filename() const;
@ -73,7 +72,7 @@ public:
/** The loaded image with Pixmap set.
* If the Pixmap is not yet set (see status() for why...), returns 0.
*/
GImage const * image() const;
Image const * image() const;
private:
/// Use the Pimpl idiom to hide the internals.

View File

@ -19,7 +19,7 @@
namespace grfx {
GParams::GParams()
Params::Params()
: display(ColorDisplay),
width(0),
height(0),
@ -28,7 +28,7 @@ GParams::GParams()
{}
bool operator==(GParams const & a, GParams const & b)
bool operator==(Params const & a, Params const & b)
{
return (a.filename == b.filename &&
a.display == b.display &&
@ -40,7 +40,7 @@ bool operator==(GParams const & a, GParams const & b)
}
bool operator!=(GParams const & a, GParams const & b)
bool operator!=(Params const & a, Params const & b)
{
return !(a == b);
}

View File

@ -43,9 +43,9 @@ struct BoundingBox {
bool operator==(BoundingBox const &, BoundingBox const &);
bool operator!=(BoundingBox const &, BoundingBox const &);
struct GParams
struct Params
{
GParams();
Params();
DisplayType display;
@ -69,8 +69,8 @@ struct GParams
int angle;
};
bool operator==(GParams const &, GParams const &);
bool operator!=(GParams const &, GParams const &);
bool operator==(Params const &, Params const &);
bool operator!=(Params const &, Params const &);
} // namespace grfx

View File

@ -7,30 +7,18 @@
* \author Angus Leeming <a.leeming@ic.ac.uk>
*
* All that header files outside the graphics subdirectory should need to
* access. That just leaves insetgraphics.C to access GraphicsCache.h.
* It also makes life easier for files inside the graphics subdirectory!
* access.
*/
#ifndef GRAPHICSTYPES_H
#define GRAPHICSTYPES_H
#include <boost/shared_ptr.hpp>
#ifdef __GNUG__
#pragma interface
#endif
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 {
/** The data is in the cache, but no request to display it

View File

@ -1,3 +1,10 @@
2002-06-28 Angus Leeming <leeming@lyx.org>
* insetgraphicsParams.[Ch]: forward declare grfx::Params.
rename asGParams -> as_grfxParams.
* insetgraphics.C: reflect above change.
2002-06-26 Angus Leeming <leeming@lyx.org>
* insetgraphics.h: use boost::scoped_ptr in preference to

View File

@ -80,6 +80,7 @@ TODO Before initial production release:
#include "graphics/GraphicsLoader.h"
#include "graphics/GraphicsImage.h"
#include "graphics/GraphicsParams.h"
#include "frontends/LyXView.h"
#include "lyxtext.h"
@ -181,7 +182,7 @@ void InsetGraphics::Cache::update(string const & file_with_path)
lyx::Assert(!file_with_path.empty());
string const path = OnlyPath(file_with_path);
loader.reset(file_with_path, parent_.params().asGParams(path));
loader.reset(file_with_path, parent_.params().as_grfxParams(path));
}

View File

@ -18,6 +18,8 @@
#include "insetgraphicsParams.h"
#include "graphics/GraphicsParams.h"
#include "support/translator.h"
#include "support/filetools.h"
#include "support/lyxlib.h"
@ -307,9 +309,9 @@ bool InsetGraphicsParams::Read(LyXLex & lex, string const & token)
}
grfx::GParams InsetGraphicsParams::asGParams(string const & filepath) const
grfx::Params InsetGraphicsParams::as_grfxParams(string const & filepath) const
{
grfx::GParams pars;
grfx::Params pars;
pars.width = 0;
pars.height = 0;
pars.scale = 0;

View File

@ -22,8 +22,9 @@
#include "buffer.h"
#include "lyxlex.h"
#include "graphics/GraphicsParams.h"
namespace grfx {
class Params;
}
/// This struct holds all the parameters needed by insetGraphics.
struct InsetGraphicsParams
@ -98,7 +99,7 @@ struct InsetGraphicsParams
// Only a subset of InsetGraphicsParams is needed for display purposes.
// This function also interrogates lyxrc to ascertain whether
// to display or not.
grfx::GParams asGParams(string const & filepath) const;
grfx::Params as_grfxParams(string const & filepath) const;
private:
/// Initialize the object to a default status.

View File

@ -1,3 +1,6 @@
2002-06-28 Angus Leeming <leeming@lyx.org>
* preview.h (preview): don't pass grfx::GraphicPtr & anymore.
2002-06-24 André Pönitz <poenitz@gmx.net>

View File

@ -2,8 +2,7 @@
#define PREVIEW_H
#include "LString.h"
#include "graphics/GraphicsTypes.h"
bool preview(string const & str, grfx::GraphicPtr & graphic);
bool preview(string const & str);
#endif