]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
do what the FIXME suggested
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index e858b95ca92c278d318fac9260250e12b8555812..45a252f592373c8deab9265d0bd1d514b77a1e6e 100644 (file)
@@ -84,6 +84,7 @@
 #include <QTimer>
 #include <QToolBar>
 #include <QUrl>
+#include <QScrollBar>
 
 #include <boost/assert.hpp>
 #include <boost/bind.hpp>
@@ -99,9 +100,6 @@ using namespace std;
 using namespace lyx::support;
 
 namespace lyx {
-
-extern bool quitting;
-
 namespace frontend {
 
 namespace {
@@ -147,8 +145,8 @@ typedef boost::shared_ptr<Dialog> DialogPtr;
 struct GuiView::GuiViewPrivate
 {
        GuiViewPrivate()
-               : current_work_area_(0), layout_(0),
-               quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false)
+               : current_work_area_(0), layout_(0), autosave_timeout_(5000),
+               in_show_(false)
        {
                // hardcode here the platform specific icon size
                smallIconSize = 14;     // scaling problems
@@ -226,17 +224,14 @@ struct GuiView::GuiViewPrivate
                        // The first TabWorkArea is always the first one, if any.
                        return tabWorkArea(0);
 
-               TabWorkArea * tab_widget = 0;
                for (int i = 0; i != splitter_->count(); ++i) {
-                       QWidget * w = splitter_->widget(i);
-                       if (!w->hasFocus())
-                               continue;
-                       tab_widget = dynamic_cast<TabWorkArea *>(w);
-                       if (tab_widget)
-                               break;
+                       TabWorkArea * twa = tabWorkArea(i);
+                       if (current_work_area_ == twa->currentWorkArea())
+                               return twa;
                }
 
-               return tab_widget;
+               // None has the focus so we just take the first one.
+               return tabWorkArea(0);
        }
 
 public:
@@ -268,8 +263,6 @@ public:
        unsigned int bigIconSize;
        ///
        QTimer statusbar_timer_;
-       /// are we quitting by the menu?
-       bool quitting_by_menu_;
        /// auto-saving of buffers
        Timeout autosave_timeout_;
        /// flag against a race condition due to multiclicks, see bug #1119
@@ -297,9 +290,9 @@ GuiView::GuiView(int id)
        connect(&d.statusbar_timer_, SIGNAL(timeout()),
                this, SLOT(clearMessage()));
 
-       // Qt bug? signal lastWindowClosed does not work
-       setAttribute(Qt::WA_QuitOnClose, false);
+       // We don't want to keep the window in memory if it is closed.
        setAttribute(Qt::WA_DeleteOnClose, true);
+
 #ifndef Q_WS_MACX
        // assign an icon to main form. We do not do it under Qt/Mac,
        // since the icon is provided in the application bundle.
@@ -341,20 +334,6 @@ GuiView::~GuiView()
 }
 
 
-void GuiView::close()
-{
-       d.quitting_by_menu_ = true;
-       d.current_work_area_ = 0;
-       for (int i = 0; i != d.splitter_->count(); ++i) {
-               TabWorkArea * twa = d.tabWorkArea(i);
-               if (twa)
-                       twa->closeAll();
-       }
-       QMainWindow::close();
-       d.quitting_by_menu_ = false;
-}
-
-
 void GuiView::setFocus()
 {
        if (d.current_work_area_)
@@ -386,10 +365,37 @@ void GuiView::showEvent(QShowEvent * e)
 
 void GuiView::closeEvent(QCloseEvent * close_event)
 {
-       // we may have been called through the close window button
-       // which bypasses the LFUN machinery.
-       if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
-               if (!quitWriteAll()) {
+       while (Buffer * b = buffer()) {
+               if (b->parent()) {
+                       // This is a child document, just close the tab after saving
+                       // but keep the file loaded.
+                       if (!saveBuffer(*b)) {
+                               close_event->ignore();
+                               return;
+                       }
+                       removeWorkArea(d.current_work_area_);
+                       continue;
+               }
+
+               std::vector<int> const & ids = guiApp->viewIds();
+               for (size_type i = 0; i != ids.size(); ++i) {
+                       if (id_ == ids[i])
+                               continue;
+                       if (guiApp->view(ids[i]).workArea(*b)) {
+                               // FIXME 1: should we put an alert box here that the buffer
+                               // is viewed elsewhere?
+                               // FIXME 2: should we try to save this buffer in any case?
+                               //saveBuffer(b);
+
+                               // This buffer is also opened in another view, so
+                               // but close the associated work area nevertheless.
+                               removeWorkArea(d.current_work_area_);
+                               // but don't close it.
+                               b = 0;
+                               break;
+                       }
+               }
+               if (b && !closeBuffer(*b)) {
                        close_event->ignore();
                        return;
                }
@@ -397,10 +403,19 @@ void GuiView::closeEvent(QCloseEvent * close_event)
 
        // Make sure that no LFUN use this close to be closed View.
        theLyXFunc().setLyXView(0);
+
+       // Save toolbars configuration
+       if (isFullScreen()) {
+        d.toolbars_->toggleFullScreen(!isFullScreen());
+        updateToolbars();
+       }
+
        // Make sure the timer time out will not trigger a statusbar update.
        d.statusbar_timer_.stop();
 
-       if (lyxrc.allow_geometry_session) {
+       // Saving fullscreen requires additional tweaks in the toolbar code.
+       // It wouldn't also work under linux natively.
+       if (lyxrc.allow_geometry_session && !isFullScreen()) {
                QSettings settings;
                QString const key = "view-" + QString::number(id_);
 #ifdef Q_WS_X11
@@ -418,20 +433,7 @@ void GuiView::closeEvent(QCloseEvent * close_event)
        }
 
        guiApp->unregisterView(id_);
-       if (guiApp->viewCount() > 0) {
-               // Just close the window and do nothing else if this is not the
-               // last window.
-               close_event->accept();
-               return;
-       }
-
-       quitting = true;
-
-       // this is the place where we leave the frontend.
-       // it is the only point at which we start quitting.
        close_event->accept();
-       // quit the event loop
-       qApp->quit();
 }
 
 
@@ -537,6 +539,7 @@ void GuiView::updateStatusBar()
        if (d.statusbar_timer_.isActive())
                return;
 
+       theLyXFunc().setLyXView(this);
        statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
 }
 
@@ -567,6 +570,10 @@ bool GuiView::event(QEvent * e)
        //      break;
 
        case QEvent::WindowActivate: {
+               if (this == guiApp->currentView()) {
+                       setFocus();
+                       return QMainWindow::event(e);
+               }
                guiApp->setCurrentView(*this);
                if (d.current_work_area_) {
                        BufferView & bv = d.current_work_area_->bufferView();
@@ -582,6 +589,7 @@ bool GuiView::event(QEvent * e)
                        setWindowTitle(qt_("LyX"));
                        setWindowIconText(qt_("LyX"));
                }
+               setFocus();
                return QMainWindow::event(e);
        }
 
@@ -687,34 +695,29 @@ GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
 
 GuiWorkArea * GuiView::workArea(Buffer & buffer)
 {
-       for (int i = 0; i != d.splitter_->count(); ++i) {
-               GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
-               if (wa)
-                       return wa;
-       }
+       if (TabWorkArea * twa = d.currentTabWorkArea())
+               return twa->workArea(buffer);
        return 0;
 }
 
 
 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
 {
-
        // Automatically create a TabWorkArea if there are none yet.
-       if (!d.splitter_->count())
-               addTabWorkArea();
-
-       TabWorkArea * tab_widget = d.currentTabWorkArea();
+       TabWorkArea * tab_widget = d.splitter_->count() 
+               ? d.currentTabWorkArea() : addTabWorkArea();
        return tab_widget->addWorkArea(buffer, *this);
 }
 
 
-void GuiView::addTabWorkArea()
+TabWorkArea * GuiView::addTabWorkArea()
 {
        TabWorkArea * twa = new TabWorkArea;
        QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
                this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
        d.splitter_->addWidget(twa);
        d.stack_widget_->setCurrentWidget(d.splitter_);
+       return twa;
 }
 
 
@@ -959,6 +962,14 @@ FuncStatus GuiView::getStatus(FuncRequest const & cmd)
                enable = buf;
                break;
 
+       case LFUN_SPLIT_VIEW:
+               enable = buf;
+               break;
+
+       case LFUN_CLOSE_TAB_GROUP:
+               enable = d.currentTabWorkArea();
+               break;
+
        case LFUN_TOOLBAR_TOGGLE:
                flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
                break;
@@ -1035,6 +1046,24 @@ FuncStatus GuiView::getStatus(FuncRequest const & cmd)
                break;
        }
 
+       case LFUN_COMPLETION_INLINE:
+               if (!d.current_work_area_
+                   || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
+                   enable = false;
+               break;
+
+       case LFUN_COMPLETION_POPUP:
+               if (!d.current_work_area_
+                   || !d.current_work_area_->completer().popupPossible(view()->cursor()))
+                   enable = false;
+               break;
+
+       case LFUN_COMPLETION_COMPLETE:
+               if (!d.current_work_area_
+                       || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
+                   enable = false;
+               break;
+
        default:
                if (!view()) {
                        enable = false;
@@ -1550,6 +1579,11 @@ bool GuiView::closeBuffer()
 
 bool GuiView::closeBuffer(Buffer & buf)
 {
+       // goto bookmark to update bookmark pit.
+       //FIXME: we should update only the bookmarks related to this buffer!
+       for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
+               theLyXFunc().gotoBookmark(i+1, false, false);
+
        if (buf.isClean() || buf.paragraphs().empty()) {
                theBufferList().release(&buf);
                return true;
@@ -1564,6 +1598,10 @@ bool GuiView::closeBuffer(Buffer & buf)
        else
                file = buf.fileName().displayName(30);
 
+       // Bring this window to top before asking questions.
+       raise();
+       activateWindow();
+
        docstring const text = bformat(_("The document %1$s has unsaved changes."
                "\n\nDo you want to save the document or discard the changes?"), file);
        int const ret = Alert::prompt(_("Save changed document?"),
@@ -1595,17 +1633,6 @@ bool GuiView::closeBuffer(Buffer & buf)
 }
 
 
-bool GuiView::quitWriteAll()
-{
-       while (!theBufferList().empty()) {
-               Buffer * b = theBufferList().first();
-               if (!closeBuffer(*b))
-                       return false;
-       }
-       return true;
-}
-
-
 bool GuiView::dispatch(FuncRequest const & cmd)
 {
        BufferView * bv = view();       
@@ -1747,8 +1774,6 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        break;
 
                case LFUN_DIALOG_HIDE: {
-                       if (quitting)
-                               break;
                        guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
                        break;
                }
@@ -1800,50 +1825,50 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        break;
                }
 
-               case LFUN_UI_TOGGLE: {
-                       string const arg = cmd.getArg(0);
-                       if (arg == "statusbar")
-                               statusBar()->setVisible(!statusBar()->isVisible());
-                       else if (arg == "menubar")
-                               menuBar()->setVisible(!menuBar()->isVisible());
-#if QT_VERSION >= 0x040300
-                       else if (arg == "frame") {
-                               int l, t, r, b;
-                               getContentsMargins(&l, &t, &r, &b);
-                               //are the frames in default state?
-                               if (l == 0) {
-                                       d.current_work_area_->setFrameStyle(QFrame::NoFrame);
-                                       setContentsMargins(-2, -2, -2, -2);
-                               } else {
-                                       d.current_work_area_->setFrameStyle(QFrame::NoFrame);
-                                       setContentsMargins(0, 0, 0, 0);
-                               }
+               case LFUN_UI_TOGGLE:
+                       lfunUiToggle(cmd);
+                       // Make sure the keyboard focus stays in the work area.
+                       setFocus();
+                       break;
+
+               case LFUN_COMPLETION_INLINE:
+                       if (d.current_work_area_)
+                               d.current_work_area_->completer().showInline();
+                       break;
+
+               case LFUN_SPLIT_VIEW:
+                       if (Buffer * buf = buffer()) {
+                               string const orientation = cmd.getArg(0);
+                               d.splitter_->setOrientation(orientation == "vertical"
+                                       ? Qt::Vertical : Qt::Horizontal);
+                               TabWorkArea * twa = addTabWorkArea();
+                               GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
+                               setCurrentWorkArea(wa);
                        }
-#endif
-                       else if (arg == "fullscreen") {
-                               if (isFullScreen()) {
-                                       showNormal();
-#if QT_VERSION >= 0x040300
-                                       setContentsMargins(0, 0, 0, 0);
-#endif
-                                       d.current_work_area_->setFrameStyle(QFrame::NoFrame);
-                                       d.current_work_area_->bufferView().setFullScreen(false);
-                                       menuBar()->show();
-                                       statusBar()->show();
-                               } else {
-                                       statusBar()->hide();
-                                       menuBar()->hide();
-                                       d.current_work_area_->setFrameStyle(QFrame::NoFrame);
-                                       d.current_work_area_->bufferView().setFullScreen(true);
-#if QT_VERSION >= 0x040300
-                                       setContentsMargins(-2, -2, -2, -2);
-#endif
-                                       showFullScreen();
-                               }
+                       break;
+
+               case LFUN_CLOSE_TAB_GROUP:
+                       if (TabWorkArea * twa = d.currentTabWorkArea()) {
+                               delete twa;
+                               twa = d.currentTabWorkArea();
+                               // Switch to the next GuiWorkArea in the found TabWorkArea.
+                               d.current_work_area_ = twa? twa->currentWorkArea() : 0;
+                               if (d.splitter_->count() == 0)
+                                       // No more work area, switch to the background widget.
+                                       d.setBackground();
                        }
+                       break;
+                       
+               case LFUN_COMPLETION_POPUP:
+                       if (d.current_work_area_)
+                               d.current_work_area_->completer().showPopup();
+                       break;
 
+
+               case LFUN_COMPLETION_COMPLETE:
+                       if (d.current_work_area_)
+                               d.current_work_area_->completer().tab();
                        break;
-               }
 
                default:
                        return false;
@@ -1853,6 +1878,73 @@ bool GuiView::dispatch(FuncRequest const & cmd)
 }
 
 
+void GuiView::lfunUiToggle(FuncRequest const & cmd)
+{
+       string const arg = cmd.getArg(0);
+       if (arg == "scrollbar") {
+               // hide() is of no help
+               if (d.current_work_area_->verticalScrollBarPolicy() ==
+                       Qt::ScrollBarAlwaysOff)
+
+                       d.current_work_area_->setVerticalScrollBarPolicy(
+                               Qt::ScrollBarAsNeeded);
+               else
+                       d.current_work_area_->setVerticalScrollBarPolicy(
+                               Qt::ScrollBarAlwaysOff);
+               return;
+       }
+       if (arg == "statusbar") {
+               statusBar()->setVisible(!statusBar()->isVisible());
+               return;
+       }
+       if (arg == "menubar") {
+               menuBar()->setVisible(!menuBar()->isVisible());
+               return;
+       }
+#if QT_VERSION >= 0x040300
+       if (arg == "frame") {
+               int l, t, r, b;
+               getContentsMargins(&l, &t, &r, &b);
+               //are the frames in default state?
+               d.current_work_area_->setFrameStyle(QFrame::NoFrame);
+               if (l == 0) {
+                       setContentsMargins(-2, -2, -2, -2);
+               } else {
+                       setContentsMargins(0, 0, 0, 0);
+               }
+               return;
+       }
+#endif
+       if (arg != "fullscreen") {
+               message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
+               return;
+       }
+
+       if (lyxrc.full_screen_toolbars)
+               d.toolbars_->toggleFullScreen(!isFullScreen());
+
+       if (isFullScreen()) {
+               for (int i = 0; i != d.splitter_->count(); ++i)
+                       d.tabWorkArea(i)->setFullScreen(false);
+#if QT_VERSION >= 0x040300
+               setContentsMargins(0, 0, 0, 0);
+#endif
+               showNormal();
+               menuBar()->show();
+               statusBar()->show();
+       } else {
+               for (int i = 0; i != d.splitter_->count(); ++i)
+                       d.tabWorkArea(i)->setFullScreen(true);
+#if QT_VERSION >= 0x040300
+               setContentsMargins(-2, -2, -2, -2);
+#endif
+               showFullScreen();
+               statusBar()->hide();
+               menuBar()->hide();
+       }
+}
+
+
 Buffer const * GuiView::updateInset(Inset const * inset)
 {
        if (!d.current_work_area_)
@@ -1873,9 +1965,17 @@ void GuiView::restartCursor()
        if (d.current_work_area_)
                d.current_work_area_->startBlinkingCursor();
 
-       // Take this occasion to update the toobars and layout list.
+       // Take this occasion to update the other GUI elements.
        updateLayoutList();
        updateToolbars();
+       updateStatusBar();
+}
+
+
+void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
+{
+       if (d.current_work_area_)
+               d.current_work_area_->completer().updateVisibility(cur, start, keep);
 }
 
 namespace {
@@ -1982,13 +2082,6 @@ bool GuiView::isDialogVisible(string const & name) const
 
 void GuiView::hideDialog(string const & name, Inset * inset)
 {
-       // Don't send the signal if we are quitting, because on MSVC it is
-       // destructed before the cut stack in CutAndPaste.cpp, and this method
-       // is called from some inset destructor if the cut stack is not empty
-       // on exit.
-       if (quitting)
-               return;
-
        map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
        if (it == d.dialogs_.end())
                return;
@@ -2101,7 +2194,6 @@ Dialog * createGuiExternal(GuiView & lv);
 Dialog * createGuiFloat(GuiView & lv);
 Dialog * createGuiGraphics(GuiView & lv);
 Dialog * createGuiInclude(GuiView & lv);
-Dialog * createGuiIndex(GuiView & lv);
 Dialog * createGuiLabel(GuiView & lv);
 Dialog * createGuiListings(GuiView & lv);
 Dialog * createGuiLog(GuiView & lv);
@@ -2166,8 +2258,6 @@ Dialog * GuiView::build(string const & name)
                return createGuiGraphics(*this);
        if (name == "include")
                return createGuiInclude(*this);
-       if (name == "index")
-               return createGuiIndex(*this);
        if (name == "nomenclature")
                return createGuiNomenclature(*this);
        if (name == "label")