]> git.lyx.org Git - features.git/blobdiff - src/frontends/qt4/GuiView.cpp
move updateLables to buffer
[features.git] / src / frontends / qt4 / GuiView.cpp
index 44bd269fffa71bab6a000efec4b05477967f701a..be58dc71c066165eefb330cb48ca741d3f2de46a 100644 (file)
@@ -3,10 +3,10 @@
  * This file is part of LyX, the document processor.
  * Licence details can be found in the file COPYING.
  *
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
  * \author John Levon
  * \author Abdelrazak Younes
- * \author Peter Kümmel
+ * \author Peter Kümmel
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -18,6 +18,7 @@
 #include "Dialog.h"
 #include "FileDialog.h"
 #include "GuiApplication.h"
+#include "GuiCommandBuffer.h"
 #include "GuiCompleter.h"
 #include "GuiWorkArea.h"
 #include "GuiKeySymbol.h"
@@ -56,6 +57,7 @@
 
 #include "support/lassert.h"
 #include "support/debug.h"
+#include "support/ExceptionMessage.h"
 #include "support/FileName.h"
 #include "support/filetools.h"
 #include "support/gettext.h"
@@ -140,6 +142,7 @@ private:
        QPixmap splash_;
 };
 
+
 /// Toolbar store providing access to individual toolbars by name.
 typedef std::map<std::string, GuiToolbar *> ToolbarMap;
 
@@ -151,13 +154,14 @@ typedef boost::shared_ptr<Dialog> DialogPtr;
 struct GuiView::GuiViewPrivate
 {
        GuiViewPrivate()
-               : current_work_area_(0), layout_(0), autosave_timeout_(5000),
+               : current_work_area_(0), current_main_work_area_(0),
+               layout_(0), autosave_timeout_(5000),
                in_show_(false)
        {
                // hardcode here the platform specific icon size
-               smallIconSize = 14;     // scaling problems
-               normalIconSize = 20;    // ok, default
-               bigIconSize = 26;               // better for some math icons
+               smallIconSize = 14;  // scaling problems
+               normalIconSize = 20; // ok, default
+               bigIconSize = 26;    // better for some math icons
 
                splitter_ = new QSplitter;
                bg_widget_ = new BackgroundWidget;
@@ -231,7 +235,7 @@ struct GuiView::GuiViewPrivate
 
                for (int i = 0; i != splitter_->count(); ++i) {
                        TabWorkArea * twa = tabWorkArea(i);
-                       if (current_work_area_ == twa->currentWorkArea())
+                       if (current_main_work_area_ == twa->currentWorkArea())
                                return twa;
                }
 
@@ -241,6 +245,7 @@ struct GuiView::GuiViewPrivate
 
 public:
        GuiWorkArea * current_work_area_;
+       GuiWorkArea * current_main_work_area_;
        QSplitter * splitter_;
        QStackedWidget * stack_widget_;
        BackgroundWidget * bg_widget_;
@@ -279,9 +284,10 @@ public:
 
 
 GuiView::GuiView(int id)
-       : d(*new GuiViewPrivate), id_(id)
+       : d(*new GuiViewPrivate), 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
        constructToolbars();
 
        // set ourself as the current view. This is needed for the menu bar
@@ -321,37 +327,74 @@ GuiView::GuiView(int id)
        // with some window manager under X11.
        setMinimumSize(300, 200);
 
-       // Now take care of session management.
+       if (lyxrc.allow_geometry_session) {
+               // Now take care of session management.
+               if (restoreLayout())
+                       return;
+       }
+
+       // no session handling, default to a sane size.
+       setGeometry(50, 50, 690, 510);
+       initToolbars();
+
+       // clear session data if any.
        QSettings settings;
+       settings.remove("views");
+}
 
-       if (!lyxrc.allow_geometry_session) {
-               // No session handling, default to a sane size.
-               setGeometry(50, 50, 690, 510);
-               initToolbars();
-               settings.clear();
-               return;
-       }
 
-       QString const key = "view-" + QString::number(id_);
+GuiView::~GuiView()
+{
+       delete &d;
+}
+
+
+void GuiView::saveLayout() const
+{
+       QSettings settings;
+       settings.beginGroup("views");
+       settings.beginGroup(QString::number(id_));
+#ifdef Q_WS_X11
+       settings.setValue("pos", pos());
+       settings.setValue("size", size());
+#else
+       settings.setValue("geometry", saveGeometry());
+#endif
+       settings.setValue("layout", saveState(0));
+       settings.setValue("icon_size", iconSize());
+}
+
+
+bool GuiView::restoreLayout()
+{
+       QSettings settings;
+       settings.beginGroup("views");
+       settings.beginGroup(QString::number(id_));
+       QString const icon_key = "icon_size";
+       if (!settings.contains(icon_key))
+               return false;
+
+       setIconSize(settings.value(icon_key).toSize());
 #ifdef Q_WS_X11
-       QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
-       QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
+       QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
+       QSize size = settings.value("size", QSize(690, 510)).toSize();
        resize(size);
        move(pos);
 #else
-       if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
+       if (!restoreGeometry(settings.value("geometry").toByteArray()))
                setGeometry(50, 50, 690, 510);
 #endif
-       if (!restoreState(settings.value(key + "/layout").toByteArray(), 0))
-               initToolbars();
-
-       setIconSize(settings.value(key + "/icon_size").toSize());
-}
+       // Make sure layout is correctly oriented.
+       setLayoutDirection(qApp->layoutDirection());
 
+       // Allow the toc and view-source dock widget to be restored if needed.
+       findOrBuild("toc", true);
+       findOrBuild("view-source", true);
 
-GuiView::~GuiView()
-{
-       delete &d;
+       if (!restoreState(settings.value("layout").toByteArray(), 0))
+               initToolbars();
+       updateDialogs();
+       return true;
 }
 
 
@@ -373,6 +416,7 @@ void GuiView::constructToolbars()
        for (; it != d.toolbars_.end(); ++it)
                delete it->second;
        d.toolbars_.clear();
+       d.layout_ = 0;
 
        // extracts the toolbars from the backend
        Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
@@ -440,10 +484,13 @@ TocModels & GuiView::tocModels()
 
 void GuiView::setFocus()
 {
+       LYXERR(Debug::DEBUG, "GuiView::setFocus()" << this);
+       // Make sure LyXFunc points to the correct view.
+       guiApp->setCurrentView(this);
+       theLyXFunc().setLyXView(this);
+       QMainWindow::setFocus();
        if (d.current_work_area_)
                d.current_work_area_->setFocus();
-       else
-               QWidget::setFocus();
 }
 
 
@@ -467,21 +514,29 @@ void GuiView::showEvent(QShowEvent * e)
 }
 
 
