X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt%2FGuiView.cpp;h=82a6f173820eb82be645136b590f418c297ea5db;hb=70a71a82;hp=767791f57b47fab5920b2dead679a788f4816578;hpb=ada713a8815063cfa9fbd4666b3ae5a220a07eba;p=features.git diff --git a/src/frontends/qt/GuiView.cpp b/src/frontends/qt/GuiView.cpp index 767791f57b..82a6f17382 100644 --- a/src/frontends/qt/GuiView.cpp +++ b/src/frontends/qt/GuiView.cpp @@ -18,6 +18,7 @@ #include "DialogFactory.h" #include "DispatchResult.h" #include "FileDialog.h" +#include "FindAndReplace.h" #include "FontLoader.h" #include "GuiApplication.h" #include "GuiClickableLabel.h" @@ -68,6 +69,8 @@ #include "Toolbars.h" #include "version.h" +#include "graphics/PreviewLoader.h" + #include "support/convert.h" #include "support/debug.h" #include "support/ExceptionMessage.h" @@ -110,6 +113,8 @@ #include #include #include +#include +#include // sync with GuiAlert.cpp @@ -207,7 +212,6 @@ public: QStringList titlesegs = htext.split('\n'); int wline = 0; int hline = fm.maxHeight(); - QStringList::const_iterator sit; for (QString const & seg : titlesegs) { if (fm.width(seg) > wline) wline = fm.width(seg); @@ -521,6 +525,7 @@ public: /// QTimer statusbar_timer_; + QTimer statusbar_stats_timer_; /// auto-saving of buffers Timeout autosave_timeout_; @@ -544,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 GuiView::GuiViewPrivate::busyBuffers; @@ -551,8 +570,9 @@ QSet 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())); @@ -580,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,6 +633,10 @@ GuiView::GuiView(int id) // 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 search_mode mode = theGuiApp()->imageSearchMode(); QString fn = toqstr(lyx::libFileSearch("images", "busy", "svgz", mode).absFileName()); @@ -618,14 +645,34 @@ GuiView::GuiView(int id) // 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()), busySVG, SLOT(show())); connect(&d.processing_thread_watcher_, SIGNAL(finished()), busySVG, SLOT(hide())); - connect(busySVG, SIGNAL(pressed()), this, SLOT(checkCancelBackground())); + 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()); + 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 @@ -642,20 +689,24 @@ GuiView::GuiView(int id) 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(zoom_min_)) - zoom = zoom_min_; + 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 - zoom_in_ = new QPushButton(statusBar()); +#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_->setFlat(true); - zoom_in_->setFixedSize(QSize(fm.height(), fm.height())); - zoom_out_ = new QPushButton(statusBar()); + zoom_in_->setFixedSize(s); + zoom_in_->setAlignment(Qt::AlignCenter); + zoom_out_ = new GuiClickableLabel(statusBar()); zoom_out_->setText(QString(QChar(0x2212))); - zoom_out_->setFixedSize(QSize(fm.height(), fm.height())); - zoom_out_->setFlat(true); + zoom_out_->setFixedSize(s); + zoom_out_->setAlignment(Qt::AlignCenter); statusBar()->addPermanentWidget(zoom_out_); zoom_out_->setEnabled(currentBufferView()); @@ -670,23 +721,29 @@ GuiView::GuiView(int id) connect(zoom_in_, SIGNAL(clicked()), this, SLOT(zoomInPressed())); connect(zoom_out_, SIGNAL(clicked()), this, SLOT(zoomOutPressed())); - zoom_value_ = new QLabel(statusBar()); + // 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("000%")); + zoom_value_->setMinimumWidth(fm.horizontalAdvance("444\%")); #else - zoom_value_->setMinimumWidth(fm.width("000%")); + 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()); - zoom_value_->setContextMenuPolicy(Qt::CustomContextMenu); - connect(zoom_value_, SIGNAL(customContextMenuRequested(QPoint)), - this, SLOT(showZoomContextMenu())); + statusBar()->setContextMenuPolicy(Qt::CustomContextMenu); + connect(statusBar(), SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(showStatusBarContextMenu())); - int const iconheight = max(int(d.normalIconSize), fm.height()); - QSize const iconsize(iconheight, iconheight); + // enable pinch to zoom + grabGesture(Qt::PinchGesture); QPixmap shellescape = QIcon(getPixmap("images/", "emblem-shellescape", "svgz,png")).pixmap(iconsize); shell_escape_ = new QLabel(statusBar()); @@ -777,16 +834,25 @@ 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(value)), dr); - currentWorkArea()->scheduleRedraw(true); + scheduleRedrawWorkAreas(); zoom_value_->setText(toqstr(bformat(_("[[ZOOM]]%1$d%"), value))); } @@ -802,7 +868,7 @@ void GuiView::zoomInPressed() { DispatchResult dr; dispatch(FuncRequest(LFUN_BUFFER_ZOOM_IN), dr); - currentWorkArea()->scheduleRedraw(true); + scheduleRedrawWorkAreas(); } @@ -810,7 +876,7 @@ void GuiView::zoomOutPressed() { DispatchResult dr; dispatch(FuncRequest(LFUN_BUFFER_ZOOM_OUT), dr); - currentWorkArea()->scheduleRedraw(true); + scheduleRedrawWorkAreas(); } @@ -823,6 +889,26 @@ void GuiView::showZoomContextMenu() } +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); + } + } +} + + QVector GuiView::GuiViewPrivate::guiWorkAreas() { QVector areas; @@ -925,7 +1011,11 @@ void GuiView::saveLayout() const 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_); } @@ -956,8 +1046,7 @@ 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(zoom_min_)) - zoom = zoom_min_; + zoom = min(max(zoom, zoom_min_), zoom_max_); setCurrentZoom(zoom); devel_mode_ = settings.value("devel_mode", devel_mode_).toBool(); settings.beginGroup("views"); @@ -969,11 +1058,18 @@ bool GuiView::restoreLayout() //code below is skipped when when ~/.config/LyX is (re)created setIconSize(d.iconSize(settings.value(icon_key).toString())); + 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(); @@ -1039,6 +1135,11 @@ 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 } @@ -1239,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. @@ -1344,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) { @@ -1483,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()) @@ -1549,7 +1724,8 @@ bool GuiView::event(QEvent * e) setContentsMargins(0, 0, 0, 0); } return result; - } + } + case QEvent::WindowActivate: { GuiView * old_view = guiApp->currentView(); if (this == old_view) { @@ -1592,6 +1768,27 @@ bool GuiView::event(QEvent * e) return QMainWindow::event(e); } + case QEvent::Gesture: { + QGestureEvent *ge = static_cast(e); + QGesture *gp = ge->gesture(Qt::PinchGesture); + if (gp) { + QPinchGesture *pinch = static_cast(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); } @@ -1814,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(find("findreplaceadv", false)); + return fr->isVisible() && fr->hasWorkArea(wa); +} + + LayoutBox * GuiView::getLayoutDialog() const { return d.layout_; @@ -2045,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(cmd.argument()) / double(lyxrc.defaultZoom); + else if (cmd.action() == LFUN_BUFFER_ZOOM_IN) + return zr + convert(cmd.argument()) / 100.0; + else // cmd.action() == LFUN_BUFFER_ZOOM_OUT + return zr - convert(cmd.argument()) / 100.0; + } +} + +} + + bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) { bool enable = true; @@ -2326,9 +2558,16 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; case LFUN_UI_TOGGLE: - if (cmd.argument() == "zoomslider") { - enable = doc_buffer; + 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; @@ -2423,37 +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(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(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 if (cmd.argument().empty() && lyxrc.currentZoom == lyxrc.defaultZoom) - enable = false; - else + } else enable = doc_buffer; break; } + case LFUN_BUFFER_MOVE_NEXT: case LFUN_BUFFER_MOVE_PREVIOUS: // we do not cycle when moving @@ -2516,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: @@ -3002,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) @@ -3021,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. @@ -3170,6 +3396,8 @@ 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 (fname.exists()) { docstring const file = makeDisplayPath(fname.absFileName(), 30); @@ -3932,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" @@ -4488,12 +4716,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; } @@ -4670,26 +4897,11 @@ 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(cmd.argument()) / double(lyxrc.defaultZoom); - else if (cmd.action() == LFUN_BUFFER_ZOOM_IN) - zoom_ratio_ += convert(cmd.argument()) / 100.0; - else - zoom_ratio_ -= convert(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(zoom_min_)) - zoom = zoom_min_; + zoom = min(max(zoom, zoom_min_), zoom_max_); setCurrentZoom(zoom); @@ -4697,6 +4909,10 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) lyxrc.currentZoom, lyxrc.defaultZoom)); guiApp->fontLoader().update(); + // 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; } @@ -4755,10 +4971,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; } @@ -4836,10 +5054,24 @@ bool GuiView::lfunUiToggle(string const & ui_component) statusBar()->setVisible(!statusBar()->isVisible()); } else if (ui_component == "menubar") { menuBar()->setVisible(!menuBar()->isVisible()); + } 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(); @@ -4861,6 +5093,7 @@ bool GuiView::lfunUiToggle(string const & ui_component) toggleFullScreen(); } else return false; + stat_counts_->setVisible(statsEnabled()); return true; } @@ -4982,7 +5215,7 @@ void GuiView::flatGroupBoxes(const QObject * widget, bool flag) } -Dialog * GuiView::findOrBuild(string const & name, bool hide_it) +Dialog * GuiView::find(string const & name, bool hide_it) const { if (!isValidName(name)) return nullptr; @@ -4994,8 +5227,17 @@ 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