Detach Buffer preview and update preview in a new thread. Only for Qt4.4 users. This new feature can be disabled by setting EXPORT_in_THREAD to 0 in GuiView.cpp.

Two things are missing (but are fixable):
- the lack of feedback of the background latex compilation
- the error list is not shown in case of compilation error.

* Buffer:
- create a "cloned buffer" type.
- Transfer LFUN_MASTER_BUFFER_UPDATE, LFUN_MASTER_BUFFER_VIEW, LFUN_BUFFER_UPDATE and LFUN_BUFFER_VIEW to GuiView. This is good itself as these LFUN are GUI oriented.

* GuiView: detach the above LFUNs to a new thread as was already done for autosave. 


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@32584 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2009-12-18 22:51:06 +00:00
parent 5ad8d44ce2
commit 4ed0169064
4 changed files with 186 additions and 92 deletions

View File

@ -147,7 +147,7 @@ class BufferSet : public std::set<Buffer const *> {};
class Buffer::Impl class Buffer::Impl
{ {
public: public:
Impl(Buffer & parent, FileName const & file, bool readonly); Impl(Buffer & parent, FileName const & file, bool readonly, Buffer const * cloned_buffer);
~Impl() ~Impl()
{ {
@ -258,9 +258,13 @@ public:
LYXERR0("Warning: a buffer should not have two parents!"); LYXERR0("Warning: a buffer should not have two parents!");
parent_buffer = pb; parent_buffer = pb;
} }
private:
/// So we can force access via the accessors. /// So we can force access via the accessors.
mutable Buffer const * parent_buffer; mutable Buffer const * parent_buffer;
/// If non zero, this buffer is a clone of existing buffer \p cloned_buffer_
/// This one is useful for preview detached in a thread.
Buffer const * cloned_buffer_;
}; };
@ -283,22 +287,31 @@ static FileName createBufferTmpDir()
} }
Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_) Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_,
Buffer const * cloned_buffer)
: lyx_clean(true), bak_clean(true), unnamed(false), : lyx_clean(true), bak_clean(true), unnamed(false),
read_only(readonly_), filename(file), file_fully_loaded(false), read_only(readonly_), filename(file), file_fully_loaded(false),
toc_backend(&parent), macro_lock(false), timestamp_(0), toc_backend(&parent), macro_lock(false), timestamp_(0),
checksum_(0), wa_(0), undo_(parent), bibinfoCacheValid_(false), checksum_(0), wa_(0), undo_(parent), bibinfoCacheValid_(false),
parent_buffer(0) parent_buffer(0), cloned_buffer_(cloned_buffer)
{ {
if (!cloned_buffer_) {
temppath = createBufferTmpDir(); temppath = createBufferTmpDir();
lyxvc.setBuffer(&parent); lyxvc.setBuffer(&parent);
if (use_gui) if (use_gui)
wa_ = new frontend::WorkAreaManager; wa_ = new frontend::WorkAreaManager;
return;
}
temppath = cloned_buffer_->d->temppath;
file_fully_loaded = true;
params = cloned_buffer_->d->params;
inset = static_cast<InsetText *>(cloned_buffer_->d->inset->clone());
inset->setBuffer(parent);
} }
Buffer::Buffer(string const & file, bool readonly) Buffer::Buffer(string const & file, bool readonly, Buffer const * cloned_buffer)
: d(new Impl(*this, FileName(file), readonly)), gui_(0) : d(new Impl(*this, FileName(file), readonly, cloned_buffer)), gui_(0)
{ {
LYXERR(Debug::INFO, "Buffer::Buffer()"); LYXERR(Debug::INFO, "Buffer::Buffer()");
@ -343,7 +356,7 @@ Buffer::~Buffer()
d->children_positions.clear(); d->children_positions.clear();
d->position_to_children.clear(); d->position_to_children.clear();
if (!d->temppath.destroyDirectory()) { if (!d->cloned_buffer_ && !d->temppath.destroyDirectory()) {
Alert::warning(_("Could not remove temporary directory"), Alert::warning(_("Could not remove temporary directory"),
bformat(_("Could not remove the temporary directory %1$s"), bformat(_("Could not remove the temporary directory %1$s"),
from_utf8(d->temppath.absFilename()))); from_utf8(d->temppath.absFilename())));
@ -358,12 +371,7 @@ Buffer::~Buffer()
Buffer * Buffer::clone() const Buffer * Buffer::clone() const
{ {
Buffer * clone = new Buffer(fileName().absFilename(), false); return new Buffer(fileName().absFilename(), false, this);
clone->d->file_fully_loaded = true;
clone->d->params = d->params;
clone->d->inset = static_cast<InsetText *>(d->inset->clone());
clone->d->inset->setBuffer(*clone);
return clone;
} }
@ -1652,6 +1660,21 @@ void Buffer::markDepClean(string const & name)
} }
bool Buffer::isExportableFormat(string const & format) const
{
typedef vector<Format const *> Formats;
Formats formats;
formats = exportableFormats(true);
Formats::const_iterator fit = formats.begin();
Formats::const_iterator end = formats.end();
for (; fit != end ; ++fit) {
if ((*fit)->name() == format)
return true;
}
return false;
}
bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
{ {
if (isInternal()) { if (isInternal()) {
@ -1687,27 +1710,6 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
break; break;
} }
case LFUN_MASTER_BUFFER_UPDATE:
case LFUN_MASTER_BUFFER_VIEW:
enable = parent() != 0;
break;
case LFUN_BUFFER_UPDATE:
case LFUN_BUFFER_VIEW: {
string format = to_utf8(cmd.argument());
if (cmd.argument().empty())
format = getDefaultOutputFormat();
typedef vector<Format const *> Formats;
Formats formats;
formats = exportableFormats(true);
Formats::const_iterator fit = formats.begin();
Formats::const_iterator end = formats.end();
enable = false;
for (; fit != end ; ++fit) {
if ((*fit)->name() == format)
enable = true;
}
break;
}
case LFUN_BUFFER_CHKTEX: case LFUN_BUFFER_CHKTEX:
enable = isLatex() && !lyxrc.chktex_command.empty(); enable = isLatex() && !lyxrc.chktex_command.empty();
break; break;
@ -1773,10 +1775,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
break; break;
case LFUN_BUFFER_EXPORT: { case LFUN_BUFFER_EXPORT: {
if (argument == "custom") {
lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
break;
}
bool success = doExport(argument, false); bool success = doExport(argument, false);
dr.setError(success); dr.setError(success);
if (!success) if (!success)
@ -1785,38 +1783,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
break; break;
} }
case LFUN_BUFFER_UPDATE: {
string format = argument;
if (argument.empty())
format = getDefaultOutputFormat();
doExport(format, true);
break;
}
case LFUN_BUFFER_VIEW: {
string format = argument;
if (argument.empty())
format = getDefaultOutputFormat();
preview(format);
break;
}
case LFUN_MASTER_BUFFER_UPDATE: {
string format = argument;
if (argument.empty())
format = masterBuffer()->getDefaultOutputFormat();
masterBuffer()->doExport(format, true);
break;
}
case LFUN_MASTER_BUFFER_VIEW: {
string format = argument;
if (argument.empty())
format = masterBuffer()->getDefaultOutputFormat();
masterBuffer()->preview(format);
break;
}
case LFUN_BUILD_PROGRAM: case LFUN_BUILD_PROGRAM:
doExport("program", true); doExport("program", true);
break; break;
@ -3132,14 +3098,18 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
path = p; path = p;
} }
} }
if (!path.empty()) if (path.empty()) {
runparams.flavor = theConverters().getFlavor(path); if (!put_in_tempdir) {
else { // Only show this alert if this is an export to a non-temporary
Alert::error(_("Couldn't export file"), // file (not for previewing).
bformat(_("No information for exporting the format %1$s."), Alert::error(_("Couldn't export file"), bformat(
_("No information for exporting the format %1$s."),
formats.prettyName(format))); formats.prettyName(format)));
}
return false; return false;
} }
runparams.flavor = theConverters().getFlavor(path);
} else { } else {
backend_format = format; backend_format = format;
// FIXME: Don't hardcode format names here, but use a flag // FIXME: Don't hardcode format names here, but use a flag

View File

@ -125,7 +125,8 @@ public:
}; };
/// Constructor /// Constructor
explicit Buffer(std::string const & file, bool b = false); explicit Buffer(std::string const & file, bool readonly = false,
Buffer const * cloned_buffer = 0);
/// Destructor /// Destructor
~Buffer(); ~Buffer();
@ -512,6 +513,8 @@ public:
bool isExportable(std::string const & format) const; bool isExportable(std::string const & format) const;
/// ///
std::vector<Format const *> exportableFormats(bool only_viewable) const; std::vector<Format const *> exportableFormats(bool only_viewable) const;
///
bool isExportableFormat(std::string const & format) const;
/// ///
typedef std::vector<std::pair<InsetRef *, ParIterator> > References; typedef std::vector<std::pair<InsetRef *, ParIterator> > References;

