]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiView.cpp
Show Biblatex files in the TeXInfo dialog
[lyx.git] / src / frontends / qt4 / GuiView.cpp
index 8ce28113537d34f3704cdabe45b767f3b64562ea..2c481245680727876bc3d2c5f4171cec0a3608fb 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "GuiView.h"
 
-#include "Dialog.h"
 #include "DispatchResult.h"
 #include "FileDialog.h"
 #include "FontLoader.h"
 #include <QSplitter>
 #include <QStackedWidget>
 #include <QStatusBar>
-#if QT_VERSION >= 0x050000
 #include <QSvgRenderer>
-#endif
 #include <QtConcurrentRun>
 #include <QTime>
 #include <QTimer>
@@ -236,24 +233,18 @@ private:
 #endif
        }
 
-       qreal fontSize() {
-               return toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble();
-       }
-
-       QPointF textPosition() {
-               return QPointF(splashWidth()/2 - 16, splashHeigth() - 40);
+       qreal fontSize() const {
+               return toqstr(lyxrc.font_sizes[FONT_SIZE_NORMAL]).toDouble();
        }
 
-       QSize splashSize() {
-               return  QSize(width_ * pixelRatio(),height_ * pixelRatio());
+       QPointF textPosition() const {
+               return QPointF(width_/2 - 18, height_/2 + 45);
        }
 
-       double splashWidth() {
-               return splash_.width()/splashPixelRatio();
-       }
-
-       double splashHeigth() {
-               return splash_.height()/splashPixelRatio();
+       QSize splashSize() const {
+               return QSize(
+                       static_cast<unsigned int>(width_ * pixelRatio()),
+                       static_cast<unsigned int>(height_ * pixelRatio()));
        }
 
        /// Ratio between physical pixels and device-independent pixels of splash image
@@ -275,8 +266,12 @@ typedef shared_ptr<Dialog> DialogPtr;
 } // namespace anon
 
 
-struct GuiView::GuiViewPrivate
+class GuiView::GuiViewPrivate
 {
+       /// noncopyable
+       GuiViewPrivate(GuiViewPrivate const &);
+       void operator=(GuiViewPrivate const &);
+public:
        GuiViewPrivate(GuiView * gv)
                : gv_(gv), current_work_area_(0), current_main_work_area_(0),
                layout_(0), autosave_timeout_(5000),
@@ -332,62 +327,6 @@ struct GuiView::GuiViewPrivate
                delete stack_widget_;
        }
 
-       QMenu * toolBarPopup(GuiView * parent)
-       {
-               // FIXME: translation
-               QMenu * menu = new QMenu(parent);
-               QActionGroup * iconSizeGroup = new QActionGroup(parent);
-
-               QAction * smallIcons = new QAction(iconSizeGroup);
-               smallIcons->setText(qt_("Small-sized icons"));
-               smallIcons->setCheckable(true);
-               QObject::connect(smallIcons, SIGNAL(triggered()),
-                       parent, SLOT(smallSizedIcons()));
-               menu->addAction(smallIcons);
-
-               QAction * normalIcons = new QAction(iconSizeGroup);
-               normalIcons->setText(qt_("Normal-sized icons"));
-               normalIcons->setCheckable(true);
-               QObject::connect(normalIcons, SIGNAL(triggered()),
-                       parent, SLOT(normalSizedIcons()));
-               menu->addAction(normalIcons);
-
-               QAction * bigIcons = new QAction(iconSizeGroup);
-               bigIcons->setText(qt_("Big-sized icons"));
-               bigIcons->setCheckable(true);
-               QObject::connect(bigIcons, SIGNAL(triggered()),
-                       parent, SLOT(bigSizedIcons()));
-               menu->addAction(bigIcons);
-
-               QAction * hugeIcons = new QAction(iconSizeGroup);
-               hugeIcons->setText(qt_("Huge-sized icons"));
-               hugeIcons->setCheckable(true);
-               QObject::connect(hugeIcons, SIGNAL(triggered()),
-                       parent, SLOT(hugeSizedIcons()));
-               menu->addAction(hugeIcons);
-
-               QAction * giantIcons = new QAction(iconSizeGroup);
-               giantIcons->setText(qt_("Giant-sized icons"));
-               giantIcons->setCheckable(true);
-               QObject::connect(giantIcons, SIGNAL(triggered()),
-                       parent, SLOT(giantSizedIcons()));
-               menu->addAction(giantIcons);
-
-               unsigned int cur = parent->iconSize().width();
-               if ( cur == parent->d.smallIconSize)
-                       smallIcons->setChecked(true);
-               else if (cur == parent->d.normalIconSize)
-                       normalIcons->setChecked(true);
-               else if (cur == parent->d.bigIconSize)
-                       bigIcons->setChecked(true);
-               else if (cur == parent->d.hugeIconSize)
-                       hugeIcons->setChecked(true);
-               else if (cur == parent->d.giantIconSize)
-                       giantIcons->setChecked(true);
-
-               return menu;
-       }
-
        void setBackground()
        {
                stack_widget_->setCurrentWidget(bg_widget_);
@@ -444,6 +383,60 @@ struct GuiView::GuiViewPrivate
                processing_thread_watcher_.setFuture(f);
        }
 
+       QSize iconSize(docstring const & icon_size)
+       {
+               unsigned int size;
+               if (icon_size == "small")
+                       size = smallIconSize;
+               else if (icon_size == "normal")
+                       size = normalIconSize;
+               else if (icon_size == "big")
+                       size = bigIconSize;
+               else if (icon_size == "huge")
+                       size = hugeIconSize;
+               else if (icon_size == "giant")
+                       size = giantIconSize;
+               else
+                       size = icon_size.empty() ? normalIconSize : convert<int>(icon_size);
+
+               if (size < smallIconSize)
+                       size = smallIconSize;
+
+               return QSize(size, size);
+       }
+
+       QSize iconSize(QString const & icon_size)
+       {
+               return iconSize(qstring_to_ucs4(icon_size));
+       }
+
+       string & iconSize(QSize const & qsize)
+       {
+               LATTEST(qsize.width() == qsize.height());
+
+               static string icon_size;
+
+               unsigned int size = qsize.width();
+
+               if (size < smallIconSize)
+                       size = smallIconSize;
+
+               if (size == smallIconSize)
+                       icon_size = "small";
+               else if (size == normalIconSize)
+                       icon_size = "normal";
+               else if (size == bigIconSize)
+                       icon_size = "big";
+               else if (size == hugeIconSize)
+                       icon_size = "huge";
+               else if (size == giantIconSize)
+                       icon_size = "giant";
+               else
+                       icon_size = convert<string>(size);
+
+               return icon_size;
+       }
+
 public:
        GuiView * gv_;
        GuiWorkArea * current_work_area_;
@@ -514,10 +507,14 @@ QSet<Buffer const *> GuiView::GuiViewPrivate::busyBuffers;
 
 
 GuiView::GuiView(int id)
-       : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0)
+       : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0),
+         command_execute_(false), minibuffer_focus_(false)
 {
+       connect(this, SIGNAL(bufferViewChanged()),
+               this, SLOT(onBufferViewChanged()));
+
        // GuiToolbars *must* be initialised before the menu bar.
-       normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge
+       setIconSize(QSize(d.normalIconSize, d.normalIconSize)); // at least on Mac the default is 32 otherwise, which is huge
        constructToolbars();
 
        // set ourself as the current view. This is needed for the menu bar
@@ -554,7 +551,7 @@ GuiView::GuiView(int id)
 #endif
 
 #endif
-       resetWindowTitleAndIconText();
+       resetWindowTitle();
 
        // use tabbed dock area for multiple docks
        // (such as "source" and "messages")
@@ -578,6 +575,23 @@ GuiView::GuiView(int id)
        connect(&d.processing_thread_watcher_, SIGNAL(finished()), 
                busylabel, SLOT(hide()));
 
+       QFontMetrics const fm(statusBar()->fontMetrics());
+       int const roheight = max(int(d.normalIconSize), fm.height());
+       QSize const rosize(roheight, roheight);
+       QPixmap readonly = QIcon(getPixmap("images/", "emblem-readonly", "svgz,png")).pixmap(rosize);
+       read_only_ = new QLabel(statusBar());
+       read_only_->setPixmap(readonly);
+       read_only_->setScaledContents(true);
+       read_only_->setAlignment(Qt::AlignCenter);
+       read_only_->hide();
+       statusBar()->addPermanentWidget(read_only_);
+
+       version_control_ = new QLabel(statusBar());
+       version_control_->setAlignment(Qt::AlignCenter);
+       version_control_->setFrameStyle(QFrame::StyledPanel);
+       version_control_->hide();
+       statusBar()->addPermanentWidget(version_control_);
+
        statusBar()->setSizeGripEnabled(true);
        updateStatusBar();
 
@@ -592,6 +606,11 @@ GuiView::GuiView(int id)
        connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)),
                SLOT(doShowDialog(QString const &, QString const &, Inset *)));
 
