]> 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 1c30baf32b9f27c83b9cd115c3312b5ef17eb13b..66ed4feccf20a3a701f07db5625580d9d449bad2 100644 (file)
 #include <config.h>
 
 #include "GuiView.h"
+#include "Dialog.h"
 
-#include "GuiImplementation.h"
+#include <boost/assert.hpp>
+
+using std::string;
+
+#include "GuiView.h"
+
+#include "GuiApplication.h"
 #include "GuiWorkArea.h"
 #include "GuiKeySymbol.h"
 #include "GuiMenubar.h"
 #include "GuiToolbar.h"
 #include "GuiToolbars.h"
-#include "Dialogs.h"
-#include "Gui.h"
 
 #include "qt_helpers.h"
 
-#include "frontends/Application.h"
-#include "frontends/Dialogs.h"
-#include "frontends/Gui.h"
-
-#include "support/filetools.h"
-#include "support/convert.h"
-#include "support/lstrings.h"
-#include "support/os.h"
-
 #include "buffer_funcs.h"
 #include "Buffer.h"
 #include "BufferList.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 "Paragraph.h"
 #include "TextClass.h"
 #include "ToolbarBackend.h"
 #include "version.h"
 
+#include "support/convert.h"
+#include "support/FileName.h"
 #include "support/lstrings.h"
-#include "support/filetools.h" // OnlyFilename()
+#include "support/os.h"
 #include "support/Timeout.h"
 
 #include <QAction>
 #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 <QUrl>
 
@@ -102,8 +104,7 @@ namespace frontend {
 
 using support::bformat;
 using support::FileName;
-using support::makeDisplayPath;
-using support::onlyFilename;
+using support::trim;
 
 namespace {
 
@@ -149,11 +150,27 @@ private:
 } // namespace anon
 
 
+typedef boost::shared_ptr<Dialog> DialogPtr;
+
 struct GuiView::GuiViewPrivate
 {
        GuiViewPrivate()
-               : current_work_area_(0), posx_offset(0), posy_offset(0)
-       {}
+               : 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();
+       }
 
        ~GuiViewPrivate()
        {
@@ -162,14 +179,9 @@ struct GuiView::GuiViewPrivate
                delete stack_widget_;
                delete menubar_;
                delete toolbars_;
+               delete autosave_timeout_;
        }
 
-       unsigned int smallIconSize;
-       unsigned int normalIconSize;
-       unsigned int bigIconSize;
-       // static needed by "New Window"
-       static unsigned int lastIconSize;
-
        QMenu * toolBarPopup(GuiView * parent)
        {
                // FIXME: translation
@@ -210,7 +222,7 @@ struct GuiView::GuiViewPrivate
 
        void initBackground()
        {
-               LYXERR(Debug::GUI) << "show banner: " << lyxrc.show_banner << endl;
+               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);
@@ -251,9 +263,6 @@ public:
        string cur_title;
 
        GuiWorkArea * current_work_area_;
-       int posx_offset;
-       int posy_offset;
-
        QSplitter * splitter_;
        QStackedWidget * stack_widget_;
        BackgroundWidget * bg_widget_;
@@ -261,69 +270,104 @@ public:
        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_;
+
        ///
-       docstring current_layout;
-};
+       std::map<std::string, Inset *> open_insets_;
 
+       ///
+       std::map<std::string, DialogPtr> dialogs_;
 
-unsigned int GuiView::GuiViewPrivate::lastIconSize = 0;
+       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),
-         d(*new GuiViewPrivate),
-               quitting_by_menu_(false),
-               autosave_timeout_(new Timeout(5000)),
-         dialogs_(new Dialogs(*this))
+       : 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) {
-               autosave_timeout_->timeout.connect(boost::bind(&GuiView::autoSave, this));
-               autosave_timeout_->setTimeout(lyxrc.autosave * 1000);
-               autosave_timeout_->start();
+               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.
        setWindowIcon(QPixmap(":/images/lyx.png"));
 #endif
 
+       // For Drag&Drop.
+       setAcceptDrops(true);
+
+       statusBar()->setSizeGripEnabled(true);
 
-       d.splitter_ = new QSplitter;
+       // Forbid too small unresizable window because it can happen
+       // with some window manager under X11.
+       setMinimumSize(300, 200);
 
-       d.initBackground();
-       LYXERR(Debug::GUI) << "stack widget!" << endl;
-       d.stack_widget_ = new QStackedWidget;
-       d.stack_widget_->addWidget(d.bg_widget_);
-       d.stack_widget_->addWidget(d.splitter_);
-       setCentralWidget(d.stack_widget_);
+       if (!lyxrc.allow_geometry_session)
+               // No session handling, default to a sane size.
+               setGeometry(50, 50, 690, 510);
 
-       // For Drag&Drop.
-       setAcceptDrops(true);
+       // 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()
 {
-       delete dialogs_;
-       delete autosave_timeout_;
        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);
@@ -331,7 +375,7 @@ void GuiView::close()
                        twa->closeAll();
        }
        QMainWindow::close();
