X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FGuiView.cpp;h=52fadcf3ef231d7619ae709f5dee7e8474008747;hb=da548dbe30ef0d36a2fb8ec6c05facb45d7f8ee7;hp=644f14317624dcdc9a72c70e35b1a4c826f01328;hpb=105f9bb5d9b81fdbc70978c19c2757db86897131;p=lyx.git diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 644f143176..52fadcf3ef 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -117,6 +117,7 @@ +// sync with GuiAlert.cpp #define EXPORT_in_THREAD 1 @@ -156,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) @@ -192,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 + } }; @@ -214,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)); @@ -222,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(); } @@ -285,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); @@ -292,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; } @@ -379,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 @@ -448,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 @@ -472,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(); @@ -601,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 @@ -639,13 +695,15 @@ bool GuiView::restoreLayout() // 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); @@ -783,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); @@ -826,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) **/ @@ -983,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, @@ -1002,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 } @@ -1058,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. @@ -1198,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()) @@ -1587,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 @@ -1732,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 { @@ -1778,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())) @@ -1808,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 @@ -1945,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); @@ -2088,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"))); @@ -2118,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 @@ -2210,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(), @@ -2252,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)); @@ -2796,7 +2940,7 @@ bool GuiView::inOtherView(Buffer & buf) } -void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np) +void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np, bool const move) { if (!documentBufferView()) return; @@ -2811,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; } } @@ -2889,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; @@ -2932,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) @@ -2969,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; @@ -2977,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: @@ -3204,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) { @@ -3425,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: { @@ -3458,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.")); @@ -3467,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 (*)"))); @@ -3693,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; @@ -3821,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(); + } } } @@ -3881,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) {