]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
Let the tag affect other sides too
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index de7d60e125ffda8b8f19cb37ee820b54469a822d..93099faaf7d5420424ac05cf614c589f32d9cfd9 100644 (file)
 #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"
@@ -77,6 +77,7 @@
 #include "support/Systemcall.h"
 #include "support/Timeout.h"
 #include "support/ProgressInterface.h"
+#include "GuiProgress.h"
 
 #include <QAction>
 #include <QApplication>
@@ -98,6 +99,7 @@
 #include <QSplitter>
 #include <QStackedWidget>
 #include <QStatusBar>
+#include <QTime>
 #include <QTimer>
 #include <QToolBar>
 #include <QUrl>
 
 #define EXPORT_in_THREAD 1
 
+
 // QtConcurrent was introduced in Qt 4.4
 #if (QT_VERSION >= 0x040400)
 #include <QFuture>
@@ -151,6 +154,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 *)
@@ -161,6 +165,18 @@ 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_;
 };
@@ -192,6 +208,7 @@ struct GuiView::GuiViewPrivate
                stack_widget_->addWidget(bg_widget_);
                stack_widget_->addWidget(splitter_);
                setBackground();
+               progress_ = new GuiProgress(gv);
        }
 
        ~GuiViewPrivate()
@@ -199,6 +216,7 @@ struct GuiView::GuiViewPrivate
                delete splitter_;
                delete bg_widget_;
                delete stack_widget_;
+               delete progress_;
        }
 
        QMenu * toolBarPopup(GuiView * parent)
@@ -243,6 +261,7 @@ struct GuiView::GuiViewPrivate
        {
                stack_widget_->setCurrentWidget(bg_widget_);
                bg_widget_->setUpdatesEnabled(true);
+               bg_widget_->setFocus();
        }
 
        TabWorkArea * tabWorkArea(int i)
@@ -266,14 +285,17 @@ struct GuiView::GuiViewPrivate
                return tabWorkArea(0);
        }
 
+#if (QT_VERSION >= 0x040400)
        void setPreviewFuture(QFuture<docstring> const & f)
        {
-               if (preview_watcher_.isRunning())
-                       preview_watcher_.waitForFinished();
+               if (preview_watcher_.isRunning()) {
+                       // we prefer to cancel this preview in order to keep a snappy
+                       // interface.
+                       return;
+               }
                preview_watcher_.setFuture(f);
-               connect(&preview_watcher_, SIGNAL(finished()), gv_,
-                       SLOT(threadFinished()));
        }
+#endif
 
 public:
        GuiView * gv_;
@@ -284,6 +306,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
@@ -315,6 +338,9 @@ public:
        ///
        QFutureWatcher<docstring> autosave_watcher_;
        QFutureWatcher<docstring> preview_watcher_;
+#else
+       struct DummyWatcher { bool isRunning(){return false;} }; 
+       DummyWatcher preview_watcher_;
 #endif
 };
 
@@ -358,6 +384,17 @@ GuiView::GuiView(int id)
        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.
@@ -376,11 +413,6 @@ GuiView::GuiView(int id)
        // clear session data if any.
        QSettings settings;
        settings.remove("views");
-
-#if (QT_VERSION >= 0x040400)
-       connect(&d.autosave_watcher_, SIGNAL(finished()), this,
-               SLOT(threadFinished()));
-#endif
 }
 
 
@@ -451,6 +483,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();
@@ -502,7 +536,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);
 
@@ -515,7 +549,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);
                }
@@ -523,7 +558,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);
                }
@@ -531,7 +567,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);
                }
@@ -551,11 +588,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();
 }
 
 
@@ -680,7 +728,7 @@ void GuiView::dropEvent(QDropEvent * event)
                        cmd = FuncRequest(LFUN_FILE_OPEN, file);
                }
 
-               // Asynchronously post the event. DropEvent usually come
+               // 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);
@@ -693,8 +741,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);
 }
@@ -720,8 +775,11 @@ void GuiView::bigSizedIcons()
 
 void GuiView::clearMessage()
 {
-       if (!hasFocus())
-               return;
+       // 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();
 }
@@ -729,7 +787,8 @@ void GuiView::clearMessage()
 
 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());
@@ -774,6 +833,7 @@ void GuiView::on_lastWorkAreaRemoved()
        updateDialogs();
 
        resetWindowTitleAndIconText();
+       updateStatusBar();
 
        if (lyxrc.open_buffers_in_tabs)
                // Nothing more to do, the window should stay open.
@@ -881,25 +941,7 @@ bool GuiView::event(QEvent * e)
                        }
                }
 #endif
-
-               if (d.current_work_area_)
-                       // Nothing special to do.
-                       return QMainWindow::event(e);
-
-               QKeyEvent * ke = static_cast<QKeyEvent*>(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);
-               guiApp->processKeySym(sym, q_key_state(ke->modifiers()));
-               e->accept();
-               return true;
+               return QMainWindow::event(e);
        }
 
        default:
@@ -1236,6 +1278,7 @@ BufferView const * GuiView::currentBufferView() const
 }
 
 
+#if (QT_VERSION >= 0x040400)
 static docstring saveAndDestroyBuffer(Buffer * buffer, FileName const & fname)
 {
        bool failed = true;
@@ -1253,6 +1296,7 @@ static docstring saveAndDestroyBuffer(Buffer * buffer, FileName const & fname)
                ? _("Automatic save failed!")
                : _("Automatic save done.");
 }
+#endif
 
 
 void GuiView::autoSave()
@@ -2093,6 +2137,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());
 }
