]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
LFUN_CLOSE_TAB_GROUP: bug fixes.
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index 5c537fa8107b102e1fcab00e0f2d01833f28c517..42b96807048a8fc66e7641e82e788306be053ae0 100644 (file)
 #include "GuiView.h"
 
 #include "Dialog.h"
-#include "frontends/FileDialog.h"
+#include "FileDialog.h"
 #include "GuiApplication.h"
 #include "GuiWorkArea.h"
 #include "GuiKeySymbol.h"
-#include "GuiMenubar.h"
 #include "GuiToolbar.h"
 #include "GuiToolbars.h"
-#include "GuiProgress.h"
+#include "Menus.h"
 
 #include "qt_helpers.h"
 
 #include "BufferList.h"
 #include "BufferParams.h"
 #include "BufferView.h"
+#include "Converter.h"
 #include "Cursor.h"
-#include "support/debug.h"
 #include "ErrorList.h"
+#include "Format.h"
 #include "FuncRequest.h"
 #include "support/gettext.h"
 #include "Intl.h"
 #include "LyX.h"
 #include "LyXRC.h"
 #include "LyXVC.h"
-#include "MenuBackend.h"
 #include "Paragraph.h"
 #include "TextClass.h"
 #include "Text.h"
 #include "ToolbarBackend.h"
 #include "version.h"
 
+#include "support/debug.h"
 #include "support/FileFilterList.h"
 #include "support/FileName.h"
 #include "support/filetools.h"
+#include "support/ForkedCalls.h"
 #include "support/lstrings.h"
 #include "support/os.h"
 #include "support/Package.h"
@@ -70,6 +71,7 @@
 #include <QDropEvent>
 #include <QList>
 #include <QMenu>
+#include <QMenuBar>
 #include <QPainter>
 #include <QPixmap>
 #include <QPoint>
@@ -82,6 +84,7 @@
 #include <QTimer>
 #include <QToolBar>
 #include <QUrl>
+#include <QScrollBar>
 
 #include <boost/assert.hpp>
 #include <boost/bind.hpp>
 # include <unistd.h>
 #endif
 
