X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiView.cpp;h=3eda5409a27cd6e0f4382abdb946e9e009ce7a4e;hb=4985015e8939df78a8d29c31aa04bc28caa3a47f;hp=249968cdfb40cebb01cf681cb70558633f12073d;hpb=a0916d4fef9d9c51665973e2bc5589a9eb60b590;p=lyx.git diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 249968cdfb..3eda5409a2 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -88,9 +88,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -134,6 +136,11 @@ using namespace std; using namespace lyx::support; namespace lyx { + +using support::addExtension; +using support::changeExtension; +using support::removeExtension; + namespace frontend { namespace { @@ -158,9 +165,8 @@ 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(397 - width, 15, text); + pain.drawText(190, 225, text); setFocusPolicy(Qt::StrongFocus); } @@ -205,10 +211,23 @@ struct GuiView::GuiViewPrivate in_show_(false) { // hardcode here the platform specific icon size - smallIconSize = 14; // scaling problems - normalIconSize = 20; // ok, default + smallIconSize = 16; // scaling problems + normalIconSize = 20; // ok, default if iconsize.png is missing bigIconSize = 26; // better for some math icons + // if it exists, use width of iconsize.png as normal size + QString const dir = toqstr(addPath("images", lyxrc.icon_set)); + FileName const fn = lyx::libFileSearch(dir, "iconsize.png"); + if (!fn.empty()) { + QImage image(toqstr(fn.absFileName())); + if (image.width() < int(smallIconSize)) + normalIconSize = smallIconSize; + else if (image.width() > int(bigIconSize)) + normalIconSize = bigIconSize; + else + normalIconSize = image.width(); + } + splitter_ = new QSplitter; bg_widget_ = new BackgroundWidget; stack_widget_ = new QStackedWidget; @@ -311,8 +330,20 @@ struct GuiView::GuiViewPrivate return tabWorkArea(0); } + int countWorkAreasOf(Buffer & buf) + { + int areas = tabWorkAreaCount(); + int count = 0; + for (int i = 0; i != areas; ++i) { + TabWorkArea * twa = tabWorkArea(i); + if (twa->workArea(buf)) + ++count; + } + return count; + } + #if (QT_VERSION >= 0x040400) - void setPreviewFuture(QFuture const & f) + void setPreviewFuture(QFuture const & f) { if (processing_thread_watcher_.isRunning()) { // we prefer to cancel this preview in order to keep a snappy @@ -363,34 +394,32 @@ public: #if (QT_VERSION >= 0x040400) /// QFutureWatcher autosave_watcher_; - QFutureWatcher processing_thread_watcher_; + QFutureWatcher processing_thread_watcher_; /// string last_export_format; + string processing_format; #else 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 compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format); - static docstring autosaveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname); + static Buffer::ExportStatus previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format); + static Buffer::ExportStatus exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format); + static Buffer::ExportStatus 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); + static Buffer::ExportStatus runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format); // 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); + Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &), + Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const, + Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const); - QTimer processing_cursor_timer_; - bool indicates_processing_; - QMap orig_cursors_; QVector guiWorkAreas(); }; @@ -427,11 +456,18 @@ GuiView::GuiView(int id) setAttribute(Qt::WA_DeleteOnClose, true); #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX)) + // QIcon::fromTheme was introduced in Qt 4.6 +#if (QT_VERSION >= 0x040600) // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac, - // since the icon is provided in the application bundle. + // since the icon is provided in the application bundle. We use a themed + // version when available and use the bundled one as fallback. + setWindowIcon(QIcon::fromTheme("lyx", getPixmap("images/", "lyx", "png"))); +#else setWindowIcon(getPixmap("images/", "lyx", "png")); #endif +#endif + #if (QT_VERSION >= 0x040300) // use tabbed dock area for multiple docks // (such as "source" and "messages") @@ -441,18 +477,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(processingThreadFinished())); + SLOT(autoSaveThreadFinished())); + + connect(&d.processing_thread_watcher_, SIGNAL(started()), this, + SLOT(processingThreadStarted())); connect(&d.processing_thread_watcher_, SIGNAL(finished()), this, SLOT(processingThreadFinished())); - d.processing_cursor_timer_.setInterval(1000 * 3); - connect(&d.processing_cursor_timer_, SIGNAL(timeout()), this, - SLOT(indicateProcessing())); #endif connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)), @@ -496,98 +547,81 @@ QVector GuiView::GuiViewPrivate::guiWorkAreas() return areas; } - -#if QT_VERSION >= 0x040400 -void GuiView::setCursorShapes(Qt::CursorShape shape) +static void handleExportStatus(GuiView * view, Buffer::ExportStatus status, + string const & format) { - QVector areas = d.guiWorkAreas(); - Q_FOREACH(GuiWorkArea* wa, areas) { - wa->setCursorShape(shape); + docstring const fmt = formats.prettyName(format); + docstring msg; + switch (status) { + case Buffer::ExportSuccess: + msg = bformat(_("Successful export to format: %1$s"), fmt); + break; + case Buffer::ExportCancel: + msg = _("Document export cancelled."); + break; + case Buffer::ExportError: + case Buffer::ExportNoPathToFormat: + case Buffer::ExportTexPathHasSpaces: + case Buffer::ExportConverterError: + msg = bformat(_("Error while exporting format: %1$s"), fmt); + break; + case Buffer::PreviewSuccess: + msg = bformat(_("Successful preview of format: %1$s"), fmt); + break; + case Buffer::PreviewError: + msg = bformat(_("Error while previewing format: %1$s"), fmt); + break; } + view->message(msg); } -void GuiView::restoreCursorShapes() -{ - QVector areas = d.guiWorkAreas(); - Q_FOREACH(GuiWorkArea* wa, areas) { - if (d.orig_cursors_.contains(wa)) { - wa->setCursorShape(d.orig_cursors_[wa]); - } - } -} - +#if QT_VERSION >= 0x040400 -void GuiView::saveCursorShapes() +void GuiView::processingThreadStarted() { - d.orig_cursors_.clear(); - QVector areas = d.guiWorkAreas(); - Q_FOREACH(GuiWorkArea* wa, areas) { - d.orig_cursors_[wa] = wa->cursorShape(); - } } -void GuiView::indicateProcessing() +void GuiView::processingThreadFinished() { - if (d.indicates_processing_) { - restoreCursorShapes(); - } else { - setCursorShapes(Qt::BusyCursor); - } - d.indicates_processing_ = !d.indicates_processing_; -} - + QFutureWatcher const * watcher = + static_cast const *>(sender()); -void GuiView::processingThreadStarted() -{ - saveCursorShapes(); - d.indicates_processing_ = false; - indicateProcessing(); - d.processing_cursor_timer_.start(); + Buffer::ExportStatus const status = watcher->result(); + handleExportStatus(this, status, d.processing_format); + + updateToolbars(); + BufferView const * const bv = currentBufferView(); + if (bv && !bv->buffer().errorList("Export").empty()) { + errors("Export"); + return; + } + errors(d.last_export_format); } -void GuiView::processingThreadFinished() +void GuiView::autoSaveThreadFinished() { QFutureWatcher const * watcher = static_cast const *>(sender()); message(watcher->result()); updateToolbars(); - errors(d.last_export_format); - d.processing_cursor_timer_.stop(); - restoreCursorShapes(); - d.indicates_processing_ = false; } #else -void GuiView::setCursorShapes(Qt::CursorShape) -{ -} - - -void GuiView::restoreCursorShapes() -{ -} - - -void GuiView::saveCursorShapes() -{ -} - - -void GuiView::indicateProcessing() +void GuiView::processingThreadStarted() { } -void GuiView::processingThreadStarted() +void GuiView::processingThreadFinished() { } -void GuiView::processingThreadFinished() +void GuiView::autoSaveThreadFinished() { } #endif @@ -609,6 +643,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; @@ -619,7 +666,16 @@ bool GuiView::restoreLayout() return false; //code below is skipped when when ~/.config/LyX is (re)created - setIconSize(settings.value(icon_key).toSize()); + QSize icon_size = settings.value(icon_key).toSize(); + // Check whether session size changed. + if (icon_size.width() != int(d.smallIconSize) && + icon_size.width() != int(d.normalIconSize) && + icon_size.width() != int(d.bigIconSize)) { + icon_size.setWidth(d.normalIconSize); + icon_size.setHeight(d.normalIconSize); + } + setIconSize(icon_size); + #ifdef Q_WS_X11 QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint(); QSize size = settings.value("size", QSize(690, 510)).toSize(); @@ -646,6 +702,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(); @@ -758,10 +816,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(); } @@ -783,6 +841,7 @@ void GuiView::showEvent(QShowEvent * e) // No work area, switch to the background widget. d.setBackground(); + updateToolbars(); QMainWindow::showEvent(e); } @@ -802,7 +861,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; } @@ -839,16 +899,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(); @@ -886,7 +938,7 @@ void GuiView::dropEvent(QDropEvent * event) = theConverters().importableFormats(); vector::const_iterator it = import_formats.begin(); for (; it != import_formats.end(); ++it) - if ((*it)->extension() == ext) + if ((*it)->hasExtension(ext)) found_formats.push_back(*it); FuncRequest cmd; @@ -982,6 +1034,9 @@ void GuiView::updateWindowTitle(GuiWorkArea * wa) void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa) { + if (d.current_work_area_) + QObject::disconnect(d.current_work_area_, SIGNAL(busy(bool)), + this, SLOT(setBusy(bool))); disconnectBuffer(); disconnectBufferView(); connectBufferView(wa->bufferView()); @@ -989,6 +1044,7 @@ void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa) d.current_work_area_ = wa; QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)), this, SLOT(updateWindowTitle(GuiWorkArea *))); + QObject::connect(wa, SIGNAL(busy(bool)), this, SLOT(setBusy(bool))); updateWindowTitle(wa); structureChanged(); @@ -1161,18 +1217,21 @@ void GuiView::setBusy(bool busy) // busy state didn't change return; - if (d.current_work_area_) { - d.current_work_area_->setUpdatesEnabled(!busy); - if (busy) - d.current_work_area_->stopBlinkingCursor(); - else - d.current_work_area_->startBlinkingCursor(); + if (busy) { + QApplication::setOverrideCursor(Qt::WaitCursor); + return; } + QApplication::restoreOverrideCursor(); + updateLayoutList(); +} - if (busy) - QApplication::setOverrideCursor(Qt::WaitCursor); - else - QApplication::restoreOverrideCursor(); + +GuiWorkArea * GuiView::workArea(int index) +{ + if (TabWorkArea * twa = d.currentTabWorkArea()) + if (index < twa->count()) + return dynamic_cast(twa->widget(index)); + return 0; } @@ -1358,12 +1417,14 @@ void GuiView::updateToolbars() lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true); bool const mathmacrotemplate = lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled(); + bool const ipa = + lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled(); for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it) - it->second->update(math, table, review, mathmacrotemplate); + it->second->update(math, table, review, mathmacrotemplate, ipa); } else for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it) - it->second->update(false, false, false, false); + it->second->update(false, false, false, false, false); } @@ -1371,11 +1432,12 @@ void GuiView::setBuffer(Buffer * newBuffer) { LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << endl); LASSERT(newBuffer, return); - setBusy(true); - + GuiWorkArea * wa = workArea(*newBuffer); if (wa == 0) { + setBusy(true); newBuffer->masterBuffer()->updateBuffer(); + setBusy(false); wa = addWorkArea(*newBuffer); // scroll to the position when the BufferView was last closed if (lyxrc.use_lastfilepos) { @@ -1390,8 +1452,6 @@ void GuiView::setBuffer(Buffer * newBuffer) connectBuffer(*newBuffer); connectBufferView(wa->bufferView()); setCurrentWorkArea(wa); - - setBusy(false); } @@ -1423,14 +1483,31 @@ void GuiView::disconnectBufferView() void GuiView::errors(string const & error_type, bool from_master) { - ErrorList & el = from_master ? - currentBufferView()->buffer().masterBuffer()->errorList(error_type) - : currentBufferView()->buffer().errorList(error_type); + BufferView const * const bv = currentBufferView(); + if (!bv) + return; + +#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) + // We are called with from_master == false by default, so we + // have to figure out whether that is the case or not. + ErrorList & el = bv->buffer().errorList(error_type); + if (el.empty()) { + el = bv->buffer().masterBuffer()->errorList(error_type); + from_master = true; + } +#else + ErrorList const & el = from_master ? + bv->buffer().masterBuffer()->errorList(error_type) : + bv->buffer().errorList(error_type); +#endif + + 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); } @@ -1493,23 +1570,15 @@ BufferView const * GuiView::currentBufferView() const #if (QT_VERSION >= 0x040400) -docstring GuiView::GuiViewPrivate::autosaveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname) +docstring GuiView::GuiViewPrivate::autosaveAndDestroy( + Buffer const * orig, Buffer * clone) { - 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); - } - delete buffer; + bool const success = clone->autoSave(); + delete clone; busyBuffers.remove(orig); - return failed - ? _("Automatic save failed!") - : _("Automatic save done."); + return success + ? _("Automatic save done.") + : _("Automatic save failed!"); } #endif @@ -1520,17 +1589,20 @@ void GuiView::autoSave() Buffer * buffer = documentBufferView() ? &documentBufferView()->buffer() : 0; - if (!buffer) + if (!buffer) { + resetAutosaveTimers(); return; + } #if (QT_VERSION >= 0x040400) GuiViewPrivate::busyBuffers.insert(buffer); QFuture f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy, - buffer, buffer->clone(), buffer->getAutosaveFileName()); + buffer, buffer->cloneBufferOnly()); d.autosave_watcher_.setFuture(f); #else buffer->autoSave(); #endif + resetAutosaveTimers(); } @@ -1583,8 +1655,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) } string format = to_utf8(cmd.argument()); if (cmd.argument().empty()) - format = doc_buffer->getDefaultOutputFormat(); - enable = doc_buffer->isExportableFormat(format); + format = doc_buffer->params().getDefaultOutputFormat(); + enable = doc_buffer->params().isExportableFormat(format); break; } @@ -1623,10 +1695,12 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) } case LFUN_BUFFER_WRITE_AS: + case LFUN_BUFFER_EXPORT_AS: enable = doc_buffer; break; case LFUN_BUFFER_CLOSE: + case LFUN_VIEW_CLOSE: enable = doc_buffer; break; @@ -1644,7 +1718,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; case LFUN_CLOSE_TAB_GROUP: - enable = d.currentTabWorkArea(); + enable = d.tabWorkAreaCount() > 1; break; case LFUN_TOOLBAR_TOGGLE: { @@ -1688,22 +1762,22 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) || name == "progress" || name == "compare"; else if (name == "print") - enable = doc_buffer->isExportable("dvi") + enable = doc_buffer->params().isExportable("dvi") && lyxrc.print_command != "none"; else if (name == "character" || name == "symbols") { 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") enable = FileName(doc_buffer->logName()).isReadableFile(); else if (name == "spellchecker") - enable = theSpellChecker() && !doc_buffer->isReadonly(); + enable = theSpellChecker() + && !doc_buffer->isReadonly() + && !doc_buffer->text().empty(); else if (name == "vclog") enable = doc_buffer->lyxvc().inUse(); break; @@ -1818,6 +1892,11 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty()); break; + case LFUN_FILE_INSERT_PLAINTEXT: + case LFUN_FILE_INSERT_PLAINTEXT_PARA: + enable = documentBufferView() && documentBufferView()->cursor().inTexted(); + break; + default: return false; } @@ -1857,20 +1936,19 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles) setBusy(false); throw(e); } + setBusy(false); if (!newBuffer) { message(_("Document not loaded.")); - setBusy(false); return 0; } - newBuffer->errors("Parse"); setBuffer(newBuffer); + newBuffer->errors("Parse"); if (tolastfiles) theSession().lastFiles().add(filename); - setBusy(false); return newBuffer; } @@ -1964,8 +2042,9 @@ static bool import(GuiView * lv, FileName const & filename, 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) { + vector::const_iterator it = loaders.begin(); + vector::const_iterator en = loaders.end(); + for (; it != en; ++it) { if (!theConverters().isReachable(format, *it)) continue; @@ -2036,10 +2115,10 @@ void GuiView::importDocument(string const & argument) toqstr(addPath(package().system_support().absFileName(), "examples"))); docstring filter = formats.prettyName(format); - filter += " (*."; + filter += " (*.{"; // FIXME UNICODE - filter += from_utf8(formats.extension(format)); - filter += ')'; + filter += from_utf8(formats.extensions(format)); + filter += "})"; FileDialog::Result result = dlg.open(toqstr(initpath), fileFilters(toqstr(filter))); @@ -2180,49 +2259,6 @@ void GuiView::insertLyXFile(docstring const & fname) } -void GuiView::insertPlaintextFile(docstring const & fname, - bool asParagraph) -{ - BufferView * bv = documentBufferView(); - if (!bv) - return; - - if (!fname.empty() && !FileName::isAbsolute(to_utf8(fname))) { - message(_("Absolute filename expected.")); - return; - } - - // FIXME UNICODE - FileName filename(to_utf8(fname)); - - if (!filename.empty()) { - bv->insertPlaintextFile(filename, asParagraph); - return; - } - - FileDialog dlg(qt_("Select file to insert"), (asParagraph ? - LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT)); - - FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()), - QStringList(qt_("All Files (*)"))); - - if (result.first == FileDialog::Later) - return; - - // FIXME UNICODE - filename.set(fromqstr(result.second)); - - // check selected filename - if (filename.empty()) { - // emit message signal. - message(_("Canceled.")); - return; - } - - bv->insertPlaintextFile(filename, asParagraph); -} - - bool GuiView::renameBuffer(Buffer & b, docstring const & newname) { FileName fname = b.fileName(); @@ -2263,9 +2299,29 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) } // fname is now the new Buffer location. + + // if there is already a Buffer open with this name, we do not want + // to have another one. (the second test makes sure we're not just + // trying to overwrite ourselves, which is fine.) + if (theBufferList().exists(fname) && fname != oldname + && theBufferList().getBuffer(fname) != &b) { + docstring const text = + bformat(_("The file\n%1$s\nis already open in your current session.\n" + "Please close it before attempting to overwrite it.\n" + "Do you want to choose a new filename?"), + from_utf8(fname.absFileName())); + int const ret = Alert::prompt(_("Chosen File Already Open"), + text, 0, 1, _("&Rename"), _("&Cancel")); + switch (ret) { + case 0: return renameBuffer(b, docstring()); + case 1: return false; + } + //return false; + } + if (FileName(fname).exists()) { docstring const file = makeDisplayPath(fname.absFileName(), 30); - docstring text = bformat(_("The document %1$s already " + docstring const text = bformat(_("The document %1$s already " "exists.\n\nDo you want to " "overwrite that document?"), file); @@ -2278,7 +2334,85 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname) } } - return saveBuffer(b, fname); + bool const saved = saveBuffer(b, fname); + if (saved) + b.reload(false); + return saved; +} + + +struct PrettyNameComparator +{ + bool operator()(Format const *first, Format const *second) const { + return compare_ascii_no_case(first->prettyname(), second->prettyname()) <= 0; + } +}; + + +bool GuiView::exportBufferAs(Buffer & b) +{ + FileName fname = b.fileName(); + + FileDialog dlg(qt_("Choose a filename to export the document as")); + dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); + + QStringList types; + types << "Any supported format (*.*)"; + Formats::const_iterator it = formats.begin(); + vector export_formats; + for (; it != formats.end(); ++it) + if (it->documentFormat() && it->inExportMenu()) + export_formats.push_back(&(*it)); + PrettyNameComparator cmp; + sort(export_formats.begin(), export_formats.end(), cmp); + vector::const_iterator fit = export_formats.begin(); + for (; fit != export_formats.end(); ++fit) + types << toqstr((*fit)->prettyname() + " (*." + (*fit)->extension() + ")"); + QString filter; + FileDialog::Result result = + dlg.save(toqstr(fname.onlyPath().absFileName()), + types, + toqstr(fname.onlyFileName()), + &filter); + if (result.first != FileDialog::Chosen) + return false; + + string s = fromqstr(filter); + size_t pos = s.find(" (*."); + LASSERT(pos != string::npos, /**/); + string fmt_prettyname = s.substr(0, pos); + string fmt_name; + fname.set(fromqstr(result.second)); + if (fmt_prettyname == "Any supported format") + fmt_name = formats.getFormatFromExtension(fname.extension()); + else + fmt_name = formats.getFormatFromPrettyName(fmt_prettyname); + LYXERR(Debug::FILES, "fmt_prettyname=" << fmt_prettyname + << ", fmt_name=" << fmt_name << ", fname=" << fname.absFileName()); + + if (fmt_name.empty() || fname.empty()) + return false; + + // fname is now the new Buffer location. + if (FileName(fname).exists()) { + docstring const file = makeDisplayPath(fname.absFileName(), 30); + docstring text = bformat(_("The document %1$s already " + "exists.\n\nDo you want to " + "overwrite that document?"), + file); + int const ret = Alert::prompt(_("Overwrite document?"), + text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel")); + switch (ret) { + case 0: break; + case 1: return exportBufferAs(b); + case 2: return false; + } + } + + FuncRequest cmd(LFUN_BUFFER_EXPORT, fmt_name + " " + fname.absFileName()); + DispatchResult dr; + dispatch(cmd, dr); + return dr.dispatched(); } @@ -2337,10 +2471,45 @@ bool GuiView::hideWorkArea(GuiWorkArea * wa) } +// We only want to close the buffer if it is not visible in other workareas +// of the same view, nor in other views, and if this is not a child bool GuiView::closeWorkArea(GuiWorkArea * wa) { Buffer & buf = wa->bufferView().buffer(); - return closeWorkArea(wa, !buf.parent()); + + bool last_wa = d.countWorkAreasOf(buf) == 1 + && !inOtherView(buf) && !buf.parent(); + + bool close_buffer = last_wa; + + if (last_wa) { + if (lyxrc.close_buffer_with_last_view == "yes") + ; // Nothing to do + else if (lyxrc.close_buffer_with_last_view == "no") + close_buffer = false; + else { + docstring file; + if (buf.isUnnamed()) + file = from_utf8(buf.fileName().onlyFileName()); + else + file = buf.fileName().displayName(30); + docstring const text = bformat( + _("Last view on document %1$s is being closed.\n" + "Would you like to close or hide the document?\n" + "\n" + "Hidden documents can be displayed back through\n" + "the menu: View->Hidden->...\n" + "\n" + "To remove this question, set your preference in:\n" + " Tools->Preferences->Look&Feel->UserInterface\n" + ), file); + int ret = Alert::prompt(_("Close or hide document?"), + text, 0, 1, _("&Close"), _("&Hide")); + close_buffer = (ret == 0); + } + } + + return closeWorkArea(wa, close_buffer); } @@ -2421,7 +2590,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; } @@ -2443,6 +2613,7 @@ 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_) { ListOfBuffers clist = buf.getChildren(); ListOfBuffers::const_iterator it = clist.begin(); @@ -2454,23 +2625,30 @@ bool GuiView::closeBuffer(Buffer & buf) 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 (saveBufferIfNeeded(buf, false)) { - buf.removeAutosaveFile(); - theBufferList().release(&buf); - return true; + 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; + } } + // open all children again to avoid a crash because of dangling + // pointers (bug 6603) + buf.updateBuffer(); return false; } @@ -2487,7 +2665,7 @@ bool GuiView::closeTabWorkArea(TabWorkArea * twa) // 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_; + !inOtherView(b) && !b.parent() && closing_; if (!closeWorkArea(wa, close_buffer)) return false; @@ -2537,10 +2715,10 @@ 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 @@ -2563,17 +2741,15 @@ 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; @@ -2586,24 +2762,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); } @@ -2893,6 +3069,13 @@ bool GuiView::goToFileRow(string const & argument) return false; } } + if (!buf) { + message(bformat( + _("No buffer for file: %1$s."), + makeDisplayPath(file_name)) + ); + return false; + } setBuffer(buf); documentBufferView()->setCursorFromRow(row); return true; @@ -2901,67 +3084,61 @@ bool GuiView::goToFileRow(string const & argument) #if (QT_VERSION >= 0x040400) template -docstring GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format, string const & msg) +Buffer::ExportStatus GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * clone, string const & format) { - bool const update_unincluded = - buffer->params().maintain_unincluded_children - && !buffer->params().getIncludedChildren().empty(); - bool const success = func(format, update_unincluded); - delete buffer; + Buffer::ExportStatus const status = func(format); + + // the cloning operation will have produced a clone of the entire set of + // documents, starting from the master. so we must delete those. + Buffer * mbuf = const_cast(clone->masterBuffer()); + delete mbuf; 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 while exporting format: %1$s"), from_utf8(format)); + return status; } -docstring GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format) +Buffer::ExportStatus GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * clone, 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"); + Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport; + return runAndDestroy(bind(mem_func, clone, _1, true), orig, clone, format); } -docstring GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format) +Buffer::ExportStatus GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * clone, 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"); + Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport; + return runAndDestroy(bind(mem_func, clone, _1, false), orig, clone, format); } -docstring GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format) +Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * clone, string const & format) { - bool(Buffer::* mem_func)(std::string const &, bool) const = &Buffer::preview; - return runAndDestroy(bind(mem_func, buffer, _1, _2), orig, buffer, format, "preview"); + Buffer::ExportStatus (Buffer::* mem_func)(std::string const &) const = &Buffer::preview; + return runAndDestroy(bind(mem_func, clone, _1), orig, clone, format); } #else // not used, but the linker needs them -docstring GuiView::GuiViewPrivate::compileAndDestroy( +Buffer::ExportStatus GuiView::GuiViewPrivate::compileAndDestroy( Buffer const *, Buffer *, string const &) { - return docstring(); + return Buffer::ExportSuccess; } -docstring GuiView::GuiViewPrivate::exportAndDestroy( +Buffer::ExportStatus GuiView::GuiViewPrivate::exportAndDestroy( Buffer const *, Buffer *, string const &) { - return docstring(); + return Buffer::ExportSuccess; } -docstring GuiView::GuiViewPrivate::previewAndDestroy( +Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy( Buffer const *, Buffer *, string const &) { - return docstring(); + return Buffer::ExportSuccess; } #endif @@ -2971,50 +3148,94 @@ 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) + Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &), + Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const, + Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const) { if (!used_buffer) return false; string format = argument; if (format.empty()) - format = used_buffer->getDefaultOutputFormat(); - + format = used_buffer->params().getDefaultOutputFormat(); + processing_format = format; #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) - gv_->processingThreadStarted(); if (!msg.empty()) { progress_->clearMessages(); gv_->message(msg); } GuiViewPrivate::busyBuffers.insert(used_buffer); - QFuture f = QtConcurrent::run( + Buffer * cloned_buffer = used_buffer->cloneFromMaster(); + if (!cloned_buffer) { + Alert::error(_("Export Error"), + _("Error cloning the Buffer.")); + return false; + } + QFuture f = QtConcurrent::run( asyncFunc, used_buffer, - used_buffer->clone(), + cloned_buffer, format); setPreviewFuture(f); - last_export_format = used_buffer->bufferFormat(); + last_export_format = used_buffer->params().bufferFormat(); (void) syncFunc; (void) previewFunc; // We are asynchronous, so we don't know here anything about the success return true; #else + Buffer::ExportStatus status; 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); + status = (used_buffer->*syncFunc)(format, true); } else if (previewFunc) { - return (used_buffer->*previewFunc)(format, false); - } + status = (used_buffer->*previewFunc)(format); + } else + return false; + handleExportStatus(gv_, status, format); (void) asyncFunc; - return false; + return (status == Buffer::ExportSuccess + || status == Buffer::PreviewSuccess); #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 != 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(); @@ -3055,7 +3276,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) #if QT_VERSION < 0x040400 if (!doc_buffer->doExport(argument, false)) { dr.setError(true); - dr.setMessage(bformat(_("Error exporting to format: %1$s."), + dr.setMessage(bformat(_("Error exporting to format: %1$s"), cmd.argument())); } #else @@ -3072,6 +3293,11 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } + case LFUN_BUFFER_EXPORT_AS: + LASSERT(doc_buffer, break); + exportBufferAs(*doc_buffer); + break; + case LFUN_BUFFER_UPDATE: { d.asyncBufferProcessing(argument, doc_buffer, @@ -3181,13 +3407,37 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) insertLyXFile(cmd.argument()); break; - case LFUN_FILE_INSERT_PLAINTEXT_PARA: - insertPlaintextFile(cmd.argument(), true); - break; - case LFUN_FILE_INSERT_PLAINTEXT: - insertPlaintextFile(cmd.argument(), false); + case LFUN_FILE_INSERT_PLAINTEXT_PARA: { + bool const as_paragraph = (cmd.action() == LFUN_FILE_INSERT_PLAINTEXT_PARA); + string const fname = to_utf8(cmd.argument()); + if (!fname.empty() && !FileName::isAbsolute(fname)) { + dr.setMessage(_("Absolute filename expected.")); + break; + } + + FileName filename(fname); + if (fname.empty()) { + FileDialog dlg(qt_("Select file to insert"), (as_paragraph ? + LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT)); + + FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()), + QStringList(qt_("All Files (*)"))); + + if (result.first == FileDialog::Later || result.second.isEmpty()) { + dr.setMessage(_("Canceled.")); + break; + } + + filename.set(fromqstr(result.second)); + } + + if (bv) { + FuncRequest const new_cmd(cmd, filename.absoluteFilePath()); + bv->dispatch(new_cmd, dr); + } break; + } case LFUN_BUFFER_RELOAD: { LASSERT(doc_buffer, break); @@ -3275,10 +3525,9 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } 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; } @@ -3369,6 +3618,21 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } break; + case LFUN_VIEW_CLOSE: + if (TabWorkArea * twa = d.currentTabWorkArea()) { + closeWorkArea(twa->currentWorkArea()); + d.current_work_area_ = 0; + twa = d.currentTabWorkArea(); + // Switch to the next GuiWorkArea in the found TabWorkArea. + if (twa) { + // Make sure the work area is up to date. + setCurrentWorkArea(twa->currentWorkArea()); + } else { + setCurrentWorkArea(0); + } + } + break; + case LFUN_COMPLETION_INLINE: if (d.current_work_area_) d.current_work_area_->completer().showInline(); @@ -3436,27 +3700,43 @@ 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 fulltexname = + support::makeAbsPath(texname, doc_master->temppath()).absFileName(); + 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"))); - if (!dviname.exists() && !pdfname.exists()) { + addExtension(mastername, "pdf"))); + bool const have_dvi = dviname.exists(); + bool const have_pdf = pdfname.exists(); + if (!have_dvi && !have_pdf) { 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()) { + if (!have_dvi || (have_pdf && + 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()); + DocIterator tmpcur = bv->cursor(); + // Leave math first + while (tmpcur.inMathed()) + tmpcur.pop_back(); + int row = tmpcur.inMathed() ? 0 : doc_buffer->texrow().getRowFromIdPos( + tmpcur.paragraph().id(), tmpcur.pos()); LYXERR(Debug::ACTION, "Forward search: row:" << row - << " id:" << bv->cursor().paragraph().id()); + << " id:" << tmpcur.paragraph().id()); if (!row || command.empty()) { dr.setMessage(_("Couldn't proceed.")); break; @@ -3464,6 +3744,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) string texrow = convert(row); command = subst(command, "$$n", texrow); + command = subst(command, "$$f", fulltexname); command = subst(command, "$$t", texname); command = subst(command, "$$o", outname); @@ -3473,7 +3754,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; } @@ -3484,8 +3767,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (statusBar()->isVisible()) statusBar()->hide(); } - - return; } @@ -3650,6 +3931,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); @@ -3741,9 +4023,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())