X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fgraphics%2FGraphicsCacheItem.C;h=59973327d441815b6bbf1ff202eb94fc5f7c8e6c;hb=33243f70037b067f90d1574b74b34f90a2ef2aa1;hp=b5b2ca04191f12bf10d4d4d4d95fc8020dee2d27;hpb=a674f70d4a013e69a88343e5b6d13357d8a33493;p=lyx.git diff --git a/src/graphics/GraphicsCacheItem.C b/src/graphics/GraphicsCacheItem.C index b5b2ca0419..59973327d4 100644 --- a/src/graphics/GraphicsCacheItem.C +++ b/src/graphics/GraphicsCacheItem.C @@ -1,41 +1,55 @@ -/* +/** * \file GraphicsCacheItem.C - * Copyright 2002 the LyX Team - * Read the file COPYING + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. * - * \author Baruch Even - * \author Herbert Voss - * \author Angus Leeming + * \author Baruch Even + * \author Herbert Voß + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. */ #include -#ifdef __GNUG__ -#pragma implementation -#endif - -#include "graphics/GraphicsCacheItem.h" -#include "graphics/GraphicsImage.h" -#include "graphics/GraphicsConverter.h" +#include "GraphicsCacheItem.h" +#include "GraphicsConverter.h" +#include "GraphicsImage.h" #include "debug.h" -#include "support/LAssert.h" #include "support/filetools.h" +#include "support/FileMonitor.h" +#include "support/lyxlib.h" -#include #include -#include -#include + + +namespace support = lyx::support; + +using support::ChangeExtension; +using support::FileMonitor; +using support::IsFileReadable; +using support::MakeDisplayPath; +using support::OnlyFilename; +using support::getExtFromContents; +using support::tempName; +using support::unlink; +using support::unzipFile; +using support::unzippedFileName; +using support::zippedFile; using std::endl; +using std::string; + -namespace grfx { +namespace lyx { +namespace graphics { struct CacheItem::Impl : public boost::signals::trackable { /// - Impl(CacheItem &, string const & file); + Impl(string const & file); /** Start the image conversion process, checking first that it is * necessary. If it is necessary, then a conversion task is started. @@ -65,20 +79,32 @@ struct CacheItem::Impl : public boost::signals::trackable { /** Get a notification when the image loading is done. * Connected to a signal on_finish_ which is passed to - * grfx::Image::loadImage. + * lyx::graphics::Image::loadImage. */ void imageLoaded(bool); /** Sets the status of the loading process. Also notifies - * listeners that the status has chacnged. + * listeners that the status has changed. */ void setStatus(ImageStatus new_status); - /// - CacheItem & parent_; + /** Can be invoked directly by the user, but is also connected to the + * FileMonitor and so is invoked when the file is changed + * (if monitoring is taking place). + */ + void startLoading(); + + /** If we are asked to load the file for a second or further time, + * (because the file has changed), then we'll have to first reset + * many of the variables below. + */ + void reset(); /// The filename we refer too. - string filename_; + string const filename_; + /// + FileMonitor const monitor_; + /// Is the file compressed? bool zipped_; /// If so, store the uncompressed file in this temporary file. @@ -95,6 +121,9 @@ struct CacheItem::Impl : public boost::signals::trackable { /// ImageStatus status_; + /// This signal is emitted when the image loading status changes. + boost::signal0 statusChanged; + /// The connection to the signal Image::finishedLoading boost::signals::connection cl_; @@ -107,10 +136,10 @@ struct CacheItem::Impl : public boost::signals::trackable { CacheItem::CacheItem(string const & file) - : pimpl_(new Impl(*this, file)) + : pimpl_(new Impl(file)) {} - + CacheItem::~CacheItem() {} @@ -121,12 +150,28 @@ string const & CacheItem::filename() const } -void CacheItem::startLoading() +void CacheItem::startLoading() const { - if (pimpl_->status_ != WaitingToLoad) - return; + pimpl_->startLoading(); +} - pimpl_->convertToDisplayFormat(); + +void CacheItem::startMonitoring() const +{ + if (!pimpl_->monitor_.monitoring()) + pimpl_->monitor_.start(); +} + + +bool CacheItem::monitoring() const +{ + return pimpl_->monitor_.monitoring(); +} + + +unsigned long CacheItem::checksum() const +{ + return pimpl_->monitor_.checksum(); } @@ -142,15 +187,63 @@ ImageStatus CacheItem::status() const } +boost::signals::connection CacheItem::connect(slot_type const & slot) const +{ + return pimpl_->statusChanged.connect(slot); +} + + //------------------------------ // Implementation details follow //------------------------------ -CacheItem::Impl::Impl(CacheItem & p, string const & file) - : parent_(p), filename_(file), zipped_(false), - remove_loaded_file_(false), status_(WaitingToLoad) -{} +CacheItem::Impl::Impl(string const & file) + : filename_(file), + monitor_(file, 2000), + zipped_(false), + remove_loaded_file_(false), + status_(WaitingToLoad) +{ + monitor_.connect(boost::bind(&Impl::startLoading, this)); +} + + +void CacheItem::Impl::startLoading() +{ + if (status_ != WaitingToLoad) + reset(); + + convertToDisplayFormat(); +} + + +void CacheItem::Impl::reset() +{ + zipped_ = false; + if (!unzipped_filename_.empty()) + unlink(unzipped_filename_); + unzipped_filename_.erase(); + + if (remove_loaded_file_ && !file_to_load_.empty()) + unlink(file_to_load_); + remove_loaded_file_ = false; + file_to_load_.erase(); + + if (image_.get()) + image_.reset(); + + status_ = WaitingToLoad; + + if (cl_.connected()) + cl_.disconnect(); + + if (cc_.connected()) + cc_.disconnect(); + + if (converter_.get()) + converter_.reset(); +} void CacheItem::Impl::setStatus(ImageStatus new_status) @@ -159,28 +252,29 @@ void CacheItem::Impl::setStatus(ImageStatus new_status) return; status_ = new_status; - parent_.statusChanged(); + statusChanged(); } void CacheItem::Impl::imageConverted(bool success) { string const text = success ? "succeeded" : "failed"; - lyxerr[Debug::GRAPHICS] << "Image conversion " << text << "." << endl; + 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) { + lyxerr[Debug::GRAPHICS] << "Unable to find converted file!" + << endl; setStatus(ErrorConverting); if (zipped_) - lyx::unlink(unzipped_filename_); + unlink(unzipped_filename_); return; } @@ -208,14 +302,14 @@ void CacheItem::Impl::loadImage() void CacheItem::Impl::imageLoaded(bool success) { string const text = success ? "succeeded" : "failed"; - lyxerr[Debug::GRAPHICS] << "Image loading " << text << "." << endl; + lyxerr[Debug::GRAPHICS] << "Image loading " << text << '.' << endl; // Clean up after loading. if (zipped_) - lyx::unlink(unzipped_filename_); + unlink(unzipped_filename_); if (remove_loaded_file_ && unzipped_filename_ != file_to_load_) - lyx::unlink(file_to_load_); + unlink(file_to_load_); cl_.disconnect(); @@ -224,77 +318,92 @@ void CacheItem::Impl::imageLoaded(bool success) return; } + // Inform the outside world. setStatus(Loaded); } -} // namespace grfx + +} // namespace graphics +} // namespace lyx namespace { string const findTargetFormat(string const & from) { - typedef grfx::Image::FormatList FormatList; - FormatList const formats = grfx::Image::loadableFormats(); + typedef lyx::graphics::Image::FormatList FormatList; + FormatList const formats = lyx::graphics::Image::loadableFormats(); // There must be a format to load from. - lyx::Assert(!formats.empty()); + BOOST_ASSERT(!formats.empty()); // First ascertain if we can load directly with no conversion - FormatList::const_iterator it1 = formats.begin(); + FormatList::const_iterator it = formats.begin(); FormatList::const_iterator end = formats.end(); - for (; it1 != end; ++it1) { - if (from == *it1) - return *it1; + for (; it != end; ++it) { + if (from == *it) + return *it; } // So, we have to convert to a loadable format. Can we? - FormatList::const_iterator it2 = formats.begin(); - for (; it2 != end; ++it2) { - if (grfx::Converter::isReachable(from, *it2)) - return *it2; + it = formats.begin(); + for (; it != end; ++it) { + if (lyx::graphics::Converter::isReachable(from, *it)) + return *it; + else + lyxerr[Debug::GRAPHICS] + << "Unable to convert from " << from + << " to " << *it << std::endl; } - // Failed! so we have to try to convert it to XPM format + // Failed! so we have to try to convert it to PPM format // with the standard converter - return string("xpm"); + return string("ppm"); } } // anon namespace -namespace grfx { +namespace lyx { +namespace graphics { void CacheItem::Impl::convertToDisplayFormat() { setStatus(Converting); + + // First, check that the file exists! + if (!IsFileReadable(filename_)) { + if (status_ != ErrorNoFile) { + setStatus(ErrorNoFile); + lyxerr[Debug::GRAPHICS] + << "\tThe file is not readable" << endl; + } + return; + } + // Make a local copy in case we unzip it - string const filename = zippedFile(filename_) ? - unzipFile(filename_) : filename_; + string filename; + if ((zipped_ = zippedFile(filename_))) { + unzipped_filename_ = tempName(string(), filename_); + if (unzipped_filename_.empty()) { + setStatus(ErrorConverting); + lyxerr[Debug::GRAPHICS] + << "\tCould not create temporary file." << endl; + return; + } + filename = unzipFile(filename_, unzipped_filename_); + } else + filename = filename_; + string const displayed_filename = MakeDisplayPath(filename_); lyxerr[Debug::GRAPHICS] << "[GrahicsCacheItem::convertToDisplayFormat]\n" << "\tAttempting to convert image file: " << filename << "\n\twith displayed filename: " << displayed_filename << endl; - // First, check that the file exists! - if (!IsFileReadable(filename)) { - setStatus(ErrorNoFile); - lyxerr[Debug::GRAPHICS] << "\tThe file is not readable" << endl; - return; - } - string from = getExtFromContents(filename); - // Some old ps-files make problems, so we do not need direct - // loading of an ps-file - if (from == "ps") { - lyxerr[Debug::GRAPHICS] - << "\n\tThe file contains PostScript format data.\n" - << "\tchanging it to eps-format to get it converted to xpm\n"; - from = "eps"; - } else - lyxerr[Debug::GRAPHICS] - << "\n\tThe file contains " << from << " format data." << endl; + lyxerr[Debug::GRAPHICS] + << "\n\tThe file contains " << from << " format data." << endl; string const to = findTargetFormat(from); if (from == to) { @@ -311,19 +420,20 @@ void CacheItem::Impl::convertToDisplayFormat() // Add some stuff to create a uniquely named temporary file. // This file is deleted in loadImage after it is loaded into memory. - string const to_file_base = lyx::tempName(string(), temp); + string const to_file_base = tempName(string(), temp); remove_loaded_file_ = true; // Remove the temp file, we only want the name... - lyx::unlink(to_file_base); + // FIXME: This is unsafe! + unlink(to_file_base); // 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. converter_.reset(new Converter(filename, to_file_base, from, to)); - converter_->finishedConversion.connect( - boost::bind(&Impl::imageConverted, this, _1)); + converter_->connect(boost::bind(&Impl::imageConverted, this, _1)); converter_->startConversion(); } -} // namespace grfx +} // namespace graphics +} // namespace lyx