]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
Introducing GuiMenubar::init() to avoid destructing the object in order to re-initial...
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index dfb14ac1c82d1e7d07a55e40efc55a55c76beb46..66ed4feccf20a3a701f07db5625580d9d449bad2 100644 (file)
 #include <config.h>
 
 #include "GuiView.h"
+#include "Dialog.h"
 
-#include "GuiImplementation.h"
-#include "GuiWorkArea.h"
-#include "QKeySymbol.h"
-#include "QLMenubar.h"
-#include "QLToolbar.h"
-#include "QCommandBuffer.h"
-#include "qt_helpers.h"
+#include <boost/assert.hpp>
 
-#include "frontends/Application.h"
-#include "frontends/Gui.h"
-#include "frontends/WorkArea.h"
+using std::string;
 
-#include "support/filetools.h"
-#include "support/convert.h"
-#include "support/lstrings.h"
-#include "support/os.h"
+#include "GuiView.h"
 
+#include "GuiApplication.h"
+#include "GuiWorkArea.h"
+#include "GuiKeySymbol.h"
+#include "GuiMenubar.h"
+#include "GuiToolbar.h"
+#include "GuiToolbars.h"
+
+#include "qt_helpers.h"
+
+#include "buffer_funcs.h"
 #include "Buffer.h"
-#include "BufferView.h"
 #include "BufferList.h"
-#include "callback.h"
+#include "BufferParams.h"
+#include "BufferView.h"
+#include "Cursor.h"
 #include "debug.h"
+#include "ErrorList.h"
 #include "FuncRequest.h"
-#include "LyX.h"
+#include "gettext.h"
+#include "Intl.h"
+#include "Layout.h"
+#include "Lexer.h"
 #include "LyXFunc.h"
+#include "LyX.h"
 #include "LyXRC.h"
+#include "LyXVC.h"
 #include "MenuBackend.h"
-#include "Session.h"
+#include "Paragraph.h"
+#include "TextClass.h"
+#include "Text.h"
+#include "ToolbarBackend.h"
+#include "version.h"
+
+#include "support/convert.h"
+#include "support/FileName.h"
+#include "support/lstrings.h"
+#include "support/os.h"
+#include "support/Timeout.h"
 
 #include <QAction>
 #include <QApplication>
 #include <QDesktopWidget>
 #include <QDragEnterEvent>
 #include <QDropEvent>
-#include <QHBoxLayout>
 #include <QList>
-#include <QMimeData>
+#include <QMenu>
+#include <QPainter>
 #include <QPixmap>
+#include <QPoint>
 #include <QPushButton>
+#include <QSettings>
+#include <QShowEvent>
+#include <QSplitter>
+#include <QStackedWidget>
 #include <QStatusBar>
+#include <QTimer>
 #include <QToolBar>
-#include <QTabBar>
 #include <QUrl>
-#include <QVBoxLayout>
-
 
 #include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
+#include <boost/current_function.hpp>
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
 
 using std::endl;
 using std::string;
@@ -71,124 +98,115 @@ using std::vector;
 
 namespace lyx {
 
-using support::FileName;
-using support::libFileSearch;
-using support::makeDisplayPath;
+extern bool quitting;
 
 namespace frontend {
 
+using support::bformat;
+using support::FileName;
+using support::trim;
+
 namespace {
 
 int const statusbar_timer_value = 3000;
 
-class TabWidget : public QWidget
+class BackgroundWidget : public QWidget
 {
-       QHBoxLayout* hlayout;
 public:
-       QTabBar* tabbar;
-       QPushButton* closeTabButton;
-
-       void hideTabsIfNecessary()
+       BackgroundWidget(QString const & file, QString const & text)
        {
-               if (tabbar->count() > 1) {
-                       tabbar->show();
-                       closeTabButton->show();
-               } else {
-                       tabbar->hide();
-                       closeTabButton->hide();
+               splash_ = new QPixmap(file);
+               if (!splash_) {
+                       lyxerr << "could not load splash screen: '" << fromqstr(file) << "'" << endl;
+                       return;
                }
+
+               QPainter pain(splash_);
+               pain.setPen(QColor(255, 255, 0));
+               QFont font;
+               // The font used to display the version info
+               font.setStyleHint(QFont::SansSerif);
+               font.setWeight(QFont::Bold);
+               font.setPointSize(convert<int>(lyxrc.font_sizes[FONT_SIZE_LARGE]));
+               pain.setFont(font);
+               pain.drawText(260, 270, text);
        }
 
-       TabWidget(QWidget* w, bool topTabBar)
+       void paintEvent(QPaintEvent *)
        {
-               closeTabButton = new QPushButton(this);
-               FileName const file = support::libFileSearch("images", "closetab", "xpm");
-               if (!file.empty()) {
-                       QPixmap pm(toqstr(file.absFilename()));
-                       closeTabButton->setIcon(QIcon(pm));
-                       closeTabButton->setMaximumSize(pm.size());
-                       closeTabButton->setFlat(true);
-               } else {
-                       closeTabButton->setText("Close");
-               }
-               closeTabButton->setCursor(Qt::ArrowCursor);
-               closeTabButton->setToolTip(tr("Close tab"));
-               closeTabButton->setEnabled(true);
+               if (!splash_)
+                       return;
 
-               tabbar = new QTabBar;
-#if QT_VERSION >= 0x040200
-               tabbar->setUsesScrollButtons(true);
-#endif
-               hlayout = new QHBoxLayout;
-               QVBoxLayout* vlayout = new QVBoxLayout;
-               hlayout->addWidget(tabbar);
-               hlayout->addWidget(closeTabButton);
-               if (topTabBar) {
-                       vlayout->addLayout(hlayout);
-                       vlayout->addWidget(w);
-               } else {
-                       tabbar->setShape(QTabBar::RoundedSouth);
-                       vlayout->addWidget(w);
-                       vlayout->addLayout(hlayout);
-               }
-               vlayout->setMargin(0);
-               vlayout->setSpacing(0);
-               hlayout->setMargin(0);
-               setLayout(vlayout);
-               hideTabsIfNecessary();
+               int x = (width() - splash_->width()) / 2;
+               int y = (height() - splash_->height()) / 2;
+               QPainter pain(this);
+               pain.drawPixmap(x, y, *splash_);
        }
 
-       void clearTabbar()
-       {
-               for (int i = tabbar->count() - 1; i >= 0; --i)
-                       tabbar->removeTab(i);
-       }
+private:
+       QPixmap * splash_;
 };
 
 } // namespace anon
 
 
+typedef boost::shared_ptr<Dialog> DialogPtr;
+
 struct GuiView::GuiViewPrivate
 {
-       vector<string> tabnames;
-       string cur_title;
-
-       TabWidget* tabWidget;
-
-       int posx_offset;
-       int posy_offset;
-
-       GuiViewPrivate() : tabWidget(0), posx_offset(0), posy_offset(0)
-       {}
+       GuiViewPrivate()
+               : current_work_area_(0), layout_(0),
+               autosave_timeout_(new Timeout(5000)), quitting_by_menu_(false),
+               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
+
+               splitter_ = new QSplitter;
+               initBackground();
+               stack_widget_ = new QStackedWidget;
+               stack_widget_->addWidget(bg_widget_);
+               stack_widget_->addWidget(splitter_);
+               setBackground();
+       }
 
-       unsigned int smallIconSize;
-       unsigned int normalIconSize;
-       unsigned int bigIconSize;
-       // static needed by "New Window"
-       static unsigned int lastIconSize;
+       ~GuiViewPrivate()
+       {
+               delete splitter_;
+               delete bg_widget_;
+               delete stack_widget_;
+               delete menubar_;
+               delete toolbars_;
+               delete autosave_timeout_;
+       }
 
-       QMenu* toolBarPopup(GuiView *parent)
+       QMenu * toolBarPopup(GuiView * parent)
        {
                // FIXME: translation
-               QMenu* menu = new QMenu(parent);
-               QActionGroup *iconSizeGroup = new QActionGroup(parent);
+               QMenu * menu = new QMenu(parent);
+               QActionGroup * iconSizeGroup = new QActionGroup(parent);
 
-               QAction *smallIcons = new QAction(iconSizeGroup);
+               QAction * smallIcons = new QAction(iconSizeGroup);
                smallIcons->setText(qt_("Small-sized icons"));
                smallIcons->setCheckable(true);
-               QObject::connect(smallIcons, SIGNAL(triggered()), parent, SLOT(smallSizedIcons()));
+               QObject::connect(smallIcons, SIGNAL(triggered()),
+                       parent, SLOT(smallSizedIcons()));
                menu->addAction(smallIcons);
 
-               QAction *normalIcons = new QAction(iconSizeGroup);
+               QAction * normalIcons = new QAction(iconSizeGroup);
                normalIcons->setText(qt_("Normal-sized icons"));
                normalIcons->setCheckable(true);
-               QObject::connect(normalIcons, SIGNAL(triggered()), parent, SLOT(normalSizedIcons()));
+               QObject::connect(normalIcons, SIGNAL(triggered()),
+                       parent, SLOT(normalSizedIcons()));
                menu->addAction(normalIcons);
 
-               QAction *bigIcons = new QAction(iconSizeGroup);
+               QAction * bigIcons = new QAction(iconSizeGroup);
                bigIcons->setText(qt_("Big-sized icons"));
                bigIcons->setCheckable(true);
-               QObject::connect(bigIcons, SIGNAL(triggered()), parent, SLOT(bigSizedIcons()));
+               QObject::connect(bigIcons, SIGNAL(triggered()),
+                       parent, SLOT(bigSizedIcons()));
                menu->addAction(bigIcons);
 
                unsigned int cur = parent->iconSize().width();
@@ -201,57 +219,172 @@ struct GuiView::GuiViewPrivate
 
                return menu;
        }
-};
 
+       void initBackground()
+       {
+               LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
+               /// The text to be written on top of the pixmap
+               QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
+               bg_widget_ = new BackgroundWidget(":/images/banner.png", text);
+       }
+
+       void setBackground()
+       {
+               stack_widget_->setCurrentWidget(bg_widget_);
+               bg_widget_->setUpdatesEnabled(true);
+       }
+
+       TabWorkArea * tabWorkArea(int i)
+       {
+               return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
+       }
+
+       TabWorkArea * currentTabWorkArea()
+       {
+               if (splitter_->count() == 1)
+                       // 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;
+               }
+
+               return tab_widget;
+       }
 
-unsigned int GuiView::GuiViewPrivate::lastIconSize = 0;
+public:
+       ///
+       string cur_title;
+
+       GuiWorkArea * current_work_area_;
+       QSplitter * splitter_;
+       QStackedWidget * stack_widget_;
+       BackgroundWidget * bg_widget_;
+       /// view's menubar
+       GuiMenubar * menubar_;
+       /// view's toolbars
+       GuiToolbars * toolbars_;
+       /// The main layout box.
+       /** 
+        * \warning Don't Delete! The layout box is actually owned by
+        * whichever toolbar contains it. All the GuiView class needs is a
+        * means of accessing it.
+        *
+        * FIXME: replace that with a proper model so that we are not limited
+        * to only one dialog.
+        */
+       GuiLayoutBox * layout_;
+
+       ///
+       std::map<std::string, Inset *> open_insets_;
+
+       ///
+       std::map<std::string, DialogPtr> dialogs_;
+
+       unsigned int smallIconSize;
+       unsigned int normalIconSize;
+       unsigned int bigIconSize;
+       ///
+       QTimer statusbar_timer_;
+       /// are we quitting by the menu?
+       bool quitting_by_menu_;
+       /// auto-saving of buffers
+       Timeout * const autosave_timeout_;
+       ///
+       /// flag against a race condition due to multiclicks in Qt frontend,
+       /// see bug #1119
+       bool in_show_;
+};
 
 
 GuiView::GuiView(int id)
