#include "GuiView.h"
-#include "Dialog.h"
#include "DispatchResult.h"
#include "FileDialog.h"
#include "FontLoader.h"
#include "TocModel.h"
#include "qt_helpers.h"
+#include "support/filetools.h"
#include "frontends/alert.h"
#include "frontends/KeySymbol.h"
#include <QSplitter>
#include <QStackedWidget>
#include <QStatusBar>
+#include <QSvgRenderer>
#include <QtConcurrentRun>
#include <QTime>
#include <QTimer>
+// sync with GuiAlert.cpp
#define EXPORT_in_THREAD 1
class BackgroundWidget : public QWidget
{
public:
- BackgroundWidget()
+ BackgroundWidget(int width, int height)
+ : width_(width), height_(height)
{
LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
if (!lyxrc.show_banner)
/// 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");
+#if QT_VERSION >= 0x050000
+ QString imagedir = "images/";
+ FileName fname = imageLibFileSearch(imagedir, "banner", "svgz");
+ QSvgRenderer svgRenderer(toqstr(fname.absFileName()));
+ if (svgRenderer.isValid()) {
+ splash_ = QPixmap(splashSize());
+ QPainter painter(&splash_);
+ svgRenderer.render(&painter);
+ splash_.setDevicePixelRatio(pixelRatio());
+ } else {
+ splash_ = getPixmap("images/", "banner", "png");
+ }
+#else
+ splash_ = getPixmap("images/", "banner", "svgz,png");
+#endif
QPainter pain(&splash_);
pain.setPen(QColor(0, 0, 0));
+ qreal const fsize = fontSize();
+ QPointF const position = textPosition();
+ LYXERR(Debug::GUI,
+ "widget pixel ratio: " << pixelRatio() <<
+ " splash pixel ratio: " << splashPixelRatio() <<
+ " version text size,position: " << fsize << "@" << position.x() << "+" << position.y());
QFont font;
// The font used to display the version info
font.setStyleHint(QFont::SansSerif);
font.setWeight(QFont::Bold);
- int size = int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble());
- size *= splashPixelRatio() / pixelRatio();
- font.setPointSize(size);
+ font.setPointSizeF(fsize);
pain.setFont(font);
- int x = 190;
- int y = 225;
- x *= splashPixelRatio() / pixelRatio();
- y *= splashPixelRatio() / pixelRatio();
- LYXERR(Debug::GUI,
- "widget pixel ratio: " << pixelRatio() <<
- " splash pixel ratio: " << splashPixelRatio() <<
- " text position: @" << x << "+" << y);
- pain.drawText(x, y, text);
+ pain.drawText(position, text);
setFocusPolicy(Qt::StrongFocus);
}
void paintEvent(QPaintEvent *)
{
- int w = splash_.width();
- int h = splash_.height();
- w /= splashPixelRatio();
- h /= splashPixelRatio();
- int x = (width() - w) / 2;
- int y = (height() - h) / 2;
+ int const w = width_;
+ int const h = height_;
+ 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);
+ "widget pixel ratio: " << pixelRatio() <<
+ " splash pixel ratio: " << splashPixelRatio() <<
+ " paint pixmap: " << w << "x" << h << "@" << x << "+" << y);
QPainter pain(this);
pain.drawPixmap(x, y, w, h, splash_);
}
private:
QPixmap splash_;
+ int const width_;
+ int const height_;
/// Current ratio between physical pixels and device-independent pixels
double pixelRatio() const {
#endif
}
+ qreal fontSize() const {
+ return toqstr(lyxrc.font_sizes[FONT_SIZE_NORMAL]).toDouble();
+ }
+
+ QPointF textPosition() const {
+ return QPointF(width_/2 - 18, height_/2 + 45);
+ }
+
+ QSize splashSize() const {
+ return QSize(
+ static_cast<unsigned int>(width_ * pixelRatio()),
+ static_cast<unsigned int>(height_ * pixelRatio()));
+ }
+
/// Ratio between physical pixels and device-independent pixels of splash image
double splashPixelRatio() const {
#if QT_VERSION >= 0x050000
} // namespace anon
-struct GuiView::GuiViewPrivate
+class GuiView::GuiViewPrivate
{
+ /// noncopyable
+ GuiViewPrivate(GuiViewPrivate const &);
+ void operator=(GuiViewPrivate const &);
+public:
GuiViewPrivate(GuiView * gv)
: gv_(gv), current_work_area_(0), current_main_work_area_(0),
layout_(0), autosave_timeout_(5000),
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));
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();
}
splitter_ = new QSplitter;
- bg_widget_ = new BackgroundWidget;
+ bg_widget_ = new BackgroundWidget(400, 250);
stack_widget_ = new QStackedWidget;
stack_widget_->addWidget(bg_widget_);
stack_widget_->addWidget(splitter_);
delete stack_widget_;
}
- QMenu * toolBarPopup(GuiView * parent)
- {
- // FIXME: translation
- QMenu * menu = new QMenu(parent);
- QActionGroup * iconSizeGroup = new QActionGroup(parent);
-
- QAction * smallIcons = new QAction(iconSizeGroup);
- smallIcons->setText(qt_("Small-sized icons"));
- smallIcons->setCheckable(true);
- QObject::connect(smallIcons, SIGNAL(triggered()),
- parent, SLOT(smallSizedIcons()));
- menu->addAction(smallIcons);
-
- QAction * normalIcons = new QAction(iconSizeGroup);
- normalIcons->setText(qt_("Normal-sized icons"));
- normalIcons->setCheckable(true);
- QObject::connect(normalIcons, SIGNAL(triggered()),
- parent, SLOT(normalSizedIcons()));
- menu->addAction(normalIcons);
-
- QAction * bigIcons = new QAction(iconSizeGroup);
- bigIcons->setText(qt_("Big-sized icons"));
- bigIcons->setCheckable(true);
- QObject::connect(bigIcons, SIGNAL(triggered()),
- parent, SLOT(bigSizedIcons()));
- menu->addAction(bigIcons);
-
- unsigned int cur = parent->iconSize().width();
- if ( cur == parent->d.smallIconSize)
- smallIcons->setChecked(true);
- else if (cur == parent->d.normalIconSize)
- normalIcons->setChecked(true);
- else if (cur == parent->d.bigIconSize)
- bigIcons->setChecked(true);
-
- return menu;
- }
-
void setBackground()
{
stack_widget_->setCurrentWidget(bg_widget_);
processing_thread_watcher_.setFuture(f);
}
+ QSize iconSize(docstring const & icon_size)
+ {
+ unsigned int size;
+ if (icon_size == "small")
+ size = smallIconSize;
+ else if (icon_size == "normal")
+ size = normalIconSize;
+ else if (icon_size == "big")
+ size = bigIconSize;
+ else if (icon_size == "huge")
+ size = hugeIconSize;
+ else if (icon_size == "giant")
+ size = giantIconSize;
+ else
+ size = icon_size.empty() ? normalIconSize : convert<int>(icon_size);
+
+ if (size < smallIconSize)
+ size = smallIconSize;
+
+ return QSize(size, size);
+ }
+
+ QSize iconSize(QString const & icon_size)
+ {
+ return iconSize(qstring_to_ucs4(icon_size));
+ }
+
+ string & iconSize(QSize const & qsize)
+ {
+ LATTEST(qsize.width() == qsize.height());
+
+ static string icon_size;
+
+ unsigned int size = qsize.width();
+
+ if (size < smallIconSize)
+ size = smallIconSize;
+
+ if (size == smallIconSize)
+ icon_size = "small";
+ else if (size == normalIconSize)
+ icon_size = "normal";
+ else if (size == bigIconSize)
+ icon_size = "big";
+ else if (size == hugeIconSize)
+ icon_size = "huge";
+ else if (size == giantIconSize)
+ icon_size = "giant";
+ else
+ icon_size = convert<string>(size);
+
+ return icon_size;
+ }
+
public:
GuiView * gv_;
GuiWorkArea * current_work_area_;
unsigned int smallIconSize;
unsigned int normalIconSize;
unsigned int bigIconSize;
+ unsigned int hugeIconSize;
+ unsigned int giantIconSize;
///
QTimer statusbar_timer_;
/// auto-saving of buffers
GuiView::GuiView(int id)
- : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0)
+ : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0),
+ command_execute_(false), minibuffer_focus_(false)
{
+ connect(this, SIGNAL(bufferViewChanged()),
+ this, SLOT(onBufferViewChanged()));
+
// GuiToolbars *must* be initialised before the menu bar.
- normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge
+ setIconSize(QSize(d.normalIconSize, d.normalIconSize)); // at least on Mac the default is 32 otherwise, which is huge
constructToolbars();
// set ourself as the current view. This is needed for the menu bar
// 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
- resetWindowTitleAndIconText();
+ resetWindowTitle();
// use tabbed dock area for multiple docks
// (such as "source" and "messages")
connect(&d.processing_thread_watcher_, SIGNAL(finished()),
busylabel, SLOT(hide()));
+ QFontMetrics const fm(statusBar()->fontMetrics());
+ int const roheight = max(int(d.normalIconSize), fm.height());
+ QSize const rosize(roheight, roheight);
+ QPixmap readonly = QIcon(getPixmap("images/", "emblem-readonly", "svgz,png")).pixmap(rosize);
+ read_only_ = new QLabel(statusBar());
+ read_only_->setPixmap(readonly);
+ read_only_->setScaledContents(true);
+ read_only_->setAlignment(Qt::AlignCenter);
+ read_only_->hide();
+ statusBar()->addPermanentWidget(read_only_);
+
+ version_control_ = new QLabel(statusBar());
+ version_control_->setAlignment(Qt::AlignCenter);
+ version_control_->setFrameStyle(QFrame::StyledPanel);
+ version_control_->hide();
+ statusBar()->addPermanentWidget(version_control_);
+
statusBar()->setSizeGripEnabled(true);
updateStatusBar();
connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)),
SLOT(doShowDialog(QString const &, QString const &, Inset *)));
+ // set custom application bars context menu, e.g. tool bar and menu bar
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
+ SLOT(toolBarPopup(const QPoint &)));
+
// Forbid too small unresizable window because it can happen
// with some window manager under X11.
setMinimumSize(300, 200);
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
settings.setValue("geometry", saveGeometry());
#endif
settings.setValue("layout", saveState(0));
- settings.setValue("icon_size", iconSize());
+ settings.setValue("icon_size", toqstr(d.iconSize(iconSize())));
}
return false;
//code below is skipped when when ~/.config/LyX is (re)created
- QSize icon_size = settings.value(icon_key).toSize();
- // Check whether session size changed.
- if (icon_size.width() != int(d.smallIconSize) &&
- icon_size.width() != int(d.normalIconSize) &&
- icon_size.width() != int(d.bigIconSize)) {
- icon_size.setWidth(d.normalIconSize);
- icon_size.setHeight(d.normalIconSize);
- }
- setIconSize(icon_size);
+ setIconSize(d.iconSize(settings.value(icon_key).toString()));
-#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);
}
+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);
}
-QMenu * GuiView::createPopupMenu()
-{
- return d.toolBarPopup(this);
-}
-
-
void GuiView::showEvent(QShowEvent * e)
{
LYXERR(Debug::GUI, "Passed Geometry "
}
+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<Buffer &>(*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)
**/
}
-void GuiView::smallSizedIcons()
-{
- setIconSize(QSize(d.smallIconSize, d.smallIconSize));
-}
-
-
-void GuiView::normalSizedIcons()
-{
- setIconSize(QSize(d.normalIconSize, d.normalIconSize));
-}
-
-
-void GuiView::bigSizedIcons()
-{
- setIconSize(QSize(d.bigIconSize, d.bigIconSize));
-}
-
-
void GuiView::clearMessage()
{
// FIXME: This code was introduced in r19643 to fix bug #4123. However,
if (wa != d.current_work_area_
|| wa->bufferView().buffer().isInternal())
return;
- setWindowTitle(qt_("LyX: ") + wa->windowTitle());
- setWindowIconText(wa->windowIconText());
-#if (QT_VERSION >= 0x040400)
- // Sets the path for the window: this is used by OSX to
+ Buffer const & buf = wa->bufferView().buffer();
+ // Set the windows title
+ docstring title = buf.fileName().displayName(130) + from_ascii("[*]");
+#ifndef Q_WS_MAC
+ title += from_ascii(" - LyX");
+#endif
+ setWindowTitle(toqstr(title));
+ // Sets the path for the window: this is used by OSX to
// allow a context click on the title bar showing a menu
// with the path up to the file
- setWindowFilePath(toqstr(wa->bufferView().buffer().absFileName()));
-#endif
+ setWindowFilePath(toqstr(buf.absFileName()));
+ // Tell Qt whether the current document is changed
+ setWindowModified(!buf.isClean());
+
+ if (buf.isReadonly())
+ read_only_->show();
+ else
+ read_only_->hide();
+
+ if (buf.lyxvc().inUse()) {
+ version_control_->show();
+ version_control_->setText(toqstr(buf.lyxvc().vcstatus()));
+ } else
+ version_control_->hide();
}
void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
{
if (d.current_work_area_)
- QObject::disconnect(d.current_work_area_, SIGNAL(busy(bool)),
- this, SLOT(setBusy(bool)));
+ // disconnect the current work area from all slots
+ QObject::disconnect(d.current_work_area_, 0, this, 0);
disconnectBuffer();
disconnectBufferView();
connectBufferView(wa->bufferView());
connectBuffer(wa->bufferView().buffer());
d.current_work_area_ = wa;
QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
- this, SLOT(updateWindowTitle(GuiWorkArea *)));
- QObject::connect(wa, SIGNAL(busy(bool)), this, SLOT(setBusy(bool)));
- updateWindowTitle(wa);
-
- structureChanged();
+ this, SLOT(updateWindowTitle(GuiWorkArea *)));
+ QObject::connect(wa, SIGNAL(busy(bool)),
+ this, SLOT(setBusy(bool)));
+ // connection of a signal to a signal
+ QObject::connect(wa, SIGNAL(bufferViewChanged()),
+ this, SIGNAL(bufferViewChanged()));
+ Q_EMIT updateWindowTitle(wa);
+ Q_EMIT bufferViewChanged();
+}
- // The document settings needs to be reinitialised.
- updateDialog("document", "");
+void GuiView::onBufferViewChanged()
+{
+ structureChanged();
// Buffer-dependent dialogs must be updated. This is done here because
// some dialogs require buffer()->text.
updateDialogs();
return;
// Reset and updates the dialogs.
- d.toc_models_.reset(0);
- updateDialog("document", "");
- updateDialogs();
+ Q_EMIT bufferViewChanged();
- resetWindowTitleAndIconText();
+ resetWindowTitle();
updateStatusBar();
if (lyxrc.open_buffers_in_tabs)
cap::saveSelection(old_view->currentBufferView()->cursor());
}
guiApp->setCurrentView(this);
- if (d.current_work_area_) {
- BufferView & bv = d.current_work_area_->bufferView();
- connectBufferView(bv);
- connectBuffer(bv.buffer());
- // The document structure, name and dialogs might have
- // changed in another view.
- structureChanged();
- // The document settings needs to be reinitialised.
- updateDialog("document", "");
- updateDialogs();
- } else {
- resetWindowTitleAndIconText();
- }
+ if (d.current_work_area_)
+ on_currentWorkAreaChanged(d.current_work_area_);
+ else
+ resetWindowTitle();
setFocus();
return QMainWindow::event(e);
}
}
}
-void GuiView::resetWindowTitleAndIconText()
+void GuiView::resetWindowTitle()
{
setWindowTitle(qt_("LyX"));
- setWindowIconText(qt_("LyX"));
}
bool GuiView::focusNextPrevChild(bool /*next*/)
}
+void GuiView::resetCommandExecute()
+{
+ command_execute_ = false;
+ updateToolbars();
+}
+
+
double GuiView::pixelRatio() const
{
#if QT_VERSION >= 0x050000
{
if (currentWorkArea()
&& ¤tWorkArea()->bufferView().buffer() == &buffer)
- return (GuiWorkArea *) currentWorkArea();
+ return currentWorkArea();
if (TabWorkArea * twa = d.currentTabWorkArea())
return twa->workArea(buffer);
return 0;
if (!wa) {
d.current_work_area_ = 0;
d.setBackground();
+ Q_EMIT bufferViewChanged();
return;
}
{
ToolbarMap::iterator end = d.toolbars_.end();
if (d.current_work_area_) {
- bool const math =
- d.current_work_area_->bufferView().cursor().inMathed()
- && !d.current_work_area_->bufferView().cursor().inRegexped();
- bool const table =
- lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
- bool const review =
- lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
- lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true);
- bool const mathmacrotemplate =
- lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
- bool const ipa =
- lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled();
+ int context = 0;
+ if (d.current_work_area_->bufferView().cursor().inMathed()
+ && !d.current_work_area_->bufferView().cursor().inRegexped())
+ context |= Toolbars::MATH;
+ if (lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled())
+ context |= Toolbars::TABLE;
+ if (currentBufferView()->buffer().areChangesPresent()
+ || (lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled()
+ && lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true))
+ || (lyx::getStatus(FuncRequest(LFUN_CHANGES_OUTPUT)).enabled()
+ && lyx::getStatus(FuncRequest(LFUN_CHANGES_OUTPUT)).onOff(true)))
+ context |= Toolbars::REVIEW;
+ if (lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled())
+ context |= Toolbars::MATHMACROTEMPLATE;
+ if (lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled())
+ context |= Toolbars::IPA;
+ if (command_execute_)
+ context |= Toolbars::MINIBUFFER;
+ if (minibuffer_focus_) {
+ context |= Toolbars::MINIBUFFER_FOCUS;
+ minibuffer_focus_ = false;
+ }
for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
- it->second->update(math, table, review, mathmacrotemplate, ipa);
+ it->second->update(context);
} else
for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
- it->second->update(false, false, false, false, false);
+ it->second->update();
}
void GuiView::structureChanged()
{
+ // This is called from the Buffer, which has no way to ensure that cursors
+ // in BufferView remain valid.
+ if (documentBufferView())
+ documentBufferView()->cursor().sanitize();
+ // FIXME: This is slightly expensive, though less than the tocBackend update
+ // (#9880). This also resets the view in the Toc Widget (#6675).
d.toc_models_.reset(documentBufferView());
// Navigator needs more than a simple update in this case. It needs to be
// rebuilt.
Buffer * doc_buffer = documentBufferView()
? &(documentBufferView()->buffer()) : 0;
+#ifdef Q_OS_MAC
+ /* In LyX/Mac, when a dialog is open, the menus of the
+ application can still be accessed without giving focus to
+ the main window. In this case, we want to disable the menu
+ entries that are buffer-related.
+ This code must not be used on Linux and Windows, since it
+ would disable buffer-related entries when hovering over the
+ menu (see bug #9574).
+ */
+ if (cmd.origin() == FuncRequest::MENU && !hasFocus()) {
+ buf = 0;
+ doc_buffer = 0;
+ }
+#endif
+
// Check whether we need a buffer
if (!lyxaction.funcHasFlag(cmd.action(), LyXAction::NoBuffer) && !buf) {
// no, exit directly
string format = to_utf8(cmd.argument());
if (cmd.argument().empty())
format = doc_buffer->params().getDefaultOutputFormat();
- enable = doc_buffer->params().isExportableFormat(format);
+ enable = doc_buffer->params().isExportable(format, true);
break;
}
break;
case LFUN_BUFFER_CHILD_OPEN:
- enable = doc_buffer;
+ enable = doc_buffer != 0;
break;
case LFUN_BUFFER_WRITE:
case LFUN_BUFFER_WRITE_AS:
case LFUN_BUFFER_EXPORT_AS:
- enable = doc_buffer;
+ enable = doc_buffer != 0;
break;
case LFUN_BUFFER_CLOSE:
case LFUN_VIEW_CLOSE:
- enable = doc_buffer;
+ enable = doc_buffer != 0;
break;
case LFUN_BUFFER_CLOSE_ALL:
break;
}
+ case LFUN_ICON_SIZE:
+ flag.setOnOff(d.iconSize(cmd.argument()) == iconSize());
+ break;
+
case LFUN_DROP_LAYOUTS_CHOICE:
- enable = buf;
+ enable = buf != 0;
break;
case LFUN_UI_TOGGLE:
|| name == "texinfo"
|| name == "progress"
|| name == "compare";
- else if (name == "print")
- enable = doc_buffer->params().isExportable("dvi")
- && lyxrc.print_command != "none";
else if (name == "character" || name == "symbols"
|| name == "mathdelimiter" || name == "mathmatrix") {
if (!buf || buf->isReadonly())
break;
case LFUN_BUFFER_ZOOM_OUT:
- enable = doc_buffer && lyxrc.zoom > 10;
- break;
-
- case LFUN_BUFFER_ZOOM_IN:
- enable = doc_buffer;
+ case LFUN_BUFFER_ZOOM_IN: {
+ // only diff between these two is that the default for ZOOM_OUT
+ // is a neg. number
+ bool const neg_zoom =
+ convert<int>(cmd.argument()) < 0 ||
+ (cmd.action() == LFUN_BUFFER_ZOOM_OUT && cmd.argument().empty());
+ if (lyxrc.zoom <= zoom_min_ && neg_zoom) {
+ docstring const msg =
+ bformat(_("Zoom level cannot be less than %1$d%."), zoom_min_);
+ flag.message(msg);
+ enable = false;
+ } else
+ enable = doc_buffer;
break;
-
+ }
+ case LFUN_BUFFER_MOVE_NEXT:
+ case LFUN_BUFFER_MOVE_PREVIOUS:
+ // we do not cycle when moving
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
break;
case LFUN_SERVER_GOTO_FILE_ROW:
+ case LFUN_LYX_ACTIVATE:
break;
case LFUN_FORWARD_SEARCH:
enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty());
}
-struct PrettyNameComparator
-{
- bool operator()(Format const *first, Format const *second) const {
- return compare_no_case(translateIfPossible(from_ascii(first->prettyname())),
- translateIfPossible(from_ascii(second->prettyname()))) <= 0;
- }
-};
-
-
bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
{
FileName fname = b.fileName();
QStringList types;
QString const anyformat = qt_("Guess from extension (*.*)");
types << anyformat;
- Formats::const_iterator it = formats.begin();
+
vector<Format const *> export_formats;
- for (; it != formats.end(); ++it)
- if (it->documentFormat())
- export_formats.push_back(&(*it));
- PrettyNameComparator cmp;
- sort(export_formats.begin(), export_formats.end(), cmp);
- vector<Format const *>::const_iterator fit = export_formats.begin();
+ for (Format const & f : formats)
+ if (f.documentFormat())
+ export_formats.push_back(&f);
+ sort(export_formats.begin(), export_formats.end(), Format::formatSorter);
map<QString, string> fmap;
QString filter;
string ext;
- for (; fit != export_formats.end(); ++fit) {
- docstring const loc_prettyname =
- translateIfPossible(from_utf8((*fit)->prettyname()));
+ for (Format const * f : export_formats) {
+ docstring const loc_prettyname = translateIfPossible(f->prettyname());
QString const loc_filter = toqstr(bformat(from_ascii("%1$s (*.%2$s)"),
loc_prettyname,
- from_ascii((*fit)->extension())));
+ from_ascii(f->extension())));
types << loc_filter;
- fmap[loc_filter] = (*fit)->name();
- if (from_ascii((*fit)->name()) == iformat) {
+ fmap[loc_filter] = f->name();
+ if (from_ascii(f->name()) == iformat) {
filter = loc_filter;
- ext = (*fit)->extension();
+ ext = f->extension();
}
}
string ofname = fname.onlyFileName();
bool GuiView::closeBuffer()
{
GuiWorkArea * wa = currentMainWorkArea();
+ // coverity complained about this
+ // it seems unnecessary, but perhaps is worth the check
+ LASSERT(wa, return false);
+
setCurrentWorkArea(wa);
Buffer & buf = wa->bufferView().buffer();
- return wa && closeWorkArea(wa, !buf.parent());
+ return closeWorkArea(wa, !buf.parent());
}
// We have to call count() each time, because it can happen that
// more than one splitter will disappear in one iteration (bug 5998).
- for (; d.splitter_->count() > empty_twa; ) {
+ while (d.splitter_->count() > empty_twa) {
TabWorkArea * twa = d.tabWorkArea(empty_twa);
if (twa->count() == 0)
Buffer & buf = wa->bufferView().buffer();
- if (close_buffer && GuiViewPrivate::busyBuffers.contains(&buf)) {
+ if (GuiViewPrivate::busyBuffers.contains(&buf)) {
Alert::warning(_("Close document"),
_("Document could not be closed because it is being processed by LyX."));
return false;
ListOfBuffers::const_iterator it = clist.begin();
ListOfBuffers::const_iterator const bend = clist.end();
for (; it != bend; ++it) {
- // If a child is dirty, do not close
- // without user intervention
- //FIXME: should we look in other tabworkareas?
Buffer * child_buf = *it;
+ if (theBufferList().isOthersChild(&buf, child_buf)) {
+ child_buf->setParent(0);
+ continue;
+ }
+
+ // FIXME: should we look in other tabworkareas?
+ // ANSWER: I don't think so. I've tested, and if the child is
+ // open in some other window, it closes without a problem.
GuiWorkArea * child_wa = workArea(*child_buf);
if (child_wa) {
- if (!closeWorkArea(child_wa, true)) {
- success = false;
+ success = closeWorkArea(child_wa, true);
+ if (!success)
break;
- }
- } else
- theBufferList().releaseChild(&buf, child_buf);
+ } else {
+ // In this case the child buffer is open but hidden.
+ // It therefore should not (MUST NOT) be dirty!
+ LATTEST(child_buf->isClean());
+ theBufferList().release(child_buf);
+ }
}
}
if (success) {
// goto bookmark to update bookmark pit.
- //FIXME: we should update only the bookmarks related to this buffer!
+ // FIXME: we should update only the bookmarks related to this buffer!
LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
guiApp->gotoBookmark(i+1, false, false);
bool GuiView::closeTabWorkArea(TabWorkArea * twa)
{
while (twa == d.currentTabWorkArea()) {
- twa->setCurrentIndex(twa->count()-1);
+ twa->setCurrentIndex(twa->count() - 1);
GuiWorkArea * wa = twa->currentWorkArea();
Buffer & b = wa->bufferView().buffer();
}
-void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np)
+void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np, bool const move)
{
if (!documentBufferView())
return;
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;
}
}
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)
}
case LFUN_VC_COMPARE: {
-
if (cmd.argument().empty()) {
lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "comparehistory"));
break;
string f1, f2;
// f1
+ // it seems safe to assume we have a buffer
+ // coverity[FORWARD_NULL]
if (!buffer->lyxvc().prepareFileRevision(rev1, f1))
break;
return false;
}
setBuffer(buf);
- documentBufferView()->setCursorFromRow(row);
- return true;
+ bool success = documentBufferView()->setCursorFromRow(row);
+ if (!success) {
+ LYXERR(Debug::LATEX,
+ "setCursorFromRow: invalid position for row " << row);
+ frontend::Alert::error(_("Inverse Search Failed"),
+ _("Invalid position requested by inverse search.\n"
+ "You may need to update the viewed document."));
+ }
+ return success;
+}
+
+
+void GuiView::toolBarPopup(const QPoint & /*pos*/)
+{
+ QMenu * menu = new QMenu;
+ menu = guiApp->menus().menu(toqstr("context-toolbars"), * this);
+ menu->exec(QCursor::pos());
}
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) {
#else
Buffer::ExportStatus status;
if (syncFunc) {
- // TODO check here if it breaks exporting with Qt < 4.4
status = (used_buffer->*syncFunc)(format, true);
} else if (previewFunc) {
status = (used_buffer->*previewFunc)(format);
case LFUN_BUFFER_EXPORT: {
if (!doc_buffer)
break;
- FileName target_dir = doc_buffer->fileName().onlyPath();
- string const dest = cmd.getArg(1);
- if (!dest.empty() && FileName::isAbsolute(dest))
- target_dir = FileName(support::onlyPath(dest));
// GCC only sees strfwd.h when building merged
if (::lyx::operator==(cmd.argument(), "custom")) {
dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
break;
}
- if (!target_dir.isDirWritable()) {
+
+ string const dest = cmd.getArg(1);
+ FileName target_dir;
+ if (!dest.empty() && FileName::isAbsolute(dest))
+ target_dir = FileName(support::onlyPath(dest));
+ else
+ target_dir = doc_buffer->fileName().onlyPath();
+
+ if ((dest.empty() && doc_buffer->isUnnamed())
+ || !target_dir.isDirWritable()) {
exportBufferAs(*doc_buffer, cmd.argument());
break;
}
for (; i != ids.size(); ++i) {
GuiView & gv = guiApp->view(ids[i]);
if (gv.workArea(*buffer)) {
+ gv.raise();
gv.activateWindow();
+ gv.setFocus();
gv.setBuffer(buffer);
break;
}
}
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: {
- bool const show_it = cmd.argument() != "off";
- // FIXME: this is a hack, "minibuffer" should not be
- // hardcoded.
- if (GuiToolbar * t = toolbar("minibuffer")) {
- t->setVisible(show_it);
- if (show_it && t->commandBuffer())
- t->commandBuffer()->setFocus();
- }
+ command_execute_ = true;
+ minibuffer_focus_ = true;
break;
}
case LFUN_DROP_LAYOUTS_CHOICE:
break;
}
+ case LFUN_ICON_SIZE: {
+ QSize size = d.iconSize(cmd.argument());
+ setIconSize(size);
+ dr.setMessage(bformat(_("Icon size set to %1$dx%2$d."),
+ size.width(), size.height()));
+ break;
+ }
+
case LFUN_DIALOG_UPDATE: {
string const name = to_utf8(cmd.argument());
if (name == "prefs" || name == "document")
break;
case LFUN_BUFFER_ZOOM_IN:
- case LFUN_BUFFER_ZOOM_OUT:
+ case LFUN_BUFFER_ZOOM_OUT: {
+ // use a signed temp to avoid overflow
+ int zoom = lyxrc.zoom;
if (cmd.argument().empty()) {
if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
- lyxrc.zoom += 20;
+ zoom += 20;
else
- lyxrc.zoom -= 20;
+ zoom -= 20;
} else
- lyxrc.zoom += convert<int>(cmd.argument());
+ zoom += convert<int>(cmd.argument());
+
+ if (zoom < static_cast<int>(zoom_min_))
+ zoom = zoom_min_;
+ lyxrc.zoom = zoom;
- if (lyxrc.zoom < 10)
- lyxrc.zoom = 10;
+ dr.setMessage(bformat(_("Zoom level is now %1$d%"), lyxrc.zoom));
// The global QPixmapCache is used in GuiPainter to cache text
// painting so we must reset it.
guiApp->fontLoader().update();
lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
break;
+ }
case LFUN_VC_REGISTER:
case LFUN_VC_RENAME:
break;
case LFUN_SERVER_GOTO_FILE_ROW:
- goToFileRow(to_utf8(cmd.argument()));
+ if(goToFileRow(to_utf8(cmd.argument())))
+ dr.screenUpdate(Update::Force | Update::FitCursor);
+ break;
+
+ case LFUN_LYX_ACTIVATE:
+ activateWindow();
break;
case LFUN_FORWARD_SEARCH: {
+ // it seems safe to assume we have a document buffer, since
+ // getStatus wants one.
+ // coverity[FORWARD_NULL]
Buffer const * doc_master = doc_buffer->masterBuffer();
FileName const path(doc_master->temppath());
string const texname = doc_master->isChild(doc_buffer)
command = lyxrc.forward_search_pdf;
}
- DocIterator tmpcur = bv->cursor();
- // Leave math first
- while (tmpcur.inMathed())
- tmpcur.pop_back();
- int row = tmpcur.inMathed() ? 0 : doc_buffer->texrow().getRowFromIdPos(
- tmpcur.paragraph().id(), tmpcur.pos());
+ DocIterator cur = bv->cursor();
+ int row = doc_buffer->texrow().rowFromDocIterator(cur).first;
LYXERR(Debug::ACTION, "Forward search: row:" << row
- << " id:" << tmpcur.paragraph().id());
- if (!row || command.empty()) {
+ << " cur:" << cur);
+ if (row == -1 || command.empty()) {
dr.setMessage(_("Couldn't proceed."));
break;
}
case LFUN_SPELLING_CONTINUOUSLY:
lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously;
- dr.screenUpdate(Update::Force | Update::FitCursor);
+ dr.screenUpdate(Update::Force);
break;
default:
if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
menuBar()->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();
+ }
+ }
}
"external", "file", "findreplace", "findreplaceadv", "float", "graphics",
"href", "include", "index", "index_print", "info", "listings", "label", "line",
"log", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
-"nomencl_print", "note", "paragraph", "phantom", "prefs", "print", "ref",
+"nomencl_print", "note", "paragraph", "phantom", "prefs", "ref",
"sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
"thesaurus", "texinfo", "toc", "view-source", "vspace", "wrap", "progress"};
return createGuiPhantom(*this);
if (name == "prefs")
return createGuiPreferences(*this);
- if (name == "print")
- return createGuiPrint(*this);
if (name == "ref")
return createGuiRef(*this);
if (name == "sendto")