@@ -2281,7 +2326,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:
@@ -2378,34 +2423,7 @@ static bool ensureBufferClean(Buffer * buffer)
 void GuiView::reloadBuffer()
 {
        Buffer * buf = &documentBufferView()->buffer();
-       reloadBuffer(buf);
-}
-
-
-void GuiView::reloadBuffer(Buffer * buf)
-{
-       FileName filename = buf->fileName();
-       Buffer const * master = buf->masterBuffer();
-       bool const is_child = master != buf;
-       // 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) {
-               // re-allocate master if necessary
-               if (is_child && theBufferList().isLoaded(master)
-                   && buf->masterBuffer() != master)
-                       buf->setParent(master);
-               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);
-       }
-       message(str);
+       buf->reload();
 }
 
 
@@ -2414,14 +2432,15 @@ void GuiView::checkExternallyModifiedBuffers()
        BufferList::iterator bit = theBufferList().begin();
        BufferList::iterator const bend = theBufferList().end();
        for (; bit != bend; ++bit) {
-               if ((*bit)->isExternallyModified(Buffer::checksum_method)) {
+               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)
-                               reloadBuffer(*bit);
+                               (*bit)->reload();
                }
        }
 }
@@ -2429,6 +2448,8 @@ void GuiView::checkExternallyModifiedBuffers()
 
 void GuiView::dispatchVC(FuncRequest const & cmd)
 {
+       // message for statusbar
+       string msg;
        Buffer * buffer = documentBufferView()
                ? &(documentBufferView()->buffer()) : 0;
 
@@ -2446,8 +2467,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;
 
@@ -2455,7 +2477,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;
@@ -2470,7 +2492,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();
                        }
                }
@@ -2491,8 +2513,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd)
        case LFUN_VC_REPO_UPDATE:
                LASSERT(buffer, return);
                if (ensureBufferClean(buffer)) {
-                       string res = buffer->lyxvc().repoUpdate();
-                       message(from_utf8(res));
+                       msg = buffer->lyxvc().repoUpdate();
                        checkExternallyModifiedBuffers();
                }
                break;
@@ -2541,6 +2562,9 @@ void GuiView::dispatchVC(FuncRequest const & cmd)
        default:
                break;
        }
+
+       if (!msg.empty())
+               message(from_utf8(msg));
 }
 
 
@@ -2578,9 +2602,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();
@@ -2621,9 +2654,13 @@ bool GuiView::goToFileRow(string const & argument)
 }
 
 
+#if (QT_VERSION >= 0x040400)
 static docstring exportAndDestroy(Buffer * buffer, string const & format)
 {
-       bool const success = buffer->doExport(format, true);
+       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))
@@ -2633,12 +2670,16 @@ static docstring exportAndDestroy(Buffer * buffer, string const & format)
 
 static docstring previewAndDestroy(Buffer * buffer, string const & format)
 {
-       bool const success = buffer->preview(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
 
 
 bool GuiView::dispatch(FuncRequest const & cmd)
@@ -2691,11 +2732,16 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        if (argument.empty())
                                format = doc_buffer->getDefaultOutputFormat();
 #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
+                       d.progress_->clearMessages();
+                       message(_("Exporting ..."));
                        QFuture<docstring> f = QtConcurrent::run(exportAndDestroy,
                                doc_buffer->clone(), format);
                        d.setPreviewFuture(f);
 #else
-                       doc_buffer->doExport(format, true);
+                       bool const update_unincluded =
+                               doc_buffer->params().maintain_unincluded_children
+                               && !doc_buffer->params().getIncludedChildren().empty();
+                       doc_buffer->doExport(format, true, update_unincluded);
 #endif
                        break;
                }
@@ -2706,11 +2752,16 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        if (argument.empty())
                                format = doc_buffer->getDefaultOutputFormat();
 #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
+                       d.progress_->clearMessages();
+                       message(_("Previewing ..."));
                        QFuture<docstring> f = QtConcurrent::run(previewAndDestroy,
                                doc_buffer->clone(), format);
                        d.setPreviewFuture(f);
 #else
-                       doc_buffer->preview(format);
+                       bool const update_unincluded =
+                               doc_buffer->params().maintain_unincluded_children
+                               && !doc_buffer->params().getIncludedChildren().empty();
+                       doc_buffer->preview(format, update_unincluded);
 #endif
                        break;
                }
@@ -2726,6 +2777,9 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                                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;
@@ -3175,7 +3229,7 @@ char const * const dialognames[] = {
 "mathmatrix", "mathspace", "nomenclature", "nomencl_print", "note",
 "paragraph", "phantom", "prefs", "print", "ref", "sendto", "space",
 "spellchecker", "symbols", "tabular", "tabularcreate", "thesaurus", "texinfo",
-"toc", "view-source", "vspace", "wrap", "progress" };
+"toc", "view-source", "vspace", "wrap", "progress"};
 
 char const * const * const end_dialognames =
        dialognames + (sizeof(dialognames) / sizeof(char *));
@@ -3241,10 +3295,20 @@ 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);
@@ -3315,8 +3379,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();
@@ -3373,7 +3441,9 @@ Dialog * createGuiHyperlink(GuiView & lv);
 Dialog * createGuiVSpace(GuiView & lv);
 Dialog * createGuiViewSource(GuiView & lv);
 Dialog * createGuiWrap(GuiView & lv);
-Dialog * createGuiProgress(GuiView & lv);
+Dialog * createGuiProgressView(GuiView & lv);
+
+
 
 Dialog * GuiView::build(string const & name)
 {
@@ -3477,8 +3547,8 @@ Dialog * GuiView::build(string const & name)
                return createGuiVSpace(*this);
        if (name == "wrap")
                return createGuiWrap(*this);
-       if (name == "progress") 
-               return createGuiProgress(*this); 
+       if (name == "progress")
+               return createGuiProgressView(*this);
 
        return 0;
 }