-       quitting_by_menu_ = false;
+       d.quitting_by_menu_ = false;
 }
 
 
@@ -350,35 +394,11 @@ QMenu* GuiView::createPopupMenu()
 }
 
 
-void GuiView::init()
-{
-       // GuiToolbars *must* be initialised before GuiMenubar.
-       d.toolbars_ = new GuiToolbars(*this);
-       // FIXME: GuiToolbars::init() cannot be integrated in the ctor
-       // because LyXFunc::getStatus() needs a properly initialized
-       // GuiToolbars object (for LFUN_TOOLBAR_TOGGLE).
-       d.toolbars_->init();
-       d.menubar_ = new GuiMenubar(this, menubackend);
-
-       statusBar()->setSizeGripEnabled(true);
-
-       QObject::connect(&statusbar_timer_, SIGNAL(timeout()),
-               this, SLOT(clearMessage()));
-
-       d.setBackground();
-}
-
-
 void GuiView::showEvent(QShowEvent * e)
 {
-       if (lyxrc.allow_geometry_session) {
-               QSettings settings;
-               QString const key = "view-" + QString::number(id());
-               if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
-                       setGeometry(50, 50, 690, 510);
-               setIconSize(settings.value(key + "/icon_size").toSize());
-       } else
-               setGeometry(50, 50, 690, 510);
+       LYXERR(Debug::GUI, "Passed Geometry "
+               << size().height() << "x" << size().width()
+               << "+" << pos().x() << "+" << pos().y());
 
        if (d.splitter_->count() == 0)
                // No work area, switch to the background widget.
@@ -392,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;
@@ -402,18 +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());
+               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();
@@ -446,8 +471,7 @@ void GuiView::dropEvent(QDropEvent* event)
        if (files.isEmpty())
                return;
 
-       LYXERR(Debug::GUI) << BOOST_CURRENT_FUNCTION
-               << " got URLs!" << endl;
+       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()));
@@ -460,8 +484,8 @@ void GuiView::dropEvent(QDropEvent* event)
 void GuiView::message(docstring const & str)
 {
        statusBar()->showMessage(toqstr(str));
-       statusbar_timer_.stop();
-       statusbar_timer_.start(statusbar_timer_value);
+       d.statusbar_timer_.stop();
+       d.statusbar_timer_.start(statusbar_timer_value);
 }
 
 
@@ -489,7 +513,7 @@ void GuiView::clearMessage()
                return;
        theLyXFunc().setLyXView(this);
        statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
-       statusbar_timer_.stop();
+       d.statusbar_timer_.stop();
 }
 
 
@@ -517,9 +541,9 @@ void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
        // Buffer-dependent dialogs should be updated or
        // hidden. This should go here because some dialogs (eg ToC)
        // require bv_->text.
-       dialogs_->updateBufferDependent(true);
+       updateBufferDependent(true);
        updateToolbars();
-       updateLayoutChoice(false);
+       updateLayoutList();
        updateStatusBar();
 }
 
