X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiView.cpp;h=37a8b94f1cb181143ac3eb2510028cf6bebd31ba;hb=57cc26305a795fb2be2f2a7a764c16d27baa40d4;hp=1e0433800281e6ae98aaabac34358547393daca0;hpb=e2c0424c17abfa105aca6f6708133d8e3d7dd575;p=lyx.git diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 1e04338002..37a8b94f1c 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -26,6 +26,7 @@ #include "GuiToc.h" #include "GuiToolbar.h" #include "GuiWorkArea.h" +#include "GuiProgress.h" #include "LayoutBox.h" #include "Menus.h" #include "TocModel.h" @@ -79,7 +80,6 @@ #include "support/Systemcall.h" #include "support/Timeout.h" #include "support/ProgressInterface.h" -#include "GuiProgress.h" #include #include @@ -88,9 +88,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -129,10 +131,16 @@ # include #endif + using namespace std; using namespace lyx::support; namespace lyx { + +using support::addExtension; +using support::changeExtension; +using support::removeExtension; + namespace frontend { namespace { @@ -217,17 +225,17 @@ struct GuiView::GuiViewPrivate // TODO cleanup, remove the singleton, handle multiple Windows? progress_ = ProgressInterface::instance(); - if (!dynamic_cast(progress_)) { + if (!dynamic_cast(progress_)) { progress_ = new GuiProgress(); // TODO who deletes it - ProgressInterface::setInstance(progress_); + ProgressInterface::setInstance(progress_); } QObject::connect( - dynamic_cast(progress_), - SIGNAL(updateStatusBarMessage(QString const&)), + dynamic_cast(progress_), + SIGNAL(updateStatusBarMessage(QString const&)), gv, SLOT(updateStatusBarMessage(QString const&))); QObject::connect( - dynamic_cast(progress_), - SIGNAL(clearMessageText()), + dynamic_cast(progress_), + SIGNAL(clearMessageText()), gv, SLOT(clearMessageText())); } @@ -283,6 +291,11 @@ struct GuiView::GuiViewPrivate bg_widget_->setFocus(); } + int tabWorkAreaCount() + { + return splitter_->count(); + } + TabWorkArea * tabWorkArea(int i) { return dynamic_cast(splitter_->widget(i)); @@ -290,11 +303,12 @@ struct GuiView::GuiViewPrivate TabWorkArea * currentTabWorkArea() { - if (splitter_->count() == 1) + int areas = tabWorkAreaCount(); + if (areas == 1) // The first TabWorkArea is always the first one, if any. return tabWorkArea(0); - for (int i = 0; i != splitter_->count(); ++i) { + for (int i = 0; i != areas; ++i) { TabWorkArea * twa = tabWorkArea(i); if (current_main_work_area_ == twa->currentWorkArea()) return twa; @@ -307,12 +321,12 @@ struct GuiView::GuiViewPrivate #if (QT_VERSION >= 0x040400) void setPreviewFuture(QFuture const & f) { - if (preview_watcher_.isRunning()) { + if (processing_thread_watcher_.isRunning()) { // we prefer to cancel this preview in order to keep a snappy // interface. return; } - preview_watcher_.setFuture(f); + processing_thread_watcher_.setFuture(f); } #endif @@ -327,7 +341,7 @@ public: ToolbarMap toolbars_; ProgressInterface* progress_; /// The main layout box. - /** + /** * \warning Don't Delete! The layout box is actually owned by * whichever toolbar contains it. All the GuiView class needs is a * means of accessing it. @@ -356,26 +370,39 @@ public: #if (QT_VERSION >= 0x040400) /// QFutureWatcher autosave_watcher_; - QFutureWatcher preview_watcher_; + QFutureWatcher processing_thread_watcher_; /// string last_export_format; #else - struct DummyWatcher { bool isRunning(){return false;} }; - DummyWatcher preview_watcher_; + struct DummyWatcher { bool isRunning(){return false;} }; + DummyWatcher processing_thread_watcher_; #endif static QSet busyBuffers; static docstring previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format); static docstring exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format); - static docstring saveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname); + static docstring compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format); + static docstring autosaveAndDestroy(Buffer const * orig, Buffer * buffer); + + template + static docstring runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format, string const & msg); + // TODO syncFunc/previewFunc: use bind + bool asyncBufferProcessing(string const & argument, + Buffer const * used_buffer, + docstring const & msg, + docstring (*asyncFunc)(Buffer const *, Buffer *, string const &), + bool (Buffer::*syncFunc)(string const &, bool, bool) const, + bool (Buffer::*previewFunc)(string const &, bool) const); + + QVector guiWorkAreas(); }; QSet GuiView::GuiViewPrivate::busyBuffers; GuiView::GuiView(int id) - : d(*new GuiViewPrivate(this)), id_(id), closing_(false) + : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0) { // GuiToolbars *must* be initialised before the menu bar. normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge @@ -385,7 +412,7 @@ GuiView::GuiView(int id) // filling, at least for the static special menu item on Mac. Otherwise // they are greyed out. guiApp->setCurrentView(this); - + // Fill up the menu bar. guiApp->menus().fillMenuBar(menuBar(), this, true); @@ -418,14 +445,33 @@ GuiView::GuiView(int id) // For Drag&Drop. setAcceptDrops(true); +#if (QT_VERSION >= 0x040400) + + // add busy indicator to statusbar + QLabel * busylabel = new QLabel(statusBar()); + statusBar()->addPermanentWidget(busylabel); + QString fn = toqstr(lyx::libFileSearch("images", "busy.gif").absFileName()); + QMovie * busyanim = new QMovie(fn, QByteArray(), busylabel); + busylabel->setMovie(busyanim); + busyanim->start(); + busylabel->hide(); + + connect(&d.processing_thread_watcher_, SIGNAL(started()), + busylabel, SLOT(show())); + connect(&d.processing_thread_watcher_, SIGNAL(finished()), + busylabel, SLOT(hide())); + statusBar()->setSizeGripEnabled(true); updateStatusBar(); -#if (QT_VERSION >= 0x040400) connect(&d.autosave_watcher_, SIGNAL(finished()), this, - SLOT(threadFinished())); - connect(&d.preview_watcher_, SIGNAL(finished()), this, - SLOT(threadFinished())); + SLOT(autoSaveThreadFinished())); + + connect(&d.processing_thread_watcher_, SIGNAL(started()), this, + SLOT(processingThreadStarted())); + connect(&d.processing_thread_watcher_, SIGNAL(finished()), this, + SLOT(processingThreadFinished())); + #endif connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)), @@ -457,18 +503,73 @@ GuiView::~GuiView() } -void GuiView::threadFinished() +QVector GuiView::GuiViewPrivate::guiWorkAreas() +{ + QVector areas; + for (int i = 0; i < tabWorkAreaCount(); i++) { + TabWorkArea* ta = tabWorkArea(i); + for (int u = 0; u < ta->count(); u++) { + areas << ta->workArea(u); + } + } + return areas; +} + + +#if QT_VERSION >= 0x040400 + +void GuiView::processingThreadStarted() +{ +} + + +void GuiView::processingThreadFinished(bool show_errors) { -#if (QT_VERSION >= 0x040400) QFutureWatcher const * watcher = static_cast const *>(sender()); message(watcher->result()); updateToolbars(); - errors(d.last_export_format); -#endif + if (show_errors) { + errors(d.last_export_format); + } } +void GuiView::processingThreadFinished() +{ + processingThreadFinished(true); +} + + +void GuiView::autoSaveThreadFinished() +{ + processingThreadFinished(false); +} + +#else + + +void GuiView::processingThreadStarted() +{ +} + + +void GuiView::processingThreadFinished(bool) +{ +} + + +void GuiView::processingThreadFinished() +{ +} + + +void GuiView::autoSaveThreadFinished() +{ +} +#endif + + void GuiView::saveLayout() const { QSettings settings; @@ -485,6 +586,19 @@ void GuiView::saveLayout() const } +void GuiView::saveUISettings() const +{ + // Save the toolbar private states + ToolbarMap::iterator end = d.toolbars_.end(); + for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it) + it->second->saveSession(); + // Now take care of all other dialogs + map::const_iterator it = d.dialogs_.begin(); + for (; it!= d.dialogs_.end(); ++it) + it->second->saveSession(); +} + + bool GuiView::restoreLayout() { QSettings settings; @@ -522,6 +636,8 @@ bool GuiView::restoreLayout() dialog->prepareView(); if ((dialog = findOrBuild("progress", true))) dialog->prepareView(); + if ((dialog = findOrBuild("findreplaceadv", true))) + dialog->prepareView(); if (!restoreState(settings.value("layout").toByteArray(), 0)) initToolbars(); @@ -634,10 +750,10 @@ void GuiView::focusInEvent(QFocusEvent * e) QMainWindow::focusInEvent(e); // Make sure guiApp points to the correct view. guiApp->setCurrentView(this); - if (currentMainWorkArea()) - currentMainWorkArea()->setFocus(); - else if (currentWorkArea()) + if (currentWorkArea()) currentWorkArea()->setFocus(); + else if (currentMainWorkArea()) + currentMainWorkArea()->setFocus(); else d.bg_widget_->setFocus(); } @@ -678,7 +794,8 @@ void GuiView::closeEvent(QCloseEvent * close_event) LYXERR(Debug::DEBUG, "GuiView::closeEvent()"); if (!GuiViewPrivate::busyBuffers.isEmpty()) { - Alert::warning(_("Exit LyX"), _("LyX could not be closed because documents are processed by LyX.")); + Alert::warning(_("Exit LyX"), + _("LyX could not be closed because documents are being processed by LyX.")); close_event->setAccepted(false); return; } @@ -715,16 +832,8 @@ void GuiView::closeEvent(QCloseEvent * close_event) // Saving fullscreen requires additional tweaks in the toolbar code. // It wouldn't also work under linux natively. if (lyxrc.allow_geometry_session) { - // Save this window geometry and layout. saveLayout(); - // Then the toolbar private states. - ToolbarMap::iterator end = d.toolbars_.end(); - for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it) - it->second->saveSession(); - // Now take care of all other dialogs: - map::const_iterator it = d.dialogs_.begin(); - for (; it!= d.dialogs_.end(); ++it) - it->second->saveSession(); + saveUISettings(); } close_event->accept(); @@ -758,7 +867,7 @@ void GuiView::dropEvent(QDropEvent * event) vector found_formats; // Find all formats that have the correct extension. - vector const & import_formats + vector const & import_formats = theConverters().importableFormats(); vector::const_iterator it = import_formats.begin(); for (; it != import_formats.end(); ++it) @@ -774,20 +883,21 @@ void GuiView::dropEvent(QDropEvent * event) } string const arg = found_formats[0]->name() + " " + file; cmd = FuncRequest(LFUN_BUFFER_IMPORT, arg); - } + } else { //FIXME: do we have to explicitly check whether it's a lyx file? LYXERR(Debug::FILES, "No formats found, trying to open it as a lyx file"); cmd = FuncRequest(LFUN_FILE_OPEN, file); } - - // Asynchronously post the event. DropEvent usually comes - // from the BufferView. But reloading a file might close - // the BufferView from within its own event handler. - guiApp->dispatchDelayed(cmd); + // add the functions to the queue + guiApp->addToFuncRequestQueue(cmd); event->accept(); } + // now process the collected functions. We perform the events + // asynchronously. This prevents potential problems in case the + // BufferView is closed within an event. + guiApp->processFuncRequestQueueAsync(); } @@ -795,7 +905,7 @@ void GuiView::message(docstring const & str) { if (ForkedProcess::iAmAChild()) return; - + // call is moved to GUI-thread by GuiProgress d.progress_->appendMessage(toqstr(str)); } @@ -1024,13 +1134,18 @@ bool GuiView::focusNextPrevChild(bool /*next*/) bool GuiView::busy() const { - return busy_; + return busy_ > 0; } void GuiView::setBusy(bool busy) { - busy_ = busy; + bool const busy_before = busy_ > 0; + busy ? ++busy_ : --busy_; + if ((busy_ > 0) == busy_before) + // busy state didn't change + return; + if (d.current_work_area_) { d.current_work_area_->setUpdatesEnabled(!busy); if (busy) @@ -1046,6 +1161,15 @@ void GuiView::setBusy(bool busy) } +GuiWorkArea * GuiView::workArea(int index) +{ + if (TabWorkArea * twa = d.currentTabWorkArea()) + if (index < twa->count()) + return dynamic_cast(twa->widget(index)); + return 0; +} + + GuiWorkArea * GuiView::workArea(Buffer & buffer) { if (currentWorkArea() @@ -1060,7 +1184,7 @@ GuiWorkArea * GuiView::workArea(Buffer & buffer) GuiWorkArea * GuiView::addWorkArea(Buffer & buffer) { // Automatically create a TabWorkArea if there are none yet. - TabWorkArea * tab_widget = d.splitter_->count() + TabWorkArea * tab_widget = d.splitter_->count() ? d.currentTabWorkArea() : addTabWorkArea(); return tab_widget->addWorkArea(buffer, *this); } @@ -1120,8 +1244,8 @@ void GuiView::setCurrentWorkArea(GuiWorkArea * wa) // FIXME: I've no clue why this is here and why it accesses // theGuiApp()->currentView, which might be 0 (bug 6464). // See also 27525 (vfr). - if (theGuiApp()->currentView() == this - && theGuiApp()->currentView()->currentWorkArea() == wa) + if (theGuiApp()->currentView() == this + && theGuiApp()->currentView()->currentWorkArea() == wa) return; if (currentBufferView()) @@ -1129,17 +1253,23 @@ void GuiView::setCurrentWorkArea(GuiWorkArea * wa) theGuiApp()->setCurrentView(this); d.current_work_area_ = wa; + + // We need to reset this now, because it will need to be + // right if the tabWorkArea gets reset in the for loop. We + // will change it back if we aren't in that case. + GuiWorkArea * const old_cmwa = d.current_main_work_area_; + d.current_main_work_area_ = wa; + for (int i = 0; i != d.splitter_->count(); ++i) { if (d.tabWorkArea(i)->setCurrentWorkArea(wa)) { - //if (d.current_main_work_area_) - // d.current_main_work_area_->setFrameStyle(QFrame::NoFrame); - d.current_main_work_area_ = wa; - //d.current_main_work_area_->setFrameStyle(QFrame::Box | QFrame::Plain); - //d.current_main_work_area_->setLineWidth(2); - LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea()); + LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() + << ", Current main wa: " << currentMainWorkArea()); return; } } + + d.current_main_work_area_ = old_cmwa; + LYXERR(Debug::DEBUG, "This is not a tabbed wa"); on_currentWorkAreaChanged(wa); BufferView & bv = wa->bufferView(); @@ -1241,6 +1371,12 @@ void GuiView::setBuffer(Buffer * newBuffer) if (wa == 0) { newBuffer->masterBuffer()->updateBuffer(); wa = addWorkArea(*newBuffer); + // scroll to the position when the BufferView was last closed + if (lyxrc.use_lastfilepos) { + LastFilePosSection::FilePos filepos = + theSession().lastFilePos().load(newBuffer->fileName()); + wa->bufferView().moveToPosition(filepos.pit, filepos.pos, 0, 0); + } } else { //Disconnect the old buffer...there's no new one. disconnectBuffer(); @@ -1281,14 +1417,20 @@ void GuiView::disconnectBufferView() void GuiView::errors(string const & error_type, bool from_master) { + BufferView const * const bv = currentBufferView(); + if (!bv) + return; + ErrorList & el = from_master ? - currentBufferView()->buffer().masterBuffer()->errorList(error_type) - : currentBufferView()->buffer().errorList(error_type); + bv->buffer().masterBuffer()->errorList(error_type) : + bv->buffer().errorList(error_type); + if (el.empty()) + return; + string data = error_type; if (from_master) data = "from_master|" + error_type; - if (!el.empty()) - showDialog("errorlist", data); + showDialog("errorlist", data); } @@ -1330,7 +1472,7 @@ BufferView * GuiView::documentBufferView() } -BufferView const * GuiView::documentBufferView() const +BufferView const * GuiView::documentBufferView() const { return currentMainWorkArea() ? ¤tMainWorkArea()->bufferView() @@ -1351,23 +1493,15 @@ BufferView const * GuiView::currentBufferView() const #if (QT_VERSION >= 0x040400) -docstring GuiView::GuiViewPrivate::saveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname) +docstring GuiView::GuiViewPrivate::autosaveAndDestroy( + Buffer const * orig, Buffer * buffer) { - bool failed = true; - FileName const tmp_ret = FileName::tempName("lyxauto"); - if (!tmp_ret.empty()) { - if (buffer->writeFile(tmp_ret)) - failed = !tmp_ret.moveTo(fname); - } - if (failed) { - // failed to write/rename tmp_ret so try writing direct - failed = buffer->writeFile(fname); - } + bool const success = buffer->autoSave(); delete buffer; busyBuffers.remove(orig); - return failed - ? _("Automatic save failed!") - : _("Automatic save done."); + return success + ? _("Automatic save done.") + : _("Automatic save failed!"); } #endif @@ -1383,12 +1517,13 @@ void GuiView::autoSave() #if (QT_VERSION >= 0x040400) GuiViewPrivate::busyBuffers.insert(buffer); - QFuture f = QtConcurrent::run(GuiViewPrivate::saveAndDestroy, buffer, buffer->clone(), - buffer->getAutosaveFileName()); + QFuture f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy, + buffer, buffer->clone()); d.autosave_watcher_.setFuture(f); #else buffer->autoSave(); #endif + resetAutosaveTimers(); } @@ -1428,14 +1563,14 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; case LFUN_MASTER_BUFFER_UPDATE: - case LFUN_MASTER_BUFFER_VIEW: + case LFUN_MASTER_BUFFER_VIEW: enable = doc_buffer && doc_buffer->parent() != 0 - && !d.preview_watcher_.isRunning(); + && !d.processing_thread_watcher_.isRunning(); break; case LFUN_BUFFER_UPDATE: case LFUN_BUFFER_VIEW: { - if (!doc_buffer || d.preview_watcher_.isRunning()) { + if (!doc_buffer || d.processing_thread_watcher_.isRunning()) { enable = false; break; } @@ -1476,7 +1611,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; } b = theBufferList().next(b); - } while (b != first); + } while (b != first); break; } @@ -1511,7 +1646,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setOnOff(t->isVisible()); else { enable = false; - docstring const msg = + docstring const msg = bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)); flag.message(msg); } @@ -1519,7 +1654,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) } case LFUN_DROP_LAYOUTS_CHOICE: - enable = buf; + enable = buf; break; case LFUN_UI_TOGGLE: @@ -1552,10 +1687,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) if (!buf || buf->isReadonly()) enable = false; else { - // FIXME we should consider passthru - // paragraphs too. - Inset const & in = currentBufferView()->cursor().inset(); - enable = !in.getLayout().isPassThru(); + Cursor const & cur = currentBufferView()->cursor(); + enable = !(cur.inTexted() && cur.paragraph().isPassThru()); } } else if (name == "latexlog") @@ -1623,7 +1756,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_BUFFER_ZOOM_IN: enable = doc_buffer; break; - + case LFUN_BUFFER_NEXT: case LFUN_BUFFER_PREVIOUS: // FIXME: should we check is there is an previous or next buffer? @@ -1651,13 +1784,13 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setOnOff(enable && doc_buffer->lyxvc().locking()); break; case LFUN_VC_REVERT: - enable = doc_buffer && doc_buffer->lyxvc().inUse(); + enable = doc_buffer && doc_buffer->lyxvc().inUse() && !doc_buffer->isReadonly(); break; case LFUN_VC_UNDO_LAST: enable = doc_buffer && doc_buffer->lyxvc().undoLastEnabled(); break; case LFUN_VC_REPO_UPDATE: - enable = doc_buffer && doc_buffer->lyxvc().inUse(); + enable = doc_buffer && doc_buffer->lyxvc().repoUpdateEnabled(); break; case LFUN_VC_COMMAND: { if (cmd.argument().empty()) @@ -1691,7 +1824,7 @@ static FileName selectTemplateFile() { FileDialog dlg(qt_("Select template file")); dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); - dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path)); + dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path)); FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path), QStringList(qt_("LyX Documents (*.lyx)"))); @@ -1708,22 +1841,22 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles) { setBusy(true); - Buffer * newBuffer = checkAndLoadLyXFile(filename); + Buffer * newBuffer = 0; + try { + newBuffer = checkAndLoadLyXFile(filename); + } catch (ExceptionMessage const & e) { + setBusy(false); + throw(e); + } if (!newBuffer) { message(_("Document not loaded.")); setBusy(false); return 0; } - - setBuffer(newBuffer); - // scroll to the position when the file was last closed - if (lyxrc.use_lastfilepos) { - LastFilePosSection::FilePos filepos = - theSession().lastFilePos().load(filename); - documentBufferView()->moveToPosition(filepos.pit, filepos.pos, 0, 0); - } + newBuffer->errors("Parse"); + setBuffer(newBuffer); if (tolastfiles) theSession().lastFiles().add(filename); @@ -1774,8 +1907,8 @@ void GuiView::openDocument(string const & fname) filename = fname; // get absolute path of file and add ".lyx" to the filename if - // necessary. - FileName const fullname = + // necessary. + FileName const fullname = fileSearch(string(), filename, "lyx", support::may_not_exist); if (!fullname.empty()) filename = fullname.absFileName(); @@ -1787,7 +1920,7 @@ void GuiView::openDocument(string const & fname) return; } - // if the file doesn't exist and isn't already open (bug 6645), + // if the file doesn't exist and isn't already open (bug 6645), // let the user create one if (!fullname.exists() && !theBufferList().exists(fullname)) { // the user specifically chose this name. Believe him. @@ -1803,10 +1936,6 @@ void GuiView::openDocument(string const & fname) docstring str2; Buffer * buf = loadDocument(fullname); if (buf) { - // I don't think this is needed, since it will be done in setBuffer(). - // buf->updateBuffer(); - setBuffer(buf); - buf->errors("Parse"); str2 = bformat(_("Document %1$s opened."), disp_fn); if (buf->lyxvc().inUse()) str2 += " " + from_utf8(buf->lyxvc().versionString()) + @@ -1853,10 +1982,6 @@ static bool import(GuiView * lv, FileName const & filename, Buffer * buf = lv->loadDocument(lyxfile); if (!buf) return false; - // I don't think this is needed, since it will be done in setBuffer(). - // buf->updateBuffer(); - lv->setBuffer(buf); - buf->errors("Parse"); } else { Buffer * const b = newFile(lyxfile.absFileName(), string(), true); if (!b) @@ -1982,7 +2107,7 @@ void GuiView::newDocument(string const & filename, bool from_template) if (templatefile.empty()) return; } - + Buffer * b; if (filename.empty()) b = newUnnamedFile(initpath, to_utf8(_("newfile")), templatefile); @@ -1992,7 +2117,7 @@ void GuiView::newDocument(string const & filename, bool from_template) if (b) setBuffer(b); - // If no new document could be created, it is unsure + // If no new document could be created, it is unsure // whether there is a valid BufferView. if (currentBufferView()) // Ensure the cursor is correctly positioned on screen. @@ -2008,44 +2133,41 @@ void GuiView::insertLyXFile(docstring const & fname) // FIXME UNICODE FileName filename(to_utf8(fname)); - - if (!filename.empty()) { - bv->insertLyXFile(filename); - return; - } - - // Launch a file browser - // FIXME UNICODE - string initpath = lyxrc.document_path; - string const trypath = bv->buffer().filePath(); - // If directory is writeable, use this as default. - if (FileName(trypath).isDirWritable()) - initpath = trypath; + if (filename.empty()) { + // Launch a file browser + // FIXME UNICODE + string initpath = lyxrc.document_path; + string const trypath = bv->buffer().filePath(); + // If directory is writeable, use this as default. + if (FileName(trypath).isDirWritable()) + initpath = trypath; - // FIXME UNICODE - FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT); - dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); - dlg.setButton2(qt_("Examples|#E#e"), - toqstr(addPath(package().system_support().absFileName(), - "examples"))); + // FIXME UNICODE + FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT); + dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); + dlg.setButton2(qt_("Examples|#E#e"), + toqstr(addPath(package().system_support().absFileName(), + "examples"))); - FileDialog::Result result = dlg.open(toqstr(initpath), - QStringList(qt_("LyX Documents (*.lyx)"))); + FileDialog::Result result = dlg.open(toqstr(initpath), + QStringList(qt_("LyX Documents (*.lyx)"))); - if (result.first == FileDialog::Later) - return; + if (result.first == FileDialog::Later) + return; - // FIXME UNICODE - filename.set(fromqstr(result.second)); + // FIXME UNICODE + filename.set(fromqstr(result.second)); - // check selected filename - if (filename.empty()) { - // emit message signal. - message(_("Canceled.")); - return; + // check selected filename + if (filename.empty()) { + // emit message signal. + message(_("Canceled.")); + return; + } } bv->insertLyXFile(filename); + bv->buffer().errors("Parse"); } @@ -2063,7 +2185,7 @@ void GuiView::insertPlaintextFile(docstring const & fname, // FIXME UNICODE FileName filename(to_utf8(fname)); - + if (!filename.empty()) { bv->insertPlaintextFile(filename, asParagraph); return; @@ -2136,7 +2258,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) docstring const file = makeDisplayPath(fname.absFileName(), 30); docstring text = bformat(_("The document %1$s already " "exists.\n\nDo you want to " - "overwrite that document?"), + "overwrite that document?"), file); int const ret = Alert::prompt(_("Overwrite document?"), text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel")); @@ -2147,45 +2269,30 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) } } - FileName oldauto = b.getAutosaveFileName(); - - // Ok, change the name of the buffer - b.setFileName(fname.absFileName()); - b.markDirty(); - bool unnamed = b.isUnnamed(); - b.setUnnamed(false); - b.saveCheckSum(fname); - - // bring the autosave file with us, just in case. - b.moveAutosaveFile(oldauto); - - if (!saveBuffer(b)) { - oldauto = b.getAutosaveFileName(); - b.setFileName(oldname.absFileName()); - b.setUnnamed(unnamed); - b.saveCheckSum(oldname); - b.moveAutosaveFile(oldauto); - return false; - } + return saveBuffer(b, fname); +} - // the file has now been saved to the new location. - // we need to check that the locations of child buffers - // are still valid. - b.checkChildBuffers(); - return true; +bool GuiView::saveBuffer(Buffer & b) { + return saveBuffer(b, FileName()); } -bool GuiView::saveBuffer(Buffer & b) +bool GuiView::saveBuffer(Buffer & b, FileName const & fn) { if (workArea(b) && workArea(b)->inDialogMode()) return true; - if (b.isUnnamed()) - return renameBuffer(b, docstring()); + if (fn.empty() && b.isUnnamed()) + return renameBuffer(b, docstring()); - if (b.save()) { + bool success; + if (fn.empty()) + success = b.save(); + else + success = b.saveAs(fn); + + if (success) { theSession().lastFiles().add(b.fileName()); return true; } @@ -2275,7 +2382,7 @@ bool GuiView::closeWorkAreaAll() setCurrentWorkArea(currentMainWorkArea()); // We might be in a situation that there is still a tabWorkArea, but - // there are no tabs anymore. This can happen when we get here after a + // there are no tabs anymore. This can happen when we get here after a // TabWorkArea::lastWorkAreaRemoved() signal. Therefore we count how // many TabWorkArea's have no documents anymore. int empty_twa = 0; @@ -2305,7 +2412,8 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer) Buffer & buf = wa->bufferView().buffer(); if (close_buffer && GuiViewPrivate::busyBuffers.contains(&buf)) { - Alert::warning(_("Close document "), _("Document could not be closed because it is processed by LyX.")); + Alert::warning(_("Close document"), + _("Document could not be closed because it is being processed by LyX.")); return false; } @@ -2327,33 +2435,42 @@ bool GuiView::closeBuffer(Buffer & buf) // so no need to do it here. This will ensure that the children end up // in the session file in the correct order. If we close the master // buffer, we can close or release the child buffers here too. + bool success = true; if (!closing_) { - vector clist = buf.getChildren(false); - for (vector::const_iterator it = clist.begin(); - it != clist.end(); ++it) { + ListOfBuffers clist = buf.getChildren(); + ListOfBuffers::const_iterator it = clist.begin(); + ListOfBuffers::const_iterator const bend = clist.end(); + for (; it != bend; ++it) { // If a child is dirty, do not close // without user intervention //FIXME: should we look in other tabworkareas? Buffer * child_buf = *it; GuiWorkArea * child_wa = workArea(*child_buf); if (child_wa) { - if (!closeWorkArea(child_wa, true)) - return false; + if (!closeWorkArea(child_wa, true)) { + success = false; + break; + } } else theBufferList().releaseChild(&buf, child_buf); } } - // goto bookmark to update bookmark pit. - //FIXME: we should update only the bookmarks related to this buffer! - LYXERR(Debug::DEBUG, "GuiView::closeBuffer()"); - for (size_t i = 0; i < theSession().bookmarks().size(); ++i) - guiApp->gotoBookmark(i+1, false, false); + if (success) { + // goto bookmark to update bookmark pit. + //FIXME: we should update only the bookmarks related to this buffer! + LYXERR(Debug::DEBUG, "GuiView::closeBuffer()"); + for (size_t i = 0; i < theSession().bookmarks().size(); ++i) + guiApp->gotoBookmark(i+1, false, false); - if (saveBufferIfNeeded(buf, false)) { - buf.removeAutosaveFile(); - theBufferList().release(&buf); - return true; + if (saveBufferIfNeeded(buf, false)) { + buf.removeAutosaveFile(); + theBufferList().release(&buf); + return true; + } } + // open all children again to avoid a crash because of dangling + // pointers (bug 6603) + buf.updateBuffer(); return false; } @@ -2369,8 +2486,8 @@ bool GuiView::closeTabWorkArea(TabWorkArea * twa) // We only want to close the buffer if the same buffer is not visible // in another view, and if this is not a child and if we are closing // a view (not a tabgroup). - bool const close_buffer = - !inMultiViews(wa) && !b.parent() && closing_; + bool const close_buffer = + !inOtherView(b) && !b.parent() && closing_; if (!closeWorkArea(wa, close_buffer)) return false; @@ -2403,7 +2520,7 @@ bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding) docstring const text = bformat(_("The document %1$s has not been " "saved yet.\n\nDo you want to save " "the document?"), file); - ret = Alert::prompt(_("Save new document?"), + ret = Alert::prompt(_("Save new document?"), text, 0, 1, _("&Save"), _("&Cancel")); if (ret == 1) ++ret; @@ -2420,14 +2537,14 @@ bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding) return false; break; case 1: - // if we crash after this we could - // have no autosave file but I guess - // this is really improbable (Jug) - // Sometime improbable things happen, bug 6857 (ps) + // If we crash after this we could have no autosave file + // but I guess this is really improbable (Jug). + // Sometimes improbable things happen: + // - see bug http://www.lyx.org/trac/ticket/6587 (ps) // buf.removeAutosaveFile(); if (hiding) // revert all changes - buf.reload(); + reloadBuffer(buf); buf.markClean(); break; case 2: @@ -2446,20 +2563,18 @@ bool GuiView::inMultiTabs(GuiWorkArea * wa) if (wa_ && wa_ != wa) return true; } - return inMultiViews(wa); + return inOtherView(buf); } -bool GuiView::inMultiViews(GuiWorkArea * wa) +bool GuiView::inOtherView(Buffer & buf) { QList const ids = guiApp->viewIds(); - Buffer & buf = wa->bufferView().buffer(); - int found_twa = 0; - for (int i = 0; i != ids.size() && found_twa <= 1; ++i) { + for (int i = 0; i != ids.size(); ++i) { if (id_ == ids[i]) continue; - + if (guiApp->view(ids[i]).workArea(buf)) return true; } @@ -2469,24 +2584,24 @@ bool GuiView::inMultiViews(GuiWorkArea * wa) void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np) { - Buffer * const curbuf = documentBufferView() - ? &documentBufferView()->buffer() : 0; - Buffer * nextbuf = curbuf; - while (true) { - if (np == NEXTBUFFER) - nextbuf = theBufferList().next(nextbuf); - else - nextbuf = theBufferList().previous(nextbuf); - if (nextbuf == curbuf) - break; - if (nextbuf == 0) { - nextbuf = curbuf; - break; + if (!documentBufferView()) + return; + + if (TabWorkArea * twa = d.currentTabWorkArea()) { + Buffer * const curbuf = &documentBufferView()->buffer(); + int nwa = twa->count(); + for (int i = 0; i < nwa; ++i) { + if (&workArea(i)->bufferView().buffer() == curbuf) { + int next_index; + if (np == NEXTBUFFER) + next_index = (i == nwa - 1 ? 0 : i + 1); + else + next_index = (i == 0 ? nwa - 1 : i - 1); + setBuffer(&workArea(next_index)->bufferView().buffer()); + break; + } } - if (workArea(*nextbuf)) - break; } - setBuffer(nextbuf); } @@ -2505,7 +2620,7 @@ static bool ensureBufferClean(Buffer * buffer) "changes.\n\nDo you want to save " "the document?"), file); title = _("Save changed document?"); - + } else { text = bformat(_("The document %1$s has not been " "saved yet.\n\nDo you want to save " @@ -2521,10 +2636,10 @@ static bool ensureBufferClean(Buffer * buffer) } -void GuiView::reloadBuffer() +bool GuiView::reloadBuffer(Buffer & buf) { - Buffer * buf = &documentBufferView()->buffer(); - buf->reload(); + Buffer::ReadStatus status = buf.reload(); + return status == Buffer::ReadSuccess; } @@ -2533,25 +2648,23 @@ void GuiView::checkExternallyModifiedBuffers() BufferList::iterator bit = theBufferList().begin(); BufferList::iterator const bend = theBufferList().end(); for (; bit != bend; ++bit) { - if ((*bit)->fileName().exists() - && (*bit)->isExternallyModified(Buffer::checksum_method)) { + Buffer * buf = *bit; + if (buf->fileName().exists() + && buf->isExternallyModified(Buffer::checksum_method)) { docstring text = bformat(_("Document \n%1$s\n has been externally modified." " Reload now? Any local changes will be lost."), - from_utf8((*bit)->absFileName())); + from_utf8(buf->absFileName())); int const ret = Alert::prompt(_("Reload externally changed document?"), text, 0, 1, _("&Reload"), _("&Cancel")); if (!ret) - (*bit)->reload(); + reloadBuffer(*buf); } } } -//FIXME use a DispatchResult object to transmit messages -void GuiView::dispatchVC(FuncRequest const & cmd) +void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr) { - // message for statusbar - string msg; Buffer * buffer = documentBufferView() ? &(documentBufferView()->buffer()) : 0; @@ -2560,8 +2673,10 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (!buffer || !ensureBufferClean(buffer)) break; if (!buffer->lyxvc().inUse()) { - if (buffer->lyxvc().registrer()) - reloadBuffer(); + if (buffer->lyxvc().registrer()) { + reloadBuffer(*buffer); + dr.suppressMessageUpdate(); + } } break; @@ -2569,9 +2684,9 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (!buffer || !ensureBufferClean(buffer)) break; if (buffer->lyxvc().inUse() && !buffer->isReadonly()) { - msg = buffer->lyxvc().checkIn(); - if (!msg.empty()) - reloadBuffer(); + dr.setMessage(buffer->lyxvc().checkIn()); + if (!dr.message().empty()) + reloadBuffer(*buffer); } break; @@ -2579,8 +2694,8 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (!buffer || !ensureBufferClean(buffer)) break; if (buffer->lyxvc().inUse()) { - msg = buffer->lyxvc().checkOut(); - reloadBuffer(); + dr.setMessage(buffer->lyxvc().checkOut()); + reloadBuffer(*buffer); } break; @@ -2594,28 +2709,31 @@ void GuiView::dispatchVC(FuncRequest const & cmd) frontend::Alert::error(_("Revision control error."), _("Error when setting the locking property.")); } else { - msg = res; - reloadBuffer(); + dr.setMessage(res); + reloadBuffer(*buffer); } } break; case LFUN_VC_REVERT: LASSERT(buffer, return); - buffer->lyxvc().revert(); - reloadBuffer(); + if (buffer->lyxvc().revert()) { + reloadBuffer(*buffer); + dr.suppressMessageUpdate(); + } break; case LFUN_VC_UNDO_LAST: LASSERT(buffer, return); buffer->lyxvc().undoLast(); - reloadBuffer(); + reloadBuffer(*buffer); + dr.suppressMessageUpdate(); break; case LFUN_VC_REPO_UPDATE: LASSERT(buffer, return); if (ensureBufferClean(buffer)) { - msg = buffer->lyxvc().repoUpdate(); + dr.setMessage(buffer->lyxvc().repoUpdate()); checkExternallyModifiedBuffers(); } break; @@ -2657,7 +2775,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (contains(flag, 'I')) buffer->markDirty(); if (contains(flag, 'R')) - reloadBuffer(); + reloadBuffer(*buffer); break; } @@ -2686,29 +2804,17 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (!buffer->lyxvc().prepareFileRevision(rev2, f2)) break; } - // FIXME We need to call comparison feature here. - // This is quick and dirty code for testing VC. - // We need that comparison feature has some LFUN_COMPARE file1 file1 - // where specifies whether we want GUI dialog or just launch - // running with defaults. - /* - FileName initpath(lyxrc.document_path); - Buffer * dest = newUnnamedFile(initpath, to_utf8(_("differences"))); - CompareOptions options; - Compare * compare = new Compare(loadIfNeeded(FileName(f1)), loadIfNeeded(FileName(f2)), dest, options); - compare->start(QThread::LowPriority); - Sleep::millisec(200); - lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH, dest->absFileName())); - */ + + LYXERR(Debug::LYXVC, "Launching comparison for fetched revisions:\n" << + f1 << "\n" << f2 << "\n" ); + string par = "compare run " + quoteName(f1) + " " + quoteName(f2); + lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, par)); break; } default: break; } - - if (!msg.empty()) - message(from_utf8(msg)); } @@ -2719,29 +2825,19 @@ void GuiView::openChildDocument(string const & fname) FileName const filename = support::makeAbsPath(fname, buffer.filePath()); documentBufferView()->saveBookmark(false); Buffer * child = 0; - bool parsed = false; if (theBufferList().exists(filename)) { child = theBufferList().getBuffer(filename); + setBuffer(child); } else { message(bformat(_("Opening child document %1$s..."), - makeDisplayPath(filename.absFileName()))); + makeDisplayPath(filename.absFileName()))); child = loadDocument(filename, false); - parsed = true; } - if (!child) - return; - // Set the parent name of the child document. // This makes insertion of citations and references in the child work, // when the target is in the parent or another child document. - child->setParent(&buffer); - - // I don't think this is needed, since it will be called in - // setBuffer(). - // child->masterBuffer()->updateBuffer(); - setBuffer(child); - if (parsed) - child->errors("Parse"); + if (child) + child->setParent(&buffer); } @@ -2788,10 +2884,6 @@ bool GuiView::goToFileRow(string const & argument) buf = loadDocument(s); if (!buf) return false; - // I don't think this is needed. loadDocument() calls - // setBuffer(), which calls updateBuffer(). - // buf->updateBuffer(); - buf->errors("Parse"); } else { message(bformat( _("File does not exist: %1$s"), @@ -2806,40 +2898,163 @@ bool GuiView::goToFileRow(string const & argument) #if (QT_VERSION >= 0x040400) -docstring GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format) +template +docstring GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format, string const & msg) { bool const update_unincluded = buffer->params().maintain_unincluded_children && !buffer->params().getIncludedChildren().empty(); - bool const success = buffer->doExport(format, true, update_unincluded); + bool const success = func(format, update_unincluded); delete buffer; busyBuffers.remove(orig); + if (msg == "preview") { + return success + ? bformat(_("Successful preview of format: %1$s"), from_utf8(format)) + : bformat(_("Error while previewing format: %1$s"), from_utf8(format)); + } return success ? bformat(_("Successful export to format: %1$s"), from_utf8(format)) - : bformat(_("Error exporting to format: %1$s"), from_utf8(format)); + : bformat(_("Error while exporting format: %1$s"), from_utf8(format)); +} + + +docstring GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format) +{ + bool (Buffer::* mem_func)(std::string const &, bool, bool) const = &Buffer::doExport; + return runAndDestroy(bind(mem_func, buffer, _1, true, _2), orig, buffer, format, "export"); +} + + +docstring GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format) +{ + bool (Buffer::* mem_func)(std::string const &, bool, bool) const = &Buffer::doExport; + return runAndDestroy(bind(mem_func, buffer, _1, false, _2), orig, buffer, format, "export"); } docstring GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format) { - bool const update_unincluded = - buffer->params().maintain_unincluded_children - && !buffer->params().getIncludedChildren().empty(); - bool const success = buffer->preview(format, update_unincluded); - delete buffer; - busyBuffers.remove(orig); - return success - ? bformat(_("Successful preview of format: %1$s"), from_utf8(format)) - : bformat(_("Error previewing format: %1$s"), from_utf8(format)); + bool(Buffer::* mem_func)(std::string const &, bool) const = &Buffer::preview; + return runAndDestroy(bind(mem_func, buffer, _1, _2), orig, buffer, format, "preview"); } + +#else + +// not used, but the linker needs them + +docstring GuiView::GuiViewPrivate::compileAndDestroy( + Buffer const *, Buffer *, string const &) +{ + return docstring(); +} + + +docstring GuiView::GuiViewPrivate::exportAndDestroy( + Buffer const *, Buffer *, string const &) +{ + return docstring(); +} + + +docstring GuiView::GuiViewPrivate::previewAndDestroy( + Buffer const *, Buffer *, string const &) +{ + return docstring(); +} + #endif +bool GuiView::GuiViewPrivate::asyncBufferProcessing( + string const & argument, + Buffer const * used_buffer, + docstring const & msg, + docstring (*asyncFunc)(Buffer const *, Buffer *, string const &), + bool (Buffer::*syncFunc)(string const &, bool, bool) const, + bool (Buffer::*previewFunc)(string const &, bool) const) +{ + if (!used_buffer) + return false; + + string format = argument; + if (format.empty()) + format = used_buffer->getDefaultOutputFormat(); + +#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) + if (!msg.empty()) { + progress_->clearMessages(); + gv_->message(msg); + } + GuiViewPrivate::busyBuffers.insert(used_buffer); + QFuture f = QtConcurrent::run( + asyncFunc, + used_buffer, + used_buffer->clone(), + format); + setPreviewFuture(f); + last_export_format = used_buffer->bufferFormat(); + (void) syncFunc; + (void) previewFunc; + // We are asynchronous, so we don't know here anything about the success + return true; +#else + if (syncFunc) { + // TODO check here if it breaks exporting with Qt < 4.4 + bool const update_unincluded = + used_buffer->params().maintain_unincluded_children && + !used_buffer->params().getIncludedChildren().empty(); + return (used_buffer->*syncFunc)(format, true, update_unincluded); + } else if (previewFunc) { + return (used_buffer->*previewFunc)(format, false); + } + (void) asyncFunc; + return false; +#endif +} + +void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr) +{ + BufferView * bv = currentBufferView(); + LASSERT(bv, /**/); + + // Let the current BufferView dispatch its own actions. + bv->dispatch(cmd, dr); + if (dr.dispatched()) + return; + + // Try with the document BufferView dispatch if any. + BufferView * doc_bv = documentBufferView(); + if (doc_bv) { + doc_bv->dispatch(cmd, dr); + if (dr.dispatched()) + return; + } + + // Then let the current Cursor dispatch its own actions. + bv->cursor().dispatch(cmd); + + // update completion. We do it here and not in + // processKeySym to avoid another redraw just for a + // changed inline completion + if (cmd.origin() == FuncRequest::KEYBOARD) { + if (cmd.action() == LFUN_SELF_INSERT + || (cmd.action() == LFUN_ERT_INSERT && bv->cursor().inMathed())) + updateCompletion(bv->cursor(), true, true); + else if (cmd.action() == LFUN_CHAR_DELETE_BACKWARD) + updateCompletion(bv->cursor(), false, true); + else + updateCompletion(bv->cursor(), false, false); + } + + dr = bv->cursor().result(); +} + + void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) { BufferView * bv = currentBufferView(); // By default we won't need any update. - dr.update(Update::None); + dr.screenUpdate(Update::None); // assume cmd will be dispatched dr.dispatched(true); @@ -2869,97 +3084,62 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; // GCC only sees strfwd.h when building merged if (::lyx::operator==(cmd.argument(), "custom")) { - dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), - dr); + dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr); break; } +#if QT_VERSION < 0x040400 if (!doc_buffer->doExport(argument, false)) { dr.setError(true); dr.setMessage(bformat(_("Error exporting to format: %1$s."), cmd.argument())); } +#else + /* TODO/Review: Is it a problem to also export the children? + See the update_unincluded flag */ + d.asyncBufferProcessing(argument, + doc_buffer, + _("Exporting ..."), + &GuiViewPrivate::exportAndDestroy, + &Buffer::doExport, + 0); + // TODO Inform user about success +#endif 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) - d.progress_->clearMessages(); - message(_("Exporting ...")); - GuiViewPrivate::busyBuffers.insert(doc_buffer); - QFuture f = QtConcurrent::run(GuiViewPrivate::exportAndDestroy, - doc_buffer, doc_buffer->clone(), format); - d.setPreviewFuture(f); - d.last_export_format = doc_buffer->bufferFormat(); -#else - bool const update_unincluded = - doc_buffer->params().maintain_unincluded_children - && !doc_buffer->params().getIncludedChildren().empty(); - doc_buffer->doExport(format, true, update_unincluded); -#endif + d.asyncBufferProcessing(argument, + doc_buffer, + _("Exporting ..."), + &GuiViewPrivate::compileAndDestroy, + &Buffer::doExport, + 0); 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) - d.progress_->clearMessages(); - message(_("Previewing ...")); - GuiViewPrivate::busyBuffers.insert(doc_buffer); - QFuture f = QtConcurrent::run(GuiViewPrivate::previewAndDestroy, - doc_buffer, doc_buffer->clone(), format); - d.setPreviewFuture(f); - d.last_export_format = doc_buffer->bufferFormat(); -#else - bool const update_unincluded = - doc_buffer->params().maintain_unincluded_children - && !doc_buffer->params().getIncludedChildren().empty(); - doc_buffer->preview(format, update_unincluded); -#endif + d.asyncBufferProcessing(argument, + doc_buffer, + _("Previewing ..."), + &GuiViewPrivate::previewAndDestroy, + 0, + &Buffer::preview); 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) - GuiViewPrivate::busyBuffers.insert(master); - QFuture f = QtConcurrent::run(GuiViewPrivate::exportAndDestroy, - master, master->clone(), format); - d.setPreviewFuture(f); - d.last_export_format = doc_buffer->bufferFormat(); -#else - bool const update_unincluded = - master->params().maintain_unincluded_children - && !master->params().getIncludedChildren().empty(); - master->doExport(format, true); -#endif + d.asyncBufferProcessing(argument, + (doc_buffer ? doc_buffer->masterBuffer() : 0), + docstring(), + &GuiViewPrivate::compileAndDestroy, + &Buffer::doExport, + 0); 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) - GuiViewPrivate::busyBuffers.insert(master); - QFuture f = QtConcurrent::run(GuiViewPrivate::previewAndDestroy, - master, master->clone(), format); - d.setPreviewFuture(f); - d.last_export_format = doc_buffer->bufferFormat(); -#else - master->preview(format); -#endif + d.asyncBufferProcessing(argument, + (doc_buffer ? doc_buffer->masterBuffer() : 0), + docstring(), + &GuiViewPrivate::previewAndDestroy, + 0, &Buffer::preview); break; } case LFUN_BUFFER_SWITCH: { @@ -2975,15 +3155,15 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) dr.setError(true); dr.setMessage(_("Document not loaded")); break; - } + } // Do we open or switch to the buffer in this view ? - if (workArea(*buffer) + if (workArea(*buffer) || lyxrc.open_buffers_in_tabs || !documentBufferView()) { setBuffer(buffer); break; - } - + } + // Look for the buffer in other views QList const ids = guiApp->viewIds(); int i = 0; @@ -3035,6 +3215,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_FILE_INSERT: insertLyXFile(cmd.argument()); break; + case LFUN_FILE_INSERT_PLAINTEXT_PARA: insertPlaintextFile(cmd.argument(), true); break; @@ -3045,15 +3226,21 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_BUFFER_RELOAD: { LASSERT(doc_buffer, break); - docstring const file = makeDisplayPath(doc_buffer->absFileName(), 20); - docstring text = bformat(_("Any changes will be lost. Are you sure " - "you want to revert to the saved version of the document %1$s?"), file); - int const ret = Alert::prompt(_("Revert to saved document?"), - text, 1, 1, _("&Revert"), _("&Cancel")); + + int ret = 0; + if (!doc_buffer->isClean()) { + docstring const file = + makeDisplayPath(doc_buffer->absFileName(), 20); + docstring text = bformat(_("Any changes will be lost. " + "Are you sure you want to revert to the saved version " + "of the document %1$s?"), file); + ret = Alert::prompt(_("Revert to saved document?"), + text, 1, 1, _("&Revert"), _("&Cancel")); + } if (ret == 0) { doc_buffer->markClean(); - reloadBuffer(); + reloadBuffer(*doc_buffer); dr.forceBufferUpdate(); } break; @@ -3082,7 +3269,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) LYXERR(Debug::ACTION, "Saved " << b->absFileName()); } b = theBufferList().next(b); - } while (b != first); + } while (b != first); dr.setMessage(_("All documents saved.")); break; } @@ -3104,29 +3291,28 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_DIALOG_UPDATE: { string const name = to_utf8(cmd.argument()); - if (currentBufferView()) { + if (name == "prefs" || name == "document") + updateDialog(name, string()); + else if (name == "paragraph") + lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE)); + else if (currentBufferView()) { Inset * inset = currentBufferView()->editedInset(name); // Can only update a dialog connected to an existing inset - if (!inset) - break; - // FIXME: get rid of this indirection; GuiView ask the inset - // if he is kind enough to update itself... - FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument()); - //FIXME: pass DispatchResult here? - inset->dispatch(currentBufferView()->cursor(), fr); - } else if (name == "paragraph") { - lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE)); - } else if (name == "prefs" || name == "document") { - updateDialog(name, string()); + if (inset) { + // FIXME: get rid of this indirection; GuiView ask the inset + // if he is kind enough to update itself... + FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument()); + //FIXME: pass DispatchResult here? + inset->dispatch(currentBufferView()->cursor(), fr); + } } break; } case LFUN_DIALOG_TOGGLE: { - if (isDialogVisible(cmd.getArg(0))) - dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()), dr); - else - dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()), dr); + FuncCode const func_code = isDialogVisible(cmd.getArg(0)) + ? LFUN_DIALOG_HIDE : LFUN_DIALOG_SHOW; + dispatch(FuncRequest(func_code, cmd.argument()), dr); break; } @@ -3148,7 +3334,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (!data.empty()) showDialog("character", data); } else if (name == "latexlog") { - Buffer::LogType type; + Buffer::LogType type; string const logfile = doc_buffer->logName(&type); switch (type) { case Buffer::latexlog: @@ -3216,7 +3402,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } } break; - + case LFUN_COMPLETION_INLINE: if (d.current_work_area_) d.current_work_area_->completer().showInline(); @@ -3259,7 +3445,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (lyxrc.zoom < 10) lyxrc.zoom = 10; - + // The global QPixmapCache is used in GuiPainter to cache text // painting so we must reset it. QPixmapCache::clear(); @@ -3276,7 +3462,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_VC_UNDO_LAST: case LFUN_VC_COMMAND: case LFUN_VC_COMPARE: - dispatchVC(cmd); + dispatchVC(cmd, dr); break; case LFUN_SERVER_GOTO_FILE_ROW: @@ -3284,12 +3470,19 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; case LFUN_FORWARD_SEARCH: { - FileName const path(doc_buffer->temppath()); - string const texname = doc_buffer->latexName(); + Buffer const * doc_master = doc_buffer->masterBuffer(); + FileName const path(doc_master->temppath()); + string const texname = doc_master->isChild(doc_buffer) + ? DocFileName(changeExtension( + doc_buffer->absFileName(), + "tex")).mangledFileName() + : doc_buffer->latexName(); + string const mastername = + removeExtension(doc_master->latexName()); FileName const dviname(addName(path.absFileName(), - support::changeExtension(texname, "dvi"))); + addExtension(mastername, "dvi"))); FileName const pdfname(addName(path.absFileName(), - support::changeExtension(texname, "pdf"))); + addExtension(mastername, "pdf"))); if (!dviname.exists() && !pdfname.exists()) { dr.setMessage(_("Please, preview the document first.")); break; @@ -3321,7 +3514,9 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } default: - dr.dispatched(false); + // The LFUN must be for one of BufferView, Buffer or Cursor; + // let's try that: + dispatchToBufferView(cmd, dr); break; } @@ -3332,8 +3527,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (statusBar()->isVisible()) statusBar()->hide(); } - - return; } @@ -3498,6 +3691,7 @@ void GuiView::resetDialogs() // Make sure that no LFUN uses any GuiView. guiApp->setCurrentView(0); saveLayout(); + saveUISettings(); menuBar()->clear(); constructToolbars(); guiApp->menus().fillMenuBar(menuBar(), this, false); @@ -3558,7 +3752,7 @@ void GuiView::doShowDialog(QString const & qname, QString const & qdata, currentBufferView()->editInset(name, inset); // We only set the focus to the new dialog if it was not yet // visible in order not to change the existing previous behaviour - if (visible) { + if (visible) { // activateWindow is needed for floating dockviews dialog->asQWidget()->raise(); dialog->asQWidget()->activateWindow(); @@ -3589,9 +3783,12 @@ void GuiView::hideDialog(string const & name, Inset * inset) if (it == d.dialogs_.end()) return; - if (inset && currentBufferView() - && inset != currentBufferView()->editedInset(name)) - return; + if (inset) { + if (!currentBufferView()) + return; + if (inset != currentBufferView()->editedInset(name)) + return; + } Dialog * const dialog = it->second.get(); if (dialog->isVisibleView()) @@ -3655,19 +3852,15 @@ Dialog * createGuiExternal(GuiView & lv); Dialog * createGuiGraphics(GuiView & lv); Dialog * createGuiInclude(GuiView & lv); Dialog * createGuiIndex(GuiView & lv); -Dialog * createGuiLabel(GuiView & lv); -Dialog * createGuiLine(GuiView & lv); Dialog * createGuiListings(GuiView & lv); Dialog * createGuiLog(GuiView & lv); Dialog * createGuiMathMatrix(GuiView & lv); -Dialog * createGuiNomenclature(GuiView & lv); Dialog * createGuiNote(GuiView & lv); Dialog * createGuiParagraph(GuiView & lv); Dialog * createGuiPhantom(GuiView & lv); Dialog * createGuiPreferences(GuiView & lv); Dialog * createGuiPrint(GuiView & lv); Dialog * createGuiPrintindex(GuiView & lv); -Dialog * createGuiPrintNomencl(GuiView & lv); Dialog * createGuiRef(GuiView & lv); Dialog * createGuiSearch(GuiView & lv); Dialog * createGuiSearchAdv(GuiView & lv); @@ -3679,7 +3872,6 @@ Dialog * createGuiTabularCreate(GuiView & lv); Dialog * createGuiTexInfo(GuiView & lv); Dialog * createGuiToc(GuiView & lv); Dialog * createGuiThesaurus(GuiView & lv); -Dialog * createGuiHyperlink(GuiView & lv); Dialog * createGuiViewSource(GuiView & lv); Dialog * createGuiWrap(GuiView & lv); Dialog * createGuiProgressView(GuiView & lv); @@ -3722,18 +3914,12 @@ Dialog * GuiView::build(string const & name) return createGuiSearchAdv(*this); if (name == "graphics") return createGuiGraphics(*this); - if (name == "href") - return createGuiHyperlink(*this); if (name == "include") return createGuiInclude(*this); if (name == "index") return createGuiIndex(*this); if (name == "index_print") return createGuiPrintindex(*this); - if (name == "label") - return createGuiLabel(*this); - if (name == "line") - return createGuiLine(*this); if (name == "listings") return createGuiListings(*this); if (name == "log") @@ -3742,10 +3928,6 @@ Dialog * GuiView::build(string const & name) return createGuiDelimiter(*this); if (name == "mathmatrix") return createGuiMathMatrix(*this); - if (name == "nomenclature") - return createGuiNomenclature(*this); - if (name == "nomencl_print") - return createGuiPrintNomencl(*this); if (name == "note") return createGuiNote(*this); if (name == "paragraph")