X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiView.cpp;h=569de58926a42788028d0e627c962fd9ef35efc1;hb=d3312032eeea9a682840e3a6b6a762cb4adec729;hp=292d23f2a7fdee4e07bf16b8eaff9e05163a2de1;hpb=21379cbef98b804cd6a71aa0801e31b4878ab0ef;p=lyx.git diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 292d23f2a7..569de58926 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -57,6 +57,7 @@ #include "LyXVC.h" #include "Paragraph.h" #include "SpellChecker.h" +#include "TexRow.h" #include "TextClass.h" #include "Text.h" #include "Toolbars.h" @@ -106,9 +107,10 @@ #include #include -#define EXPORT_in_THREAD 1 +#define EXPORT_in_THREAD 1 + // QtConcurrent was introduced in Qt 4.4 #if (QT_VERSION >= 0x040400) #include @@ -116,7 +118,7 @@ #include #endif -#include +#include "support/bind.h" #include @@ -141,6 +143,8 @@ public: BackgroundWidget() { LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner); + if (!lyxrc.show_banner) + return; /// The text to be written on top of the pixmap QString const text = lyx_version ? qt_("version ") + lyx_version : qt_("unknown version"); @@ -153,8 +157,9 @@ public: font.setStyleHint(QFont::SansSerif); font.setWeight(QFont::Bold); font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble())); + int width = QFontMetrics(font).width(text); pain.setFont(font); - pain.drawText(260, 15, text); + pain.drawText(397 - width, 15, text); setFocusPolicy(Qt::StrongFocus); } @@ -186,7 +191,7 @@ private: /// Toolbar store providing access to individual toolbars by name. typedef map ToolbarMap; -typedef boost::shared_ptr DialogPtr; +typedef shared_ptr DialogPtr; } // namespace anon @@ -201,7 +206,7 @@ struct GuiView::GuiViewPrivate // hardcode here the platform specific icon size smallIconSize = 14; // scaling problems normalIconSize = 20; // ok, default - bigIconSize = 26; // better for some math icons + bigIconSize = 26; // better for some math icons splitter_ = new QSplitter; bg_widget_ = new BackgroundWidget; @@ -209,7 +214,21 @@ struct GuiView::GuiViewPrivate stack_widget_->addWidget(bg_widget_); stack_widget_->addWidget(splitter_); setBackground(); - progress_ = new GuiProgress(gv); + + // TODO cleanup, remove the singleton, handle multiple Windows? + progress_ = ProgressInterface::instance(); + if (!dynamic_cast(progress_)) { + progress_ = new GuiProgress(); // TODO who deletes it + ProgressInterface::setInstance(progress_); + } + QObject::connect( + dynamic_cast(progress_), + SIGNAL(updateStatusBarMessage(QString const&)), + gv, SLOT(updateStatusBarMessage(QString const&))); + QObject::connect( + dynamic_cast(progress_), + SIGNAL(clearMessageText()), + gv, SLOT(clearMessageText())); } ~GuiViewPrivate() @@ -217,7 +236,6 @@ struct GuiView::GuiViewPrivate delete splitter_; delete bg_widget_; delete stack_widget_; - delete progress_; } QMenu * toolBarPopup(GuiView * parent) @@ -309,7 +327,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. @@ -339,12 +357,22 @@ public: /// QFutureWatcher autosave_watcher_; QFutureWatcher preview_watcher_; + /// + string last_export_format; #else - struct DummyWatcher { bool isRunning(){return false;} }; + struct DummyWatcher { bool isRunning(){return false;} }; DummyWatcher preview_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); + }; +QSet GuiView::GuiViewPrivate::busyBuffers; + GuiView::GuiView(int id) : d(*new GuiViewPrivate(this)), id_(id), closing_(false) @@ -357,7 +385,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); @@ -365,7 +393,7 @@ GuiView::GuiView(int id) // Start autosave timer if (lyxrc.autosave) { - d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this)); + d.autosave_timeout_.timeout.connect(bind(&GuiView::autoSave, this)); d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000); d.autosave_timeout_.start(); } @@ -435,6 +463,8 @@ void GuiView::threadFinished() QFutureWatcher const * watcher = static_cast const *>(sender()); message(watcher->result()); + updateToolbars(); + errors(d.last_export_format); #endif } @@ -633,12 +663,30 @@ void GuiView::showEvent(QShowEvent * e) } +bool GuiView::closeScheduled() +{ + closing_ = true; + return close(); +} + + /** Destroy only all tabbed WorkAreas. Destruction of other WorkAreas ** is responsibility of the container (e.g., dialog) **/ 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.")); + close_event->setAccepted(false); + return; + } + + // If the user pressed the x (so we didn't call closeView + // programmatically), we want to clear all existing entries. + if (!closing_) + theSession().lastOpened().clear(); closing_ = true; writeSession(); @@ -710,7 +758,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) @@ -726,7 +774,7 @@ 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, @@ -747,13 +795,19 @@ void GuiView::message(docstring const & str) { if (ForkedProcess::iAmAChild()) return; - + // call is moved to GUI-thread by GuiProgress d.progress_->appendMessage(toqstr(str)); } -void GuiView::updateMessage(QString const & str) +void GuiView::clearMessageText() +{ + message(docstring()); +} + + +void GuiView::updateStatusBarMessage(QString const & str) { statusBar()->showMessage(str); d.statusbar_timer_.stop(); @@ -794,7 +848,7 @@ void GuiView::clearMessage() void GuiView::updateWindowTitle(GuiWorkArea * wa) { if (wa != d.current_work_area_ - || wa->bufferView().buffer().isInternal()) + || wa->bufferView().buffer().isInternal()) return; setWindowTitle(qt_("LyX: ") + wa->windowTitle()); setWindowIconText(wa->windowIconText()); @@ -957,8 +1011,8 @@ bool GuiView::event(QEvent * e) void GuiView::resetWindowTitleAndIconText() { - setWindowTitle(qt_("LyX")); - setWindowIconText(qt_("LyX")); + setWindowTitle(qt_("LyX")); + setWindowIconText(qt_("LyX")); } bool GuiView::focusNextPrevChild(bool /*next*/) @@ -968,8 +1022,15 @@ bool GuiView::focusNextPrevChild(bool /*next*/) } +bool GuiView::busy() const +{ + return busy_; +} + + void GuiView::setBusy(bool busy) { + busy_ = busy; if (d.current_work_area_) { d.current_work_area_->setUpdatesEnabled(!busy); if (busy) @@ -988,7 +1049,7 @@ void GuiView::setBusy(bool busy) GuiWorkArea * GuiView::workArea(Buffer & buffer) { if (currentWorkArea() - && ¤tWorkArea()->bufferView().buffer() == &buffer) + && ¤tWorkArea()->bufferView().buffer() == &buffer) return (GuiWorkArea *) currentWorkArea(); if (TabWorkArea * twa = d.currentTabWorkArea()) return twa->workArea(buffer); @@ -999,7 +1060,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); } @@ -1033,16 +1094,16 @@ GuiWorkArea * GuiView::currentWorkArea() GuiWorkArea const * GuiView::currentMainWorkArea() const { - if (d.currentTabWorkArea() == NULL) - return NULL; + if (!d.currentTabWorkArea()) + return 0; return d.currentTabWorkArea()->currentWorkArea(); } GuiWorkArea * GuiView::currentMainWorkArea() { - if (d.currentTabWorkArea() == NULL) - return NULL; + if (!d.currentTabWorkArea()) + return 0; return d.currentTabWorkArea()->currentWorkArea(); } @@ -1050,13 +1111,17 @@ GuiWorkArea * GuiView::currentMainWorkArea() void GuiView::setCurrentWorkArea(GuiWorkArea * wa) { LYXERR(Debug::DEBUG, "Setting current wa: " << wa << endl); - if (wa == NULL) { - d.current_work_area_ = NULL; + if (!wa) { + d.current_work_area_ = 0; d.setBackground(); return; } - GuiWorkArea * old_gwa = theGuiApp()->currentView()->currentWorkArea(); - if (old_gwa == 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) return; if (currentBufferView()) @@ -1148,12 +1213,13 @@ void GuiView::updateToolbars() ToolbarMap::iterator end = d.toolbars_.end(); if (d.current_work_area_) { bool const math = - d.current_work_area_->bufferView().cursor().inMathed(); + d.current_work_area_->bufferView().cursor().inMathed() + && !d.current_work_area_->bufferView().cursor().inRegexped(); bool const table = lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled(); bool const review = lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() && - lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true); + lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true); bool const mathmacrotemplate = lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled(); @@ -1173,7 +1239,7 @@ void GuiView::setBuffer(Buffer * newBuffer) GuiWorkArea * wa = workArea(*newBuffer); if (wa == 0) { - newBuffer->masterBuffer()->updateLabels(); + newBuffer->masterBuffer()->updateBuffer(); wa = addWorkArea(*newBuffer); } else { //Disconnect the old buffer...there's no new one. @@ -1215,9 +1281,9 @@ void GuiView::disconnectBufferView() void GuiView::errors(string const & error_type, bool from_master) { - ErrorList & el = from_master ? - documentBufferView()->buffer().masterBuffer()->errorList(error_type) - : documentBufferView()->buffer().errorList(error_type); + ErrorList & el = from_master ? + currentBufferView()->buffer().masterBuffer()->errorList(error_type) + : currentBufferView()->buffer().errorList(error_type); string data = error_type; if (from_master) data = "from_master|" + error_type; @@ -1264,7 +1330,7 @@ BufferView * GuiView::documentBufferView() } -BufferView const * GuiView::documentBufferView() const +BufferView const * GuiView::documentBufferView() const { return currentMainWorkArea() ? ¤tMainWorkArea()->bufferView() @@ -1285,7 +1351,7 @@ BufferView const * GuiView::currentBufferView() const #if (QT_VERSION >= 0x040400) -static docstring saveAndDestroyBuffer(Buffer * buffer, FileName const & fname) +docstring GuiView::GuiViewPrivate::saveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname) { bool failed = true; FileName const tmp_ret = FileName::tempName("lyxauto"); @@ -1298,6 +1364,7 @@ static docstring saveAndDestroyBuffer(Buffer * buffer, FileName const & fname) failed = buffer->writeFile(fname); } delete buffer; + busyBuffers.remove(orig); return failed ? _("Automatic save failed!") : _("Automatic save done."); @@ -1315,8 +1382,9 @@ void GuiView::autoSave() return; #if (QT_VERSION >= 0x040400) - QFuture f = QtConcurrent::run(saveAndDestroyBuffer, buffer->clone(), - buffer->getAutosaveFilename()); + GuiViewPrivate::busyBuffers.insert(buffer); + QFuture f = QtConcurrent::run(GuiViewPrivate::saveAndDestroy, buffer, buffer->clone(), + buffer->getAutosaveFileName()); d.autosave_watcher_.setFuture(f); #else buffer->autoSave(); @@ -1340,30 +1408,27 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) ? &(documentBufferView()->buffer()) : 0; // Check whether we need a buffer - if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) { + if (!lyxaction.funcHasFlag(cmd.action(), LyXAction::NoBuffer) && !buf) { // no, exit directly flag.message(from_utf8(N_("Command not allowed with" - "out any document open"))); + "out any document open"))); flag.setEnabled(false); return true; } - if (cmd.origin == FuncRequest::TOC) { + if (cmd.origin() == FuncRequest::TOC) { GuiToc * toc = static_cast(findOrBuild("toc", false)); - FuncStatus fs; - if (toc->getStatus(documentBufferView()->cursor(), cmd, fs)) - flag |= fs; - else + if (!toc || !toc->getStatus(documentBufferView()->cursor(), cmd, flag)) flag.setEnabled(false); return true; } - switch(cmd.action) { + switch(cmd.action()) { case LFUN_BUFFER_IMPORT: 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(); break; @@ -1411,7 +1476,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; } b = theBufferList().next(b); - } while (b != first); + } while (b != first); break; } @@ -1446,7 +1511,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); } @@ -1454,7 +1519,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) } case LFUN_DROP_LAYOUTS_CHOICE: - enable = buf; + enable = buf; break; case LFUN_UI_TOGGLE: @@ -1484,8 +1549,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) enable = doc_buffer->isExportable("dvi") && lyxrc.print_command != "none"; else if (name == "character" || name == "symbols") { - if (!buf || buf->isReadonly() - || !currentBufferView()->cursor().inTexted()) + if (!buf || buf->isReadonly()) enable = false; else { // FIXME we should consider passthru @@ -1518,28 +1582,28 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_COMPLETION_INLINE: if (!d.current_work_area_ - || !d.current_work_area_->completer().inlinePossible( + || !d.current_work_area_->completer().inlinePossible( currentBufferView()->cursor())) - enable = false; + enable = false; break; case LFUN_COMPLETION_POPUP: if (!d.current_work_area_ - || !d.current_work_area_->completer().popupPossible( + || !d.current_work_area_->completer().popupPossible( currentBufferView()->cursor())) - enable = false; + enable = false; break; case LFUN_COMPLETION_COMPLETE: if (!d.current_work_area_ || !d.current_work_area_->completer().inlinePossible( currentBufferView()->cursor())) - enable = false; + enable = false; break; case LFUN_COMPLETION_ACCEPT: if (!d.current_work_area_ - || (!d.current_work_area_->completer().popupVisible() + || (!d.current_work_area_->completer().popupVisible() && !d.current_work_area_->completer().inlineVisible() && !d.current_work_area_->completer().completionAvailable())) enable = false; @@ -1547,7 +1611,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_COMPLETION_CANCEL: if (!d.current_work_area_ - || (!d.current_work_area_->completer().popupVisible() + || (!d.current_work_area_->completer().popupVisible() && !d.current_work_area_->completer().inlineVisible())) enable = false; break; @@ -1559,7 +1623,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? @@ -1587,13 +1651,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()) @@ -1603,12 +1667,14 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; } case LFUN_VC_COMPARE: - enable = doc_buffer && !cmd.argument().empty() - && doc_buffer->lyxvc().prepareFileRevisionEnabled(); + enable = doc_buffer && doc_buffer->lyxvc().prepareFileRevisionEnabled(); break; case LFUN_SERVER_GOTO_FILE_ROW: break; + case LFUN_FORWARD_SEARCH: + enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty()); + break; default: return false; @@ -1625,10 +1691,10 @@ 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)"))); + QStringList(qt_("LyX Documents (*.lyx)"))); if (result.first == FileDialog::Later) return FileName(); @@ -1649,7 +1715,7 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles) setBusy(false); return 0; } - + setBuffer(newBuffer); // scroll to the position when the file was last closed @@ -1684,7 +1750,7 @@ void GuiView::openDocument(string const & fname) FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN); dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); dlg.setButton2(qt_("Examples|#E#e"), - toqstr(addPath(package().system_support().absFilename(), "examples"))); + toqstr(addPath(package().system_support().absFileName(), "examples"))); QStringList filter(qt_("LyX Documents (*.lyx)")); filter << qt_("LyX-1.3.x Documents (*.lyx13)") @@ -1708,20 +1774,22 @@ 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(); + filename = fullname.absFileName(); if (!fullname.onlyPath().isDirectory()) { Alert::warning(_("Invalid filename"), bformat(_("The directory in the given path\n%1$s\ndoes not exist."), - from_utf8(fullname.absFilename()))); + from_utf8(fullname.absFileName()))); return; } - // if the file doesn't exist, let the user create one - if (!fullname.exists()) { + + // 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. Buffer * const b = newFile(filename, string(), true); if (b) @@ -1735,7 +1803,8 @@ void GuiView::openDocument(string const & fname) docstring str2; Buffer * buf = loadDocument(fullname); if (buf) { - buf->updateLabels(); + // 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); @@ -1752,18 +1821,18 @@ void GuiView::openDocument(string const & fname) static bool import(GuiView * lv, FileName const & filename, string const & format, ErrorList & errorList) { - FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx")); + FileName const lyxfile(support::changeExtension(filename.absFileName(), ".lyx")); string loader_format; vector loaders = theConverters().loaders(); if (find(loaders.begin(), loaders.end(), format) == loaders.end()) { for (vector::const_iterator it = loaders.begin(); - it != loaders.end(); ++it) { + it != loaders.end(); ++it) { if (!theConverters().isReachable(format, *it)) continue; string const tofile = - support::changeExtension(filename.absFilename(), + support::changeExtension(filename.absFileName(), formats.extension(*it)); if (!theConverters().convert(0, filename, FileName(tofile), filename, format, *it, errorList)) @@ -1773,7 +1842,7 @@ static bool import(GuiView * lv, FileName const & filename, } if (loader_format.empty()) { frontend::Alert::error(_("Couldn't import file"), - bformat(_("No information for importing the format %1$s."), + bformat(_("No information for importing the format %1$s."), formats.prettyName(format))); return false; } @@ -1784,17 +1853,18 @@ static bool import(GuiView * lv, FileName const & filename, Buffer * buf = lv->loadDocument(lyxfile); if (!buf) return false; - buf->updateLabels(); + // 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); + Buffer * const b = newFile(lyxfile.absFileName(), string(), true); if (!b) return false; lv->setBuffer(b); bool as_paragraphs = loader_format == "textparagraph"; - string filename2 = (loader_format == format) ? filename.absFilename() - : support::changeExtension(filename.absFilename(), + string filename2 = (loader_format == format) ? filename.absFileName() + : support::changeExtension(filename.absFileName(), formats.extension(loader_format)); lv->currentBufferView()->insertPlaintextFile(FileName(filename2), as_paragraphs); @@ -1829,7 +1899,7 @@ void GuiView::importDocument(string const & argument) FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT); dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); dlg.setButton2(qt_("Examples|#E#e"), - toqstr(addPath(package().system_support().absFilename(), "examples"))); + toqstr(addPath(package().system_support().absFileName(), "examples"))); docstring filter = formats.prettyName(format); filter += " (*."; @@ -1856,7 +1926,7 @@ void GuiView::importDocument(string const & argument) // get absolute path of file FileName const fullname(support::makeAbsPath(filename)); - FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx")); + FileName const lyxfile(support::changeExtension(fullname.absFileName(), ".lyx")); // Check if the document already is open Buffer * buf = theBufferList().getBuffer(lyxfile); @@ -1868,7 +1938,7 @@ void GuiView::importDocument(string const & argument) } } - docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30); + docstring const displaypath = makeDisplayPath(lyxfile.absFileName(), 30); // if the file exists already, and we didn't do // -i lyx thefile.lyx, warn @@ -1908,11 +1978,11 @@ void GuiView::newDocument(string const & filename, bool from_template) string templatefile; if (from_template) { - templatefile = selectTemplateFile().absFilename(); + templatefile = selectTemplateFile().absFileName(); if (templatefile.empty()) return; } - + Buffer * b; if (filename.empty()) b = newUnnamedFile(initpath, to_utf8(_("newfile")), templatefile); @@ -1922,7 +1992,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. @@ -1938,7 +2008,7 @@ void GuiView::insertLyXFile(docstring const & fname) // FIXME UNICODE FileName filename(to_utf8(fname)); - + if (!filename.empty()) { bv->insertLyXFile(filename); return; @@ -1956,11 +2026,11 @@ void GuiView::insertLyXFile(docstring const & fname) 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(), + toqstr(addPath(package().system_support().absFileName(), "examples"))); FileDialog::Result result = dlg.open(toqstr(initpath), - QStringList(qt_("LyX Documents (*.lyx)"))); + QStringList(qt_("LyX Documents (*.lyx)"))); if (result.first == FileDialog::Later) return; @@ -1993,7 +2063,7 @@ void GuiView::insertPlaintextFile(docstring const & fname, // FIXME UNICODE FileName filename(to_utf8(fname)); - + if (!filename.empty()) { bv->insertPlaintextFile(filename, asParagraph); return; @@ -2029,7 +2099,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) if (!newname.empty()) { // FIXME UNICODE - fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename()); + fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFileName()); } else { // Switch to this Buffer. setBuffer(&b); @@ -2041,13 +2111,13 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path)); - if (!isLyXFilename(fname.absFilename())) + if (!isLyXFileName(fname.absFileName())) fname.changeExtension(".lyx"); FileDialog::Result result = - dlg.save(toqstr(fname.onlyPath().absFilename()), - QStringList(qt_("LyX Documents (*.lyx)")), - toqstr(fname.onlyFileName())); + dlg.save(toqstr(fname.onlyPath().absFileName()), + QStringList(qt_("LyX Documents (*.lyx)")), + toqstr(fname.onlyFileName())); if (result.first == FileDialog::Later) return false; @@ -2057,15 +2127,16 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) if (fname.empty()) return false; - if (!isLyXFilename(fname.absFilename())) + if (!isLyXFileName(fname.absFileName())) fname.changeExtension(".lyx"); } + // fname is now the new Buffer location. if (FileName(fname).exists()) { - docstring const file = makeDisplayPath(fname.absFilename(), 30); + 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")); @@ -2076,10 +2147,10 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) } } - FileName oldauto = b.getAutosaveFilename(); + FileName oldauto = b.getAutosaveFileName(); // Ok, change the name of the buffer - b.setFileName(fname.absFilename()); + b.setFileName(fname.absFileName()); b.markDirty(); bool unnamed = b.isUnnamed(); b.setUnnamed(false); @@ -2087,16 +2158,21 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) // bring the autosave file with us, just in case. b.moveAutosaveFile(oldauto); - + if (!saveBuffer(b)) { - oldauto = b.getAutosaveFilename(); - b.setFileName(oldname.absFilename()); + oldauto = b.getAutosaveFileName(); + b.setFileName(oldname.absFileName()); b.setUnnamed(unnamed); b.saveCheckSum(oldname); b.moveAutosaveFile(oldauto); return false; } + // 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; } @@ -2199,7 +2275,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; @@ -2228,6 +2304,11 @@ 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.")); + return false; + } + if (close_buffer) return closeBuffer(buf); else { @@ -2247,9 +2328,10 @@ bool GuiView::closeBuffer(Buffer & buf) // in the session file in the correct order. If we close the master // buffer, we can close or release the child buffers here too. 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? @@ -2269,6 +2351,7 @@ bool GuiView::closeBuffer(Buffer & buf) guiApp->gotoBookmark(i+1, false, false); if (saveBufferIfNeeded(buf, false)) { + buf.removeAutosaveFile(); theBufferList().release(&buf); return true; } @@ -2287,7 +2370,7 @@ 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 = + bool const close_buffer = !inMultiViews(wa) && !b.parent() && closing_; if (!closeWorkArea(wa, close_buffer)) @@ -2319,9 +2402,9 @@ bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding) int ret; if (hiding && buf.isUnnamed()) { 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?"), + "saved yet.\n\nDo you want to save " + "the document?"), file); + ret = Alert::prompt(_("Save new document?"), text, 0, 1, _("&Save"), _("&Cancel")); if (ret == 1) ++ret; @@ -2341,7 +2424,8 @@ bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding) // if we crash after this we could // have no autosave file but I guess // this is really improbable (Jug) - buf.removeAutosaveFile(); + // Sometime improbable things happen, bug 6857 (ps) + // buf.removeAutosaveFile(); if (hiding) // revert all changes buf.reload(); @@ -2376,7 +2460,7 @@ bool GuiView::inMultiViews(GuiWorkArea * wa) for (int i = 0; i != ids.size() && found_twa <= 1; ++i) { if (id_ == ids[i]) continue; - + if (guiApp->view(ids[i]).workArea(buf)) return true; } @@ -2419,14 +2503,14 @@ static bool ensureBufferClean(Buffer * buffer) docstring text; if (!buffer->isUnnamed()) { text = bformat(_("The document %1$s has unsaved " - "changes.\n\nDo you want to save " - "the document?"), file); + "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 " - "the document?"), file); + "saved yet.\n\nDo you want to save " + "the document?"), file); title = _("Save new document?"); } int const ret = Alert::prompt(title, text, 0, 1, _("&Save"), _("&Cancel")); @@ -2438,10 +2522,10 @@ static bool ensureBufferClean(Buffer * buffer) } -void GuiView::reloadBuffer() +bool GuiView::reloadBuffer() { Buffer * buf = &documentBufferView()->buffer(); - buf->reload(); + return buf->reload(); } @@ -2451,7 +2535,7 @@ void GuiView::checkExternallyModifiedBuffers() BufferList::iterator const bend = theBufferList().end(); for (; bit != bend; ++bit) { if ((*bit)->fileName().exists() - && (*bit)->isExternallyModified(Buffer::checksum_method)) { + && (*bit)->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())); @@ -2464,21 +2548,20 @@ void GuiView::checkExternallyModifiedBuffers() } -//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; - switch (cmd.action) { + switch (cmd.action()) { case LFUN_VC_REGISTER: if (!buffer || !ensureBufferClean(buffer)) break; if (!buffer->lyxvc().inUse()) { - if (buffer->lyxvc().registrer()) + if (buffer->lyxvc().registrer()) { reloadBuffer(); + dr.suppressMessageUpdate(); + } } break; @@ -2486,8 +2569,8 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (!buffer || !ensureBufferClean(buffer)) break; if (buffer->lyxvc().inUse() && !buffer->isReadonly()) { - msg = buffer->lyxvc().checkIn(); - if (!msg.empty()) + dr.setMessage(buffer->lyxvc().checkIn()); + if (!dr.message().empty()) reloadBuffer(); } break; @@ -2496,7 +2579,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (!buffer || !ensureBufferClean(buffer)) break; if (buffer->lyxvc().inUse()) { - msg = buffer->lyxvc().checkOut(); + dr.setMessage(buffer->lyxvc().checkOut()); reloadBuffer(); } break; @@ -2511,7 +2594,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd) frontend::Alert::error(_("Revision control error."), _("Error when setting the locking property.")); } else { - msg = res; + dr.setMessage(res); reloadBuffer(); } } @@ -2521,18 +2604,20 @@ void GuiView::dispatchVC(FuncRequest const & cmd) LASSERT(buffer, return); buffer->lyxvc().revert(); reloadBuffer(); + dr.suppressMessageUpdate(); break; case LFUN_VC_UNDO_LAST: LASSERT(buffer, return); buffer->lyxvc().undoLast(); reloadBuffer(); + 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; @@ -2581,6 +2666,11 @@ void GuiView::dispatchVC(FuncRequest const & cmd) case LFUN_VC_COMPARE: { + if (cmd.argument().empty()) { + lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "comparehistory")); + break; + } + string rev1 = cmd.getArg(0); string f1, f2; @@ -2598,25 +2688,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 - 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(2); - 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)); } @@ -2632,7 +2714,7 @@ void GuiView::openChildDocument(string const & fname) child = theBufferList().getBuffer(filename); } else { message(bformat(_("Opening child document %1$s..."), - makeDisplayPath(filename.absFilename()))); + makeDisplayPath(filename.absFileName()))); child = loadDocument(filename, false); parsed = true; } @@ -2643,7 +2725,10 @@ void GuiView::openChildDocument(string const & fname) // 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); - child->masterBuffer()->updateLabels(); + + // I don't think this is needed, since it will be called in + // setBuffer(). + // child->masterBuffer()->updateBuffer(); setBuffer(child); if (parsed) child->errors("Parse"); @@ -2667,7 +2752,7 @@ bool GuiView::goToFileRow(string const & argument) return false; } Buffer * buf = 0; - string const abstmp = package().temp_dir().absFilename(); + string const abstmp = package().temp_dir().absFileName(); string const realtmp = package().temp_dir().realPath(); // We have to use os::path_prefix_is() here, instead of // simply prefixIs(), because the file name comes from @@ -2685,13 +2770,17 @@ bool GuiView::goToFileRow(string const & argument) // Must replace extension of the file to be .lyx // and get full path FileName const s = fileSearch(string(), - support::changeExtension(file_name, ".lyx"), "lyx"); + support::changeExtension(file_name, ".lyx"), "lyx"); // Either change buffer or load the file if (theBufferList().exists(s)) buf = theBufferList().getBuffer(s); else if (s.exists()) { buf = loadDocument(s); - buf->updateLabels(); + 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( @@ -2707,26 +2796,28 @@ bool GuiView::goToFileRow(string const & argument) #if (QT_VERSION >= 0x040400) -static docstring exportAndDestroy(Buffer * buffer, string const & format) +docstring GuiView::GuiViewPrivate::exportAndDestroy(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->doExport(format, true, update_unincluded); delete buffer; + busyBuffers.remove(orig); return success ? bformat(_("Successful export to format: %1$s"), from_utf8(format)) : bformat(_("Error exporting to format: %1$s"), from_utf8(format)); } -static docstring previewAndDestroy(Buffer * buffer, string const & format) +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)); @@ -2734,18 +2825,19 @@ static docstring previewAndDestroy(Buffer * buffer, string const & format) #endif + 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); Buffer * doc_buffer = documentBufferView() ? &(documentBufferView()->buffer()) : 0; - if (cmd.origin == FuncRequest::TOC) { + if (cmd.origin() == FuncRequest::TOC) { GuiToc * toc = static_cast(findOrBuild("toc", false)); // FIXME: do we need to pass a DispatchResult object here? toc->doDispatch(bv->cursor(), cmd); @@ -2754,7 +2846,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) string const argument = to_utf8(cmd.argument()); - switch(cmd.action) { + switch(cmd.action()) { case LFUN_BUFFER_CHILD_OPEN: openChildDocument(to_utf8(cmd.argument())); break; @@ -2768,11 +2860,11 @@ 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"), + dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr); break; } - if (doc_buffer->doExport(argument, false)) { + if (!doc_buffer->doExport(argument, false)) { dr.setError(true); dr.setMessage(bformat(_("Error exporting to format: %1$s."), cmd.argument())); @@ -2783,88 +2875,148 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_BUFFER_UPDATE: { if (!doc_buffer) break; + docstring msg = _("Exporting ..."); + Buffer const * used_buffer = doc_buffer; string format = argument; - if (argument.empty()) - format = doc_buffer->getDefaultOutputFormat(); + if (format.empty()) + format = used_buffer->getDefaultOutputFormat(); #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) - d.progress_->clearMessages(); - message(_("Exporting ...")); - QFuture f = QtConcurrent::run(exportAndDestroy, - doc_buffer->clone(), format); + if (!msg.empty()) { + d.progress_->clearMessages(); + message(msg); + } + GuiViewPrivate::busyBuffers.insert(used_buffer); + QFuture f = QtConcurrent::run( + GuiViewPrivate::exportAndDestroy, + used_buffer, + used_buffer->clone(), + format); d.setPreviewFuture(f); + d.last_export_format = used_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); + used_buffer->params().maintain_unincluded_children && + !used_buffer->params().getIncludedChildren().empty(); + used_buffer->doExport(format, true, update_unincluded); #endif break; } case LFUN_BUFFER_VIEW: { if (!doc_buffer) break; + docstring msg = _("Previewing ..."); + Buffer const * used_buffer = doc_buffer; string format = argument; - if (argument.empty()) - format = doc_buffer->getDefaultOutputFormat(); + if (format.empty()) + format = used_buffer->getDefaultOutputFormat(); #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) - d.progress_->clearMessages(); - message(_("Previewing ...")); - QFuture f = QtConcurrent::run(previewAndDestroy, - doc_buffer->clone(), format); + if (!msg.empty()) { + d.progress_->clearMessages(); + message(msg); + } + GuiViewPrivate::busyBuffers.insert(used_buffer); + QFuture f = QtConcurrent::run( + GuiViewPrivate::previewAndDestroy, + used_buffer, + used_buffer->clone(), + format); d.setPreviewFuture(f); + d.last_export_format = used_buffer->bufferFormat(); #else bool const update_unincluded = - doc_buffer->params().maintain_unincluded_children - && !doc_buffer->params().getIncludedChildren().empty(); - doc_buffer->preview(format, update_unincluded); + used_buffer->params().maintain_unincluded_children && + !used_buffer->params().getIncludedChildren().empty(); + used_buffer->preview(format, update_unincluded); #endif break; } case LFUN_MASTER_BUFFER_UPDATE: { if (!doc_buffer) break; + Buffer const * used_buffer = doc_buffer->masterBuffer(); string format = argument; - Buffer const * master = doc_buffer->masterBuffer(); - if (argument.empty()) - format = master->getDefaultOutputFormat(); + if (format.empty()) + format = used_buffer->getDefaultOutputFormat(); #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) - QFuture f = QtConcurrent::run(exportAndDestroy, - master->clone(), format); + GuiViewPrivate::busyBuffers.insert(used_buffer); + QFuture f = QtConcurrent::run( + GuiViewPrivate::exportAndDestroy, + used_buffer, + used_buffer->clone(), + format); d.setPreviewFuture(f); + d.last_export_format = used_buffer->bufferFormat(); #else bool const update_unincluded = - master->params().maintain_unincluded_children - && !master->params().getIncludedChildren().empty(); - master->doExport(format, true); + used_buffer->params().maintain_unincluded_children && + !used_buffer->params().getIncludedChildren().empty(); + used_buffer->doExport(format, update_unincluded); #endif break; } case LFUN_MASTER_BUFFER_VIEW: { + if (!doc_buffer) + break; + Buffer const * used_buffer = doc_buffer->masterBuffer(); string format = argument; - Buffer const * master = doc_buffer->masterBuffer(); - if (argument.empty()) - format = master->getDefaultOutputFormat(); + if (format.empty()) + format = used_buffer->getDefaultOutputFormat(); #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) - QFuture f = QtConcurrent::run(previewAndDestroy, - master->clone(), format); + GuiViewPrivate::busyBuffers.insert(used_buffer); + QFuture f = QtConcurrent::run( + GuiViewPrivate::previewAndDestroy, + used_buffer, + used_buffer->clone(), + format); d.setPreviewFuture(f); + // TODO doc_buffer was used used? Was this this a copy & paste error? + d.last_export_format = used_buffer->bufferFormat(); #else - master->preview(format); + used_buffer->preview(format); #endif break; } - case LFUN_BUFFER_SWITCH: - if (FileName::isAbsolute(to_utf8(cmd.argument()))) { - Buffer * buffer = - theBufferList().getBuffer(FileName(to_utf8(cmd.argument()))); - if (buffer) - setBuffer(buffer); - else { - dr.setError(true); - dr.setMessage(_("Document not loaded")); + case LFUN_BUFFER_SWITCH: { + string const file_name = to_utf8(cmd.argument()); + if (!FileName::isAbsolute(file_name)) { + dr.setError(true); + dr.setMessage(_("Absolute filename expected.")); + break; + } + + Buffer * buffer = theBufferList().getBuffer(FileName(file_name)); + if (!buffer) { + dr.setError(true); + dr.setMessage(_("Document not loaded")); + break; + } + + // Do we open or switch to the buffer in this view ? + 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; + for (; i != ids.size(); ++i) { + GuiView & gv = guiApp->view(ids[i]); + if (gv.workArea(*buffer)) { + gv.activateWindow(); + gv.setBuffer(buffer); + break; } } + + // If necessary, open a new window as a last resort + if (i == ids.size()) { + lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW)); + lyx::dispatch(cmd); + } break; + } case LFUN_BUFFER_NEXT: gotoNextOrPreviousBuffer(NEXTBUFFER); @@ -2909,13 +3061,14 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) 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); + "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")); if (ret == 0) { doc_buffer->markClean(); reloadBuffer(); + dr.forceBufferUpdate(); } break; } @@ -2943,7 +3096,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; } @@ -3009,7 +3162,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: @@ -3077,7 +3230,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(); @@ -3111,7 +3264,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_BUFFER_ZOOM_IN: case LFUN_BUFFER_ZOOM_OUT: if (cmd.argument().empty()) { - if (cmd.action == LFUN_BUFFER_ZOOM_IN) + if (cmd.action() == LFUN_BUFFER_ZOOM_IN) lyxrc.zoom += 20; else lyxrc.zoom -= 20; @@ -3120,7 +3273,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(); @@ -3137,13 +3290,50 @@ 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: goToFileRow(to_utf8(cmd.argument())); break; + case LFUN_FORWARD_SEARCH: { + FileName const path(doc_buffer->temppath()); + string const texname = doc_buffer->latexName(); + FileName const dviname(addName(path.absFileName(), + support::changeExtension(texname, "dvi"))); + FileName const pdfname(addName(path.absFileName(), + support::changeExtension(texname, "pdf"))); + if (!dviname.exists() && !pdfname.exists()) { + dr.setMessage(_("Please, preview the document first.")); + break; + } + string outname = dviname.onlyFileName(); + string command = lyxrc.forward_search_dvi; + if (!dviname.exists() || + pdfname.lastModified() > dviname.lastModified()) { + outname = pdfname.onlyFileName(); + command = lyxrc.forward_search_pdf; + } + + int row = doc_buffer->texrow().getRowFromIdPos(bv->cursor().paragraph().id(), bv->cursor().pos()); + LYXERR(Debug::ACTION, "Forward search: row:" << row + << " id:" << bv->cursor().paragraph().id()); + if (!row || command.empty()) { + dr.setMessage(_("Couldn't proceed.")); + break; + } + string texrow = convert(row); + + command = subst(command, "$$n", texrow); + command = subst(command, "$$t", texname); + command = subst(command, "$$o", outname); + + PathChanger p(path); + Systemcall one; + one.startscript(Systemcall::DontWait, command); + break; + } default: dr.dispatched(false); break; @@ -3238,13 +3428,20 @@ void GuiView::toggleFullScreen() Buffer const * GuiView::updateInset(Inset const * inset) { - if (!d.current_work_area_) + if (!inset) return 0; - if (inset) - d.current_work_area_->scheduleRedraw(); + Buffer const * inset_buffer = &(inset->buffer()); - return &d.current_work_area_->bufferView().buffer(); + for (int i = 0; i != d.splitter_->count(); ++i) { + GuiWorkArea * wa = d.tabWorkArea(i)->currentWorkArea(); + if (!wa) + continue; + Buffer const * buffer = &(wa->bufferView().buffer()); + if (inset_buffer == buffer) + wa->scheduleRedraw(); + } + return inset_buffer; } @@ -3277,14 +3474,15 @@ namespace { // docs in LyXAction.cpp. char const * const dialognames[] = { + "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character", -"citation", "compare", "document", "errorlist", "ert", "external", "file", -"findreplace", "findreplaceadv", "float", "graphics", "href", "include", -"index", "index_print", "info", "listings", "label", "log", "mathdelimiter", -"mathmatrix", "mathspace", "nomenclature", "nomencl_print", "note", -"paragraph", "phantom", "prefs", "print", "ref", "sendto", "space", -"spellchecker", "symbols", "tabular", "tabularcreate", "thesaurus", "texinfo", -"toc", "view-source", "vspace", "wrap", "progress"}; +"citation", "compare", "comparehistory", "document", "errorlist", "ert", +"external", "file", "findreplace", "findreplaceadv", "float", "graphics", +"href", "include", "index", "index_print", "info", "listings", "label", "line", +"log", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature", +"nomencl_print", "note", "paragraph", "phantom", "prefs", "print", "ref", +"sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate", +"thesaurus", "texinfo", "toc", "view-source", "vspace", "wrap", "progress"}; char const * const * const end_dialognames = dialognames + (sizeof(dialognames) / sizeof(char *)); @@ -3303,7 +3501,7 @@ private: bool isValidName(string const & name) { return find_if(dialognames, end_dialognames, - cmpCStr(name.c_str())) != end_dialognames; + cmpCStr(name.c_str())) != end_dialognames; } } // namespace anon @@ -3368,9 +3566,18 @@ void GuiView::doShowDialog(QString const & qname, QString const & qdata, try { Dialog * dialog = findOrBuild(name, false); if (dialog) { + bool const visible = dialog->isVisibleView(); dialog->showData(data); if (inset && currentBufferView()) 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) { + // activateWindow is needed for floating dockviews + dialog->asQWidget()->raise(); + dialog->asQWidget()->activateWindow(); + dialog->asQWidget()->setFocus(); + } } } catch (ExceptionMessage const & ex) { @@ -3435,7 +3642,7 @@ void GuiView::updateDialogs() for(; it != end; ++it) { Dialog * dialog = it->second.get(); if (dialog) { - if (dialog->isBufferDependent() && !documentBufferView()) + if (dialog->needBufferOpen() && !documentBufferView()) hideDialog(fromqstr(dialog->name()), 0); else if (dialog->isVisibleView()) dialog->checkStatus(); @@ -3449,12 +3656,12 @@ Dialog * createDialog(GuiView & lv, string const & name); // will be replaced by a proper factory... Dialog * createGuiAbout(GuiView & lv); -Dialog * createGuiBibitem(GuiView & lv); Dialog * createGuiBibtex(GuiView & lv); Dialog * createGuiChanges(GuiView & lv); Dialog * createGuiCharacter(GuiView & lv); Dialog * createGuiCitation(GuiView & lv); Dialog * createGuiCompare(GuiView & lv); +Dialog * createGuiCompareHistory(GuiView & lv); Dialog * createGuiDelimiter(GuiView & lv); Dialog * createGuiDocument(GuiView & lv); Dialog * createGuiErrorList(GuiView & lv); @@ -3502,8 +3709,6 @@ Dialog * GuiView::build(string const & name) if (name == "aboutlyx") return createGuiAbout(*this); - if (name == "bibitem") - return createGuiBibitem(*this); if (name == "bibtex") return createGuiBibtex(*this); if (name == "changes") @@ -3514,6 +3719,8 @@ Dialog * GuiView::build(string const & name) return createGuiCitation(*this); if (name == "compare") return createGuiCompare(*this); + if (name == "comparehistory") + return createGuiCompareHistory(*this); if (name == "document") return createGuiDocument(*this); if (name == "errorlist")