@@ -527,7 +551,7 @@ void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
 void GuiView::updateStatusBar()
 {
        // let the user see the explicit message
-       if (statusbar_timer_.isActive())
+       if (d.statusbar_timer_.isActive())
                return;
 
        statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
@@ -560,14 +584,14 @@ bool GuiView::event(QEvent * e)
        //      break;
 
        case QEvent::WindowActivate: {
-               theApp()->setCurrentView(*this);
+               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.
-                       dialogs_->updateBufferDependent(true);
+                       updateBufferDependent(true);
                } else {
                        setWindowTitle(qt_("LyX"));
                        setWindowIconText(qt_("LyX"));
@@ -682,23 +706,13 @@ GuiWorkArea * GuiView::workArea(Buffer & buffer)
 
 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
 {
-       GuiWorkArea * wa = new GuiWorkArea(buffer, *this);
-       wa->setUpdatesEnabled(false);
 
        // Automatically create a TabWorkArea if there are none yet.
        if (!d.splitter_->count())
                addTabWorkArea();
 
        TabWorkArea * tab_widget = d.currentTabWorkArea();
-       tab_widget->addTab(wa, wa->windowTitle());
-       QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
-               tab_widget, SLOT(updateTabText(GuiWorkArea *)));
-
-       wa->bufferView().updateMetrics();
-
-       // Hide tabbar if there's only one tab.
-       tab_widget->showBar(tab_widget->count() > 1);
-       return wa;
+       return tab_widget->addWorkArea(buffer, *this);
 }
 
 
@@ -742,7 +756,7 @@ void GuiView::removeWorkArea(GuiWorkArea * work_area)
        if (gwa == d.current_work_area_) {
                disconnectBuffer();
                disconnectBufferView();
-               dialogs_->hideBufferDependent();
+               hideBufferDependent();
                d.current_work_area_ = 0;
        }
 
@@ -778,34 +792,19 @@ void GuiView::removeWorkArea(GuiWorkArea * work_area)
 }
 
 
-void GuiView::updateLayoutChoice(bool force)
+void GuiView::setLayoutDialog(GuiLayoutBox * layout)
 {
-       // Don't show any layouts without a buffer
-       if (!buffer()) {
-               d.toolbars_->clearLayoutList();
-               return;
-       }
-
-       // Update the layout display
-       if (d.toolbars_->updateLayoutList(buffer()->params().getTextClassPtr(), force)) {
-               d.current_layout = buffer()->params().getTextClass().defaultLayoutName();
-       }
-
-       docstring const & layout = d.current_work_area_->bufferView().cursor().
-               innerParagraph().layout()->name();
-
-       if (layout != d.current_layout) {
-               d.toolbars_->setLayout(layout);
-               d.current_layout = layout;
-       }
+       d.layout_ = layout;
 }
 
 
-bool GuiView::isToolbarVisible(std::string const & id)
+void GuiView::updateLayoutList()
 {
-       return d.toolbars_->visible(id);
+       if (d.layout_)
+               d.layout_->updateContents(false);
 }
 
+
 void GuiView::updateToolbars()
 {
        if (d.current_work_area_) {
@@ -822,7 +821,7 @@ void GuiView::updateToolbars()
                d.toolbars_->update(false, false, false);
 
        // update read-only status of open dialogs.
-       dialogs_->checkStatus();
+       checkStatus();
 }
 
 
@@ -863,40 +862,6 @@ void GuiView::setBuffer(Buffer * newBuffer)
 }
 
 
