]> git.lyx.org Git - features.git/blobdiff - src/frontends/qt/GuiView.cpp
After export-cancel, hide busy and cancel buttons
[features.git] / src / frontends / qt / GuiView.cpp
index 382496e3e501dd14b33c7b166326596d1f672f30..8269ff09cceec5164a8882c2045b17d6992678c4 100644 (file)
 
 #include "GuiView.h"
 
+#include "DialogFactory.h"
 #include "DispatchResult.h"
 #include "FileDialog.h"
+#include "FindAndReplace.h"
 #include "FontLoader.h"
 #include "GuiApplication.h"
 #include "GuiClickableLabel.h"
-#include "GuiCommandBuffer.h"
 #include "GuiCompleter.h"
+#include "GuiFontMetrics.h"
 #include "GuiKeySymbol.h"
 #include "GuiToc.h"
 #include "GuiToolbar.h"
@@ -51,9 +53,8 @@
 #include "Format.h"
 #include "FuncStatus.h"
 #include "FuncRequest.h"
-#include "Intl.h"
+#include "KeySymbol.h"
 #include "Language.h"
-#include "Layout.h"
 #include "LayoutFile.h"
 #include "Lexer.h"
 #include "LyXAction.h"
 #include "SpellChecker.h"
 #include "Session.h"
 #include "TexRow.h"
-#include "TextClass.h"
 #include "Text.h"
 #include "Toolbars.h"
 #include "version.h"
 
+#include "graphics/PreviewLoader.h"
+
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/ExceptionMessage.h"
 #include "support/FileName.h"
-#include "support/filetools.h"
 #include "support/gettext.h"
-#include "support/filetools.h"
 #include "support/ForkedCalls.h"
 #include "support/lassert.h"
 #include "support/lstrings.h"
 #include <QAction>
 #include <QApplication>
 #include <QCloseEvent>
-#include <QDebug>
-#include <QDesktopWidget>
 #include <QDragEnterEvent>
 #include <QDropEvent>
 #include <QFuture>
 #include <QFutureWatcher>
+#include <QGroupBox>
 #include <QLabel>
 #include <QList>
 #include <QMenu>
 #include <QMenuBar>
 #include <QMimeData>
-#include <QMovie>
 #include <QPainter>
 #include <QPixmap>
 #include <QPoint>
-#include <QPushButton>
-#include <QScrollBar>
 #include <QSettings>
 #include <QShowEvent>
+#include <QSlider>
 #include <QSplitter>
 #include <QStackedWidget>
 #include <QStatusBar>
 #include <QSvgRenderer>
 #include <QtConcurrentRun>
-#include <QTime>
 #include <QTimer>
-#include <QToolBar>
 #include <QUrl>
-
+#include <QWindowStateChangeEvent>
+#include <QGestureEvent>
+#include <QPinchGesture>
 
 
 // sync with GuiAlert.cpp
@@ -209,16 +206,15 @@ public:
                // Check how long the logo gets with the current font
                // and adapt if the font is running wider than what
                // we assume
-               QFontMetrics fm(font);
+               GuiFontMetrics fm(font);
                // Split the title into lines to measure the longest line
                // in the current l7n.
                QStringList titlesegs = htext.split('\n');
                int wline = 0;
-               int hline = fm.height();
-               QStringList::const_iterator sit;
-               for (sit = titlesegs.constBegin(); sit != titlesegs.constEnd(); ++sit) {
-                       if (fm.width(*sit) > wline)
-                               wline = fm.width(*sit);
+               int hline = fm.maxHeight();
+               for (QString const & seg : titlesegs) {
+                       if (fm.width(seg) > wline)
+                               wline = fm.width(seg);
                }
                // The longest line in the reference font (for English)
                // is 180. Calculate scale factor from that.
@@ -235,7 +231,7 @@ public:
                setFocusPolicy(Qt::StrongFocus);
        }
 
-       void paintEvent(QPaintEvent *)
+       void paintEvent(QPaintEvent *) override
        {
                int const w = width_;
                int const h = height_;
@@ -249,7 +245,7 @@ public:
                pain.drawPixmap(x, y, w, h, splash_);
        }
 
-       void keyPressEvent(QKeyEvent * ev)
+       void keyPressEvent(QKeyEvent * ev) override
        {
                KeySymbol sym;
                setKeySymbol(&sym, ev);
@@ -499,7 +495,7 @@ public:
                                   Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
                                   Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
                                   Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const,
-                                  bool allow_async);
+                                  bool allow_async, bool use_tmpdir = false);
 
        QVector<GuiWorkArea*> guiWorkAreas();
 
@@ -529,6 +525,7 @@ public:
 
        ///
        QTimer statusbar_timer_;
+       QTimer statusbar_stats_timer_;
        /// auto-saving of buffers
        Timeout autosave_timeout_;
 
@@ -552,6 +549,20 @@ public:
 
        /// flag against a race condition due to multiclicks, see bug #1119
        bool in_show_;
+
+       // Timers for statistic updates in buffer
+       /// Current time left to the nearest info update
+       int time_to_update = 1000;
+       ///Basic step for timer in ms. Basically reaction time for short selections
+       int const timer_rate = 500;
+       /// Real stats updates infrequently. First they take long time for big buffers, second
+       /// they are visible for fast-repeat keyboards even for mid documents.
+       int const default_stats_rate = 5000;
+       /// Detection of new selection, so we can react fast
+       bool already_in_selection_ = false;
+       /// Maximum size of "short" selection for which we can update with faster timer_rate
+       int const max_sel_chars = 5000;
+
 };
 
 QSet<Buffer const *> GuiView::GuiViewPrivate::busyBuffers;
@@ -559,8 +570,9 @@ QSet<Buffer const *> GuiView::GuiViewPrivate::busyBuffers;
 
 GuiView::GuiView(int id)
        : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0),
-         command_execute_(false), minibuffer_focus_(false), toolbarsMovable_(true),
-         devel_mode_(false)
+         command_execute_(false), minibuffer_focus_(false), word_count_enabled_(true),
+         char_count_enabled_(true),  char_nb_count_enabled_(false),
+         toolbarsMovable_(true), devel_mode_(false)
 {
        connect(this, SIGNAL(bufferViewChanged()),
                this, SLOT(onBufferViewChanged()));
@@ -588,6 +600,9 @@ GuiView::GuiView(int id)
        }
        connect(&d.statusbar_timer_, SIGNAL(timeout()),
                this, SLOT(clearMessage()));
+       connect(&d.statusbar_stats_timer_, SIGNAL(timeout()),
+               this, SLOT(showStats()));
+       d.statusbar_stats_timer_.start(d.timer_rate);
 
        // We don't want to keep the window in memory if it is closed.
        setAttribute(Qt::WA_DeleteOnClose, true);
@@ -610,33 +625,129 @@ GuiView::GuiView(int id)
        // (such as "source" and "messages")
        setDockOptions(QMainWindow::ForceTabbedDocks);
 
+#ifdef Q_OS_MAC
+       // use document mode tabs on docks
+       setDocumentMode(true);
+#endif
+
        // For Drag&Drop.
        setAcceptDrops(true);
 
+       QFontMetrics const fm(statusBar()->fontMetrics());
+       int const iconheight = max(int(d.normalIconSize), fm.height());
+       QSize const iconsize(iconheight, iconheight);
+
        // add busy indicator to statusbar
-       GuiClickableLabel * busylabel = new GuiClickableLabel(statusBar());
-       statusBar()->addPermanentWidget(busylabel);
        search_mode mode = theGuiApp()->imageSearchMode();
-       QString fn = toqstr(lyx::libFileSearch("images", "busy", "gif", mode).absFileName());
-       QMovie * busyanim = new QMovie(fn, QByteArray(), busylabel);
-       busylabel->setMovie(busyanim);
-       busyanim->start();
-       busylabel->hide();
+       QString fn = toqstr(lyx::libFileSearch("images", "busy", "svgz", mode).absFileName());
+       PressableSvgWidget * busySVG = new PressableSvgWidget(fn);
+       statusBar()->addPermanentWidget(busySVG);
+       // make busy indicator square with 5px margins
+       busySVG->setMaximumSize(busySVG->height() - 5, busySVG->height() - 5);
+       busySVG->hide();
+       // Add cancel button
+       QPixmap ps = QIcon(getPixmap("images/", "process-stop", "svgz")).pixmap(iconsize);
+       GuiClickableLabel * processStop = new GuiClickableLabel(statusBar());
+       processStop->setPixmap(ps);
+       processStop->setToolTip(qt_("Click here to stop export/output process"));
+       processStop->hide();
+       statusBar()->addPermanentWidget(processStop);
 
        connect(&d.processing_thread_watcher_, SIGNAL(started()),
-               busylabel, SLOT(show()));
+               busySVG, SLOT(show()));
        connect(&d.processing_thread_watcher_, SIGNAL(finished()),
-               busylabel, SLOT(hide()));
-       connect(busylabel, SIGNAL(clicked()), this, SLOT(checkCancelBackground()));
+               busySVG, SLOT(hide()));
+       connect(&d.processing_thread_watcher_, SIGNAL(started()),
+               processStop, SLOT(show()));
+       connect(&d.processing_thread_watcher_, SIGNAL(finished()),
+               processStop, SLOT(hide()));
+       connect(processStop, SIGNAL(pressed()), this, SLOT(checkCancelBackground()));
 