+       // set custom application bars context menu, e.g. tool bar and menu bar
+       setContextMenuPolicy(Qt::CustomContextMenu);
+       connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
+               SLOT(toolBarPopup(const QPoint &)));
+
        // Forbid too small unresizable window because it can happen
        // with some window manager under X11.
        setMinimumSize(300, 200);
@@ -703,7 +722,7 @@ void GuiView::saveLayout() const
        settings.setValue("geometry", saveGeometry());
 #endif
        settings.setValue("layout", saveState(0));
-       settings.setValue("icon_size", iconSize());
+       settings.setValue("icon_size", toqstr(d.iconSize(iconSize())));
 }
 
 
@@ -730,17 +749,7 @@ bool GuiView::restoreLayout()
                return false;
 
        //code below is skipped when when ~/.config/LyX is (re)created
-       QSize icon_size = settings.value(icon_key).toSize();
-       // Check whether session size changed.
-       if (icon_size.width() != int(d.smallIconSize) &&
-           icon_size.width() != int(d.normalIconSize) &&
-           icon_size.width() != int(d.bigIconSize) &&
-           icon_size.width() != int(d.hugeIconSize) &&
-           icon_size.width() != int(d.giantIconSize)) {
-               icon_size.setWidth(d.normalIconSize);
-               icon_size.setHeight(d.normalIconSize);
-       }
-       setIconSize(icon_size);
+       setIconSize(d.iconSize(settings.value(icon_key).toString()));
 
 #if defined(Q_WS_X11) || defined(QPA_XCB)
        QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
