#include "GuiView.h"
-#include "Dialog.h"
#include "DispatchResult.h"
#include "FileDialog.h"
#include "FontLoader.h"
#include <QSplitter>
#include <QStackedWidget>
#include <QStatusBar>
-#if QT_VERSION >= 0x050000
#include <QSvgRenderer>
-#endif
#include <QtConcurrentRun>
#include <QTime>
#include <QTimer>
/// Current ratio between physical pixels and device-independent pixels
double pixelRatio() const {
#if QT_VERSION >= 0x050000
- return devicePixelRatio();
+ return qt_scale_factor * devicePixelRatio();
#else
return 1.0;
#endif
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);
-
- 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);
- else if (cur == parent->d.normalIconSize)
- 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;
- }
-
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_;
GuiView::GuiView(int id)
: d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0),
- command_execute_(false)
+ 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
#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);
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.width() != int(d.hugeIconSize) &&
- icon_size.width() != int(d.giantIconSize)) {
- icon_size.setWidth(d.normalIconSize);
- icon_size.setHeight(d.normalIconSize);
- }
- setIconSize(icon_size);
+ setIconSize(d.iconSize(settings.value(icon_key).toString()));
#if defined(Q_WS_X11) || defined(QPA_XCB)
QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
}
-QMenu * GuiView::createPopupMenu()
-{
- return d.toolBarPopup(this);
-}
-
-
void GuiView::showEvent(QShowEvent * e)
{
LYXERR(Debug::GUI, "Passed Geometry "
}
-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::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,
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*/)
double GuiView::pixelRatio() const
{
#if QT_VERSION >= 0x050000
- return devicePixelRatio();
+ return qt_scale_factor * devicePixelRatio();
#else
return 1.0;
#endif
if (!wa) {
d.current_work_area_ = 0;
d.setBackground();
+ Q_EMIT bufferViewChanged();
return;
}
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(context);
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());
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_ICON_SIZE:
+ flag.setOnOff(d.iconSize(cmd.argument()) == iconSize());
+ break;
+
case LFUN_DROP_LAYOUTS_CHOICE:
enable = buf != 0;
break;
break;
case LFUN_BUFFER_ZOOM_OUT:
- enable = doc_buffer && lyxrc.zoom > 10;
- break;
-
- case LFUN_BUFFER_ZOOM_IN:
- enable = doc_buffer != 0;
+ 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
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();
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());
}
#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()) {
- exportBufferAs(*doc_buffer, cmd.argument());
+
+ 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();
+
+ string const format = argument.empty() ?
+ doc_buffer->params().getDefaultOutputFormat() : argument;
+
+ if ((dest.empty() && doc_buffer->isUnnamed())
+ || !target_dir.isDirWritable()) {
+ exportBufferAs(*doc_buffer, from_utf8(format));
break;
}
/* TODO/Review: Is it a problem to also export the children?
See the update_unincluded flag */
- d.asyncBufferProcessing(argument,
+ d.asyncBufferProcessing(format,
doc_buffer,
_("Exporting ..."),
&GuiViewPrivate::exportAndDestroy,
case LFUN_COMMAND_EXECUTE: {
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: {
case LFUN_SPELLING_CONTINUOUSLY:
lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously;
- dr.screenUpdate(Update::Force | Update::FitCursor);
+ dr.screenUpdate(Update::Force);
break;
default:
bv = currentBufferView();
// Clear non-empty selections
- // (e.g. from a "char-forward-select" followed by "char-backward-select")
+ // (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())) {