-using std::endl;
-using std::string;
-using std::vector;
+using namespace std;
+using namespace lyx::support;
 
 namespace lyx {
-
-extern bool quitting;
-
 namespace frontend {
 
-using support::addPath;
-using support::bformat;
-using support::FileFilterList;
-using support::FileName;
-using support::makeAbsPath;
-using support::makeDisplayPath;
-using support::package;
-using support::removeAutosaveFile;
-using support::trim;
-
 namespace {
 
 class BackgroundWidget : public QWidget
@@ -177,7 +166,6 @@ struct GuiView::GuiViewPrivate
                delete splitter_;
                delete bg_widget_;
                delete stack_widget_;
-               delete menubar_;
                delete toolbars_;
        }
 
@@ -236,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:
@@ -254,8 +239,6 @@ public:
        QSplitter * splitter_;
        QStackedWidget * stack_widget_;
        BackgroundWidget * bg_widget_;
-       /// view's menubar
-       GuiMenubar * menubar_;
        /// view's toolbars
        GuiToolbars * toolbars_;
        /// The main layout box.
@@ -270,10 +253,10 @@ public:
        GuiLayoutBox * layout_;
 
        ///
-       std::map<std::string, Inset *> open_insets_;
+       map<string, Inset *> open_insets_;
 
        ///
-       std::map<std::string, DialogPtr> dialogs_;
+       map<string, DialogPtr> dialogs_;
 
        unsigned int smallIconSize;
        unsigned int normalIconSize;
@@ -292,9 +275,11 @@ public:
 GuiView::GuiView(int id)
        : d(*new GuiViewPrivate), id_(id)
 {
-       // GuiToolbars *must* be initialised before GuiMenubar.
+       // GuiToolbars *must* be initialised before the menu bar.
        d.toolbars_ = new GuiToolbars(*this);
-       d.menubar_ = new GuiMenubar(this, menubackend);
+
+       // Fill up the menu bar.
+       guiApp->menus().fillMenuBar(this);
 
        setCentralWidget(d.stack_widget_);
 
@@ -407,10 +392,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
@@ -422,7 +416,7 @@ void GuiView::closeEvent(QCloseEvent * close_event)
                settings.setValue(key + "/icon_size", iconSize());
                d.toolbars_->saveToolbarInfo();
                // Now take care of all other dialogs:
-               std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
+               map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
                for (; it!= d.dialogs_.end(); ++it)
                        it->second->saveSession();
        }
@@ -463,7 +457,7 @@ void GuiView::dropEvent(QDropEvent* event)
 
        LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
        for (int i = 0; i != files.size(); ++i) {
-               string const file = support::os::internal_path(fromqstr(
+               string const file = os::internal_path(fromqstr(
                        files.at(i).toLocalFile()));
                if (!file.empty())
                        lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
@@ -473,6 +467,9 @@ void GuiView::dropEvent(QDropEvent* event)
 
 void GuiView::message(docstring const & str)
 {
+       if (ForkedProcess::iAmAChild())
+               return;
+
        statusBar()->showMessage(toqstr(str));
        d.statusbar_timer_.stop();
        d.statusbar_timer_.start(3000);
@@ -544,6 +541,7 @@ void GuiView::updateStatusBar()
        if (d.statusbar_timer_.isActive())
                return;
 
+       theLyXFunc().setLyXView(this);
        statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
 }
 
@@ -582,30 +580,40 @@ bool GuiView::event(QEvent * e)
                        // The document structure, name and dialogs might have
                        // changed in another view.
                        updateBufferDependent(true);
+                       updateToolbars();
+                       updateLayoutList();
+                       updateStatusBar();
                } else {
                        setWindowTitle(qt_("LyX"));
                        setWindowIconText(qt_("LyX"));
                }
+               setFocus();
                return QMainWindow::event(e);
        }
+
        case QEvent::ShortcutOverride: {
+               if (d.current_work_area_)
+                       // Nothing special to do.
+                       return QMainWindow::event(e);
+
                QKeyEvent * ke = static_cast<QKeyEvent*>(e);
-               if (!d.current_work_area_) {
-                       theLyXFunc().setLyXView(this);
-                       KeySymbol sym;
-                       setKeySymbol(&sym, ke);
-                       theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
-                       e->accept();
-                       return true;
-               }
-               if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
-                       KeySymbol sym;
-                       setKeySymbol(&sym, ke);
-                       d.current_work_area_->processKeySym(sym, NoModifier);
-                       e->accept();
-                       return true;
-               }
+
+               // 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.
+               theLyXFunc().setLyXView(this);
+               KeySymbol sym;
+               setKeySymbol(&sym, ke);
+               theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
+               e->accept();
+               return true;
        }
+
        default:
                return QMainWindow::event(e);
        }
@@ -619,17 +627,17 @@ bool GuiView::focusNextPrevChild(bool /*next*/)
 }
 
 
-void GuiView::setBusy(bool yes)
+void GuiView::setBusy(bool busy)
 {
        if (d.current_work_area_) {
-               d.current_work_area_->setUpdatesEnabled(!yes);
-               if (yes)
+               d.current_work_area_->setUpdatesEnabled(!busy);
+               if (busy)
                        d.current_work_area_->stopBlinkingCursor();
                else
                        d.current_work_area_->startBlinkingCursor();
        }
 
-       if (yes)
+       if (busy)
                QApplication::setOverrideCursor(Qt::WaitCursor);
        else
                QApplication::restoreOverrideCursor();
@@ -685,34 +693,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;
 }
 
 
@@ -799,10 +802,12 @@ void GuiView::updateToolbars()
                bool const review =
                        lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
                        lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
+               bool const mathmacrotemplate =
+                       lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
 
-               d.toolbars_->update(math, table, review);
+               d.toolbars_->update(math, table, review, mathmacrotemplate);
        } else
-               d.toolbars_->update(false, false, false);
+               d.toolbars_->update(false, false, false, false);
 
        // update read-only status of open dialogs.
        checkStatus();