View File

@ -102,6 +102,8 @@
#include <QUrl> #include <QUrl>
#include <QScrollBar> #include <QScrollBar>
#define EXPORT_in_THREAD 1
// QtConcurrent was introduced in Qt 4.4 // QtConcurrent was introduced in Qt 4.4
#if (QT_VERSION >= 0x040400) #if (QT_VERSION >= 0x040400)
#include <QFuture> #include <QFuture>
@ -300,7 +302,8 @@ public:
#if (QT_VERSION >= 0x040400) #if (QT_VERSION >= 0x040400)
/// ///
QFutureWatcher<bool> autosave_watcher_; QFutureWatcher<docstring> autosave_watcher_;
QFutureWatcher<docstring> preview_watcher_;
#endif #endif
}; };
@ -365,7 +368,9 @@ GuiView::GuiView(int id)
#if (QT_VERSION >= 0x040400) #if (QT_VERSION >= 0x040400)
connect(&d.autosave_watcher_, SIGNAL(finished()), this, connect(&d.autosave_watcher_, SIGNAL(finished()), this,
SLOT(autoSaveFinished())); SLOT(threadFinished()));
connect(&d.preview_watcher_, SIGNAL(finished()), this,
SLOT(threadFinished()));
#endif #endif
} }
@ -376,12 +381,12 @@ GuiView::~GuiView()
} }
void GuiView::autoSaveFinished() void GuiView::threadFinished()
{ {
#if (QT_VERSION >= 0x040400) #if (QT_VERSION >= 0x040400)
docstring const msg = d.autosave_watcher_.result() QFutureWatcher<docstring> const * watcher =
? _("Automatic save done.") : _("Automatic save failed!"); static_cast<QFutureWatcher<docstring> const *>(sender());
message(msg); message(watcher->result());
#endif #endif
} }
@ -1222,7 +1227,7 @@ BufferView const * GuiView::currentBufferView() const
} }
static bool saveAndDestroyBuffer(Buffer * buffer, FileName const & fname) static docstring saveAndDestroyBuffer(Buffer * buffer, FileName const & fname)
{ {
bool failed = true; bool failed = true;
FileName const tmp_ret = FileName::tempName("lyxauto"); FileName const tmp_ret = FileName::tempName("lyxauto");
@ -1235,7 +1240,9 @@ static bool saveAndDestroyBuffer(Buffer * buffer, FileName const & fname)
failed = buffer->writeFile(fname); failed = buffer->writeFile(fname);
} }
delete buffer; delete buffer;
return !failed; return failed
? _("Automatic save failed!")
: _("Automatic save done.");
} }
@ -1249,7 +1256,7 @@ void GuiView::autoSave()
return; return;
#if (QT_VERSION >= 0x040400) #if (QT_VERSION >= 0x040400)
QFuture<bool> f = QtConcurrent::run(saveAndDestroyBuffer, buffer->clone(), QFuture<docstring> f = QtConcurrent::run(saveAndDestroyBuffer, buffer->clone(),
buffer->getAutosaveFilename()); buffer->getAutosaveFilename());
d.autosave_watcher_.setFuture(f); d.autosave_watcher_.setFuture(f);
#else #else
@ -1296,6 +1303,24 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
case LFUN_BUFFER_IMPORT: case LFUN_BUFFER_IMPORT:
break; break;
case LFUN_MASTER_BUFFER_UPDATE:
case LFUN_MASTER_BUFFER_VIEW:
enable = doc_buffer && doc_buffer->parent() != 0;
break;
case LFUN_BUFFER_UPDATE:
case LFUN_BUFFER_VIEW: {
if (!doc_buffer) {
enable = false;
break;
}
string format = to_utf8(cmd.argument());
if (cmd.argument().empty())
format = doc_buffer->getDefaultOutputFormat();
enable = doc_buffer->isExportableFormat(format);
break;
}
case LFUN_BUFFER_RELOAD: case LFUN_BUFFER_RELOAD:
enable = doc_buffer && !doc_buffer->isUnnamed() enable = doc_buffer && !doc_buffer->isUnnamed()
&& doc_buffer->fileName().exists() && doc_buffer->fileName().exists()
@ -2585,6 +2610,26 @@ bool GuiView::goToFileRow(string const & argument)
} }
static docstring exportAndDestroy(Buffer * buffer, docstring const & format)
{
bool const success = buffer->doExport(to_utf8(format), true);
delete buffer;
return success
? bformat(_("Successful export to format: %1$s."), format)
: bformat(_("Error exporting to format: %1$s."), format);
}
static docstring previewAndDestroy(Buffer * buffer, docstring const & format)
{
bool const success = buffer->preview(to_utf8(format));
delete buffer;
return success
? bformat(_("Successful preview of format: %1$s."), format)
: bformat(_("Error previewing format: %1$s."), format);
}
bool GuiView::dispatch(FuncRequest const & cmd) bool GuiView::dispatch(FuncRequest const & cmd)
{ {
BufferView * bv = currentBufferView(); BufferView * bv = currentBufferView();
@ -2603,6 +2648,8 @@ bool GuiView::dispatch(FuncRequest const & cmd)
return true; return true;
} }
string const argument = to_utf8(cmd.argument());
switch(cmd.action) { switch(cmd.action) {
case LFUN_BUFFER_CHILD_OPEN: case LFUN_BUFFER_CHILD_OPEN:
openChildDocument(to_utf8(cmd.argument())); openChildDocument(to_utf8(cmd.argument()));
@ -2612,6 +2659,80 @@ bool GuiView::dispatch(FuncRequest const & cmd)
importDocument(to_utf8(cmd.argument())); importDocument(to_utf8(cmd.argument()));
break; break;
case LFUN_BUFFER_EXPORT: {
if (!doc_buffer)
break;
if (cmd.argument() == "custom") {
lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
break;
}
if (doc_buffer->doExport(argument, false)) {
message(bformat(_("Error exporting to format: %1$s."),
cmd.argument()));
}
break;
}
case LFUN_BUFFER_UPDATE: {
if (!doc_buffer)
break;
string format = argument;
if (argument.empty())
format = doc_buffer->getDefaultOutputFormat();
#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
QFuture<docstring> f = QtConcurrent::run(exportAndDestroy,
doc_buffer->clone(), cmd.argument());
d.preview_watcher_.setFuture(f);
#else
doc_buffer->doExport(format, true);
#endif
break;
}
case LFUN_BUFFER_VIEW: {
if (!doc_buffer)
break;
string format = argument;
if (argument.empty())
format = doc_buffer->getDefaultOutputFormat();
#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
QFuture<docstring> f = QtConcurrent::run(previewAndDestroy,
doc_buffer->clone(), cmd.argument());
d.preview_watcher_.setFuture(f);
#else
doc_buffer->preview(format);
#endif
break;
}
case LFUN_MASTER_BUFFER_UPDATE: {
if (!doc_buffer)
break;
string format = argument;
Buffer const * master = doc_buffer->masterBuffer();
if (argument.empty())
format = master->getDefaultOutputFormat();
#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
QFuture<docstring> f = QtConcurrent::run(exportAndDestroy,
master->clone(), cmd.argument());
d.preview_watcher_.setFuture(f);
#else
master->doExport(format, true);
#endif
break;
}
case LFUN_MASTER_BUFFER_VIEW: {
string format = argument;
Buffer const * master = doc_buffer->masterBuffer();
if (argument.empty())
format = master->getDefaultOutputFormat();
#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
QFuture<docstring> f = QtConcurrent::run(previewAndDestroy,
master->clone(), cmd.argument());
d.preview_watcher_.setFuture(f);
#else
master->preview(format);
#endif
break;
}
case LFUN_BUFFER_SWITCH: case LFUN_BUFFER_SWITCH:
if (FileName::isAbsolute(to_utf8(cmd.argument()))) { if (FileName::isAbsolute(to_utf8(cmd.argument()))) {
Buffer * buffer = Buffer * buffer =

View File

@ -180,8 +180,8 @@ private Q_SLOTS:
void normalSizedIcons(); void normalSizedIcons();
void bigSizedIcons(); void bigSizedIcons();
/// For completion of Buffer autosave thread. /// For completion of autosave or exporrt threads.
void autoSaveFinished(); void threadFinished();
private: private:
/// Open given child document in current buffer directory. /// Open given child document in current buffer directory.