@@ -905,12 +914,6 @@ void GuiView::focusInEvent(QFocusEvent * e)
 }
 
 
-QMenu * GuiView::createPopupMenu()
-{
-       return d.toolBarPopup(this);
-}
-
-
 void GuiView::showEvent(QShowEvent * e)
 {
        LYXERR(Debug::GUI, "Passed Geometry "
@@ -1098,36 +1101,6 @@ void GuiView::updateStatusBarMessage(QString const & str)
 }
 
 
-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::hugeSizedIcons()
-{
-       setIconSize(QSize(d.hugeIconSize, d.hugeIconSize));
-}
-
-
-void GuiView::giantSizedIcons()
-{
-       setIconSize(QSize(d.giantIconSize, d.giantIconSize));
-}
-
-
 void GuiView::clearMessage()
 {
        // FIXME: This code was introduced in r19643 to fix bug #4123. However,
@@ -1145,37 +1118,58 @@ void GuiView::updateWindowTitle(GuiWorkArea * wa)
        if (wa != d.current_work_area_
                || wa->bufferView().buffer().isInternal())
                return;
-       setWindowTitle(qt_("LyX: ") + wa->windowTitle());
-       setWindowIconText(wa->windowIconText());
-#if (QT_VERSION >= 0x040400)
-       // Sets the path for the window: this is used by OSX to 
+       Buffer const & buf = wa->bufferView().buffer();
+       // Set the windows title
+       docstring title = buf.fileName().displayName(130) + from_ascii("[*]");
+#ifndef Q_WS_MAC
+       title += from_ascii(" - LyX");
+#endif
+       setWindowTitle(toqstr(title));
+       // Sets the path for the window: this is used by OSX to
        // allow a context click on the title bar showing a menu
        // with the path up to the file
-       setWindowFilePath(toqstr(wa->bufferView().buffer().absFileName()));
-#endif
+       setWindowFilePath(toqstr(buf.absFileName()));
+       // Tell Qt whether the current document is changed
+       setWindowModified(!buf.isClean());
+
+       if (buf.isReadonly())
+               read_only_->show();
+       else
+               read_only_->hide();
+
+       if (buf.lyxvc().inUse()) {
+               version_control_->show();
+               version_control_->setText(toqstr(buf.lyxvc().vcstatus()));
+       } else
+               version_control_->hide();
 }
 
 
 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
 {
        if (d.current_work_area_)
-               QObject::disconnect(d.current_work_area_, SIGNAL(busy(bool)),
-                       this, SLOT(setBusy(bool)));
+               // disconnect the current work area from all slots
+               QObject::disconnect(d.current_work_area_, 0, this, 0);
        disconnectBuffer();
        disconnectBufferView();
        connectBufferView(wa->bufferView());
        connectBuffer(wa->bufferView().buffer());
        d.current_work_area_ = wa;
        QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
-               this, SLOT(updateWindowTitle(GuiWorkArea *)));
-       QObject::connect(wa, SIGNAL(busy(bool)), this, SLOT(setBusy(bool)));
-       updateWindowTitle(wa);
-
-       structureChanged();
+                        this, SLOT(updateWindowTitle(GuiWorkArea *)));
+       QObject::connect(wa, SIGNAL(busy(bool)),
+                        this, SLOT(setBusy(bool)));
+       // connection of a signal to a signal
+       QObject::connect(wa, SIGNAL(bufferViewChanged()),
+                        this, SIGNAL(bufferViewChanged()));
+       Q_EMIT updateWindowTitle(wa);
+       Q_EMIT bufferViewChanged();
+}
 
