X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiView.cpp;h=fe0c201b8dc3fe26d20f4ab403dcc02555094797;hb=425d092204118ea6c24c28e85fdf03fcf2bb51a4;hp=b9462b4710077a08c2a5d8294cb02abd9f7038d0;hpb=966da4da130badf62d854ab01f06da9f4799431e;p=lyx.git diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index b9462b4710..fe0c201b8d 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -16,15 +16,16 @@ #include "GuiView.h" #include "Dialog.h" +#include "DispatchResult.h" #include "FileDialog.h" #include "FontLoader.h" #include "GuiApplication.h" #include "GuiCommandBuffer.h" #include "GuiCompleter.h" -#include "GuiWorkArea.h" #include "GuiKeySymbol.h" #include "GuiToc.h" #include "GuiToolbar.h" +#include "GuiWorkArea.h" #include "LayoutBox.h" #include "Menus.h" #include "TocModel.h" @@ -76,6 +77,8 @@ #include "support/Path.h" #include "support/Systemcall.h" #include "support/Timeout.h" +#include "support/ProgressInterface.h" +#include "GuiProgress.h" #include #include @@ -97,11 +100,22 @@ #include #include #include +#include #include #include #include #include +#define EXPORT_in_THREAD 1 + + +// QtConcurrent was introduced in Qt 4.4 +#if (QT_VERSION >= 0x040400) +#include +#include +#include +#endif + #include #include @@ -141,6 +155,7 @@ public: font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble())); pain.setFont(font); pain.drawText(260, 15, text); + setFocusPolicy(Qt::StrongFocus); } void paintEvent(QPaintEvent *) @@ -151,13 +166,25 @@ public: pain.drawPixmap(x, y, splash_); } + void keyPressEvent(QKeyEvent * ev) + { + KeySymbol sym; + setKeySymbol(&sym, ev); + if (sym.isOK()) { + guiApp->processKeySym(sym, q_key_state(ev->modifiers())); + ev->accept(); + } else { + ev->ignore(); + } + } + private: QPixmap splash_; }; /// Toolbar store providing access to individual toolbars by name. -typedef std::map ToolbarMap; +typedef map ToolbarMap; typedef boost::shared_ptr DialogPtr; @@ -166,8 +193,8 @@ typedef boost::shared_ptr DialogPtr; struct GuiView::GuiViewPrivate { - GuiViewPrivate() - : current_work_area_(0), current_main_work_area_(0), + GuiViewPrivate(GuiView * gv) + : gv_(gv), current_work_area_(0), current_main_work_area_(0), layout_(0), autosave_timeout_(5000), in_show_(false) { @@ -182,6 +209,7 @@ struct GuiView::GuiViewPrivate stack_widget_->addWidget(bg_widget_); stack_widget_->addWidget(splitter_); setBackground(); + progress_ = new GuiProgress(gv); } ~GuiViewPrivate() @@ -189,6 +217,7 @@ struct GuiView::GuiViewPrivate delete splitter_; delete bg_widget_; delete stack_widget_; + delete progress_; } QMenu * toolBarPopup(GuiView * parent) @@ -233,6 +262,7 @@ struct GuiView::GuiViewPrivate { stack_widget_->setCurrentWidget(bg_widget_); bg_widget_->setUpdatesEnabled(true); + bg_widget_->setFocus(); } TabWorkArea * tabWorkArea(int i) @@ -256,7 +286,20 @@ struct GuiView::GuiViewPrivate return tabWorkArea(0); } +#if (QT_VERSION >= 0x040400) + void setPreviewFuture(QFuture const & f) + { + if (preview_watcher_.isRunning()) { + // we prefer to cancel this preview in order to keep a snappy + // interface. + return; + } + preview_watcher_.setFuture(f); + } +#endif + public: + GuiView * gv_; GuiWorkArea * current_work_area_; GuiWorkArea * current_main_work_area_; QSplitter * splitter_; @@ -264,6 +307,7 @@ public: BackgroundWidget * bg_widget_; /// view's toolbars ToolbarMap toolbars_; + ProgressInterface* progress_; /// The main layout box. /** * \warning Don't Delete! The layout box is actually owned by @@ -275,9 +319,6 @@ public: */ LayoutBox * layout_; - /// - map open_insets_; - /// map dialogs_; @@ -293,11 +334,20 @@ public: /// TocModels toc_models_; + +#if (QT_VERSION >= 0x040400) + /// + QFutureWatcher autosave_watcher_; + QFutureWatcher preview_watcher_; +#else + struct DummyWatcher { bool isRunning(){return false;} }; + DummyWatcher preview_watcher_; +#endif }; GuiView::GuiView(int id) - : d(*new GuiViewPrivate), id_(id), closing_(false) + : d(*new GuiViewPrivate(this)), id_(id), closing_(false) { // GuiToolbars *must* be initialised before the menu bar. normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge @@ -331,10 +381,27 @@ GuiView::GuiView(int id) setWindowIcon(getPixmap("images/", "lyx", "png")); #endif +#if (QT_VERSION >= 0x040300) + // use tabbed dock area for multiple docks + // (such as "source" and "messages") + setDockOptions(QMainWindow::ForceTabbedDocks); +#endif + // For Drag&Drop. setAcceptDrops(true); statusBar()->setSizeGripEnabled(true); + updateStatusBar(); + +#if (QT_VERSION >= 0x040400) + connect(&d.autosave_watcher_, SIGNAL(finished()), this, + SLOT(threadFinished())); + connect(&d.preview_watcher_, SIGNAL(finished()), this, + SLOT(threadFinished())); +#endif + + connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)), + SLOT(doShowDialog(QString const &, QString const &, Inset *))); // Forbid too small unresizable window because it can happen // with some window manager under X11. @@ -362,6 +429,16 @@ GuiView::~GuiView() } +void GuiView::threadFinished() +{ +#if (QT_VERSION >= 0x040400) + QFutureWatcher const * watcher = + static_cast const *>(sender()); + message(watcher->result()); +#endif +} + + void GuiView::saveLayout() const { QSettings settings; @@ -413,6 +490,8 @@ bool GuiView::restoreLayout() dialog->prepareView(); if ((dialog = findOrBuild("view-source", true))) dialog->prepareView(); + if ((dialog = findOrBuild("progress", true))) + dialog->prepareView(); if (!restoreState(settings.value("layout").toByteArray(), 0)) initToolbars(); @@ -464,7 +543,7 @@ void GuiView::initToolbars() if (!tb) continue; int const visibility = guiApp->toolbars().defaultVisibility(cit->name); - bool newline = true; + bool newline = !(visibility & Toolbars::SAMEROW); tb->setVisible(false); tb->setVisibility(visibility); @@ -477,7 +556,8 @@ void GuiView::initToolbars() if (visibility & Toolbars::BOTTOM) { // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock. #if (QT_VERSION >= 0x040202) - addToolBarBreak(Qt::BottomToolBarArea); + if (newline) + addToolBarBreak(Qt::BottomToolBarArea); #endif addToolBar(Qt::BottomToolBarArea, tb); } @@ -485,7 +565,8 @@ void GuiView::initToolbars() if (visibility & Toolbars::LEFT) { // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock. #if (QT_VERSION >= 0x040202) - addToolBarBreak(Qt::LeftToolBarArea); + if (newline) + addToolBarBreak(Qt::LeftToolBarArea); #endif addToolBar(Qt::LeftToolBarArea, tb); } @@ -493,7 +574,8 @@ void GuiView::initToolbars() if (visibility & Toolbars::RIGHT) { // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock. #if (QT_VERSION >= 0x040202) - addToolBarBreak(Qt::RightToolBarArea); + if (newline) + addToolBarBreak(Qt::RightToolBarArea); #endif addToolBar(Qt::RightToolBarArea, tb); } @@ -513,11 +595,22 @@ TocModels & GuiView::tocModels() void GuiView::setFocus() { LYXERR(Debug::DEBUG, "GuiView::setFocus()" << this); + QMainWindow::setFocus(); +} + + +void GuiView::focusInEvent(QFocusEvent * e) +{ + LYXERR(Debug::DEBUG, "GuiView::focusInEvent()" << this); + QMainWindow::focusInEvent(e); // Make sure LyXFunc points to the correct view. guiApp->setCurrentView(this); - QMainWindow::setFocus(); - if (d.current_work_area_) - d.current_work_area_->setFocus(); + if (currentMainWorkArea()) + currentMainWorkArea()->setFocus(); + else if (currentWorkArea()) + currentWorkArea()->setFocus(); + else + d.bg_widget_->setFocus(); } @@ -611,13 +704,42 @@ void GuiView::dropEvent(QDropEvent * event) for (int i = 0; i != files.size(); ++i) { string const file = os::internal_path(fromqstr( files.at(i).toLocalFile())); - if (!file.empty()) { - // Asynchronously post the event. DropEvent usually come - // from the BufferView. But reloading a file might close - // the BufferView from within its own event handler. - guiApp->dispatchDelayed(FuncRequest(LFUN_FILE_OPEN, file)); - event->accept(); + if (file.empty()) + continue; + + string const ext = support::getExtension(file); + vector found_formats; + + // Find all formats that have the correct extension. + vector const & import_formats + = theConverters().importableFormats(); + vector::const_iterator it = import_formats.begin(); + for (; it != import_formats.end(); ++it) + if ((*it)->extension() == ext) + found_formats.push_back(*it); + + FuncRequest cmd; + if (found_formats.size() >= 1) { + if (found_formats.size() > 1) { + //FIXME: show a dialog to choose the correct importable format + LYXERR(Debug::FILES, + "Multiple importable formats found, selecting first"); + } + string const arg = found_formats[0]->name() + " " + file; + cmd = FuncRequest(LFUN_BUFFER_IMPORT, arg); + } + else { + //FIXME: do we have to explicitly check whether it's a lyx file? + LYXERR(Debug::FILES, + "No formats found, trying to open it as a lyx file"); + cmd = FuncRequest(LFUN_FILE_OPEN, file); } + + // Asynchronously post the event. DropEvent usually comes + // from the BufferView. But reloading a file might close + // the BufferView from within its own event handler. + guiApp->dispatchDelayed(cmd); + event->accept(); } } @@ -626,8 +748,15 @@ void GuiView::message(docstring const & str) { if (ForkedProcess::iAmAChild()) return; + + // call is moved to GUI-thread by GuiProgress + d.progress_->appendMessage(toqstr(str)); +} + - statusBar()->showMessage(toqstr(str)); +void GuiView::updateMessage(QString const & str) +{ + statusBar()->showMessage(str); d.statusbar_timer_.stop(); d.statusbar_timer_.start(3000); } @@ -653,16 +782,20 @@ void GuiView::bigSizedIcons() void GuiView::clearMessage() { - if (!hasFocus()) - return; - statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage())); + // FIXME: This code was introduced in r19643 to fix bug #4123. However, + // the hasFocus function mostly returns false, even if the focus is on + // a workarea in this view. + //if (!hasFocus()) + // return; + showMessage(); d.statusbar_timer_.stop(); } void GuiView::updateWindowTitle(GuiWorkArea * wa) { - if (wa != d.current_work_area_) + if (wa != d.current_work_area_ + || wa->bufferView().buffer().isInternal()) return; setWindowTitle(qt_("LyX: ") + wa->windowTitle()); setWindowIconText(wa->windowIconText()); @@ -707,6 +840,7 @@ void GuiView::on_lastWorkAreaRemoved() updateDialogs(); resetWindowTitleAndIconText(); + updateStatusBar(); if (lyxrc.open_buffers_in_tabs) // Nothing more to do, the window should stay open. @@ -732,7 +866,21 @@ void GuiView::updateStatusBar() if (d.statusbar_timer_.isActive()) return; - statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage())); + showMessage(); +} + + +void GuiView::showMessage() +{ + QString msg = toqstr(theGuiApp()->viewStatusMessage()); + if (msg.isEmpty()) { + BufferView const * bv = currentBufferView(); + if (bv) + msg = toqstr(bv->cursor().currentState()); + else + msg = qt_("Welcome to LyX!"); + } + statusBar()->showMessage(msg); } @@ -800,25 +948,7 @@ bool GuiView::event(QEvent * e) } } #endif - - if (d.current_work_area_) - // Nothing special to do. - return QMainWindow::event(e); - - QKeyEvent * ke = static_cast(e); - // Let Qt handle menu access and the Tab keys to navigate keys to navigate - // between controls. - if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab - || ke->key() == Qt::Key_Backtab) - return QMainWindow::event(e); - - // Allow processing of shortcuts that are allowed even when no Buffer - // is viewed. - KeySymbol sym; - setKeySymbol(&sym, ke); - theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers())); - e->accept(); - return true; + return QMainWindow::event(e); } default: @@ -1038,7 +1168,7 @@ void GuiView::updateToolbars() void GuiView::setBuffer(Buffer * newBuffer) { - LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << std::endl); + LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << endl); LASSERT(newBuffer, return); setBusy(true); @@ -1097,7 +1227,7 @@ void GuiView::errors(string const & error_type, bool from_master) } -void GuiView::updateTocItem(std::string const & type, DocIterator const & dit) +void GuiView::updateTocItem(string const & type, DocIterator const & dit) { d.toc_models_.updateItem(toqstr(type), dit); } @@ -1155,12 +1285,43 @@ BufferView const * GuiView::currentBufferView() const } +#if (QT_VERSION >= 0x040400) +static docstring saveAndDestroyBuffer(Buffer * buffer, FileName const & fname) +{ + 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; + return failed + ? _("Automatic save failed!") + : _("Automatic save done."); +} +#endif + + void GuiView::autoSave() { LYXERR(Debug::INFO, "Running autoSave()"); - if (documentBufferView()) - documentBufferView()->buffer().autoSave(); + Buffer * buffer = documentBufferView() + ? &documentBufferView()->buffer() : 0; + if (!buffer) + return; + +#if (QT_VERSION >= 0x040400) + QFuture f = QtConcurrent::run(saveAndDestroyBuffer, buffer->clone(), + buffer->getAutosaveFilename()); + d.autosave_watcher_.setFuture(f); +#else + buffer->autoSave(); +#endif } @@ -1202,6 +1363,25 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_BUFFER_IMPORT: break; + case LFUN_MASTER_BUFFER_UPDATE: + case LFUN_MASTER_BUFFER_VIEW: + enable = doc_buffer && doc_buffer->parent() != 0 + && !d.preview_watcher_.isRunning(); + break; + + case LFUN_BUFFER_UPDATE: + case LFUN_BUFFER_VIEW: { + if (!doc_buffer || d.preview_watcher_.isRunning()) { + enable = false; + break; + } + string format = to_utf8(cmd.argument()); + if (cmd.argument().empty()) + format = doc_buffer->getDefaultOutputFormat(); + enable = doc_buffer->isExportableFormat(format); + break; + } + case LFUN_BUFFER_RELOAD: enable = doc_buffer && !doc_buffer->isUnnamed() && doc_buffer->fileName().exists() @@ -1266,6 +1446,10 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setOnOff(t->isVisible()); break; + case LFUN_DROP_LAYOUTS_CHOICE: + enable = buf; + break; + case LFUN_UI_TOGGLE: flag.setOnOff(isFullScreen()); break; @@ -1286,7 +1470,9 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) enable = name == "aboutlyx" || name == "file" //FIXME: should be removed. || name == "prefs" - || name == "texinfo"; + || name == "texinfo" + || name == "progress" + || name == "compare"; else if (name == "print") enable = doc_buffer->isExportable("dvi") && lyxrc.print_command != "none"; @@ -1323,25 +1509,6 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) // Nothing to check. break; - case LFUN_INSET_APPLY: { - string const name = cmd.getArg(0); - Inset * inset = getOpenInset(name); - if (inset) { - FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument()); - FuncStatus fs; - if (!inset->getStatus(currentBufferView()->cursor(), fr, fs)) { - // Every inset is supposed to handle this - LASSERT(false, break); - } - flag |= fs; - } else { - FuncRequest fr(LFUN_INSET_INSERT, cmd.argument()); - flag |= lyx::getStatus(fr); - } - enable = flag.enabled(); - break; - } - case LFUN_COMPLETION_INLINE: if (!d.current_work_area_ || !d.current_work_area_->completer().inlinePossible( @@ -1418,6 +1585,9 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) 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(); + break; case LFUN_VC_COMMAND: { if (cmd.argument().empty()) enable = false; @@ -1734,7 +1904,7 @@ void GuiView::newDocument(string const & filename, bool from_template) Buffer * b; if (filename.empty()) - b = newUnnamedFile(templatefile, initpath); + b = newUnnamedFile(initpath, to_utf8(_("newfile")), templatefile); else b = newFile(filename, templatefile, true); @@ -1974,6 +2144,7 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa) bool GuiView::closeBuffer() { GuiWorkArea * wa = currentMainWorkArea(); + setCurrentWorkArea(wa); Buffer & buf = wa->bufferView().buffer(); return wa && closeWorkArea(wa, !buf.parent()); } @@ -2041,14 +2212,31 @@ bool GuiView::closeWorkAreaAll() bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer) { + if (!wa) + return false; + Buffer & buf = wa->bufferView().buffer(); + if (close_buffer) + return closeBuffer(buf); + else { + if (!inMultiTabs(wa)) + if (!saveBufferIfNeeded(buf, true)) + return false; + removeWorkArea(wa); + return true; + } +} + + +bool GuiView::closeBuffer(Buffer & buf) +{ // If we are in a close_event all children will be closed in some time, // 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. - if (close_buffer && !closing_) { - vector clist = buf.getChildren(); + if (!closing_) { + vector clist = buf.getChildren(false); for (vector::const_iterator it = clist.begin(); it != clist.end(); ++it) { // If a child is dirty, do not close @@ -2069,18 +2257,8 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer) for (size_t i = 0; i < theSession().bookmarks().size(); ++i) theLyXFunc().gotoBookmark(i+1, false, false); - // if we are only hiding the buffer and there are multiple views - // of the buffer, then we do not need to ensure a clean buffer. - bool const allow_dirty = inMultiTabs(wa) && !close_buffer; - - if (allow_dirty || saveBufferIfNeeded(buf, !close_buffer)) { - // save in sessions if requested - // do not save childs if their master - // is opened as well - if (!close_buffer) - removeWorkArea(wa); - else - theBufferList().release(&buf); + if (saveBufferIfNeeded(buf, false)) { + theBufferList().release(&buf); return true; } return false; @@ -2155,7 +2333,7 @@ bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding) buf.removeAutosaveFile(); if (hiding) // revert all changes - buf.loadLyXFile(buf.fileName()); + buf.reload(); buf.markClean(); break; case 2: @@ -2252,27 +2430,34 @@ static bool ensureBufferClean(Buffer * buffer) void GuiView::reloadBuffer() { Buffer * buf = &documentBufferView()->buffer(); - FileName filename = buf->fileName(); - // The user has already confirmed that the changes, if any, should - // be discarded. So we just release the Buffer and don't call closeBuffer(); - theBufferList().release(buf); - buf = loadDocument(filename); - docstring const disp_fn = makeDisplayPath(filename.absFilename()); - docstring str; - if (buf) { - buf->updateLabels(); - setBuffer(buf); - buf->errors("Parse"); - str = bformat(_("Document %1$s reloaded."), disp_fn); - } else { - str = bformat(_("Could not reload document %1$s"), disp_fn); + buf->reload(); +} + + +void GuiView::checkExternallyModifiedBuffers() +{ + BufferList::iterator bit = theBufferList().begin(); + BufferList::iterator const bend = theBufferList().end(); + for (; bit != bend; ++bit) { + if ((*bit)->fileName().exists() + && (*bit)->isExternallyModified(Buffer::checksum_method)) { + docstring text = bformat(_("Document \n%1$s\n has been externally modified." + " Reload now? Any local changes will be lost."), + from_utf8((*bit)->absFileName())); + int const ret = Alert::prompt(_("Reload externally changed document?"), + text, 0, 1, _("&Reload"), _("&Cancel")); + if (!ret) + (*bit)->reload(); + } } - message(str); } +//FIXME use a DispatchResult object to transmit messages void GuiView::dispatchVC(FuncRequest const & cmd) { + // message for statusbar + string msg; Buffer * buffer = documentBufferView() ? &(documentBufferView()->buffer()) : 0; @@ -2290,8 +2475,9 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (!buffer || !ensureBufferClean(buffer)) break; if (buffer->lyxvc().inUse() && !buffer->isReadonly()) { - message(from_utf8(buffer->lyxvc().checkIn())); - reloadBuffer(); + msg = buffer->lyxvc().checkIn(); + if (!msg.empty()) + reloadBuffer(); } break; @@ -2299,7 +2485,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd) if (!buffer || !ensureBufferClean(buffer)) break; if (buffer->lyxvc().inUse()) { - message(from_utf8(buffer->lyxvc().checkOut())); + msg = buffer->lyxvc().checkOut(); reloadBuffer(); } break; @@ -2314,7 +2500,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd) frontend::Alert::error(_("Revision control error."), _("Error when setting the locking property.")); } else { - message(from_utf8(res)); + msg = res; reloadBuffer(); } } @@ -2332,6 +2518,14 @@ void GuiView::dispatchVC(FuncRequest const & cmd) reloadBuffer(); break; + case LFUN_VC_REPO_UPDATE: + LASSERT(buffer, return); + if (ensureBufferClean(buffer)) { + msg = buffer->lyxvc().repoUpdate(); + checkExternallyModifiedBuffers(); + } + break; + case LFUN_VC_COMMAND: { string flag = cmd.getArg(0); if (buffer && contains(flag, 'R') && !ensureBufferClean(buffer)) @@ -2376,6 +2570,9 @@ void GuiView::dispatchVC(FuncRequest const & cmd) default: break; } + + if (!msg.empty()) + message(from_utf8(msg)); } @@ -2413,9 +2610,18 @@ bool GuiView::goToFileRow(string const & argument) { string file_name; int row; - istringstream is(argument); - is >> file_name >> row; - file_name = os::internal_path(file_name); + size_t i = argument.find_last_of(' '); + if (i != string::npos) { + file_name = os::internal_path(trim(argument.substr(0, i))); + istringstream is(argument.substr(i + 1)); + is >> row; + if (is.fail()) + i = string::npos; + } + if (i == string::npos) { + LYXERR0("Wrong argument: " << argument); + return false; + } Buffer * buf = 0; string const abstmp = package().temp_dir().absFilename(); string const realtmp = package().temp_dir().realPath(); @@ -2456,24 +2662,54 @@ bool GuiView::goToFileRow(string const & argument) } -bool GuiView::dispatch(FuncRequest const & cmd) +#if (QT_VERSION >= 0x040400) +static docstring exportAndDestroy(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; + 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) +{ + bool const update_unincluded = + buffer->params().maintain_unincluded_children + && !buffer->params().getIncludedChildren().empty(); + bool const success = buffer->preview(format, update_unincluded); + delete buffer; + return success + ? bformat(_("Successful preview of format: %1$s"), from_utf8(format)) + : bformat(_("Error previewing format: %1$s"), from_utf8(format)); +} +#endif + + +void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) { BufferView * bv = currentBufferView(); // By default we won't need any update. - if (bv) - bv->cursor().updateFlags(Update::None); + dr.update(Update::None); + // assume cmd will be dispatched + dr.dispatched(true); Buffer * doc_buffer = documentBufferView() ? &(documentBufferView()->buffer()) : 0; - bool dispatched = true; - 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); - return true; + return; } + string const argument = to_utf8(cmd.argument()); + switch(cmd.action) { case LFUN_BUFFER_CHILD_OPEN: openChildDocument(to_utf8(cmd.argument())); @@ -2483,14 +2719,105 @@ bool GuiView::dispatch(FuncRequest const & cmd) importDocument(to_utf8(cmd.argument())); break; + case LFUN_BUFFER_EXPORT: { + if (!doc_buffer) + break; + if (cmd.argument() == "custom") { + dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), + dr); + break; + } + if (doc_buffer->doExport(argument, false)) { + dr.setError(true); + dr.setMessage(bformat(_("Error exporting to format: %1$s."), + cmd.argument())); + } + break; + } + + case LFUN_BUFFER_UPDATE: { + if (!doc_buffer) + break; + string format = argument; + if (argument.empty()) + format = doc_buffer->getDefaultOutputFormat(); +#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) + d.progress_->clearMessages(); + message(_("Exporting ...")); + QFuture f = QtConcurrent::run(exportAndDestroy, + doc_buffer->clone(), format); + d.setPreviewFuture(f); +#else + bool const update_unincluded = + doc_buffer->params().maintain_unincluded_children + && !doc_buffer->params().getIncludedChildren().empty(); + doc_buffer->doExport(format, true, update_unincluded); +#endif + break; + } + case LFUN_BUFFER_VIEW: { + if (!doc_buffer) + break; + string format = argument; + if (argument.empty()) + format = doc_buffer->getDefaultOutputFormat(); +#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) + d.progress_->clearMessages(); + message(_("Previewing ...")); + QFuture f = QtConcurrent::run(previewAndDestroy, + doc_buffer->clone(), format); + d.setPreviewFuture(f); +#else + bool const update_unincluded = + doc_buffer->params().maintain_unincluded_children + && !doc_buffer->params().getIncludedChildren().empty(); + doc_buffer->preview(format, update_unincluded); +#endif + break; + } + case LFUN_MASTER_BUFFER_UPDATE: { + if (!doc_buffer) + break; + string format = argument; + Buffer const * master = doc_buffer->masterBuffer(); + if (argument.empty()) + format = master->getDefaultOutputFormat(); +#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) + QFuture f = QtConcurrent::run(exportAndDestroy, + master->clone(), format); + d.setPreviewFuture(f); +#else + bool const update_unincluded = + master->params().maintain_unincluded_children + && !master->params().getIncludedChildren().empty(); + master->doExport(format, true); +#endif + break; + } + case LFUN_MASTER_BUFFER_VIEW: { + string format = argument; + Buffer const * master = doc_buffer->masterBuffer(); + if (argument.empty()) + format = master->getDefaultOutputFormat(); +#if EXPORT_in_THREAD && (QT_VERSION >= 0x040400) + QFuture f = QtConcurrent::run(previewAndDestroy, + master->clone(), format); + d.setPreviewFuture(f); +#else + master->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 - bv->cursor().message(_("Document not loaded")); + else { + dr.setError(true); + dr.setMessage(_("Document not loaded")); + } } break; @@ -2541,8 +2868,10 @@ bool GuiView::dispatch(FuncRequest const & cmd) int const ret = Alert::prompt(_("Revert to saved document?"), text, 1, 1, _("&Revert"), _("&Cancel")); - if (ret == 0) + if (ret == 0) { + doc_buffer->markClean(); reloadBuffer(); + } break; } @@ -2591,10 +2920,15 @@ bool GuiView::dispatch(FuncRequest const & cmd) case LFUN_DIALOG_UPDATE: { string const name = to_utf8(cmd.argument()); - // Can only update a dialog connected to an existing inset - Inset * inset = getOpenInset(name); - if (inset) { + if (currentBufferView()) { + Inset * inset = currentBufferView()->editedInset(name); + // Can only update a dialog connected to an existing inset + if (!inset) + break; + // FIXME: get rid of this indirection; GuiView ask the inset + // if he is kind enough to update itself... FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument()); + //FIXME: pass DispatchResult here? inset->dispatch(currentBufferView()->cursor(), fr); } else if (name == "paragraph") { lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE)); @@ -2606,9 +2940,9 @@ bool GuiView::dispatch(FuncRequest const & cmd) case LFUN_DIALOG_TOGGLE: { if (isDialogVisible(cmd.getArg(0))) - dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument())); + dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()), dr); else - dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument())); + dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()), dr); break; } @@ -2664,28 +2998,6 @@ bool GuiView::dispatch(FuncRequest const & cmd) message(cmd.argument()); break; - case LFUN_INSET_APPLY: { - string const name = cmd.getArg(0); - Inset * inset = getOpenInset(name); - if (inset) { - // put cursor in front of inset. - if (!currentBufferView()->setCursorFromInset(inset)) { - LASSERT(false, break); - } - BufferView * bv = currentBufferView(); - // useful if we are called from a dialog. - bv->cursor().beginUndoGroup(); - bv->cursor().recordUndo(); - FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument()); - inset->dispatch(bv->cursor(), fr); - bv->cursor().endUndoGroup(); - } else { - FuncRequest fr(LFUN_INSET_INSERT, cmd.argument()); - lyx::dispatch(fr); - } - break; - } - case LFUN_UI_TOGGLE: lfunUiToggle(cmd); // Make sure the keyboard focus stays in the work area. @@ -2770,6 +3082,7 @@ bool GuiView::dispatch(FuncRequest const & cmd) case LFUN_VC_REGISTER: case LFUN_VC_CHECK_IN: case LFUN_VC_CHECK_OUT: + case LFUN_VC_REPO_UPDATE: case LFUN_VC_LOCKING_TOGGLE: case LFUN_VC_REVERT: case LFUN_VC_UNDO_LAST: @@ -2782,7 +3095,7 @@ bool GuiView::dispatch(FuncRequest const & cmd) break; default: - dispatched = false; + dr.dispatched(false); break; } @@ -2794,7 +3107,7 @@ bool GuiView::dispatch(FuncRequest const & cmd) statusBar()->hide(); } - return dispatched; + return; } @@ -2923,13 +3236,13 @@ namespace { char const * const dialognames[] = { "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character", -"citation", "document", "errorlist", "ert", "external", "file", "findreplace", -"findreplaceadv", "float", "graphics", "href", "include", "index", -"index_print", "info", "listings", "label", "log", "mathdelimiter", +"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" }; +"toc", "view-source", "vspace", "wrap", "progress"}; char const * const * const end_dialognames = dialognames + (sizeof(dialognames) / sizeof(char *)); @@ -2995,17 +3308,27 @@ Dialog * GuiView::findOrBuild(string const & name, bool hide_it) void GuiView::showDialog(string const & name, string const & data, Inset * inset) +{ + triggerShowDialog(toqstr(name), toqstr(data), inset); +} + + +void GuiView::doShowDialog(QString const & qname, QString const & qdata, + Inset * inset) { if (d.in_show_) return; + const string name = fromqstr(qname); + const string data = fromqstr(qdata); + d.in_show_ = true; try { Dialog * dialog = findOrBuild(name, false); if (dialog) { dialog->showData(data); - if (inset) - d.open_insets_[name] = inset; + if (inset && currentBufferView()) + currentBufferView()->editInset(name, inset); } } catch (ExceptionMessage const & ex) { @@ -3031,13 +3354,15 @@ void GuiView::hideDialog(string const & name, Inset * inset) if (it == d.dialogs_.end()) return; - if (inset && inset != getOpenInset(name)) + if (inset && currentBufferView() + && inset != currentBufferView()->editedInset(name)) return; Dialog * const dialog = it->second.get(); if (dialog->isVisibleView()) dialog->hideView(); - d.open_insets_[name] = 0; + if (currentBufferView()) + currentBufferView()->editInset(name, 0); } @@ -3045,19 +3370,8 @@ void GuiView::disconnectDialog(string const & name) { if (!isValidName(name)) return; - - if (d.open_insets_.find(name) != d.open_insets_.end()) - d.open_insets_[name] = 0; -} - - -Inset * GuiView::getOpenInset(string const & name) const -{ - if (!isValidName(name)) - return 0; - - map::const_iterator it = d.open_insets_.find(name); - return it == d.open_insets_.end() ? 0 : it->second; + if (currentBufferView()) + currentBufferView()->editInset(name, 0); } @@ -3078,8 +3392,12 @@ void GuiView::updateDialogs() for(; it != end; ++it) { Dialog * dialog = it->second.get(); - if (dialog && dialog->isVisibleView()) - dialog->checkStatus(); + if (dialog) { + if (dialog->isBufferDependent() && !documentBufferView()) + hideDialog(fromqstr(dialog->name()), 0); + else if (dialog->isVisibleView()) + dialog->checkStatus(); + } } updateToolbars(); updateLayoutList(); @@ -3095,6 +3413,7 @@ Dialog * createGuiBranch(GuiView & lv); Dialog * createGuiChanges(GuiView & lv); Dialog * createGuiCharacter(GuiView & lv); Dialog * createGuiCitation(GuiView & lv); +Dialog * createGuiCompare(GuiView & lv); Dialog * createGuiDelimiter(GuiView & lv); Dialog * createGuiDocument(GuiView & lv); Dialog * createGuiErrorList(GuiView & lv); @@ -3135,6 +3454,8 @@ Dialog * createGuiHyperlink(GuiView & lv); Dialog * createGuiVSpace(GuiView & lv); Dialog * createGuiViewSource(GuiView & lv); Dialog * createGuiWrap(GuiView & lv); +Dialog * createGuiProgressView(GuiView & lv); + Dialog * GuiView::build(string const & name) @@ -3157,6 +3478,8 @@ Dialog * GuiView::build(string const & name) return createGuiCharacter(*this); if (name == "citation") return createGuiCitation(*this); + if (name == "compare") + return createGuiCompare(*this); if (name == "document") return createGuiDocument(*this); if (name == "errorlist") @@ -3237,6 +3560,8 @@ Dialog * GuiView::build(string const & name) return createGuiVSpace(*this); if (name == "wrap") return createGuiWrap(*this); + if (name == "progress") + return createGuiProgressView(*this); return 0; }