-       QFontMetrics const fm(statusBar()->fontMetrics());
-       int const iconheight = max(int(d.normalIconSize), fm.height());
-       QSize const iconsize(iconheight, iconheight);
+       connect(this, SIGNAL(scriptKilled()), busySVG, SLOT(hide()));
+       connect(this, SIGNAL(scriptKilled()), processStop, SLOT(hide()));
+
+       stat_counts_ = new GuiClickableLabel(statusBar());
+       stat_counts_->setAlignment(Qt::AlignCenter);
+       stat_counts_->setFrameStyle(QFrame::StyledPanel);
+       stat_counts_->hide();
+       statusBar()->addPermanentWidget(stat_counts_);
+
+       connect(stat_counts_, SIGNAL(clicked()), this, SLOT(statsPressed()));
+
+       zoom_slider_ = new QSlider(Qt::Horizontal, statusBar());
+       // Small size slider for macOS to prevent the status bar from enlarging
+       zoom_slider_->setAttribute(Qt::WA_MacSmallSize);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
+       zoom_slider_->setFixedWidth(fm.horizontalAdvance('x') * 15);
+#else
+       zoom_slider_->setFixedWidth(fm.width('x') * 15);
+#endif
+       // Make the defaultZoom center
+       zoom_slider_->setRange(10, (lyxrc.defaultZoom * 2) - 10);
+       // Initialize proper zoom value
+       QSettings settings;
+       zoom_ratio_ = settings.value("zoom_ratio", 1.0).toDouble();
+       // Actual zoom value: default zoom + fractional offset
+       int zoom = (int)(lyxrc.defaultZoom * zoom_ratio_);
+       zoom = min(max(zoom, zoom_min_), zoom_max_);
+       zoom_slider_->setValue(zoom);
+       zoom_slider_->setToolTip(qt_("Workarea zoom level. Drag, use Ctrl-+/- or Shift-Mousewheel to adjust."));
+
+       // Buttons to change zoom stepwise
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
+       QSize s(fm.horizontalAdvance('+'), fm.height());
+#else
+       QSize s(fm.width('+'), fm.height());
+#endif
+       zoom_in_ = new GuiClickableLabel(statusBar());
+       zoom_in_->setText("+");
+       zoom_in_->setFixedSize(s);
+       zoom_in_->setAlignment(Qt::AlignCenter);
+       zoom_out_ = new GuiClickableLabel(statusBar());
+       zoom_out_->setText(QString(QChar(0x2212)));
+       zoom_out_->setFixedSize(s);
+       zoom_out_->setAlignment(Qt::AlignCenter);
+
+       statusBar()->addPermanentWidget(zoom_out_);
+       zoom_out_->setEnabled(currentBufferView());
+       statusBar()->addPermanentWidget(zoom_slider_);
+       zoom_slider_->setEnabled(currentBufferView());
+       zoom_in_->setEnabled(currentBufferView());
+       statusBar()->addPermanentWidget(zoom_in_);
+
+       connect(zoom_slider_, SIGNAL(sliderMoved(int)), this, SLOT(zoomSliderMoved(int)));
+       connect(zoom_slider_, SIGNAL(valueChanged(int)), this, SLOT(zoomValueChanged(int)));
+       connect(this, SIGNAL(currentZoomChanged(int)), zoom_slider_, SLOT(setValue(int)));
+       connect(zoom_in_, SIGNAL(clicked()), this, SLOT(zoomInPressed()));
+       connect(zoom_out_, SIGNAL(clicked()), this, SLOT(zoomOutPressed()));
+
+       // QPalette palette = statusBar()->palette();
+
+       zoom_value_ = new GuiClickableLabel(statusBar());
+       connect(zoom_value_, SIGNAL(pressed()), this, SLOT(showZoomContextMenu()));
+       // zoom_value_->setPalette(palette);
+       zoom_value_->setForegroundRole(statusBar()->foregroundRole());
+       zoom_value_->setFixedHeight(fm.height());
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
+       zoom_value_->setMinimumWidth(fm.horizontalAdvance("444\%"));
+#else
+       zoom_value_->setMinimumWidth(fm.width("444\%"));
+#endif
+       zoom_value_->setAlignment(Qt::AlignCenter);
+       zoom_value_->setText(toqstr(bformat(_("[[ZOOM]]%1$d%"), zoom)));
+       statusBar()->addPermanentWidget(zoom_value_);
+       zoom_value_->setEnabled(currentBufferView());
+
+       statusBar()->setContextMenuPolicy(Qt::CustomContextMenu);
+       connect(statusBar(), SIGNAL(customContextMenuRequested(QPoint)),
+               this, SLOT(showStatusBarContextMenu()));
+
+       // enable pinch to zoom
+       grabGesture(Qt::PinchGesture);
 
        QPixmap shellescape = QIcon(getPixmap("images/", "emblem-shellescape", "svgz,png")).pixmap(iconsize);
        shell_escape_ = new QLabel(statusBar());
        shell_escape_->setPixmap(shellescape);
-       shell_escape_->setScaledContents(true);
        shell_escape_->setAlignment(Qt::AlignCenter);
        shell_escape_->setContextMenuPolicy(Qt::CustomContextMenu);
        shell_escape_->setToolTip(qt_("WARNING: LaTeX is allowed to execute "
@@ -651,7 +762,6 @@ GuiView::GuiView(int id)
        QPixmap readonly = QIcon(getPixmap("images/", "emblem-readonly", "svgz,png")).pixmap(iconsize);
        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_);
@@ -696,7 +806,6 @@ GuiView::GuiView(int id)
        initToolbars();
 
        // clear session data if any.
-       QSettings settings;
        settings.remove("views");
 }
 
@@ -725,8 +834,78 @@ void GuiView::checkCancelBackground()
        int const ret =
                Alert::prompt(ttl, msg, 1, 1,
                        _("&Cancel export"), _("Co&ntinue"));
-       if (ret == 0)
+       if (ret == 0) {
                Systemcall::killscript();
+               // stop busy signal immediately so that in the subsequent
+               // "Export canceled" prompt the status bar icons are accurate.
+               Q_EMIT scriptKilled();
+       }
+}
+
+void GuiView::statsPressed()
+{
+       DispatchResult dr;
+       dispatch(FuncRequest(LFUN_STATISTICS), dr);
+}
+
+void GuiView::zoomSliderMoved(int value)
+{
+       DispatchResult dr;
+       dispatch(FuncRequest(LFUN_BUFFER_ZOOM, convert<string>(value)), dr);
+       scheduleRedrawWorkAreas();
+       zoom_value_->setText(toqstr(bformat(_("[[ZOOM]]%1$d%"), value)));
+}
+
+
+void GuiView::zoomValueChanged(int value)
+{
+       if (value != lyxrc.currentZoom)
+               zoomSliderMoved(value);
+}
+
+
+void GuiView::zoomInPressed()
+{
+       DispatchResult dr;
+       dispatch(FuncRequest(LFUN_BUFFER_ZOOM_IN), dr);
+       scheduleRedrawWorkAreas();
+}
+
+
+void GuiView::zoomOutPressed()
+{
+       DispatchResult dr;
+       dispatch(FuncRequest(LFUN_BUFFER_ZOOM_OUT), dr);
+       scheduleRedrawWorkAreas();
+}
+
+
+void GuiView::showZoomContextMenu()
+{
+       QMenu * menu = guiApp->menus().menu(toqstr("context-zoom"), * this);
+       if (!menu)
+               return;
+       menu->exec(QCursor::pos());
+}
+
+
+void GuiView::showStatusBarContextMenu()
+{
+       QMenu * menu = guiApp->menus().menu(toqstr("context-statusbar"), * this);
+       if (!menu)
+               return;
+       menu->exec(QCursor::pos());
+}
+
+
+void GuiView::scheduleRedrawWorkAreas()
+{
+       for (int i = 0; i < d.tabWorkAreaCount(); i++) {
+               TabWorkArea* ta = d.tabWorkArea(i);
+               for (int u = 0; u < ta->count(); u++) {
+                       ta->workArea(u)->scheduleRedraw(true);
+               }
+       }
 }
 
 