-       // The document settings needs to be reinitialised.
-       updateDialog("document", "");
 
+void GuiView::onBufferViewChanged()
+{
+       structureChanged();
        // Buffer-dependent dialogs must be updated. This is done here because
        // some dialogs require buffer()->text.
        updateDialogs();
@@ -1193,11 +1187,9 @@ void GuiView::on_lastWorkAreaRemoved()
                return;
 
        // Reset and updates the dialogs.
-       d.toc_models_.reset(0);
-       updateDialog("document", "");
-       updateDialogs();
+       Q_EMIT bufferViewChanged();
 
-       resetWindowTitleAndIconText();
+       resetWindowTitle();
        updateStatusBar();
 
        if (lyxrc.open_buffers_in_tabs)
@@ -1275,19 +1267,10 @@ bool GuiView::event(QEvent * e)
                        cap::saveSelection(old_view->currentBufferView()->cursor());
                }
                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.
-                       structureChanged();
-                       // The document settings needs to be reinitialised.
-                       updateDialog("document", "");
-                       updateDialogs();
-               } else {
-                       resetWindowTitleAndIconText();
-               }
+               if (d.current_work_area_)
+                       on_currentWorkAreaChanged(d.current_work_area_);
+               else
+                       resetWindowTitle();
                setFocus();
                return QMainWindow::event(e);
        }
@@ -1313,10 +1296,9 @@ bool GuiView::event(QEvent * e)
        }
 }
 
-void GuiView::resetWindowTitleAndIconText()
+void GuiView::resetWindowTitle()
 {
        setWindowTitle(qt_("LyX"));
-       setWindowIconText(qt_("LyX"));
 }
 
 bool GuiView::focusNextPrevChild(bool /*next*/)
@@ -1349,6 +1331,13 @@ void GuiView::setBusy(bool busy)
 }
 
 
+void GuiView::resetCommandExecute()
+{
+       command_execute_ = false;
+       updateToolbars();
+}
+
+
 double GuiView::pixelRatio() const
 {
 #if QT_VERSION >= 0x050000
@@ -1372,7 +1361,7 @@ GuiWorkArea * GuiView::workArea(Buffer & buffer)
 {
        if (currentWorkArea()
                && &currentWorkArea()->bufferView().buffer() == &buffer)
-               return (GuiWorkArea *) currentWorkArea();
+               return currentWorkArea();
        if (TabWorkArea * twa = d.currentTabWorkArea())
                return twa->workArea(buffer);
        return 0;
@@ -1436,6 +1425,7 @@ void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
        if (!wa) {
                d.current_work_area_ = 0;
                d.setBackground();
+               Q_EMIT bufferViewChanged();
                return;
        }
 
@@ -1540,24 +1530,34 @@ void GuiView::updateToolbars()
 {
        ToolbarMap::iterator end = d.toolbars_.end();
        if (d.current_work_area_) {
-               bool const math =
-                       d.current_work_area_->bufferView().cursor().inMathed()
-                       && !d.current_work_area_->bufferView().cursor().inRegexped();
-               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);
-               bool const mathmacrotemplate =
-                       lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
-               bool const ipa =
-                       lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled();
+               int context = 0;
+               if (d.current_work_area_->bufferView().cursor().inMathed()
+                       && !d.current_work_area_->bufferView().cursor().inRegexped())
+                       context |= Toolbars::MATH;
+               if (lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled())
+                       context |= Toolbars::TABLE;
+               if (currentBufferView()->buffer().areChangesPresent()
+                   || (lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled()
+                       && lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true))
+                   || (lyx::getStatus(FuncRequest(LFUN_CHANGES_OUTPUT)).enabled()
+                       && lyx::getStatus(FuncRequest(LFUN_CHANGES_OUTPUT)).onOff(true)))
+                       context |= Toolbars::REVIEW;
+               if (lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled())
+                       context |= Toolbars::MATHMACROTEMPLATE;
+               if (lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled())
+                       context |= Toolbars::IPA;
+               if (command_execute_)
+                       context |= Toolbars::MINIBUFFER;
+               if (minibuffer_focus_) {
+                       context |= Toolbars::MINIBUFFER_FOCUS;
+                       minibuffer_focus_ = false;
+               }
 
                for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-                       it->second->update(math, table, review, mathmacrotemplate, ipa);
+                       it->second->update(context);
        } else
                for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-                       it->second->update(false, false, false, false, false);
+                       it->second->update();
 }
 
 