@@ -885,7 +890,7 @@ void GuiView::updateDialog(string const & name, string const & data)
        if (!isDialogVisible(name))
                return;
 
-       std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+       map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
        if (it == d.dialogs_.end())
                return;
 
@@ -955,6 +960,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;
@@ -980,6 +993,14 @@ FuncStatus GuiView::getStatus(FuncRequest const & cmd)
                                enable = ic != ERT_CODE && ic != LISTINGS_CODE;
                        }
                }
+               else if (name == "symbols") {
+                       if (!view() || view()->cursor().inMathed())
+                               enable = false;
+                       else {
+                               InsetCode ic = view()->cursor().inset().lyxCode();
+                               enable = ic != ERT_CODE && ic != LISTINGS_CODE;
+                       }
+               }
                else if (name == "latexlog")
                        enable = FileName(buf->logName()).isReadableFile();
                else if (name == "spellchecker")
@@ -1056,6 +1077,255 @@ static FileName selectTemplateFile()
 }
 
 
+Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
+{
+       setBusy(true);
+
+       Buffer * newBuffer = checkAndLoadLyXFile(filename);
+
+       if (!newBuffer) {
+               message(_("Document not loaded."));
+               setBusy(false);
+               return 0;
+       }
+
+       setBuffer(newBuffer);
+
+       // scroll to the position when the file was last closed
+       if (lyxrc.use_lastfilepos) {
+               LastFilePosSection::FilePos filepos =
+                       LyX::ref().session().lastFilePos().load(filename);
+               view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
+       }
+
+       if (tolastfiles)
+               LyX::ref().session().lastFiles().add(filename);
+
+       setBusy(false);
+       return newBuffer;
+}
+
+
+void GuiView::openDocument(string const & fname)
+{
+       string initpath = lyxrc.document_path;
+
+       if (buffer()) {
+               string const trypath = buffer()->filePath();
+               // If directory is writeable, use this as default.
+               if (FileName(trypath).isDirWritable())
+                       initpath = trypath;
+       }
+
+       string filename;
+
+       if (fname.empty()) {
+               FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
+               dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+               dlg.setButton2(_("Examples|#E#e"),
+                               from_utf8(addPath(package().system_support().absFilename(), "examples")));
+
+               FileDialog::Result result =
+                       dlg.open(from_utf8(initpath),
+                                    FileFilterList(_("LyX Documents (*.lyx)")),
+                                    docstring());
+
+               if (result.first == FileDialog::Later)
+                       return;
+
+               filename = to_utf8(result.second);
+
+               // check selected filename
+               if (filename.empty()) {
+                       message(_("Canceled."));
+                       return;
+               }
+       } else
+               filename = fname;
+
+       // get absolute path of file and add ".lyx" to the filename if
+       // necessary. 
+       FileName const fullname = 
+                       fileSearch(string(), filename, "lyx", support::may_not_exist);
+       if (!fullname.empty())
+               filename = fullname.absFilename();
+
+       // if the file doesn't exist, let the user create one
+       if (!fullname.exists()) {
+               // the user specifically chose this name. Believe him.
+               Buffer * const b = newFile(filename, string(), true);
+               if (b)
+                       setBuffer(b);
+               return;
+       }
+
+       docstring const disp_fn = makeDisplayPath(filename);
+       message(bformat(_("Opening document %1$s..."), disp_fn));
+
+       docstring str2;
+       Buffer * buf = loadDocument(fullname);
+       if (buf) {
+               updateLabels(*buf);
+               setBuffer(buf);
+               buf->errors("Parse");
+               str2 = bformat(_("Document %1$s opened."), disp_fn);
+       } else {
+               str2 = bformat(_("Could not open document %1$s"), disp_fn);
+       }
+       message(str2);
+}
+
+// FIXME: clean that
+static bool import(GuiView * lv, FileName const & filename,
+       string const & format, ErrorList & errorList)
+{
+       FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
+
+       string loader_format;
+       vector<string> loaders = theConverters().loaders();
+       if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
+               for (vector<string>::const_iterator it = loaders.begin();
+                    it != loaders.end(); ++it) {
+                       if (!theConverters().isReachable(format, *it))
+                               continue;
+
+                       string const tofile =
+                               changeExtension(filename.absFilename(),
+                               formats.extension(*it));
+                       if (!theConverters().convert(0, filename, FileName(tofile),
+                               filename, format, *it, errorList))
+                               return false;
+                       loader_format = *it;
+                       break;
+               }
+               if (loader_format.empty()) {
+                       frontend::Alert::error(_("Couldn't import file"),
+                                    bformat(_("No information for importing the format %1$s."),
+                                        formats.prettyName(format)));
+                       return false;
+               }
+       } else
+               loader_format = format;
+
+       if (loader_format == "lyx") {
+               Buffer * buf = lv->loadDocument(lyxfile);
+               if (!buf)
+                       return false;
+               updateLabels(*buf);
+               lv->setBuffer(buf);
+               buf->errors("Parse");
+       } else {
+               Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
+               if (!b)
+                       return false;
+               lv->setBuffer(b);
+               bool as_paragraphs = loader_format == "textparagraph";
+               string filename2 = (loader_format == format) ? filename.absFilename()
+                       : changeExtension(filename.absFilename(),
+                                         formats.extension(loader_format));
+               lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
+               theLyXFunc().setLyXView(lv);
+               lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
+       }
+
+       return true;
+}
+
+
+void GuiView::importDocument(string const & argument)
+{
+       string format;
+       string filename = split(argument, format, ' ');
+
+       LYXERR(Debug::INFO, format << " file: " << filename);
+
+       // need user interaction
+       if (filename.empty()) {
+               string initpath = lyxrc.document_path;
+
+               Buffer const * buf = buffer();
+               if (buf) {
+                       string const trypath = buf->filePath();
+                       // If directory is writeable, use this as default.
+                       if (FileName(trypath).isDirWritable())
+                               initpath = trypath;
+               }
+
+               docstring const text = bformat(_("Select %1$s file to import"),
+                       formats.prettyName(format));
+
+               FileDialog dlg(text, LFUN_BUFFER_IMPORT);
+               dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+               dlg.setButton2(_("Examples|#E#e"),
+                       from_utf8(addPath(package().system_support().absFilename(), "examples")));
+
+               docstring filter = formats.prettyName(format);
+               filter += " (*.";
+               // FIXME UNICODE
+               filter += from_utf8(formats.extension(format));
+               filter += ')';
+
+               FileDialog::Result result =
+                       dlg.open(from_utf8(initpath),
+                                    FileFilterList(filter),
+                                    docstring());
+
+               if (result.first == FileDialog::Later)
+                       return;
+
+               filename = to_utf8(result.second);
+
+               // check selected filename
+               if (filename.empty())
+                       message(_("Canceled."));
+       }
+
+       if (filename.empty())
+               return;
+
+       // get absolute path of file
+       FileName const fullname(makeAbsPath(filename));
+
+       FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
+
+       // Check if the document already is open
+       Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
+       if (buf) {
+               setBuffer(buf);
+               if (!closeBuffer()) {
+                       message(_("Canceled."));
+                       return;
+               }
+       }
+
+       docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
+
+       // if the file exists already, and we didn't do
+       // -i lyx thefile.lyx, warn
+       if (lyxfile.exists() && fullname != lyxfile) {
+
+               docstring text = bformat(_("The document %1$s already exists.\n\n"
+                       "Do you want to overwrite that document?"), displaypath);
+               int const ret = Alert::prompt(_("Overwrite document?"),
+                       text, 0, 1, _("&Overwrite"), _("&Cancel"));
+
+               if (ret == 1) {
+                       message(_("Canceled."));
+                       return;
+               }
+       }
+
+       message(bformat(_("Importing %1$s..."), displaypath));
+       ErrorList errorList;
+       if (import(this, fullname, format, errorList))
+               message(_("imported."));
+       else
+               message(_("file not imported!"));
+
+       // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
+}
+
+
 void GuiView::newDocument(string const & filename, bool from_template)
 {
        FileName initpath(lyxrc.document_path);
@@ -1077,6 +1347,8 @@ void GuiView::newDocument(string const & filename, bool from_template)
 
        if (b)
                setBuffer(b);
+       // Ensure the cursor is correctly positionned on screen.
+       view()->showCursor();
 }
 
 