@@ -745,7 +924,7 @@ QVector<GuiWorkArea*> GuiView::GuiViewPrivate::guiWorkAreas()
 static void handleExportStatus(GuiView * view, Buffer::ExportStatus status,
        string const & format)
 {
-       docstring const fmt = theFormats().prettyName(format);
+       docstring const fmt = translateIfPossible(theFormats().prettyName(format));
        docstring msg;
        switch (status) {
        case Buffer::ExportSuccess:
@@ -825,14 +1004,18 @@ void GuiView::saveLayout() const
        settings.setValue("devel_mode", devel_mode_);
        settings.beginGroup("views");
        settings.beginGroup(QString::number(id_));
-#if defined(Q_WS_X11) || defined(QPA_XCB)
-       settings.setValue("pos", pos());
-       settings.setValue("size", size());
-#else
-       settings.setValue("geometry", saveGeometry());
-#endif
+       if (guiApp->platformName() == "qt4x11" || guiApp->platformName() == "xcb") {
+               settings.setValue("pos", pos());
+               settings.setValue("size", size());
+       } else
+               settings.setValue("geometry", saveGeometry());
        settings.setValue("layout", saveState(0));
        settings.setValue("icon_size", toqstr(d.iconSize(iconSize())));
+       settings.setValue("zoom_value_visible", zoom_value_->isVisible());
+       settings.setValue("zoom_slider_visible", zoom_slider_->isVisible());
+       settings.setValue("word_count_enabled", word_count_enabled_);
+       settings.setValue("char_count_enabled", char_count_enabled_);
+       settings.setValue("char_nb_count_enabled", char_nb_count_enabled_);
 }
 
 
@@ -841,13 +1024,19 @@ void GuiView::saveUISettings() const
        QSettings settings;
 
        // Save the toolbar private states
-       ToolbarMap::iterator end = d.toolbars_.end();
-       for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-               it->second->saveSession(settings);
+       for (auto const & tb_p : d.toolbars_)
+               tb_p.second->saveSession(settings);
        // Now take care of all other dialogs
-       map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
-       for (; it!= d.dialogs_.end(); ++it)
-               it->second->saveSession(settings);
+       for (auto const & dlg_p : d.dialogs_)
+               dlg_p.second->saveSession(settings);
+}
+
+
+void GuiView::setCurrentZoom(const int v)
+{
+       lyxrc.currentZoom = v;
+       zoom_value_->setText(toqstr(bformat(_("[[ZOOM]]%1$d%"), v)));
+       Q_EMIT currentZoomChanged(v);
 }
 
 
@@ -857,9 +1046,8 @@ bool GuiView::restoreLayout()
        zoom_ratio_ = settings.value("zoom_ratio", 1.0).toDouble();
        // Actual zoom value: default zoom + fractional offset
        int zoom = (int)(lyxrc.defaultZoom * zoom_ratio_);
-       if (zoom < static_cast<int>(zoom_min_))
-               zoom = zoom_min_;
-       lyxrc.currentZoom = zoom;
+       zoom = min(max(zoom, zoom_min_), zoom_max_);
+       setCurrentZoom(zoom);
        devel_mode_ = settings.value("devel_mode", devel_mode_).toBool();
        settings.beginGroup("views");
        settings.beginGroup(QString::number(id_));
@@ -870,19 +1058,32 @@ bool GuiView::restoreLayout()
        //code below is skipped when when ~/.config/LyX is (re)created
        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();
-       QSize size = settings.value("size", QSize(690, 510)).toSize();
-       resize(size);
-       move(pos);
-#else
-       // Work-around for bug #6034: the window ends up in an undetermined
-       // state when trying to restore a maximized window when it is
-       // already maximized.
-       if (!(windowState() & Qt::WindowMaximized))
-               if (!restoreGeometry(settings.value("geometry").toByteArray()))
-                       setGeometry(50, 50, 690, 510);
-#endif
+       zoom_value_->setVisible(settings.value("zoom_value_visible", true).toBool());
+
+       bool const show_zoom_slider = settings.value("zoom_slider_visible", true).toBool();
+       zoom_slider_->setVisible(show_zoom_slider);
+       zoom_in_->setVisible(show_zoom_slider);
+       zoom_out_->setVisible(show_zoom_slider);
+
+       word_count_enabled_ = settings.value("word_count_enabled", true).toBool();
+       char_count_enabled_ = settings.value("char_count_enabled", true).toBool();
+       char_nb_count_enabled_ = settings.value("char_nb_count_enabled", true).toBool();
+       stat_counts_->setVisible(word_count_enabled_ || char_count_enabled_ || char_nb_count_enabled_);
+
+       if (guiApp->platformName() == "qt4x11" || guiApp->platformName() == "xcb") {
+               QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
+               QSize size = settings.value("size", QSize(690, 510)).toSize();
+               resize(size);
+               move(pos);
+       } else {
+               // Work-around for bug #6034: the window ends up in an undetermined
+               // state when trying to restore a maximized window when it is
+               // already maximized.
+               if (!(windowState() & Qt::WindowMaximized))
+                       if (!restoreGeometry(settings.value("geometry").toByteArray()))
+                               setGeometry(50, 50, 690, 510);
+       }
+
        // Make sure layout is correctly oriented.
        setLayoutDirection(qApp->layoutDirection());
 
@@ -901,12 +1102,10 @@ bool GuiView::restoreLayout()
                initToolbars();
 
        // init the toolbars that have not been restored
-       Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
-       Toolbars::Infos::iterator end = guiApp->toolbars().end();
-       for (; cit != end; ++cit) {
-               GuiToolbar * tb = toolbar(cit->name);
+       for (auto const & tb_p : guiApp->toolbars()) {
+               GuiToolbar * tb = toolbar(tb_p.name);
                if (tb && !tb->isRestored())
-                       initToolbar(cit->name);
+                       initToolbar(tb_p.name);
        }
 
        // update lock (all) toolbars positions
@@ -936,14 +1135,18 @@ void GuiView::updateLockToolbars()
                if (tb && tb->isMovable())
                        toolbarsMovable_ = true;
        }
+#if QT_VERSION >= 0x050200
+       // set unified mac toolbars only when not movable as recommended:
+       // https://doc.qt.io/qt-5/qmainwindow.html#unifiedTitleAndToolBarOnMac-prop
+       setUnifiedTitleAndToolBarOnMac(!toolbarsMovable_);
+#endif
 }
 
 
 void GuiView::constructToolbars()
 {
-       ToolbarMap::iterator it = d.toolbars_.begin();
-       for (; it != d.toolbars_.end(); ++it)
-               delete it->second;
+       for (auto const & tb_p : d.toolbars_)
+               delete tb_p.second;
        d.toolbars_.clear();
 
        // I don't like doing this here, but the standard toolbar
@@ -953,20 +1156,18 @@ void GuiView::constructToolbars()
        d.layout_->move(0,0);
 
        // extracts the toolbars from the backend
-       Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
-       Toolbars::Infos::iterator end = guiApp->toolbars().end();
-       for (; cit != end; ++cit)
-               d.toolbars_[cit->name] =  new GuiToolbar(*cit, *this);
+       for (ToolbarInfo const & inf : guiApp->toolbars())
+               d.toolbars_[inf.name] =  new GuiToolbar(inf, *this);
+
+       DynamicMenuButton::resetIconCache();
 }
 
 
 void GuiView::initToolbars()
 {
        // extracts the toolbars from the backend
-       Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
-       Toolbars::Infos::iterator end = guiApp->toolbars().end();
-       for (; cit != end; ++cit)
-               initToolbar(cit->name);
+       for (ToolbarInfo const & inf : guiApp->toolbars())
+               initToolbar(inf.name);
 }
 
 
@@ -1082,7 +1283,7 @@ bool GuiView::prepareAllBuffersForLogout()
        // We cannot use a for loop as the buffer list cycles.
        Buffer * b = first;
        do {
-               if (!saveBufferIfNeeded(const_cast<Buffer &>(*b), false))
+               if (!saveBufferIfNeeded(*b, false))
                        return false;
                b = theBufferList().next(b);
        } while (b != first);
@@ -1139,6 +1340,7 @@ void GuiView::closeEvent(QCloseEvent * close_event)
 
        // Make sure the timer time out will not trigger a statusbar update.
        d.statusbar_timer_.stop();
+       d.statusbar_stats_timer_.stop();
 
        // Saving fullscreen requires additional tweaks in the toolbar code.
        // It wouldn't also work under linux natively.
@@ -1178,15 +1380,12 @@ void GuiView::dropEvent(QDropEvent * event)
                vector<const Format *> found_formats;
 
                // Find all formats that have the correct extension.
-               vector<const Format *> const & import_formats
-                       = theConverters().importableFormats();
-               vector<const Format *>::const_iterator it = import_formats.begin();
-               for (; it != import_formats.end(); ++it)
-                       if ((*it)->hasExtension(ext))
-                               found_formats.push_back(*it);
+               for (const Format * fmt : theConverters().importableFormats())
+                       if (fmt->hasExtension(ext))
+                               found_formats.push_back(fmt);
 
                FuncRequest cmd;
