X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiView.cpp;h=225033b10a332ceb3f9a832fee6db4ee2185d37f;hb=d57f66022c7159fff6a5c63fabe4dcde80ad7ef3;hp=4048dcfa361b70070162ad81f8156766406c6964;hpb=74a3fa9cf1c81702a755675a55fe3395b597967d;p=lyx.git diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 4048dcfa36..225033b10a 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; @@ -375,7 +394,7 @@ public: 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 saveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname); + 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); @@ -388,9 +407,6 @@ public: bool (Buffer::*syncFunc)(string const &, bool, bool) const, bool (Buffer::*previewFunc)(string const &, bool) const); - QTimer processing_cursor_timer_; - bool indicates_processing_; - QMap orig_cursors_; QVector guiWorkAreas(); }; @@ -441,18 +457,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 *)), @@ -497,71 +528,65 @@ QVector GuiView::GuiViewPrivate::guiWorkAreas() } -void GuiView::setCursorShapes(Qt::CursorShape shape) +#if QT_VERSION >= 0x040400 + +void GuiView::processingThreadStarted() { - QVector areas = d.guiWorkAreas(); - Q_FOREACH(GuiWorkArea* wa, areas) { - wa->setCursorShape(shape); - } } -void GuiView::restoreCursorShapes() +void GuiView::processingThreadFinished(bool show_errors) { - QVector areas = d.guiWorkAreas(); - Q_FOREACH(GuiWorkArea* wa, areas) { - if (d.orig_cursors_.contains(wa)) { - wa->setCursorShape(d.orig_cursors_[wa]); + QFutureWatcher const * watcher = + static_cast const *>(sender()); + message(watcher->result()); + updateToolbars(); + if (show_errors) { + BufferView const * const bv = currentBufferView(); + if (bv && !bv->buffer().errorList("Export").empty()) { + errors("Export"); + return; } - } + errors(d.last_export_format); + } } -void GuiView::saveCursorShapes() +void GuiView::processingThreadFinished() { - d.orig_cursors_.clear(); - QVector areas = d.guiWorkAreas(); - Q_FOREACH(GuiWorkArea* wa, areas) { - d.orig_cursors_[wa] = wa->cursorShape(); - } + processingThreadFinished(true); } -void GuiView::indicateProcessing() +void GuiView::autoSaveThreadFinished() { - if (d.indicates_processing_) { - restoreCursorShapes(); - } else { - setCursorShapes(Qt::BusyCursor); - } - d.indicates_processing_ = !d.indicates_processing_; + processingThreadFinished(false); } +#else + void GuiView::processingThreadStarted() { - saveCursorShapes(); - d.indicates_processing_ = false; - indicateProcessing(); - d.processing_cursor_timer_.start(); +} + + +void GuiView::processingThreadFinished(bool) +{ } void GuiView::processingThreadFinished() { -#if (QT_VERSION >= 0x040400) - 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; -#endif } +void GuiView::autoSaveThreadFinished() +{ +} +#endif + + void GuiView::saveLayout() const { QSettings settings; @@ -578,6 +603,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; @@ -588,7 +626,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(); @@ -615,6 +662,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(); @@ -727,10 +776,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(); } @@ -771,7 +820,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; } @@ -808,16 +858,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(); @@ -855,7 +897,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; @@ -1131,7 +1173,9 @@ void GuiView::setBusy(bool busy) return; if (d.current_work_area_) { - d.current_work_area_->setUpdatesEnabled(!busy); + //Why would we want to stop updates only for one workarea and + //not for the others ? This leads to problems as in #7314 (vfr). + //d.current_work_area_->setUpdatesEnabled(!busy); if (busy) d.current_work_area_->stopBlinkingCursor(); else @@ -1145,6 +1189,15 @@ void GuiView::setBusy(bool busy) } +GuiWorkArea * GuiView::workArea(int index) +{ + if (TabWorkArea * twa = d.currentTabWorkArea()) + if (index < twa->count()) + return dynamic_cast(twa->widget(index)); + return 0; +} + + GuiWorkArea * GuiView::workArea(Buffer & buffer) { if (currentWorkArea() @@ -1340,11 +1393,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) { @@ -1359,8 +1413,6 @@ void GuiView::setBuffer(Buffer * newBuffer) connectBuffer(*newBuffer); connectBufferView(wa->bufferView()); setCurrentWorkArea(wa); - - setBusy(false); } @@ -1392,14 +1444,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); } @@ -1462,23 +1531,15 @@ BufferView const * GuiView::currentBufferView() const #if (QT_VERSION >= 0x040400) -docstring GuiView::GuiViewPrivate::saveAndDestroy(Buffer const * orig, Buffer * buffer, FileName const & fname) +docstring GuiView::GuiViewPrivate::autosaveAndDestroy( + Buffer const * orig, Buffer * buffer) { - bool failed = true; - FileName const tmp_ret = FileName::tempName("lyxauto"); - if (!tmp_ret.empty()) { - if (buffer->writeFile(tmp_ret)) - failed = !tmp_ret.moveTo(fname); - } - if (failed) { - // failed to write/rename tmp_ret so try writing direct - failed = buffer->writeFile(fname); - } + bool const success = buffer->autoSave(); delete buffer; busyBuffers.remove(orig); - return failed - ? _("Automatic save failed!") - : _("Automatic save done."); + return success + ? _("Automatic save done.") + : _("Automatic save failed!"); } #endif @@ -1489,17 +1550,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::saveAndDestroy, buffer, buffer->clone(), - buffer->getAutosaveFileName()); + QFuture f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy, + buffer, buffer->clone()); d.autosave_watcher_.setFuture(f); #else buffer->autoSave(); #endif + resetAutosaveTimers(); } @@ -1552,8 +1616,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; } @@ -1657,16 +1721,14 @@ 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") @@ -1826,20 +1888,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; } @@ -2005,10 +2066,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))); @@ -2390,7 +2451,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; } @@ -2412,6 +2474,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(); @@ -2423,23 +2486,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; } @@ -2456,7 +2526,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; @@ -2506,10 +2576,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 @@ -2532,17 +2602,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; @@ -2555,24 +2623,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); } @@ -2862,6 +2930,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; @@ -2876,11 +2951,20 @@ docstring GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * o buffer->params().maintain_unincluded_children && !buffer->params().getIncludedChildren().empty(); bool const success = func(format, update_unincluded); - delete buffer; + + // 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(buffer->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 " + msg + " to format: %1$s"), from_utf8(format)) - : bformat(_("Error " + msg + " format: %1$s"), from_utf8(format)); + ? bformat(_("Successful export to format: %1$s"), from_utf8(format)) + : bformat(_("Error while exporting format: %1$s"), from_utf8(format)); } @@ -2942,10 +3026,9 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing( if (!used_buffer) return false; - gv_->processingThreadStarted(); string format = argument; if (format.empty()) - format = used_buffer->getDefaultOutputFormat(); + format = used_buffer->params().getDefaultOutputFormat(); #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) if (!msg.empty()) { @@ -2959,7 +3042,7 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing( used_buffer->clone(), 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 @@ -2972,7 +3055,6 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing( !used_buffer->params().getIncludedChildren().empty(); return (used_buffer->*syncFunc)(format, true, update_unincluded); } else if (previewFunc) { - // TODO includeall must be false or we get a 100% busy thread, a bug? return (used_buffer->*previewFunc)(format, false); } (void) asyncFunc; @@ -2980,6 +3062,44 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing( #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(); @@ -3020,7 +3140,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 @@ -3240,10 +3360,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; } @@ -3401,20 +3520,29 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; case LFUN_FORWARD_SEARCH: { - FileName const path(doc_buffer->temppath()); - string const texname = doc_buffer->latexName(); + Buffer const * doc_master = doc_buffer->masterBuffer(); + FileName const path(doc_master->temppath()); + string const texname = doc_master->isChild(doc_buffer) + ? DocFileName(changeExtension( + doc_buffer->absFileName(), + "tex")).mangledFileName() + : doc_buffer->latexName(); + string const mastername = + removeExtension(doc_master->latexName()); FileName const dviname(addName(path.absFileName(), - support::changeExtension(texname, "dvi"))); + addExtension(mastername, "dvi"))); FileName const pdfname(addName(path.absFileName(), - support::changeExtension(texname, "pdf"))); - 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; } @@ -3438,7 +3566,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; } @@ -3449,8 +3579,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (statusBar()->isVisible()) statusBar()->hide(); } - - return; } @@ -3615,6 +3743,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); @@ -3706,9 +3835,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())