@@ -1188,10 +1460,10 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
                dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
                dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
 
-               if (!support::isLyXFilename(fname.absFilename()))
+               if (!isLyXFilename(fname.absFilename()))
                        fname.changeExtension(".lyx");
 
-               support::FileFilterList const filter(_("LyX Documents (*.lyx)"));
+               FileFilterList const filter(_("LyX Documents (*.lyx)"));
 
                FileDialog::Result result =
                        dlg.save(from_utf8(fname.onlyPath().absFilename()),
@@ -1206,7 +1478,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
                if (fname.empty())
                        return false;
 
-               if (!support::isLyXFilename(fname.absFilename()))
+               if (!isLyXFilename(fname.absFilename()))
                        fname.changeExtension(".lyx");
        }
 
@@ -1269,9 +1541,9 @@ bool GuiView::saveBuffer(Buffer & b)
                        return false;
                break;
        case 1:
-               return false;
-       case 2:
                break;
+       case 2:
+               return false;
        }
 
        return saveBuffer(b);
@@ -1351,6 +1623,14 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                bv->cursor().updateFlags(Update::None);
 
        switch(cmd.action) {
+               case LFUN_FILE_OPEN:
+                       openDocument(to_utf8(cmd.argument()));
+                       break;
+
+               case LFUN_BUFFER_IMPORT:
+                       importDocument(to_utf8(cmd.argument()));
+                       break;
+
                case LFUN_BUFFER_SWITCH:
                        setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
                        break;
@@ -1374,7 +1654,8 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        break;
 
                case LFUN_MENU_OPEN:
-                       d.menubar_->openByName(toqstr(cmd.argument()));
+                       if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument())))
+                               menu->exec(QCursor::pos());
                        break;
 
                case LFUN_FILE_INSERT:
@@ -1506,6 +1787,10 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                                string const data = "vc " +
                                        Lexer::quoteString(buffer()->lyxvc().getLogFile());
                                showDialog("log", data);
+                       } else if (name == "symbols") {
+                               data = bv->cursor().getEncoding()->name();
+                               if (!data.empty())
+                                       showDialog("symbols", data);
                        } else
                                showDialog(name, data);
                        break;
@@ -1524,6 +1809,35 @@ bool GuiView::dispatch(FuncRequest const & cmd)
                        break;
                }
 
+               case LFUN_UI_TOGGLE:
+                       lfunUiToggle(cmd);
+                       // Make sure the keyboard focus stays in the work area.
+                       setFocus();
+                       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);
+                       }
+                       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;
+
                default:
                        return false;
        }
@@ -1532,6 +1846,74 @@ 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?
+               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);
+               }
+               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_)
@@ -1567,14 +1949,14 @@ char const * const dialognames[] = {
 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
-"mathdelimiter", "mathmatrix", "note", "paragraph",
-"prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
+"mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", 
+"ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
 
 #ifdef HAVE_LIBAIKSAURUS
 "thesaurus",
 #endif
 
-"texinfo", "toc", "href", "view-source", "latex-progress", "vspace", "wrap", "listings" };
+"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
 
 char const * const * const end_dialognames =
        dialognames + (sizeof(dialognames) / sizeof(char *));
