From: Abdelrazak Younes Date: Fri, 18 Dec 2009 22:51:06 +0000 (+0000) Subject: Detach Buffer preview and update preview in a new thread. Only for Qt4.4 users. This... X-Git-Tag: 2.0.0~4767 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=4ed0169064b5fdb36382fdf831b696daf86f88c0;p=features.git 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 --- diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 90512f0b63..b4671076ad 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -147,7 +147,7 @@ class BufferSet : public std::set {}; 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(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(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 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 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 diff --git a/src/Buffer.h b/src/Buffer.h index f745aa04b8..50bdf77bc9 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -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 exportableFormats(bool only_viewable) const; + /// + bool isExportableFormat(std::string const & format) const; /// typedef std::vector > References; diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 1967eacf41..435db42f29 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -102,6 +102,8 @@ #include #include +#define EXPORT_in_THREAD 1 + // QtConcurrent was introduced in Qt 4.4 #if (QT_VERSION >= 0x040400) #include @@ -300,7 +302,8 @@ public: #if (QT_VERSION >= 0x040400) /// - QFutureWatcher autosave_watcher_; + QFutureWatcher autosave_watcher_; + QFutureWatcher 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 const * watcher = + static_cast 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 f = QtConcurrent::run(saveAndDestroyBuffer, buffer->clone(), + QFuture 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 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 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 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 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 = diff --git a/src/frontends/qt4/GuiView.h b/src/frontends/qt4/GuiView.h index 7a610f0199..02bb82dfb9 100644 --- a/src/frontends/qt4/GuiView.h +++ b/src/frontends/qt4/GuiView.h @@ -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.