+/** Destroy only all tabbed WorkAreas. Destruction of other WorkAreas
+ ** is responsibility of the container (e.g., dialog)
+ **/
 void GuiView::closeEvent(QCloseEvent * close_event)
 {
+       LYXERR(Debug::DEBUG, "GuiView::closeEvent()");
+       closing_ = true;
+
        // it can happen that this event arrives without selecting the view,
        // e.g. when clicking the close button on a background window.
-       theLyXFunc().setLyXView(this);
-
-       while (Buffer * b = buffer()) {
+       setFocus();
+       setCurrentWorkArea(currentMainWorkArea());
+       while (GuiWorkArea * wa = currentMainWorkArea()) {
+               Buffer * b = &wa->bufferView().buffer();
                if (b->parent()) {
                        // This is a child document, just close the tab after saving
                        // but keep the file loaded.
                        if (!saveBuffer(*b)) {
+                               closing_ = false;
                                close_event->ignore();
                                return;
                        }
-                       removeWorkArea(d.current_work_area_);
+               removeWorkArea(wa);
                        continue;
                }
 
@@ -496,14 +551,16 @@ void GuiView::closeEvent(QCloseEvent * close_event)
                                //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.
+                               // close the associated work area...
+                               removeWorkArea(wa);
+                               // ... but don't close the buffer.
                                b = 0;
                                break;
                        }
                }
+               // closeBuffer() needs buffer workArea still alive and set as currrent one, and destroys it
                if (b && !closeBuffer(*b, true)) {
+                       closing_ = false;
                        close_event->ignore();
                        return;
                }
@@ -523,18 +580,10 @@ 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 && !isFullScreen()) {
-               QSettings settings;
-               QString const key = "view-" + QString::number(id_);
-#ifdef Q_WS_X11
-               settings.setValue(key + "/pos", pos());
-               settings.setValue(key + "/size", size());
-#else
-               settings.setValue(key + "/geometry", saveGeometry());
-#endif
-               settings.setValue(key + "/icon_size", iconSize());
-               settings.setValue(key + "/layout", saveState(0));
-
+       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();
@@ -558,7 +607,7 @@ void GuiView::dragEnterEvent(QDragEnterEvent * event)
 }
 
 
