mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 21:21:32 +00:00
File monitoring is Go!
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4703 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
10fd14e55b
commit
6206e59009
@ -1,3 +1,15 @@
|
||||
2002-07-18 Angus Leeming <leeming@lyx.org>
|
||||
|
||||
* GraphicsCacheItem.[Ch]: add a FileMonitor variable to the the Impl
|
||||
class.
|
||||
(startMonitoring, monitoring, checksum): new methods to interact with
|
||||
the FileMonitor.
|
||||
|
||||
* GraphicsLoader.[Ch] (startMonitoring, monitoring, checksum): new
|
||||
methods invoking the CacheItem methods of the same name.
|
||||
(resetFile): if monitoring and the file changes, start monitoring this
|
||||
new file.
|
||||
|
||||
2002-07-17 Jean-Marc Lasgouttes <lasgouttes@freesurf.fr>
|
||||
|
||||
* Makefile.am: remove FileMonitor.[Ch]
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "GraphicsImage.h"
|
||||
#include "GraphicsConverter.h"
|
||||
|
||||
#include "support/FileMonitor.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "support/LAssert.h"
|
||||
@ -73,8 +75,22 @@ struct CacheItem::Impl : public boost::signals::trackable {
|
||||
*/
|
||||
void setStatus(ImageStatus new_status);
|
||||
|
||||
/** 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 const filename_;
|
||||
///
|
||||
FileMonitor const monitor_;
|
||||
|
||||
/// Is the file compressed?
|
||||
bool zipped_;
|
||||
@ -123,10 +139,26 @@ string const & CacheItem::filename() const
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@ -154,9 +186,51 @@ boost::signals::connection CacheItem::connect(slot_type const & slot) const
|
||||
|
||||
|
||||
CacheItem::Impl::Impl(string const & file)
|
||||
: filename_(file), zipped_(false),
|
||||
remove_loaded_file_(false), status_(WaitingToLoad)
|
||||
{}
|
||||
: 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())
|
||||
lyx::unlink(unzipped_filename_);
|
||||
unzipped_filename_.clear();
|
||||
|
||||
if (remove_loaded_file_ && !file_to_load_.empty())
|
||||
lyx::unlink(file_to_load_);
|
||||
remove_loaded_file_ = false;
|
||||
file_to_load_.clear();
|
||||
|
||||
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)
|
||||
@ -276,6 +350,17 @@ namespace grfx {
|
||||
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_;
|
||||
@ -285,13 +370,6 @@ void CacheItem::Impl::convertToDisplayFormat()
|
||||
<< "\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);
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\n\tThe file contains " << from << " format data." << endl;
|
||||
|
@ -59,6 +59,19 @@ public:
|
||||
/// It's in the cache. Now start the loading process.
|
||||
void startLoading() const;
|
||||
|
||||
/** Monitor any changes to the file.
|
||||
* There is no point monitoring the file before startLoading() is
|
||||
* invoked.
|
||||
*/
|
||||
void startMonitoring() const;
|
||||
///
|
||||
bool monitoring() const;
|
||||
/** Returns the check sum of filename() so that, for example, you can
|
||||
* ascertain whether to output a new PostScript version of the file
|
||||
* for a LaTeX run.
|
||||
*/
|
||||
unsigned long checksum() const;
|
||||
|
||||
/** Get the image associated with filename().
|
||||
* If the image is not yet loaded, returns 0.
|
||||
* This routine returns a pointer to const; if you want to modify it,
|
||||
|
@ -139,6 +139,33 @@ void Loader::startLoading(Inset const & inset, BufferView const & bv) const
|
||||
}
|
||||
|
||||
|
||||
void Loader::startMonitoring() const
|
||||
{
|
||||
if (!pimpl_->cached_item_.get())
|
||||
return;
|
||||
|
||||
pimpl_->cached_item_->startMonitoring();
|
||||
}
|
||||
|
||||
|
||||
bool Loader::monitoring() const
|
||||
{
|
||||
if (!pimpl_->cached_item_.get())
|
||||
return false;
|
||||
|
||||
return pimpl_->cached_item_->monitoring();
|
||||
}
|
||||
|
||||
|
||||
unsigned long Loader::checksum() const
|
||||
{
|
||||
if (!pimpl_->cached_item_.get())
|
||||
return 0;
|
||||
|
||||
return pimpl_->cached_item_->checksum();
|
||||
}
|
||||
|
||||
|
||||
string const & Loader::filename() const
|
||||
{
|
||||
static string const empty;
|
||||
@ -187,7 +214,12 @@ void Loader::Impl::resetFile(string const & file)
|
||||
if (file == old_file)
|
||||
return;
|
||||
|
||||
// If monitoring() the current file, should continue to monitor the
|
||||
// new file.
|
||||
bool continue_monitoring = false;
|
||||
|
||||
if (!old_file.empty()) {
|
||||
continue_monitoring = cached_item_->monitoring();
|
||||
cached_item_.reset();
|
||||
Cache::get().remove(old_file);
|
||||
}
|
||||
@ -206,6 +238,9 @@ void Loader::Impl::resetFile(string const & file)
|
||||
cached_item_ = gc.item(file);
|
||||
status_ = cached_item_->status();
|
||||
|
||||
if (continue_monitoring && !cached_item_->monitoring())
|
||||
cached_item_->startMonitoring();
|
||||
|
||||
cached_item_->connect(boost::bind(&Impl::statusChanged, this));
|
||||
}
|
||||
|
||||
@ -231,7 +266,7 @@ void Loader::Impl::statusChanged()
|
||||
|
||||
void Loader::Impl::createPixmap()
|
||||
{
|
||||
if (!cached_item_.get() || image_.get() ||
|
||||
if (!cached_item_.get() ||
|
||||
params_.display == NoDisplay || status_ != Loaded)
|
||||
return;
|
||||
|
||||
|
@ -73,6 +73,19 @@ public:
|
||||
*/
|
||||
void startLoading(Inset const &, BufferView const &) const;
|
||||
|
||||
/** Monitor any changes to the file.
|
||||
* There is no point monitoring the file before startLoading() is
|
||||
* invoked.
|
||||
*/
|
||||
void startMonitoring() const;
|
||||
///
|
||||
bool monitoring() const;
|
||||
/** Returns the check sum of filename() so that, for example, you can
|
||||
* ascertain whether to output a new PostScript version of the file
|
||||
* for a LaTeX run.
|
||||
*/
|
||||
unsigned long checksum() const;
|
||||
|
||||
/// How far have we got in loading the image?
|
||||
ImageStatus status() const;
|
||||
|
||||
|
@ -1,3 +1,10 @@
|
||||
2002-07-18 Angus Leeming <leeming@lyx.org>
|
||||
|
||||
* insetgraphics.C: clean-up comments (from Herbert).
|
||||
add a new checksum variable to the cache. Use it in PrepareFile.
|
||||
(draw): start monitoring the file for a change.
|
||||
(prepareFile): re-arrange a little to avoid unnecessary steps.
|
||||
|
||||
2002-07-17 Angus Leeming <leeming@lyx.org>
|
||||
|
||||
* insetgraphics.C (Cache c-tor): bind to the GraphicsLoader through
|
||||
|
@ -10,25 +10,7 @@
|
||||
* ====================================================== */
|
||||
|
||||
/*
|
||||
Known BUGS:
|
||||
|
||||
* If the image is from the clipart, and the document is moved to another
|
||||
directory, the user is screwed. Need a way to handle it.
|
||||
This amounts to a problem of when to use relative or absolute file paths
|
||||
We should probably use what the user asks to use... but when he chooses
|
||||
by the file dialog we normally get an absolute path and this may not be
|
||||
what the user meant.
|
||||
|
||||
Note that browseRelFile in helper_funcs.* provides a file name
|
||||
which is relative if it is at reference path (here puffer path)
|
||||
level or below, and an absolute path if the file name is not a
|
||||
`natural' relative file name. In any case,
|
||||
MakeAbsPath(filename, buf->filePath())
|
||||
is guaranteed to provide the correct absolute path. This is what is
|
||||
done know for include insets. Feel free to ask me -- JMarc
|
||||
14/01/2002
|
||||
|
||||
TODO Before initial production release:
|
||||
TODO
|
||||
|
||||
* What advanced features the users want to do?
|
||||
Implement them in a non latex dependent way, but a logical way.
|
||||
@ -162,6 +144,8 @@ struct InsetGraphics::Cache : boost::signals::trackable
|
||||
int old_ascent;
|
||||
///
|
||||
grfx::Loader loader;
|
||||
///
|
||||
unsigned long checksum;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -170,7 +154,7 @@ private:
|
||||
|
||||
|
||||
InsetGraphics::Cache::Cache(InsetGraphics & p)
|
||||
: old_ascent(0), parent_(p)
|
||||
: old_ascent(0), checksum(0), parent_(p)
|
||||
{
|
||||
loader.connect(boost::bind(&InsetGraphics::statusChanged, &parent_));
|
||||
}
|
||||
@ -327,9 +311,11 @@ void InsetGraphics::draw(BufferView * bv, LyXFont const & font,
|
||||
int old_x = int(x);
|
||||
x += lwidth;
|
||||
|
||||
if (cache_->loader.status() == grfx::WaitingToLoad) {
|
||||
if (cache_->loader.status() == grfx::WaitingToLoad)
|
||||
cache_->loader.startLoading(*this, *bv);
|
||||
}
|
||||
|
||||
if (!cache_->loader.monitoring())
|
||||
cache_->loader.startMonitoring();
|
||||
|
||||
// This will draw the graphics. If the graphics has not been loaded yet,
|
||||
// we draw just a rectangle.
|
||||
@ -626,41 +612,39 @@ string const InsetGraphics::prepareFile(Buffer const *buf) const
|
||||
if (!IsFileReadable(orig_file_with_path))
|
||||
return orig_file;
|
||||
|
||||
// If the file is compressed and we have specified that it should not be
|
||||
// uncompressed, then just return its name and let LaTeX do the rest!
|
||||
|
||||
// maybe that other zip extensions also be useful, especially the
|
||||
// ones that may be declared in texmf/tex/latex/config/graphics.cfg.
|
||||
// for example:
|
||||
/* -----------snip-------------
|
||||
{\DeclareGraphicsRule{.pz}{eps}{.bb}{}%
|
||||
\DeclareGraphicsRule{.eps.Z}{eps}{.eps.bb}{}%
|
||||
\DeclareGraphicsRule{.ps.Z}{eps}{.ps.bb}{}%
|
||||
\DeclareGraphicsRule{.ps.gz}{eps}{.ps.bb}{}%
|
||||
\DeclareGraphicsRule{.eps.gz}{eps}{.eps.bb}{}}}%
|
||||
-----------snip-------------*/
|
||||
|
||||
bool const zipped = zippedFile(orig_file_with_path);
|
||||
if (zipped)
|
||||
lyxerr[Debug::GRAPHICS] << "\twe have a zipped file ("
|
||||
<< getExtFromContents(orig_file_with_path) << ")\n";
|
||||
if (params().noUnzip && zipped) {
|
||||
|
||||
// If the file is compressed and we have specified that it
|
||||
// should not be uncompressed, then just return its name and
|
||||
// let LaTeX do the rest!
|
||||
if (zipped && params().noUnzip) {
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\tpass file unzipped to LaTeX but with full path.\n";
|
||||
// latex needs an absolue path, otherwise the coresponding
|
||||
// *.eps.bb file isn't found
|
||||
<< "\tpass zipped file to LaTeX but with full path.\n";
|
||||
// LaTeX needs an absolue path, otherwise the
|
||||
// coresponding *.eps.bb file isn't found
|
||||
return orig_file_with_path;
|
||||
}
|
||||
|
||||
// Ascertain whether the file has changed.
|
||||
unsigned long const new_checksum = cache_->loader.checksum();
|
||||
bool const file_has_changed = cache_->checksum != new_checksum;
|
||||
if (file_has_changed)
|
||||
cache_->checksum = new_checksum;
|
||||
|
||||
// temp_file will contain the file for LaTeX to act on if, for example,
|
||||
// we move it to a temp dir or uncompress it.
|
||||
string temp_file(orig_file);
|
||||
// Uncompress the file if necessary. If it has been uncompressed in
|
||||
// a previous call to prepareFile, do nothing.
|
||||
|
||||
if (zipped) {
|
||||
// Uncompress the file if necessary.
|
||||
// If it has been uncompressed in a previous call to
|
||||
// prepareFile, do nothing.
|
||||
temp_file = MakeAbsPath(OnlyFilename(temp_file), buf->tmppath);
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\ttemp_file: " << temp_file << endl;
|
||||
if (!IsFileReadable(temp_file)) {
|
||||
bool const success = lyx::copy(orig_file_with_path, temp_file);
|
||||
if (file_has_changed || !IsFileReadable(temp_file)) {
|
||||
bool const success = lyx::copy(orig_file_with_path,
|
||||
temp_file);
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\tCopying zipped file from "
|
||||
<< orig_file_with_path << " to " << temp_file
|
||||
@ -673,16 +657,17 @@ string const InsetGraphics::prepareFile(Buffer const *buf) const
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\tunzipped to " << orig_file_with_path << endl;
|
||||
}
|
||||
string const from = getExtFromContents(orig_file_with_path);
|
||||
|
||||
// "nice" means that the buffer is exported to LaTeX format but not
|
||||
// run through the LaTeX compiler.
|
||||
// if (nice)
|
||||
// no conversion needed!
|
||||
// Return the original filename as is, because we do not know
|
||||
// what the user decide.
|
||||
if (buf->niceFile)
|
||||
return orig_file;
|
||||
string const from = getExtFromContents(orig_file_with_path);
|
||||
string const to = findTargetFormat(from);
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\t we have: from " << from << " to " << to << '\n';
|
||||
|
||||
if (from == to && !lyxrc.use_tempdir)
|
||||
// No conversion is needed. LaTeX can handle the
|
||||
// graphic file as is.
|
||||
// This is true even if the orig_file is compressed.
|
||||
return RemoveExtension(orig_file_with_path);
|
||||
|
||||
// We're going to be running the exported buffer through the LaTeX
|
||||
// compiler, so must ensure that LaTeX can cope with the graphics
|
||||
@ -711,8 +696,8 @@ string const InsetGraphics::prepareFile(Buffer const *buf) const
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\tchanged to: " << temp_file << endl;
|
||||
|
||||
// if the file doen't exists, copy it into the tempdi
|
||||
if (!IsFileReadable(temp_file)) {
|
||||
// if the file doen't exists, copy it into the tempdir
|
||||
if (file_has_changed || !IsFileReadable(temp_file)) {
|
||||
bool const success = lyx::copy(orig_file_with_path, temp_file);
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\tcopying from " << orig_file_with_path << " to "
|
||||
@ -724,18 +709,11 @@ string const InsetGraphics::prepareFile(Buffer const *buf) const
|
||||
return orig_file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string const to = findTargetFormat(from);
|
||||
lyxerr[Debug::GRAPHICS]
|
||||
<< "\t we have: from " << from << " to " << to << '\n';
|
||||
if (from == to) {
|
||||
// No conversion is needed. LaTeX can handle the graphic file as is.
|
||||
// This is true even if the orig_file is compressed. We have to return
|
||||
// the orig_file_with_path, maybe it is a zipped one
|
||||
if (lyxrc.use_tempdir)
|
||||
if (from == to)
|
||||
// No conversion is needed. LaTeX can handle the
|
||||
// graphic file as is.
|
||||
return RemoveExtension(temp_file);
|
||||
return RemoveExtension(orig_file_with_path);
|
||||
}
|
||||
|
||||
string const outfile_base = RemoveExtension(temp_file);
|
||||
@ -821,6 +799,14 @@ int InsetGraphics::latex(Buffer const *buf, ostream & os,
|
||||
<< "\tBefore = " << before
|
||||
<< "\n\tafter = " << after << endl;
|
||||
|
||||
|
||||
// "nice" means that the buffer is exported to LaTeX format but not
|
||||
// run through the LaTeX compiler.
|
||||
if (buf->niceFile) {
|
||||
os << before <<'{' << params().filename << '}' << after;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Make the filename relative to the lyx file
|
||||
// and remove the extension so the LaTeX will use whatever is
|
||||
// appropriate (when there are several versions in different formats)
|
||||
|
@ -1 +0,0 @@
|
||||
timestamp
|
@ -1,3 +1,9 @@
|
||||
2002-07-18 Angus Leeming <leeming@lyx.org>
|
||||
|
||||
* FileMonitor.[Ch]: new files. Monitor a file for any change and emit a
|
||||
signal should it do so.
|
||||
|
||||
* Makefile.am: add FileMonitor.[Ch].
|
||||
|
||||
2002-07-18 André Pönitz <poenitz@gmx.net>
|
||||
|
||||
|
176
src/support/FileMonitor.C
Normal file
176
src/support/FileMonitor.C
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* \file FileMonitor.C
|
||||
* Copyright 2002 the LyX Team
|
||||
* Read the file COPYING
|
||||
*
|
||||
* \author Angus Leeming <leeming@lyx.org>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef __GNUG__
|
||||
#pragma implementation
|
||||
#endif
|
||||
|
||||
#include "FileMonitor.h"
|
||||
|
||||
#include "frontends/Timeout.h"
|
||||
|
||||
#include "support/FileInfo.h"
|
||||
#include "support/lyxlib.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/signals/trackable.hpp>
|
||||
|
||||
struct FileMonitor::Impl : public boost::signals::trackable {
|
||||
|
||||
///
|
||||
Impl(string const & file_with_path, int interval);
|
||||
|
||||
///
|
||||
void monitorFile();
|
||||
|
||||
///
|
||||
string filename_;
|
||||
|
||||
///
|
||||
Timeout timer_;
|
||||
|
||||
/// This signal is emitted if the file is modified (has a new checksum).
|
||||
boost::signal0<void> fileChanged_;
|
||||
|
||||
/** We use these to ascertain whether a file (once loaded successfully)
|
||||
* has changed.
|
||||
*/
|
||||
time_t timestamp_;
|
||||
///
|
||||
unsigned long checksum_;
|
||||
};
|
||||
|
||||
|
||||
FileMonitor::FileMonitor(string const & file_with_path, int interval)
|
||||
: pimpl_(new Impl(file_with_path, interval))
|
||||
{}
|
||||
|
||||
|
||||
FileMonitor::~FileMonitor()
|
||||
{}
|
||||
|
||||
|
||||
void FileMonitor::reset(string const & file_with_path) const
|
||||
{
|
||||
if (pimpl_->filename_ == file_with_path)
|
||||
return;
|
||||
|
||||
bool const monitor = pimpl_->timer_.running();
|
||||
if (monitor)
|
||||
stop();
|
||||
|
||||
pimpl_->filename_ = file_with_path;
|
||||
|
||||
if (monitor)
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
string const & FileMonitor::filename() const
|
||||
{
|
||||
return pimpl_->filename_;
|
||||
}
|
||||
|
||||
|
||||
void FileMonitor::start() const
|
||||
{
|
||||
if (monitoring())
|
||||
return;
|
||||
|
||||
FileInfo finfo(pimpl_->filename_);
|
||||
if (!finfo.isOK())
|
||||
return;
|
||||
|
||||
pimpl_->timestamp_ = finfo.getModificationTime();
|
||||
pimpl_->checksum_ = lyx::sum(pimpl_->filename_);
|
||||
|
||||
if (pimpl_->timestamp_ && pimpl_->checksum_) {
|
||||
pimpl_->timer_.start();
|
||||
} else {
|
||||
pimpl_->timestamp_ = 0;
|
||||
pimpl_->checksum_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FileMonitor::stop() const
|
||||
{
|
||||
pimpl_->timestamp_ = 0;
|
||||
pimpl_->checksum_ = 0;
|
||||
pimpl_->timer_.stop();
|
||||
}
|
||||
|
||||
|
||||
bool FileMonitor::monitoring() const
|
||||
{
|
||||
return pimpl_->timer_.running();
|
||||
}
|
||||
|
||||
|
||||
unsigned long FileMonitor::checksum() const
|
||||
{
|
||||
// If we aren't actively monitoring the file, then recompute the
|
||||
// checksum explicitly.
|
||||
if (!pimpl_->timer_.running() && !pimpl_->filename_.empty())
|
||||
return lyx::sum(pimpl_->filename_);
|
||||
|
||||
return pimpl_->checksum_;
|
||||
}
|
||||
|
||||
|
||||
boost::signals::connection FileMonitor::connect(slot_type const & slot) const
|
||||
{
|
||||
return pimpl_->fileChanged_.connect(slot);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------
|
||||
// Implementation details follow
|
||||
//------------------------------
|
||||
|
||||
|
||||
FileMonitor::Impl::Impl(string const & file_with_path, int interval)
|
||||
: filename_(file_with_path),
|
||||
timer_(interval, Timeout::ONETIME),
|
||||
timestamp_(0),
|
||||
checksum_(0)
|
||||
{
|
||||
timer_.timeout.connect(boost::bind(&Impl::monitorFile, this));
|
||||
}
|
||||
|
||||
|
||||
void FileMonitor::Impl::monitorFile()
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
FileInfo finfo(filename_);
|
||||
if (!finfo.isOK()) {
|
||||
changed = timestamp_ || checksum_;
|
||||
timestamp_ = 0;
|
||||
checksum_ = 0;
|
||||
|
||||
} else {
|
||||
time_t const new_timestamp = finfo.getModificationTime();
|
||||
|
||||
if (new_timestamp != timestamp_) {
|
||||
timestamp_ = new_timestamp;
|
||||
|
||||
unsigned long const new_checksum = lyx::sum(filename_);
|
||||
if (new_checksum != checksum_) {
|
||||
checksum_ = new_checksum;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer_.start();
|
||||
if (changed)
|
||||
fileChanged_();
|
||||
}
|
68
src/support/FileMonitor.h
Normal file
68
src/support/FileMonitor.h
Normal file
@ -0,0 +1,68 @@
|
||||
// -*- C++ -*-
|
||||
/*
|
||||
* \file FileMonitor.h
|
||||
* Copyright 2002 the LyX Team
|
||||
* Read the file COPYING
|
||||
*
|
||||
* \author Angus Leeming <leeming@lyx.org>
|
||||
*
|
||||
* FileMonitor monitors a file and informs a listener when that file has
|
||||
* changed.
|
||||
*/
|
||||
|
||||
#ifndef FILEMONITOR_H
|
||||
#define FILEMONITOR_H
|
||||
|
||||
#ifdef __GNUG__
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
#include "LString.h"
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/signals/signal0.hpp>
|
||||
|
||||
class FileMonitor : boost::noncopyable {
|
||||
public:
|
||||
/** Once monitoring begins, the file will be monitored every
|
||||
* interval ms.
|
||||
*/
|
||||
FileMonitor(string const & file_with_path, int interval);
|
||||
|
||||
/// Define an empty d-tor out-of-line to keep boost::scoped_ptr happy.
|
||||
~FileMonitor();
|
||||
|
||||
///
|
||||
void reset(string const & file_with_path) const;
|
||||
|
||||
///
|
||||
string const & filename() const;
|
||||
|
||||
/// Begin monitoring the file
|
||||
void start() const;
|
||||
///
|
||||
void stop() const;
|
||||
///
|
||||
bool monitoring() const;
|
||||
|
||||
/** The checksum is recomputed whenever the file is modified.
|
||||
* If the file is not being monitored, then the checksum will be
|
||||
* recomputed each time this function is called.
|
||||
*/
|
||||
unsigned long checksum() const;
|
||||
|
||||
/// Connect and you'll be informed when the file has changed.
|
||||
typedef boost::signal0<void>::slot_type slot_type;
|
||||
///
|
||||
boost::signals::connection connect(slot_type const &) const;
|
||||
|
||||
private:
|
||||
/// 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_;
|
||||
};
|
||||
|
||||
#endif // FILEMONITOR_H
|
@ -16,6 +16,8 @@ libsupport_la_SOURCES = \
|
||||
DebugStream.h \
|
||||
FileInfo.C \
|
||||
FileInfo.h \
|
||||
FileMonitor.h \
|
||||
FileMonitor.C \
|
||||
LAssert.C \
|
||||
LAssert.h \
|
||||
LIstream.h \
|
||||
|
Loading…
Reference in New Issue
Block a user