@@ -1652,6 +1652,12 @@ void GuiView::updateTocItem(string const & type, DocIterator const & dit)
 
 void GuiView::structureChanged()
 {
+       // This is called from the Buffer, which has no way to ensure that cursors
+       // in BufferView remain valid.
+       if (documentBufferView())
+               documentBufferView()->cursor().sanitize();
+       // FIXME: This is slightly expensive, though less than the tocBackend update
+       // (#9880). This also resets the view in the Toc Widget (#6675).
        d.toc_models_.reset(documentBufferView());
        // Navigator needs more than a simple update in this case. It needs to be
        // rebuilt.
@@ -1748,15 +1754,20 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
        Buffer * doc_buffer = documentBufferView()
                ? &(documentBufferView()->buffer()) : 0;
 
+#ifdef Q_OS_MAC
        /* 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.
+          This code must not be used on Linux and Windows, since it
+          would disable buffer-related entries when hovering over the
+          menu (see bug #9574).
         */
        if (cmd.origin() == FuncRequest::MENU && !hasFocus()) {
                buf = 0;
                doc_buffer = 0;
        }
+#endif
 
        // Check whether we need a buffer
        if (!lyxaction.funcHasFlag(cmd.action(), LyXAction::NoBuffer) && !buf) {
@@ -1795,7 +1806,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                string format = to_utf8(cmd.argument());
                if (cmd.argument().empty())
                        format = doc_buffer->params().getDefaultOutputFormat();
-               enable = doc_buffer->params().isExportableFormat(format);
+               enable = doc_buffer->params().isExportable(format, true);
                break;
        }
 
@@ -1807,7 +1818,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                break;
 
        case LFUN_BUFFER_CHILD_OPEN:
-               enable = doc_buffer;
+               enable = doc_buffer != 0;
                break;
 
        case LFUN_BUFFER_WRITE:
@@ -1835,12 +1846,12 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
        case LFUN_BUFFER_WRITE_AS:
        case LFUN_BUFFER_EXPORT_AS:
-               enable = doc_buffer;
+               enable = doc_buffer != 0;
                break;
 
        case LFUN_BUFFER_CLOSE:
        case LFUN_VIEW_CLOSE:
-               enable = doc_buffer;
+               enable = doc_buffer != 0;
                break;
 
        case LFUN_BUFFER_CLOSE_ALL:
@@ -1873,8 +1884,12 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                break;
        }
 
+       case LFUN_ICON_SIZE:
+               flag.setOnOff(d.iconSize(cmd.argument()) == iconSize());
+               break;
+
        case LFUN_DROP_LAYOUTS_CHOICE:
-               enable = buf;
+               enable = buf != 0;
                break;
 
        case LFUN_UI_TOGGLE:
@@ -1900,9 +1915,6 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                                || name == "texinfo"
                                || name == "progress"
                                || name == "compare";
-               else if (name == "print")
-                       enable = doc_buffer->params().isExportable("dvi")
-                               && lyxrc.print_command != "none";
                else if (name == "character" || name == "symbols"
                        || name == "mathdelimiter" || name == "mathmatrix") {
                        if (!buf || buf->isReadonly())
@@ -1973,13 +1985,21 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                break;
 
        case LFUN_BUFFER_ZOOM_OUT:
-               enable = doc_buffer && lyxrc.zoom > 10;
-               break;
-
-       case LFUN_BUFFER_ZOOM_IN:
-               enable = doc_buffer;
+       case LFUN_BUFFER_ZOOM_IN: {
+               // only diff between these two is that the default for ZOOM_OUT
+               // is a neg. number
+               bool const neg_zoom =
+                       convert<int>(cmd.argument()) < 0 ||
+                       (cmd.action() == LFUN_BUFFER_ZOOM_OUT && cmd.argument().empty());
+               if (lyxrc.zoom <= zoom_min_ && neg_zoom) {
+                       docstring const msg =
+                               bformat(_("Zoom level cannot be less than %1$d%."), zoom_min_);
+                       flag.message(msg);
+                       enable = false;
+               } else
+                       enable = doc_buffer;
                break;
-
+       }
        case LFUN_BUFFER_MOVE_NEXT:
        case LFUN_BUFFER_MOVE_PREVIOUS:
                // we do not cycle when moving
@@ -2037,6 +2057,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                break;
 
        case LFUN_SERVER_GOTO_FILE_ROW:
+       case LFUN_LYX_ACTIVATE:
                break;
        case LFUN_FORWARD_SEARCH:
                enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty());
@@ -2550,15 +2571,6 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin
 }
 
 