-               if (found_formats.size() >= 1) {
+               if (!found_formats.empty()) {
                        if (found_formats.size() > 1) {
                                //FIXME: show a dialog to choose the correct importable format
                                LYXERR(Debug::FILES,
@@ -1247,6 +1446,73 @@ void GuiView::clearMessage()
        d.statusbar_timer_.stop();
 }
 
+void GuiView::showStats()
+{
+       if (!statsEnabled())
+               return;
+
+       d.time_to_update -= d.timer_rate;
+
+       BufferView * bv = currentBufferView();
+       Buffer * buf = bv ? &bv->buffer() : nullptr;
+       if (!buf) {
+               stat_counts_->hide();
+               return;
+       }
+
+       Cursor const & cur = bv->cursor();
+
+       // we start new selection and need faster update
+       if (!d.already_in_selection_ && cur.selection())
+               d.time_to_update = 0;
+
+       if (d.time_to_update > 0)
+               return;
+
+       DocIterator from, to;
+       if (cur.selection()) {
+               from = cur.selectionBegin();
+               to = cur.selectionEnd();
+               d.already_in_selection_ = true;
+       } else {
+               from = doc_iterator_begin(buf);
+               to = doc_iterator_end(buf);
+               d.already_in_selection_ = false;
+       }
+
+       buf->updateStatistics(from, to);
+
+       QStringList stats;
+       if (word_count_enabled_) {
+               int const words = buf->wordCount();
+               if (words == 1)
+                       stats << toqstr(bformat(_("%1$d Word"), words));
+               else
+                       stats << toqstr(bformat(_("%1$d Words"), words));
+       }
+       int const chars_with_blanks = buf->charCount(true);
+       if (char_count_enabled_) {
+               if (chars_with_blanks == 1)
+                       stats << toqstr(bformat(_("%1$d Character"), chars_with_blanks));
+               else
+                       stats << toqstr(bformat(_("%1$d Characters"), chars_with_blanks));
+       }
+       if (char_nb_count_enabled_) {
+               int const chars = buf->charCount(false);
+               if (chars == 1)
+                       stats << toqstr(bformat(_("%1$d Character (no Blanks)"), chars));
+               else
+                       stats << toqstr(bformat(_("%1$d Characters (no Blanks)"), chars));
+       }
+       stat_counts_->setText(stats.join(qt_(", [[stats separator]]")));
+       stat_counts_->show();
+
+       d.time_to_update = d.default_stats_rate;
+       // fast updates for small selections
+       if (chars_with_blanks < d.max_sel_chars && cur.selection())
+               d.time_to_update = d.timer_rate;
+}
+
 
 void GuiView::updateWindowTitle(GuiWorkArea * wa)
 {
@@ -1319,6 +1585,10 @@ void GuiView::onBufferViewChanged()
        // Buffer-dependent dialogs must be updated. This is done here because
        // some dialogs require buffer()->text.
        updateDialogs();
+       zoom_slider_->setEnabled(currentBufferView());
+       zoom_value_->setEnabled(currentBufferView());
+       zoom_in_->setEnabled(currentBufferView());
+       zoom_out_->setEnabled(currentBufferView());
 }
 
 
@@ -1382,6 +1652,12 @@ void GuiView::showMessage()
 }
 
 
+bool GuiView::statsEnabled() const
+{
+       return word_count_enabled_ || char_count_enabled_ || char_nb_count_enabled_;
+}
+
+
 bool GuiView::event(QEvent * e)
 {
        switch (e->type())
@@ -1401,6 +1677,55 @@ bool GuiView::event(QEvent * e)
        //case QEvent::Drop:
        //      break;
 
+       case QEvent::WindowStateChange: {
+               QWindowStateChangeEvent * ev = (QWindowStateChangeEvent*)e;
+               bool ofstate = (ev->oldState() & Qt::WindowFullScreen);
+               bool result = QMainWindow::event(e);
+               bool nfstate = (windowState() & Qt::WindowFullScreen);
+               if (!ofstate && nfstate) {
+                       LYXERR(Debug::DEBUG, "GuiView: WindowStateChange(): full-screen " << nfstate);
+                       // switch to full-screen state
+                       if (lyxrc.full_screen_statusbar)
+                               statusBar()->hide();
+                       if (lyxrc.full_screen_menubar)
+                               menuBar()->hide();
+                       if (lyxrc.full_screen_toolbars) {
+                               for (auto const & tb_p  : d.toolbars_)
+                                       if (tb_p.second->isVisibilityOn() && tb_p.second->isVisible())
+                                               tb_p.second->hide();
+                       }
+                       for (int i = 0; i != d.splitter_->count(); ++i)
+                               d.tabWorkArea(i)->setFullScreen(true);
+#if QT_VERSION > 0x050903
+                       //Qt's 5.9.4 ba44cdae38406c safe area measures won't allow us to go negative in margins
+                       setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, false);
+#endif
+                       setContentsMargins(-2, -2, -2, -2);
+                       // bug 5274
+                       hideDialogs("prefs", nullptr);
+               } else if (ofstate && !nfstate) {
+                       LYXERR(Debug::DEBUG, "GuiView: WindowStateChange(): full-screen " << nfstate);
+                       // switch back from full-screen state
+                       if (lyxrc.full_screen_statusbar && !statusBar()->isVisible())
+                               statusBar()->show();
+                       if (lyxrc.full_screen_menubar && !menuBar()->isVisible())
+                               menuBar()->show();
+                       if (lyxrc.full_screen_toolbars) {
+                               for (auto const & tb_p  : d.toolbars_)
+                                       if (tb_p.second->isVisibilityOn() && !tb_p.second->isVisible())
+                                               tb_p.second->show();
+                               //updateToolbars();
+                       }
+                       for (int i = 0; i != d.splitter_->count(); ++i)
+                               d.tabWorkArea(i)->setFullScreen(false);
+#if QT_VERSION > 0x050903
+                       setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, true);
+#endif
+                       setContentsMargins(0, 0, 0, 0);
+               }
+               return result;
+       }
+
        case QEvent::WindowActivate: {
                GuiView * old_view = guiApp->currentView();
                if (this == old_view) {
@@ -1437,6 +1762,33 @@ bool GuiView::event(QEvent * e)
                return QMainWindow::event(e);
        }
 
+       case QEvent::ApplicationPaletteChange: {
+               // runtime switch from/to dark mode
+               refillToolbars();
+               return QMainWindow::event(e);
+       }
+
+       case QEvent::Gesture: {
+               QGestureEvent *ge = static_cast<QGestureEvent*>(e);
+               QGesture *gp = ge->gesture(Qt::PinchGesture);
+               if (gp) {
+                       QPinchGesture *pinch = static_cast<QPinchGesture *>(gp);
+                       QPinchGesture::ChangeFlags changeFlags = pinch->changeFlags();
+                       qreal totalScaleFactor = pinch->totalScaleFactor();
+                       LYXERR(Debug::GUI, "totalScaleFactor: " << totalScaleFactor);
+                       if (pinch->state() == Qt::GestureStarted) {
+                               initialZoom_ = lyxrc.currentZoom;
+                               LYXERR(Debug::GUI, "initialZoom_: " << initialZoom_);
+                       }
+                       if (changeFlags & QPinchGesture::ScaleFactorChanged) {
+                               qreal factor = initialZoom_ * totalScaleFactor;
+                               LYXERR(Debug::GUI, "scaleFactor: " << factor);
+                               zoomValueChanged(factor);
+                       }
+               }
+               return QMainWindow::event(e);
+       }
+
        default:
                return QMainWindow::event(e);
        }
@@ -1659,6 +2011,17 @@ void GuiView::removeWorkArea(GuiWorkArea * wa)
 }
 
 
+bool GuiView::hasVisibleWorkArea(GuiWorkArea * wa) const
+{
+       for (int i = 0; i < d.splitter_->count(); ++i)
+               if (d.tabWorkArea(i)->currentWorkArea() == wa)
+                       return true;
+
+       FindAndReplace * fr = static_cast<FindAndReplace*>(find("findreplaceadv", false));
+       return fr->isVisible() && fr->hasWorkArea(wa);
+}
+
+
 LayoutBox * GuiView::getLayoutDialog() const
 {
        return d.layout_;
@@ -1674,7 +2037,6 @@ void GuiView::updateLayoutList()
 
 void GuiView::updateToolbars()
 {
-       ToolbarMap::iterator end = d.toolbars_.end();
        if (d.current_work_area_) {
                int context = 0;
                if (d.current_work_area_->bufferView().cursor().inMathed()
@@ -1699,11 +2061,19 @@ void GuiView::updateToolbars()
                        minibuffer_focus_ = false;
                }
 
-               for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-                       it->second->update(context);
+               for (auto const & tb_p : d.toolbars_)
+                       tb_p.second->update(context);
        } else
-               for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-                       it->second->update();
+               for (auto const & tb_p : d.toolbars_)
+                       tb_p.second->update();
+}
+
+
+void GuiView::refillToolbars()
+{
+       DynamicMenuButton::resetIconCache();
+       for (auto const & tb_p : d.toolbars_)
+               tb_p.second->refill();
 }
 
 
@@ -1883,6 +2253,30 @@ void GuiView::resetAutosaveTimers()
 }
 
 
