X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fgraphics%2FGraphicsCacheItem.cpp;h=f54ce80ec3f0d790c1169745ace908d09eb1e888;hb=47973dc2b448dd2753f0b55c057ceda9e349a5f1;hp=592e51c5257cdf9c14f77754fd2b77cbbeac291b;hpb=264f32ec376b04538d9d0a2d1664de7527772f79;p=lyx.git diff --git a/src/graphics/GraphicsCacheItem.cpp b/src/graphics/GraphicsCacheItem.cpp index 592e51c525..f54ce80ec3 100644 --- a/src/graphics/GraphicsCacheItem.cpp +++ b/src/graphics/GraphicsCacheItem.cpp @@ -4,7 +4,7 @@ * Licence details can be found in the file COPYING. * * \author Baruch Even - * \author Herbert Voß + * \author Herbert Voß * \author Angus Leeming * * Full author contact details are available in file CREDITS. @@ -14,6 +14,7 @@ #include "GraphicsCacheItem.h" +#include "Buffer.h" #include "GraphicsCache.h" #include "GraphicsConverter.h" #include "GraphicsImage.h" @@ -25,8 +26,10 @@ #include "support/FileName.h" #include "support/filetools.h" #include "support/FileMonitor.h" +#include "support/lassert.h" +#include "support/unique_ptr.h" -#include +#include "support/TempFile.h" using namespace std; using namespace lyx::support; @@ -35,11 +38,20 @@ namespace lyx { namespace graphics { -class CacheItem::Impl : public boost::signals::trackable { +class CacheItem::Impl { public: /// - Impl(FileName const & file); + Impl(FileName const & file, FileName const & doc_file); + + void startMonitor(); + + /** + * If no file conversion is needed, then tryDisplayFormat() calls + * loadImage() directly. + * \return true if a conversion is necessary and no error occurred. + */ + bool tryDisplayFormat(FileName & filename, string & from); /** Start the image conversion process, checking first that it is * necessary. If it is necessary, then a conversion task is started. @@ -48,9 +60,6 @@ public: * 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(). */ @@ -59,7 +68,7 @@ public: /** Load the image into memory. This is called either from * convertToDisplayFormat() direct or from imageConverted(). */ - void loadImage(); + bool loadImage(); /** Get a notification when the image conversion is done. * Connected to a signal on_finish_ which is passed to @@ -86,8 +95,10 @@ public: /// The filename we refer too. FileName const filename_; + /// The document filename this graphic item belongs to + FileName const doc_file_; /// - FileMonitor const monitor_; + ActiveFileMonitorPtr monitor_; /// Is the file compressed? bool zipped_; @@ -103,23 +114,20 @@ public: bool remove_loaded_file_; /// The image and its loading status. - boost::shared_ptr image_; + std::shared_ptr image_; /// ImageStatus status_; /// This signal is emitted when the image loading status changes. - boost::signal statusChanged; - - /// The connection of the signal ConvProcess::finishedConversion, - boost::signals::connection cc_; + signals2::signal statusChanged; /// - boost::scoped_ptr converter_; + unique_ptr converter_; }; -CacheItem::CacheItem(FileName const & file) - : pimpl_(new Impl(file)) +CacheItem::CacheItem(FileName const & file, FileName const & doc_file) + : pimpl_(new Impl(file,doc_file)) {} @@ -135,6 +143,20 @@ FileName const & CacheItem::filename() const } +bool CacheItem::tryDisplayFormat() const +{ + if (pimpl_->status_ != WaitingToLoad) + pimpl_->reset(); + FileName filename; + string from; + bool const conversion_needed = pimpl_->tryDisplayFormat(filename, from); + bool const success = status() == Loaded && !conversion_needed; + if (!success) + pimpl_->reset(); + return success; +} + + void CacheItem::startLoading() const { pimpl_->startLoading(); @@ -143,20 +165,21 @@ void CacheItem::startLoading() const void CacheItem::startMonitoring() const { - if (!pimpl_->monitor_.monitoring()) - pimpl_->monitor_.start(); + pimpl_->startMonitor(); } bool CacheItem::monitoring() const { - return pimpl_->monitor_.monitoring(); + return (bool)pimpl_->monitor_; } -unsigned long CacheItem::checksum() const +void CacheItem::checkModifiedAsync() const { - return pimpl_->monitor_.checksum(); + if (!pimpl_->monitor_) + return; + pimpl_->monitor_->checkModifiedAsync(); } @@ -172,7 +195,7 @@ ImageStatus CacheItem::status() const } -boost::signals::connection CacheItem::connect(slot_type const & slot) const +signals2::connection CacheItem::connect(slot_type const & slot) const { return pimpl_->statusChanged.connect(slot); } @@ -183,14 +206,21 @@ boost::signals::connection CacheItem::connect(slot_type const & slot) const //------------------------------ -CacheItem::Impl::Impl(FileName const & file) - : filename_(file), - monitor_(file, 2000), +CacheItem::Impl::Impl(FileName const & file, FileName const & doc_file) + : filename_(file), doc_file_(doc_file), zipped_(false), remove_loaded_file_(false), status_(WaitingToLoad) +{} + + +void CacheItem::Impl::startMonitor() { - monitor_.connect(boost::bind(&Impl::startLoading, this)); + if (monitor_) + return; + monitor_ = FileSystemWatcher::activeMonitor(filename_); + // Disconnected at the same time as this is destroyed. + monitor_->connect([=](bool /* exists */){ startLoading(); }); } @@ -216,15 +246,12 @@ void CacheItem::Impl::reset() file_to_load_.erase(); to_.erase(); - if (image_.get()) + if (image_) image_.reset(); status_ = WaitingToLoad; - if (cc_.connected()) - cc_.disconnect(); - - if (converter_.get()) + if (converter_) converter_.reset(); } @@ -244,10 +271,9 @@ void CacheItem::Impl::imageConverted(bool success) string const text = success ? "succeeded" : "failed"; LYXERR(Debug::GRAPHICS, "Image conversion " << text << '.'); - file_to_load_ = converter_.get() ? - FileName(converter_->convertedFile()) : FileName(); + file_to_load_ = converter_ ? FileName(converter_->convertedFile()) + : FileName(); converter_.reset(); - cc_.disconnect(); success = !file_to_load_.empty() && file_to_load_.isReadableFile(); @@ -264,18 +290,17 @@ void CacheItem::Impl::imageConverted(bool success) // Add the converted file to the file cache ConverterCache::get().add(filename_, to_, file_to_load_); - loadImage(); + setStatus(loadImage() ? Loaded : ErrorLoading); } // This function gets called from the callback after the image has been // converted successfully. -void CacheItem::Impl::loadImage() +bool CacheItem::Impl::loadImage() { - setStatus(Loading); LYXERR(Debug::GRAPHICS, "Loading image."); - image_.reset(Image::newImage()); + image_.reset(newImage()); bool success = image_->load(file_to_load_); string const text = success ? "succeeded" : "failed"; @@ -288,23 +313,16 @@ void CacheItem::Impl::loadImage() if (remove_loaded_file_ && unzipped_filename_ != file_to_load_) file_to_load_.removeFile(); - if (!success) { - setStatus(ErrorLoading); - return; - } - - // Inform the outside world. - setStatus(Loaded); + return success; } -static string const findTargetFormat(string const & from) -{ - typedef vector FormatList; - FormatList const & formats = Cache::get().loadableFormats(); +typedef vector FormatList; +static string const findTargetFormat(FormatList const & format_list, string const & from) +{ // There must be a format to load from. - LASSERT(!formats.empty(), /**/); + LASSERT(!theFormats().empty(), return string()); // Use the standard converter if we don't know the format to load // from. @@ -312,15 +330,15 @@ static string const findTargetFormat(string const & from) return string("ppm"); // First ascertain if we can load directly with no conversion - FormatList::const_iterator it = formats.begin(); - FormatList::const_iterator end = formats.end(); + FormatList::const_iterator it = format_list.begin(); + FormatList::const_iterator end = format_list.end(); for (; it != end; ++it) { if (from == *it) return *it; } // So, we have to convert to a loadable format. Can we? - it = formats.begin(); + it = format_list.begin(); for (; it != end; ++it) { if (lyx::graphics::Converter::isReachable(from, *it)) return *it; @@ -335,79 +353,102 @@ static string const findTargetFormat(string const & from) } -void CacheItem::Impl::convertToDisplayFormat() +bool CacheItem::Impl::tryDisplayFormat(FileName & filename, string & from) { - setStatus(Converting); - // First, check that the file exists! + filename_.refresh(); if (!filename_.isReadableFile()) { if (status_ != ErrorNoFile) { - setStatus(ErrorNoFile); + status_ = ErrorNoFile; LYXERR(Debug::GRAPHICS, "\tThe file is not readable"); } - return; + return false; } - // Make a local copy in case we unzip it - FileName filename; - zipped_ = filename_.isZippedFile(); + zipped_ = theFormats().isZippedFile(filename_); if (zipped_) { - unzipped_filename_ = FileName::tempName( - filename_.toFilesystemEncoding()); + string tempname = unzippedFileName(filename_.toFilesystemEncoding()); + string const ext = getExtension(tempname); + tempname = changeExtension(tempname, "") + "-XXXXXX"; + if (!ext.empty()) + tempname = addExtension(tempname, ext); + TempFile tempfile(tempname); + tempfile.setAutoRemove(false); + unzipped_filename_ = tempfile.name(); if (unzipped_filename_.empty()) { - setStatus(ErrorConverting); + status_ = ErrorConverting; LYXERR(Debug::GRAPHICS, "\tCould not create temporary file."); - return; + return false; } filename = unzipFile(filename_, unzipped_filename_.toFilesystemEncoding()); } else { filename = filename_; } - docstring const displayed_filename = makeDisplayPath(filename_.absFilename()); + docstring const displayed_filename = makeDisplayPath(filename_.absFileName()); LYXERR(Debug::GRAPHICS, "[CacheItem::Impl::convertToDisplayFormat]\n" << "\tAttempting to convert image file: " << filename << "\n\twith displayed filename: " << to_utf8(displayed_filename)); - string const from = formats.getFormatFromFile(filename); + from = theFormats().getFormatFromFile(filename); if (from.empty()) { - setStatus(ErrorConverting); + status_ = ErrorConverting; LYXERR(Debug::GRAPHICS, "\tCould not determine file format."); } LYXERR(Debug::GRAPHICS, "\n\tThe file contains " << from << " format data."); - to_ = findTargetFormat(from); + to_ = findTargetFormat(Cache::get().loadableFormats(), from); if (from == to_) { // No conversion needed! LYXERR(Debug::GRAPHICS, "\tNo conversion needed (from == to)!"); file_to_load_ = filename; - loadImage(); - return; + status_ = loadImage() ? Loaded : ErrorLoading; + return false; } if (ConverterCache::get().inCache(filename, to_)) { LYXERR(Debug::GRAPHICS, "\tNo conversion needed (file in file cache)!"); file_to_load_ = ConverterCache::get().cacheName(filename, to_); - loadImage(); - return; + status_ = loadImage() ? Loaded : ErrorLoading; + return false; } + return true; +} + +void CacheItem::Impl::convertToDisplayFormat() +{ LYXERR(Debug::GRAPHICS, "\tConverting it to " << to_ << " format."); + // Make a local copy in case we unzip it + FileName filename; + string from; + if (!tryDisplayFormat(filename, from)) { + // The image status has changed, tell it to the outside world. + statusChanged(); + return; + } + + // We will need a conversion, tell it to the outside world. + setStatus(Converting); + // Add some stuff to create a uniquely named temporary file. // This file is deleted in loadImage after it is loaded into memory. - FileName const to_file_base = FileName::tempName("CacheItem"); + TempFile tempfile("CacheItem"); + tempfile.setAutoRemove(false); + FileName const to_file_base = tempfile.name(); remove_loaded_file_ = true; - // Remove the temp file, we only want the name... - // FIXME: This is unsafe! - to_file_base.removeFile(); - // 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.absFilename(), from, to_)); - converter_->connect(boost::bind(&Impl::imageConverted, this, _1)); + converter_ = make_unique(doc_file_, filename, + to_file_base.absFileName(), + from, to_); + // Connection is closed at the same time as *this is destroyed. + converter_->connect([this](bool success){ + imageConverted(success); + }); converter_->startConversion(); }