-struct PrettyNameComparator
-{
-       bool operator()(Format const *first, Format const *second) const {
-               return compare_no_case(translateIfPossible(from_ascii(first->prettyname())),
-                                      translateIfPossible(from_ascii(second->prettyname()))) <= 0;
-       }
-};
-
-
 bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
 {
        FileName fname = b.fileName();
@@ -2569,28 +2581,25 @@ bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
        QStringList types;
        QString const anyformat = qt_("Guess from extension (*.*)");
        types << anyformat;
-       Formats::const_iterator it = formats.begin();
+
        vector<Format const *> export_formats;
-       for (; it != formats.end(); ++it)
-               if (it->documentFormat())
-                       export_formats.push_back(&(*it));
-       PrettyNameComparator cmp;
-       sort(export_formats.begin(), export_formats.end(), cmp);
-       vector<Format const *>::const_iterator fit = export_formats.begin();
+       for (Format const & f : formats)
+               if (f.documentFormat())
+                       export_formats.push_back(&f);
+       sort(export_formats.begin(), export_formats.end(), Format::formatSorter);
        map<QString, string> fmap;
        QString filter;
        string ext;
-       for (; fit != export_formats.end(); ++fit) {
-               docstring const loc_prettyname =
-                       translateIfPossible(from_utf8((*fit)->prettyname()));
+       for (Format const * f : export_formats) {
+               docstring const loc_prettyname = translateIfPossible(f->prettyname());
                QString const loc_filter = toqstr(bformat(from_ascii("%1$s (*.%2$s)"),
                                                     loc_prettyname,
-                                                    from_ascii((*fit)->extension())));
+                                                    from_ascii(f->extension())));
                types << loc_filter;
-               fmap[loc_filter] = (*fit)->name();
-               if (from_ascii((*fit)->name()) == iformat) {
+               fmap[loc_filter] = f->name();
+               if (from_ascii(f->name()) == iformat) {
                        filter = loc_filter;
-                       ext = (*fit)->extension();
+                       ext = f->extension();
                }
        }
        string ofname = fname.onlyFileName();
@@ -2735,9 +2744,13 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa)
 bool GuiView::closeBuffer()
 {
        GuiWorkArea * wa = currentMainWorkArea();
+       // coverity complained about this
+       // it seems unnecessary, but perhaps is worth the check
+       LASSERT(wa, return false);
+
        setCurrentWorkArea(wa);
        Buffer & buf = wa->bufferView().buffer();
-       return wa && closeWorkArea(wa, !buf.parent());
+       return closeWorkArea(wa, !buf.parent());
 }
 
 
@@ -2786,7 +2799,7 @@ bool GuiView::closeWorkAreaAll()
 
        // We have to call count() each time, because it can happen that
        // more than one splitter will disappear in one iteration (bug 5998).
