X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiView.cpp;h=52fadcf3ef231d7619ae709f5dee7e8474008747;hb=da548dbe30ef0d36a2fb8ec6c05facb45d7f8ee7;hp=66d3997862c1b076f0626ff5a7b0511e5ff97d7c;hpb=0f26aabeee3663f2cfaa89c983b668486610e564;p=lyx.git diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 66d3997862..52fadcf3ef 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -34,6 +34,7 @@ #include "qt_helpers.h" #include "frontends/alert.h" +#include "frontends/KeySymbol.h" #include "buffer_funcs.h" #include "Buffer.h" @@ -58,6 +59,7 @@ #include "LyXVC.h" #include "Paragraph.h" #include "SpellChecker.h" +#include "Session.h" #include "TexRow.h" #include "TextClass.h" #include "Text.h" @@ -115,6 +117,7 @@ +// sync with GuiAlert.cpp #define EXPORT_in_THREAD 1 @@ -154,26 +157,40 @@ public: /// The text to be written on top of the pixmap QString const text = lyx_version ? qt_("version ") + lyx_version : qt_("unknown version"); - splash_ = getPixmap("images/", "banner", "png"); + splash_ = getPixmap("images/", "banner", "svgz,png"); QPainter pain(&splash_); pain.setPen(QColor(0, 0, 0)); + double const multiplier = splashPixelRatio() / pixelRatio(); + int const size = static_cast(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble() * multiplier); + int const x = static_cast(190 * multiplier); + int const y = static_cast(225 * multiplier); + LYXERR(Debug::GUI, + "widget pixel ratio: " << pixelRatio() << + " splash pixel ratio: " << splashPixelRatio() << + " version text size,position: " << size << "@" << x << "+" << y); QFont font; // The font used to display the version info font.setStyleHint(QFont::SansSerif); font.setWeight(QFont::Bold); - font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble())); + font.setPointSize(size); pain.setFont(font); - pain.drawText(190, 225, text); + pain.drawText(x, y, text); setFocusPolicy(Qt::StrongFocus); } void paintEvent(QPaintEvent *) { - int x = (width() - splash_.width()) / 2; - int y = (height() - splash_.height()) / 2; + int const w = static_cast(splash_.width() / splashPixelRatio()); + int const h = static_cast(splash_.height() / splashPixelRatio()); + int const x = (width() - w) / 2; + int const y = (height() - h) / 2; + LYXERR(Debug::GUI, + "widget pixel ratio: " << pixelRatio() << + " splash pixel ratio: " << splashPixelRatio() << + " paint pixmap: " << w << "x" << h << "@" << x << "+" << y); QPainter pain(this); - pain.drawPixmap(x, y, splash_); + pain.drawPixmap(x, y, w, h, splash_); } void keyPressEvent(QKeyEvent * ev) @@ -190,6 +207,24 @@ public: private: QPixmap splash_; + + /// Current ratio between physical pixels and device-independent pixels + double pixelRatio() const { +#if QT_VERSION >= 0x050000 + return devicePixelRatio(); +#else + return 1.0; +#endif + } + + /// Ratio between physical pixels and device-independent pixels of splash image + double splashPixelRatio() const { +#if QT_VERSION >= 0x050000 + return splash_.devicePixelRatio(); +#else + return 1.0; +#endif + } }; @@ -212,6 +247,8 @@ struct GuiView::GuiViewPrivate smallIconSize = 16; // scaling problems normalIconSize = 20; // ok, default if iconsize.png is missing bigIconSize = 26; // better for some math icons + hugeIconSize = 32; // better for hires displays + giantIconSize = 48; // if it exists, use width of iconsize.png as normal size QString const dir = toqstr(addPath("images", lyxrc.icon_set)); @@ -220,8 +257,8 @@ struct GuiView::GuiViewPrivate QImage image(toqstr(fn.absFileName())); if (image.width() < int(smallIconSize)) normalIconSize = smallIconSize; - else if (image.width() > int(bigIconSize)) - normalIconSize = bigIconSize; + else if (image.width() > int(giantIconSize)) + normalIconSize = giantIconSize; else normalIconSize = image.width(); } @@ -283,6 +320,20 @@ struct GuiView::GuiViewPrivate parent, SLOT(bigSizedIcons())); menu->addAction(bigIcons); + QAction * hugeIcons = new QAction(iconSizeGroup); + hugeIcons->setText(qt_("Huge-sized icons")); + hugeIcons->setCheckable(true); + QObject::connect(hugeIcons, SIGNAL(triggered()), + parent, SLOT(hugeSizedIcons())); + menu->addAction(hugeIcons); + + QAction * giantIcons = new QAction(iconSizeGroup); + giantIcons->setText(qt_("Giant-sized icons")); + giantIcons->setCheckable(true); + QObject::connect(giantIcons, SIGNAL(triggered()), + parent, SLOT(giantSizedIcons())); + menu->addAction(giantIcons); + unsigned int cur = parent->iconSize().width(); if ( cur == parent->d.smallIconSize) smallIcons->setChecked(true); @@ -290,6 +341,10 @@ struct GuiView::GuiViewPrivate normalIcons->setChecked(true); else if (cur == parent->d.bigIconSize) bigIcons->setChecked(true); + else if (cur == parent->d.hugeIconSize) + hugeIcons->setChecked(true); + else if (cur == parent->d.giantIconSize) + giantIcons->setChecked(true); return menu; } @@ -377,6 +432,8 @@ public: unsigned int smallIconSize; unsigned int normalIconSize; unsigned int bigIconSize; + unsigned int hugeIconSize; + unsigned int giantIconSize; /// QTimer statusbar_timer_; /// auto-saving of buffers @@ -446,15 +503,15 @@ GuiView::GuiView(int id) // We don't want to keep the window in memory if it is closed. setAttribute(Qt::WA_DeleteOnClose, true); -#if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX)) +#if !(defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)) && !defined(Q_OS_MAC) // QIcon::fromTheme was introduced in Qt 4.6 #if (QT_VERSION >= 0x040600) // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac, // since the icon is provided in the application bundle. We use a themed // version when available and use the bundled one as fallback. - setWindowIcon(QIcon::fromTheme("lyx", getPixmap("images/", "lyx", "png"))); + setWindowIcon(QIcon::fromTheme("lyx", getPixmap("images/", "lyx", "svg,png"))); #else - setWindowIcon(getPixmap("images/", "lyx", "png")); + setWindowIcon(getPixmap("images/", "lyx", "svg,png")); #endif #endif @@ -470,7 +527,8 @@ GuiView::GuiView(int id) // add busy indicator to statusbar QLabel * busylabel = new QLabel(statusBar()); statusBar()->addPermanentWidget(busylabel); - QString fn = toqstr(lyx::libFileSearch("images", "busy.gif").absFileName()); + 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(); @@ -501,7 +559,7 @@ GuiView::GuiView(int id) if (lyxrc.allow_geometry_session) { // Now take care of session management. - if (restoreLayout(true)) + if (restoreLayout()) return; } @@ -599,7 +657,7 @@ void GuiView::saveLayout() const QSettings settings; settings.beginGroup("views"); settings.beginGroup(QString::number(id_)); -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) || defined(QPA_XCB) settings.setValue("pos", pos()); settings.setValue("size", size()); #else @@ -623,7 +681,7 @@ void GuiView::saveUISettings() const } -bool GuiView::restoreLayout(bool force_inittoolbars) +bool GuiView::restoreLayout() { QSettings settings; settings.beginGroup("views"); @@ -637,13 +695,15 @@ bool GuiView::restoreLayout(bool force_inittoolbars) // Check whether session size changed. if (icon_size.width() != int(d.smallIconSize) && icon_size.width() != int(d.normalIconSize) && - icon_size.width() != int(d.bigIconSize)) { + icon_size.width() != int(d.bigIconSize) && + icon_size.width() != int(d.hugeIconSize) && + icon_size.width() != int(d.giantIconSize)) { icon_size.setWidth(d.normalIconSize); icon_size.setHeight(d.normalIconSize); } setIconSize(icon_size); -#ifdef Q_WS_X11 +#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); @@ -669,12 +729,19 @@ bool GuiView::restoreLayout(bool force_inittoolbars) dialog->prepareView(); if ((dialog = findOrBuild("progress", true))) dialog->prepareView(); - if ((dialog = findOrBuild("findreplaceadv", true))) - dialog->prepareView(); - if (!restoreState(settings.value("layout").toByteArray(), 0) - || force_inittoolbars) + if (!restoreState(settings.value("layout").toByteArray(), 0)) 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); + if (tb && !tb->isRestored()) + initToolbar(cit->name); + } + updateDialogs(); return true; } @@ -717,42 +784,47 @@ 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) { - GuiToolbar * tb = toolbar(cit->name); - if (!tb) - continue; - int const visibility = guiApp->toolbars().defaultVisibility(cit->name); - bool newline = !(visibility & Toolbars::SAMEROW); - tb->setVisible(false); - tb->setVisibility(visibility); - - if (visibility & Toolbars::TOP) { - if (newline) - addToolBarBreak(Qt::TopToolBarArea); - addToolBar(Qt::TopToolBarArea, tb); - } + for (; cit != end; ++cit) + initToolbar(cit->name); +} - if (visibility & Toolbars::BOTTOM) { - if (newline) - addToolBarBreak(Qt::BottomToolBarArea); - addToolBar(Qt::BottomToolBarArea, tb); - } - if (visibility & Toolbars::LEFT) { - if (newline) - addToolBarBreak(Qt::LeftToolBarArea); - addToolBar(Qt::LeftToolBarArea, tb); - } +void GuiView::initToolbar(string const & name) +{ + GuiToolbar * tb = toolbar(name); + if (!tb) + return; + int const visibility = guiApp->toolbars().defaultVisibility(name); + bool newline = !(visibility & Toolbars::SAMEROW); + tb->setVisible(false); + tb->setVisibility(visibility); + + if (visibility & Toolbars::TOP) { + if (newline) + addToolBarBreak(Qt::TopToolBarArea); + addToolBar(Qt::TopToolBarArea, tb); + } - if (visibility & Toolbars::RIGHT) { - if (newline) - addToolBarBreak(Qt::RightToolBarArea); - addToolBar(Qt::RightToolBarArea, tb); - } + if (visibility & Toolbars::BOTTOM) { + if (newline) + addToolBarBreak(Qt::BottomToolBarArea); + addToolBar(Qt::BottomToolBarArea, tb); + } - if (visibility & Toolbars::ON) - tb->setVisible(true); + if (visibility & Toolbars::LEFT) { + if (newline) + addToolBarBreak(Qt::LeftToolBarArea); + addToolBar(Qt::LeftToolBarArea, tb); } + + if (visibility & Toolbars::RIGHT) { + if (newline) + addToolBarBreak(Qt::RightToolBarArea); + addToolBar(Qt::RightToolBarArea, tb); + } + + if (visibility & Toolbars::ON) + tb->setVisible(true); } @@ -769,6 +841,16 @@ void GuiView::setFocus() } +bool GuiView::hasFocus() const +{ + if (currentWorkArea()) + return currentWorkArea()->hasFocus(); + if (currentMainWorkArea()) + return currentMainWorkArea()->hasFocus(); + return d.bg_widget_->hasFocus(); +} + + void GuiView::focusInEvent(QFocusEvent * e) { LYXERR(Debug::DEBUG, "GuiView::focusInEvent()" << this); @@ -812,6 +894,32 @@ bool GuiView::closeScheduled() } +bool GuiView::prepareAllBuffersForLogout() +{ + Buffer * first = theBufferList().first(); + if (!first) + return true; + + // First, iterate over all buffers and ask the users if unsaved + // changes should be saved. + // We cannot use a for loop as the buffer list cycles. + Buffer * b = first; + do { + if (!saveBufferIfNeeded(const_cast(*b), false)) + return false; + b = theBufferList().next(b); + } while (b != first); + + // Next, save session state + // When a view/window was closed before without quitting LyX, there + // are already entries in the lastOpened list. + theSession().lastOpened().clear(); + writeSession(); + + return true; +} + + /** Destroy only all tabbed WorkAreas. Destruction of other WorkAreas ** is responsibility of the container (e.g., dialog) **/ @@ -969,6 +1077,18 @@ void GuiView::bigSizedIcons() } +void GuiView::hugeSizedIcons() +{ + setIconSize(QSize(d.hugeIconSize, d.hugeIconSize)); +} + + +void GuiView::giantSizedIcons() +{ + setIconSize(QSize(d.giantIconSize, d.giantIconSize)); +} + + void GuiView::clearMessage() { // FIXME: This code was introduced in r19643 to fix bug #4123. However, @@ -988,6 +1108,12 @@ void GuiView::updateWindowTitle(GuiWorkArea * wa) return; setWindowTitle(qt_("LyX: ") + wa->windowTitle()); setWindowIconText(wa->windowIconText()); +#if (QT_VERSION >= 0x040400) + // Sets the path for the window: this is used by OSX to + // allow a context click on the title bar showing a menu + // with the path up to the file + setWindowFilePath(toqstr(wa->bufferView().buffer().absFileName())); +#endif } @@ -1044,7 +1170,7 @@ void GuiView::on_lastWorkAreaRemoved() return; } -#ifdef Q_WS_MACX +#ifdef Q_OS_MAC // On Mac we also close the last window because the application stay // resident in memory. On other platforms we don't close the last // window because this would quit the application. @@ -1184,6 +1310,16 @@ void GuiView::setBusy(bool busy) } +double GuiView::pixelRatio() const +{ +#if QT_VERSION >= 0x050000 + return devicePixelRatio(); +#else + return 1.0; +#endif +} + + GuiWorkArea * GuiView::workArea(int index) { if (TabWorkArea * twa = d.currentTabWorkArea()) @@ -1334,7 +1470,7 @@ void GuiView::removeWorkArea(GuiWorkArea * wa) // It is not a tabbed work area (i.e., the search work area), so it // should be deleted by other means. - LASSERT(found_twa, /* */); + LASSERT(found_twa, return); if (d.current_work_area_ == 0) { if (d.splitter_->count() != 0) { @@ -1573,6 +1709,16 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) Buffer * doc_buffer = documentBufferView() ? &(documentBufferView()->buffer()) : 0; + /* In LyX/Mac, when a dialog is open, the menus of the + application can still be accessed without giving focus to + the main window. In this case, we want to disable the menu + entries that are buffer-related. + */ + if (cmd.origin() == FuncRequest::MENU && !hasFocus()) { + buf = 0; + doc_buffer = 0; + } + // Check whether we need a buffer if (!lyxaction.funcHasFlag(cmd.action(), LyXAction::NoBuffer) && !buf) { // no, exit directly @@ -1595,7 +1741,9 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_MASTER_BUFFER_UPDATE: case LFUN_MASTER_BUFFER_VIEW: - enable = doc_buffer && doc_buffer->parent() != 0 + enable = doc_buffer + && (doc_buffer->parent() != 0 + || doc_buffer->hasChildren()) && !d.processing_thread_watcher_.isRunning(); break; @@ -1716,7 +1864,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) else if (name == "print") enable = doc_buffer->params().isExportable("dvi") && lyxrc.print_command != "none"; - else if (name == "character" || name == "symbols") { + else if (name == "character" || name == "symbols" + || name == "mathdelimiter" || name == "mathmatrix") { if (!buf || buf->isReadonly()) enable = false; else { @@ -1762,7 +1911,7 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) enable = false; break; - case LFUN_COMPLETION_COMPLETE: + case LFUN_COMPLETE: if (!d.current_work_area_ || !d.current_work_area_->completer().inlinePossible( currentBufferView()->cursor())) @@ -1792,9 +1941,13 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) enable = doc_buffer; break; + case LFUN_BUFFER_MOVE_NEXT: + case LFUN_BUFFER_MOVE_PREVIOUS: + // we do not cycle when moving case LFUN_BUFFER_NEXT: case LFUN_BUFFER_PREVIOUS: - // FIXME: should we check is there is an previous or next buffer? + // because we cycle, it doesn't matter whether on first or last + enable = (d.currentTabWorkArea()->count() > 1); break; case LFUN_BUFFER_SWITCH: // toggle on the current buffer, but do not toggle off @@ -1855,6 +2008,10 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) enable = documentBufferView() && documentBufferView()->cursor().inTexted(); break; + case LFUN_SPELLING_CONTINUOUSLY: + flag.setOnOff(lyxrc.spellcheck_continuously); + break; + default: return false; } @@ -1925,16 +2082,12 @@ void GuiView::openDocument(string const & fname) string filename; if (fname.empty()) { - FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN); + FileDialog dlg(qt_("Select document to open")); dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); dlg.setButton2(qt_("Examples|#E#e"), toqstr(addPath(package().system_support().absFileName(), "examples"))); - QStringList filter(qt_("LyX Documents (*.lyx)")); - filter << qt_("LyX-1.3.x Documents (*.lyx13)") - << qt_("LyX-1.4.x Documents (*.lyx14)") - << qt_("LyX-1.5.x Documents (*.lyx15)") - << qt_("LyX-1.6.x Documents (*.lyx16)"); + QStringList const filter(qt_("LyX Documents (*.lyx)")); FileDialog::Result result = dlg.open(toqstr(initpath), filter); @@ -2068,7 +2221,7 @@ void GuiView::importDocument(string const & argument) docstring const text = bformat(_("Select %1$s file to import"), formats.prettyName(format)); - FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT); + FileDialog dlg(toqstr(text)); dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); dlg.setButton2(qt_("Examples|#E#e"), toqstr(addPath(package().system_support().absFileName(), "examples"))); @@ -2098,6 +2251,18 @@ void GuiView::importDocument(string const & argument) // get absolute path of file FileName const fullname(support::makeAbsPath(filename)); + // Can happen if the user entered a path into the dialog + // (see bug #7437) + if (fullname.onlyFileName().empty()) { + docstring msg = bformat(_("The file name '%1$s' is invalid!\n" + "Aborting import."), + from_utf8(fullname.absFileName())); + frontend::Alert::error(_("File name error"), msg); + message(_("Canceled.")); + return; + } + + FileName const lyxfile(support::changeExtension(fullname.absFileName(), ".lyx")); // Check if the document already is open @@ -2190,7 +2355,7 @@ void GuiView::insertLyXFile(docstring const & fname) initpath = trypath; // FIXME UNICODE - FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT); + FileDialog dlg(qt_("Select LyX document to insert")); dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); dlg.setButton2(qt_("Examples|#E#e"), toqstr(addPath(package().system_support().absFileName(), @@ -2232,8 +2397,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin // No argument? Ask user through dialog. // FIXME UNICODE - FileDialog dlg(qt_("Choose a filename to save document as"), - LFUN_BUFFER_WRITE_AS); + FileDialog dlg(qt_("Choose a filename to save document as")); dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path)); @@ -2342,7 +2506,7 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin bool const saved = saveBuffer(b, fname); if (saved) - b.reload(false); + b.reload(); return saved; } @@ -2350,12 +2514,13 @@ bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kin struct PrettyNameComparator { bool operator()(Format const *first, Format const *second) const { - return compare_ascii_no_case(first->prettyname(), second->prettyname()) <= 0; + return compare_no_case(translateIfPossible(from_ascii(first->prettyname())), + translateIfPossible(from_ascii(second->prettyname()))) <= 0; } }; -bool GuiView::exportBufferAs(Buffer & b) +bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat) { FileName fname = b.fileName(); @@ -2363,37 +2528,50 @@ bool GuiView::exportBufferAs(Buffer & b) dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path)); QStringList types; - types << "Any supported format (*.*)"; + QString const anyformat = qt_("Guess from extension (*.*)"); + types << anyformat; Formats::const_iterator it = formats.begin(); vector export_formats; for (; it != formats.end(); ++it) - if (it->documentFormat() && it->inExportMenu()) + if (it->documentFormat()) export_formats.push_back(&(*it)); PrettyNameComparator cmp; sort(export_formats.begin(), export_formats.end(), cmp); vector::const_iterator fit = export_formats.begin(); - for (; fit != export_formats.end(); ++fit) - types << toqstr((*fit)->prettyname() + " (*." + (*fit)->extension() + ")"); + map fmap; QString filter; + string ext; + for (; fit != export_formats.end(); ++fit) { + docstring const loc_prettyname = + translateIfPossible(from_utf8((*fit)->prettyname())); + QString const loc_filter = toqstr(bformat(from_ascii("%1$s (*.%2$s)"), + loc_prettyname, + from_ascii((*fit)->extension()))); + types << loc_filter; + fmap[loc_filter] = (*fit)->name(); + if (from_ascii((*fit)->name()) == iformat) { + filter = loc_filter; + ext = (*fit)->extension(); + } + } + string ofname = fname.onlyFileName(); + if (!ext.empty()) + ofname = support::changeExtension(ofname, ext); FileDialog::Result result = dlg.save(toqstr(fname.onlyPath().absFileName()), types, - toqstr(fname.onlyFileName()), + toqstr(ofname), &filter); if (result.first != FileDialog::Chosen) return false; - string s = fromqstr(filter); - size_t pos = s.find(" (*."); - LASSERT(pos != string::npos, /**/); - string fmt_prettyname = s.substr(0, pos); string fmt_name; fname.set(fromqstr(result.second)); - if (fmt_prettyname == "Any supported format") + if (filter == anyformat) fmt_name = formats.getFormatFromExtension(fname.extension()); else - fmt_name = formats.getFormatFromPrettyName(fmt_prettyname); - LYXERR(Debug::FILES, "fmt_prettyname=" << fmt_prettyname + fmt_name = fmap[filter]; + LYXERR(Debug::FILES, "filter=" << fromqstr(filter) << ", fmt_name=" << fmt_name << ", fname=" << fname.absFileName()); if (fmt_name.empty() || fname.empty()) @@ -2410,7 +2588,7 @@ bool GuiView::exportBufferAs(Buffer & b) text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel")); switch (ret) { case 0: break; - case 1: return exportBufferAs(b); + case 1: return exportBufferAs(b, from_ascii(fmt_name)); case 2: return false; } } @@ -2436,12 +2614,7 @@ bool GuiView::saveBuffer(Buffer & b, FileName const & fn) if (fn.empty() && b.isUnnamed()) return renameBuffer(b, docstring()); - bool success; - if (fn.empty()) - success = b.save(); - else - success = b.saveAs(fn); - + bool const success = (fn.empty() ? b.save() : b.saveAs(fn)); if (success) { theSession().lastFiles().add(b.fileName()); return true; @@ -2767,7 +2940,7 @@ bool GuiView::inOtherView(Buffer & buf) } -void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np) +void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np, bool const move) { if (!documentBufferView()) return; @@ -2782,7 +2955,10 @@ void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np) next_index = (i == nwa - 1 ? 0 : i + 1); else next_index = (i == 0 ? nwa - 1 : i - 1); - setBuffer(&workArea(next_index)->bufferView().buffer()); + if (move) + twa->moveTab(i, next_index); + else + setBuffer(&workArea(next_index)->bufferView().buffer()); break; } } @@ -2860,7 +3036,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr) if (!buffer->lyxvc().inUse()) { if (buffer->lyxvc().registrer()) { reloadBuffer(*buffer); - dr.suppressMessageUpdate(); + dr.clearMessageUpdate(); } } break; @@ -2903,7 +3079,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr) LyXVC::CommandResult ret = buffer->lyxvc().checkIn(log); dr.setMessage(log); // Only skip reloading if the checkin was cancelled or - // an error occured before the real checkin VCS command + // an error occurred before the real checkin VCS command // was executed, since the VCS might have changed the // file even if it could not checkin successfully. if (ret == LyXVC::ErrorCommand || ret == LyXVC::VCSuccess) @@ -2940,7 +3116,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr) LASSERT(buffer, return); if (buffer->lyxvc().revert()) { reloadBuffer(*buffer); - dr.suppressMessageUpdate(); + dr.clearMessageUpdate(); } break; @@ -2948,7 +3124,7 @@ void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr) LASSERT(buffer, return); buffer->lyxvc().undoLast(); reloadBuffer(*buffer); - dr.suppressMessageUpdate(); + dr.clearMessageUpdate(); break; case LFUN_VC_REPO_UPDATE: @@ -3175,11 +3351,11 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing( if (format.empty()) format = used_buffer->params().getDefaultOutputFormat(); processing_format = format; -#if EXPORT_in_THREAD if (!msg.empty()) { progress_->clearMessages(); gv_->message(msg); } +#if EXPORT_in_THREAD GuiViewPrivate::busyBuffers.insert(used_buffer); Buffer * cloned_buffer = used_buffer->cloneFromMaster(); if (!cloned_buffer) { @@ -3217,7 +3393,7 @@ bool GuiView::GuiViewPrivate::asyncBufferProcessing( void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr) { BufferView * bv = currentBufferView(); - LASSERT(bv, /**/); + LASSERT(bv, return); // Let the current BufferView dispatch its own actions. bv->dispatch(cmd, dr); @@ -3284,11 +3460,19 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_BUFFER_EXPORT: { if (!doc_buffer) break; + FileName target_dir = doc_buffer->fileName().onlyPath(); + string const dest = cmd.getArg(1); + if (!dest.empty() && FileName::isAbsolute(dest)) + target_dir = FileName(support::onlyPath(dest)); // GCC only sees strfwd.h when building merged if (::lyx::operator==(cmd.argument(), "custom")) { dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr); break; } + if (!target_dir.isDirWritable()) { + exportBufferAs(*doc_buffer, cmd.argument()); + break; + } /* TODO/Review: Is it a problem to also export the children? See the update_unincluded flag */ d.asyncBufferProcessing(argument, @@ -3301,10 +3485,14 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } - case LFUN_BUFFER_EXPORT_AS: + case LFUN_BUFFER_EXPORT_AS: { LASSERT(doc_buffer, break); - exportBufferAs(*doc_buffer); + docstring f = cmd.argument(); + if (f.empty()) + f = from_ascii(doc_buffer->params().getDefaultOutputFormat()); + exportBufferAs(*doc_buffer, f); break; + } case LFUN_BUFFER_UPDATE: { d.asyncBufferProcessing(argument, @@ -3384,11 +3572,19 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } case LFUN_BUFFER_NEXT: - gotoNextOrPreviousBuffer(NEXTBUFFER); + gotoNextOrPreviousBuffer(NEXTBUFFER, false); + break; + + case LFUN_BUFFER_MOVE_NEXT: + gotoNextOrPreviousBuffer(NEXTBUFFER, true); break; case LFUN_BUFFER_PREVIOUS: - gotoNextOrPreviousBuffer(PREVBUFFER); + gotoNextOrPreviousBuffer(PREVBUFFER, false); + break; + + case LFUN_BUFFER_MOVE_PREVIOUS: + gotoNextOrPreviousBuffer(PREVBUFFER, true); break; case LFUN_COMMAND_EXECUTE: { @@ -3417,7 +3613,6 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_FILE_INSERT_PLAINTEXT: case LFUN_FILE_INSERT_PLAINTEXT_PARA: { - bool const as_paragraph = (cmd.action() == LFUN_FILE_INSERT_PLAINTEXT_PARA); string const fname = to_utf8(cmd.argument()); if (!fname.empty() && !FileName::isAbsolute(fname)) { dr.setMessage(_("Absolute filename expected.")); @@ -3426,8 +3621,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) FileName filename(fname); if (fname.empty()) { - FileDialog dlg(qt_("Select file to insert"), (as_paragraph ? - LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT)); + FileDialog dlg(qt_("Select file to insert")); FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()), QStringList(qt_("All Files (*)"))); @@ -3652,7 +3846,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; - case LFUN_COMPLETION_COMPLETE: + case LFUN_COMPLETE: if (d.current_work_area_) d.current_work_area_->completer().tab(); break; @@ -3763,6 +3957,12 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) one.startscript(Systemcall::DontWait, command); break; } + + case LFUN_SPELLING_CONTINUOUSLY: + lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously; + dr.screenUpdate(Update::Force | Update::FitCursor); + break; + default: // The LFUN must be for one of BufferView, Buffer or Cursor; // let's try that: @@ -3774,8 +3974,18 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (isFullScreen()) { if (menuBar()->isVisible() && lyxrc.full_screen_menubar) menuBar()->hide(); - if (statusBar()->isVisible()) - statusBar()->hide(); + } + + // Need to update bv because many LFUNs here might have destroyed it + bv = currentBufferView(); + + // Clear non-empty selections + // (e.g. from a "char-forward-select" followed by "char-backward-select") + if (bv) { + Cursor & cur = bv->cursor(); + if ((cur.selection() && cur.selBegin() == cur.selEnd())) { + cur.clearSelection(); + } } } @@ -3834,7 +4044,8 @@ void GuiView::toggleFullScreen() setContentsMargins(-2, -2, -2, -2); saveLayout(); setWindowState(windowState() ^ Qt::WindowFullScreen); - statusBar()->hide(); + if (lyxrc.full_screen_statusbar) + statusBar()->hide(); if (lyxrc.full_screen_menubar) menuBar()->hide(); if (lyxrc.full_screen_toolbars) {