+namespace {
+
+double zoomRatio(FuncRequest const & cmd, double const zr)
+{
+       if (cmd.argument().empty()) {
+               if (cmd.action() == LFUN_BUFFER_ZOOM)
+                       return 1.0;
+               else if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
+                       return zr + 0.1;
+               else // cmd.action() == LFUN_BUFFER_ZOOM_OUT
+                       return zr - 0.1;
+       } else {
+               if (cmd.action() == LFUN_BUFFER_ZOOM)
+                       return convert<int>(cmd.argument()) / double(lyxrc.defaultZoom);
+               else if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
+                       return zr + convert<int>(cmd.argument()) / 100.0;
+               else // cmd.action() == LFUN_BUFFER_ZOOM_OUT
+                       return zr - convert<int>(cmd.argument()) / 100.0;
+       }
+}
+
+}
+
+
 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 {
        bool enable = true;
@@ -2090,6 +2484,41 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                flag.setOnOff(devel_mode_);
                break;
 
+       case LFUN_TOOLBAR_SET: {
+               string const name = cmd.getArg(0);
+               string const state = cmd.getArg(1);
+               if (name.empty() || state.empty()) {
+                       enable = false;
+                       docstring const msg =
+                               _("Function toolbar-set requires two arguments!");
+                       flag.message(msg);
+                       break;
+               }
+               if (state != "on" && state != "off" && state != "auto") {
+                       enable = false;
+                       docstring const msg =
+                               bformat(_("Invalid argument \"%1$s\" to function toolbar-set!"),
+                                       from_utf8(state));
+                       flag.message(msg);
+                       break;
+               }
+               if (GuiToolbar * t = toolbar(name)) {
+                       bool const autovis = t->visibility() & Toolbars::AUTO;
+                       if (state == "on")
+                               flag.setOnOff(t->isVisible() && !autovis);
+                       else if (state == "off")
+                               flag.setOnOff(!t->isVisible() && !autovis);
+                       else if (state == "auto")
+                               flag.setOnOff(autovis);
+               } else {
+                       enable = false;
+                       docstring const msg =
+                               bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name));
+                       flag.message(msg);
+               }
+               break;
+       }
+
        case LFUN_TOOLBAR_TOGGLE: {
                string const name = cmd.getArg(0);
                if (GuiToolbar * t = toolbar(name))
@@ -2129,7 +2558,18 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                break;
 
        case LFUN_UI_TOGGLE:
-               flag.setOnOff(isFullScreen());
+               if (cmd.argument() == "zoomlevel") {
+                       flag.setOnOff(zoom_value_ ? zoom_value_->isVisible() : false);
+               } else if (cmd.argument() == "zoomslider") {
+                       flag.setOnOff(zoom_slider_ ? zoom_slider_->isVisible() : false);
+               } else if (cmd.argument() == "statistics-w") {
+                       flag.setOnOff(word_count_enabled_);
+               } else if (cmd.argument() == "statistics-cb") {
+                       flag.setOnOff(char_count_enabled_);
+               } else if (cmd.argument() == "statistics-c") {
+                       flag.setOnOff(char_nb_count_enabled_);
+               } else
+                       flag.setOnOff(isFullScreen());
                break;
 
        case LFUN_DIALOG_DISCONNECT_INSET:
@@ -2166,7 +2606,6 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                        enable = FileName(doc_buffer->logName()).isReadableFile();
                else if (name == "spellchecker")
                        enable = theSpellChecker()
-                               && !doc_buffer->isReadonly()
                                && !doc_buffer->text().empty();
                else if (name == "vclog")
                        enable = doc_buffer->lyxvc().inUse();
@@ -2223,36 +2662,25 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                break;
 
        case LFUN_BUFFER_ZOOM_OUT:
-       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.currentZoom <= zoom_min_ && neg_zoom) {
+       case LFUN_BUFFER_ZOOM_IN:
+       case LFUN_BUFFER_ZOOM: {
+               int const zoom = (int)(lyxrc.defaultZoom * zoomRatio(cmd, zoom_ratio_));
+               if (zoom < zoom_min_) {
                        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_ZOOM: {
-               bool const less_than_min_zoom =
-                       !cmd.argument().empty() && convert<int>(cmd.argument()) < zoom_min_;
-               if (lyxrc.currentZoom <= zoom_min_ && less_than_min_zoom) {
+               } else if (zoom > zoom_max_) {
                        docstring const msg =
-                               bformat(_("Zoom level cannot be less than %1$d%."), zoom_min_);
+                               bformat(_("Zoom level cannot be more than %1$d%."), zoom_max_);
                        flag.message(msg);
                        enable = false;
-               }
-               else
+               } else
                        enable = doc_buffer;
                break;
        }
 
+
        case LFUN_BUFFER_MOVE_NEXT:
        case LFUN_BUFFER_MOVE_PREVIOUS:
                // we do not cycle when moving
@@ -2315,7 +2743,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
        case LFUN_WINDOW_RAISE:
                break;
        case LFUN_FORWARD_SEARCH:
-               enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty());
+               enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty()) &&
+                       doc_buffer && doc_buffer->isSyncTeXenabled();
                break;
 
        case LFUN_FILE_INSERT_PLAINTEXT:
@@ -2327,6 +2756,10 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                flag.setOnOff(lyxrc.spellcheck_continuously);
                break;
 
+       case LFUN_CITATION_OPEN:
+               enable = true;
+               break;
+
        default:
                return false;
        }
@@ -2362,9 +2795,9 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
        Buffer * newBuffer = nullptr;
        try {
                newBuffer = checkAndLoadLyXFile(filename);
-       } catch (ExceptionMessage const & e) {
+       } catch (ExceptionMessage const &) {
                setBusy(false);
-               throw(e);
+               throw;
        }
        setBusy(false);
 
@@ -2403,7 +2836,11 @@ void GuiView::openDocument(string const & fname)
                dlg.setButton1(qt_("D&ocuments"), toqstr(lyxrc.document_path));
                dlg.setButton2(qt_("&Examples"), toqstr(lyxrc.example_path));
 
-               QStringList const filter(qt_("LyX Documents (*.lyx)"));
+               QStringList const filter({
+                               qt_("LyX Documents (*.lyx)"),
+                               qt_("LyX Document Backups (*.lyx~)"),
+                               qt_("All Files (*.*)")
+               });
                FileDialog::Result result =
                        dlg.open(toqstr(initpath), filter);
 
@@ -2470,25 +2907,23 @@ static bool import(GuiView * lv, FileName const & filename,
        string loader_format;
        vector<string> loaders = theConverters().loaders();
        if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
-               vector<string>::const_iterator it = loaders.begin();
-               vector<string>::const_iterator en = loaders.end();
-               for (; it != en; ++it) {
-                       if (!theConverters().isReachable(format, *it))
+               for (string const & loader : loaders) {
+                       if (!theConverters().isReachable(format, loader))
                                continue;
 
                        string const tofile =
                                support::changeExtension(filename.absFileName(),
-                               theFormats().extension(*it));
+                               theFormats().extension(loader));
                        if (theConverters().convert(nullptr, filename, FileName(tofile),
-                               filename, format, *it, errorList) != Converters::SUCCESS)
+                               filename, format, loader, errorList) != Converters::SUCCESS)
                                return false;
-                       loader_format = *it;
+                       loader_format = loader;
                        break;
                }
                if (loader_format.empty()) {
                        frontend::Alert::error(_("Couldn't import file"),
                                         bformat(_("No information for importing the format %1$s."),
-                                        theFormats().prettyName(format)));
+                                        translateIfPossible(theFormats().prettyName(format))));
                        return false;
                }
        } else
@@ -2535,13 +2970,13 @@ void GuiView::importDocument(string const & argument)
                }
 
                docstring const text = bformat(_("Select %1$s file to import"),
-                       theFormats().prettyName(format));
+                       translateIfPossible(theFormats().prettyName(format)));
 
                FileDialog dlg(toqstr(text));
                dlg.setButton1(qt_("D&ocuments"), toqstr(lyxrc.document_path));
                dlg.setButton2(qt_("&Examples"), toqstr(lyxrc.example_path));
 
