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
{
public:
Impl(Buffer & parent, FileName const & file, bool readonly);
Impl(Buffer & parent, FileName const & file, bool readonly, Buffer const * cloned_buffer);
~Impl()
{
@ -258,9 +258,13 @@ public:
LYXERR0("Warning: a buffer should not have two parents!");
parent_buffer = pb;
}
private:
/// So we can force access via the accessors.
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),
read_only(readonly_), filename(file), file_fully_loaded(false),
toc_backend(&parent), macro_lock(false), timestamp_(0),
checksum_(0), wa_(0), undo_(parent), bibinfoCacheValid_(false),
parent_buffer(0)
parent_buffer(0), cloned_buffer_(cloned_buffer)
{
temppath = createBufferTmpDir();
lyxvc.setBuffer(&parent);
if (use_gui)
wa_ = new frontend::WorkAreaManager;
if (!cloned_buffer_) {
temppath = createBufferTmpDir();
lyxvc.setBuffer(&parent);
if (use_gui)
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)
: d(new Impl(*this, FileName(file), readonly)), gui_(0)
Buffer::Buffer(string const & file, bool readonly, Buffer const * cloned_buffer)
: d(new Impl(*this, FileName(file), readonly, cloned_buffer)), gui_(0)
{
LYXERR(Debug::INFO, "Buffer::Buffer()");
@ -343,7 +356,7 @@ Buffer::~Buffer()
d->children_positions.clear();
d->position_to_children.clear();
if (!d->temppath.destroyDirectory()) {
if (!d->cloned_buffer_ && !d->temppath.destroyDirectory()) {
Alert::warning(_("Could not remove temporary directory"),
bformat(_("Could not remove the temporary directory %1$s"),
from_utf8(d->temppath.absFilename())));
@ -358,12 +371,7 @@ Buffer::~Buffer()
Buffer * Buffer::clone() const
{
Buffer * clone = new Buffer(fileName().absFilename(), false);
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;
return new Buffer(fileName().absFilename(), false, this);
}
@ -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)
{
if (isInternal()) {
@ -1687,27 +1710,6 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
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:
enable = isLatex() && !lyxrc.chktex_command.empty();
break;
@ -1773,10 +1775,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
break;
case LFUN_BUFFER_EXPORT: {
if (argument == "custom") {
lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
break;
}
bool success = doExport(argument, false);
dr.setError(success);
if (!success)
@ -1785,38 +1783,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
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:
doExport("program", true);
break;
@ -3132,14 +3098,18 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
path = p;
}
}
if (!path.empty())
runparams.flavor = theConverters().getFlavor(path);
else {
Alert::error(_("Couldn't export file"),
bformat(_("No information for exporting the format %1$s."),
formats.prettyName(format)));
if (path.empty()) {
if (!put_in_tempdir) {
// Only show this alert if this is an export to a non-temporary
// file (not for previewing).
Alert::error(_("Couldn't export file"), bformat(
_("No information for exporting the format %1$s."),
formats.prettyName(format)));
}
return false;
}
runparams.flavor = theConverters().getFlavor(path);
} else {
backend_format = format;
// FIXME: Don't hardcode format names here, but use a flag

View File

@ -125,7 +125,8 @@ public:
};
/// 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
~Buffer();
@ -512,6 +513,8 @@ public:
bool isExportable(std::string const & format) 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;

View File

@ -102,6 +102,8 @@
#include <QUrl>
#include <QScrollBar>
#define EXPORT_in_THREAD 1
// QtConcurrent was introduced in Qt 4.4
#if (QT_VERSION >= 0x040400)
#include <QFuture>
@ -300,7 +302,8 @@ public:
#if (QT_VERSION >= 0x040400)
///
QFutureWatcher<bool> autosave_watcher_;
QFutureWatcher<docstring> autosave_watcher_;
QFutureWatcher<docstring> preview_watcher_;
#endif
};
@ -365,7 +368,9 @@ GuiView::GuiView(int id)
#if (QT_VERSION >= 0x040400)
connect(&d.autosave_watcher_, SIGNAL(finished()), this,
SLOT(autoSaveFinished()));
SLOT(threadFinished()));
connect(&d.preview_watcher_, SIGNAL(finished()), this,
SLOT(threadFinished()));
#endif
}
@ -376,12 +381,12 @@ GuiView::~GuiView()
}
void GuiView::autoSaveFinished()
void GuiView::threadFinished()
{
#if (QT_VERSION >= 0x040400)
docstring const msg = d.autosave_watcher_.result()
? _("Automatic save done.") : _("Automatic save failed!");
message(msg);
QFutureWatcher<docstring> const * watcher =
static_cast<QFutureWatcher<docstring> const *>(sender());
message(watcher->result());
#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;
FileName const tmp_ret = FileName::tempName("lyxauto");
@ -1235,7 +1240,9 @@ static bool saveAndDestroyBuffer(Buffer * buffer, FileName const & fname)
failed = buffer->writeFile(fname);
}
delete buffer;
return !failed;
return failed
? _("Automatic save failed!")
: _("Automatic save done.");
}
@ -1249,7 +1256,7 @@ void GuiView::autoSave()
return;
#if (QT_VERSION >= 0x040400)
QFuture<bool> f = QtConcurrent::run(saveAndDestroyBuffer, buffer->clone(),
QFuture<docstring> f = QtConcurrent::run(saveAndDestroyBuffer, buffer->clone(),
buffer->getAutosaveFilename());
d.autosave_watcher_.setFuture(f);
#else
@ -1296,6 +1303,24 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
case LFUN_BUFFER_IMPORT:
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:
enable = doc_buffer && !doc_buffer->isUnnamed()
&& 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)
{
BufferView * bv = currentBufferView();
@ -2603,6 +2648,8 @@ bool GuiView::dispatch(FuncRequest const & cmd)
return true;
}
string const argument = to_utf8(cmd.argument());
switch(cmd.action) {
case LFUN_BUFFER_CHILD_OPEN:
openChildDocument(to_utf8(cmd.argument()));
@ -2612,6 +2659,80 @@ bool GuiView::dispatch(FuncRequest const & cmd)
importDocument(to_utf8(cmd.argument()));
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:
if (FileName::isAbsolute(to_utf8(cmd.argument()))) {
Buffer * buffer =

View File

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