3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "DispatchResult.h"
20 #include "FileDialog.h"
21 #include "FontLoader.h"
22 #include "GuiApplication.h"
23 #include "GuiCommandBuffer.h"
24 #include "GuiCompleter.h"
25 #include "GuiKeySymbol.h"
27 #include "GuiToolbar.h"
28 #include "GuiWorkArea.h"
29 #include "GuiProgress.h"
30 #include "LayoutBox.h"
34 #include "qt_helpers.h"
35 #include "support/filetools.h"
37 #include "frontends/alert.h"
38 #include "frontends/KeySymbol.h"
40 #include "buffer_funcs.h"
42 #include "BufferList.h"
43 #include "BufferParams.h"
44 #include "BufferView.h"
46 #include "Converter.h"
48 #include "CutAndPaste.h"
50 #include "ErrorList.h"
52 #include "FuncStatus.h"
53 #include "FuncRequest.h"
57 #include "LyXAction.h"
61 #include "Paragraph.h"
62 #include "SpellChecker.h"
65 #include "TextClass.h"
70 #include "support/convert.h"
71 #include "support/debug.h"
72 #include "support/ExceptionMessage.h"
73 #include "support/FileName.h"
74 #include "support/filetools.h"
75 #include "support/gettext.h"
76 #include "support/filetools.h"
77 #include "support/ForkedCalls.h"
78 #include "support/lassert.h"
79 #include "support/lstrings.h"
80 #include "support/os.h"
81 #include "support/Package.h"
82 #include "support/PathChanger.h"
83 #include "support/Systemcall.h"
84 #include "support/Timeout.h"
85 #include "support/ProgressInterface.h"
88 #include <QApplication>
89 #include <QCloseEvent>
91 #include <QDesktopWidget>
92 #include <QDragEnterEvent>
95 #include <QFutureWatcher>
104 #include <QPixmapCache>
106 #include <QPushButton>
107 #include <QScrollBar>
109 #include <QShowEvent>
111 #include <QStackedWidget>
112 #include <QStatusBar>
113 #if QT_VERSION >= 0x050000
114 #include <QSvgRenderer>
116 #include <QtConcurrentRun>
124 // sync with GuiAlert.cpp
125 #define EXPORT_in_THREAD 1
128 #include "support/bind.h"
132 #ifdef HAVE_SYS_TIME_H
133 # include <sys/time.h>
141 using namespace lyx::support;
145 using support::addExtension;
146 using support::changeExtension;
147 using support::removeExtension;
153 class BackgroundWidget : public QWidget
156 BackgroundWidget(int width, int height)
157 : width_(width), height_(height)
159 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
160 if (!lyxrc.show_banner)
162 /// The text to be written on top of the pixmap
163 QString const text = lyx_version ?
164 qt_("version ") + lyx_version : qt_("unknown version");
165 #if QT_VERSION >= 0x050000
166 QString imagedir = "images/";
167 FileName fname = imageLibFileSearch(imagedir, "banner", "svgz");
168 QSvgRenderer svgRenderer(toqstr(fname.absFileName()));
169 if (svgRenderer.isValid()) {
170 splash_ = QPixmap(splashSize());
171 QPainter painter(&splash_);
172 svgRenderer.render(&painter);
173 splash_.setDevicePixelRatio(pixelRatio());
175 splash_ = getPixmap("images/", "banner", "png");
178 splash_ = getPixmap("images/", "banner", "svgz,png");
181 QPainter pain(&splash_);
182 pain.setPen(QColor(0, 0, 0));
183 qreal const fsize = fontSize();
184 QPointF const position = textPosition();
186 "widget pixel ratio: " << pixelRatio() <<
187 " splash pixel ratio: " << splashPixelRatio() <<
188 " version text size,position: " << fsize << "@" << position.x() << "+" << position.y());
190 // The font used to display the version info
191 font.setStyleHint(QFont::SansSerif);
192 font.setWeight(QFont::Bold);
193 font.setPointSizeF(fsize);
195 pain.drawText(position, text);
196 setFocusPolicy(Qt::StrongFocus);
199 void paintEvent(QPaintEvent *)
201 int const w = width_;
202 int const h = height_;
203 int const x = (width() - w) / 2;
204 int const y = (height() - h) / 2;
206 "widget pixel ratio: " << pixelRatio() <<
207 " splash pixel ratio: " << splashPixelRatio() <<
208 " paint pixmap: " << w << "x" << h << "@" << x << "+" << y);
210 pain.drawPixmap(x, y, w, h, splash_);
213 void keyPressEvent(QKeyEvent * ev)
216 setKeySymbol(&sym, ev);
218 guiApp->processKeySym(sym, q_key_state(ev->modifiers()));
230 /// Current ratio between physical pixels and device-independent pixels
231 double pixelRatio() const {
232 #if QT_VERSION >= 0x050000
233 return devicePixelRatio();
239 qreal fontSize() const {
240 return toqstr(lyxrc.font_sizes[FONT_SIZE_NORMAL]).toDouble();
243 QPointF textPosition() const {
244 return QPointF(width_/2 - 18, height_/2 + 45);
247 QSize splashSize() const {
249 static_cast<unsigned int>(width_ * pixelRatio()),
250 static_cast<unsigned int>(height_ * pixelRatio()));
253 /// Ratio between physical pixels and device-independent pixels of splash image
254 double splashPixelRatio() const {
255 #if QT_VERSION >= 0x050000
256 return splash_.devicePixelRatio();
264 /// Toolbar store providing access to individual toolbars by name.
265 typedef map<string, GuiToolbar *> ToolbarMap;
267 typedef shared_ptr<Dialog> DialogPtr;
272 class GuiView::GuiViewPrivate
275 GuiViewPrivate(GuiViewPrivate const &);
276 void operator=(GuiViewPrivate const &);
278 GuiViewPrivate(GuiView * gv)
279 : gv_(gv), current_work_area_(0), current_main_work_area_(0),
280 layout_(0), autosave_timeout_(5000),
283 // hardcode here the platform specific icon size
284 smallIconSize = 16; // scaling problems
285 normalIconSize = 20; // ok, default if iconsize.png is missing
286 bigIconSize = 26; // better for some math icons
287 hugeIconSize = 32; // better for hires displays
290 // if it exists, use width of iconsize.png as normal size
291 QString const dir = toqstr(addPath("images", lyxrc.icon_set));
292 FileName const fn = lyx::libFileSearch(dir, "iconsize.png");
294 QImage image(toqstr(fn.absFileName()));
295 if (image.width() < int(smallIconSize))
296 normalIconSize = smallIconSize;
297 else if (image.width() > int(giantIconSize))
298 normalIconSize = giantIconSize;
300 normalIconSize = image.width();
303 splitter_ = new QSplitter;
304 bg_widget_ = new BackgroundWidget(400, 250);
305 stack_widget_ = new QStackedWidget;
306 stack_widget_->addWidget(bg_widget_);
307 stack_widget_->addWidget(splitter_);
310 // TODO cleanup, remove the singleton, handle multiple Windows?
311 progress_ = ProgressInterface::instance();
312 if (!dynamic_cast<GuiProgress*>(progress_)) {
313 progress_ = new GuiProgress; // TODO who deletes it
314 ProgressInterface::setInstance(progress_);
317 dynamic_cast<GuiProgress*>(progress_),
318 SIGNAL(updateStatusBarMessage(QString const&)),
319 gv, SLOT(updateStatusBarMessage(QString const&)));
321 dynamic_cast<GuiProgress*>(progress_),
322 SIGNAL(clearMessageText()),
323 gv, SLOT(clearMessageText()));
330 delete stack_widget_;
333 QMenu * toolBarPopup(GuiView * parent)
335 // FIXME: translation
336 QMenu * menu = new QMenu(parent);
337 QActionGroup * iconSizeGroup = new QActionGroup(parent);
339 QAction * smallIcons = new QAction(iconSizeGroup);
340 smallIcons->setText(qt_("Small-sized icons"));
341 smallIcons->setCheckable(true);
342 QObject::connect(smallIcons, SIGNAL(triggered()),
343 parent, SLOT(smallSizedIcons()));
344 menu->addAction(smallIcons);
346 QAction * normalIcons = new QAction(iconSizeGroup);
347 normalIcons->setText(qt_("Normal-sized icons"));
348 normalIcons->setCheckable(true);
349 QObject::connect(normalIcons, SIGNAL(triggered()),
350 parent, SLOT(normalSizedIcons()));
351 menu->addAction(normalIcons);
353 QAction * bigIcons = new QAction(iconSizeGroup);
354 bigIcons->setText(qt_("Big-sized icons"));
355 bigIcons->setCheckable(true);
356 QObject::connect(bigIcons, SIGNAL(triggered()),
357 parent, SLOT(bigSizedIcons()));
358 menu->addAction(bigIcons);
360 QAction * hugeIcons = new QAction(iconSizeGroup);
361 hugeIcons->setText(qt_("Huge-sized icons"));
362 hugeIcons->setCheckable(true);
363 QObject::connect(hugeIcons, SIGNAL(triggered()),
364 parent, SLOT(hugeSizedIcons()));
365 menu->addAction(hugeIcons);
367 QAction * giantIcons = new QAction(iconSizeGroup);
368 giantIcons->setText(qt_("Giant-sized icons"));
369 giantIcons->setCheckable(true);
370 QObject::connect(giantIcons, SIGNAL(triggered()),
371 parent, SLOT(giantSizedIcons()));
372 menu->addAction(giantIcons);
374 unsigned int cur = parent->iconSize().width();
375 if ( cur == parent->d.smallIconSize)
376 smallIcons->setChecked(true);
377 else if (cur == parent->d.normalIconSize)
378 normalIcons->setChecked(true);
379 else if (cur == parent->d.bigIconSize)
380 bigIcons->setChecked(true);
381 else if (cur == parent->d.hugeIconSize)
382 hugeIcons->setChecked(true);
383 else if (cur == parent->d.giantIconSize)
384 giantIcons->setChecked(true);
391 stack_widget_->setCurrentWidget(bg_widget_);
392 bg_widget_->setUpdatesEnabled(true);
393 bg_widget_->setFocus();
396 int tabWorkAreaCount()
398 return splitter_->count();
401 TabWorkArea * tabWorkArea(int i)
403 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
406 TabWorkArea * currentTabWorkArea()
408 int areas = tabWorkAreaCount();
410 // The first TabWorkArea is always the first one, if any.
411 return tabWorkArea(0);
413 for (int i = 0; i != areas; ++i) {
414 TabWorkArea * twa = tabWorkArea(i);
415 if (current_main_work_area_ == twa->currentWorkArea())
419 // None has the focus so we just take the first one.
420 return tabWorkArea(0);
423 int countWorkAreasOf(Buffer & buf)
425 int areas = tabWorkAreaCount();
427 for (int i = 0; i != areas; ++i) {
428 TabWorkArea * twa = tabWorkArea(i);
429 if (twa->workArea(buf))
435 void setPreviewFuture(QFuture<Buffer::ExportStatus> const & f)
437 if (processing_thread_watcher_.isRunning()) {
438 // we prefer to cancel this preview in order to keep a snappy
442 processing_thread_watcher_.setFuture(f);
447 GuiWorkArea * current_work_area_;
448 GuiWorkArea * current_main_work_area_;
449 QSplitter * splitter_;
450 QStackedWidget * stack_widget_;
451 BackgroundWidget * bg_widget_;
453 ToolbarMap toolbars_;
454 ProgressInterface* progress_;
455 /// The main layout box.
457 * \warning Don't Delete! The layout box is actually owned by
458 * whichever toolbar contains it. All the GuiView class needs is a
459 * means of accessing it.
461 * FIXME: replace that with a proper model so that we are not limited
462 * to only one dialog.
467 map<string, DialogPtr> dialogs_;
469 unsigned int smallIconSize;
470 unsigned int normalIconSize;
471 unsigned int bigIconSize;
472 unsigned int hugeIconSize;
473 unsigned int giantIconSize;
475 QTimer statusbar_timer_;
476 /// auto-saving of buffers
477 Timeout autosave_timeout_;
478 /// flag against a race condition due to multiclicks, see bug #1119
482 TocModels toc_models_;
485 QFutureWatcher<docstring> autosave_watcher_;
486 QFutureWatcher<Buffer::ExportStatus> processing_thread_watcher_;
488 string last_export_format;
489 string processing_format;
491 static QSet<Buffer const *> busyBuffers;
492 static Buffer::ExportStatus previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
493 static Buffer::ExportStatus exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
494 static Buffer::ExportStatus compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
495 static docstring autosaveAndDestroy(Buffer const * orig, Buffer * buffer);
498 static Buffer::ExportStatus runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format);
500 // TODO syncFunc/previewFunc: use bind
501 bool asyncBufferProcessing(string const & argument,
502 Buffer const * used_buffer,
503 docstring const & msg,
504 Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
505 Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
506 Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const);
508 QVector<GuiWorkArea*> guiWorkAreas();
511 QSet<Buffer const *> GuiView::GuiViewPrivate::busyBuffers;
514 GuiView::GuiView(int id)
515 : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0),
516 command_execute_(false)
518 // GuiToolbars *must* be initialised before the menu bar.
519 normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge
522 // set ourself as the current view. This is needed for the menu bar
523 // filling, at least for the static special menu item on Mac. Otherwise
524 // they are greyed out.
525 guiApp->setCurrentView(this);
527 // Fill up the menu bar.
528 guiApp->menus().fillMenuBar(menuBar(), this, true);
530 setCentralWidget(d.stack_widget_);
532 // Start autosave timer
533 if (lyxrc.autosave) {
534 d.autosave_timeout_.timeout.connect(bind(&GuiView::autoSave, this));
535 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
536 d.autosave_timeout_.start();
538 connect(&d.statusbar_timer_, SIGNAL(timeout()),
539 this, SLOT(clearMessage()));
541 // We don't want to keep the window in memory if it is closed.
542 setAttribute(Qt::WA_DeleteOnClose, true);
544 #if !(defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)) && !defined(Q_OS_MAC)
545 // QIcon::fromTheme was introduced in Qt 4.6
546 #if (QT_VERSION >= 0x040600)
547 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
548 // since the icon is provided in the application bundle. We use a themed
549 // version when available and use the bundled one as fallback.
550 setWindowIcon(QIcon::fromTheme("lyx", getPixmap("images/", "lyx", "svg,png")));
552 setWindowIcon(getPixmap("images/", "lyx", "svg,png"));
556 resetWindowTitleAndIconText();
558 // use tabbed dock area for multiple docks
559 // (such as "source" and "messages")
560 setDockOptions(QMainWindow::ForceTabbedDocks);
563 setAcceptDrops(true);
565 // add busy indicator to statusbar
566 QLabel * busylabel = new QLabel(statusBar());
567 statusBar()->addPermanentWidget(busylabel);
568 search_mode mode = theGuiApp()->imageSearchMode();
569 QString fn = toqstr(lyx::libFileSearch("images", "busy", "gif", mode).absFileName());
570 QMovie * busyanim = new QMovie(fn, QByteArray(), busylabel);
571 busylabel->setMovie(busyanim);
575 connect(&d.processing_thread_watcher_, SIGNAL(started()),
576 busylabel, SLOT(show()));
577 connect(&d.processing_thread_watcher_, SIGNAL(finished()),
578 busylabel, SLOT(hide()));
580 statusBar()->setSizeGripEnabled(true);
583 connect(&d.autosave_watcher_, SIGNAL(finished()), this,
584 SLOT(autoSaveThreadFinished()));
586 connect(&d.processing_thread_watcher_, SIGNAL(started()), this,
587 SLOT(processingThreadStarted()));
588 connect(&d.processing_thread_watcher_, SIGNAL(finished()), this,
589 SLOT(processingThreadFinished()));
591 connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)),
592 SLOT(doShowDialog(QString const &, QString const &, Inset *)));
594 // Forbid too small unresizable window because it can happen
595 // with some window manager under X11.
596 setMinimumSize(300, 200);
598 if (lyxrc.allow_geometry_session) {
599 // Now take care of session management.
604 // no session handling, default to a sane size.
605 setGeometry(50, 50, 690, 510);
608 // clear session data if any.
610 settings.remove("views");
620 QVector<GuiWorkArea*> GuiView::GuiViewPrivate::guiWorkAreas()
622 QVector<GuiWorkArea*> areas;
623 for (int i = 0; i < tabWorkAreaCount(); i++) {
624 TabWorkArea* ta = tabWorkArea(i);
625 for (int u = 0; u < ta->count(); u++) {
626 areas << ta->workArea(u);
632 static void handleExportStatus(GuiView * view, Buffer::ExportStatus status,
633 string const & format)
635 docstring const fmt = formats.prettyName(format);
638 case Buffer::ExportSuccess:
639 msg = bformat(_("Successful export to format: %1$s"), fmt);
641 case Buffer::ExportCancel:
642 msg = _("Document export cancelled.");
644 case Buffer::ExportError:
645 case Buffer::ExportNoPathToFormat:
646 case Buffer::ExportTexPathHasSpaces:
647 case Buffer::ExportConverterError:
648 msg = bformat(_("Error while exporting format: %1$s"), fmt);
650 case Buffer::PreviewSuccess:
651 msg = bformat(_("Successful preview of format: %1$s"), fmt);
653 case Buffer::PreviewError:
654 msg = bformat(_("Error while previewing format: %1$s"), fmt);
661 void GuiView::processingThreadStarted()
666 void GuiView::processingThreadFinished()
668 QFutureWatcher<Buffer::ExportStatus> const * watcher =
669 static_cast<QFutureWatcher<Buffer::ExportStatus> const *>(sender());
671 Buffer::ExportStatus const status = watcher->result();
672 handleExportStatus(this, status, d.processing_format);
675 BufferView const * const bv = currentBufferView();
676 if (bv && !bv->buffer().errorList("Export").empty()) {
680 errors(d.last_export_format);
684 void GuiView::autoSaveThreadFinished()
686 QFutureWatcher<docstring> const * watcher =
687 static_cast<QFutureWatcher<docstring> const *>(sender());
688 message(watcher->result());
693 void GuiView::saveLayout() const
696 settings.beginGroup("views");
697 settings.beginGroup(QString::number(id_));
698 #if defined(Q_WS_X11) || defined(QPA_XCB)
699 settings.setValue("pos", pos());
700 settings.setValue("size", size());
702 settings.setValue("geometry", saveGeometry());
704 settings.setValue("layout", saveState(0));
705 settings.setValue("icon_size", iconSize());
709 void GuiView::saveUISettings() const
711 // Save the toolbar private states
712 ToolbarMap::iterator end = d.toolbars_.end();
713 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
714 it->second->saveSession();
715 // Now take care of all other dialogs
716 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
717 for (; it!= d.dialogs_.end(); ++it)
718 it->second->saveSession();
722 bool GuiView::restoreLayout()
725 settings.beginGroup("views");
726 settings.beginGroup(QString::number(id_));
727 QString const icon_key = "icon_size";
728 if (!settings.contains(icon_key))
731 //code below is skipped when when ~/.config/LyX is (re)created
732 QSize icon_size = settings.value(icon_key).toSize();
733 // Check whether session size changed.
734 if (icon_size.width() != int(d.smallIconSize) &&
735 icon_size.width() != int(d.normalIconSize) &&
736 icon_size.width() != int(d.bigIconSize) &&
737 icon_size.width() != int(d.hugeIconSize) &&
738 icon_size.width() != int(d.giantIconSize)) {
739 icon_size.setWidth(d.normalIconSize);
740 icon_size.setHeight(d.normalIconSize);
742 setIconSize(icon_size);
744 #if defined(Q_WS_X11) || defined(QPA_XCB)
745 QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
746 QSize size = settings.value("size", QSize(690, 510)).toSize();
750 // Work-around for bug #6034: the window ends up in an undetermined
751 // state when trying to restore a maximized window when it is
752 // already maximized.
753 if (!(windowState() & Qt::WindowMaximized))
754 if (!restoreGeometry(settings.value("geometry").toByteArray()))
755 setGeometry(50, 50, 690, 510);
757 // Make sure layout is correctly oriented.
758 setLayoutDirection(qApp->layoutDirection());
760 // Allow the toc and view-source dock widget to be restored if needed.
762 if ((dialog = findOrBuild("toc", true)))
763 // see bug 5082. At least setup title and enabled state.
764 // Visibility will be adjusted by restoreState below.
765 dialog->prepareView();
766 if ((dialog = findOrBuild("view-source", true)))
767 dialog->prepareView();
768 if ((dialog = findOrBuild("progress", true)))
769 dialog->prepareView();
771 if (!restoreState(settings.value("layout").toByteArray(), 0))
774 // init the toolbars that have not been restored
775 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
776 Toolbars::Infos::iterator end = guiApp->toolbars().end();
777 for (; cit != end; ++cit) {
778 GuiToolbar * tb = toolbar(cit->name);
779 if (tb && !tb->isRestored())
780 initToolbar(cit->name);
788 GuiToolbar * GuiView::toolbar(string const & name)
790 ToolbarMap::iterator it = d.toolbars_.find(name);
791 if (it != d.toolbars_.end())
794 LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
799 void GuiView::constructToolbars()
801 ToolbarMap::iterator it = d.toolbars_.begin();
802 for (; it != d.toolbars_.end(); ++it)
806 // I don't like doing this here, but the standard toolbar
807 // destroys this object when it's destroyed itself (vfr)
808 d.layout_ = new LayoutBox(*this);
809 d.stack_widget_->addWidget(d.layout_);
810 d.layout_->move(0,0);
812 // extracts the toolbars from the backend
813 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
814 Toolbars::Infos::iterator end = guiApp->toolbars().end();
815 for (; cit != end; ++cit)
816 d.toolbars_[cit->name] = new GuiToolbar(*cit, *this);
820 void GuiView::initToolbars()
822 // extracts the toolbars from the backend
823 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
824 Toolbars::Infos::iterator end = guiApp->toolbars().end();
825 for (; cit != end; ++cit)
826 initToolbar(cit->name);
830 void GuiView::initToolbar(string const & name)
832 GuiToolbar * tb = toolbar(name);
835 int const visibility = guiApp->toolbars().defaultVisibility(name);
836 bool newline = !(visibility & Toolbars::SAMEROW);
837 tb->setVisible(false);
838 tb->setVisibility(visibility);
840 if (visibility & Toolbars::TOP) {
842 addToolBarBreak(Qt::TopToolBarArea);
843 addToolBar(Qt::TopToolBarArea, tb);
846 if (visibility & Toolbars::BOTTOM) {
848 addToolBarBreak(Qt::BottomToolBarArea);
849 addToolBar(Qt::BottomToolBarArea, tb);
852 if (visibility & Toolbars::LEFT) {
854 addToolBarBreak(Qt::LeftToolBarArea);
855 addToolBar(Qt::LeftToolBarArea, tb);
858 if (visibility & Toolbars::RIGHT) {
860 addToolBarBreak(Qt::RightToolBarArea);
861 addToolBar(Qt::RightToolBarArea, tb);
864 if (visibility & Toolbars::ON)
865 tb->setVisible(true);
869 TocModels & GuiView::tocModels()
871 return d.toc_models_;
875 void GuiView::setFocus()
877 LYXERR(Debug::DEBUG, "GuiView::setFocus()" << this);
878 QMainWindow::setFocus();
882 bool GuiView::hasFocus() const
884 if (currentWorkArea())
885 return currentWorkArea()->hasFocus();
886 if (currentMainWorkArea())
887 return currentMainWorkArea()->hasFocus();
888 return d.bg_widget_->hasFocus();
892 void GuiView::focusInEvent(QFocusEvent * e)
894 LYXERR(Debug::DEBUG, "GuiView::focusInEvent()" << this);
895 QMainWindow::focusInEvent(e);
896 // Make sure guiApp points to the correct view.
897 guiApp->setCurrentView(this);
898 if (currentWorkArea())
899 currentWorkArea()->setFocus();
900 else if (currentMainWorkArea())
901 currentMainWorkArea()->setFocus();
903 d.bg_widget_->setFocus();
907 QMenu * GuiView::createPopupMenu()
909 return d.toolBarPopup(this);
913 void GuiView::showEvent(QShowEvent * e)
915 LYXERR(Debug::GUI, "Passed Geometry "
916 << size().height() << "x" << size().width()
917 << "+" << pos().x() << "+" << pos().y());
919 if (d.splitter_->count() == 0)
920 // No work area, switch to the background widget.
924 QMainWindow::showEvent(e);
928 bool GuiView::closeScheduled()
935 bool GuiView::prepareAllBuffersForLogout()
937 Buffer * first = theBufferList().first();
941 // First, iterate over all buffers and ask the users if unsaved
942 // changes should be saved.
943 // We cannot use a for loop as the buffer list cycles.
946 if (!saveBufferIfNeeded(const_cast<Buffer &>(*b), false))
948 b = theBufferList().next(b);
949 } while (b != first);
951 // Next, save session state
952 // When a view/window was closed before without quitting LyX, there
953 // are already entries in the lastOpened list.
954 theSession().lastOpened().clear();
961 /** Destroy only all tabbed WorkAreas. Destruction of other WorkAreas
962 ** is responsibility of the container (e.g., dialog)
964 void GuiView::closeEvent(QCloseEvent * close_event)
966 LYXERR(Debug::DEBUG, "GuiView::closeEvent()");
968 if (!GuiViewPrivate::busyBuffers.isEmpty()) {
969 Alert::warning(_("Exit LyX"),
970 _("LyX could not be closed because documents are being processed by LyX."));
971 close_event->setAccepted(false);
975 // If the user pressed the x (so we didn't call closeView
976 // programmatically), we want to clear all existing entries.
978 theSession().lastOpened().clear();
983 // it can happen that this event arrives without selecting the view,
984 // e.g. when clicking the close button on a background window.
986 if (!closeWorkAreaAll()) {
988 close_event->ignore();
992 // Make sure that nothing will use this to be closed View.
993 guiApp->unregisterView(this);
995 if (isFullScreen()) {
996 // Switch off fullscreen before closing.
1001 // Make sure the timer time out will not trigger a statusbar update.
1002 d.statusbar_timer_.stop();
1004 // Saving fullscreen requires additional tweaks in the toolbar code.
1005 // It wouldn't also work under linux natively.
1006 if (lyxrc.allow_geometry_session) {
1011 close_event->accept();
1015 void GuiView::dragEnterEvent(QDragEnterEvent * event)
1017 if (event->mimeData()->hasUrls())
1019 /// \todo Ask lyx-devel is this is enough:
1020 /// if (event->mimeData()->hasFormat("text/plain"))
1021 /// event->acceptProposedAction();
1025 void GuiView::dropEvent(QDropEvent * event)
1027 QList<QUrl> files = event->mimeData()->urls();
1028 if (files.isEmpty())
1031 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
1032 for (int i = 0; i != files.size(); ++i) {
1033 string const file = os::internal_path(fromqstr(
1034 files.at(i).toLocalFile()));
1038 string const ext = support::getExtension(file);
1039 vector<const Format *> found_formats;
1041 // Find all formats that have the correct extension.
1042 vector<const Format *> const & import_formats
1043 = theConverters().importableFormats();
1044 vector<const Format *>::const_iterator it = import_formats.begin();
1045 for (; it != import_formats.end(); ++it)
1046 if ((*it)->hasExtension(ext))
1047 found_formats.push_back(*it);
1050 if (found_formats.size() >= 1) {
1051 if (found_formats.size() > 1) {
1052 //FIXME: show a dialog to choose the correct importable format
1053 LYXERR(Debug::FILES,
1054 "Multiple importable formats found, selecting first");
1056 string const arg = found_formats[0]->name() + " " + file;
1057 cmd = FuncRequest(LFUN_BUFFER_IMPORT, arg);
1060 //FIXME: do we have to explicitly check whether it's a lyx file?
1061 LYXERR(Debug::FILES,
1062 "No formats found, trying to open it as a lyx file");
1063 cmd = FuncRequest(LFUN_FILE_OPEN, file);
1065 // add the functions to the queue
1066 guiApp->addToFuncRequestQueue(cmd);
1069 // now process the collected functions. We perform the events
1070 // asynchronously. This prevents potential problems in case the
1071 // BufferView is closed within an event.
1072 guiApp->processFuncRequestQueueAsync();
1076 void GuiView::message(docstring const & str)
1078 if (ForkedProcess::iAmAChild())
1081 // call is moved to GUI-thread by GuiProgress
1082 d.progress_->appendMessage(toqstr(str));
1086 void GuiView::clearMessageText()
1088 message(docstring());
1092 void GuiView::updateStatusBarMessage(QString const & str)
1094 statusBar()->showMessage(str);
1095 d.statusbar_timer_.stop();
1096 d.statusbar_timer_.start(3000);
1100 void GuiView::smallSizedIcons()
1102 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
1106 void GuiView::normalSizedIcons()
1108 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
1112 void GuiView::bigSizedIcons()
1114 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
1118 void GuiView::hugeSizedIcons()
1120 setIconSize(QSize(d.hugeIconSize, d.hugeIconSize));
1124 void GuiView::giantSizedIcons()
1126 setIconSize(QSize(d.giantIconSize, d.giantIconSize));
1130 void GuiView::clearMessage()
1132 // FIXME: This code was introduced in r19643 to fix bug #4123. However,
1133 // the hasFocus function mostly returns false, even if the focus is on
1134 // a workarea in this view.
1138 d.statusbar_timer_.stop();
1142 void GuiView::updateWindowTitle(GuiWorkArea * wa)
1144 if (wa != d.current_work_area_
1145 || wa->bufferView().buffer().isInternal())
1147 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
1148 setWindowIconText(wa->windowIconText());
1149 #if (QT_VERSION >= 0x040400)
1150 // Sets the path for the window: this is used by OSX to
1151 // allow a context click on the title bar showing a menu
1152 // with the path up to the file
1153 setWindowFilePath(toqstr(wa->bufferView().buffer().absFileName()));
1158 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
1160 if (d.current_work_area_)
1161 QObject::disconnect(d.current_work_area_, SIGNAL(busy(bool)),
1162 this, SLOT(setBusy(bool)));
1164 disconnectBufferView();
1165 connectBufferView(wa->bufferView());
1166 connectBuffer(wa->bufferView().buffer());
1167 d.current_work_area_ = wa;
1168 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
1169 this, SLOT(updateWindowTitle(GuiWorkArea *)));
1170 QObject::connect(wa, SIGNAL(busy(bool)), this, SLOT(setBusy(bool)));
1171 updateWindowTitle(wa);
1175 // The document settings needs to be reinitialised.
1176 updateDialog("document", "");
1178 // Buffer-dependent dialogs must be updated. This is done here because
1179 // some dialogs require buffer()->text.
1184 void GuiView::on_lastWorkAreaRemoved()
1187 // We already are in a close event. Nothing more to do.
1190 if (d.splitter_->count() > 1)
1191 // We have a splitter so don't close anything.
1194 // Reset and updates the dialogs.
1195 d.toc_models_.reset(0);
1196 updateDialog("document", "");
1199 resetWindowTitleAndIconText();
1202 if (lyxrc.open_buffers_in_tabs)
1203 // Nothing more to do, the window should stay open.
1206 if (guiApp->viewIds().size() > 1) {
1212 // On Mac we also close the last window because the application stay
1213 // resident in memory. On other platforms we don't close the last
1214 // window because this would quit the application.
1220 void GuiView::updateStatusBar()
1222 // let the user see the explicit message
1223 if (d.statusbar_timer_.isActive())
1230 void GuiView::showMessage()
1234 QString msg = toqstr(theGuiApp()->viewStatusMessage());
1235 if (msg.isEmpty()) {
1236 BufferView const * bv = currentBufferView();
1238 msg = toqstr(bv->cursor().currentState());
1240 msg = qt_("Welcome to LyX!");
1242 statusBar()->showMessage(msg);
1246 bool GuiView::event(QEvent * e)
1250 // Useful debug code:
1251 //case QEvent::ActivationChange:
1252 //case QEvent::WindowDeactivate:
1253 //case QEvent::Paint:
1254 //case QEvent::Enter:
1255 //case QEvent::Leave:
1256 //case QEvent::HoverEnter:
1257 //case QEvent::HoverLeave:
1258 //case QEvent::HoverMove:
1259 //case QEvent::StatusTip:
1260 //case QEvent::DragEnter:
1261 //case QEvent::DragLeave:
1262 //case QEvent::Drop:
1265 case QEvent::WindowActivate: {
1266 GuiView * old_view = guiApp->currentView();
1267 if (this == old_view) {
1269 return QMainWindow::event(e);
1271 if (old_view && old_view->currentBufferView()) {
1272 // save current selection to the selection buffer to allow
1273 // middle-button paste in this window.
1274 cap::saveSelection(old_view->currentBufferView()->cursor());
1276 guiApp->setCurrentView(this);
1277 if (d.current_work_area_) {
1278 BufferView & bv = d.current_work_area_->bufferView();
1279 connectBufferView(bv);
1280 connectBuffer(bv.buffer());
1281 // The document structure, name and dialogs might have
1282 // changed in another view.
1284 // The document settings needs to be reinitialised.
1285 updateDialog("document", "");
1288 resetWindowTitleAndIconText();
1291 return QMainWindow::event(e);
1294 case QEvent::ShortcutOverride: {
1296 if (isFullScreen() && menuBar()->isHidden()) {
1297 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
1298 // FIXME: we should also try to detect special LyX shortcut such as
1299 // Alt-P and Alt-M. Right now there is a hack in
1300 // GuiWorkArea::processKeySym() that hides again the menubar for
1302 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt) {
1304 return QMainWindow::event(e);
1307 return QMainWindow::event(e);
1311 return QMainWindow::event(e);
1315 void GuiView::resetWindowTitleAndIconText()
1317 setWindowTitle(qt_("LyX"));
1318 setWindowIconText(qt_("LyX"));
1321 bool GuiView::focusNextPrevChild(bool /*next*/)
1328 bool GuiView::busy() const
1334 void GuiView::setBusy(bool busy)
1336 bool const busy_before = busy_ > 0;
1337 busy ? ++busy_ : --busy_;
1338 if ((busy_ > 0) == busy_before)
1339 // busy state didn't change
1343 QApplication::setOverrideCursor(Qt::WaitCursor);
1346 QApplication::restoreOverrideCursor();
1351 void GuiView::resetCommandExecute()
1353 command_execute_ = false;
1358 double GuiView::pixelRatio() const
1360 #if QT_VERSION >= 0x050000
1361 return devicePixelRatio();
1368 GuiWorkArea * GuiView::workArea(int index)
1370 if (TabWorkArea * twa = d.currentTabWorkArea())
1371 if (index < twa->count())
1372 return dynamic_cast<GuiWorkArea *>(twa->widget(index));
1377 GuiWorkArea * GuiView::workArea(Buffer & buffer)
1379 if (currentWorkArea()
1380 && ¤tWorkArea()->bufferView().buffer() == &buffer)
1381 return currentWorkArea();
1382 if (TabWorkArea * twa = d.currentTabWorkArea())
1383 return twa->workArea(buffer);
1388 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
1390 // Automatically create a TabWorkArea if there are none yet.
1391 TabWorkArea * tab_widget = d.splitter_->count()
1392 ? d.currentTabWorkArea() : addTabWorkArea();
1393 return tab_widget->addWorkArea(buffer, *this);
1397 TabWorkArea * GuiView::addTabWorkArea()
1399 TabWorkArea * twa = new TabWorkArea;
1400 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
1401 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
1402 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
1403 this, SLOT(on_lastWorkAreaRemoved()));
1405 d.splitter_->addWidget(twa);
1406 d.stack_widget_->setCurrentWidget(d.splitter_);
1411 GuiWorkArea const * GuiView::currentWorkArea() const
1413 return d.current_work_area_;
1417 GuiWorkArea * GuiView::currentWorkArea()
1419 return d.current_work_area_;
1423 GuiWorkArea const * GuiView::currentMainWorkArea() const
1425 if (!d.currentTabWorkArea())
1427 return d.currentTabWorkArea()->currentWorkArea();
1431 GuiWorkArea * GuiView::currentMainWorkArea()
1433 if (!d.currentTabWorkArea())
1435 return d.currentTabWorkArea()->currentWorkArea();
1439 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
1441 LYXERR(Debug::DEBUG, "Setting current wa: " << wa << endl);
1443 d.current_work_area_ = 0;
1448 // FIXME: I've no clue why this is here and why it accesses
1449 // theGuiApp()->currentView, which might be 0 (bug 6464).
1450 // See also 27525 (vfr).
1451 if (theGuiApp()->currentView() == this
1452 && theGuiApp()->currentView()->currentWorkArea() == wa)
1455 if (currentBufferView())
1456 cap::saveSelection(currentBufferView()->cursor());
1458 theGuiApp()->setCurrentView(this);
1459 d.current_work_area_ = wa;
1461 // We need to reset this now, because it will need to be
1462 // right if the tabWorkArea gets reset in the for loop. We
1463 // will change it back if we aren't in that case.
1464 GuiWorkArea * const old_cmwa = d.current_main_work_area_;
1465 d.current_main_work_area_ = wa;
1467 for (int i = 0; i != d.splitter_->count(); ++i) {
1468 if (d.tabWorkArea(i)->setCurrentWorkArea(wa)) {
1469 LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea()
1470 << ", Current main wa: " << currentMainWorkArea());
1475 d.current_main_work_area_ = old_cmwa;
1477 LYXERR(Debug::DEBUG, "This is not a tabbed wa");
1478 on_currentWorkAreaChanged(wa);
1479 BufferView & bv = wa->bufferView();
1480 bv.cursor().fixIfBroken();
1482 wa->setUpdatesEnabled(true);
1483 LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
1487 void GuiView::removeWorkArea(GuiWorkArea * wa)
1489 LASSERT(wa, return);
1490 if (wa == d.current_work_area_) {
1492 disconnectBufferView();
1493 d.current_work_area_ = 0;
1494 d.current_main_work_area_ = 0;
1497 bool found_twa = false;
1498 for (int i = 0; i != d.splitter_->count(); ++i) {
1499 TabWorkArea * twa = d.tabWorkArea(i);
1500 if (twa->removeWorkArea(wa)) {
1501 // Found in this tab group, and deleted the GuiWorkArea.
1503 if (twa->count() != 0) {
1504 if (d.current_work_area_ == 0)
1505 // This means that we are closing the current GuiWorkArea, so
1506 // switch to the next GuiWorkArea in the found TabWorkArea.
1507 setCurrentWorkArea(twa->currentWorkArea());
1509 // No more WorkAreas in this tab group, so delete it.
1516 // It is not a tabbed work area (i.e., the search work area), so it
1517 // should be deleted by other means.
1518 LASSERT(found_twa, return);
1520 if (d.current_work_area_ == 0) {
1521 if (d.splitter_->count() != 0) {
1522 TabWorkArea * twa = d.currentTabWorkArea();
1523 setCurrentWorkArea(twa->currentWorkArea());
1525 // No more work areas, switch to the background widget.
1526 setCurrentWorkArea(0);
1532 LayoutBox * GuiView::getLayoutDialog() const
1538 void GuiView::updateLayoutList()
1541 d.layout_->updateContents(false);
1545 void GuiView::updateToolbars()
1547 ToolbarMap::iterator end = d.toolbars_.end();
1548 if (d.current_work_area_) {
1550 if (d.current_work_area_->bufferView().cursor().inMathed()
1551 && !d.current_work_area_->bufferView().cursor().inRegexped())
1552 context |= Toolbars::MATH;
1553 if (lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled())
1554 context |= Toolbars::TABLE;
1555 if (lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled()
1556 && lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true))
1557 context |= Toolbars::REVIEW;
1558 if (lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled())
1559 context |= Toolbars::MATHMACROTEMPLATE;
1560 if (lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled())
1561 context |= Toolbars::IPA;
1562 if (command_execute_)
1563 context |= Toolbars::MINIBUFFER;
1565 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1566 it->second->update(context);
1568 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1569 it->second->update();
1573 void GuiView::setBuffer(Buffer * newBuffer)
1575 LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << endl);
1576 LASSERT(newBuffer, return);
1578 GuiWorkArea * wa = workArea(*newBuffer);
1581 newBuffer->masterBuffer()->updateBuffer();
1583 wa = addWorkArea(*newBuffer);
1584 // scroll to the position when the BufferView was last closed
1585 if (lyxrc.use_lastfilepos) {
1586 LastFilePosSection::FilePos filepos =
1587 theSession().lastFilePos().load(newBuffer->fileName());
1588 wa->bufferView().moveToPosition(filepos.pit, filepos.pos, 0, 0);
1591 //Disconnect the old buffer...there's no new one.
1594 connectBuffer(*newBuffer);
1595 connectBufferView(wa->bufferView());
1596 setCurrentWorkArea(wa);
1600 void GuiView::connectBuffer(Buffer & buf)
1602 buf.setGuiDelegate(this);
1606 void GuiView::disconnectBuffer()
1608 if (d.current_work_area_)
1609 d.current_work_area_->bufferView().buffer().setGuiDelegate(0);
1613 void GuiView::connectBufferView(BufferView & bv)
1615 bv.setGuiDelegate(this);
1619 void GuiView::disconnectBufferView()
1621 if (d.current_work_area_)
1622 d.current_work_area_->bufferView().setGuiDelegate(0);
1626 void GuiView::errors(string const & error_type, bool from_master)
1628 BufferView const * const bv = currentBufferView();
1632 #if EXPORT_in_THREAD
1633 // We are called with from_master == false by default, so we
1634 // have to figure out whether that is the case or not.
1635 ErrorList & el = bv->buffer().errorList(error_type);
1637 el = bv->buffer().masterBuffer()->errorList(error_type);
1641 ErrorList const & el = from_master ?
1642 bv->buffer().masterBuffer()->errorList(error_type) :
1643 bv->buffer().errorList(error_type);
1649 string data = error_type;
1651 data = "from_master|" + error_type;
1652 showDialog("errorlist", data);
1656 void GuiView::updateTocItem(string const & type, DocIterator const & dit)
1658 d.toc_models_.updateItem(toqstr(type), dit);
1662 void GuiView::structureChanged()
1664 d.toc_models_.reset(documentBufferView());
1665 // Navigator needs more than a simple update in this case. It needs to be
1667 updateDialog("toc", "");
1671 void GuiView::updateDialog(string const & name, string const & data)
1673 if (!isDialogVisible(name))
1676 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1677 if (it == d.dialogs_.end())
1680 Dialog * const dialog = it->second.get();
1681 if (dialog->isVisibleView())
1682 dialog->initialiseParams(data);
1686 BufferView * GuiView::documentBufferView()
1688 return currentMainWorkArea()
1689 ? ¤tMainWorkArea()->bufferView()
1694 BufferView const * GuiView::documentBufferView() const
1696 return currentMainWorkArea()
1697 ? ¤tMainWorkArea()->bufferView()
1702 BufferView * GuiView::currentBufferView()
1704 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1708 BufferView const * GuiView::currentBufferView() const
1710 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1714 docstring GuiView::GuiViewPrivate::autosaveAndDestroy(
1715 Buffer const * orig, Buffer * clone)
1717 bool const success = clone->autoSave();
1719 busyBuffers.remove(orig);
1721 ? _("Automatic save done.")
1722 : _("Automatic save failed!");
1726 void GuiView::autoSave()
1728 LYXERR(Debug::INFO, "Running autoSave()");
1730 Buffer * buffer = documentBufferView()
1731 ? &documentBufferView()->buffer() : 0;
1733 resetAutosaveTimers();
1737 GuiViewPrivate::busyBuffers.insert(buffer);
1738 QFuture<docstring> f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy,
1739 buffer, buffer->cloneBufferOnly());
1740 d.autosave_watcher_.setFuture(f);
1741 resetAutosaveTimers();
1745 void GuiView::resetAutosaveTimers()
1748 d.autosave_timeout_.restart();
1752 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1755 Buffer * buf = currentBufferView()
1756 ? ¤tBufferView()->buffer() : 0;
1757 Buffer * doc_buffer = documentBufferView()
1758 ? &(documentBufferView()->buffer()) : 0;
1761 /* In LyX/Mac, when a dialog is open, the menus of the
1762 application can still be accessed without giving focus to
1763 the main window. In this case, we want to disable the menu
1764 entries that are buffer-related.
1765 This code must not be used on Linux and Windows, since it
1766 would disable buffer-related entries when hovering over the
1767 menu (see bug #9574).
1769 if (cmd.origin() == FuncRequest::MENU && !hasFocus()) {
1775 // Check whether we need a buffer
1776 if (!lyxaction.funcHasFlag(cmd.action(), LyXAction::NoBuffer) && !buf) {
1777 // no, exit directly
1778 flag.message(from_utf8(N_("Command not allowed with"
1779 "out any document open")));
1780 flag.setEnabled(false);
1784 if (cmd.origin() == FuncRequest::TOC) {
1785 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
1786 if (!toc || !toc->getStatus(documentBufferView()->cursor(), cmd, flag))
1787 flag.setEnabled(false);
1791 switch(cmd.action()) {
1792 case LFUN_BUFFER_IMPORT:
1795 case LFUN_MASTER_BUFFER_UPDATE:
1796 case LFUN_MASTER_BUFFER_VIEW:
1798 && (doc_buffer->parent() != 0
1799 || doc_buffer->hasChildren())
1800 && !d.processing_thread_watcher_.isRunning();
1803 case LFUN_BUFFER_UPDATE:
1804 case LFUN_BUFFER_VIEW: {
1805 if (!doc_buffer || d.processing_thread_watcher_.isRunning()) {
1809 string format = to_utf8(cmd.argument());
1810 if (cmd.argument().empty())
1811 format = doc_buffer->params().getDefaultOutputFormat();
1812 enable = doc_buffer->params().isExportableFormat(format);
1816 case LFUN_BUFFER_RELOAD:
1817 enable = doc_buffer && !doc_buffer->isUnnamed()
1818 && doc_buffer->fileName().exists()
1819 && (!doc_buffer->isClean()
1820 || doc_buffer->isExternallyModified(Buffer::timestamp_method));
1823 case LFUN_BUFFER_CHILD_OPEN:
1824 enable = doc_buffer != 0;
1827 case LFUN_BUFFER_WRITE:
1828 enable = doc_buffer && (doc_buffer->isUnnamed() || !doc_buffer->isClean());
1831 //FIXME: This LFUN should be moved to GuiApplication.
1832 case LFUN_BUFFER_WRITE_ALL: {
1833 // We enable the command only if there are some modified buffers
1834 Buffer * first = theBufferList().first();
1839 // We cannot use a for loop as the buffer list is a cycle.
1841 if (!b->isClean()) {
1845 b = theBufferList().next(b);
1846 } while (b != first);
1850 case LFUN_BUFFER_WRITE_AS:
1851 case LFUN_BUFFER_EXPORT_AS:
1852 enable = doc_buffer != 0;
1855 case LFUN_BUFFER_CLOSE:
1856 case LFUN_VIEW_CLOSE:
1857 enable = doc_buffer != 0;
1860 case LFUN_BUFFER_CLOSE_ALL:
1861 enable = theBufferList().last() != theBufferList().first();
1864 case LFUN_VIEW_SPLIT:
1865 if (cmd.getArg(0) == "vertical")
1866 enable = doc_buffer && (d.splitter_->count() == 1 ||
1867 d.splitter_->orientation() == Qt::Vertical);
1869 enable = doc_buffer && (d.splitter_->count() == 1 ||
1870 d.splitter_->orientation() == Qt::Horizontal);
1873 case LFUN_TAB_GROUP_CLOSE:
1874 enable = d.tabWorkAreaCount() > 1;
1877 case LFUN_TOOLBAR_TOGGLE: {
1878 string const name = cmd.getArg(0);
1879 if (GuiToolbar * t = toolbar(name))
1880 flag.setOnOff(t->isVisible());
1883 docstring const msg =
1884 bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name));
1890 case LFUN_DROP_LAYOUTS_CHOICE:
1894 case LFUN_UI_TOGGLE:
1895 flag.setOnOff(isFullScreen());
1898 case LFUN_DIALOG_DISCONNECT_INSET:
1901 case LFUN_DIALOG_HIDE:
1902 // FIXME: should we check if the dialog is shown?
1905 case LFUN_DIALOG_TOGGLE:
1906 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1907 // fall through to set "enable"
1908 case LFUN_DIALOG_SHOW: {
1909 string const name = cmd.getArg(0);
1911 enable = name == "aboutlyx"
1912 || name == "file" //FIXME: should be removed.
1914 || name == "texinfo"
1915 || name == "progress"
1916 || name == "compare";
1917 else if (name == "character" || name == "symbols"
1918 || name == "mathdelimiter" || name == "mathmatrix") {
1919 if (!buf || buf->isReadonly())
1922 Cursor const & cur = currentBufferView()->cursor();
1923 enable = !(cur.inTexted() && cur.paragraph().isPassThru());
1926 else if (name == "latexlog")
1927 enable = FileName(doc_buffer->logName()).isReadableFile();
1928 else if (name == "spellchecker")
1929 enable = theSpellChecker()
1930 && !doc_buffer->isReadonly()
1931 && !doc_buffer->text().empty();
1932 else if (name == "vclog")
1933 enable = doc_buffer->lyxvc().inUse();
1937 case LFUN_DIALOG_UPDATE: {
1938 string const name = cmd.getArg(0);
1940 enable = name == "prefs";
1944 case LFUN_COMMAND_EXECUTE:
1946 case LFUN_MENU_OPEN:
1947 // Nothing to check.
1950 case LFUN_COMPLETION_INLINE:
1951 if (!d.current_work_area_
1952 || !d.current_work_area_->completer().inlinePossible(
1953 currentBufferView()->cursor()))
1957 case LFUN_COMPLETION_POPUP:
1958 if (!d.current_work_area_
1959 || !d.current_work_area_->completer().popupPossible(
1960 currentBufferView()->cursor()))
1965 if (!d.current_work_area_
1966 || !d.current_work_area_->completer().inlinePossible(
1967 currentBufferView()->cursor()))
1971 case LFUN_COMPLETION_ACCEPT:
1972 if (!d.current_work_area_
1973 || (!d.current_work_area_->completer().popupVisible()
1974 && !d.current_work_area_->completer().inlineVisible()
1975 && !d.current_work_area_->completer().completionAvailable()))
1979 case LFUN_COMPLETION_CANCEL:
1980 if (!d.current_work_area_
1981 || (!d.current_work_area_->completer().popupVisible()
1982 && !d.current_work_area_->completer().inlineVisible()))
1986 case LFUN_BUFFER_ZOOM_OUT:
1987 enable = doc_buffer && lyxrc.zoom > 10;
1990 case LFUN_BUFFER_ZOOM_IN:
1991 enable = doc_buffer != 0;
1994 case LFUN_BUFFER_MOVE_NEXT:
1995 case LFUN_BUFFER_MOVE_PREVIOUS:
1996 // we do not cycle when moving
1997 case LFUN_BUFFER_NEXT:
1998 case LFUN_BUFFER_PREVIOUS:
1999 // because we cycle, it doesn't matter whether on first or last
2000 enable = (d.currentTabWorkArea()->count() > 1);
2002 case LFUN_BUFFER_SWITCH:
2003 // toggle on the current buffer, but do not toggle off
2004 // the other ones (is that a good idea?)
2006 && to_utf8(cmd.argument()) == doc_buffer->absFileName())
2007 flag.setOnOff(true);
2010 case LFUN_VC_REGISTER:
2011 enable = doc_buffer && !doc_buffer->lyxvc().inUse();
2013 case LFUN_VC_RENAME:
2014 enable = doc_buffer && doc_buffer->lyxvc().renameEnabled();
2017 enable = doc_buffer && doc_buffer->lyxvc().copyEnabled();
2019 case LFUN_VC_CHECK_IN:
2020 enable = doc_buffer && doc_buffer->lyxvc().checkInEnabled();
2022 case LFUN_VC_CHECK_OUT:
2023 enable = doc_buffer && doc_buffer->lyxvc().checkOutEnabled();
2025 case LFUN_VC_LOCKING_TOGGLE:
2026 enable = doc_buffer && !doc_buffer->isReadonly()
2027 && doc_buffer->lyxvc().lockingToggleEnabled();
2028 flag.setOnOff(enable && doc_buffer->lyxvc().locking());
2030 case LFUN_VC_REVERT:
2031 enable = doc_buffer && doc_buffer->lyxvc().inUse() && !doc_buffer->isReadonly();
2033 case LFUN_VC_UNDO_LAST:
2034 enable = doc_buffer && doc_buffer->lyxvc().undoLastEnabled();
2036 case LFUN_VC_REPO_UPDATE:
2037 enable = doc_buffer && doc_buffer->lyxvc().repoUpdateEnabled();
2039 case LFUN_VC_COMMAND: {
2040 if (cmd.argument().empty())
2042 if (!doc_buffer && contains(cmd.getArg(0), 'D'))
2046 case LFUN_VC_COMPARE:
2047 enable = doc_buffer && doc_buffer->lyxvc().prepareFileRevisionEnabled();
2050 case LFUN_SERVER_GOTO_FILE_ROW:
2052 case LFUN_FORWARD_SEARCH:
2053 enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty());
2056 case LFUN_FILE_INSERT_PLAINTEXT:
2057 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
2058 enable = documentBufferView() && documentBufferView()->cursor().inTexted();
2061 case LFUN_SPELLING_CONTINUOUSLY:
2062 flag.setOnOff(lyxrc.spellcheck_continuously);
2070 flag.setEnabled(false);
2076 static FileName selectTemplateFile()
2078 FileDialog dlg(qt_("Select template file"));
2079 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2080 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2082 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
2083 QStringList(qt_("LyX Documents (*.lyx)")));
2085 if (result.first == FileDialog::Later)
2087 if (result.second.isEmpty())
2089 return FileName(fromqstr(result.second));
2093 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
2097 Buffer * newBuffer = 0;
2099 newBuffer = checkAndLoadLyXFile(filename);
2100 } catch (ExceptionMessage const & e) {
2107 message(_("Document not loaded."));
2111 setBuffer(newBuffer);
2112 newBuffer->errors("Parse");
2115 theSession().lastFiles().add(filename);
2121 void GuiView::openDocument(string const & fname)
2123 string initpath = lyxrc.document_path;
2125 if (documentBufferView()) {
2126 string const trypath = documentBufferView()->buffer().filePath();
2127 // If directory is writeable, use this as default.
2128 if (FileName(trypath).isDirWritable())
2134 if (fname.empty()) {
2135 FileDialog dlg(qt_("Select document to open"));
2136 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2137 dlg.setButton2(qt_("Examples|#E#e"),
2138 toqstr(addPath(package().system_support().absFileName(), "examples")));
2140 QStringList const filter(qt_("LyX Documents (*.lyx)"));
2141 FileDialog::Result result =
2142 dlg.open(toqstr(initpath), filter);
2144 if (result.first == FileDialog::Later)
2147 filename = fromqstr(result.second);
2149 // check selected filename
2150 if (filename.empty()) {
2151 message(_("Canceled."));
2157 // get absolute path of file and add ".lyx" to the filename if
2159 FileName const fullname =
2160 fileSearch(string(), filename, "lyx", support::may_not_exist);
2161 if (!fullname.empty())
2162 filename = fullname.absFileName();
2164 if (!fullname.onlyPath().isDirectory()) {
2165 Alert::warning(_("Invalid filename"),
2166 bformat(_("The directory in the given path\n%1$s\ndoes not exist."),
2167 from_utf8(fullname.absFileName())));
2171 // if the file doesn't exist and isn't already open (bug 6645),
2172 // let the user create one
2173 if (!fullname.exists() && !theBufferList().exists(fullname) &&
2174 !LyXVC::file_not_found_hook(fullname)) {
2175 // the user specifically chose this name. Believe him.
2176 Buffer * const b = newFile(filename, string(), true);
2182 docstring const disp_fn = makeDisplayPath(filename);
2183 message(bformat(_("Opening document %1$s..."), disp_fn));
2186 Buffer * buf = loadDocument(fullname);
2188 str2 = bformat(_("Document %1$s opened."), disp_fn);
2189 if (buf->lyxvc().inUse())
2190 str2 += " " + from_utf8(buf->lyxvc().versionString()) +
2191 " " + _("Version control detected.");
2193 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2198 // FIXME: clean that
2199 static bool import(GuiView * lv, FileName const & filename,
2200 string const & format, ErrorList & errorList)
2202 FileName const lyxfile(support::changeExtension(filename.absFileName(), ".lyx"));
2204 string loader_format;
2205 vector<string> loaders = theConverters().loaders();
2206 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
2207 vector<string>::const_iterator it = loaders.begin();
2208 vector<string>::const_iterator en = loaders.end();
2209 for (; it != en; ++it) {
2210 if (!theConverters().isReachable(format, *it))
2213 string const tofile =
2214 support::changeExtension(filename.absFileName(),
2215 formats.extension(*it));
2216 if (!theConverters().convert(0, filename, FileName(tofile),
2217 filename, format, *it, errorList))
2219 loader_format = *it;
2222 if (loader_format.empty()) {
2223 frontend::Alert::error(_("Couldn't import file"),
2224 bformat(_("No information for importing the format %1$s."),
2225 formats.prettyName(format)));
2229 loader_format = format;
2231 if (loader_format == "lyx") {
2232 Buffer * buf = lv->loadDocument(lyxfile);
2236 Buffer * const b = newFile(lyxfile.absFileName(), string(), true);
2240 bool as_paragraphs = loader_format == "textparagraph";
2241 string filename2 = (loader_format == format) ? filename.absFileName()
2242 : support::changeExtension(filename.absFileName(),
2243 formats.extension(loader_format));
2244 lv->currentBufferView()->insertPlaintextFile(FileName(filename2),
2246 guiApp->setCurrentView(lv);
2247 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
2254 void GuiView::importDocument(string const & argument)
2257 string filename = split(argument, format, ' ');
2259 LYXERR(Debug::INFO, format << " file: " << filename);
2261 // need user interaction
2262 if (filename.empty()) {
2263 string initpath = lyxrc.document_path;
2264 if (documentBufferView()) {
2265 string const trypath = documentBufferView()->buffer().filePath();
2266 // If directory is writeable, use this as default.
2267 if (FileName(trypath).isDirWritable())
2271 docstring const text = bformat(_("Select %1$s file to import"),
2272 formats.prettyName(format));
2274 FileDialog dlg(toqstr(text));
2275 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2276 dlg.setButton2(qt_("Examples|#E#e"),
2277 toqstr(addPath(package().system_support().absFileName(), "examples")));
2279 docstring filter = formats.prettyName(format);
2282 filter += from_utf8(formats.extensions(format));
2285 FileDialog::Result result =
2286 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
2288 if (result.first == FileDialog::Later)
2291 filename = fromqstr(result.second);
2293 // check selected filename
2294 if (filename.empty())
2295 message(_("Canceled."));
2298 if (filename.empty())
2301 // get absolute path of file
2302 FileName const fullname(support::makeAbsPath(filename));
2304 // Can happen if the user entered a path into the dialog
2306 if (fullname.onlyFileName().empty()) {
2307 docstring msg = bformat(_("The file name '%1$s' is invalid!\n"
2308 "Aborting import."),
2309 from_utf8(fullname.absFileName()));
2310 frontend::Alert::error(_("File name error"), msg);
2311 message(_("Canceled."));
2316 FileName const lyxfile(support::changeExtension(fullname.absFileName(), ".lyx"));
2318 // Check if the document already is open
2319 Buffer * buf = theBufferList().getBuffer(lyxfile);
2322 if (!closeBuffer()) {
2323 message(_("Canceled."));
2328 docstring const displaypath = makeDisplayPath(lyxfile.absFileName(), 30);
2330 // if the file exists already, and we didn't do
2331 // -i lyx thefile.lyx, warn
2332 if (lyxfile.exists() && fullname != lyxfile) {
2334 docstring text = bformat(_("The document %1$s already exists.\n\n"
2335 "Do you want to overwrite that document?"), displaypath);
2336 int const ret = Alert::prompt(_("Overwrite document?"),
2337 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2340 message(_("Canceled."));
2345 message(bformat(_("Importing %1$s..."), displaypath));
2346 ErrorList errorList;
2347 if (import(this, fullname, format, errorList))
2348 message(_("imported."));
2350 message(_("file not imported!"));
2352 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2356 void GuiView::newDocument(string const & filename, bool from_template)
2358 FileName initpath(lyxrc.document_path);
2359 if (documentBufferView()) {
2360 FileName const trypath(documentBufferView()->buffer().filePath());
2361 // If directory is writeable, use this as default.
2362 if (trypath.isDirWritable())
2366 string templatefile;
2367 if (from_template) {
2368 templatefile = selectTemplateFile().absFileName();
2369 if (templatefile.empty())
2374 if (filename.empty())
2375 b = newUnnamedFile(initpath, to_utf8(_("newfile")), templatefile);
2377 b = newFile(filename, templatefile, true);
2382 // If no new document could be created, it is unsure
2383 // whether there is a valid BufferView.
2384 if (currentBufferView())
2385 // Ensure the cursor is correctly positioned on screen.
2386 currentBufferView()->showCursor();
2390 void GuiView::insertLyXFile(docstring const & fname)
2392 BufferView * bv = documentBufferView();
2397 FileName filename(to_utf8(fname));
2398 if (filename.empty()) {
2399 // Launch a file browser
2401 string initpath = lyxrc.document_path;
2402 string const trypath = bv->buffer().filePath();
2403 // If directory is writeable, use this as default.
2404 if (FileName(trypath).isDirWritable())
2408 FileDialog dlg(qt_("Select LyX document to insert"));
2409 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2410 dlg.setButton2(qt_("Examples|#E#e"),
2411 toqstr(addPath(package().system_support().absFileName(),
2414 FileDialog::Result result = dlg.open(toqstr(initpath),
2415 QStringList(qt_("LyX Documents (*.lyx)")));
2417 if (result.first == FileDialog::Later)
2421 filename.set(fromqstr(result.second));
2423 // check selected filename
2424 if (filename.empty()) {
2425 // emit message signal.
2426 message(_("Canceled."));
2431 bv->insertLyXFile(filename);
2432 bv->buffer().errors("Parse");
2436 bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kind)
2438 FileName fname = b.fileName();
2439 FileName const oldname = fname;
2441 if (!newname.empty()) {
2443 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFileName());
2445 // Switch to this Buffer.
2448 // No argument? Ask user through dialog.
2450 FileDialog dlg(qt_("Choose a filename to save document as"));
2451 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2452 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2454 if (!isLyXFileName(fname.absFileName()))
2455 fname.changeExtension(".lyx");
2457 FileDialog::Result result =
2458 dlg.save(toqstr(fname.onlyPath().absFileName()),
2459 QStringList(qt_("LyX Documents (*.lyx)")),
2460 toqstr(fname.onlyFileName()));
2462 if (result.first == FileDialog::Later)
2465 fname.set(fromqstr(result.second));
2470 if (!isLyXFileName(fname.absFileName()))
2471 fname.changeExtension(".lyx");
2474 // fname is now the new Buffer location.
2476 // if there is already a Buffer open with this name, we do not want
2477 // to have another one. (the second test makes sure we're not just
2478 // trying to overwrite ourselves, which is fine.)
2479 if (theBufferList().exists(fname) && fname != oldname
2480 && theBufferList().getBuffer(fname) != &b) {
2481 docstring const text =
2482 bformat(_("The file\n%1$s\nis already open in your current session.\n"
2483 "Please close it before attempting to overwrite it.\n"
2484 "Do you want to choose a new filename?"),
2485 from_utf8(fname.absFileName()));
2486 int const ret = Alert::prompt(_("Chosen File Already Open"),
2487 text, 0, 1, _("&Rename"), _("&Cancel"));
2489 case 0: return renameBuffer(b, docstring(), kind);
2490 case 1: return false;
2495 bool const existsLocal = fname.exists();
2496 bool const existsInVC = LyXVC::fileInVC(fname);
2497 if (existsLocal || existsInVC) {
2498 docstring const file = makeDisplayPath(fname.absFileName(), 30);
2499 if (kind != LV_WRITE_AS && existsInVC) {
2500 // renaming to a name that is already in VC
2502 docstring text = bformat(_("The document %1$s "
2503 "is already registered.\n\n"
2504 "Do you want to choose a new name?"),
2506 docstring const title = (kind == LV_VC_RENAME) ?
2507 _("Rename document?") : _("Copy document?");
2508 docstring const button = (kind == LV_VC_RENAME) ?
2509 _("&Rename") : _("&Copy");
2510 int const ret = Alert::prompt(title, text, 0, 1,
2511 button, _("&Cancel"));
2513 case 0: return renameBuffer(b, docstring(), kind);
2514 case 1: return false;
2519 docstring text = bformat(_("The document %1$s "
2520 "already exists.\n\n"
2521 "Do you want to overwrite that document?"),
2523 int const ret = Alert::prompt(_("Overwrite document?"),
2524 text, 0, 2, _("&Overwrite"),
2525 _("&Rename"), _("&Cancel"));
2528 case 1: return renameBuffer(b, docstring(), kind);
2529 case 2: return false;
2535 case LV_VC_RENAME: {
2536 string msg = b.lyxvc().rename(fname);
2539 message(from_utf8(msg));
2543 string msg = b.lyxvc().copy(fname);
2546 message(from_utf8(msg));
2552 // LyXVC created the file already in case of LV_VC_RENAME or
2553 // LV_VC_COPY, but call saveBuffer() nevertheless to get
2554 // relative paths of included stuff right if we moved e.g. from
2555 // /a/b.lyx to /a/c/b.lyx.
2557 bool const saved = saveBuffer(b, fname);
2564 struct PrettyNameComparator
2566 bool operator()(Format const *first, Format const *second) const {
2567 return compare_no_case(translateIfPossible(from_ascii(first->prettyname())),
2568 translateIfPossible(from_ascii(second->prettyname()))) <= 0;
2573 bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
2575 FileName fname = b.fileName();
2577 FileDialog dlg(qt_("Choose a filename to export the document as"));
2578 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2581 QString const anyformat = qt_("Guess from extension (*.*)");
2583 Formats::const_iterator it = formats.begin();
2584 vector<Format const *> export_formats;
2585 for (; it != formats.end(); ++it)
2586 if (it->documentFormat())
2587 export_formats.push_back(&(*it));
2588 PrettyNameComparator cmp;
2589 sort(export_formats.begin(), export_formats.end(), cmp);
2590 vector<Format const *>::const_iterator fit = export_formats.begin();
2591 map<QString, string> fmap;
2594 for (; fit != export_formats.end(); ++fit) {
2595 docstring const loc_prettyname =
2596 translateIfPossible(from_utf8((*fit)->prettyname()));
2597 QString const loc_filter = toqstr(bformat(from_ascii("%1$s (*.%2$s)"),
2599 from_ascii((*fit)->extension())));
2600 types << loc_filter;
2601 fmap[loc_filter] = (*fit)->name();
2602 if (from_ascii((*fit)->name()) == iformat) {
2603 filter = loc_filter;
2604 ext = (*fit)->extension();
2607 string ofname = fname.onlyFileName();
2609 ofname = support::changeExtension(ofname, ext);
2610 FileDialog::Result result =
2611 dlg.save(toqstr(fname.onlyPath().absFileName()),
2615 if (result.first != FileDialog::Chosen)
2619 fname.set(fromqstr(result.second));
2620 if (filter == anyformat)
2621 fmt_name = formats.getFormatFromExtension(fname.extension());
2623 fmt_name = fmap[filter];
2624 LYXERR(Debug::FILES, "filter=" << fromqstr(filter)
2625 << ", fmt_name=" << fmt_name << ", fname=" << fname.absFileName());
2627 if (fmt_name.empty() || fname.empty())
2630 // fname is now the new Buffer location.
2631 if (FileName(fname).exists()) {
2632 docstring const file = makeDisplayPath(fname.absFileName(), 30);
2633 docstring text = bformat(_("The document %1$s already "
2634 "exists.\n\nDo you want to "
2635 "overwrite that document?"),
2637 int const ret = Alert::prompt(_("Overwrite document?"),
2638 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
2641 case 1: return exportBufferAs(b, from_ascii(fmt_name));
2642 case 2: return false;
2646 FuncRequest cmd(LFUN_BUFFER_EXPORT, fmt_name + " " + fname.absFileName());
2649 return dr.dispatched();
2653 bool GuiView::saveBuffer(Buffer & b)
2655 return saveBuffer(b, FileName());
2659 bool GuiView::saveBuffer(Buffer & b, FileName const & fn)
2661 if (workArea(b) && workArea(b)->inDialogMode())
2664 if (fn.empty() && b.isUnnamed())
2665 return renameBuffer(b, docstring());
2667 bool const success = (fn.empty() ? b.save() : b.saveAs(fn));
2669 theSession().lastFiles().add(b.fileName());
2673 // Switch to this Buffer.
2676 // FIXME: we don't tell the user *WHY* the save failed !!
2677 docstring const file = makeDisplayPath(b.absFileName(), 30);
2678 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
2679 "Do you want to rename the document and "
2680 "try again?"), file);
2681 int const ret = Alert::prompt(_("Rename and save?"),
2682 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
2685 if (!renameBuffer(b, docstring()))
2694 return saveBuffer(b, fn);
2698 bool GuiView::hideWorkArea(GuiWorkArea * wa)
2700 return closeWorkArea(wa, false);
2704 // We only want to close the buffer if it is not visible in other workareas
2705 // of the same view, nor in other views, and if this is not a child
2706 bool GuiView::closeWorkArea(GuiWorkArea * wa)
2708 Buffer & buf = wa->bufferView().buffer();
2710 bool last_wa = d.countWorkAreasOf(buf) == 1
2711 && !inOtherView(buf) && !buf.parent();
2713 bool close_buffer = last_wa;
2716 if (lyxrc.close_buffer_with_last_view == "yes")
2718 else if (lyxrc.close_buffer_with_last_view == "no")
2719 close_buffer = false;
2722 if (buf.isUnnamed())
2723 file = from_utf8(buf.fileName().onlyFileName());
2725 file = buf.fileName().displayName(30);
2726 docstring const text = bformat(
2727 _("Last view on document %1$s is being closed.\n"
2728 "Would you like to close or hide the document?\n"
2730 "Hidden documents can be displayed back through\n"
2731 "the menu: View->Hidden->...\n"
2733 "To remove this question, set your preference in:\n"
2734 " Tools->Preferences->Look&Feel->UserInterface\n"
2736 int ret = Alert::prompt(_("Close or hide document?"),
2737 text, 0, 1, _("&Close"), _("&Hide"));
2738 close_buffer = (ret == 0);
2742 return closeWorkArea(wa, close_buffer);
2746 bool GuiView::closeBuffer()
2748 GuiWorkArea * wa = currentMainWorkArea();
2749 setCurrentWorkArea(wa);
2750 Buffer & buf = wa->bufferView().buffer();
2751 return wa && closeWorkArea(wa, !buf.parent());
2755 void GuiView::writeSession() const {
2756 GuiWorkArea const * active_wa = currentMainWorkArea();
2757 for (int i = 0; i < d.splitter_->count(); ++i) {
2758 TabWorkArea * twa = d.tabWorkArea(i);
2759 for (int j = 0; j < twa->count(); ++j) {
2760 GuiWorkArea * wa = static_cast<GuiWorkArea *>(twa->widget(j));
2761 Buffer & buf = wa->bufferView().buffer();
2762 theSession().lastOpened().add(buf.fileName(), wa == active_wa);
2768 bool GuiView::closeBufferAll()
2770 // Close the workareas in all other views
2771 QList<int> const ids = guiApp->viewIds();
2772 for (int i = 0; i != ids.size(); ++i) {
2773 if (id_ != ids[i] && !guiApp->view(ids[i]).closeWorkAreaAll())
2777 // Close our own workareas
2778 if (!closeWorkAreaAll())
2781 // Now close the hidden buffers. We prevent hidden buffers from being
2782 // dirty, so we can just close them.
2783 theBufferList().closeAll();
2788 bool GuiView::closeWorkAreaAll()
2790 setCurrentWorkArea(currentMainWorkArea());
2792 // We might be in a situation that there is still a tabWorkArea, but
2793 // there are no tabs anymore. This can happen when we get here after a
2794 // TabWorkArea::lastWorkAreaRemoved() signal. Therefore we count how
2795 // many TabWorkArea's have no documents anymore.
2798 // We have to call count() each time, because it can happen that
2799 // more than one splitter will disappear in one iteration (bug 5998).
2800 while (d.splitter_->count() > empty_twa) {
2801 TabWorkArea * twa = d.tabWorkArea(empty_twa);
2803 if (twa->count() == 0)
2806 setCurrentWorkArea(twa->currentWorkArea());
2807 if (!closeTabWorkArea(twa))
2815 bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
2820 Buffer & buf = wa->bufferView().buffer();
2822 if (GuiViewPrivate::busyBuffers.contains(&buf)) {
2823 Alert::warning(_("Close document"),
2824 _("Document could not be closed because it is being processed by LyX."));
2829 return closeBuffer(buf);
2831 if (!inMultiTabs(wa))
2832 if (!saveBufferIfNeeded(buf, true))
2840 bool GuiView::closeBuffer(Buffer & buf)
2842 // If we are in a close_event all children will be closed in some time,
2843 // so no need to do it here. This will ensure that the children end up
2844 // in the session file in the correct order. If we close the master
2845 // buffer, we can close or release the child buffers here too.
2846 bool success = true;
2848 ListOfBuffers clist = buf.getChildren();
2849 ListOfBuffers::const_iterator it = clist.begin();
2850 ListOfBuffers::const_iterator const bend = clist.end();
2851 for (; it != bend; ++it) {
2852 // If a child is dirty, do not close
2853 // without user intervention
2854 //FIXME: should we look in other tabworkareas?
2855 Buffer * child_buf = *it;
2856 GuiWorkArea * child_wa = workArea(*child_buf);
2858 if (!closeWorkArea(child_wa, true)) {
2863 theBufferList().releaseChild(&buf, child_buf);
2867 // goto bookmark to update bookmark pit.
2868 //FIXME: we should update only the bookmarks related to this buffer!
2869 LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
2870 for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
2871 guiApp->gotoBookmark(i+1, false, false);
2873 if (saveBufferIfNeeded(buf, false)) {
2874 buf.removeAutosaveFile();
2875 theBufferList().release(&buf);
2879 // open all children again to avoid a crash because of dangling
2880 // pointers (bug 6603)
2886 bool GuiView::closeTabWorkArea(TabWorkArea * twa)
2888 while (twa == d.currentTabWorkArea()) {
2889 twa->setCurrentIndex(twa->count() - 1);
2891 GuiWorkArea * wa = twa->currentWorkArea();
2892 Buffer & b = wa->bufferView().buffer();
2894 // We only want to close the buffer if the same buffer is not visible
2895 // in another view, and if this is not a child and if we are closing
2896 // a view (not a tabgroup).
2897 bool const close_buffer =
2898 !inOtherView(b) && !b.parent() && closing_;
2900 if (!closeWorkArea(wa, close_buffer))
2907 bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding)
2909 if (buf.isClean() || buf.paragraphs().empty())
2912 // Switch to this Buffer.
2917 if (buf.isUnnamed())
2918 file = from_utf8(buf.fileName().onlyFileName());
2920 file = buf.fileName().displayName(30);
2922 // Bring this window to top before asking questions.
2927 if (hiding && buf.isUnnamed()) {
2928 docstring const text = bformat(_("The document %1$s has not been "
2929 "saved yet.\n\nDo you want to save "
2930 "the document?"), file);
2931 ret = Alert::prompt(_("Save new document?"),
2932 text, 0, 1, _("&Save"), _("&Cancel"));
2936 docstring const text = bformat(_("The document %1$s has unsaved changes."
2937 "\n\nDo you want to save the document or discard the changes?"), file);
2938 ret = Alert::prompt(_("Save changed document?"),
2939 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
2944 if (!saveBuffer(buf))
2948 // If we crash after this we could have no autosave file
2949 // but I guess this is really improbable (Jug).
2950 // Sometimes improbable things happen:
2951 // - see bug http://www.lyx.org/trac/ticket/6587 (ps)
2952 // buf.removeAutosaveFile();
2954 // revert all changes
2965 bool GuiView::inMultiTabs(GuiWorkArea * wa)
2967 Buffer & buf = wa->bufferView().buffer();
2969 for (int i = 0; i != d.splitter_->count(); ++i) {
2970 GuiWorkArea * wa_ = d.tabWorkArea(i)->workArea(buf);
2971 if (wa_ && wa_ != wa)
2974 return inOtherView(buf);
2978 bool GuiView::inOtherView(Buffer & buf)
2980 QList<int> const ids = guiApp->viewIds();
2982 for (int i = 0; i != ids.size(); ++i) {
2986 if (guiApp->view(ids[i]).workArea(buf))
2993 void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np, bool const move)
2995 if (!documentBufferView())
2998 if (TabWorkArea * twa = d.currentTabWorkArea()) {
2999 Buffer * const curbuf = &documentBufferView()->buffer();
3000 int nwa = twa->count();
3001 for (int i = 0; i < nwa; ++i) {
3002 if (&workArea(i)->bufferView().buffer() == curbuf) {
3004 if (np == NEXTBUFFER)
3005 next_index = (i == nwa - 1 ? 0 : i + 1);
3007 next_index = (i == 0 ? nwa - 1 : i - 1);
3009 twa->moveTab(i, next_index);
3011 setBuffer(&workArea(next_index)->bufferView().buffer());
3019 /// make sure the document is saved
3020 static bool ensureBufferClean(Buffer * buffer)
3022 LASSERT(buffer, return false);
3023 if (buffer->isClean() && !buffer->isUnnamed())
3026 docstring const file = buffer->fileName().displayName(30);
3029 if (!buffer->isUnnamed()) {
3030 text = bformat(_("The document %1$s has unsaved "
3031 "changes.\n\nDo you want to save "
3032 "the document?"), file);
3033 title = _("Save changed document?");
3036 text = bformat(_("The document %1$s has not been "
3037 "saved yet.\n\nDo you want to save "
3038 "the document?"), file);
3039 title = _("Save new document?");
3041 int const ret = Alert::prompt(title, text, 0, 1, _("&Save"), _("&Cancel"));
3044 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
3046 return buffer->isClean() && !buffer->isUnnamed();
3050 bool GuiView::reloadBuffer(Buffer & buf)
3052 Buffer::ReadStatus status = buf.reload();
3053 return status == Buffer::ReadSuccess;
3057 void GuiView::checkExternallyModifiedBuffers()
3059 BufferList::iterator bit = theBufferList().begin();
3060 BufferList::iterator const bend = theBufferList().end();
3061 for (; bit != bend; ++bit) {
3062 Buffer * buf = *bit;
3063 if (buf->fileName().exists()
3064 && buf->isExternallyModified(Buffer::checksum_method)) {
3065 docstring text = bformat(_("Document \n%1$s\n has been externally modified."
3066 " Reload now? Any local changes will be lost."),
3067 from_utf8(buf->absFileName()));
3068 int const ret = Alert::prompt(_("Reload externally changed document?"),
3069 text, 0, 1, _("&Reload"), _("&Cancel"));
3077 void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
3079 Buffer * buffer = documentBufferView()
3080 ? &(documentBufferView()->buffer()) : 0;
3082 switch (cmd.action()) {
3083 case LFUN_VC_REGISTER:
3084 if (!buffer || !ensureBufferClean(buffer))
3086 if (!buffer->lyxvc().inUse()) {
3087 if (buffer->lyxvc().registrer()) {
3088 reloadBuffer(*buffer);
3089 dr.clearMessageUpdate();
3094 case LFUN_VC_RENAME:
3095 case LFUN_VC_COPY: {
3096 if (!buffer || !ensureBufferClean(buffer))
3098 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
3099 if (buffer->lyxvc().isCheckInWithConfirmation()) {
3100 // Some changes are not yet committed.
3101 // We test here and not in getStatus(), since
3102 // this test is expensive.
3104 LyXVC::CommandResult ret =
3105 buffer->lyxvc().checkIn(log);
3107 if (ret == LyXVC::ErrorCommand ||
3108 ret == LyXVC::VCSuccess)
3109 reloadBuffer(*buffer);
3110 if (buffer->lyxvc().isCheckInWithConfirmation()) {
3111 frontend::Alert::error(
3112 _("Revision control error."),
3113 _("Document could not be checked in."));
3117 RenameKind const kind = (cmd.action() == LFUN_VC_RENAME) ?
3118 LV_VC_RENAME : LV_VC_COPY;
3119 renameBuffer(*buffer, cmd.argument(), kind);
3124 case LFUN_VC_CHECK_IN:
3125 if (!buffer || !ensureBufferClean(buffer))
3127 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
3129 LyXVC::CommandResult ret = buffer->lyxvc().checkIn(log);
3131 // Only skip reloading if the checkin was cancelled or
3132 // an error occurred before the real checkin VCS command
3133 // was executed, since the VCS might have changed the
3134 // file even if it could not checkin successfully.
3135 if (ret == LyXVC::ErrorCommand || ret == LyXVC::VCSuccess)
3136 reloadBuffer(*buffer);
3140 case LFUN_VC_CHECK_OUT:
3141 if (!buffer || !ensureBufferClean(buffer))
3143 if (buffer->lyxvc().inUse()) {
3144 dr.setMessage(buffer->lyxvc().checkOut());
3145 reloadBuffer(*buffer);
3149 case LFUN_VC_LOCKING_TOGGLE:
3150 LASSERT(buffer, return);
3151 if (!ensureBufferClean(buffer) || buffer->isReadonly())
3153 if (buffer->lyxvc().inUse()) {
3154 string res = buffer->lyxvc().lockingToggle();
3156 frontend::Alert::error(_("Revision control error."),
3157 _("Error when setting the locking property."));
3160 reloadBuffer(*buffer);
3165 case LFUN_VC_REVERT:
3166 LASSERT(buffer, return);
3167 if (buffer->lyxvc().revert()) {
3168 reloadBuffer(*buffer);
3169 dr.clearMessageUpdate();
3173 case LFUN_VC_UNDO_LAST:
3174 LASSERT(buffer, return);
3175 buffer->lyxvc().undoLast();
3176 reloadBuffer(*buffer);
3177 dr.clearMessageUpdate();
3180 case LFUN_VC_REPO_UPDATE:
3181 LASSERT(buffer, return);
3182 if (ensureBufferClean(buffer)) {
3183 dr.setMessage(buffer->lyxvc().repoUpdate());
3184 checkExternallyModifiedBuffers();
3188 case LFUN_VC_COMMAND: {
3189 string flag = cmd.getArg(0);
3190 if (buffer && contains(flag, 'R') && !ensureBufferClean(buffer))
3193 if (contains(flag, 'M')) {
3194 if (!Alert::askForText(message, _("LyX VC: Log Message")))
3197 string path = cmd.getArg(1);
3198 if (contains(path, "$$p") && buffer)
3199 path = subst(path, "$$p", buffer->filePath());
3200 LYXERR(Debug::LYXVC, "Directory: " << path);
3202 if (!pp.isReadableDirectory()) {
3203 lyxerr << _("Directory is not accessible.") << endl;
3206 support::PathChanger p(pp);
3208 string command = cmd.getArg(2);
3209 if (command.empty())
3212 command = subst(command, "$$i", buffer->absFileName());
3213 command = subst(command, "$$p", buffer->filePath());
3215 command = subst(command, "$$m", to_utf8(message));
3216 LYXERR(Debug::LYXVC, "Command: " << command);
3218 one.startscript(Systemcall::Wait, command);
3222 if (contains(flag, 'I'))
3223 buffer->markDirty();
3224 if (contains(flag, 'R'))
3225 reloadBuffer(*buffer);
3230 case LFUN_VC_COMPARE: {
3232 if (cmd.argument().empty()) {
3233 lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "comparehistory"));
3237 string rev1 = cmd.getArg(0);
3241 if (!buffer->lyxvc().prepareFileRevision(rev1, f1))
3244 if (isStrInt(rev1) && convert<int>(rev1) <= 0) {
3245 f2 = buffer->absFileName();
3247 string rev2 = cmd.getArg(1);
3251 if (!buffer->lyxvc().prepareFileRevision(rev2, f2))
3255 LYXERR(Debug::LYXVC, "Launching comparison for fetched revisions:\n" <<
3256 f1 << "\n" << f2 << "\n" );
3257 string par = "compare run " + quoteName(f1) + " " + quoteName(f2);
3258 lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, par));
3268 void GuiView::openChildDocument(string const & fname)
3270 LASSERT(documentBufferView(), return);
3271 Buffer & buffer = documentBufferView()->buffer();
3272 FileName const filename = support::makeAbsPath(fname, buffer.filePath());
3273 documentBufferView()->saveBookmark(false);
3275 if (theBufferList().exists(filename)) {
3276 child = theBufferList().getBuffer(filename);
3279 message(bformat(_("Opening child document %1$s..."),
3280 makeDisplayPath(filename.absFileName())));
3281 child = loadDocument(filename, false);
3283 // Set the parent name of the child document.
3284 // This makes insertion of citations and references in the child work,
3285 // when the target is in the parent or another child document.
3287 child->setParent(&buffer);
3291 bool GuiView::goToFileRow(string const & argument)
3295 size_t i = argument.find_last_of(' ');
3296 if (i != string::npos) {
3297 file_name = os::internal_path(trim(argument.substr(0, i)));
3298 istringstream is(argument.substr(i + 1));
3303 if (i == string::npos) {
3304 LYXERR0("Wrong argument: " << argument);
3308 string const abstmp = package().temp_dir().absFileName();
3309 string const realtmp = package().temp_dir().realPath();
3310 // We have to use os::path_prefix_is() here, instead of
3311 // simply prefixIs(), because the file name comes from
3312 // an external application and may need case adjustment.
3313 if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
3314 || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
3315 // Needed by inverse dvi search. If it is a file
3316 // in tmpdir, call the apropriated function.
3317 // If tmpdir is a symlink, we may have the real
3318 // path passed back, so we correct for that.
3319 if (!prefixIs(file_name, abstmp))
3320 file_name = subst(file_name, realtmp, abstmp);
3321 buf = theBufferList().getBufferFromTmp(file_name);
3323 // Must replace extension of the file to be .lyx
3324 // and get full path
3325 FileName const s = fileSearch(string(),
3326 support::changeExtension(file_name, ".lyx"), "lyx");
3327 // Either change buffer or load the file
3328 if (theBufferList().exists(s))
3329 buf = theBufferList().getBuffer(s);
3330 else if (s.exists()) {
3331 buf = loadDocument(s);
3336 _("File does not exist: %1$s"),
3337 makeDisplayPath(file_name)));
3343 _("No buffer for file: %1$s."),
3344 makeDisplayPath(file_name))
3349 documentBufferView()->setCursorFromRow(row);
3355 Buffer::ExportStatus GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * clone, string const & format)
3357 Buffer::ExportStatus const status = func(format);
3359 // the cloning operation will have produced a clone of the entire set of
3360 // documents, starting from the master. so we must delete those.
3361 Buffer * mbuf = const_cast<Buffer *>(clone->masterBuffer());
3363 busyBuffers.remove(orig);
3368 Buffer::ExportStatus GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3370 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
3371 return runAndDestroy(lyx::bind(mem_func, clone, _1, true), orig, clone, format);
3375 Buffer::ExportStatus GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3377 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
3378 return runAndDestroy(lyx::bind(mem_func, clone, _1, false), orig, clone, format);
3382 Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3384 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &) const = &Buffer::preview;
3385 return runAndDestroy(lyx::bind(mem_func, clone, _1), orig, clone, format);
3389 bool GuiView::GuiViewPrivate::asyncBufferProcessing(
3390 string const & argument,
3391 Buffer const * used_buffer,
3392 docstring const & msg,
3393 Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
3394 Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
3395 Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const)
3400 string format = argument;
3402 format = used_buffer->params().getDefaultOutputFormat();
3403 processing_format = format;
3405 progress_->clearMessages();
3408 #if EXPORT_in_THREAD
3409 GuiViewPrivate::busyBuffers.insert(used_buffer);
3410 Buffer * cloned_buffer = used_buffer->cloneFromMaster();
3411 if (!cloned_buffer) {
3412 Alert::error(_("Export Error"),
3413 _("Error cloning the Buffer."));
3416 QFuture<Buffer::ExportStatus> f = QtConcurrent::run(
3421 setPreviewFuture(f);
3422 last_export_format = used_buffer->params().bufferFormat();
3425 // We are asynchronous, so we don't know here anything about the success
3428 Buffer::ExportStatus status;
3430 // TODO check here if it breaks exporting with Qt < 4.4
3431 status = (used_buffer->*syncFunc)(format, true);
3432 } else if (previewFunc) {
3433 status = (used_buffer->*previewFunc)(format);
3436 handleExportStatus(gv_, status, format);
3438 return (status == Buffer::ExportSuccess
3439 || status == Buffer::PreviewSuccess);
3443 void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr)
3445 BufferView * bv = currentBufferView();
3446 LASSERT(bv, return);
3448 // Let the current BufferView dispatch its own actions.
3449 bv->dispatch(cmd, dr);
3450 if (dr.dispatched())
3453 // Try with the document BufferView dispatch if any.
3454 BufferView * doc_bv = documentBufferView();
3455 if (doc_bv && doc_bv != bv) {
3456 doc_bv->dispatch(cmd, dr);
3457 if (dr.dispatched())
3461 // Then let the current Cursor dispatch its own actions.
3462 bv->cursor().dispatch(cmd);
3464 // update completion. We do it here and not in
3465 // processKeySym to avoid another redraw just for a
3466 // changed inline completion
3467 if (cmd.origin() == FuncRequest::KEYBOARD) {
3468 if (cmd.action() == LFUN_SELF_INSERT
3469 || (cmd.action() == LFUN_ERT_INSERT && bv->cursor().inMathed()))
3470 updateCompletion(bv->cursor(), true, true);
3471 else if (cmd.action() == LFUN_CHAR_DELETE_BACKWARD)
3472 updateCompletion(bv->cursor(), false, true);
3474 updateCompletion(bv->cursor(), false, false);
3477 dr = bv->cursor().result();
3481 void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
3483 BufferView * bv = currentBufferView();
3484 // By default we won't need any update.
3485 dr.screenUpdate(Update::None);
3486 // assume cmd will be dispatched
3487 dr.dispatched(true);
3489 Buffer * doc_buffer = documentBufferView()
3490 ? &(documentBufferView()->buffer()) : 0;
3492 if (cmd.origin() == FuncRequest::TOC) {
3493 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
3494 // FIXME: do we need to pass a DispatchResult object here?
3495 toc->doDispatch(bv->cursor(), cmd);
3499 string const argument = to_utf8(cmd.argument());
3501 switch(cmd.action()) {
3502 case LFUN_BUFFER_CHILD_OPEN:
3503 openChildDocument(to_utf8(cmd.argument()));
3506 case LFUN_BUFFER_IMPORT:
3507 importDocument(to_utf8(cmd.argument()));
3510 case LFUN_BUFFER_EXPORT: {
3513 FileName target_dir = doc_buffer->fileName().onlyPath();
3514 string const dest = cmd.getArg(1);
3515 if (!dest.empty() && FileName::isAbsolute(dest))
3516 target_dir = FileName(support::onlyPath(dest));
3517 // GCC only sees strfwd.h when building merged
3518 if (::lyx::operator==(cmd.argument(), "custom")) {
3519 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
3522 if (!target_dir.isDirWritable()) {
3523 exportBufferAs(*doc_buffer, cmd.argument());
3526 /* TODO/Review: Is it a problem to also export the children?
3527 See the update_unincluded flag */
3528 d.asyncBufferProcessing(argument,
3531 &GuiViewPrivate::exportAndDestroy,
3534 // TODO Inform user about success
3538 case LFUN_BUFFER_EXPORT_AS: {
3539 LASSERT(doc_buffer, break);
3540 docstring f = cmd.argument();
3542 f = from_ascii(doc_buffer->params().getDefaultOutputFormat());
3543 exportBufferAs(*doc_buffer, f);
3547 case LFUN_BUFFER_UPDATE: {
3548 d.asyncBufferProcessing(argument,
3551 &GuiViewPrivate::compileAndDestroy,
3556 case LFUN_BUFFER_VIEW: {
3557 d.asyncBufferProcessing(argument,
3559 _("Previewing ..."),
3560 &GuiViewPrivate::previewAndDestroy,
3565 case LFUN_MASTER_BUFFER_UPDATE: {
3566 d.asyncBufferProcessing(argument,
3567 (doc_buffer ? doc_buffer->masterBuffer() : 0),
3569 &GuiViewPrivate::compileAndDestroy,
3574 case LFUN_MASTER_BUFFER_VIEW: {
3575 d.asyncBufferProcessing(argument,
3576 (doc_buffer ? doc_buffer->masterBuffer() : 0),
3578 &GuiViewPrivate::previewAndDestroy,
3579 0, &Buffer::preview);
3582 case LFUN_BUFFER_SWITCH: {
3583 string const file_name = to_utf8(cmd.argument());
3584 if (!FileName::isAbsolute(file_name)) {
3586 dr.setMessage(_("Absolute filename expected."));
3590 Buffer * buffer = theBufferList().getBuffer(FileName(file_name));
3593 dr.setMessage(_("Document not loaded"));
3597 // Do we open or switch to the buffer in this view ?
3598 if (workArea(*buffer)
3599 || lyxrc.open_buffers_in_tabs || !documentBufferView()) {
3604 // Look for the buffer in other views
3605 QList<int> const ids = guiApp->viewIds();
3607 for (; i != ids.size(); ++i) {
3608 GuiView & gv = guiApp->view(ids[i]);
3609 if (gv.workArea(*buffer)) {
3610 gv.activateWindow();
3611 gv.setBuffer(buffer);
3616 // If necessary, open a new window as a last resort
3617 if (i == ids.size()) {
3618 lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW));
3624 case LFUN_BUFFER_NEXT:
3625 gotoNextOrPreviousBuffer(NEXTBUFFER, false);
3628 case LFUN_BUFFER_MOVE_NEXT:
3629 gotoNextOrPreviousBuffer(NEXTBUFFER, true);
3632 case LFUN_BUFFER_PREVIOUS:
3633 gotoNextOrPreviousBuffer(PREVBUFFER, false);
3636 case LFUN_BUFFER_MOVE_PREVIOUS:
3637 gotoNextOrPreviousBuffer(PREVBUFFER, true);
3640 case LFUN_COMMAND_EXECUTE: {
3641 command_execute_ = true;
3644 case LFUN_DROP_LAYOUTS_CHOICE:
3645 d.layout_->showPopup();
3648 case LFUN_MENU_OPEN:
3649 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
3650 menu->exec(QCursor::pos());
3653 case LFUN_FILE_INSERT:
3654 insertLyXFile(cmd.argument());
3657 case LFUN_FILE_INSERT_PLAINTEXT:
3658 case LFUN_FILE_INSERT_PLAINTEXT_PARA: {
3659 string const fname = to_utf8(cmd.argument());
3660 if (!fname.empty() && !FileName::isAbsolute(fname)) {
3661 dr.setMessage(_("Absolute filename expected."));
3665 FileName filename(fname);
3666 if (fname.empty()) {
3667 FileDialog dlg(qt_("Select file to insert"));
3669 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
3670 QStringList(qt_("All Files (*)")));
3672 if (result.first == FileDialog::Later || result.second.isEmpty()) {
3673 dr.setMessage(_("Canceled."));
3677 filename.set(fromqstr(result.second));
3681 FuncRequest const new_cmd(cmd, filename.absoluteFilePath());
3682 bv->dispatch(new_cmd, dr);
3687 case LFUN_BUFFER_RELOAD: {
3688 LASSERT(doc_buffer, break);
3691 if (!doc_buffer->isClean()) {
3692 docstring const file =
3693 makeDisplayPath(doc_buffer->absFileName(), 20);
3694 docstring text = bformat(_("Any changes will be lost. "
3695 "Are you sure you want to revert to the saved version "
3696 "of the document %1$s?"), file);
3697 ret = Alert::prompt(_("Revert to saved document?"),
3698 text, 1, 1, _("&Revert"), _("&Cancel"));
3702 doc_buffer->markClean();
3703 reloadBuffer(*doc_buffer);
3704 dr.forceBufferUpdate();
3709 case LFUN_BUFFER_WRITE:
3710 LASSERT(doc_buffer, break);
3711 saveBuffer(*doc_buffer);
3714 case LFUN_BUFFER_WRITE_AS:
3715 LASSERT(doc_buffer, break);
3716 renameBuffer(*doc_buffer, cmd.argument());
3719 case LFUN_BUFFER_WRITE_ALL: {
3720 Buffer * first = theBufferList().first();
3723 message(_("Saving all documents..."));
3724 // We cannot use a for loop as the buffer list cycles.
3727 if (!b->isClean()) {
3729 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
3731 b = theBufferList().next(b);
3732 } while (b != first);
3733 dr.setMessage(_("All documents saved."));
3737 case LFUN_BUFFER_CLOSE:
3741 case LFUN_BUFFER_CLOSE_ALL:
3745 case LFUN_TOOLBAR_TOGGLE: {
3746 string const name = cmd.getArg(0);
3747 if (GuiToolbar * t = toolbar(name))
3752 case LFUN_DIALOG_UPDATE: {
3753 string const name = to_utf8(cmd.argument());
3754 if (name == "prefs" || name == "document")
3755 updateDialog(name, string());
3756 else if (name == "paragraph")
3757 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
3758 else if (currentBufferView()) {
3759 Inset * inset = currentBufferView()->editedInset(name);
3760 // Can only update a dialog connected to an existing inset
3762 // FIXME: get rid of this indirection; GuiView ask the inset
3763 // if he is kind enough to update itself...
3764 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
3765 //FIXME: pass DispatchResult here?
3766 inset->dispatch(currentBufferView()->cursor(), fr);
3772 case LFUN_DIALOG_TOGGLE: {
3773 FuncCode const func_code = isDialogVisible(cmd.getArg(0))
3774 ? LFUN_DIALOG_HIDE : LFUN_DIALOG_SHOW;
3775 dispatch(FuncRequest(func_code, cmd.argument()), dr);
3779 case LFUN_DIALOG_DISCONNECT_INSET:
3780 disconnectDialog(to_utf8(cmd.argument()));
3783 case LFUN_DIALOG_HIDE: {
3784 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
3788 case LFUN_DIALOG_SHOW: {
3789 string const name = cmd.getArg(0);
3790 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
3792 if (name == "character") {
3793 data = freefont2string();
3795 showDialog("character", data);
3796 } else if (name == "latexlog") {
3797 Buffer::LogType type;
3798 string const logfile = doc_buffer->logName(&type);
3800 case Buffer::latexlog:
3803 case Buffer::buildlog:
3807 data += Lexer::quoteString(logfile);
3808 showDialog("log", data);
3809 } else if (name == "vclog") {
3810 string const data = "vc " +
3811 Lexer::quoteString(doc_buffer->lyxvc().getLogFile());
3812 showDialog("log", data);
3813 } else if (name == "symbols") {
3814 data = bv->cursor().getEncoding()->name();
3816 showDialog("symbols", data);
3818 } else if (name == "prefs" && isFullScreen()) {
3819 lfunUiToggle("fullscreen");
3820 showDialog("prefs", data);
3822 showDialog(name, data);
3827 dr.setMessage(cmd.argument());
3830 case LFUN_UI_TOGGLE: {
3831 string arg = cmd.getArg(0);
3832 if (!lfunUiToggle(arg)) {
3833 docstring const msg = "ui-toggle " + _("%1$s unknown command!");
3834 dr.setMessage(bformat(msg, from_utf8(arg)));
3836 // Make sure the keyboard focus stays in the work area.
3841 case LFUN_VIEW_SPLIT: {
3842 LASSERT(doc_buffer, break);
3843 string const orientation = cmd.getArg(0);
3844 d.splitter_->setOrientation(orientation == "vertical"
3845 ? Qt::Vertical : Qt::Horizontal);
3846 TabWorkArea * twa = addTabWorkArea();
3847 GuiWorkArea * wa = twa->addWorkArea(*doc_buffer, *this);
3848 setCurrentWorkArea(wa);
3851 case LFUN_TAB_GROUP_CLOSE:
3852 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3853 closeTabWorkArea(twa);
3854 d.current_work_area_ = 0;
3855 twa = d.currentTabWorkArea();
3856 // Switch to the next GuiWorkArea in the found TabWorkArea.
3858 // Make sure the work area is up to date.
3859 setCurrentWorkArea(twa->currentWorkArea());
3861 setCurrentWorkArea(0);
3866 case LFUN_VIEW_CLOSE:
3867 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3868 closeWorkArea(twa->currentWorkArea());
3869 d.current_work_area_ = 0;
3870 twa = d.currentTabWorkArea();
3871 // Switch to the next GuiWorkArea in the found TabWorkArea.
3873 // Make sure the work area is up to date.
3874 setCurrentWorkArea(twa->currentWorkArea());
3876 setCurrentWorkArea(0);
3881 case LFUN_COMPLETION_INLINE:
3882 if (d.current_work_area_)
3883 d.current_work_area_->completer().showInline();
3886 case LFUN_COMPLETION_POPUP:
3887 if (d.current_work_area_)
3888 d.current_work_area_->completer().showPopup();
3893 if (d.current_work_area_)
3894 d.current_work_area_->completer().tab();
3897 case LFUN_COMPLETION_CANCEL:
3898 if (d.current_work_area_) {
3899 if (d.current_work_area_->completer().popupVisible())
3900 d.current_work_area_->completer().hidePopup();
3902 d.current_work_area_->completer().hideInline();
3906 case LFUN_COMPLETION_ACCEPT:
3907 if (d.current_work_area_)
3908 d.current_work_area_->completer().activate();
3911 case LFUN_BUFFER_ZOOM_IN:
3912 case LFUN_BUFFER_ZOOM_OUT:
3913 if (cmd.argument().empty()) {
3914 if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
3919 lyxrc.zoom += convert<int>(cmd.argument());
3921 if (lyxrc.zoom < 10)
3924 // The global QPixmapCache is used in GuiPainter to cache text
3925 // painting so we must reset it.
3926 QPixmapCache::clear();
3927 guiApp->fontLoader().update();
3928 lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
3931 case LFUN_VC_REGISTER:
3932 case LFUN_VC_RENAME:
3934 case LFUN_VC_CHECK_IN:
3935 case LFUN_VC_CHECK_OUT:
3936 case LFUN_VC_REPO_UPDATE:
3937 case LFUN_VC_LOCKING_TOGGLE:
3938 case LFUN_VC_REVERT:
3939 case LFUN_VC_UNDO_LAST:
3940 case LFUN_VC_COMMAND:
3941 case LFUN_VC_COMPARE:
3942 dispatchVC(cmd, dr);
3945 case LFUN_SERVER_GOTO_FILE_ROW:
3946 goToFileRow(to_utf8(cmd.argument()));
3949 case LFUN_FORWARD_SEARCH: {
3950 Buffer const * doc_master = doc_buffer->masterBuffer();
3951 FileName const path(doc_master->temppath());
3952 string const texname = doc_master->isChild(doc_buffer)
3953 ? DocFileName(changeExtension(
3954 doc_buffer->absFileName(),
3955 "tex")).mangledFileName()
3956 : doc_buffer->latexName();
3957 string const fulltexname =
3958 support::makeAbsPath(texname, doc_master->temppath()).absFileName();
3959 string const mastername =
3960 removeExtension(doc_master->latexName());
3961 FileName const dviname(addName(path.absFileName(),
3962 addExtension(mastername, "dvi")));
3963 FileName const pdfname(addName(path.absFileName(),
3964 addExtension(mastername, "pdf")));
3965 bool const have_dvi = dviname.exists();
3966 bool const have_pdf = pdfname.exists();
3967 if (!have_dvi && !have_pdf) {
3968 dr.setMessage(_("Please, preview the document first."));
3971 string outname = dviname.onlyFileName();
3972 string command = lyxrc.forward_search_dvi;
3973 if (!have_dvi || (have_pdf &&
3974 pdfname.lastModified() > dviname.lastModified())) {
3975 outname = pdfname.onlyFileName();
3976 command = lyxrc.forward_search_pdf;
3979 DocIterator cur = bv->cursor();
3980 int row = doc_buffer->texrow().rowFromDocIterator(cur).first;
3981 LYXERR(Debug::ACTION, "Forward search: row:" << row
3983 if (row == -1 || command.empty()) {
3984 dr.setMessage(_("Couldn't proceed."));
3987 string texrow = convert<string>(row);
3989 command = subst(command, "$$n", texrow);
3990 command = subst(command, "$$f", fulltexname);
3991 command = subst(command, "$$t", texname);
3992 command = subst(command, "$$o", outname);
3994 PathChanger p(path);
3996 one.startscript(Systemcall::DontWait, command);
4000 case LFUN_SPELLING_CONTINUOUSLY:
4001 lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously;
4002 dr.screenUpdate(Update::Force | Update::FitCursor);
4006 // The LFUN must be for one of BufferView, Buffer or Cursor;
4008 dispatchToBufferView(cmd, dr);
4012 // Part of automatic menu appearance feature.
4013 if (isFullScreen()) {
4014 if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
4018 // Need to update bv because many LFUNs here might have destroyed it
4019 bv = currentBufferView();
4021 // Clear non-empty selections
4022 // (e.g. from a "char-forward-select" followed by "char-backward-select")
4024 Cursor & cur = bv->cursor();
4025 if ((cur.selection() && cur.selBegin() == cur.selEnd())) {
4026 cur.clearSelection();
4032 bool GuiView::lfunUiToggle(string const & ui_component)
4034 if (ui_component == "scrollbar") {
4035 // hide() is of no help
4036 if (d.current_work_area_->verticalScrollBarPolicy() ==
4037 Qt::ScrollBarAlwaysOff)
4039 d.current_work_area_->setVerticalScrollBarPolicy(
4040 Qt::ScrollBarAsNeeded);
4042 d.current_work_area_->setVerticalScrollBarPolicy(
4043 Qt::ScrollBarAlwaysOff);
4044 } else if (ui_component == "statusbar") {
4045 statusBar()->setVisible(!statusBar()->isVisible());
4046 } else if (ui_component == "menubar") {
4047 menuBar()->setVisible(!menuBar()->isVisible());
4049 if (ui_component == "frame") {
4051 getContentsMargins(&l, &t, &r, &b);
4052 //are the frames in default state?
4053 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
4055 setContentsMargins(-2, -2, -2, -2);
4057 setContentsMargins(0, 0, 0, 0);
4060 if (ui_component == "fullscreen") {
4068 void GuiView::toggleFullScreen()
4070 if (isFullScreen()) {
4071 for (int i = 0; i != d.splitter_->count(); ++i)
4072 d.tabWorkArea(i)->setFullScreen(false);
4073 setContentsMargins(0, 0, 0, 0);
4074 setWindowState(windowState() ^ Qt::WindowFullScreen);
4077 statusBar()->show();
4080 hideDialogs("prefs", 0);
4081 for (int i = 0; i != d.splitter_->count(); ++i)
4082 d.tabWorkArea(i)->setFullScreen(true);
4083 setContentsMargins(-2, -2, -2, -2);
4085 setWindowState(windowState() ^ Qt::WindowFullScreen);
4086 if (lyxrc.full_screen_statusbar)
4087 statusBar()->hide();
4088 if (lyxrc.full_screen_menubar)
4090 if (lyxrc.full_screen_toolbars) {
4091 ToolbarMap::iterator end = d.toolbars_.end();
4092 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
4097 // give dialogs like the TOC a chance to adapt
4102 Buffer const * GuiView::updateInset(Inset const * inset)
4107 Buffer const * inset_buffer = &(inset->buffer());
4109 for (int i = 0; i != d.splitter_->count(); ++i) {
4110 GuiWorkArea * wa = d.tabWorkArea(i)->currentWorkArea();
4113 Buffer const * buffer = &(wa->bufferView().buffer());
4114 if (inset_buffer == buffer)
4115 wa->scheduleRedraw();
4117 return inset_buffer;
4121 void GuiView::restartCursor()
4123 /* When we move around, or type, it's nice to be able to see
4124 * the cursor immediately after the keypress.
4126 if (d.current_work_area_)
4127 d.current_work_area_->startBlinkingCursor();
4129 // Take this occasion to update the other GUI elements.
4135 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
4137 if (d.current_work_area_)
4138 d.current_work_area_->completer().updateVisibility(cur, start, keep);
4143 // This list should be kept in sync with the list of insets in
4144 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
4145 // dialog should have the same name as the inset.
4146 // Changes should be also recorded in LFUN_DIALOG_SHOW doxygen
4147 // docs in LyXAction.cpp.
4149 char const * const dialognames[] = {
4151 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
4152 "citation", "compare", "comparehistory", "document", "errorlist", "ert",
4153 "external", "file", "findreplace", "findreplaceadv", "float", "graphics",
4154 "href", "include", "index", "index_print", "info", "listings", "label", "line",
4155 "log", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
4156 "nomencl_print", "note", "paragraph", "phantom", "prefs", "ref",
4157 "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
4158 "thesaurus", "texinfo", "toc", "view-source", "vspace", "wrap", "progress"};
4160 char const * const * const end_dialognames =
4161 dialognames + (sizeof(dialognames) / sizeof(char *));
4165 cmpCStr(char const * name) : name_(name) {}
4166 bool operator()(char const * other) {
4167 return strcmp(other, name_) == 0;
4174 bool isValidName(string const & name)
4176 return find_if(dialognames, end_dialognames,
4177 cmpCStr(name.c_str())) != end_dialognames;
4183 void GuiView::resetDialogs()
4185 // Make sure that no LFUN uses any GuiView.
4186 guiApp->setCurrentView(0);
4190 constructToolbars();
4191 guiApp->menus().fillMenuBar(menuBar(), this, false);
4192 d.layout_->updateContents(true);
4193 // Now update controls with current buffer.
4194 guiApp->setCurrentView(this);
4200 Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
4202 if (!isValidName(name))
4205 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
4207 if (it != d.dialogs_.end()) {
4209 it->second->hideView();
4210 return it->second.get();
4213 Dialog * dialog = build(name);
4214 d.dialogs_[name].reset(dialog);
4215 if (lyxrc.allow_geometry_session)
4216 dialog->restoreSession();
4223 void GuiView::showDialog(string const & name, string const & data,
4226 triggerShowDialog(toqstr(name), toqstr(data), inset);
4230 void GuiView::doShowDialog(QString const & qname, QString const & qdata,
4236 const string name = fromqstr(qname);
4237 const string data = fromqstr(qdata);
4241 Dialog * dialog = findOrBuild(name, false);
4243 bool const visible = dialog->isVisibleView();
4244 dialog->showData(data);
4245 if (inset && currentBufferView())
4246 currentBufferView()->editInset(name, inset);
4247 // We only set the focus to the new dialog if it was not yet
4248 // visible in order not to change the existing previous behaviour
4250 // activateWindow is needed for floating dockviews
4251 dialog->asQWidget()->raise();
4252 dialog->asQWidget()->activateWindow();
4253 dialog->asQWidget()->setFocus();
4257 catch (ExceptionMessage const & ex) {
4265 bool GuiView::isDialogVisible(string const & name) const
4267 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
4268 if (it == d.dialogs_.end())
4270 return it->second.get()->isVisibleView() && !it->second.get()->isClosing();
4274 void GuiView::hideDialog(string const & name, Inset * inset)
4276 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
4277 if (it == d.dialogs_.end())
4281 if (!currentBufferView())
4283 if (inset != currentBufferView()->editedInset(name))
4287 Dialog * const dialog = it->second.get();
4288 if (dialog->isVisibleView())
4290 if (currentBufferView())
4291 currentBufferView()->editInset(name, 0);
4295 void GuiView::disconnectDialog(string const & name)
4297 if (!isValidName(name))
4299 if (currentBufferView())
4300 currentBufferView()->editInset(name, 0);
4304 void GuiView::hideAll() const
4306 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
4307 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
4309 for(; it != end; ++it)
4310 it->second->hideView();
4314 void GuiView::updateDialogs()
4316 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
4317 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
4319 for(; it != end; ++it) {
4320 Dialog * dialog = it->second.get();
4322 if (dialog->needBufferOpen() && !documentBufferView())
4323 hideDialog(fromqstr(dialog->name()), 0);
4324 else if (dialog->isVisibleView())
4325 dialog->checkStatus();
4332 Dialog * createDialog(GuiView & lv, string const & name);
4334 // will be replaced by a proper factory...
4335 Dialog * createGuiAbout(GuiView & lv);
4336 Dialog * createGuiBibtex(GuiView & lv);
4337 Dialog * createGuiChanges(GuiView & lv);
4338 Dialog * createGuiCharacter(GuiView & lv);
4339 Dialog * createGuiCitation(GuiView & lv);
4340 Dialog * createGuiCompare(GuiView & lv);
4341 Dialog * createGuiCompareHistory(GuiView & lv);
4342 Dialog * createGuiDelimiter(GuiView & lv);
4343 Dialog * createGuiDocument(GuiView & lv);
4344 Dialog * createGuiErrorList(GuiView & lv);
4345 Dialog * createGuiExternal(GuiView & lv);
4346 Dialog * createGuiGraphics(GuiView & lv);
4347 Dialog * createGuiInclude(GuiView & lv);
4348 Dialog * createGuiIndex(GuiView & lv);
4349 Dialog * createGuiListings(GuiView & lv);
4350 Dialog * createGuiLog(GuiView & lv);
4351 Dialog * createGuiMathMatrix(GuiView & lv);
4352 Dialog * createGuiNote(GuiView & lv);
4353 Dialog * createGuiParagraph(GuiView & lv);
4354 Dialog * createGuiPhantom(GuiView & lv);
4355 Dialog * createGuiPreferences(GuiView & lv);
4356 Dialog * createGuiPrint(GuiView & lv);
4357 Dialog * createGuiPrintindex(GuiView & lv);
4358 Dialog * createGuiRef(GuiView & lv);
4359 Dialog * createGuiSearch(GuiView & lv);
4360 Dialog * createGuiSearchAdv(GuiView & lv);
4361 Dialog * createGuiSendTo(GuiView & lv);
4362 Dialog * createGuiShowFile(GuiView & lv);
4363 Dialog * createGuiSpellchecker(GuiView & lv);
4364 Dialog * createGuiSymbols(GuiView & lv);
4365 Dialog * createGuiTabularCreate(GuiView & lv);
4366 Dialog * createGuiTexInfo(GuiView & lv);
4367 Dialog * createGuiToc(GuiView & lv);
4368 Dialog * createGuiThesaurus(GuiView & lv);
4369 Dialog * createGuiViewSource(GuiView & lv);
4370 Dialog * createGuiWrap(GuiView & lv);
4371 Dialog * createGuiProgressView(GuiView & lv);
4375 Dialog * GuiView::build(string const & name)
4377 LASSERT(isValidName(name), return 0);
4379 Dialog * dialog = createDialog(*this, name);
4383 if (name == "aboutlyx")
4384 return createGuiAbout(*this);
4385 if (name == "bibtex")
4386 return createGuiBibtex(*this);
4387 if (name == "changes")
4388 return createGuiChanges(*this);
4389 if (name == "character")
4390 return createGuiCharacter(*this);
4391 if (name == "citation")
4392 return createGuiCitation(*this);
4393 if (name == "compare")
4394 return createGuiCompare(*this);
4395 if (name == "comparehistory")
4396 return createGuiCompareHistory(*this);
4397 if (name == "document")
4398 return createGuiDocument(*this);
4399 if (name == "errorlist")
4400 return createGuiErrorList(*this);
4401 if (name == "external")
4402 return createGuiExternal(*this);
4404 return createGuiShowFile(*this);
4405 if (name == "findreplace")
4406 return createGuiSearch(*this);
4407 if (name == "findreplaceadv")
4408 return createGuiSearchAdv(*this);
4409 if (name == "graphics")
4410 return createGuiGraphics(*this);
4411 if (name == "include")
4412 return createGuiInclude(*this);
4413 if (name == "index")
4414 return createGuiIndex(*this);
4415 if (name == "index_print")
4416 return createGuiPrintindex(*this);
4417 if (name == "listings")
4418 return createGuiListings(*this);
4420 return createGuiLog(*this);
4421 if (name == "mathdelimiter")
4422 return createGuiDelimiter(*this);
4423 if (name == "mathmatrix")
4424 return createGuiMathMatrix(*this);
4426 return createGuiNote(*this);
4427 if (name == "paragraph")
4428 return createGuiParagraph(*this);
4429 if (name == "phantom")
4430 return createGuiPhantom(*this);
4431 if (name == "prefs")
4432 return createGuiPreferences(*this);
4434 return createGuiRef(*this);
4435 if (name == "sendto")
4436 return createGuiSendTo(*this);
4437 if (name == "spellchecker")
4438 return createGuiSpellchecker(*this);
4439 if (name == "symbols")
4440 return createGuiSymbols(*this);
4441 if (name == "tabularcreate")
4442 return createGuiTabularCreate(*this);
4443 if (name == "texinfo")
4444 return createGuiTexInfo(*this);
4445 if (name == "thesaurus")
4446 return createGuiThesaurus(*this);
4448 return createGuiToc(*this);
4449 if (name == "view-source")
4450 return createGuiViewSource(*this);
4452 return createGuiWrap(*this);
4453 if (name == "progress")
4454 return createGuiProgressView(*this);
4460 } // namespace frontend
4463 #include "moc_GuiView.cpp"