-Buffer * GuiView::loadLyXFile(FileName const & filename, bool tolastfiles)
-{
-       setBusy(true);
-
-       Buffer * newBuffer = checkAndLoadLyXFile(filename);
-
-       if (!newBuffer) {
-               message(_("Document not loaded."));
-               updateStatusBar();
-               setBusy(false);
-               return 0;
-       }
-
-       GuiWorkArea * wa = workArea(*newBuffer);
-       if (wa == 0)
-               wa = addWorkArea(*newBuffer);
-
-       // scroll to the position when the file was last closed
-       if (lyxrc.use_lastfilepos) {
-               LastFilePosSection::FilePos filepos =
-                       LyX::ref().session().lastFilePos().load(filename);
-               // if successfully move to pit (returned par_id is not zero),
-               // update metrics and reset font
-               wa->bufferView().moveToPosition(filepos.pit, filepos.pos, 0, 0);
-       }
-
-       if (tolastfiles)
-               LyX::ref().session().lastFiles().add(filename);
-
-       setBusy(false);
-       return newBuffer;
-}
-
-
 void GuiView::connectBuffer(Buffer & buf)
 {
        buf.setGuiDelegate(this);
@@ -927,33 +892,22 @@ void GuiView::errors(string const & error_type)
 {
        ErrorList & el = buffer()->errorList(error_type);
        if (!el.empty())
-               dialogs_->show("errorlist", error_type);
+               showDialog("errorlist", error_type);
 }
 
 
-void GuiView::showDialog(string const & name)
-{
-       dialogs_->show(name);
-}
-
-
-void GuiView::showDialogWithData(string const & name, string const & data)
-{
-       dialogs_->show(name, data);
-}
-
-
-void GuiView::showInsetDialog(string const & name, string const & data,
-               Inset * inset)
+void GuiView::updateDialog(string const & name, string const & data)
 {
-       dialogs_->show(name, data, inset);
-}
+       if (!isDialogVisible(name))
+               return;
 
+       std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+       if (it == d.dialogs_.end())
+               return;
 
-void GuiView::updateDialog(string const & name, string const & data)
-{
-       if (dialogs_->visible(name))
-               dialogs_->update(name, data);
+       Dialog * const dialog = it->second.get();
+       if (dialog->isVisibleView())
+               dialog->updateData(data);
 }
 
 
@@ -977,7 +931,7 @@ void GuiView::updateEmbeddedFiles()
 
 void GuiView::autoSave()
 {
-       LYXERR(Debug::INFO) << "Running autoSave()" << endl;
+       LYXERR(Debug::INFO, "Running autoSave()");
 
        if (buffer())
                view()->buffer().autoSave();
@@ -987,12 +941,90 @@ void GuiView::autoSave()
 void GuiView::resetAutosaveTimers()
 {
        if (lyxrc.autosave)
-               autosave_timeout_->restart();
+               d.autosave_timeout_->restart();
+}
+
+
+FuncStatus GuiView::getStatus(FuncRequest const & cmd)
+{
+       FuncStatus flag;
+       bool enable = true;
+       Buffer * buf = buffer();
+
+       /* 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:
+               if (!view()) {
+                       enable = false;
+                       break;
+               }
+       }
+
+       if (!enable)
+               flag.enabled(false);
+
+       return flag;
 }
 
 
 void GuiView::dispatch(FuncRequest const & cmd)
 {
+       Buffer * buf = buffer();
        switch(cmd.action) {
                case LFUN_BUFFER_SWITCH:
                        setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
@@ -1004,7 +1036,8 @@ void GuiView::dispatch(FuncRequest const & cmd)
                        break;
                }
                case LFUN_DROP_LAYOUTS_CHOICE:
-                       d.toolbars_->openLayoutList();
+                       if (d.layout_)
+                               d.layout_->showPopup();
                        break;
 
                case LFUN_MENU_OPEN:
@@ -1042,6 +1075,70 @@ void GuiView::dispatch(FuncRequest const & cmd)
                        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);
@@ -1068,8 +1165,342 @@ void GuiView::restartCursor()
         */
        if (d.current_work_area_)
                d.current_work_area_->startBlinkingCursor();
+
+       // Take this occasion to update the toobars and layout list.
+       updateLayoutList();
+       updateToolbars();
+}
+
+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
+
+
+void GuiView::resetDialogs()
+{
+       // Make sure that no LFUN uses any LyXView.
+       theLyXFunc().setLyXView(0);
+       d.toolbars_->init();
+       d.menubar_->init();
+       if (d.layout_)
+               d.layout_->updateContents(true);
+}
+
+
+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;
+}
+
+
+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();
+       }
+}
+
+
+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();
+               }
+       }
+}
+
+
+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();
+       }
+}
+
+
+
+// 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