-void GuiView::dropEvent(QDropEvent* event)
+void GuiView::dropEvent(QDropEvent * event)
 {
        QList<QUrl> files = event->mimeData()->urls();
        if (files.isEmpty())
@@ -568,8 +617,13 @@ 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())
-                       lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
+               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();
+               }
        }
 }
 
@@ -646,21 +700,35 @@ void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
 
 void GuiView::on_lastWorkAreaRemoved()
 {
-#ifdef Q_WS_MACX
-       // On Mac close the view if there is no Tab open anymore,
-       // but only if no splitter is visible
-       if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
-               TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
-               if (twa && twa->count() == 0) {
-                       // close the view, as no tab is open anymore
-                       QTimer::singleShot(0, this, SLOT(close()));
-               }
-       }
-#else
-       structureChanged();
-       // The document settings needs to be reinitialised.
+       if (closing_)
+               // We already are in a close event. Nothing more to do.
+               return;
+
+       if (d.splitter_->count() > 1)
+               // We have a splitter so don't close anything.
+               return;
+
+       // Reset and updates the dialogs.
+       d.toc_models_.reset(0);
        updateDialog("document", "");
        updateDialogs();
+
+       resetWindowTitleAndIconText();
+
+       if (lyxrc.open_buffers_in_tabs)
+               // Nothing more to do, the window should stay open.
+               return;
+
+       if (guiApp->viewIds().size() > 1) {
+               close();
+               return;
+       }
+
+#ifdef Q_WS_MACX
+       // On Mac we also close the last window because the application stay
+       // resident in memory. On other platforms we don't close the last
+       // window because this would quit the application.
+       close();
 #endif
 }
 
@@ -707,6 +775,7 @@ bool GuiView::event(QEvent * e)
                        return QMainWindow::event(e);
                }
                guiApp->setCurrentView(this);
+               theLyXFunc().setLyXView(this);
                if (d.current_work_area_) {
                        BufferView & bv = d.current_work_area_->bufferView();
                        connectBufferView(bv);
@@ -718,8 +787,7 @@ bool GuiView::event(QEvent * e)
                        updateDialog("document", "");
                        updateDialogs();
                } else {
-                       setWindowTitle(qt_("LyX"));
-                       setWindowIconText(qt_("LyX"));
+                       resetWindowTitleAndIconText();
                }
                setFocus();
                return QMainWindow::event(e);
@@ -727,6 +795,8 @@ bool GuiView::event(QEvent * e)
 
        case QEvent::ShortcutOverride: {
 
+#ifndef Q_WS_X11
+               // FIXME bug 4888
                if (isFullScreen() && menuBar()->isHidden()) {
                        QKeyEvent * ke = static_cast<QKeyEvent*>(e);
                        // FIXME: we should also try to detect special LyX shortcut such as
@@ -737,6 +807,7 @@ bool GuiView::event(QEvent * e)
                                menuBar()->show();
                        return QMainWindow::event(e);
                }
+#endif
 
                if (d.current_work_area_)
                        // Nothing special to do.
@@ -764,6 +835,11 @@ bool GuiView::event(QEvent * e)
        }
 }
 