-       : QMainWindow(), LyXView(id), commandbuffer_(0), quitting_by_menu_(false),
-         d(*new GuiViewPrivate)
+       : d(*new GuiViewPrivate),  id_(id)
 {
+       // GuiToolbars *must* be initialised before GuiMenubar.
+       d.toolbars_ = new GuiToolbars(*this);
+       d.menubar_ = new GuiMenubar(this, menubackend);
+
+       setCentralWidget(d.stack_widget_);
+
+       // Start autosave timer
+       if (lyxrc.autosave) {
+               d.autosave_timeout_->timeout.connect(boost::bind(&GuiView::autoSave, this));
+               d.autosave_timeout_->setTimeout(lyxrc.autosave * 1000);
+               d.autosave_timeout_->start();
+       }
+       QObject::connect(&d.statusbar_timer_, SIGNAL(timeout()),
+               this, SLOT(clearMessage()));
+
        // Qt bug? signal lastWindowClosed does not work
        setAttribute(Qt::WA_QuitOnClose, false);
        setAttribute(Qt::WA_DeleteOnClose, true);
-
-       // hardcode here the platform specific icon size
-       d.smallIconSize = 14;   // scaling problems
-       d.normalIconSize = 20;  // ok, default
-       d.bigIconSize = 26;             // better for some math icons
-
 #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.
-       FileName const iconname = libFileSearch("images", "lyx", "xpm");
-       if (!iconname.empty())
-               setWindowIcon(QPixmap(toqstr(iconname.absFilename())));
+       // assign an icon to main form. We do not do it under Qt/Mac,
+       // since the icon is provided in the application bundle.
+       setWindowIcon(QPixmap(":/images/lyx.png"));
 #endif
 
        // For Drag&Drop.
        setAcceptDrops(true);
+
+       statusBar()->setSizeGripEnabled(true);
+
+       // Forbid too small unresizable window because it can happen
+       // with some window manager under X11.
+       setMinimumSize(300, 200);
+
+       if (!lyxrc.allow_geometry_session)
+               // No session handling, default to a sane size.
+               setGeometry(50, 50, 690, 510);
+
+       // Now take care of session management.
+       QSettings settings;
+       QString const key = "view-" + QString::number(id_);
+#ifdef Q_WS_X11
+       QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
+       QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
+       resize(size);
+       move(pos);
+#else
+       if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
+               setGeometry(50, 50, 690, 510);
+#endif
+       setIconSize(settings.value(key + "/icon_size").toSize());
 }
 
 
 GuiView::~GuiView()
 {
-       menubar_.reset();
        delete &d;
 }
 
 
 void GuiView::close()
 {
-       quitting_by_menu_ = true;
+       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();
-       quitting_by_menu_ = false;
+       d.quitting_by_menu_ = false;
 }
 
 
 void GuiView::setFocus()
 {
-       BOOST_ASSERT(work_area_);
-       static_cast<GuiWorkArea *>(work_area_)->setFocus();
+       if (d.current_work_area_)
+               d.current_work_area_->setFocus();
+       else
+               QWidget::setFocus();
 }
 
 