@@ -1592,7 +1974,7 @@ private:
 
 bool isValidName(string const & name)
 {
-       return std::find_if(dialognames, end_dialognames,
+       return find_if(dialognames, end_dialognames,
                            cmpCStr(name.c_str())) != end_dialognames;
 }
 
@@ -1603,8 +1985,10 @@ void GuiView::resetDialogs()
 {
        // Make sure that no LFUN uses any LyXView.
        theLyXFunc().setLyXView(0);
-       d.toolbars_->init();
-       d.menubar_->init();
+       // FIXME: the "math panels" toolbar takes an awful lot of time to
+       // initialise so we don't do that for the time being.
+       //d.toolbars_->init();
+       guiApp->menus().fillMenuBar(this);
        if (d.layout_)
                d.layout_->updateContents(true);
        // Now update controls with current buffer.
@@ -1618,7 +2002,7 @@ Dialog * GuiView::find_or_build(string const & name)
        if (!isValidName(name))
                return 0;
 
-       std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
+       map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
 
        if (it != d.dialogs_.end())
                return it->second.get();
@@ -1650,7 +2034,7 @@ void GuiView::showDialog(string const & name, string const & data,
 
 bool GuiView::isDialogVisible(string const & name) const
 {
-       std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+       map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
        if (it == d.dialogs_.end())
                return false;
        return it->second.get()->isVisibleView();
@@ -1666,7 +2050,7 @@ void GuiView::hideDialog(string const & name, Inset * inset)
        if (quitting)
                return;
 
-       std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+       map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
        if (it == d.dialogs_.end())
                return;
 
@@ -1695,15 +2079,15 @@ Inset * GuiView::getOpenInset(string const & name) const
        if (!isValidName(name))
                return 0;
 
-       std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
+       map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
        return it == d.open_insets_.end() ? 0 : it->second;
 }
 
 
 void GuiView::hideAll() const
 {
-       std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
-       std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+       map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
+       map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
 
        for(; it != end; ++it)
                it->second->hideView();
@@ -1712,8 +2096,8 @@ void GuiView::hideAll() const
 
 void GuiView::hideBufferDependent() const
 {
-       std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
-       std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+       map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
+       map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
 
        for(; it != end; ++it) {
                Dialog * dialog = it->second.get();
@@ -1725,8 +2109,8 @@ void GuiView::hideBufferDependent() const
 
 void GuiView::updateBufferDependent(bool switched) const
 {
-       std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
-       std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+       map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
+       map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
 
        for(; it != end; ++it) {
                Dialog * dialog = it->second.get();
@@ -1749,8 +2133,8 @@ void GuiView::updateBufferDependent(bool switched) const
 
 void GuiView::checkStatus()
 {
-       std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
-       std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+       map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
+       map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
 
        for(; it != end; ++it) {
                Dialog * const dialog = it->second.get();
@@ -1778,7 +2162,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);
@@ -1793,6 +2176,7 @@ Dialog * createGuiSearch(GuiView & lv);
 Dialog * createGuiSendTo(GuiView & lv);
 Dialog * createGuiShowFile(GuiView & lv);
 Dialog * createGuiSpellchecker(GuiView & lv);
+Dialog * createGuiSymbols(GuiView & lv);
 Dialog * createGuiTabularCreate(GuiView & lv);
 Dialog * createGuiTabular(GuiView & lv);
 Dialog * createGuiTexInfo(GuiView & lv);
@@ -1801,7 +2185,6 @@ Dialog * createGuiThesaurus(GuiView & lv);
 Dialog * createGuiHyperlink(GuiView & lv);
 Dialog * createGuiVSpace(GuiView & lv);
 Dialog * createGuiViewSource(GuiView & lv);
-Dialog * createGuiProgress(GuiView & lv);
 Dialog * createGuiWrap(GuiView & lv);
 
 
@@ -1843,8 +2226,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")
@@ -1853,8 +2234,6 @@ Dialog * GuiView::build(string const & name)
                return createGuiLog(*this);
        if (name == "view-source")
                return createGuiViewSource(*this);
-       if (name == "latex-progress")
-               return createGuiProgress(*this);
        if (name == "mathdelimiter")
                return createGuiDelimiter(*this);
        if (name == "mathmatrix")
@@ -1873,6 +2252,8 @@ Dialog * GuiView::build(string const & name)
                return createGuiSendTo(*this);
        if (name == "spellchecker")
                return createGuiSpellchecker(*this);
+       if (name == "symbols")
+               return createGuiSymbols(*this);
        if (name == "tabular")
                return createGuiTabular(*this);
        if (name == "tabularcreate")