+void GuiView::resetWindowTitleAndIconText()
+{
+    setWindowTitle(qt_("LyX"));
+    setWindowIconText(qt_("LyX"));
+}
 
 bool GuiView::focusNextPrevChild(bool /*next*/)
 {
@@ -791,6 +867,9 @@ void GuiView::setBusy(bool busy)
 
 GuiWorkArea * GuiView::workArea(Buffer & buffer)
 {
+       if (currentWorkArea()
+           && &currentWorkArea()->bufferView().buffer() == &buffer)
+               return (GuiWorkArea *) currentWorkArea();
        if (TabWorkArea * twa = d.currentTabWorkArea())
                return twa->workArea(buffer);
        return 0;
@@ -826,51 +905,105 @@ GuiWorkArea const * GuiView::currentWorkArea() const
 }
 
 
+GuiWorkArea * GuiView::currentWorkArea()
+{
+       return d.current_work_area_;
+}
+
+
+GuiWorkArea const * GuiView::currentMainWorkArea() const
+{
+       if (d.currentTabWorkArea() == NULL)
+               return NULL;
+       return d.currentTabWorkArea()->currentWorkArea();
+}
+
+
+GuiWorkArea * GuiView::currentMainWorkArea()
+{
+       if (d.currentTabWorkArea() == NULL)
+               return NULL;
+       return d.currentTabWorkArea()->currentWorkArea();
+}
+
+
 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
 {
-       LASSERT(wa, /**/);
+       LYXERR(Debug::DEBUG, "Setting current wa: " << wa << endl);
+       if (wa == NULL) {
+               d.current_work_area_ = NULL;
+               d.setBackground();
+               return;
+       }
+       GuiWorkArea * old_gwa = theGuiApp()->currentView()->currentWorkArea();
+       if (old_gwa == wa)
+               return;
+
+       theGuiApp()->setCurrentView(this);
        d.current_work_area_ = wa;
        for (int i = 0; i != d.splitter_->count(); ++i) {
-               if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
+               if (d.tabWorkArea(i)->setCurrentWorkArea(wa)) {
+                       //if (d.current_main_work_area_)
+                       //      d.current_main_work_area_->setFrameStyle(QFrame::NoFrame);
+                       d.current_main_work_area_ = wa;
+                       //d.current_main_work_area_->setFrameStyle(QFrame::Box | QFrame::Plain);
+                       //d.current_main_work_area_->setLineWidth(2);
+                       LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
                        return;
+               }
        }
+       LYXERR(Debug::DEBUG, "This is not a tabbed wa");
+       on_currentWorkAreaChanged(wa);
+       BufferView & bv = wa->bufferView();
+       bv.cursor().fixIfBroken();
+       bv.updateMetrics();
+       wa->setUpdatesEnabled(true);
+       LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
 }
 
 
 void GuiView::removeWorkArea(GuiWorkArea * wa)
 {
-       LASSERT(wa, /**/);
+       LASSERT(wa, return);
        if (wa == d.current_work_area_) {
                disconnectBuffer();
                disconnectBufferView();
                d.current_work_area_ = 0;
+               d.current_main_work_area_ = 0;
        }
 
+       bool found_twa = false;
        for (int i = 0; i != d.splitter_->count(); ++i) {
                TabWorkArea * twa = d.tabWorkArea(i);
-               if (!twa->removeWorkArea(wa))
-                       // Not found in this tab group.
-                       continue;
-
-               // We found and removed the GuiWorkArea.
-               if (!twa->count()) {
-                       // No more WorkAreas in this tab group, so delete it.
-                       delete twa;
+               if (twa->removeWorkArea(wa)) {
+                       // Found in this tab group, and deleted the GuiWorkArea.
+                       found_twa = true;
+                       if (twa->count() != 0) {
+                               if (d.current_work_area_ == 0)
+                                       // This means that we are closing the current GuiWorkArea, so
+                                       // switch to the next GuiWorkArea in the found TabWorkArea.
+                                       setCurrentWorkArea(twa->currentWorkArea());
+                       } else {
+                               // No more WorkAreas in this tab group, so delete it.
+                               delete twa;
+                       }
                        break;
                }
+       }
 
-               if (d.current_work_area_)
-                       // This means that we are not closing the current GuiWorkArea;
-                       break;
+       // It is not a tabbed work area (i.e., the search work area), so it
+       // should be deleted by other means.
+       LASSERT(found_twa, /* */);
 
-               // Switch to the next GuiWorkArea in the found TabWorkArea.
-               d.current_work_area_ = twa->currentWorkArea();
-               break;
+       if (d.current_work_area_ == 0) {
+               if (d.splitter_->count() != 0) {
+                       TabWorkArea * twa = d.currentTabWorkArea();
+                       setCurrentWorkArea(twa->currentWorkArea());
+               } else {
+                       // No more work areas, switch to the background widget.
+                       setCurrentWorkArea(0);
+               }
        }
-
-       if (d.splitter_->count() == 0)
-               // No more work area, switch to the background widget.
-               d.setBackground();
 }
 
 
@@ -927,12 +1060,13 @@ Buffer const * GuiView::buffer() const
 
 void GuiView::setBuffer(Buffer * newBuffer)
 {
-       LASSERT(newBuffer, /**/);
+       LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << std::endl);
+       LASSERT(newBuffer, return);
        setBusy(true);
 
        GuiWorkArea * wa = workArea(*newBuffer);
        if (wa == 0) {
-               updateLabels(*newBuffer->masterBuffer());
+               newBuffer->masterBuffer()->updateLabels();
                wa = addWorkArea(*newBuffer);
        } else {
                //Disconnect the old buffer...there's no new one.
@@ -980,6 +1114,12 @@ void GuiView::errors(string const & error_type)
 }
 
 
+void GuiView::updateTocItem(std::string const & type, DocIterator const & dit)
+{
+       d.toc_models_.updateItem(toqstr(type), dit);
+}
+
+
 void GuiView::structureChanged()
 {
        d.toc_models_.reset(view());
@@ -1052,7 +1192,12 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                break;
 
        case LFUN_SPLIT_VIEW:
-               enable = buf;
+               if (cmd.getArg(0) == "vertical")
+                       enable = buf && (d.splitter_->count() == 1 ||
+                                        d.splitter_->orientation() == Qt::Vertical);
+               else
+                       enable = buf && (d.splitter_->count() == 1 ||
+                                        d.splitter_->orientation() == Qt::Horizontal);
                break;
 
        case LFUN_CLOSE_TAB_GROUP:
@@ -1100,7 +1245,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                else if (name == "latexlog")
                        enable = FileName(buf->logName()).isReadableFile();
                else if (name == "spellchecker")
-#if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
+#if defined (USE_ASPELL)
                        enable = !buf->isReadonly();
 #else
                        enable = false;
@@ -1125,7 +1270,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                        FuncStatus fs;
                        if (!inset->getStatus(view()->cursor(), fr, fs)) {
                                // Every inset is supposed to handle this
-                               LASSERT(false, /**/);
+                               LASSERT(false, break);
                        }
                        flag |= fs;
                } else {
@@ -1154,12 +1299,27 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                    enable = false;
                break;
 
+       case LFUN_COMPLETION_ACCEPT:
+               if (!d.current_work_area_
+                   || (!d.current_work_area_->completer().popupVisible()
+                       && !d.current_work_area_->completer().inlineVisible()
+                       && !d.current_work_area_->completer().completionAvailable()))
+                       enable = false;
+               break;
+
+               case LFUN_COMPLETION_CANCEL:
+               if (!d.current_work_area_
+                   || (!d.current_work_area_->completer().popupVisible()
+                       && !d.current_work_area_->completer().inlineVisible()))
+                       enable = false;
+               break;
+
        default:
                return false;
        }
 
        if (!enable)
-               flag.enabled(false);
+               flag.setEnabled(false);
 
        return true;
 }
@@ -1199,12 +1359,12 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
        // scroll to the position when the file was last closed
        if (lyxrc.use_lastfilepos) {
                LastFilePosSection::FilePos filepos =
-                       LyX::ref().session().lastFilePos().load(filename);
+                       theSession().lastFilePos().load(filename);
                view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
        }
 
        if (tolastfiles)
-               LyX::ref().session().lastFiles().add(filename);
+               theSession().lastFiles().add(filename);
 
        setBusy(false);
        return newBuffer;
@@ -1230,8 +1390,12 @@ void GuiView::openDocument(string const & fname)
                dlg.setButton2(qt_("Examples|#E#e"),
                                toqstr(addPath(package().system_support().absFilename(), "examples")));
 
+               QStringList filter(qt_("LyX Documents (*.lyx)"));
+               filter << qt_("LyX-1.3.x Documents (*.lyx13)")
+                       << qt_("LyX-1.4.x Documents (*.lyx14)")
+                       << qt_("LyX-1.5.x Documents (*.lyx15)");
                FileDialog::Result result =
-                       dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
+                       dlg.open(toqstr(initpath), filter);
 
                if (result.first == FileDialog::Later)
                        return;
@@ -1253,6 +1417,12 @@ void GuiView::openDocument(string const & fname)
        if (!fullname.empty())
                filename = fullname.absFilename();
 
+       if (!fullname.onlyPath().isDirectory()) {
+               Alert::warning(_("Invalid filename"),
+                               bformat(_("The directory in the given path\n%1$s\ndoes not exists."),
+                               from_utf8(fullname.absFilename())));
+               return;
+       }
        // if the file doesn't exist, let the user create one
        if (!fullname.exists()) {
                // the user specifically chose this name. Believe him.
@@ -1268,11 +1438,13 @@ void GuiView::openDocument(string const & fname)
        docstring str2;
        Buffer * buf = loadDocument(fullname);
        if (buf) {
-               updateLabels(*buf);
-               
+               buf->updateLabels();
                setBuffer(buf);
                buf->errors("Parse");
                str2 = bformat(_("Document %1$s opened."), disp_fn);
+               if (buf->lyxvc().inUse())
+                       str2 += " " + from_utf8(buf->lyxvc().versionString()) +
+                               " " + _("Version control detected.");
        } else {
                str2 = bformat(_("Could not open document %1$s"), disp_fn);
        }
@@ -1315,7 +1487,7 @@ static bool import(GuiView * lv, FileName const & filename,
                Buffer * buf = lv->loadDocument(lyxfile);
                if (!buf)
                        return false;
-               updateLabels(*buf);
+               buf->updateLabels();
                lv->setBuffer(buf);
                buf->errors("Parse");
        } else {
@@ -1391,7 +1563,7 @@ void GuiView::importDocument(string const & argument)
        FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
 
        // Check if the document already is open
-       Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
+       Buffer * buf = theBufferList().getBuffer(lyxfile);
        if (buf) {
                setBuffer(buf);
                if (!closeBuffer()) {
@@ -1615,11 +1787,14 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
 
 bool GuiView::saveBuffer(Buffer & b)
 {
+       if (workArea(b) && workArea(b)->inDialogMode())
+               return true;
+
        if (b.isUnnamed())
                return renameBuffer(b, docstring());
 
        if (b.save()) {
-               LyX::ref().session().lastFiles().add(b.fileName());
+               theSession().lastFiles().add(b.fileName());
                return true;
        }
 
@@ -1659,13 +1834,18 @@ bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
 {
        // 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)
+       LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
+       for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
                theLyXFunc().gotoBookmark(i+1, false, false);
 
        if (buf.isClean() || buf.paragraphs().empty()) {
                if (buf.masterBuffer() == &buf && tolastopened)
-                       LyX::ref().session().lastOpened().add(buf.fileName());
-               theBufferList().release(&buf);
+                       theSession().lastOpened().add(buf.fileName());
+               if (buf.parent())
+                       // Don't close child documents.
+                       removeWorkArea(currentMainWorkArea());
+               else
+                       theBufferList().release(&buf);
                return true;
        }
        // Switch to this Buffer.
@@ -1706,9 +1886,14 @@ bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
        // if master/slave are both open, do not save slave since it
        // will be automatically loaded when the master is loaded
        if (buf.masterBuffer() == &buf && tolastopened)
-               LyX::ref().session().lastOpened().add(buf.fileName());
+               theSession().lastOpened().add(buf.fileName());
+
+       if (buf.parent())
+               // Don't close child documents.
+               removeWorkArea(currentMainWorkArea());
+       else
+               theBufferList().release(&buf);
 
-       theBufferList().release(&buf);
        return true;
 }
 
@@ -1727,7 +1912,7 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        break;
 
                case LFUN_BUFFER_SWITCH:
-                       setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
+                       setBuffer(theBufferList().getBuffer(FileName(to_utf8(cmd.argument()))));
                        break;
 
                case LFUN_BUFFER_NEXT:
@@ -1742,8 +1927,11 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        bool const show_it = cmd.argument() != "off";
                        // FIXME: this is a hack, "minibuffer" should not be
                        // hardcoded.
-                       if (GuiToolbar * t = toolbar("minibuffer"))
+                       if (GuiToolbar * t = toolbar("minibuffer")) {
                                t->setVisible(show_it);
+                               if (show_it && t->commandBuffer())
+                                       t->commandBuffer()->setFocus();
+                       }
                        break;
                }
                case LFUN_DROP_LAYOUTS_CHOICE:
@@ -1863,18 +2051,30 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                                data = bv->cursor().getEncoding()->name();
                                if (!data.empty())
                                        showDialog("symbols", data);
+                       // bug 5274
+                       } else if (name == "prefs" && isFullScreen()) {
+                               FuncRequest fr(LFUN_INSET_INSERT, "fullscreen");
+                               lfunUiToggle(fr);
+                               showDialog("prefs", data);
                        } else
                                showDialog(name, data);
                        break;
                }
 
                case LFUN_INSET_APPLY: {
-                       view()->cursor().recordUndoFullDocument();
                        string const name = cmd.getArg(0);
                        Inset * inset = getOpenInset(name);
                        if (inset) {
+                               // put cursor in front of inset.
+                               if (!view()->setCursorFromInset(inset))
+                                       LASSERT(false, break);
+                               
+                               // useful if we are called from a dialog.
+                               view()->cursor().beginUndoGroup();
+                               view()->cursor().recordUndo();
                                FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
                                inset->dispatch(view()->cursor(), fr);
+                               view()->cursor().endUndoGroup();
                        } else {
                                FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
                                lyx::dispatch(fr);
@@ -1888,11 +2088,6 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        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);
@@ -1909,13 +2104,20 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                                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();
+                               if (twa) {
+                                       // Make sure the work area is up to date.
+                                       setCurrentWorkArea(twa->currentWorkArea());
+                               } else {
+                                       setCurrentWorkArea(0);
+                               }
                        }
                        break;
                        
+               case LFUN_COMPLETION_INLINE:
+                       if (d.current_work_area_)
+                               d.current_work_area_->completer().showInline();
+                       break;
+
                case LFUN_COMPLETION_POPUP:
                        if (d.current_work_area_)
                                d.current_work_area_->completer().showPopup();
@@ -1927,11 +2129,27 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                                d.current_work_area_->completer().tab();
                        break;
 
+               case LFUN_COMPLETION_CANCEL:
+                       if (d.current_work_area_) {
+                               if (d.current_work_area_->completer().popupVisible())
+                                       d.current_work_area_->completer().hidePopup();
+                               else
+                                       d.current_work_area_->completer().hideInline();
+                       }
+                       break;
+
+               case LFUN_COMPLETION_ACCEPT:
+                       if (d.current_work_area_)
+                               d.current_work_area_->completer().activate();
+                       break;
+
+
                default:
                        dispatched = false;
                        break;
        }
 
+       // Part of automatic menu appearance feature.
        if (isFullScreen()) {
                if (menuBar()->isVisible())
                        menuBar()->hide();
@@ -1991,9 +2209,6 @@ void GuiView::lfunUiToggle(FuncRequest const & cmd)
 
 void GuiView::toggleFullScreen()
 {
-       QSettings settings;
-       QString const key = "view-" + QString::number(id_);
-
        if (isFullScreen()) {
                for (int i = 0; i != d.splitter_->count(); ++i)
                        d.tabWorkArea(i)->setFullScreen(false);
@@ -2001,28 +2216,30 @@ void GuiView::toggleFullScreen()
                setContentsMargins(0, 0, 0, 0);
 #endif
                setWindowState(windowState() ^ Qt::WindowFullScreen);
+               restoreLayout();
                menuBar()->show();
                statusBar()->show();
-               if (lyxrc.full_screen_toolbars) {
-                       if (!restoreState(settings.value(key + "/layout").toByteArray(), 0))
-                               initToolbars();
-               }
        } else {
+               // bug 5274
+               hideDialogs("prefs", 0);
                for (int i = 0; i != d.splitter_->count(); ++i)
                        d.tabWorkArea(i)->setFullScreen(true);
 #if QT_VERSION >= 0x040300
                setContentsMargins(-2, -2, -2, -2);
 #endif
+               saveLayout();
                setWindowState(windowState() ^ Qt::WindowFullScreen);
                statusBar()->hide();
                menuBar()->hide();
                if (lyxrc.full_screen_toolbars) {
-                       settings.setValue(key + "/layout", saveState(0));
                        ToolbarMap::iterator end = d.toolbars_.end();
                        for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
                                it->second->hide();
                }
        }
+
+       // give dialogs like the TOC a chance to adapt
+       updateDialogs();
 }
 
 
@@ -2048,6 +2265,7 @@ void GuiView::restartCursor()
 
        // Take this occasion to update the other GUI elements.
        updateDialogs();
+       updateStatusBar();
 }
 
 
@@ -2062,11 +2280,13 @@ namespace {
 // This list should be kept in sync with the list of insets in
 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
 // dialog should have the same name as the inset.
+// Changes should be also recorded in LFUN_DIALOG_SHOW doxygen
+// docs in LyXAction.cpp.
 
 char const * const dialognames[] = {
 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
 "citation", "document", "errorlist", "ert", "external", "file",
-"findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
+"findreplace", "float", "graphics", "include", "index", "info", "nomenclature", "label", "log",
 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", 
 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
 
@@ -2074,7 +2294,7 @@ char const * const dialognames[] = {
 "thesaurus",
 #endif
 
-"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
+"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings", "findreplaceadv" };
 
 char const * const * const end_dialognames =
        dialognames + (sizeof(dialognames) / sizeof(char *));
@@ -2103,32 +2323,38 @@ void GuiView::resetDialogs()
 {
        // Make sure that no LFUN uses any LyXView.
        theLyXFunc().setLyXView(0);
-       // FIXME: the "math panels" toolbar takes an awful lot of time to
-       // initialise so we don't do that for the time being.
-       //initToolbars();
-       guiApp->menus().fillMenuBar(menuBar(), this);
+       saveLayout();
+       menuBar()->clear();
+       constructToolbars();
+       guiApp->menus().fillMenuBar(menuBar(), this, false);
        if (d.layout_)
                d.layout_->updateContents(true);
        // Now update controls with current buffer.
        theLyXFunc().setLyXView(this);
+       restoreLayout();
        restartCursor();
 }
 
 
-Dialog * GuiView::find_or_build(string const & name)
+Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
 {
        if (!isValidName(name))
                return 0;
 
        map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
 
-       if (it != d.dialogs_.end())
+       if (it != d.dialogs_.end()) {
+               if (hide_it)
+                       it->second->hideView();
                return it->second.get();
+       }
 
        Dialog * dialog = build(name);
        d.dialogs_[name].reset(dialog);
        if (lyxrc.allow_geometry_session)
                dialog->restoreSession();
+       if (hide_it)
+               dialog->hideView();
        return dialog;
 }
 
@@ -2140,11 +2366,17 @@ void GuiView::showDialog(string const & name, string const & data,
                return;
 
        d.in_show_ = true;
-       Dialog * dialog = find_or_build(name);
-       if (dialog) {
-               dialog->showData(data);
-               if (inset)
-                       d.open_insets_[name] = inset;
+       try {
+               Dialog * dialog = findOrBuild(name, false);
+               if (dialog) {
+                       dialog->showData(data);
+                       if (inset)
+                               d.open_insets_[name] = inset;
+               }
+       }
+       catch (ExceptionMessage const & ex) {
+               d.in_show_ = false;
+               throw ex;
        }
        d.in_show_ = false;
 }
@@ -2217,7 +2449,6 @@ void GuiView::updateDialogs()
        }
        updateToolbars();
        updateLayoutList();
-       updateStatusBar();
 }
 
 
@@ -2239,6 +2470,7 @@ Dialog * createGuiFloat(GuiView & lv);
 Dialog * createGuiGraphics(GuiView & lv);
 Dialog * createGuiHSpace(GuiView & lv);
 Dialog * createGuiInclude(GuiView & lv);
+Dialog * createGuiInfo(GuiView & lv);
 Dialog * createGuiLabel(GuiView & lv);
 Dialog * createGuiListings(GuiView & lv);
 Dialog * createGuiLog(GuiView & lv);
@@ -2250,6 +2482,7 @@ Dialog * createGuiPreferences(GuiView & lv);
 Dialog * createGuiPrint(GuiView & lv);
 Dialog * createGuiRef(GuiView & lv);
 Dialog * createGuiSearch(GuiView & lv);
+Dialog * createGuiSearchAdv(GuiView & lv);
 Dialog * createGuiSendTo(GuiView & lv);
 Dialog * createGuiShowFile(GuiView & lv);
 Dialog * createGuiSpellchecker(GuiView & lv);
@@ -2267,7 +2500,7 @@ Dialog * createGuiWrap(GuiView & lv);
 
 Dialog * GuiView::build(string const & name)
 {
-       LASSERT(isValidName(name), /**/);
+       LASSERT(isValidName(name), return 0);
 
        if (name == "aboutlyx")
                return createGuiAbout(*this);
@@ -2297,12 +2530,16 @@ Dialog * GuiView::build(string const & name)
                return createGuiShowFile(*this);
        if (name == "findreplace")
                return createGuiSearch(*this);
+       if (name == "findreplaceadv")
+               return createGuiSearchAdv(*this);
        if (name == "float")
                return createGuiFloat(*this);
        if (name == "graphics")
                return createGuiGraphics(*this);
        if (name == "include")
                return createGuiInclude(*this);
+       if (name == "info")
+               return createGuiInfo(*this);
        if (name == "nomenclature")
                return createGuiNomenclature(*this);
        if (name == "label")
@@ -2361,4 +2598,4 @@ Dialog * GuiView::build(string const & name)
 } // namespace frontend
 } // namespace lyx
 
-#include "GuiView_moc.cpp"
+#include "moc_GuiView.cpp"