-               docstring filter = theFormats().prettyName(format);
+               docstring filter = translateIfPossible(theFormats().prettyName(format));
                filter += " (*.{";
                // FIXME UNICODE
                filter += from_utf8(theFormats().extensions(format));
@@ -2653,11 +3088,11 @@ void GuiView::newDocument(string const & filename, string templatefile,
 }
 
 
-void GuiView::insertLyXFile(docstring const & fname, bool ignorelang)
+bool GuiView::insertLyXFile(docstring const & fname, bool ignorelang)
 {
        BufferView * bv = documentBufferView();
        if (!bv)
-               return;
+               return false;
 
        // FIXME UNICODE
        FileName filename(to_utf8(fname));
@@ -2679,7 +3114,7 @@ void GuiView::insertLyXFile(docstring const & fname, bool ignorelang)
                                         QStringList(qt_("LyX Documents (*.lyx)")));
 
                if (result.first == FileDialog::Later)
-                       return;
+                       return false;
 
                // FIXME UNICODE
                filename.set(fromqstr(result.second));
@@ -2688,12 +3123,13 @@ void GuiView::insertLyXFile(docstring const & fname, bool ignorelang)
                if (filename.empty()) {
                        // emit message signal.
                        message(_("Canceled."));
-                       return;
+                       return false;
                }
        }
 
        bv->insertLyXFile(filename, ignorelang);
        bv->buffer().errors("Parse");
+       return true;
 }
 
 
@@ -2794,8 +3230,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin
                dlg.setButton1(qt_("D&ocuments"), toqstr(lyxrc.document_path));
                dlg.setButton2(qt_("&Templates"), toqstr(lyxrc.template_path));
 
-               if (!isLyXFileName(fname.absFileName()))
-                       fname.changeExtension(".lyx");
+               fname.ensureExtension(".lyx");
 
                string const path = as_template ?
                                        getTemplatesPath(b)
@@ -2813,8 +3248,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin
                if (fname.empty())
                        return false;
 
-               if (!isLyXFileName(fname.absFileName()))
-                       fname.changeExtension(".lyx");
+               fname.ensureExtension(".lyx");
        }
 
        // fname is now the new Buffer location.
@@ -2962,8 +3396,10 @@ bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
        if (fmt_name.empty() || fname.empty())
                return false;
 
+       fname.ensureExtension(theFormats().extension(fmt_name));
+
        // fname is now the new Buffer location.
-       if (FileName(fname).exists()) {
+       if (fname.exists()) {
                docstring const file = makeDisplayPath(fname.absFileName(), 30);
                docstring text = bformat(_("The document %1$s already "
                                           "exists.\n\nDo you want to "
@@ -3070,7 +3506,9 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa)
                                  "  Tools->Preferences->Look&Feel->UserInterface\n"
                                ), file);
                        int ret = Alert::prompt(_("Close or hide document?"),
-                               text, 0, 1, _("&Close"), _("&Hide"));
+                               text, 0, 2, _("&Close"), _("&Hide"), _("&Cancel"));
+                       if (ret == 2)
+                               return false;
                        close_buffer = (ret == 0);
                }
        }