-       for (; d.splitter_->count() > empty_twa; ) {
+       while (d.splitter_->count() > empty_twa) {
                TabWorkArea * twa = d.tabWorkArea(empty_twa);
 
                if (twa->count() == 0)
@@ -2808,7 +2821,7 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
 
        Buffer & buf = wa->bufferView().buffer();
 
-       if (close_buffer && GuiViewPrivate::busyBuffers.contains(&buf)) {
+       if (GuiViewPrivate::busyBuffers.contains(&buf)) {
                Alert::warning(_("Close document"), 
                        _("Document could not be closed because it is being processed by LyX."));
                return false;
@@ -2838,23 +2851,31 @@ bool GuiView::closeBuffer(Buffer & buf)
                ListOfBuffers::const_iterator it = clist.begin();
                ListOfBuffers::const_iterator const bend = clist.end();
                for (; it != bend; ++it) {
-                       // If a child is dirty, do not close
-                       // without user intervention
-                       //FIXME: should we look in other tabworkareas?
                        Buffer * child_buf = *it;
+                       if (theBufferList().isOthersChild(&buf, child_buf)) {
+                               child_buf->setParent(0);
+                               continue;
+                       }
+
+                       // FIXME: should we look in other tabworkareas?
+                       // ANSWER: I don't think so. I've tested, and if the child is
+                       // open in some other window, it closes without a problem.
                        GuiWorkArea * child_wa = workArea(*child_buf);
                        if (child_wa) {
-                               if (!closeWorkArea(child_wa, true)) {
-                                       success = false;
+                               success = closeWorkArea(child_wa, true);
+                               if (!success)
                                        break;
-                               }
-                       } else
-                               theBufferList().releaseChild(&buf, child_buf);
+                       } else {
+                               // In this case the child buffer is open but hidden.
+                               // It therefore should not (MUST NOT) be dirty!
+                               LATTEST(child_buf->isClean());
+                               theBufferList().release(child_buf);
+                       }
                }
        }
        if (success) {
                // goto bookmark to update bookmark pit.
-               //FIXME: we should update only the bookmarks related to this buffer!
+               // FIXME: we should update only the bookmarks related to this buffer!
                LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
                for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
                        guiApp->gotoBookmark(i+1, false, false);
@@ -2875,7 +2896,7 @@ bool GuiView::closeBuffer(Buffer & buf)
 bool GuiView::closeTabWorkArea(TabWorkArea * twa)
 {
        while (twa == d.currentTabWorkArea()) {
-               twa->setCurrentIndex(twa->count()-1);
+               twa->setCurrentIndex(twa->count() - 1);
 
                GuiWorkArea * wa = twa->currentWorkArea();
                Buffer & b = wa->bufferView().buffer();
@@ -3217,7 +3238,6 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
                }
 
        case LFUN_VC_COMPARE: {
-
                if (cmd.argument().empty()) {
                        lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "comparehistory"));
                        break;
@@ -3227,6 +3247,8 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
                string f1, f2;
 
                // f1
+               // it seems safe to assume we have a buffer
+               // coverity[FORWARD_NULL]
                if (!buffer->lyxvc().prepareFileRevision(rev1, f1))
                        break;
 
@@ -3335,8 +3357,23 @@ bool GuiView::goToFileRow(string const & argument)
                return false;
        }
        setBuffer(buf);
-       documentBufferView()->setCursorFromRow(row);
-       return true;
+       bool success = documentBufferView()->setCursorFromRow(row);
+       if (!success) {
+               LYXERR(Debug::LATEX,
+                      "setCursorFromRow: invalid position for row " << row);
+               frontend::Alert::error(_("Inverse Search Failed"),
+                                      _("Invalid position requested by inverse search.\n"
+                                        "You may need to update the viewed document."));
+       }
+       return success;
+}
+
+
+void GuiView::toolBarPopup(const QPoint & /*pos*/)
+{
+       QMenu * menu = new QMenu;
+       menu = guiApp->menus().menu(toqstr("context-toolbars"), * this);
+       menu->exec(QCursor::pos());
 }
 
 
@@ -3416,7 +3453,6 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
 #else
        Buffer::ExportStatus status;
        if (syncFunc) {
-               // TODO check here if it breaks exporting with Qt < 4.4
                status = (used_buffer->*syncFunc)(format, true);
        } else if (previewFunc) {
                status = (used_buffer->*previewFunc)(format); 
@@ -3499,16 +3535,21 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                case LFUN_BUFFER_EXPORT: {
                        if (!doc_buffer)
                                break;
-                       FileName target_dir = doc_buffer->fileName().onlyPath();
-                       string const dest = cmd.getArg(1);
-                       if (!dest.empty() && FileName::isAbsolute(dest))
-                               target_dir = FileName(support::onlyPath(dest));
                        // GCC only sees strfwd.h when building merged
                        if (::lyx::operator==(cmd.argument(), "custom")) {
                                dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
                                break;
                        }
-                       if (!target_dir.isDirWritable()) {
+
+                       string const dest = cmd.getArg(1);
+                       FileName target_dir;
+                       if (!dest.empty() && FileName::isAbsolute(dest))
+                               target_dir = FileName(support::onlyPath(dest));
+                       else
+                               target_dir = doc_buffer->fileName().onlyPath();
+
+                       if ((dest.empty() && doc_buffer->isUnnamed())
+                           || !target_dir.isDirWritable()) {
                                exportBufferAs(*doc_buffer, cmd.argument());
                                break;
                        }
@@ -3596,7 +3637,9 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        for (; i != ids.size(); ++i) {
                                GuiView & gv = guiApp->view(ids[i]);
                                if (gv.workArea(*buffer)) {
+                                       gv.raise();
                                        gv.activateWindow();
+                                       gv.setFocus();
                                        gv.setBuffer(buffer);
                                        break;
                                }
@@ -3627,14 +3670,8 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
 
                case LFUN_COMMAND_EXECUTE: {
-                       bool const show_it = cmd.argument() != "off";
-                       // FIXME: this is a hack, "minibuffer" should not be
-                       // hardcoded.
-                       if (GuiToolbar * t = toolbar("minibuffer")) {
-                               t->setVisible(show_it);
-                               if (show_it && t->commandBuffer())
-                                       t->commandBuffer()->setFocus();
-                       }
+                       command_execute_ = true;
+                       minibuffer_focus_ = true;
                        break;
                }
                case LFUN_DROP_LAYOUTS_CHOICE:
@@ -3745,6 +3782,14 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
                }
 
+               case LFUN_ICON_SIZE: {
+                       QSize size = d.iconSize(cmd.argument());
+                       setIconSize(size);
+                       dr.setMessage(bformat(_("Icon size set to %1$dx%2$d."),
+                                               size.width(), size.height()));
+                       break;
+               }
+
                case LFUN_DIALOG_UPDATE: {
                        string const name = to_utf8(cmd.argument());
                        if (name == "prefs" || name == "document")
@@ -3905,17 +3950,22 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
 
                case LFUN_BUFFER_ZOOM_IN:
-               case LFUN_BUFFER_ZOOM_OUT:
+               case LFUN_BUFFER_ZOOM_OUT: {
+                       // use a signed temp to avoid overflow
+                       int zoom = lyxrc.zoom;
                        if (cmd.argument().empty()) {
                                if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
-                                       lyxrc.zoom += 20;
+                                       zoom += 20;
                                else
-                                       lyxrc.zoom -= 20;
+                                       zoom -= 20;
                        } else
-                               lyxrc.zoom += convert<int>(cmd.argument());
+                               zoom += convert<int>(cmd.argument());
+
+                       if (zoom < static_cast<int>(zoom_min_))
+                               zoom = zoom_min_;
+                       lyxrc.zoom = zoom;
 
-                       if (lyxrc.zoom < 10)
-                               lyxrc.zoom = 10;
+                       dr.setMessage(bformat(_("Zoom level is now %1$d%"), lyxrc.zoom));
 
                        // The global QPixmapCache is used in GuiPainter to cache text
                        // painting so we must reset it.
@@ -3923,6 +3973,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        guiApp->fontLoader().update();
                        lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
                        break;
+               }
 
                case LFUN_VC_REGISTER:
                case LFUN_VC_RENAME:
@@ -3939,10 +3990,18 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
 
                case LFUN_SERVER_GOTO_FILE_ROW:
-                       goToFileRow(to_utf8(cmd.argument()));
+                       if(goToFileRow(to_utf8(cmd.argument())))
+                               dr.screenUpdate(Update::Force | Update::FitCursor);
+                       break;
+
+               case LFUN_LYX_ACTIVATE:
+                       activateWindow();
                        break;
 
                case LFUN_FORWARD_SEARCH: {
+               // it seems safe to assume we have a document buffer, since
+               // getStatus wants one.
+               // coverity[FORWARD_NULL]
                        Buffer const * doc_master = doc_buffer->masterBuffer();
                        FileName const path(doc_master->temppath());
                        string const texname = doc_master->isChild(doc_buffer)
@@ -3972,15 +4031,11 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                command = lyxrc.forward_search_pdf;
                        }
 
-                       DocIterator tmpcur = bv->cursor();
-                       // Leave math first
-                       while (tmpcur.inMathed())
-                               tmpcur.pop_back();
-                       int row = tmpcur.inMathed() ? 0 : doc_buffer->texrow().getRowFromIdPos(
-                                                               tmpcur.paragraph().id(), tmpcur.pos());
+                       DocIterator cur = bv->cursor();
+                       int row = doc_buffer->texrow().rowFromDocIterator(cur).first;
                        LYXERR(Debug::ACTION, "Forward search: row:" << row
-                               << " id:" << tmpcur.paragraph().id());
-                       if (!row || command.empty()) {
+                                  << " cur:" << cur);
+                       if (row == -1 || command.empty()) {
                                dr.setMessage(_("Couldn't proceed."));
                                break;
                        }
@@ -3999,7 +4054,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 
                case LFUN_SPELLING_CONTINUOUSLY:
                        lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously;
-                       dr.screenUpdate(Update::Force | Update::FitCursor);
+                       dr.screenUpdate(Update::Force);
                        break;
 
                default:
@@ -4019,7 +4074,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
        bv = currentBufferView();
 
        // Clear non-empty selections
-        // (e.g. from a "char-forward-select" followed by "char-backward-select")
+       // (e.g. from a "char-forward-select" followed by "char-backward-select")
        if (bv) {
                Cursor & cur = bv->cursor();
                if ((cur.selection() && cur.selBegin() == cur.selEnd())) {
@@ -4153,7 +4208,7 @@ char const * const dialognames[] = {
 "external", "file", "findreplace", "findreplaceadv", "float", "graphics",
 "href", "include", "index", "index_print", "info", "listings", "label", "line",
 "log", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
-"nomencl_print", "note", "paragraph", "phantom", "prefs", "print", "ref",
+"nomencl_print", "note", "paragraph", "phantom", "prefs", "ref",
 "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
 "thesaurus", "texinfo", "toc", "view-source", "vspace", "wrap", "progress"};
 
@@ -4430,8 +4485,6 @@ Dialog * GuiView::build(string const & name)
                return createGuiPhantom(*this);
        if (name == "prefs")
                return createGuiPreferences(*this);
-       if (name == "print")
-               return createGuiPrint(*this);
        if (name == "ref")
                return createGuiRef(*this);
        if (name == "sendto")