@@ -261,27 +394,17 @@ QMenu* GuiView::createPopupMenu()
 }
 
 
-void GuiView::init()
+void GuiView::showEvent(QShowEvent * e)
 {
-       menubar_.reset(new QLMenubar(this, menubackend));
-       QObject::connect(menuBar(), SIGNAL(triggered(QAction *)),
-               this, SLOT(updateMenu(QAction *)));
+       LYXERR(Debug::GUI, "Passed Geometry "
+               << size().height() << "x" << size().width()
+               << "+" << pos().x() << "+" << pos().y());
 
-       getToolbars().init();
+       if (d.splitter_->count() == 0)
+               // No work area, switch to the background widget.
+               d.setBackground();
 
-       statusBar()->setSizeGripEnabled(true);
-
-       QObject::connect(&statusbar_timer_, SIGNAL(timeout()),
-               this, SLOT(update_view_state_qt()));
-
-       BOOST_ASSERT(work_area_);
-       if (!work_area_->bufferView().buffer() && !theBufferList().empty())
-               setBuffer(theBufferList().first());
-
-       // make sure the buttons are disabled if needed
-       updateToolbars();
-       updateLayoutChoice();
-       updateMenubar();
+       QMainWindow::showEvent(e);
 }
 
 
@@ -289,7 +412,7 @@ void GuiView::closeEvent(QCloseEvent * close_event)
 {
        // we may have been called through the close window button
        // which bypasses the LFUN machinery.
-       if (!quitting_by_menu_ && theApp()->gui().viewIds().size() == 1) {
+       if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
                if (!theBufferList().quitWriteAll()) {
                        close_event->ignore();
                        return;
@@ -299,10 +422,23 @@ void GuiView::closeEvent(QCloseEvent * close_event)
        // Make sure that no LFUN use this close to be closed View.
        theLyXFunc().setLyXView(0);
        // Make sure the timer time out will not trigger a statusbar update.
-       statusbar_timer_.stop();
+       d.statusbar_timer_.stop();
+
+       if (lyxrc.allow_geometry_session) {
+               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());
+               d.toolbars_->saveToolbarInfo();
+       }
 
-       theApp()->gui().unregisterView(id());
-       if (!theApp()->gui().viewIds().empty()) {
+       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();
@@ -311,18 +447,8 @@ void GuiView::closeEvent(QCloseEvent * close_event)
 
        quitting = true;
 
-       if (view()->buffer()) {
-               // save cursor position for opened files to .lyx/session
-               // only bottom (whole doc) level pit and pos is saved.
-               LyX::ref().session().lastFilePos().save(
-                       FileName(buffer()->fileName()),
-                       boost::tie(view()->cursor().bottom().pit(),
-                       view()->cursor().bottom().pos()));
-       }
-
        // this is the place where we leave the frontend.
        // it is the only point at which we start quitting.
-       saveGeometry();
        close_event->accept();
        // quit the event loop
        qApp->quit();
@@ -345,9 +471,8 @@ void GuiView::dropEvent(QDropEvent* event)
        if (files.isEmpty())
                return;
 
-       LYXERR(Debug::GUI) << BOOST_CURRENT_FUNCTION
-               << " got URLs!" << endl;
-       for (int i = 0; i!=files.size(); ++i) {
+       LYXERR(Debug::GUI, BOOST_CURRENT_FUNCTION << " got URLs!");
+       for (int i = 0; i != files.size(); ++i) {
                string const file = support::os::internal_path(fromqstr(
                        files.at(i).toLocalFile()));
                if (!file.empty())
@@ -356,483 +481,1026 @@ void GuiView::dropEvent(QDropEvent* event)
 }
 
 
-void GuiView::saveGeometry()
+void GuiView::message(docstring const & str)
+{
+       statusBar()->showMessage(toqstr(str));
+       d.statusbar_timer_.stop();
+       d.statusbar_timer_.start(statusbar_timer_value);
+}
+
+
+void GuiView::smallSizedIcons()
+{
+       setIconSize(QSize(d.smallIconSize, d.smallIconSize));
+}
+
+
+void GuiView::normalSizedIcons()
+{
+       setIconSize(QSize(d.normalIconSize, d.normalIconSize));
+}
+
+
+void GuiView::bigSizedIcons()
+{
+       setIconSize(QSize(d.bigIconSize, d.bigIconSize));
+}
+
+
+void GuiView::clearMessage()
 {
-       static bool done = false;
-       if (done)
+       if (!hasFocus())
                return;
-       else
-               done = true;
-
-       // FIXME:
-       // change the ifdef to 'geometry = normalGeometry();' only
-       // when Trolltech has fixed the broken normalGeometry on X11:
-       // http://www.trolltech.com/developer/task-tracker/index_html?id=119684+&method=entry
-       // Then also the moveEvent, resizeEvent, and the
-       // code for floatingGeometry_ can be removed;
-       // adjust GuiView::setGeometry()
-
-       QRect normal_geometry;
-       int maximized;
-#ifdef Q_WS_WIN
-       normal_geometry = normalGeometry();
-       if (isMaximized()) {
-               maximized = CompletelyMaximized;
-       } else {
-               maximized = NotMaximized;
-       }
-#else
-       normal_geometry = updateFloatingGeometry();
-
-       QDesktopWidget& dw = *qApp->desktop();
-       QRect desk = dw.availableGeometry(dw.primaryScreen());
-       // Qt bug on Linux: load completely maximized, vert max. save-> frameGeometry().height() is wrong
-       if (isMaximized() && desk.width() <= frameGeometry().width() && desk.height() <= frameGeometry().height()) {
-               maximized = CompletelyMaximized;
-               // maximizing does not work when the window is allready hor. or vert. maximized
-               // Tested only on KDE
-               int dh = frameGeometry().height() - height();
-               if (desk.height() <= normal_geometry.height() + dh)
-                       normal_geometry.setHeight(normal_geometry.height() - 1);
-               int dw = frameGeometry().width() - width();
-               if (desk.width() <= normal_geometry.width() + dw)
-                       normal_geometry.setWidth(normal_geometry.width() - 1);
-       } else if (desk.height() <= frameGeometry().height()) {
-               maximized = VerticallyMaximized;
-       } else if (desk.width() <= frameGeometry().width()) {
-               maximized = HorizontallyMaximized;
-       } else {
-               maximized = NotMaximized;
-       }
+       theLyXFunc().setLyXView(this);
+       statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
+       d.statusbar_timer_.stop();
+}
 
 
-#endif
-       // save windows size and position
-       Session & session = LyX::ref().session();
-       session.sessionInfo().save("WindowWidth", convert<string>(normal_geometry.width()));
-       session.sessionInfo().save("WindowHeight", convert<string>(normal_geometry.height()));
-       session.sessionInfo().save("WindowMaximized", convert<string>(maximized));
-       session.sessionInfo().save("IconSizeXY", convert<string>(iconSize().width()));
-       if (lyxrc.geometry_xysaved) {
-               session.sessionInfo().save("WindowPosX", convert<string>(normal_geometry.x() + d.posx_offset));
-               session.sessionInfo().save("WindowPosY", convert<string>(normal_geometry.y() + d.posy_offset));
-       }
-       getToolbars().saveToolbarInfo();
-}
-
-
-void GuiView::setGeometry(unsigned int width,
-                         unsigned int height,
-                         int posx, int posy,
-                         int maximized,
-                         unsigned int iconSizeXY,
-                         const string & geometryArg)
-{
-       // use last value (not at startup)
-       if (d.lastIconSize != 0)
-               setIconSize(d.lastIconSize);
-       else if (iconSizeXY != 0)
-               setIconSize(iconSizeXY);
-       else
-               setIconSize(d.normalIconSize);
-
-       // only true when the -geometry option was NOT used
-       if (width != 0 && height != 0) {
-               if (posx != -1 && posy != -1) {
-                       // if there are startup positioning problems:
-                       // http://doc.trolltech.com/4.2/qdesktopwidget.html
-                       QDesktopWidget& dw = *qApp->desktop();
-                       if (dw.isVirtualDesktop()) {
-                               if(!dw.geometry().contains(posx, posy)) {
-                                       posx = 50;
-                                       posy = 50;
-                               }
-                       } else {
-                               // Which system doesn't use a virtual desktop?
-                               // TODO save also last screen number and check if it is still availabe.
-                       }
-#ifdef Q_WS_WIN
-                       // FIXME: use setGeometry only when Trolltech has fixed the qt4/X11 bug
-                       QWidget::setGeometry(posx, posy, width, height);
-#else
-                       resize(width, height);
-                       move(posx, posy);
-#endif
+void GuiView::updateWindowTitle(GuiWorkArea * wa)
+{
+       if (wa != d.current_work_area_)
+               return;
+       setWindowTitle(qt_("LyX: ") + wa->windowTitle());
+       setWindowIconText(wa->windowIconText());
+}
+
+
+void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
+{
+       disconnectBuffer();
+       disconnectBufferView();
+       connectBufferView(wa->bufferView());
+       connectBuffer(wa->bufferView().buffer());
+       d.current_work_area_ = wa;
+       QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
+               this, SLOT(updateWindowTitle(GuiWorkArea *)));
+       updateWindowTitle(wa);
+
+       updateToc();
+       // Buffer-dependent dialogs should be updated or
+       // hidden. This should go here because some dialogs (eg ToC)
+       // require bv_->text.
+       updateBufferDependent(true);
+       updateToolbars();
+       updateLayoutList();
+       updateStatusBar();
+}
+
+
+void GuiView::updateStatusBar()
+{
+       // let the user see the explicit message
+       if (d.statusbar_timer_.isActive())
+               return;
+
+       statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
+}
+
+
+bool GuiView::hasFocus() const
+{
+       return qApp->activeWindow() == this;
+}
+
+
+bool GuiView::event(QEvent * e)
+{
+       switch (e->type())
+       {
+       // Useful debug code:
+       //case QEvent::ActivationChange:
+       //case QEvent::WindowDeactivate:
+       //case QEvent::Paint:
+       //case QEvent::Enter:
+       //case QEvent::Leave:
+       //case QEvent::HoverEnter:
+       //case QEvent::HoverLeave:
+       //case QEvent::HoverMove:
+       //case QEvent::StatusTip:
+       //case QEvent::DragEnter:
+       //case QEvent::DragLeave:
+       //case QEvent::Drop:
+       //      break;
+
+       case QEvent::WindowActivate: {
+               guiApp->setCurrentView(*this);
+               if (d.current_work_area_) {
+                       BufferView & bv = d.current_work_area_->bufferView();
+                       connectBufferView(bv);
+                       connectBuffer(bv.buffer());
+                       // The document structure, name and dialogs might have
+                       // changed in another view.
+                       updateBufferDependent(true);
                } else {
-                       resize(width, height);
+                       setWindowTitle(qt_("LyX"));
+                       setWindowIconText(qt_("LyX"));
                }
-
-               // remember original size
-               floatingGeometry_ = QRect(posx, posy, width, height);
-
-               if (maximized != NotMaximized) {
-                       if (maximized == CompletelyMaximized) {
-                               setWindowState(Qt::WindowMaximized);
-                       } else {
-#ifndef Q_WS_WIN
-                               // TODO How to set by the window manager?
-                               //      setWindowState(Qt::WindowVerticallyMaximized);
-                               //      is not possible
-                               QDesktopWidget& dw = *qApp->desktop();
-                               QRect desk = dw.availableGeometry(dw.primaryScreen());
-                               if (maximized == VerticallyMaximized)
-                                       resize(width, desk.height());
-                               if (maximized == HorizontallyMaximized)
-                                       resize(desk.width(), height);
-#endif
-                       }
+               return QMainWindow::event(e);
+       }
+       case QEvent::ShortcutOverride: {
+               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;
                }
        }
-       else
-       {
-               // FIXME: move this code into parse_geometry() (LyX.cpp)
-#ifdef Q_WS_WIN
-               int x, y;
-               int w, h;
-               QRegExp re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)([+-][0-9]*)){0,1}" );
-               re.indexIn(toqstr(geometryArg.c_str()));
-               w = re.cap(1).toInt();
-               h = re.cap(2).toInt();
-               x = re.cap(3).toInt();
-               y = re.cap(4).toInt();
-               QWidget::setGeometry( x, y, w, h );
-#else
-               // silence warning
-               (void)geometryArg;
-#endif
+       default:
+               return QMainWindow::event(e);
        }
+}
 
-       show();
 
-       // For an unknown reason, the Window title update is not effective for
-       // the second windows up until it is shown on screen (Qt bug?).
-       updateWindowTitle();
+bool GuiView::focusNextPrevChild(bool /*next*/)
+{
+       setFocus();
+       return true;
+}
 
-       // after show geometry() has changed (Qt bug?)
-       // we compensate the drift when storing the position
-       d.posx_offset = 0;
-       d.posy_offset = 0;
-       if (width != 0 && height != 0)
-               if (posx != -1 && posy != -1) {
-#ifdef Q_WS_WIN
-                       d.posx_offset = posx - normalGeometry().x();
-                       d.posy_offset = posy - normalGeometry().y();
-#else
-#ifndef Q_WS_MACX
-                       if (maximized == NotMaximized) {
-                               d.posx_offset = posx - geometry().x();
-                               d.posy_offset = posy - geometry().y();
-                       }
-#endif
-#endif
-               }
+
+void GuiView::setBusy(bool yes)
+{
+       if (d.current_work_area_) {
+               d.current_work_area_->setUpdatesEnabled(!yes);
+               if (yes)
+                       d.current_work_area_->stopBlinkingCursor();
+               else
+                       d.current_work_area_->startBlinkingCursor();
+       }
+
+       if (yes)
+               QApplication::setOverrideCursor(Qt::WaitCursor);
+       else
+               QApplication::restoreOverrideCursor();
 }
 
 
-void GuiView::updateMenu(QAction * /*action*/)
+GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
 {
-       menubar_->update();
+       GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
+
+       if (tbinfo.flags & ToolbarInfo::TOP) {
+               if (newline)
+                       addToolBarBreak(Qt::TopToolBarArea);
+               addToolBar(Qt::TopToolBarArea, toolBar);
+       }
+
+       if (tbinfo.flags & ToolbarInfo::BOTTOM) {
+// Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
+#if (QT_VERSION >= 0x040202)
+               if (newline)
+                       addToolBarBreak(Qt::BottomToolBarArea);
+#endif
+               addToolBar(Qt::BottomToolBarArea, toolBar);
+       }
+
+       if (tbinfo.flags & ToolbarInfo::LEFT) {
+// Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
+#if (QT_VERSION >= 0x040202)
+               if (newline)
+                       addToolBarBreak(Qt::LeftToolBarArea);
+#endif
+               addToolBar(Qt::LeftToolBarArea, toolBar);
+       }
+
+       if (tbinfo.flags & ToolbarInfo::RIGHT) {
+// Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
+#if (QT_VERSION >= 0x040202)
+               if (newline)
+                       addToolBarBreak(Qt::RightToolBarArea);
+#endif
+               addToolBar(Qt::RightToolBarArea, toolBar);
+       }
+
+       // The following does not work so I cannot restore to exact toolbar location
+       /*
+       ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
+       toolBar->move(tbinfo.posx, tbinfo.posy);
+       */
+
+       return toolBar;
 }
 
 
-void GuiView::setWindowTitle(docstring const & t, docstring const & it)
+GuiWorkArea * GuiView::workArea(Buffer & buffer)
 {
-       QString title = windowTitle();
-       QString new_title = toqstr(t);
-       if (title != new_title) {
-               QMainWindow::setWindowTitle(new_title);
-               QMainWindow::setWindowIconText(toqstr(it));
+       for (int i = 0; i != d.splitter_->count(); ++i) {
+               GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
+               if (wa)
+                       return wa;
        }
+       return 0;
 }
 
 
-void GuiView::addCommandBuffer(QToolBar * toolbar)
+GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
 {
-       commandbuffer_ = new QCommandBuffer(this, *controlcommand_);
-       focus_command_buffer.connect(boost::bind(&GuiView::focus_command_widget, this));
-       toolbar->addWidget(commandbuffer_);
+
+       // Automatically create a TabWorkArea if there are none yet.
+       if (!d.splitter_->count())
+               addTabWorkArea();
+
+       TabWorkArea * tab_widget = d.currentTabWorkArea();
+       return tab_widget->addWorkArea(buffer, *this);
 }
 
 
-void GuiView::message(docstring const & str)
+void GuiView::addTabWorkArea()
 {
-       statusBar()->showMessage(toqstr(str));
-       statusbar_timer_.stop();
-       statusbar_timer_.start(statusbar_timer_value);
+       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_);
 }
 
 
-void GuiView::clearMessage()
+GuiWorkArea const * GuiView::currentWorkArea() const
 {
-       update_view_state_qt();
+       return d.current_work_area_;
 }
 
 
-void GuiView::setIconSize(unsigned int size)
+void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
 {
-       d.lastIconSize = size;
-       QMainWindow::setIconSize(QSize(size, size));
+       BOOST_ASSERT(work_area);
+
+       // Changing work area can result from opening a file so
+       // update the toc in any case.
+       updateToc();
+
+       GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
+       d.current_work_area_ = wa;
+       for (int i = 0; i != d.splitter_->count(); ++i) {
+               if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
+                       return;
+       }
 }
 
 
-void GuiView::smallSizedIcons()
+void GuiView::removeWorkArea(GuiWorkArea * work_area)
 {
-       setIconSize(d.smallIconSize);
+       BOOST_ASSERT(work_area);
+       GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
+       if (gwa == d.current_work_area_) {
+               disconnectBuffer();
+               disconnectBufferView();
+               hideBufferDependent();
+               d.current_work_area_ = 0;
+       }
+
+       // removing a work area often results from closing a file so
+       // update the toc in any case.
+       updateToc();
+
+       for (int i = 0; i != d.splitter_->count(); ++i) {
+               TabWorkArea * twa = d.tabWorkArea(i);
+               if (!twa->removeWorkArea(gwa))
+                       // 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;
+                       break;
+               }
+
+               if (d.current_work_area_)
+                       // This means that we are not closing the current GuiWorkArea;
+                       break;
+
+               // Switch to the next GuiWorkArea in the found TabWorkArea.
+               d.current_work_area_ = twa->currentWorkArea();
+               break;
+       }
+
+       if (d.splitter_->count() == 0)
+               // No more work area, switch to the background widget.
+               d.setBackground();
 }
 
 
-void GuiView::normalSizedIcons()
+void GuiView::setLayoutDialog(GuiLayoutBox * layout)
 {
-       setIconSize(d.normalIconSize);
+       d.layout_ = layout;
 }
 
 
-void GuiView::bigSizedIcons()
+void GuiView::updateLayoutList()
 {
-       setIconSize(d.bigIconSize);
+       if (d.layout_)
+               d.layout_->updateContents(false);
 }
 
 
-void GuiView::focus_command_widget()
+void GuiView::updateToolbars()
 {
-       if (commandbuffer_)
-               commandbuffer_->focus_command();
+       if (d.current_work_area_) {
+               bool const math =
+                       d.current_work_area_->bufferView().cursor().inMathed();
+               bool const table =
+                       lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
+               bool const review =
+                       lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
+                       lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
+
+               d.toolbars_->update(math, table, review);
+       } else
+               d.toolbars_->update(false, false, false);
+
+       // update read-only status of open dialogs.
+       checkStatus();
 }
 
 
-void GuiView::update_view_state_qt()
+Buffer * GuiView::buffer()
 {
-       if (!hasFocus())
-               return;
-       theLyXFunc().setLyXView(this);
-       statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
-       statusbar_timer_.stop();
+       if (d.current_work_area_)
+               return &d.current_work_area_->bufferView().buffer();
+       return 0;
 }
 
 
-void GuiView::initTab(QWidget* workarea)
+Buffer const * GuiView::buffer() const
 {
-       // construct the TabWidget with 'false' to have the tabbar at the bottom
-       d.tabWidget = new TabWidget(workarea, true);
-       setCentralWidget(d.tabWidget);
-       QObject::connect(d.tabWidget->tabbar, SIGNAL(currentChanged(int)),
-                       this, SLOT(currentTabChanged(int)));
-       QObject::connect(d.tabWidget->closeTabButton, SIGNAL(clicked()),
-                       this, SLOT(closeCurrentTab()));
+       if (d.current_work_area_)
+               return &d.current_work_area_->bufferView().buffer();
+       return 0;
 }
 
 
-void GuiView::updateTab()
+void GuiView::setBuffer(Buffer * newBuffer)
 {
-       std::vector<string> const & names = theBufferList().getFileNames();
+       BOOST_ASSERT(newBuffer);
+       setBusy(true);
 
-       string cur_title;
-       if (view()->buffer()) {
-               cur_title = view()->buffer()->fileName();
+       GuiWorkArea * wa = workArea(*newBuffer);
+       if (wa == 0) {
+               updateLabels(*newBuffer->masterBuffer());
+               wa = addWorkArea(*newBuffer);
+       } else {
+               //Disconnect the old buffer...there's no new one.
+               disconnectBuffer();
        }
+       connectBuffer(*newBuffer);
+       connectBufferView(wa->bufferView());
+       setCurrentWorkArea(wa);
 
-       // avoid unnecessary tabbar rebuild:
-       // check if something has changed
-       if (d.tabnames == names && d.cur_title == cur_title)
-               return;
-       d.tabnames = names;
-       d.cur_title = cur_title;
+       setBusy(false);
+}
 
-       QTabBar & tabbar = *d.tabWidget->tabbar;
 
-       // update when all is done
-       tabbar.blockSignals(true);
+void GuiView::connectBuffer(Buffer & buf)
+{
+       buf.setGuiDelegate(this);
+}
 
-       // remove all tab bars
-       d.tabWidget->clearTabbar();
 
-       // rebuild tabbar and function map from scratch
-       if (names.size() > 1) {
-               for(size_t i = 0; i < names.size(); i++) {
-                       tabbar.addTab(toqstr(makeDisplayPath(names[i], 30)));
-                       // set current tab
-                       if (names[i] == cur_title)
-                               tabbar.setCurrentIndex(i);
-               }
-       }
-       tabbar.blockSignals(false);
-       d.tabWidget->hideTabsIfNecessary();
+void GuiView::disconnectBuffer()
+{
+       if (d.current_work_area_)
+               d.current_work_area_->bufferView().setGuiDelegate(0);
 }
 
 
-void GuiView::closeCurrentTab()
+void GuiView::connectBufferView(BufferView & bv)
 {
-       dispatch(FuncRequest(LFUN_BUFFER_CLOSE));
+       bv.setGuiDelegate(this);
 }
 
 
-void GuiView::currentTabChanged(int i)
+void GuiView::disconnectBufferView()
 {
-       BOOST_ASSERT(i >= 0 && size_type(i) < d.tabnames.size());
-       dispatch(FuncRequest(LFUN_BUFFER_SWITCH, d.tabnames[i]));
+       if (d.current_work_area_)
+               d.current_work_area_->bufferView().setGuiDelegate(0);
 }
 
 
-void GuiView::updateStatusBar()
+void GuiView::errors(string const & error_type)
 {
-       // let the user see the explicit message
-       if (statusbar_timer_.isActive())
+       ErrorList & el = buffer()->errorList(error_type);
+       if (!el.empty())
+               showDialog("errorlist", error_type);
+}
+
+
+void GuiView::updateDialog(string const & name, string const & data)
+{
+       if (!isDialogVisible(name))
                return;
 
-       statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
+       std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+       if (it == d.dialogs_.end())
+               return;
+
+       Dialog * const dialog = it->second.get();
+       if (dialog->isVisibleView())
+               dialog->updateData(data);
 }
 
 
-void GuiView::activated(FuncRequest const & func)
+BufferView * GuiView::view()
 {
-       dispatch(func);
+       return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
 }
 
 
-bool GuiView::hasFocus() const
+void GuiView::updateToc()
 {
-       return qApp->activeWindow() == this;
+       updateDialog("toc", "");
 }
 
 
-QRect  GuiView::updateFloatingGeometry()
+void GuiView::updateEmbeddedFiles()
 {
-       QDesktopWidget& dw = *qApp->desktop();
-       QRect desk = dw.availableGeometry(dw.primaryScreen());
-       // remember only non-maximized sizes
-       if (!isMaximized() && desk.width() > frameGeometry().width() && desk.height() > frameGeometry().height()) {
-               floatingGeometry_ = QRect(x(), y(), width(), height());
-       }
-       return floatingGeometry_;
+       updateDialog("embedding", "");
 }
 
 
-void GuiView::resizeEvent(QResizeEvent *)
+void GuiView::autoSave()
 {
-       updateFloatingGeometry();
+       LYXERR(Debug::INFO, "Running autoSave()");
+
+       if (buffer())
+               view()->buffer().autoSave();
 }
 
 
-void GuiView::moveEvent(QMoveEvent *)
+void GuiView::resetAutosaveTimers()
 {
-       updateFloatingGeometry();
+       if (lyxrc.autosave)
+               d.autosave_timeout_->restart();
 }
 
 
-bool GuiView::event(QEvent * e)
+FuncStatus GuiView::getStatus(FuncRequest const & cmd)
 {
-       switch (e->type())
-       {
-       // Useful debug code:
-       //case QEvent::WindowActivate:
-       //case QEvent::ActivationChange:
-       //case QEvent::WindowDeactivate:
-       //case QEvent::Paint:
-       //case QEvent::Enter:
-       //case QEvent::Leave:
-       //case QEvent::HoverEnter:
-       //case QEvent::HoverLeave:
-       //case QEvent::HoverMove:
-       //case QEvent::StatusTip:
-       //case QEvent::DragEnter:
-       //case QEvent::DragLeave:
-       //case QEvent::Drop:
-       //      break;
+       FuncStatus flag;
+       bool enable = true;
+       Buffer * buf = buffer();
 
-       case QEvent::ShortcutOverride: {
-               QKeyEvent * ke = static_cast<QKeyEvent*>(e);
-               if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
-                       boost::shared_ptr<QKeySymbol> sym(new QKeySymbol);
-                       sym->set(ke);
-                       BOOST_ASSERT(work_area_);
-                       work_area_->processKeySym(sym, key_modifier::none);
-                       e->accept();
-                       return true;
+       /* In LyX/Mac, when a dialog is open, the menus of the
+          application can still be accessed without giving focus to
+          the main window. In this case, we want to disable the menu
+          entries that are buffer-related.
+
+          Note that this code is not perfect, as bug 1941 attests:
+          http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
+       */
+       if (cmd.origin == FuncRequest::MENU && !hasFocus())
+               buf = 0;
+
+       switch(cmd.action) {
+       case LFUN_TOOLBAR_TOGGLE:
+               flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
+               break;
+
+       case LFUN_DIALOG_TOGGLE:
+               flag.setOnOff(isDialogVisible(cmd.getArg(0)));
+               // fall through to set "enable"
+       case LFUN_DIALOG_SHOW: {
+               string const name = cmd.getArg(0);
+               if (!buf)
+                       enable = name == "aboutlyx"
+                               || name == "file" //FIXME: should be removed.
+                               || name == "prefs"
+                               || name == "texinfo";
+               else if (name == "print")
+                       enable = buf->isExportable("dvi")
+                               && lyxrc.print_command != "none";
+               else if (name == "character") {
+                       if (!view())
+                               enable = false;
+                       else {
+                               InsetCode ic = view()->cursor().inset().lyxCode();
+                               enable = ic != ERT_CODE && ic != LISTINGS_CODE;
+                       }
                }
+               else if (name == "latexlog")
+                       enable = FileName(buf->logName()).isFileReadable();
+               else if (name == "spellchecker")
+#if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
+                       enable = !buf->isReadonly();
+#else
+                       enable = false;
+#endif
+               else if (name == "vclog")
+                       enable = buf->lyxvc().inUse();
+               break;
+       }
+
+       case LFUN_DIALOG_UPDATE: {
+               string const name = cmd.getArg(0);
+               if (!buf)
+                       enable = name == "prefs";
+               break;
        }
+
        default:
-               return QMainWindow::event(e);
+               if (!view()) {
+                       enable = false;
+                       break;
+               }
        }
+
+       if (!enable)
+               flag.enabled(false);
+
+       return flag;
 }
 
 
-bool GuiView::focusNextPrevChild(bool /*next*/)
+void GuiView::dispatch(FuncRequest const & cmd)
 {
-       setFocus();
-       return true;
+       Buffer * buf = buffer();
+       switch(cmd.action) {
+               case LFUN_BUFFER_SWITCH:
+                       setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
+                       break;
+
+               case LFUN_COMMAND_EXECUTE: {
+                       bool const show_it = cmd.argument() != "off";
+                       d.toolbars_->showCommandBuffer(show_it);
+                       break;
+               }
+               case LFUN_DROP_LAYOUTS_CHOICE:
+                       if (d.layout_)
+                               d.layout_->showPopup();
+                       break;
+
+               case LFUN_MENU_OPEN:
+                       d.menubar_->openByName(toqstr(cmd.argument()));
+                       break;
+
+               case LFUN_TOOLBAR_TOGGLE: {
+                       string const name = cmd.getArg(0);
+                       bool const allowauto = cmd.getArg(1) == "allowauto";
+                       // it is possible to get current toolbar status like this,...
+                       // but I decide to obey the order of ToolbarBackend::flags
+                       // and disregard real toolbar status.
+                       // toolbars_->saveToolbarInfo();
+                       //
+                       // toggle state on/off/auto
+                       d.toolbars_->toggleToolbarState(name, allowauto);
+                       // update toolbar
+                       updateToolbars();
+
+                       ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
+                       if (!tbi) {
+                               message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
+                               break;
+                       }
+                       docstring state;
+                       if (tbi->flags & ToolbarInfo::ON)
+                               state = _("on");
+                       else if (tbi->flags & ToolbarInfo::OFF)
+                               state = _("off");
+                       else if (tbi->flags & ToolbarInfo::AUTO)
+                               state = _("auto");
+
+                       message(bformat(_("Toolbar \"%1$s\" state set to %2$s"), 
+                                          _(tbi->gui_name), state));
+                       break;
+               }
+
+               case LFUN_DIALOG_UPDATE: {
+                       string const name = to_utf8(cmd.argument());
+                       // Can only update a dialog connected to an existing inset
+                       Inset * inset = getOpenInset(name);
+                       if (inset) {
+                               FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
+                               inset->dispatch(view()->cursor(), fr);
+                       } else if (name == "paragraph") {
+                               lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
+                       } else if (name == "prefs") {
+                               updateDialog(name, string());
+                       }
+                       break;
+               }
+
+               case LFUN_DIALOG_TOGGLE: {
+                       if (isDialogVisible(cmd.getArg(0)))
+                               dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
+                       else
+                               dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
+                       break;
+               }
+
+               case LFUN_DIALOG_DISCONNECT_INSET:
+                       disconnectDialog(to_utf8(cmd.argument()));
+                       break;
+
+               case LFUN_DIALOG_HIDE: {
+                       if (quitting)
+                               break;
+                       guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
+                       break;
+               }
+
+               case LFUN_DIALOG_SHOW: {
+                       string const name = cmd.getArg(0);
+                       string data = trim(to_utf8(cmd.argument()).substr(name.size()));
+
+                       if (name == "character") {
+                               data = freefont2string();
+                               if (!data.empty())
+                                       showDialog("character", data);
+                       } else if (name == "latexlog") {
+                               Buffer::LogType type; 
+                               string const logfile = buf->logName(&type);
+                               switch (type) {
+                               case Buffer::latexlog:
+                                       data = "latex ";
+                                       break;
+                               case Buffer::buildlog:
+                                       data = "literate ";
+                                       break;
+                               }
+                               data += Lexer::quoteString(logfile);
+                               showDialog("log", data);
+                       } else if (name == "vclog") {
+                               string const data = "vc " +
+                                       Lexer::quoteString(buf->lyxvc().getLogFile());
+                               showDialog("log", data);
+                       } else
+                               showDialog(name, data);
+                       break;
+               }
+
+               default:
+                       theLyXFunc().setLyXView(this);
+                       lyx::dispatch(cmd);
+       }
 }
 
 
-void GuiView::show()
+Buffer const * GuiView::updateInset(Inset const * inset)
 {
-       QMainWindow::setWindowTitle(qt_("LyX"));
-       QMainWindow::show();
-       updateFloatingGeometry();
+       if (!d.current_work_area_)
+               return 0;
+
+       if (inset)
+               d.current_work_area_->scheduleRedraw();
+
+       return &d.current_work_area_->bufferView().buffer();
 }
 
 
-void GuiView::busy(bool yes)
+void GuiView::restartCursor()
 {
-       BOOST_ASSERT(work_area_);
-       static_cast<GuiWorkArea *>(work_area_)->setUpdatesEnabled(!yes);
+       /* When we move around, or type, it's nice to be able to see
+        * the cursor immediately after the keypress.
+        */
+       if (d.current_work_area_)
+               d.current_work_area_->startBlinkingCursor();
+
+       // Take this occasion to update the toobars and layout list.
+       updateLayoutList();
+       updateToolbars();
+}
 
-       if (yes) {
-               work_area_->stopBlinkingCursor();
-               QApplication::setOverrideCursor(Qt::WaitCursor);
-       }
-       else {
-               work_area_->startBlinkingCursor();
-               QApplication::restoreOverrideCursor();
+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.
+
+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",
+
+#ifdef HAVE_LIBAIKSAURUS
+"thesaurus",
+#endif
+
+"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
+
+char const * const * const end_dialognames =
+       dialognames + (sizeof(dialognames) / sizeof(char *));
+
+class cmpCStr {
+public:
+       cmpCStr(char const * name) : name_(name) {}
+       bool operator()(char const * other) {
+               return strcmp(other, name_) == 0;
        }
+private:
+       char const * name_;
+};
+
+
+bool isValidName(string const & name)
+{
+       return std::find_if(dialognames, end_dialognames,
+                           cmpCStr(name.c_str())) != end_dialognames;
 }
 
+} // namespace anon
+
 
-Toolbars::ToolbarPtr GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
+void GuiView::resetDialogs()
 {
-       QLToolbar * Tb = new QLToolbar(tbinfo, *this);
+       // Make sure that no LFUN uses any LyXView.
+       theLyXFunc().setLyXView(0);
+       d.toolbars_->init();
+       d.menubar_->init();
+       if (d.layout_)
+               d.layout_->updateContents(true);
+}
 
-       if (tbinfo.flags & ToolbarInfo::TOP) {
-               if (newline)
-                       addToolBarBreak(Qt::TopToolBarArea);
-               addToolBar(Qt::TopToolBarArea, Tb);
+
+Dialog * GuiView::find_or_build(string const & name)
+{
+       if (!isValidName(name))
+               return 0;
+
+       std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
+
+       if (it != d.dialogs_.end())
+               return it->second.get();
+
+       d.dialogs_[name].reset(build(name));
+       return d.dialogs_[name].get();
+}
+
+
+void GuiView::showDialog(string const & name, string const & data,
+       Inset * inset)
+{
+       if (d.in_show_)
+               return;
+
+       d.in_show_ = true;
+       Dialog * dialog = find_or_build(name);
+       if (dialog) {
+               dialog->showData(data);
+               if (inset)
+                       d.open_insets_[name] = inset;
        }
+       d.in_show_ = false;
+}
 
-       if (tbinfo.flags & ToolbarInfo::BOTTOM) {
-// Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
-#if (QT_VERSION >= 0x040202)
-               if (newline)
-                       addToolBarBreak(Qt::BottomToolBarArea);
-#endif
-               addToolBar(Qt::BottomToolBarArea, Tb);
+
+bool GuiView::isDialogVisible(string const & name) const
+{
+       std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+       if (it == d.dialogs_.end())
+               return false;
+       return it->second.get()->isVisibleView();
+}
+
+
+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;
+
+       std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+       if (it == d.dialogs_.end())
+               return;
+
+       if (inset && inset != getOpenInset(name))
+               return;
+
+       Dialog * const dialog = it->second.get();
+       if (dialog->isVisibleView())
+               dialog->hide();
+       d.open_insets_[name] = 0;
+}
+
+
+void GuiView::disconnectDialog(string const & name)
+{
+       if (!isValidName(name))
+               return;
+
+       if (d.open_insets_.find(name) != d.open_insets_.end())
+               d.open_insets_[name] = 0;
+}
+
+
+Inset * GuiView::getOpenInset(string const & name) const
+{
+       if (!isValidName(name))
+               return 0;
+
+       std::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();
+
+       for(; it != end; ++it)
+               it->second->hide();
+}
+
+
+void GuiView::hideBufferDependent() const
+{
+       std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
+       std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+
+       for(; it != end; ++it) {
+               Dialog * dialog = it->second.get();
+               if (dialog->isBufferDependent())
+                       dialog->hide();
        }
+}
 
-       if (tbinfo.flags & ToolbarInfo::LEFT) {
-// Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
-#if (QT_VERSION >= 0x040202)
-               if (newline)
-                       addToolBarBreak(Qt::LeftToolBarArea);
-#endif
-               addToolBar(Qt::LeftToolBarArea, Tb);
+
+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();
+
+       for(; it != end; ++it) {
+               Dialog * dialog = it->second.get();
+               if (switched && dialog->isBufferDependent()) {
+                       if (dialog->isVisibleView() && dialog->initialiseParams(""))
+                               dialog->updateView();
+                       else
+                               dialog->hide();
+               } else {
+                       // A bit clunky, but the dialog will request
+                       // that the kernel provides it with the necessary
+                       // data.
+                       dialog->slotRestore();
+               }
        }
+}
 
-       if (tbinfo.flags & ToolbarInfo::RIGHT) {
-// Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
-#if (QT_VERSION >= 0x040202)
-               if (newline)
-                       addToolBarBreak(Qt::RightToolBarArea);
-#endif
-               addToolBar(Qt::RightToolBarArea, Tb);
+
+void GuiView::checkStatus()
+{
+       std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
+       std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+
+       for(; it != end; ++it) {
+               Dialog * const dialog = it->second.get();
+               if (dialog && dialog->isVisibleView())
+                       dialog->checkStatus();
        }
+}
+
 
-       // The following does not work so I cannot restore to exact toolbar location
-       /*
-       ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
-       Tb->move(tbinfo.posx, tbinfo.posy);
-       */
 
-       return Toolbars::ToolbarPtr(Tb);
+// will be replaced by a proper factory...
+Dialog * createGuiAbout(LyXView & lv);
+Dialog * createGuiBibitem(LyXView & lv);
+Dialog * createGuiBibtex(LyXView & lv);
+Dialog * createGuiBox(LyXView & lv);
+Dialog * createGuiBranch(LyXView & lv);
+Dialog * createGuiChanges(LyXView & lv);
+Dialog * createGuiCharacter(LyXView & lv);
+Dialog * createGuiCitation(LyXView & lv);
+Dialog * createGuiDelimiter(LyXView & lv);
+Dialog * createGuiDocument(LyXView & lv);
+Dialog * createGuiErrorList(LyXView & lv);
+Dialog * createGuiERT(LyXView & lv);
+Dialog * createGuiExternal(LyXView & lv);
+Dialog * createGuiFloat(LyXView & lv);
+Dialog * createGuiGraphics(LyXView & lv);
+Dialog * createGuiInclude(LyXView & lv);
+Dialog * createGuiIndex(LyXView & lv);
+Dialog * createGuiLabel(LyXView & lv);
+Dialog * createGuiListings(LyXView & lv);
+Dialog * createGuiLog(LyXView & lv);
+Dialog * createGuiMathMatrix(LyXView & lv);
+Dialog * createGuiNomenclature(LyXView & lv);
+Dialog * createGuiNote(LyXView & lv);
+Dialog * createGuiParagraph(LyXView & lv);
+Dialog * createGuiPreferences(LyXView & lv);
+Dialog * createGuiPrint(LyXView & lv);
+Dialog * createGuiRef(LyXView & lv);
+Dialog * createGuiSearch(LyXView & lv);
+Dialog * createGuiSendTo(LyXView & lv);
+Dialog * createGuiShowFile(LyXView & lv);
+Dialog * createGuiSpellchecker(LyXView & lv);
+Dialog * createGuiTabularCreate(LyXView & lv);
+Dialog * createGuiTabular(LyXView & lv);
+Dialog * createGuiTexInfo(LyXView & lv);
+Dialog * createGuiToc(LyXView & lv);
+Dialog * createGuiThesaurus(LyXView & lv);
+Dialog * createGuiHyperlink(LyXView & lv);
+Dialog * createGuiVSpace(LyXView & lv);
+Dialog * createGuiViewSource(LyXView & lv);
+Dialog * createGuiWrap(LyXView & lv);
+
+
+Dialog * GuiView::build(string const & name)
+{
+       BOOST_ASSERT(isValidName(name));
+
+       if (name == "aboutlyx")
+               return createGuiAbout(*this);
+       if (name == "bibitem")
+               return createGuiBibitem(*this);
+       if (name == "bibtex")
+               return createGuiBibtex(*this);
+       if (name == "box")
+               return createGuiBox(*this);
+       if (name == "branch")
+               return createGuiBranch(*this);
+       if (name == "changes")
+               return createGuiChanges(*this);
+       if (name == "character")
+               return createGuiCharacter(*this);
+       if (name == "citation")
+               return createGuiCitation(*this);
+       if (name == "document")
+               return createGuiDocument(*this);
+       if (name == "errorlist")
+               return createGuiErrorList(*this);
+       if (name == "ert")
+               return createGuiERT(*this);
+       if (name == "external")
+               return createGuiExternal(*this);
+       if (name == "file")
+               return createGuiShowFile(*this);
+       if (name == "findreplace")
+               return createGuiSearch(*this);
+       if (name == "float")
+               return createGuiFloat(*this);
+       if (name == "graphics")
+               return createGuiGraphics(*this);
+       if (name == "include")
+               return createGuiInclude(*this);
+       if (name == "index")
+               return createGuiIndex(*this);
+       if (name == "nomenclature")
+               return createGuiNomenclature(*this);
+       if (name == "label")
+               return createGuiLabel(*this);
+       if (name == "log")
+               return createGuiLog(*this);
+       if (name == "view-source")
+               return createGuiViewSource(*this);
+       if (name == "mathdelimiter")
+               return createGuiDelimiter(*this);
+       if (name == "mathmatrix")
+               return createGuiMathMatrix(*this);
+       if (name == "note")
+               return createGuiNote(*this);
+       if (name == "paragraph")
+               return createGuiParagraph(*this);
+       if (name == "prefs")
+               return createGuiPreferences(*this);
+       if (name == "print")
+               return createGuiPrint(*this);
+       if (name == "ref")
+               return createGuiRef(*this);
+       if (name == "sendto")
+               return createGuiSendTo(*this);
+       if (name == "spellchecker")
+               return createGuiSpellchecker(*this);
+       if (name == "tabular")
+               return createGuiTabular(*this);
+       if (name == "tabularcreate")
+               return createGuiTabularCreate(*this);
+       if (name == "texinfo")
+               return createGuiTexInfo(*this);
+#ifdef HAVE_LIBAIKSAURUS
+       if (name == "thesaurus")
+               return createGuiThesaurus(*this);
+#endif
+       if (name == "toc")
+               return createGuiToc(*this);
+       if (name == "href")
+               return createGuiHyperlink(*this);
+       if (name == "vspace")
+               return createGuiVSpace(*this);
+       if (name == "wrap")
+               return createGuiWrap(*this);
+       if (name == "listings")
+               return createGuiListings(*this);
+
+       return 0;
 }
 
+
 } // namespace frontend
 } // namespace lyx