@@ -3107,6 +3545,14 @@ void GuiView::writeSession() const {
 
 bool GuiView::closeBufferAll()
 {
+
+       for (auto & buf : theBufferList()) {
+               if (!saveBufferIfNeeded(*buf, false)) {
+                       // Closing has been cancelled, so abort.
+                       return false;
+               }
+       }
+
        // Close the workareas in all other views
        QList<int> const ids = guiApp->viewIds();
        for (int i = 0; i != ids.size(); ++i) {
@@ -3118,9 +3564,6 @@ bool GuiView::closeBufferAll()
        if (!closeWorkAreaAll())
                return false;
 
-       // Now close the hidden buffers. We prevent hidden buffers from being
-       // dirty, so we can just close them.
-       theBufferList().closeAll();
        return true;
 }
 
@@ -3180,11 +3623,7 @@ bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
 bool GuiView::closeBuffer(Buffer & buf)
 {
        bool success = true;
-       ListOfBuffers clist = buf.getChildren();
-       ListOfBuffers::const_iterator it = clist.begin();
-       ListOfBuffers::const_iterator const bend = clist.end();
-       for (; it != bend; ++it) {
-               Buffer * child_buf = *it;
+       for (Buffer * child_buf : buf.getChildren()) {
                if (theBufferList().isOthersChild(&buf, child_buf)) {
                        child_buf->setParent(nullptr);
                        continue;
@@ -3209,12 +3648,13 @@ bool GuiView::closeBuffer(Buffer & buf)
                        // Even in this case, children can be dirty (e.g.,
                        // after a label change in the master, see #11405).
                        // Therefore, check this
-                       if (closing_ && (child_buf->isClean() || child_buf->paragraphs().empty()))
+                       if (closing_ && (child_buf->isClean() || child_buf->paragraphs().empty())) {
                                // If we are in a close_event all children will be closed in some time,
                                // so no need to do it here. This will ensure that the children end up
                                // in the session file in the correct order. If we close the master
                                // buffer, we can close or release the child buffers here too.
                                continue;
+                       }
                        // Save dirty buffers also if closing_!
                        if (saveBufferIfNeeded(*child_buf, false)) {
                                child_buf->removeAutosaveFile();
@@ -3230,9 +3670,10 @@ bool GuiView::closeBuffer(Buffer & buf)
        if (success) {
                // goto bookmark to update bookmark pit.
                // FIXME: we should update only the bookmarks related to this buffer!
+               // FIXME: this is done also in LFUN_WINDOW_CLOSE!
                LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
-               for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
-                       guiApp->gotoBookmark(i+1, false, false);
+               for (unsigned int i = 1; i < theSession().bookmarks().size(); ++i)
+                       guiApp->gotoBookmark(i, false, false);
 
                if (saveBufferIfNeeded(buf, false)) {
                        buf.removeAutosaveFile();
@@ -3434,10 +3875,7 @@ bool GuiView::reloadBuffer(Buffer & buf)
 
 void GuiView::checkExternallyModifiedBuffers()
 {
-       BufferList::iterator bit = theBufferList().begin();
-       BufferList::iterator const bend = theBufferList().end();
-       for (; bit != bend; ++bit) {
-               Buffer * buf = *bit;
+       for (Buffer * buf : theBufferList()) {
                if (buf->fileName().exists() && buf->isChecksumModified()) {
                        docstring text = bformat(_("Document \n%1$s\n has been externally modified."
                                        " Reload now? Any local changes will be lost."),
@@ -3722,7 +4160,7 @@ bool GuiView::goToFileRow(string const & argument)
        setBuffer(buf);
        bool success = documentBufferView()->setCursorFromRow(row);
        if (!success) {
-               LYXERR(Debug::LATEX,
+               LYXERR(Debug::OUTFILE,
                       "setCursorFromRow: invalid position for row " << row);
                frontend::Alert::error(_("Inverse Search Failed"),
                                       _("Invalid position requested by inverse search.\n"
@@ -3781,14 +4219,13 @@ Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy(
 }
 
 
-bool GuiView::GuiViewPrivate::asyncBufferProcessing(
-                          string const & argument,
+bool GuiView::GuiViewPrivate::asyncBufferProcessing(string const & argument,
                           Buffer const * used_buffer,
                           docstring const & msg,
                           Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
                           Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
                           Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const,
-                          bool allow_async)
+                          bool allow_async, bool use_tmpdir)
 {
        if (!used_buffer)
                return false;
@@ -3824,7 +4261,7 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing(
        } else {
                Buffer::ExportStatus status;
                if (syncFunc) {
-                       status = (used_buffer->*syncFunc)(format, false);
+                       status = (used_buffer->*syncFunc)(format, use_tmpdir);
                } else if (previewFunc) {
                        status = (used_buffer->*previewFunc)(format);
                } else
@@ -3981,7 +4418,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                _("Exporting ..."),
                                                &GuiViewPrivate::compileAndDestroy,
                                                &Buffer::doExport,
-                                               nullptr, cmd.allowAsync());
+                                               nullptr, cmd.allowAsync(), true);
                        break;
                }
                case LFUN_BUFFER_VIEW: {
@@ -3999,7 +4436,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                                docstring(),
                                                &GuiViewPrivate::compileAndDestroy,
                                                &Buffer::doExport,
-                                               nullptr, cmd.allowAsync());
+                                               nullptr, cmd.allowAsync(), true);
                        break;
                }
                case LFUN_MASTER_BUFFER_VIEW: {
@@ -4012,6 +4449,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                }
                case LFUN_EXPORT_CANCEL: {
                        Systemcall::killscript();
+                       Q_EMIT scriptKilled();
                        break;
                }
                case LFUN_BUFFER_SWITCH: {
@@ -4094,10 +4532,11 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
 
                case LFUN_FILE_INSERT: {
-                       if (cmd.getArg(1) == "ignorelang")
-                               insertLyXFile(from_utf8(cmd.getArg(0)), true);
-                       else
-                               insertLyXFile(cmd.argument());
+                       bool const ignore_lang = cmd.getArg(1) == "ignorelang";
+                       if (insertLyXFile(from_utf8(cmd.getArg(0)), ignore_lang)) {
+                               dr.forceBufferUpdate();
+                               dr.screenUpdate(Update::Force);
+                       }
                        break;
                }
 
@@ -4246,6 +4685,14 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                dr.setMessage(_("Developer mode is now disabled."));
                        break;
 
+               case LFUN_TOOLBAR_SET: {
+                       string const name = cmd.getArg(0);
+                       string const state = cmd.getArg(1);
+                       if (GuiToolbar * t = toolbar(name))
+                               t->setState(state);
+                       break;
+               }
+
                case LFUN_TOOLBAR_TOGGLE: {
                        string const name = cmd.getArg(0);
                        if (GuiToolbar * t = toolbar(name))
@@ -4270,12 +4717,11 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                        dr.setMessage(_("Toolbars unlocked."));
                                else
                                        dr.setMessage(_("Toolbars locked."));
-                       } else if (GuiToolbar * t = toolbar(name)) {
+                       } else if (GuiToolbar * tb = toolbar(name))
                                // toggle current toolbar movablity
-                               t->movable();
-                               // update lock (all) toolbars positions
-                               updateLockToolbars();
-                       }
+                               tb->movable();
+                       // update lock (all) toolbars positions
+                       updateLockToolbars();
                        break;
                }
 
@@ -4352,6 +4798,9 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                sdata = bv->cursor().getEncoding()->name();
                                if (!sdata.empty())
                                        showDialog("symbols", sdata);
+                       } else if (name == "findreplace") {
+                               sdata = to_utf8(bv->cursor().selectionAsString(false));
+                               showDialog(name, sdata);
                        // bug 5274
                        } else if (name == "prefs" && isFullScreen()) {
                                lfunUiToggle("fullscreen");
@@ -4449,34 +4898,23 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                case LFUN_BUFFER_ZOOM_IN:
                case LFUN_BUFFER_ZOOM_OUT:
                case LFUN_BUFFER_ZOOM: {
-                       if (cmd.argument().empty()) {
-                               if (cmd.action() == LFUN_BUFFER_ZOOM)
-                                       zoom_ratio_ = 1.0;
-                               else if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
-                                       zoom_ratio_ += 0.1;
-                               else
-                                       zoom_ratio_ -= 0.1;
-                       } else {
-                               if (cmd.action() == LFUN_BUFFER_ZOOM)
-                                       zoom_ratio_ = convert<int>(cmd.argument()) / double(lyxrc.defaultZoom);
-                               else if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
-                                       zoom_ratio_ += convert<int>(cmd.argument()) / 100.0;
-                               else
-                                       zoom_ratio_ -= convert<int>(cmd.argument()) / 100.0;
-                       }
+                       zoom_ratio_ = zoomRatio(cmd, zoom_ratio_);
 
                        // Actual zoom value: default zoom + fractional extra value
                        int zoom = (int)(lyxrc.defaultZoom * zoom_ratio_);
-                       if (zoom < static_cast<int>(zoom_min_))
-                               zoom = zoom_min_;
+                       zoom = min(max(zoom, zoom_min_), zoom_max_);
 
-                       lyxrc.currentZoom = zoom;
+                       setCurrentZoom(zoom);
 
                        dr.setMessage(bformat(_("Zoom level is now %1$d% (default value: %2$d%)"),
                                              lyxrc.currentZoom, lyxrc.defaultZoom));
 
                        guiApp->fontLoader().update();
-                       dr.screenUpdate(Update::Force | Update::FitCursor);
+                       // Regenerate instant previews
+                       if (lyxrc.preview != LyXRC::PREVIEW_OFF
+                           && doc_buffer && doc_buffer->loader())
+                               doc_buffer->loader()->refreshPreviews();
+                       dr.screenUpdate(Update::ForceAll | Update::FitCursor);
                        break;
                }
 
@@ -4534,10 +4972,12 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                dr.setMessage(_("Please, preview the document first."));
                                break;
                        }
+                       bool const goto_dvi = have_dvi && !lyxrc.forward_search_dvi.empty();
+                       bool const goto_pdf = have_pdf && !lyxrc.forward_search_pdf.empty();
                        string outname = dviname.onlyFileName();
                        string command = lyxrc.forward_search_dvi;
-                       if (!have_dvi || (have_pdf &&
-                           pdfname.lastModified() > dviname.lastModified())) {
+                       if ((!goto_dvi || goto_pdf) &&
+                           pdfname.lastModified() > dviname.lastModified()) {
                                outname = pdfname.onlyFileName();
                                command = lyxrc.forward_search_pdf;
                        }
@@ -4568,6 +5008,16 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        dr.screenUpdate(Update::Force);
                        break;
 
+               case LFUN_CITATION_OPEN: {
+                       string pdfv, psv;
+                       if (theFormats().getFormat("pdf"))
+                               pdfv = theFormats().getFormat("pdf")->viewer();
+                       if (theFormats().getFormat("ps"))
+                               psv = theFormats().getFormat("ps")->viewer();
+                       frontend::showTarget(argument, pdfv, psv);
+                       break;
+               }
+
                default:
                        // The LFUN must be for one of BufferView, Buffer or Cursor;
                        // let's try that:
@@ -4575,12 +5025,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        break;
        }
 
-       // Part of automatic menu appearance feature.
-       if (isFullScreen()) {
-               if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
-                       menuBar()->hide();
-       }
-
        // Need to update bv because many LFUNs here might have destroyed it
        bv = currentBufferView();
 
@@ -4611,15 +5055,38 @@ bool GuiView::lfunUiToggle(string const & ui_component)
                statusBar()->setVisible(!statusBar()->isVisible());
        } else if (ui_component == "menubar") {
                menuBar()->setVisible(!menuBar()->isVisible());
-       } else
-       if (ui_component == "frame") {
+       } else if (ui_component == "zoomlevel") {
+               zoom_value_->setVisible(!zoom_value_->isVisible());
+       } else if (ui_component == "zoomslider") {
+               zoom_slider_->setVisible(!zoom_slider_->isVisible());
+               zoom_in_->setVisible(zoom_slider_->isVisible());
+               zoom_out_->setVisible(zoom_slider_->isVisible());
+       } else if (ui_component == "statistics-w") {
+               word_count_enabled_ = !word_count_enabled_;
+               if (statsEnabled())
+                       showStats();
+       } else if (ui_component == "statistics-cb") {
+               char_count_enabled_ = !char_count_enabled_;
+               if (statsEnabled())
+                       showStats();
+       } else if (ui_component == "statistics-c") {
+               char_nb_count_enabled_ = !char_nb_count_enabled_;
+               if (statsEnabled())
+                       showStats();
+       } else if (ui_component == "frame") {
                int const l = contentsMargins().left();
 
                //are the frames in default state?
                d.current_work_area_->setFrameStyle(QFrame::NoFrame);
                if (l == 0) {
+#if QT_VERSION >  0x050903
+                       setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, false);
+#endif
                        setContentsMargins(-2, -2, -2, -2);
                } else {
+#if QT_VERSION >  0x050903
+                       setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, true);
+#endif
                        setContentsMargins(0, 0, 0, 0);
                }
        } else
@@ -4627,41 +5094,14 @@ bool GuiView::lfunUiToggle(string const & ui_component)
                toggleFullScreen();
        } else
                return false;
+       stat_counts_->setVisible(statsEnabled());
        return true;
 }
 
 
 void GuiView::toggleFullScreen()
 {
-       if (isFullScreen()) {
-               for (int i = 0; i != d.splitter_->count(); ++i)
-                       d.tabWorkArea(i)->setFullScreen(false);
-               setContentsMargins(0, 0, 0, 0);
-               setWindowState(windowState() ^ Qt::WindowFullScreen);
-               restoreLayout();
-               menuBar()->show();
-               statusBar()->show();
-       } else {
-               // bug 5274
-               hideDialogs("prefs", nullptr);
-               for (int i = 0; i != d.splitter_->count(); ++i)
-                       d.tabWorkArea(i)->setFullScreen(true);
-               setContentsMargins(-2, -2, -2, -2);
-               saveLayout();
-               setWindowState(windowState() ^ Qt::WindowFullScreen);
-               if (lyxrc.full_screen_statusbar)
-                       statusBar()->hide();
-               if (lyxrc.full_screen_menubar)
-                       menuBar()->hide();
-               if (lyxrc.full_screen_toolbars) {
-                       ToolbarMap::iterator end = d.toolbars_.end();
-                       for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
-                               it->second->hide();
-               }
-       }
-
-       // give dialogs like the TOC a chance to adapt
-       updateDialogs();
+       setWindowState(windowState() ^ Qt::WindowFullScreen);
 }
 
 
@@ -4715,7 +5155,7 @@ namespace {
 char const * const dialognames[] = {
 
 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
-"citation", "compare", "comparehistory", "document", "errorlist", "ert",
+"citation", "compare", "comparehistory", "counter", "document", "errorlist", "ert",
 "external", "file", "findreplace", "findreplaceadv", "float", "graphics",
 "href", "include", "index", "index_print", "info", "listings", "label", "line",
 "log", "lyxfiles", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
@@ -4763,7 +5203,20 @@ void GuiView::resetDialogs()
 }
 
 
-Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
+void GuiView::flatGroupBoxes(const QObject * widget, bool flag)
+{
+       for (QObject * child: widget->children()) {
+               if (child->inherits("QGroupBox")) {
+                       QGroupBox * box = (QGroupBox*) child;
+                       box->setFlat(flag);
+               } else {
+                       flatGroupBoxes(child, flag);
+               }
+       }
+}
+
+
+Dialog * GuiView::find(string const & name, bool hide_it) const
 {
        if (!isValidName(name))
                return nullptr;
@@ -4775,9 +5228,23 @@ Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
                        it->second->hideView();
                return it->second.get();
        }
+       return nullptr;
+}
+
+
+Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
+{
+       Dialog * dialog = find(name, hide_it);
+       if (dialog != nullptr)
+               return dialog;
 
-       Dialog * dialog = build(name);
+       dialog = build(name);
        d.dialogs_[name].reset(dialog);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+       // Force a uniform style for group boxes
+       // On Mac non-flat works better, on Linux flat is standard
+       flatGroupBoxes(dialog->asQWidget(), guiApp->platformName() != "cocoa");
+#endif
        if (lyxrc.allow_geometry_session)
                dialog->restoreSession();
        if (hide_it)
@@ -4816,13 +5283,14 @@ void GuiView::doShowDialog(QString const & qname, QString const & qdata,
                                // activateWindow is needed for floating dockviews
                                dialog->asQWidget()->raise();
                                dialog->asQWidget()->activateWindow();
-                               dialog->asQWidget()->setFocus();
+                               if (dialog->wantInitialFocus())
+                                       dialog->asQWidget()->setFocus();
                        }
                }
        }
-       catch (ExceptionMessage const & ex) {
+       catch (ExceptionMessage const &) {
                d.in_show_ = false;
-               throw ex;
+               throw;
        }
        d.in_show_ = false;
 }
@@ -4869,21 +5337,15 @@ void GuiView::disconnectDialog(string const & name)
 
 void GuiView::hideAll() const
 {
-       map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
-       map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
-
-       for(; it != end; ++it)
-               it->second->hideView();
+       for(auto const & dlg_p : d.dialogs_)
+               dlg_p.second->hideView();
 }
 
 
 void GuiView::updateDialogs()
 {
-       map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
-       map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
-
-       for(; it != end; ++it) {
-               Dialog * dialog = it->second.get();
+       for(auto const & dlg_p : d.dialogs_) {
+               Dialog * dialog = dlg_p.second.get();
                if (dialog) {
                        if (dialog->needBufferOpen() && !documentBufferView())
                                hideDialog(fromqstr(dialog->name()), nullptr);
@@ -4895,134 +5357,10 @@ void GuiView::updateDialogs()
        updateLayoutList();
 }
 
-Dialog * createDialog(GuiView & lv, string const & name);
-
-// will be replaced by a proper factory...
-Dialog * createGuiAbout(GuiView & lv);
-Dialog * createGuiBibtex(GuiView & lv);
-Dialog * createGuiChanges(GuiView & lv);
-Dialog * createGuiCharacter(GuiView & lv);
-Dialog * createGuiCitation(GuiView & lv);
-Dialog * createGuiCompare(GuiView & lv);
-Dialog * createGuiCompareHistory(GuiView & lv);
-Dialog * createGuiDelimiter(GuiView & lv);
-Dialog * createGuiDocument(GuiView & lv);
-Dialog * createGuiErrorList(GuiView & lv);
-Dialog * createGuiExternal(GuiView & lv);
-Dialog * createGuiGraphics(GuiView & lv);
-Dialog * createGuiInclude(GuiView & lv);
-Dialog * createGuiIndex(GuiView & lv);
-Dialog * createGuiListings(GuiView & lv);
-Dialog * createGuiLog(GuiView & lv);
-Dialog * createGuiLyXFiles(GuiView & lv);
-Dialog * createGuiMathMatrix(GuiView & lv);
-Dialog * createGuiNote(GuiView & lv);
-Dialog * createGuiParagraph(GuiView & lv);
-Dialog * createGuiPhantom(GuiView & lv);
-Dialog * createGuiPreferences(GuiView & lv);
-Dialog * createGuiPrint(GuiView & lv);
-Dialog * createGuiPrintindex(GuiView & lv);
-Dialog * createGuiRef(GuiView & lv);
-Dialog * createGuiSearch(GuiView & lv);
-Dialog * createGuiSearchAdv(GuiView & lv);
-Dialog * createGuiSendTo(GuiView & lv);
-Dialog * createGuiShowFile(GuiView & lv);
-Dialog * createGuiSpellchecker(GuiView & lv);
-Dialog * createGuiSymbols(GuiView & lv);
-Dialog * createGuiTabularCreate(GuiView & lv);
-Dialog * createGuiTexInfo(GuiView & lv);
-Dialog * createGuiToc(GuiView & lv);
-Dialog * createGuiThesaurus(GuiView & lv);
-Dialog * createGuiViewSource(GuiView & lv);
-Dialog * createGuiWrap(GuiView & lv);
-Dialog * createGuiProgressView(GuiView & lv);
-
-
 
 Dialog * GuiView::build(string const & name)
 {
-       LASSERT(isValidName(name), return nullptr);
-
-       Dialog * dialog = createDialog(*this, name);
-       if (dialog)
-               return dialog;
-
-       if (name == "aboutlyx")
-               return createGuiAbout(*this);
-       if (name == "bibtex")
-               return createGuiBibtex(*this);
-       if (name == "changes")
-               return createGuiChanges(*this);
-       if (name == "character")
-               return createGuiCharacter(*this);
-       if (name == "citation")
-               return createGuiCitation(*this);
-       if (name == "compare")
-               return createGuiCompare(*this);
-       if (name == "comparehistory")
-               return createGuiCompareHistory(*this);
-       if (name == "document")
-               return createGuiDocument(*this);
-       if (name == "errorlist")
-               return createGuiErrorList(*this);
-       if (name == "external")
-               return createGuiExternal(*this);
-       if (name == "file")
-               return createGuiShowFile(*this);
-       if (name == "findreplace")
-               return createGuiSearch(*this);
-       if (name == "findreplaceadv")
-               return createGuiSearchAdv(*this);
-       if (name == "graphics")
-               return createGuiGraphics(*this);
-       if (name == "include")
-               return createGuiInclude(*this);
-       if (name == "index")
-               return createGuiIndex(*this);
-       if (name == "index_print")
-               return createGuiPrintindex(*this);
-       if (name == "listings")
-               return createGuiListings(*this);
-       if (name == "log")
-               return createGuiLog(*this);
-       if (name == "lyxfiles")
-               return createGuiLyXFiles(*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 == "phantom")
-               return createGuiPhantom(*this);
-       if (name == "prefs")
-               return createGuiPreferences(*this);
-       if (name == "ref")
-               return createGuiRef(*this);
-       if (name == "sendto")
-               return createGuiSendTo(*this);
-       if (name == "spellchecker")
-               return createGuiSpellchecker(*this);
-       if (name == "symbols")
-               return createGuiSymbols(*this);
-       if (name == "tabularcreate")
-               return createGuiTabularCreate(*this);
-       if (name == "texinfo")
-               return createGuiTexInfo(*this);
-       if (name == "thesaurus")
-               return createGuiThesaurus(*this);
-       if (name == "toc")
-               return createGuiToc(*this);
-       if (name == "view-source")
-               return createGuiViewSource(*this);
-       if (name == "wrap")
-               return createGuiWrap(*this);
-       if (name == "progress")
-               return createGuiProgressView(*this);
-
-       return nullptr;
+       return createDialog(*this, name);
 }
 
 
@@ -5033,6 +5371,14 @@ SEMenu::SEMenu(QWidget * parent)
                parent, SLOT(disableShellEscape()));
 }
 
+
+void PressableSvgWidget::mousePressEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton) {
+        Q_EMIT pressed();
+    }
+}
+
 } // namespace frontend
 } // namespace lyx