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"
36 #include "frontends/alert.h"
37 #include "frontends/KeySymbol.h"
39 #include "buffer_funcs.h"
41 #include "BufferList.h"
42 #include "BufferParams.h"
43 #include "BufferView.h"
45 #include "Converter.h"
47 #include "CutAndPaste.h"
49 #include "ErrorList.h"
51 #include "FuncStatus.h"
52 #include "FuncRequest.h"
56 #include "LyXAction.h"
60 #include "Paragraph.h"
61 #include "SpellChecker.h"
64 #include "TextClass.h"
69 #include "support/convert.h"
70 #include "support/debug.h"
71 #include "support/ExceptionMessage.h"
72 #include "support/FileName.h"
73 #include "support/filetools.h"
74 #include "support/gettext.h"
75 #include "support/filetools.h"
76 #include "support/ForkedCalls.h"
77 #include "support/lassert.h"
78 #include "support/lstrings.h"
79 #include "support/os.h"
80 #include "support/Package.h"
81 #include "support/PathChanger.h"
82 #include "support/Systemcall.h"
83 #include "support/Timeout.h"
84 #include "support/ProgressInterface.h"
87 #include <QApplication>
88 #include <QCloseEvent>
90 #include <QDesktopWidget>
91 #include <QDragEnterEvent>
94 #include <QFutureWatcher>
103 #include <QPixmapCache>
105 #include <QPushButton>
106 #include <QScrollBar>
108 #include <QShowEvent>
110 #include <QStackedWidget>
111 #include <QStatusBar>
112 #include <QtConcurrentRun>
120 // sync with GuiAlert.cpp
121 #define EXPORT_in_THREAD 1
124 #include "support/bind.h"
128 #ifdef HAVE_SYS_TIME_H
129 # include <sys/time.h>
137 using namespace lyx::support;
141 using support::addExtension;
142 using support::changeExtension;
143 using support::removeExtension;
149 class BackgroundWidget : public QWidget
154 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
155 if (!lyxrc.show_banner)
157 /// The text to be written on top of the pixmap
158 QString const text = lyx_version ?
159 qt_("version ") + lyx_version : qt_("unknown version");
160 splash_ = getPixmap("images/", "banner", "svgz,png");
162 QPainter pain(&splash_);
163 pain.setPen(QColor(0, 0, 0));
164 double const multiplier = splashPixelRatio() / pixelRatio();
165 int const size = static_cast<int>(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble() * multiplier);
166 int const x = static_cast<int>(190 * multiplier);
167 int const y = static_cast<int>(225 * multiplier);
169 "widget pixel ratio: " << pixelRatio() <<
170 " splash pixel ratio: " << splashPixelRatio() <<
171 " version text size,position: " << size << "@" << x << "+" << y);
173 // The font used to display the version info
174 font.setStyleHint(QFont::SansSerif);
175 font.setWeight(QFont::Bold);
176 font.setPointSize(size);
178 pain.drawText(x, y, text);
179 setFocusPolicy(Qt::StrongFocus);
182 void paintEvent(QPaintEvent *)
184 int const w = static_cast<int>(splash_.width() / splashPixelRatio());
185 int const h = static_cast<int>(splash_.height() / splashPixelRatio());
186 int const x = (width() - w) / 2;
187 int const y = (height() - h) / 2;
189 "widget pixel ratio: " << pixelRatio() <<
190 " splash pixel ratio: " << splashPixelRatio() <<
191 " paint pixmap: " << w << "x" << h << "@" << x << "+" << y);
193 pain.drawPixmap(x, y, w, h, splash_);
196 void keyPressEvent(QKeyEvent * ev)
199 setKeySymbol(&sym, ev);
201 guiApp->processKeySym(sym, q_key_state(ev->modifiers()));
211 /// Current ratio between physical pixels and device-independent pixels
212 double pixelRatio() const {
213 #if QT_VERSION >= 0x050000
214 return devicePixelRatio();
220 /// Ratio between physical pixels and device-independent pixels of splash image
221 double splashPixelRatio() const {
222 #if QT_VERSION >= 0x050000
223 return splash_.devicePixelRatio();
231 /// Toolbar store providing access to individual toolbars by name.
232 typedef map<string, GuiToolbar *> ToolbarMap;
234 typedef shared_ptr<Dialog> DialogPtr;
239 struct GuiView::GuiViewPrivate
241 GuiViewPrivate(GuiView * gv)
242 : gv_(gv), current_work_area_(0), current_main_work_area_(0),
243 layout_(0), autosave_timeout_(5000),
246 // hardcode here the platform specific icon size
247 smallIconSize = 16; // scaling problems
248 normalIconSize = 20; // ok, default if iconsize.png is missing
249 bigIconSize = 26; // better for some math icons
250 hugeIconSize = 32; // better for hires displays
253 // if it exists, use width of iconsize.png as normal size
254 QString const dir = toqstr(addPath("images", lyxrc.icon_set));
255 FileName const fn = lyx::libFileSearch(dir, "iconsize.png");
257 QImage image(toqstr(fn.absFileName()));
258 if (image.width() < int(smallIconSize))
259 normalIconSize = smallIconSize;
260 else if (image.width() > int(giantIconSize))
261 normalIconSize = giantIconSize;
263 normalIconSize = image.width();
266 splitter_ = new QSplitter;
267 bg_widget_ = new BackgroundWidget;
268 stack_widget_ = new QStackedWidget;
269 stack_widget_->addWidget(bg_widget_);
270 stack_widget_->addWidget(splitter_);
273 // TODO cleanup, remove the singleton, handle multiple Windows?
274 progress_ = ProgressInterface::instance();
275 if (!dynamic_cast<GuiProgress*>(progress_)) {
276 progress_ = new GuiProgress; // TODO who deletes it
277 ProgressInterface::setInstance(progress_);
280 dynamic_cast<GuiProgress*>(progress_),
281 SIGNAL(updateStatusBarMessage(QString const&)),
282 gv, SLOT(updateStatusBarMessage(QString const&)));
284 dynamic_cast<GuiProgress*>(progress_),
285 SIGNAL(clearMessageText()),
286 gv, SLOT(clearMessageText()));
293 delete stack_widget_;
296 QMenu * toolBarPopup(GuiView * parent)
298 // FIXME: translation
299 QMenu * menu = new QMenu(parent);
300 QActionGroup * iconSizeGroup = new QActionGroup(parent);
302 QAction * smallIcons = new QAction(iconSizeGroup);
303 smallIcons->setText(qt_("Small-sized icons"));
304 smallIcons->setCheckable(true);
305 QObject::connect(smallIcons, SIGNAL(triggered()),
306 parent, SLOT(smallSizedIcons()));
307 menu->addAction(smallIcons);
309 QAction * normalIcons = new QAction(iconSizeGroup);
310 normalIcons->setText(qt_("Normal-sized icons"));
311 normalIcons->setCheckable(true);
312 QObject::connect(normalIcons, SIGNAL(triggered()),
313 parent, SLOT(normalSizedIcons()));
314 menu->addAction(normalIcons);
316 QAction * bigIcons = new QAction(iconSizeGroup);
317 bigIcons->setText(qt_("Big-sized icons"));
318 bigIcons->setCheckable(true);
319 QObject::connect(bigIcons, SIGNAL(triggered()),
320 parent, SLOT(bigSizedIcons()));
321 menu->addAction(bigIcons);
323 QAction * hugeIcons = new QAction(iconSizeGroup);
324 hugeIcons->setText(qt_("Huge-sized icons"));
325 hugeIcons->setCheckable(true);
326 QObject::connect(hugeIcons, SIGNAL(triggered()),
327 parent, SLOT(hugeSizedIcons()));
328 menu->addAction(hugeIcons);
330 QAction * giantIcons = new QAction(iconSizeGroup);
331 giantIcons->setText(qt_("Giant-sized icons"));
332 giantIcons->setCheckable(true);
333 QObject::connect(giantIcons, SIGNAL(triggered()),
334 parent, SLOT(giantSizedIcons()));
335 menu->addAction(giantIcons);
337 unsigned int cur = parent->iconSize().width();
338 if ( cur == parent->d.smallIconSize)
339 smallIcons->setChecked(true);
340 else if (cur == parent->d.normalIconSize)
341 normalIcons->setChecked(true);
342 else if (cur == parent->d.bigIconSize)
343 bigIcons->setChecked(true);
344 else if (cur == parent->d.hugeIconSize)
345 hugeIcons->setChecked(true);
346 else if (cur == parent->d.giantIconSize)
347 giantIcons->setChecked(true);
354 stack_widget_->setCurrentWidget(bg_widget_);
355 bg_widget_->setUpdatesEnabled(true);
356 bg_widget_->setFocus();
359 int tabWorkAreaCount()
361 return splitter_->count();
364 TabWorkArea * tabWorkArea(int i)
366 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
369 TabWorkArea * currentTabWorkArea()
371 int areas = tabWorkAreaCount();
373 // The first TabWorkArea is always the first one, if any.
374 return tabWorkArea(0);
376 for (int i = 0; i != areas; ++i) {
377 TabWorkArea * twa = tabWorkArea(i);
378 if (current_main_work_area_ == twa->currentWorkArea())
382 // None has the focus so we just take the first one.
383 return tabWorkArea(0);
386 int countWorkAreasOf(Buffer & buf)
388 int areas = tabWorkAreaCount();
390 for (int i = 0; i != areas; ++i) {
391 TabWorkArea * twa = tabWorkArea(i);
392 if (twa->workArea(buf))
398 void setPreviewFuture(QFuture<Buffer::ExportStatus> const & f)
400 if (processing_thread_watcher_.isRunning()) {
401 // we prefer to cancel this preview in order to keep a snappy
405 processing_thread_watcher_.setFuture(f);
410 GuiWorkArea * current_work_area_;
411 GuiWorkArea * current_main_work_area_;
412 QSplitter * splitter_;
413 QStackedWidget * stack_widget_;
414 BackgroundWidget * bg_widget_;
416 ToolbarMap toolbars_;
417 ProgressInterface* progress_;
418 /// The main layout box.
420 * \warning Don't Delete! The layout box is actually owned by
421 * whichever toolbar contains it. All the GuiView class needs is a
422 * means of accessing it.
424 * FIXME: replace that with a proper model so that we are not limited
425 * to only one dialog.
430 map<string, DialogPtr> dialogs_;
432 unsigned int smallIconSize;
433 unsigned int normalIconSize;
434 unsigned int bigIconSize;
435 unsigned int hugeIconSize;
436 unsigned int giantIconSize;
438 QTimer statusbar_timer_;
439 /// auto-saving of buffers
440 Timeout autosave_timeout_;
441 /// flag against a race condition due to multiclicks, see bug #1119
445 TocModels toc_models_;
448 QFutureWatcher<docstring> autosave_watcher_;
449 QFutureWatcher<Buffer::ExportStatus> processing_thread_watcher_;
451 string last_export_format;
452 string processing_format;
454 static QSet<Buffer const *> busyBuffers;
455 static Buffer::ExportStatus previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
456 static Buffer::ExportStatus exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
457 static Buffer::ExportStatus compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
458 static docstring autosaveAndDestroy(Buffer const * orig, Buffer * buffer);
461 static Buffer::ExportStatus runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format);
463 // TODO syncFunc/previewFunc: use bind
464 bool asyncBufferProcessing(string const & argument,
465 Buffer const * used_buffer,
466 docstring const & msg,
467 Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
468 Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
469 Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const);
471 QVector<GuiWorkArea*> guiWorkAreas();
474 QSet<Buffer const *> GuiView::GuiViewPrivate::busyBuffers;
477 GuiView::GuiView(int id)
478 : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0)
480 // GuiToolbars *must* be initialised before the menu bar.
481 normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge
484 // set ourself as the current view. This is needed for the menu bar
485 // filling, at least for the static special menu item on Mac. Otherwise
486 // they are greyed out.
487 guiApp->setCurrentView(this);
489 // Fill up the menu bar.
490 guiApp->menus().fillMenuBar(menuBar(), this, true);
492 setCentralWidget(d.stack_widget_);
494 // Start autosave timer
495 if (lyxrc.autosave) {
496 d.autosave_timeout_.timeout.connect(bind(&GuiView::autoSave, this));
497 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
498 d.autosave_timeout_.start();
500 connect(&d.statusbar_timer_, SIGNAL(timeout()),
501 this, SLOT(clearMessage()));
503 // We don't want to keep the window in memory if it is closed.
504 setAttribute(Qt::WA_DeleteOnClose, true);
506 #if !(defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)) && !defined(Q_OS_MAC)
507 // QIcon::fromTheme was introduced in Qt 4.6
508 #if (QT_VERSION >= 0x040600)
509 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
510 // since the icon is provided in the application bundle. We use a themed
511 // version when available and use the bundled one as fallback.
512 setWindowIcon(QIcon::fromTheme("lyx", getPixmap("images/", "lyx", "svg,png")));
514 setWindowIcon(getPixmap("images/", "lyx", "svg,png"));
518 resetWindowTitleAndIconText();
520 // use tabbed dock area for multiple docks
521 // (such as "source" and "messages")
522 setDockOptions(QMainWindow::ForceTabbedDocks);
525 setAcceptDrops(true);
527 // add busy indicator to statusbar
528 QLabel * busylabel = new QLabel(statusBar());
529 statusBar()->addPermanentWidget(busylabel);
530 search_mode mode = theGuiApp()->imageSearchMode();
531 QString fn = toqstr(lyx::libFileSearch("images", "busy", "gif", mode).absFileName());
532 QMovie * busyanim = new QMovie(fn, QByteArray(), busylabel);
533 busylabel->setMovie(busyanim);
537 connect(&d.processing_thread_watcher_, SIGNAL(started()),
538 busylabel, SLOT(show()));
539 connect(&d.processing_thread_watcher_, SIGNAL(finished()),
540 busylabel, SLOT(hide()));
542 statusBar()->setSizeGripEnabled(true);
545 connect(&d.autosave_watcher_, SIGNAL(finished()), this,
546 SLOT(autoSaveThreadFinished()));
548 connect(&d.processing_thread_watcher_, SIGNAL(started()), this,
549 SLOT(processingThreadStarted()));
550 connect(&d.processing_thread_watcher_, SIGNAL(finished()), this,
551 SLOT(processingThreadFinished()));
553 connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)),
554 SLOT(doShowDialog(QString const &, QString const &, Inset *)));
556 // Forbid too small unresizable window because it can happen
557 // with some window manager under X11.
558 setMinimumSize(300, 200);
560 if (lyxrc.allow_geometry_session) {
561 // Now take care of session management.
566 // no session handling, default to a sane size.
567 setGeometry(50, 50, 690, 510);
570 // clear session data if any.
572 settings.remove("views");
582 QVector<GuiWorkArea*> GuiView::GuiViewPrivate::guiWorkAreas()
584 QVector<GuiWorkArea*> areas;
585 for (int i = 0; i < tabWorkAreaCount(); i++) {
586 TabWorkArea* ta = tabWorkArea(i);
587 for (int u = 0; u < ta->count(); u++) {
588 areas << ta->workArea(u);
594 static void handleExportStatus(GuiView * view, Buffer::ExportStatus status,
595 string const & format)
597 docstring const fmt = formats.prettyName(format);
600 case Buffer::ExportSuccess:
601 msg = bformat(_("Successful export to format: %1$s"), fmt);
603 case Buffer::ExportCancel:
604 msg = _("Document export cancelled.");
606 case Buffer::ExportError:
607 case Buffer::ExportNoPathToFormat:
608 case Buffer::ExportTexPathHasSpaces:
609 case Buffer::ExportConverterError:
610 msg = bformat(_("Error while exporting format: %1$s"), fmt);
612 case Buffer::PreviewSuccess:
613 msg = bformat(_("Successful preview of format: %1$s"), fmt);
615 case Buffer::PreviewError:
616 msg = bformat(_("Error while previewing format: %1$s"), fmt);
623 void GuiView::processingThreadStarted()
628 void GuiView::processingThreadFinished()
630 QFutureWatcher<Buffer::ExportStatus> const * watcher =
631 static_cast<QFutureWatcher<Buffer::ExportStatus> const *>(sender());
633 Buffer::ExportStatus const status = watcher->result();
634 handleExportStatus(this, status, d.processing_format);
637 BufferView const * const bv = currentBufferView();
638 if (bv && !bv->buffer().errorList("Export").empty()) {
642 errors(d.last_export_format);
646 void GuiView::autoSaveThreadFinished()
648 QFutureWatcher<docstring> const * watcher =
649 static_cast<QFutureWatcher<docstring> const *>(sender());
650 message(watcher->result());
655 void GuiView::saveLayout() const
658 settings.beginGroup("views");
659 settings.beginGroup(QString::number(id_));
660 #if defined(Q_WS_X11) || defined(QPA_XCB)
661 settings.setValue("pos", pos());
662 settings.setValue("size", size());
664 settings.setValue("geometry", saveGeometry());
666 settings.setValue("layout", saveState(0));
667 settings.setValue("icon_size", iconSize());
671 void GuiView::saveUISettings() const
673 // Save the toolbar private states
674 ToolbarMap::iterator end = d.toolbars_.end();
675 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
676 it->second->saveSession();
677 // Now take care of all other dialogs
678 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
679 for (; it!= d.dialogs_.end(); ++it)
680 it->second->saveSession();
684 bool GuiView::restoreLayout()
687 settings.beginGroup("views");
688 settings.beginGroup(QString::number(id_));
689 QString const icon_key = "icon_size";
690 if (!settings.contains(icon_key))
693 //code below is skipped when when ~/.config/LyX is (re)created
694 QSize icon_size = settings.value(icon_key).toSize();
695 // Check whether session size changed.
696 if (icon_size.width() != int(d.smallIconSize) &&
697 icon_size.width() != int(d.normalIconSize) &&
698 icon_size.width() != int(d.bigIconSize) &&
699 icon_size.width() != int(d.hugeIconSize) &&
700 icon_size.width() != int(d.giantIconSize)) {
701 icon_size.setWidth(d.normalIconSize);
702 icon_size.setHeight(d.normalIconSize);
704 setIconSize(icon_size);
706 #if defined(Q_WS_X11) || defined(QPA_XCB)
707 QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
708 QSize size = settings.value("size", QSize(690, 510)).toSize();
712 // Work-around for bug #6034: the window ends up in an undetermined
713 // state when trying to restore a maximized window when it is
714 // already maximized.
715 if (!(windowState() & Qt::WindowMaximized))
716 if (!restoreGeometry(settings.value("geometry").toByteArray()))
717 setGeometry(50, 50, 690, 510);
719 // Make sure layout is correctly oriented.
720 setLayoutDirection(qApp->layoutDirection());
722 // Allow the toc and view-source dock widget to be restored if needed.
724 if ((dialog = findOrBuild("toc", true)))
725 // see bug 5082. At least setup title and enabled state.
726 // Visibility will be adjusted by restoreState below.
727 dialog->prepareView();
728 if ((dialog = findOrBuild("view-source", true)))
729 dialog->prepareView();
730 if ((dialog = findOrBuild("progress", true)))
731 dialog->prepareView();
733 if (!restoreState(settings.value("layout").toByteArray(), 0))
736 // init the toolbars that have not been restored
737 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
738 Toolbars::Infos::iterator end = guiApp->toolbars().end();
739 for (; cit != end; ++cit) {
740 GuiToolbar * tb = toolbar(cit->name);
741 if (tb && !tb->isRestored())
742 initToolbar(cit->name);
750 GuiToolbar * GuiView::toolbar(string const & name)
752 ToolbarMap::iterator it = d.toolbars_.find(name);
753 if (it != d.toolbars_.end())
756 LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
761 void GuiView::constructToolbars()
763 ToolbarMap::iterator it = d.toolbars_.begin();
764 for (; it != d.toolbars_.end(); ++it)
768 // I don't like doing this here, but the standard toolbar
769 // destroys this object when it's destroyed itself (vfr)
770 d.layout_ = new LayoutBox(*this);
771 d.stack_widget_->addWidget(d.layout_);
772 d.layout_->move(0,0);
774 // extracts the toolbars from the backend
775 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
776 Toolbars::Infos::iterator end = guiApp->toolbars().end();
777 for (; cit != end; ++cit)
778 d.toolbars_[cit->name] = new GuiToolbar(*cit, *this);
782 void GuiView::initToolbars()
784 // extracts the toolbars from the backend
785 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
786 Toolbars::Infos::iterator end = guiApp->toolbars().end();
787 for (; cit != end; ++cit)
788 initToolbar(cit->name);
792 void GuiView::initToolbar(string const & name)
794 GuiToolbar * tb = toolbar(name);
797 int const visibility = guiApp->toolbars().defaultVisibility(name);
798 bool newline = !(visibility & Toolbars::SAMEROW);
799 tb->setVisible(false);
800 tb->setVisibility(visibility);
802 if (visibility & Toolbars::TOP) {
804 addToolBarBreak(Qt::TopToolBarArea);
805 addToolBar(Qt::TopToolBarArea, tb);
808 if (visibility & Toolbars::BOTTOM) {
810 addToolBarBreak(Qt::BottomToolBarArea);
811 addToolBar(Qt::BottomToolBarArea, tb);
814 if (visibility & Toolbars::LEFT) {
816 addToolBarBreak(Qt::LeftToolBarArea);
817 addToolBar(Qt::LeftToolBarArea, tb);
820 if (visibility & Toolbars::RIGHT) {
822 addToolBarBreak(Qt::RightToolBarArea);
823 addToolBar(Qt::RightToolBarArea, tb);
826 if (visibility & Toolbars::ON)
827 tb->setVisible(true);
831 TocModels & GuiView::tocModels()
833 return d.toc_models_;
837 void GuiView::setFocus()
839 LYXERR(Debug::DEBUG, "GuiView::setFocus()" << this);
840 QMainWindow::setFocus();
844 bool GuiView::hasFocus() const
846 if (currentWorkArea())
847 return currentWorkArea()->hasFocus();
848 if (currentMainWorkArea())
849 return currentMainWorkArea()->hasFocus();
850 return d.bg_widget_->hasFocus();
854 void GuiView::focusInEvent(QFocusEvent * e)
856 LYXERR(Debug::DEBUG, "GuiView::focusInEvent()" << this);
857 QMainWindow::focusInEvent(e);
858 // Make sure guiApp points to the correct view.
859 guiApp->setCurrentView(this);
860 if (currentWorkArea())
861 currentWorkArea()->setFocus();
862 else if (currentMainWorkArea())
863 currentMainWorkArea()->setFocus();
865 d.bg_widget_->setFocus();
869 QMenu * GuiView::createPopupMenu()
871 return d.toolBarPopup(this);
875 void GuiView::showEvent(QShowEvent * e)
877 LYXERR(Debug::GUI, "Passed Geometry "
878 << size().height() << "x" << size().width()
879 << "+" << pos().x() << "+" << pos().y());
881 if (d.splitter_->count() == 0)
882 // No work area, switch to the background widget.
886 QMainWindow::showEvent(e);
890 bool GuiView::closeScheduled()
897 bool GuiView::prepareAllBuffersForLogout()
899 Buffer * first = theBufferList().first();
903 // First, iterate over all buffers and ask the users if unsaved
904 // changes should be saved.
905 // We cannot use a for loop as the buffer list cycles.
908 if (!saveBufferIfNeeded(const_cast<Buffer &>(*b), false))
910 b = theBufferList().next(b);
911 } while (b != first);
913 // Next, save session state
914 // When a view/window was closed before without quitting LyX, there
915 // are already entries in the lastOpened list.
916 theSession().lastOpened().clear();
923 /** Destroy only all tabbed WorkAreas. Destruction of other WorkAreas
924 ** is responsibility of the container (e.g., dialog)
926 void GuiView::closeEvent(QCloseEvent * close_event)
928 LYXERR(Debug::DEBUG, "GuiView::closeEvent()");
930 if (!GuiViewPrivate::busyBuffers.isEmpty()) {
931 Alert::warning(_("Exit LyX"),
932 _("LyX could not be closed because documents are being processed by LyX."));
933 close_event->setAccepted(false);
937 // If the user pressed the x (so we didn't call closeView
938 // programmatically), we want to clear all existing entries.
940 theSession().lastOpened().clear();
945 // it can happen that this event arrives without selecting the view,
946 // e.g. when clicking the close button on a background window.
948 if (!closeWorkAreaAll()) {
950 close_event->ignore();
954 // Make sure that nothing will use this to be closed View.
955 guiApp->unregisterView(this);
957 if (isFullScreen()) {
958 // Switch off fullscreen before closing.
963 // Make sure the timer time out will not trigger a statusbar update.
964 d.statusbar_timer_.stop();
966 // Saving fullscreen requires additional tweaks in the toolbar code.
967 // It wouldn't also work under linux natively.
968 if (lyxrc.allow_geometry_session) {
973 close_event->accept();
977 void GuiView::dragEnterEvent(QDragEnterEvent * event)
979 if (event->mimeData()->hasUrls())
981 /// \todo Ask lyx-devel is this is enough:
982 /// if (event->mimeData()->hasFormat("text/plain"))
983 /// event->acceptProposedAction();
987 void GuiView::dropEvent(QDropEvent * event)
989 QList<QUrl> files = event->mimeData()->urls();
993 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
994 for (int i = 0; i != files.size(); ++i) {
995 string const file = os::internal_path(fromqstr(
996 files.at(i).toLocalFile()));
1000 string const ext = support::getExtension(file);
1001 vector<const Format *> found_formats;
1003 // Find all formats that have the correct extension.
1004 vector<const Format *> const & import_formats
1005 = theConverters().importableFormats();
1006 vector<const Format *>::const_iterator it = import_formats.begin();
1007 for (; it != import_formats.end(); ++it)
1008 if ((*it)->hasExtension(ext))
1009 found_formats.push_back(*it);
1012 if (found_formats.size() >= 1) {
1013 if (found_formats.size() > 1) {
1014 //FIXME: show a dialog to choose the correct importable format
1015 LYXERR(Debug::FILES,
1016 "Multiple importable formats found, selecting first");
1018 string const arg = found_formats[0]->name() + " " + file;
1019 cmd = FuncRequest(LFUN_BUFFER_IMPORT, arg);
1022 //FIXME: do we have to explicitly check whether it's a lyx file?
1023 LYXERR(Debug::FILES,
1024 "No formats found, trying to open it as a lyx file");
1025 cmd = FuncRequest(LFUN_FILE_OPEN, file);
1027 // add the functions to the queue
1028 guiApp->addToFuncRequestQueue(cmd);
1031 // now process the collected functions. We perform the events
1032 // asynchronously. This prevents potential problems in case the
1033 // BufferView is closed within an event.
1034 guiApp->processFuncRequestQueueAsync();
1038 void GuiView::message(docstring const & str)
1040 if (ForkedProcess::iAmAChild())
1043 // call is moved to GUI-thread by GuiProgress
1044 d.progress_->appendMessage(toqstr(str));
1048 void GuiView::clearMessageText()
1050 message(docstring());
1054 void GuiView::updateStatusBarMessage(QString const & str)
1056 statusBar()->showMessage(str);
1057 d.statusbar_timer_.stop();
1058 d.statusbar_timer_.start(3000);
1062 void GuiView::smallSizedIcons()
1064 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
1068 void GuiView::normalSizedIcons()
1070 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
1074 void GuiView::bigSizedIcons()
1076 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
1080 void GuiView::hugeSizedIcons()
1082 setIconSize(QSize(d.hugeIconSize, d.hugeIconSize));
1086 void GuiView::giantSizedIcons()
1088 setIconSize(QSize(d.giantIconSize, d.giantIconSize));
1092 void GuiView::clearMessage()
1094 // FIXME: This code was introduced in r19643 to fix bug #4123. However,
1095 // the hasFocus function mostly returns false, even if the focus is on
1096 // a workarea in this view.
1100 d.statusbar_timer_.stop();
1104 void GuiView::updateWindowTitle(GuiWorkArea * wa)
1106 if (wa != d.current_work_area_
1107 || wa->bufferView().buffer().isInternal())
1109 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
1110 setWindowIconText(wa->windowIconText());
1111 #if (QT_VERSION >= 0x040400)
1112 // Sets the path for the window: this is used by OSX to
1113 // allow a context click on the title bar showing a menu
1114 // with the path up to the file
1115 setWindowFilePath(toqstr(wa->bufferView().buffer().absFileName()));
1120 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
1122 if (d.current_work_area_)
1123 QObject::disconnect(d.current_work_area_, SIGNAL(busy(bool)),
1124 this, SLOT(setBusy(bool)));
1126 disconnectBufferView();
1127 connectBufferView(wa->bufferView());
1128 connectBuffer(wa->bufferView().buffer());
1129 d.current_work_area_ = wa;
1130 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
1131 this, SLOT(updateWindowTitle(GuiWorkArea *)));
1132 QObject::connect(wa, SIGNAL(busy(bool)), this, SLOT(setBusy(bool)));
1133 updateWindowTitle(wa);
1137 // The document settings needs to be reinitialised.
1138 updateDialog("document", "");
1140 // Buffer-dependent dialogs must be updated. This is done here because
1141 // some dialogs require buffer()->text.
1146 void GuiView::on_lastWorkAreaRemoved()
1149 // We already are in a close event. Nothing more to do.
1152 if (d.splitter_->count() > 1)
1153 // We have a splitter so don't close anything.
1156 // Reset and updates the dialogs.
1157 d.toc_models_.reset(0);
1158 updateDialog("document", "");
1161 resetWindowTitleAndIconText();
1164 if (lyxrc.open_buffers_in_tabs)
1165 // Nothing more to do, the window should stay open.
1168 if (guiApp->viewIds().size() > 1) {
1174 // On Mac we also close the last window because the application stay
1175 // resident in memory. On other platforms we don't close the last
1176 // window because this would quit the application.
1182 void GuiView::updateStatusBar()
1184 // let the user see the explicit message
1185 if (d.statusbar_timer_.isActive())
1192 void GuiView::showMessage()
1196 QString msg = toqstr(theGuiApp()->viewStatusMessage());
1197 if (msg.isEmpty()) {
1198 BufferView const * bv = currentBufferView();
1200 msg = toqstr(bv->cursor().currentState());
1202 msg = qt_("Welcome to LyX!");
1204 statusBar()->showMessage(msg);
1208 bool GuiView::event(QEvent * e)
1212 // Useful debug code:
1213 //case QEvent::ActivationChange:
1214 //case QEvent::WindowDeactivate:
1215 //case QEvent::Paint:
1216 //case QEvent::Enter:
1217 //case QEvent::Leave:
1218 //case QEvent::HoverEnter:
1219 //case QEvent::HoverLeave:
1220 //case QEvent::HoverMove:
1221 //case QEvent::StatusTip:
1222 //case QEvent::DragEnter:
1223 //case QEvent::DragLeave:
1224 //case QEvent::Drop:
1227 case QEvent::WindowActivate: {
1228 GuiView * old_view = guiApp->currentView();
1229 if (this == old_view) {
1231 return QMainWindow::event(e);
1233 if (old_view && old_view->currentBufferView()) {
1234 // save current selection to the selection buffer to allow
1235 // middle-button paste in this window.
1236 cap::saveSelection(old_view->currentBufferView()->cursor());
1238 guiApp->setCurrentView(this);
1239 if (d.current_work_area_) {
1240 BufferView & bv = d.current_work_area_->bufferView();
1241 connectBufferView(bv);
1242 connectBuffer(bv.buffer());
1243 // The document structure, name and dialogs might have
1244 // changed in another view.
1246 // The document settings needs to be reinitialised.
1247 updateDialog("document", "");
1250 resetWindowTitleAndIconText();
1253 return QMainWindow::event(e);
1256 case QEvent::ShortcutOverride: {
1258 if (isFullScreen() && menuBar()->isHidden()) {
1259 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
1260 // FIXME: we should also try to detect special LyX shortcut such as
1261 // Alt-P and Alt-M. Right now there is a hack in
1262 // GuiWorkArea::processKeySym() that hides again the menubar for
1264 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt) {
1266 return QMainWindow::event(e);
1269 return QMainWindow::event(e);
1273 return QMainWindow::event(e);
1277 void GuiView::resetWindowTitleAndIconText()
1279 setWindowTitle(qt_("LyX"));
1280 setWindowIconText(qt_("LyX"));
1283 bool GuiView::focusNextPrevChild(bool /*next*/)
1290 bool GuiView::busy() const
1296 void GuiView::setBusy(bool busy)
1298 bool const busy_before = busy_ > 0;
1299 busy ? ++busy_ : --busy_;
1300 if ((busy_ > 0) == busy_before)
1301 // busy state didn't change
1305 QApplication::setOverrideCursor(Qt::WaitCursor);
1308 QApplication::restoreOverrideCursor();
1313 double GuiView::pixelRatio() const
1315 #if QT_VERSION >= 0x050000
1316 return devicePixelRatio();
1323 GuiWorkArea * GuiView::workArea(int index)
1325 if (TabWorkArea * twa = d.currentTabWorkArea())
1326 if (index < twa->count())
1327 return dynamic_cast<GuiWorkArea *>(twa->widget(index));
1332 GuiWorkArea * GuiView::workArea(Buffer & buffer)
1334 if (currentWorkArea()
1335 && ¤tWorkArea()->bufferView().buffer() == &buffer)
1336 return (GuiWorkArea *) currentWorkArea();
1337 if (TabWorkArea * twa = d.currentTabWorkArea())
1338 return twa->workArea(buffer);
1343 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
1345 // Automatically create a TabWorkArea if there are none yet.
1346 TabWorkArea * tab_widget = d.splitter_->count()
1347 ? d.currentTabWorkArea() : addTabWorkArea();
1348 return tab_widget->addWorkArea(buffer, *this);
1352 TabWorkArea * GuiView::addTabWorkArea()
1354 TabWorkArea * twa = new TabWorkArea;
1355 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
1356 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
1357 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
1358 this, SLOT(on_lastWorkAreaRemoved()));
1360 d.splitter_->addWidget(twa);
1361 d.stack_widget_->setCurrentWidget(d.splitter_);
1366 GuiWorkArea const * GuiView::currentWorkArea() const
1368 return d.current_work_area_;
1372 GuiWorkArea * GuiView::currentWorkArea()
1374 return d.current_work_area_;
1378 GuiWorkArea const * GuiView::currentMainWorkArea() const
1380 if (!d.currentTabWorkArea())
1382 return d.currentTabWorkArea()->currentWorkArea();
1386 GuiWorkArea * GuiView::currentMainWorkArea()
1388 if (!d.currentTabWorkArea())
1390 return d.currentTabWorkArea()->currentWorkArea();
1394 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
1396 LYXERR(Debug::DEBUG, "Setting current wa: " << wa << endl);
1398 d.current_work_area_ = 0;
1403 // FIXME: I've no clue why this is here and why it accesses
1404 // theGuiApp()->currentView, which might be 0 (bug 6464).
1405 // See also 27525 (vfr).
1406 if (theGuiApp()->currentView() == this
1407 && theGuiApp()->currentView()->currentWorkArea() == wa)
1410 if (currentBufferView())
1411 cap::saveSelection(currentBufferView()->cursor());
1413 theGuiApp()->setCurrentView(this);
1414 d.current_work_area_ = wa;
1416 // We need to reset this now, because it will need to be
1417 // right if the tabWorkArea gets reset in the for loop. We
1418 // will change it back if we aren't in that case.
1419 GuiWorkArea * const old_cmwa = d.current_main_work_area_;
1420 d.current_main_work_area_ = wa;
1422 for (int i = 0; i != d.splitter_->count(); ++i) {
1423 if (d.tabWorkArea(i)->setCurrentWorkArea(wa)) {
1424 LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea()
1425 << ", Current main wa: " << currentMainWorkArea());
1430 d.current_main_work_area_ = old_cmwa;
1432 LYXERR(Debug::DEBUG, "This is not a tabbed wa");
1433 on_currentWorkAreaChanged(wa);
1434 BufferView & bv = wa->bufferView();
1435 bv.cursor().fixIfBroken();
1437 wa->setUpdatesEnabled(true);
1438 LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
1442 void GuiView::removeWorkArea(GuiWorkArea * wa)
1444 LASSERT(wa, return);
1445 if (wa == d.current_work_area_) {
1447 disconnectBufferView();
1448 d.current_work_area_ = 0;
1449 d.current_main_work_area_ = 0;
1452 bool found_twa = false;
1453 for (int i = 0; i != d.splitter_->count(); ++i) {
1454 TabWorkArea * twa = d.tabWorkArea(i);
1455 if (twa->removeWorkArea(wa)) {
1456 // Found in this tab group, and deleted the GuiWorkArea.
1458 if (twa->count() != 0) {
1459 if (d.current_work_area_ == 0)
1460 // This means that we are closing the current GuiWorkArea, so
1461 // switch to the next GuiWorkArea in the found TabWorkArea.
1462 setCurrentWorkArea(twa->currentWorkArea());
1464 // No more WorkAreas in this tab group, so delete it.
1471 // It is not a tabbed work area (i.e., the search work area), so it
1472 // should be deleted by other means.
1473 LASSERT(found_twa, return);
1475 if (d.current_work_area_ == 0) {
1476 if (d.splitter_->count() != 0) {
1477 TabWorkArea * twa = d.currentTabWorkArea();
1478 setCurrentWorkArea(twa->currentWorkArea());
1480 // No more work areas, switch to the background widget.
1481 setCurrentWorkArea(0);
1487 LayoutBox * GuiView::getLayoutDialog() const
1493 void GuiView::updateLayoutList()
1496 d.layout_->updateContents(false);
1500 void GuiView::updateToolbars()
1502 ToolbarMap::iterator end = d.toolbars_.end();
1503 if (d.current_work_area_) {
1505 d.current_work_area_->bufferView().cursor().inMathed()
1506 && !d.current_work_area_->bufferView().cursor().inRegexped();
1508 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
1510 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
1511 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true);
1512 bool const mathmacrotemplate =
1513 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
1515 lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled();
1517 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1518 it->second->update(math, table, review, mathmacrotemplate, ipa);
1520 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1521 it->second->update(false, false, false, false, false);
1525 void GuiView::setBuffer(Buffer * newBuffer)
1527 LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << endl);
1528 LASSERT(newBuffer, return);
1530 GuiWorkArea * wa = workArea(*newBuffer);
1533 newBuffer->masterBuffer()->updateBuffer();
1535 wa = addWorkArea(*newBuffer);
1536 // scroll to the position when the BufferView was last closed
1537 if (lyxrc.use_lastfilepos) {
1538 LastFilePosSection::FilePos filepos =
1539 theSession().lastFilePos().load(newBuffer->fileName());
1540 wa->bufferView().moveToPosition(filepos.pit, filepos.pos, 0, 0);
1543 //Disconnect the old buffer...there's no new one.
1546 connectBuffer(*newBuffer);
1547 connectBufferView(wa->bufferView());
1548 setCurrentWorkArea(wa);
1552 void GuiView::connectBuffer(Buffer & buf)
1554 buf.setGuiDelegate(this);
1558 void GuiView::disconnectBuffer()
1560 if (d.current_work_area_)
1561 d.current_work_area_->bufferView().buffer().setGuiDelegate(0);
1565 void GuiView::connectBufferView(BufferView & bv)
1567 bv.setGuiDelegate(this);
1571 void GuiView::disconnectBufferView()
1573 if (d.current_work_area_)
1574 d.current_work_area_->bufferView().setGuiDelegate(0);
1578 void GuiView::errors(string const & error_type, bool from_master)
1580 BufferView const * const bv = currentBufferView();
1584 #if EXPORT_in_THREAD
1585 // We are called with from_master == false by default, so we
1586 // have to figure out whether that is the case or not.
1587 ErrorList & el = bv->buffer().errorList(error_type);
1589 el = bv->buffer().masterBuffer()->errorList(error_type);
1593 ErrorList const & el = from_master ?
1594 bv->buffer().masterBuffer()->errorList(error_type) :
1595 bv->buffer().errorList(error_type);
1601 string data = error_type;
1603 data = "from_master|" + error_type;
1604 showDialog("errorlist", data);
1608 void GuiView::updateTocItem(string const & type, DocIterator const & dit)
1610 d.toc_models_.updateItem(toqstr(type), dit);
1614 void GuiView::structureChanged()
1616 d.toc_models_.reset(documentBufferView());
1617 // Navigator needs more than a simple update in this case. It needs to be
1619 updateDialog("toc", "");
1623 void GuiView::updateDialog(string const & name, string const & data)
1625 if (!isDialogVisible(name))
1628 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1629 if (it == d.dialogs_.end())
1632 Dialog * const dialog = it->second.get();
1633 if (dialog->isVisibleView())
1634 dialog->initialiseParams(data);
1638 BufferView * GuiView::documentBufferView()
1640 return currentMainWorkArea()
1641 ? ¤tMainWorkArea()->bufferView()
1646 BufferView const * GuiView::documentBufferView() const
1648 return currentMainWorkArea()
1649 ? ¤tMainWorkArea()->bufferView()
1654 BufferView * GuiView::currentBufferView()
1656 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1660 BufferView const * GuiView::currentBufferView() const
1662 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1666 docstring GuiView::GuiViewPrivate::autosaveAndDestroy(
1667 Buffer const * orig, Buffer * clone)
1669 bool const success = clone->autoSave();
1671 busyBuffers.remove(orig);
1673 ? _("Automatic save done.")
1674 : _("Automatic save failed!");
1678 void GuiView::autoSave()
1680 LYXERR(Debug::INFO, "Running autoSave()");
1682 Buffer * buffer = documentBufferView()
1683 ? &documentBufferView()->buffer() : 0;
1685 resetAutosaveTimers();
1689 GuiViewPrivate::busyBuffers.insert(buffer);
1690 QFuture<docstring> f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy,
1691 buffer, buffer->cloneBufferOnly());
1692 d.autosave_watcher_.setFuture(f);
1693 resetAutosaveTimers();
1697 void GuiView::resetAutosaveTimers()
1700 d.autosave_timeout_.restart();
1704 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1707 Buffer * buf = currentBufferView()
1708 ? ¤tBufferView()->buffer() : 0;
1709 Buffer * doc_buffer = documentBufferView()
1710 ? &(documentBufferView()->buffer()) : 0;
1712 /* In LyX/Mac, when a dialog is open, the menus of the
1713 application can still be accessed without giving focus to
1714 the main window. In this case, we want to disable the menu
1715 entries that are buffer-related.
1717 if (cmd.origin() == FuncRequest::MENU && !hasFocus()) {
1722 // Check whether we need a buffer
1723 if (!lyxaction.funcHasFlag(cmd.action(), LyXAction::NoBuffer) && !buf) {
1724 // no, exit directly
1725 flag.message(from_utf8(N_("Command not allowed with"
1726 "out any document open")));
1727 flag.setEnabled(false);
1731 if (cmd.origin() == FuncRequest::TOC) {
1732 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
1733 if (!toc || !toc->getStatus(documentBufferView()->cursor(), cmd, flag))
1734 flag.setEnabled(false);
1738 switch(cmd.action()) {
1739 case LFUN_BUFFER_IMPORT:
1742 case LFUN_MASTER_BUFFER_UPDATE:
1743 case LFUN_MASTER_BUFFER_VIEW:
1745 && (doc_buffer->parent() != 0
1746 || doc_buffer->hasChildren())
1747 && !d.processing_thread_watcher_.isRunning();
1750 case LFUN_BUFFER_UPDATE:
1751 case LFUN_BUFFER_VIEW: {
1752 if (!doc_buffer || d.processing_thread_watcher_.isRunning()) {
1756 string format = to_utf8(cmd.argument());
1757 if (cmd.argument().empty())
1758 format = doc_buffer->params().getDefaultOutputFormat();
1759 enable = doc_buffer->params().isExportableFormat(format);
1763 case LFUN_BUFFER_RELOAD:
1764 enable = doc_buffer && !doc_buffer->isUnnamed()
1765 && doc_buffer->fileName().exists()
1766 && (!doc_buffer->isClean()
1767 || doc_buffer->isExternallyModified(Buffer::timestamp_method));
1770 case LFUN_BUFFER_CHILD_OPEN:
1771 enable = doc_buffer;
1774 case LFUN_BUFFER_WRITE:
1775 enable = doc_buffer && (doc_buffer->isUnnamed() || !doc_buffer->isClean());
1778 //FIXME: This LFUN should be moved to GuiApplication.
1779 case LFUN_BUFFER_WRITE_ALL: {
1780 // We enable the command only if there are some modified buffers
1781 Buffer * first = theBufferList().first();
1786 // We cannot use a for loop as the buffer list is a cycle.
1788 if (!b->isClean()) {
1792 b = theBufferList().next(b);
1793 } while (b != first);
1797 case LFUN_BUFFER_WRITE_AS:
1798 case LFUN_BUFFER_EXPORT_AS:
1799 enable = doc_buffer;
1802 case LFUN_BUFFER_CLOSE:
1803 case LFUN_VIEW_CLOSE:
1804 enable = doc_buffer;
1807 case LFUN_BUFFER_CLOSE_ALL:
1808 enable = theBufferList().last() != theBufferList().first();
1811 case LFUN_VIEW_SPLIT:
1812 if (cmd.getArg(0) == "vertical")
1813 enable = doc_buffer && (d.splitter_->count() == 1 ||
1814 d.splitter_->orientation() == Qt::Vertical);
1816 enable = doc_buffer && (d.splitter_->count() == 1 ||
1817 d.splitter_->orientation() == Qt::Horizontal);
1820 case LFUN_TAB_GROUP_CLOSE:
1821 enable = d.tabWorkAreaCount() > 1;
1824 case LFUN_TOOLBAR_TOGGLE: {
1825 string const name = cmd.getArg(0);
1826 if (GuiToolbar * t = toolbar(name))
1827 flag.setOnOff(t->isVisible());
1830 docstring const msg =
1831 bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name));
1837 case LFUN_DROP_LAYOUTS_CHOICE:
1841 case LFUN_UI_TOGGLE:
1842 flag.setOnOff(isFullScreen());
1845 case LFUN_DIALOG_DISCONNECT_INSET:
1848 case LFUN_DIALOG_HIDE:
1849 // FIXME: should we check if the dialog is shown?
1852 case LFUN_DIALOG_TOGGLE:
1853 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1854 // fall through to set "enable"
1855 case LFUN_DIALOG_SHOW: {
1856 string const name = cmd.getArg(0);
1858 enable = name == "aboutlyx"
1859 || name == "file" //FIXME: should be removed.
1861 || name == "texinfo"
1862 || name == "progress"
1863 || name == "compare";
1864 else if (name == "print")
1865 enable = doc_buffer->params().isExportable("dvi")
1866 && lyxrc.print_command != "none";
1867 else if (name == "character" || name == "symbols"
1868 || name == "mathdelimiter" || name == "mathmatrix") {
1869 if (!buf || buf->isReadonly())
1872 Cursor const & cur = currentBufferView()->cursor();
1873 enable = !(cur.inTexted() && cur.paragraph().isPassThru());
1876 else if (name == "latexlog")
1877 enable = FileName(doc_buffer->logName()).isReadableFile();
1878 else if (name == "spellchecker")
1879 enable = theSpellChecker()
1880 && !doc_buffer->isReadonly()
1881 && !doc_buffer->text().empty();
1882 else if (name == "vclog")
1883 enable = doc_buffer->lyxvc().inUse();
1887 case LFUN_DIALOG_UPDATE: {
1888 string const name = cmd.getArg(0);
1890 enable = name == "prefs";
1894 case LFUN_COMMAND_EXECUTE:
1896 case LFUN_MENU_OPEN:
1897 // Nothing to check.
1900 case LFUN_COMPLETION_INLINE:
1901 if (!d.current_work_area_
1902 || !d.current_work_area_->completer().inlinePossible(
1903 currentBufferView()->cursor()))
1907 case LFUN_COMPLETION_POPUP:
1908 if (!d.current_work_area_
1909 || !d.current_work_area_->completer().popupPossible(
1910 currentBufferView()->cursor()))
1915 if (!d.current_work_area_
1916 || !d.current_work_area_->completer().inlinePossible(
1917 currentBufferView()->cursor()))
1921 case LFUN_COMPLETION_ACCEPT:
1922 if (!d.current_work_area_
1923 || (!d.current_work_area_->completer().popupVisible()
1924 && !d.current_work_area_->completer().inlineVisible()
1925 && !d.current_work_area_->completer().completionAvailable()))
1929 case LFUN_COMPLETION_CANCEL:
1930 if (!d.current_work_area_
1931 || (!d.current_work_area_->completer().popupVisible()
1932 && !d.current_work_area_->completer().inlineVisible()))
1936 case LFUN_BUFFER_ZOOM_OUT:
1937 enable = doc_buffer && lyxrc.zoom > 10;
1940 case LFUN_BUFFER_ZOOM_IN:
1941 enable = doc_buffer;
1944 case LFUN_BUFFER_MOVE_NEXT:
1945 case LFUN_BUFFER_MOVE_PREVIOUS:
1946 // we do not cycle when moving
1947 case LFUN_BUFFER_NEXT:
1948 case LFUN_BUFFER_PREVIOUS:
1949 // because we cycle, it doesn't matter whether on first or last
1950 enable = (d.currentTabWorkArea()->count() > 1);
1952 case LFUN_BUFFER_SWITCH:
1953 // toggle on the current buffer, but do not toggle off
1954 // the other ones (is that a good idea?)
1956 && to_utf8(cmd.argument()) == doc_buffer->absFileName())
1957 flag.setOnOff(true);
1960 case LFUN_VC_REGISTER:
1961 enable = doc_buffer && !doc_buffer->lyxvc().inUse();
1963 case LFUN_VC_RENAME:
1964 enable = doc_buffer && doc_buffer->lyxvc().renameEnabled();
1967 enable = doc_buffer && doc_buffer->lyxvc().copyEnabled();
1969 case LFUN_VC_CHECK_IN:
1970 enable = doc_buffer && doc_buffer->lyxvc().checkInEnabled();
1972 case LFUN_VC_CHECK_OUT:
1973 enable = doc_buffer && doc_buffer->lyxvc().checkOutEnabled();
1975 case LFUN_VC_LOCKING_TOGGLE:
1976 enable = doc_buffer && !doc_buffer->isReadonly()
1977 && doc_buffer->lyxvc().lockingToggleEnabled();
1978 flag.setOnOff(enable && doc_buffer->lyxvc().locking());
1980 case LFUN_VC_REVERT:
1981 enable = doc_buffer && doc_buffer->lyxvc().inUse() && !doc_buffer->isReadonly();
1983 case LFUN_VC_UNDO_LAST:
1984 enable = doc_buffer && doc_buffer->lyxvc().undoLastEnabled();
1986 case LFUN_VC_REPO_UPDATE:
1987 enable = doc_buffer && doc_buffer->lyxvc().repoUpdateEnabled();
1989 case LFUN_VC_COMMAND: {
1990 if (cmd.argument().empty())
1992 if (!doc_buffer && contains(cmd.getArg(0), 'D'))
1996 case LFUN_VC_COMPARE:
1997 enable = doc_buffer && doc_buffer->lyxvc().prepareFileRevisionEnabled();
2000 case LFUN_SERVER_GOTO_FILE_ROW:
2002 case LFUN_FORWARD_SEARCH:
2003 enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty());
2006 case LFUN_FILE_INSERT_PLAINTEXT:
2007 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
2008 enable = documentBufferView() && documentBufferView()->cursor().inTexted();
2011 case LFUN_SPELLING_CONTINUOUSLY:
2012 flag.setOnOff(lyxrc.spellcheck_continuously);
2020 flag.setEnabled(false);
2026 static FileName selectTemplateFile()
2028 FileDialog dlg(qt_("Select template file"));
2029 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2030 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2032 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
2033 QStringList(qt_("LyX Documents (*.lyx)")));
2035 if (result.first == FileDialog::Later)
2037 if (result.second.isEmpty())
2039 return FileName(fromqstr(result.second));
2043 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
2047 Buffer * newBuffer = 0;
2049 newBuffer = checkAndLoadLyXFile(filename);
2050 } catch (ExceptionMessage const & e) {
2057 message(_("Document not loaded."));
2061 setBuffer(newBuffer);
2062 newBuffer->errors("Parse");
2065 theSession().lastFiles().add(filename);
2071 void GuiView::openDocument(string const & fname)
2073 string initpath = lyxrc.document_path;
2075 if (documentBufferView()) {
2076 string const trypath = documentBufferView()->buffer().filePath();
2077 // If directory is writeable, use this as default.
2078 if (FileName(trypath).isDirWritable())
2084 if (fname.empty()) {
2085 FileDialog dlg(qt_("Select document to open"));
2086 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2087 dlg.setButton2(qt_("Examples|#E#e"),
2088 toqstr(addPath(package().system_support().absFileName(), "examples")));
2090 QStringList const filter(qt_("LyX Documents (*.lyx)"));
2091 FileDialog::Result result =
2092 dlg.open(toqstr(initpath), filter);
2094 if (result.first == FileDialog::Later)
2097 filename = fromqstr(result.second);
2099 // check selected filename
2100 if (filename.empty()) {
2101 message(_("Canceled."));
2107 // get absolute path of file and add ".lyx" to the filename if
2109 FileName const fullname =
2110 fileSearch(string(), filename, "lyx", support::may_not_exist);
2111 if (!fullname.empty())
2112 filename = fullname.absFileName();
2114 if (!fullname.onlyPath().isDirectory()) {
2115 Alert::warning(_("Invalid filename"),
2116 bformat(_("The directory in the given path\n%1$s\ndoes not exist."),
2117 from_utf8(fullname.absFileName())));
2121 // if the file doesn't exist and isn't already open (bug 6645),
2122 // let the user create one
2123 if (!fullname.exists() && !theBufferList().exists(fullname) &&
2124 !LyXVC::file_not_found_hook(fullname)) {
2125 // the user specifically chose this name. Believe him.
2126 Buffer * const b = newFile(filename, string(), true);
2132 docstring const disp_fn = makeDisplayPath(filename);
2133 message(bformat(_("Opening document %1$s..."), disp_fn));
2136 Buffer * buf = loadDocument(fullname);
2138 str2 = bformat(_("Document %1$s opened."), disp_fn);
2139 if (buf->lyxvc().inUse())
2140 str2 += " " + from_utf8(buf->lyxvc().versionString()) +
2141 " " + _("Version control detected.");
2143 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2148 // FIXME: clean that
2149 static bool import(GuiView * lv, FileName const & filename,
2150 string const & format, ErrorList & errorList)
2152 FileName const lyxfile(support::changeExtension(filename.absFileName(), ".lyx"));
2154 string loader_format;
2155 vector<string> loaders = theConverters().loaders();
2156 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
2157 vector<string>::const_iterator it = loaders.begin();
2158 vector<string>::const_iterator en = loaders.end();
2159 for (; it != en; ++it) {
2160 if (!theConverters().isReachable(format, *it))
2163 string const tofile =
2164 support::changeExtension(filename.absFileName(),
2165 formats.extension(*it));
2166 if (!theConverters().convert(0, filename, FileName(tofile),
2167 filename, format, *it, errorList))
2169 loader_format = *it;
2172 if (loader_format.empty()) {
2173 frontend::Alert::error(_("Couldn't import file"),
2174 bformat(_("No information for importing the format %1$s."),
2175 formats.prettyName(format)));
2179 loader_format = format;
2181 if (loader_format == "lyx") {
2182 Buffer * buf = lv->loadDocument(lyxfile);
2186 Buffer * const b = newFile(lyxfile.absFileName(), string(), true);
2190 bool as_paragraphs = loader_format == "textparagraph";
2191 string filename2 = (loader_format == format) ? filename.absFileName()
2192 : support::changeExtension(filename.absFileName(),
2193 formats.extension(loader_format));
2194 lv->currentBufferView()->insertPlaintextFile(FileName(filename2),
2196 guiApp->setCurrentView(lv);
2197 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
2204 void GuiView::importDocument(string const & argument)
2207 string filename = split(argument, format, ' ');
2209 LYXERR(Debug::INFO, format << " file: " << filename);
2211 // need user interaction
2212 if (filename.empty()) {
2213 string initpath = lyxrc.document_path;
2214 if (documentBufferView()) {
2215 string const trypath = documentBufferView()->buffer().filePath();
2216 // If directory is writeable, use this as default.
2217 if (FileName(trypath).isDirWritable())
2221 docstring const text = bformat(_("Select %1$s file to import"),
2222 formats.prettyName(format));
2224 FileDialog dlg(toqstr(text));
2225 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2226 dlg.setButton2(qt_("Examples|#E#e"),
2227 toqstr(addPath(package().system_support().absFileName(), "examples")));
2229 docstring filter = formats.prettyName(format);
2232 filter += from_utf8(formats.extensions(format));
2235 FileDialog::Result result =
2236 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
2238 if (result.first == FileDialog::Later)
2241 filename = fromqstr(result.second);
2243 // check selected filename
2244 if (filename.empty())
2245 message(_("Canceled."));
2248 if (filename.empty())
2251 // get absolute path of file
2252 FileName const fullname(support::makeAbsPath(filename));
2254 // Can happen if the user entered a path into the dialog
2256 if (fullname.onlyFileName().empty()) {
2257 docstring msg = bformat(_("The file name '%1$s' is invalid!\n"
2258 "Aborting import."),
2259 from_utf8(fullname.absFileName()));
2260 frontend::Alert::error(_("File name error"), msg);
2261 message(_("Canceled."));
2266 FileName const lyxfile(support::changeExtension(fullname.absFileName(), ".lyx"));
2268 // Check if the document already is open
2269 Buffer * buf = theBufferList().getBuffer(lyxfile);
2272 if (!closeBuffer()) {
2273 message(_("Canceled."));
2278 docstring const displaypath = makeDisplayPath(lyxfile.absFileName(), 30);
2280 // if the file exists already, and we didn't do
2281 // -i lyx thefile.lyx, warn
2282 if (lyxfile.exists() && fullname != lyxfile) {
2284 docstring text = bformat(_("The document %1$s already exists.\n\n"
2285 "Do you want to overwrite that document?"), displaypath);
2286 int const ret = Alert::prompt(_("Overwrite document?"),
2287 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2290 message(_("Canceled."));
2295 message(bformat(_("Importing %1$s..."), displaypath));
2296 ErrorList errorList;
2297 if (import(this, fullname, format, errorList))
2298 message(_("imported."));
2300 message(_("file not imported!"));
2302 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2306 void GuiView::newDocument(string const & filename, bool from_template)
2308 FileName initpath(lyxrc.document_path);
2309 if (documentBufferView()) {
2310 FileName const trypath(documentBufferView()->buffer().filePath());
2311 // If directory is writeable, use this as default.
2312 if (trypath.isDirWritable())
2316 string templatefile;
2317 if (from_template) {
2318 templatefile = selectTemplateFile().absFileName();
2319 if (templatefile.empty())
2324 if (filename.empty())
2325 b = newUnnamedFile(initpath, to_utf8(_("newfile")), templatefile);
2327 b = newFile(filename, templatefile, true);
2332 // If no new document could be created, it is unsure
2333 // whether there is a valid BufferView.
2334 if (currentBufferView())
2335 // Ensure the cursor is correctly positioned on screen.
2336 currentBufferView()->showCursor();
2340 void GuiView::insertLyXFile(docstring const & fname)
2342 BufferView * bv = documentBufferView();
2347 FileName filename(to_utf8(fname));
2348 if (filename.empty()) {
2349 // Launch a file browser
2351 string initpath = lyxrc.document_path;
2352 string const trypath = bv->buffer().filePath();
2353 // If directory is writeable, use this as default.
2354 if (FileName(trypath).isDirWritable())
2358 FileDialog dlg(qt_("Select LyX document to insert"));
2359 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2360 dlg.setButton2(qt_("Examples|#E#e"),
2361 toqstr(addPath(package().system_support().absFileName(),
2364 FileDialog::Result result = dlg.open(toqstr(initpath),
2365 QStringList(qt_("LyX Documents (*.lyx)")));
2367 if (result.first == FileDialog::Later)
2371 filename.set(fromqstr(result.second));
2373 // check selected filename
2374 if (filename.empty()) {
2375 // emit message signal.
2376 message(_("Canceled."));
2381 bv->insertLyXFile(filename);
2382 bv->buffer().errors("Parse");
2386 bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kind)
2388 FileName fname = b.fileName();
2389 FileName const oldname = fname;
2391 if (!newname.empty()) {
2393 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFileName());
2395 // Switch to this Buffer.
2398 // No argument? Ask user through dialog.
2400 FileDialog dlg(qt_("Choose a filename to save document as"));
2401 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2402 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2404 if (!isLyXFileName(fname.absFileName()))
2405 fname.changeExtension(".lyx");
2407 FileDialog::Result result =
2408 dlg.save(toqstr(fname.onlyPath().absFileName()),
2409 QStringList(qt_("LyX Documents (*.lyx)")),
2410 toqstr(fname.onlyFileName()));
2412 if (result.first == FileDialog::Later)
2415 fname.set(fromqstr(result.second));
2420 if (!isLyXFileName(fname.absFileName()))
2421 fname.changeExtension(".lyx");
2424 // fname is now the new Buffer location.
2426 // if there is already a Buffer open with this name, we do not want
2427 // to have another one. (the second test makes sure we're not just
2428 // trying to overwrite ourselves, which is fine.)
2429 if (theBufferList().exists(fname) && fname != oldname
2430 && theBufferList().getBuffer(fname) != &b) {
2431 docstring const text =
2432 bformat(_("The file\n%1$s\nis already open in your current session.\n"
2433 "Please close it before attempting to overwrite it.\n"
2434 "Do you want to choose a new filename?"),
2435 from_utf8(fname.absFileName()));
2436 int const ret = Alert::prompt(_("Chosen File Already Open"),
2437 text, 0, 1, _("&Rename"), _("&Cancel"));
2439 case 0: return renameBuffer(b, docstring(), kind);
2440 case 1: return false;
2445 bool const existsLocal = fname.exists();
2446 bool const existsInVC = LyXVC::fileInVC(fname);
2447 if (existsLocal || existsInVC) {
2448 docstring const file = makeDisplayPath(fname.absFileName(), 30);
2449 if (kind != LV_WRITE_AS && existsInVC) {
2450 // renaming to a name that is already in VC
2452 docstring text = bformat(_("The document %1$s "
2453 "is already registered.\n\n"
2454 "Do you want to choose a new name?"),
2456 docstring const title = (kind == LV_VC_RENAME) ?
2457 _("Rename document?") : _("Copy document?");
2458 docstring const button = (kind == LV_VC_RENAME) ?
2459 _("&Rename") : _("&Copy");
2460 int const ret = Alert::prompt(title, text, 0, 1,
2461 button, _("&Cancel"));
2463 case 0: return renameBuffer(b, docstring(), kind);
2464 case 1: return false;
2469 docstring text = bformat(_("The document %1$s "
2470 "already exists.\n\n"
2471 "Do you want to overwrite that document?"),
2473 int const ret = Alert::prompt(_("Overwrite document?"),
2474 text, 0, 2, _("&Overwrite"),
2475 _("&Rename"), _("&Cancel"));
2478 case 1: return renameBuffer(b, docstring(), kind);
2479 case 2: return false;
2485 case LV_VC_RENAME: {
2486 string msg = b.lyxvc().rename(fname);
2489 message(from_utf8(msg));
2493 string msg = b.lyxvc().copy(fname);
2496 message(from_utf8(msg));
2502 // LyXVC created the file already in case of LV_VC_RENAME or
2503 // LV_VC_COPY, but call saveBuffer() nevertheless to get
2504 // relative paths of included stuff right if we moved e.g. from
2505 // /a/b.lyx to /a/c/b.lyx.
2507 bool const saved = saveBuffer(b, fname);
2514 struct PrettyNameComparator
2516 bool operator()(Format const *first, Format const *second) const {
2517 return compare_no_case(translateIfPossible(from_ascii(first->prettyname())),
2518 translateIfPossible(from_ascii(second->prettyname()))) <= 0;
2523 bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
2525 FileName fname = b.fileName();
2527 FileDialog dlg(qt_("Choose a filename to export the document as"));
2528 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2531 QString const anyformat = qt_("Guess from extension (*.*)");
2533 Formats::const_iterator it = formats.begin();
2534 vector<Format const *> export_formats;
2535 for (; it != formats.end(); ++it)
2536 if (it->documentFormat())
2537 export_formats.push_back(&(*it));
2538 PrettyNameComparator cmp;
2539 sort(export_formats.begin(), export_formats.end(), cmp);
2540 vector<Format const *>::const_iterator fit = export_formats.begin();
2541 map<QString, string> fmap;
2544 for (; fit != export_formats.end(); ++fit) {
2545 docstring const loc_prettyname =
2546 translateIfPossible(from_utf8((*fit)->prettyname()));
2547 QString const loc_filter = toqstr(bformat(from_ascii("%1$s (*.%2$s)"),
2549 from_ascii((*fit)->extension())));
2550 types << loc_filter;
2551 fmap[loc_filter] = (*fit)->name();
2552 if (from_ascii((*fit)->name()) == iformat) {
2553 filter = loc_filter;
2554 ext = (*fit)->extension();
2557 string ofname = fname.onlyFileName();
2559 ofname = support::changeExtension(ofname, ext);
2560 FileDialog::Result result =
2561 dlg.save(toqstr(fname.onlyPath().absFileName()),
2565 if (result.first != FileDialog::Chosen)
2569 fname.set(fromqstr(result.second));
2570 if (filter == anyformat)
2571 fmt_name = formats.getFormatFromExtension(fname.extension());
2573 fmt_name = fmap[filter];
2574 LYXERR(Debug::FILES, "filter=" << fromqstr(filter)
2575 << ", fmt_name=" << fmt_name << ", fname=" << fname.absFileName());
2577 if (fmt_name.empty() || fname.empty())
2580 // fname is now the new Buffer location.
2581 if (FileName(fname).exists()) {
2582 docstring const file = makeDisplayPath(fname.absFileName(), 30);
2583 docstring text = bformat(_("The document %1$s already "
2584 "exists.\n\nDo you want to "
2585 "overwrite that document?"),
2587 int const ret = Alert::prompt(_("Overwrite document?"),
2588 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
2591 case 1: return exportBufferAs(b, from_ascii(fmt_name));
2592 case 2: return false;
2596 FuncRequest cmd(LFUN_BUFFER_EXPORT, fmt_name + " " + fname.absFileName());
2599 return dr.dispatched();
2603 bool GuiView::saveBuffer(Buffer & b)
2605 return saveBuffer(b, FileName());
2609 bool GuiView::saveBuffer(Buffer & b, FileName const & fn)
2611 if (workArea(b) && workArea(b)->inDialogMode())
2614 if (fn.empty() && b.isUnnamed())
2615 return renameBuffer(b, docstring());
2617 bool const success = (fn.empty() ? b.save() : b.saveAs(fn));
2619 theSession().lastFiles().add(b.fileName());
2623 // Switch to this Buffer.
2626 // FIXME: we don't tell the user *WHY* the save failed !!
2627 docstring const file = makeDisplayPath(b.absFileName(), 30);
2628 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
2629 "Do you want to rename the document and "
2630 "try again?"), file);
2631 int const ret = Alert::prompt(_("Rename and save?"),
2632 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
2635 if (!renameBuffer(b, docstring()))
2644 return saveBuffer(b, fn);
2648 bool GuiView::hideWorkArea(GuiWorkArea * wa)
2650 return closeWorkArea(wa, false);
2654 // We only want to close the buffer if it is not visible in other workareas
2655 // of the same view, nor in other views, and if this is not a child
2656 bool GuiView::closeWorkArea(GuiWorkArea * wa)
2658 Buffer & buf = wa->bufferView().buffer();
2660 bool last_wa = d.countWorkAreasOf(buf) == 1
2661 && !inOtherView(buf) && !buf.parent();
2663 bool close_buffer = last_wa;
2666 if (lyxrc.close_buffer_with_last_view == "yes")
2668 else if (lyxrc.close_buffer_with_last_view == "no")
2669 close_buffer = false;
2672 if (buf.isUnnamed())
2673 file = from_utf8(buf.fileName().onlyFileName());
2675 file = buf.fileName().displayName(30);
2676 docstring const text = bformat(
2677 _("Last view on document %1$s is being closed.\n"
2678 "Would you like to close or hide the document?\n"
2680 "Hidden documents can be displayed back through\n"
2681 "the menu: View->Hidden->...\n"
2683 "To remove this question, set your preference in:\n"
2684 " Tools->Preferences->Look&Feel->UserInterface\n"
2686 int ret = Alert::prompt(_("Close or hide document?"),
2687 text, 0, 1, _("&Close"), _("&Hide"));
2688 close_buffer = (ret == 0);
2692 return closeWorkArea(wa, close_buffer);
2696 bool GuiView::closeBuffer()
2698 GuiWorkArea * wa = currentMainWorkArea();
2699 setCurrentWorkArea(wa);
2700 Buffer & buf = wa->bufferView().buffer();
2701 return wa && closeWorkArea(wa, !buf.parent());
2705 void GuiView::writeSession() const {
2706 GuiWorkArea const * active_wa = currentMainWorkArea();
2707 for (int i = 0; i < d.splitter_->count(); ++i) {
2708 TabWorkArea * twa = d.tabWorkArea(i);
2709 for (int j = 0; j < twa->count(); ++j) {
2710 GuiWorkArea * wa = static_cast<GuiWorkArea *>(twa->widget(j));
2711 Buffer & buf = wa->bufferView().buffer();
2712 theSession().lastOpened().add(buf.fileName(), wa == active_wa);
2718 bool GuiView::closeBufferAll()
2720 // Close the workareas in all other views
2721 QList<int> const ids = guiApp->viewIds();
2722 for (int i = 0; i != ids.size(); ++i) {
2723 if (id_ != ids[i] && !guiApp->view(ids[i]).closeWorkAreaAll())
2727 // Close our own workareas
2728 if (!closeWorkAreaAll())
2731 // Now close the hidden buffers. We prevent hidden buffers from being
2732 // dirty, so we can just close them.
2733 theBufferList().closeAll();
2738 bool GuiView::closeWorkAreaAll()
2740 setCurrentWorkArea(currentMainWorkArea());
2742 // We might be in a situation that there is still a tabWorkArea, but
2743 // there are no tabs anymore. This can happen when we get here after a
2744 // TabWorkArea::lastWorkAreaRemoved() signal. Therefore we count how
2745 // many TabWorkArea's have no documents anymore.
2748 // We have to call count() each time, because it can happen that
2749 // more than one splitter will disappear in one iteration (bug 5998).
2750 for (; d.splitter_->count() > empty_twa; ) {
2751 TabWorkArea * twa = d.tabWorkArea(empty_twa);
2753 if (twa->count() == 0)
2756 setCurrentWorkArea(twa->currentWorkArea());
2757 if (!closeTabWorkArea(twa))
2765 bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
2770 Buffer & buf = wa->bufferView().buffer();
2772 if (close_buffer && GuiViewPrivate::busyBuffers.contains(&buf)) {
2773 Alert::warning(_("Close document"),
2774 _("Document could not be closed because it is being processed by LyX."));
2779 return closeBuffer(buf);
2781 if (!inMultiTabs(wa))
2782 if (!saveBufferIfNeeded(buf, true))
2790 bool GuiView::closeBuffer(Buffer & buf)
2792 // If we are in a close_event all children will be closed in some time,
2793 // so no need to do it here. This will ensure that the children end up
2794 // in the session file in the correct order. If we close the master
2795 // buffer, we can close or release the child buffers here too.
2796 bool success = true;
2798 ListOfBuffers clist = buf.getChildren();
2799 ListOfBuffers::const_iterator it = clist.begin();
2800 ListOfBuffers::const_iterator const bend = clist.end();
2801 for (; it != bend; ++it) {
2802 // If a child is dirty, do not close
2803 // without user intervention
2804 //FIXME: should we look in other tabworkareas?
2805 Buffer * child_buf = *it;
2806 GuiWorkArea * child_wa = workArea(*child_buf);
2808 if (!closeWorkArea(child_wa, true)) {
2813 theBufferList().releaseChild(&buf, child_buf);
2817 // goto bookmark to update bookmark pit.
2818 //FIXME: we should update only the bookmarks related to this buffer!
2819 LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
2820 for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
2821 guiApp->gotoBookmark(i+1, false, false);
2823 if (saveBufferIfNeeded(buf, false)) {
2824 buf.removeAutosaveFile();
2825 theBufferList().release(&buf);
2829 // open all children again to avoid a crash because of dangling
2830 // pointers (bug 6603)
2836 bool GuiView::closeTabWorkArea(TabWorkArea * twa)
2838 while (twa == d.currentTabWorkArea()) {
2839 twa->setCurrentIndex(twa->count()-1);
2841 GuiWorkArea * wa = twa->currentWorkArea();
2842 Buffer & b = wa->bufferView().buffer();
2844 // We only want to close the buffer if the same buffer is not visible
2845 // in another view, and if this is not a child and if we are closing
2846 // a view (not a tabgroup).
2847 bool const close_buffer =
2848 !inOtherView(b) && !b.parent() && closing_;
2850 if (!closeWorkArea(wa, close_buffer))
2857 bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding)
2859 if (buf.isClean() || buf.paragraphs().empty())
2862 // Switch to this Buffer.
2867 if (buf.isUnnamed())
2868 file = from_utf8(buf.fileName().onlyFileName());
2870 file = buf.fileName().displayName(30);
2872 // Bring this window to top before asking questions.
2877 if (hiding && buf.isUnnamed()) {
2878 docstring const text = bformat(_("The document %1$s has not been "
2879 "saved yet.\n\nDo you want to save "
2880 "the document?"), file);
2881 ret = Alert::prompt(_("Save new document?"),
2882 text, 0, 1, _("&Save"), _("&Cancel"));
2886 docstring const text = bformat(_("The document %1$s has unsaved changes."
2887 "\n\nDo you want to save the document or discard the changes?"), file);
2888 ret = Alert::prompt(_("Save changed document?"),
2889 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
2894 if (!saveBuffer(buf))
2898 // If we crash after this we could have no autosave file
2899 // but I guess this is really improbable (Jug).
2900 // Sometimes improbable things happen:
2901 // - see bug http://www.lyx.org/trac/ticket/6587 (ps)
2902 // buf.removeAutosaveFile();
2904 // revert all changes
2915 bool GuiView::inMultiTabs(GuiWorkArea * wa)
2917 Buffer & buf = wa->bufferView().buffer();
2919 for (int i = 0; i != d.splitter_->count(); ++i) {
2920 GuiWorkArea * wa_ = d.tabWorkArea(i)->workArea(buf);
2921 if (wa_ && wa_ != wa)
2924 return inOtherView(buf);
2928 bool GuiView::inOtherView(Buffer & buf)
2930 QList<int> const ids = guiApp->viewIds();
2932 for (int i = 0; i != ids.size(); ++i) {
2936 if (guiApp->view(ids[i]).workArea(buf))
2943 void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np, bool const move)
2945 if (!documentBufferView())
2948 if (TabWorkArea * twa = d.currentTabWorkArea()) {
2949 Buffer * const curbuf = &documentBufferView()->buffer();
2950 int nwa = twa->count();
2951 for (int i = 0; i < nwa; ++i) {
2952 if (&workArea(i)->bufferView().buffer() == curbuf) {
2954 if (np == NEXTBUFFER)
2955 next_index = (i == nwa - 1 ? 0 : i + 1);
2957 next_index = (i == 0 ? nwa - 1 : i - 1);
2959 twa->moveTab(i, next_index);
2961 setBuffer(&workArea(next_index)->bufferView().buffer());
2969 /// make sure the document is saved
2970 static bool ensureBufferClean(Buffer * buffer)
2972 LASSERT(buffer, return false);
2973 if (buffer->isClean() && !buffer->isUnnamed())
2976 docstring const file = buffer->fileName().displayName(30);
2979 if (!buffer->isUnnamed()) {
2980 text = bformat(_("The document %1$s has unsaved "
2981 "changes.\n\nDo you want to save "
2982 "the document?"), file);
2983 title = _("Save changed document?");
2986 text = bformat(_("The document %1$s has not been "
2987 "saved yet.\n\nDo you want to save "
2988 "the document?"), file);
2989 title = _("Save new document?");
2991 int const ret = Alert::prompt(title, text, 0, 1, _("&Save"), _("&Cancel"));
2994 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
2996 return buffer->isClean() && !buffer->isUnnamed();
3000 bool GuiView::reloadBuffer(Buffer & buf)
3002 Buffer::ReadStatus status = buf.reload();
3003 return status == Buffer::ReadSuccess;
3007 void GuiView::checkExternallyModifiedBuffers()
3009 BufferList::iterator bit = theBufferList().begin();
3010 BufferList::iterator const bend = theBufferList().end();
3011 for (; bit != bend; ++bit) {
3012 Buffer * buf = *bit;
3013 if (buf->fileName().exists()
3014 && buf->isExternallyModified(Buffer::checksum_method)) {
3015 docstring text = bformat(_("Document \n%1$s\n has been externally modified."
3016 " Reload now? Any local changes will be lost."),
3017 from_utf8(buf->absFileName()));
3018 int const ret = Alert::prompt(_("Reload externally changed document?"),
3019 text, 0, 1, _("&Reload"), _("&Cancel"));
3027 void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
3029 Buffer * buffer = documentBufferView()
3030 ? &(documentBufferView()->buffer()) : 0;
3032 switch (cmd.action()) {
3033 case LFUN_VC_REGISTER:
3034 if (!buffer || !ensureBufferClean(buffer))
3036 if (!buffer->lyxvc().inUse()) {
3037 if (buffer->lyxvc().registrer()) {
3038 reloadBuffer(*buffer);
3039 dr.clearMessageUpdate();
3044 case LFUN_VC_RENAME:
3045 case LFUN_VC_COPY: {
3046 if (!buffer || !ensureBufferClean(buffer))
3048 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
3049 if (buffer->lyxvc().isCheckInWithConfirmation()) {
3050 // Some changes are not yet committed.
3051 // We test here and not in getStatus(), since
3052 // this test is expensive.
3054 LyXVC::CommandResult ret =
3055 buffer->lyxvc().checkIn(log);
3057 if (ret == LyXVC::ErrorCommand ||
3058 ret == LyXVC::VCSuccess)
3059 reloadBuffer(*buffer);
3060 if (buffer->lyxvc().isCheckInWithConfirmation()) {
3061 frontend::Alert::error(
3062 _("Revision control error."),
3063 _("Document could not be checked in."));
3067 RenameKind const kind = (cmd.action() == LFUN_VC_RENAME) ?
3068 LV_VC_RENAME : LV_VC_COPY;
3069 renameBuffer(*buffer, cmd.argument(), kind);
3074 case LFUN_VC_CHECK_IN:
3075 if (!buffer || !ensureBufferClean(buffer))
3077 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
3079 LyXVC::CommandResult ret = buffer->lyxvc().checkIn(log);
3081 // Only skip reloading if the checkin was cancelled or
3082 // an error occurred before the real checkin VCS command
3083 // was executed, since the VCS might have changed the
3084 // file even if it could not checkin successfully.
3085 if (ret == LyXVC::ErrorCommand || ret == LyXVC::VCSuccess)
3086 reloadBuffer(*buffer);
3090 case LFUN_VC_CHECK_OUT:
3091 if (!buffer || !ensureBufferClean(buffer))
3093 if (buffer->lyxvc().inUse()) {
3094 dr.setMessage(buffer->lyxvc().checkOut());
3095 reloadBuffer(*buffer);
3099 case LFUN_VC_LOCKING_TOGGLE:
3100 LASSERT(buffer, return);
3101 if (!ensureBufferClean(buffer) || buffer->isReadonly())
3103 if (buffer->lyxvc().inUse()) {
3104 string res = buffer->lyxvc().lockingToggle();
3106 frontend::Alert::error(_("Revision control error."),
3107 _("Error when setting the locking property."));
3110 reloadBuffer(*buffer);
3115 case LFUN_VC_REVERT:
3116 LASSERT(buffer, return);
3117 if (buffer->lyxvc().revert()) {
3118 reloadBuffer(*buffer);
3119 dr.clearMessageUpdate();
3123 case LFUN_VC_UNDO_LAST:
3124 LASSERT(buffer, return);
3125 buffer->lyxvc().undoLast();
3126 reloadBuffer(*buffer);
3127 dr.clearMessageUpdate();
3130 case LFUN_VC_REPO_UPDATE:
3131 LASSERT(buffer, return);
3132 if (ensureBufferClean(buffer)) {
3133 dr.setMessage(buffer->lyxvc().repoUpdate());
3134 checkExternallyModifiedBuffers();
3138 case LFUN_VC_COMMAND: {
3139 string flag = cmd.getArg(0);
3140 if (buffer && contains(flag, 'R') && !ensureBufferClean(buffer))
3143 if (contains(flag, 'M')) {
3144 if (!Alert::askForText(message, _("LyX VC: Log Message")))
3147 string path = cmd.getArg(1);
3148 if (contains(path, "$$p") && buffer)
3149 path = subst(path, "$$p", buffer->filePath());
3150 LYXERR(Debug::LYXVC, "Directory: " << path);
3152 if (!pp.isReadableDirectory()) {
3153 lyxerr << _("Directory is not accessible.") << endl;
3156 support::PathChanger p(pp);
3158 string command = cmd.getArg(2);
3159 if (command.empty())
3162 command = subst(command, "$$i", buffer->absFileName());
3163 command = subst(command, "$$p", buffer->filePath());
3165 command = subst(command, "$$m", to_utf8(message));
3166 LYXERR(Debug::LYXVC, "Command: " << command);
3168 one.startscript(Systemcall::Wait, command);
3172 if (contains(flag, 'I'))
3173 buffer->markDirty();
3174 if (contains(flag, 'R'))
3175 reloadBuffer(*buffer);
3180 case LFUN_VC_COMPARE: {
3182 if (cmd.argument().empty()) {
3183 lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "comparehistory"));
3187 string rev1 = cmd.getArg(0);
3191 if (!buffer->lyxvc().prepareFileRevision(rev1, f1))
3194 if (isStrInt(rev1) && convert<int>(rev1) <= 0) {
3195 f2 = buffer->absFileName();
3197 string rev2 = cmd.getArg(1);
3201 if (!buffer->lyxvc().prepareFileRevision(rev2, f2))
3205 LYXERR(Debug::LYXVC, "Launching comparison for fetched revisions:\n" <<
3206 f1 << "\n" << f2 << "\n" );
3207 string par = "compare run " + quoteName(f1) + " " + quoteName(f2);
3208 lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, par));
3218 void GuiView::openChildDocument(string const & fname)
3220 LASSERT(documentBufferView(), return);
3221 Buffer & buffer = documentBufferView()->buffer();
3222 FileName const filename = support::makeAbsPath(fname, buffer.filePath());
3223 documentBufferView()->saveBookmark(false);
3225 if (theBufferList().exists(filename)) {
3226 child = theBufferList().getBuffer(filename);
3229 message(bformat(_("Opening child document %1$s..."),
3230 makeDisplayPath(filename.absFileName())));
3231 child = loadDocument(filename, false);
3233 // Set the parent name of the child document.
3234 // This makes insertion of citations and references in the child work,
3235 // when the target is in the parent or another child document.
3237 child->setParent(&buffer);
3241 bool GuiView::goToFileRow(string const & argument)
3245 size_t i = argument.find_last_of(' ');
3246 if (i != string::npos) {
3247 file_name = os::internal_path(trim(argument.substr(0, i)));
3248 istringstream is(argument.substr(i + 1));
3253 if (i == string::npos) {
3254 LYXERR0("Wrong argument: " << argument);
3258 string const abstmp = package().temp_dir().absFileName();
3259 string const realtmp = package().temp_dir().realPath();
3260 // We have to use os::path_prefix_is() here, instead of
3261 // simply prefixIs(), because the file name comes from
3262 // an external application and may need case adjustment.
3263 if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
3264 || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
3265 // Needed by inverse dvi search. If it is a file
3266 // in tmpdir, call the apropriated function.
3267 // If tmpdir is a symlink, we may have the real
3268 // path passed back, so we correct for that.
3269 if (!prefixIs(file_name, abstmp))
3270 file_name = subst(file_name, realtmp, abstmp);
3271 buf = theBufferList().getBufferFromTmp(file_name);
3273 // Must replace extension of the file to be .lyx
3274 // and get full path
3275 FileName const s = fileSearch(string(),
3276 support::changeExtension(file_name, ".lyx"), "lyx");
3277 // Either change buffer or load the file
3278 if (theBufferList().exists(s))
3279 buf = theBufferList().getBuffer(s);
3280 else if (s.exists()) {
3281 buf = loadDocument(s);
3286 _("File does not exist: %1$s"),
3287 makeDisplayPath(file_name)));
3293 _("No buffer for file: %1$s."),
3294 makeDisplayPath(file_name))
3299 documentBufferView()->setCursorFromRow(row);
3305 Buffer::ExportStatus GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * clone, string const & format)
3307 Buffer::ExportStatus const status = func(format);
3309 // the cloning operation will have produced a clone of the entire set of
3310 // documents, starting from the master. so we must delete those.
3311 Buffer * mbuf = const_cast<Buffer *>(clone->masterBuffer());
3313 busyBuffers.remove(orig);
3318 Buffer::ExportStatus GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3320 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
3321 return runAndDestroy(lyx::bind(mem_func, clone, _1, true), orig, clone, format);
3325 Buffer::ExportStatus GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3327 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
3328 return runAndDestroy(lyx::bind(mem_func, clone, _1, false), orig, clone, format);
3332 Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3334 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &) const = &Buffer::preview;
3335 return runAndDestroy(lyx::bind(mem_func, clone, _1), orig, clone, format);
3339 bool GuiView::GuiViewPrivate::asyncBufferProcessing(
3340 string const & argument,
3341 Buffer const * used_buffer,
3342 docstring const & msg,
3343 Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
3344 Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
3345 Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const)
3350 string format = argument;
3352 format = used_buffer->params().getDefaultOutputFormat();
3353 processing_format = format;
3355 progress_->clearMessages();
3358 #if EXPORT_in_THREAD
3359 GuiViewPrivate::busyBuffers.insert(used_buffer);
3360 Buffer * cloned_buffer = used_buffer->cloneFromMaster();
3361 if (!cloned_buffer) {
3362 Alert::error(_("Export Error"),
3363 _("Error cloning the Buffer."));
3366 QFuture<Buffer::ExportStatus> f = QtConcurrent::run(
3371 setPreviewFuture(f);
3372 last_export_format = used_buffer->params().bufferFormat();
3375 // We are asynchronous, so we don't know here anything about the success
3378 Buffer::ExportStatus status;
3380 // TODO check here if it breaks exporting with Qt < 4.4
3381 status = (used_buffer->*syncFunc)(format, true);
3382 } else if (previewFunc) {
3383 status = (used_buffer->*previewFunc)(format);
3386 handleExportStatus(gv_, status, format);
3388 return (status == Buffer::ExportSuccess
3389 || status == Buffer::PreviewSuccess);
3393 void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr)
3395 BufferView * bv = currentBufferView();
3396 LASSERT(bv, return);
3398 // Let the current BufferView dispatch its own actions.
3399 bv->dispatch(cmd, dr);
3400 if (dr.dispatched())
3403 // Try with the document BufferView dispatch if any.
3404 BufferView * doc_bv = documentBufferView();
3405 if (doc_bv && doc_bv != bv) {
3406 doc_bv->dispatch(cmd, dr);
3407 if (dr.dispatched())
3411 // Then let the current Cursor dispatch its own actions.
3412 bv->cursor().dispatch(cmd);
3414 // update completion. We do it here and not in
3415 // processKeySym to avoid another redraw just for a
3416 // changed inline completion
3417 if (cmd.origin() == FuncRequest::KEYBOARD) {
3418 if (cmd.action() == LFUN_SELF_INSERT
3419 || (cmd.action() == LFUN_ERT_INSERT && bv->cursor().inMathed()))
3420 updateCompletion(bv->cursor(), true, true);
3421 else if (cmd.action() == LFUN_CHAR_DELETE_BACKWARD)
3422 updateCompletion(bv->cursor(), false, true);
3424 updateCompletion(bv->cursor(), false, false);
3427 dr = bv->cursor().result();
3431 void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
3433 BufferView * bv = currentBufferView();
3434 // By default we won't need any update.
3435 dr.screenUpdate(Update::None);
3436 // assume cmd will be dispatched
3437 dr.dispatched(true);
3439 Buffer * doc_buffer = documentBufferView()
3440 ? &(documentBufferView()->buffer()) : 0;
3442 if (cmd.origin() == FuncRequest::TOC) {
3443 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
3444 // FIXME: do we need to pass a DispatchResult object here?
3445 toc->doDispatch(bv->cursor(), cmd);
3449 string const argument = to_utf8(cmd.argument());
3451 switch(cmd.action()) {
3452 case LFUN_BUFFER_CHILD_OPEN:
3453 openChildDocument(to_utf8(cmd.argument()));
3456 case LFUN_BUFFER_IMPORT:
3457 importDocument(to_utf8(cmd.argument()));
3460 case LFUN_BUFFER_EXPORT: {
3463 FileName target_dir = doc_buffer->fileName().onlyPath();
3464 string const dest = cmd.getArg(1);
3465 if (!dest.empty() && FileName::isAbsolute(dest))
3466 target_dir = FileName(support::onlyPath(dest));
3467 // GCC only sees strfwd.h when building merged
3468 if (::lyx::operator==(cmd.argument(), "custom")) {
3469 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
3472 if (!target_dir.isDirWritable()) {
3473 exportBufferAs(*doc_buffer, cmd.argument());
3476 /* TODO/Review: Is it a problem to also export the children?
3477 See the update_unincluded flag */
3478 d.asyncBufferProcessing(argument,
3481 &GuiViewPrivate::exportAndDestroy,
3484 // TODO Inform user about success
3488 case LFUN_BUFFER_EXPORT_AS: {
3489 LASSERT(doc_buffer, break);
3490 docstring f = cmd.argument();
3492 f = from_ascii(doc_buffer->params().getDefaultOutputFormat());
3493 exportBufferAs(*doc_buffer, f);
3497 case LFUN_BUFFER_UPDATE: {
3498 d.asyncBufferProcessing(argument,
3501 &GuiViewPrivate::compileAndDestroy,
3506 case LFUN_BUFFER_VIEW: {
3507 d.asyncBufferProcessing(argument,
3509 _("Previewing ..."),
3510 &GuiViewPrivate::previewAndDestroy,
3515 case LFUN_MASTER_BUFFER_UPDATE: {
3516 d.asyncBufferProcessing(argument,
3517 (doc_buffer ? doc_buffer->masterBuffer() : 0),
3519 &GuiViewPrivate::compileAndDestroy,
3524 case LFUN_MASTER_BUFFER_VIEW: {
3525 d.asyncBufferProcessing(argument,
3526 (doc_buffer ? doc_buffer->masterBuffer() : 0),
3528 &GuiViewPrivate::previewAndDestroy,
3529 0, &Buffer::preview);
3532 case LFUN_BUFFER_SWITCH: {
3533 string const file_name = to_utf8(cmd.argument());
3534 if (!FileName::isAbsolute(file_name)) {
3536 dr.setMessage(_("Absolute filename expected."));
3540 Buffer * buffer = theBufferList().getBuffer(FileName(file_name));
3543 dr.setMessage(_("Document not loaded"));
3547 // Do we open or switch to the buffer in this view ?
3548 if (workArea(*buffer)
3549 || lyxrc.open_buffers_in_tabs || !documentBufferView()) {
3554 // Look for the buffer in other views
3555 QList<int> const ids = guiApp->viewIds();
3557 for (; i != ids.size(); ++i) {
3558 GuiView & gv = guiApp->view(ids[i]);
3559 if (gv.workArea(*buffer)) {
3560 gv.activateWindow();
3561 gv.setBuffer(buffer);
3566 // If necessary, open a new window as a last resort
3567 if (i == ids.size()) {
3568 lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW));
3574 case LFUN_BUFFER_NEXT:
3575 gotoNextOrPreviousBuffer(NEXTBUFFER, false);
3578 case LFUN_BUFFER_MOVE_NEXT:
3579 gotoNextOrPreviousBuffer(NEXTBUFFER, true);
3582 case LFUN_BUFFER_PREVIOUS:
3583 gotoNextOrPreviousBuffer(PREVBUFFER, false);
3586 case LFUN_BUFFER_MOVE_PREVIOUS:
3587 gotoNextOrPreviousBuffer(PREVBUFFER, true);
3590 case LFUN_COMMAND_EXECUTE: {
3591 bool const show_it = cmd.argument() != "off";
3592 // FIXME: this is a hack, "minibuffer" should not be
3594 if (GuiToolbar * t = toolbar("minibuffer")) {
3595 t->setVisible(show_it);
3596 if (show_it && t->commandBuffer())
3597 t->commandBuffer()->setFocus();
3601 case LFUN_DROP_LAYOUTS_CHOICE:
3602 d.layout_->showPopup();
3605 case LFUN_MENU_OPEN:
3606 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
3607 menu->exec(QCursor::pos());
3610 case LFUN_FILE_INSERT:
3611 insertLyXFile(cmd.argument());
3614 case LFUN_FILE_INSERT_PLAINTEXT:
3615 case LFUN_FILE_INSERT_PLAINTEXT_PARA: {
3616 string const fname = to_utf8(cmd.argument());
3617 if (!fname.empty() && !FileName::isAbsolute(fname)) {
3618 dr.setMessage(_("Absolute filename expected."));
3622 FileName filename(fname);
3623 if (fname.empty()) {
3624 FileDialog dlg(qt_("Select file to insert"));
3626 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
3627 QStringList(qt_("All Files (*)")));
3629 if (result.first == FileDialog::Later || result.second.isEmpty()) {
3630 dr.setMessage(_("Canceled."));
3634 filename.set(fromqstr(result.second));
3638 FuncRequest const new_cmd(cmd, filename.absoluteFilePath());
3639 bv->dispatch(new_cmd, dr);
3644 case LFUN_BUFFER_RELOAD: {
3645 LASSERT(doc_buffer, break);
3648 if (!doc_buffer->isClean()) {
3649 docstring const file =
3650 makeDisplayPath(doc_buffer->absFileName(), 20);
3651 docstring text = bformat(_("Any changes will be lost. "
3652 "Are you sure you want to revert to the saved version "
3653 "of the document %1$s?"), file);
3654 ret = Alert::prompt(_("Revert to saved document?"),
3655 text, 1, 1, _("&Revert"), _("&Cancel"));
3659 doc_buffer->markClean();
3660 reloadBuffer(*doc_buffer);
3661 dr.forceBufferUpdate();
3666 case LFUN_BUFFER_WRITE:
3667 LASSERT(doc_buffer, break);
3668 saveBuffer(*doc_buffer);
3671 case LFUN_BUFFER_WRITE_AS:
3672 LASSERT(doc_buffer, break);
3673 renameBuffer(*doc_buffer, cmd.argument());
3676 case LFUN_BUFFER_WRITE_ALL: {
3677 Buffer * first = theBufferList().first();
3680 message(_("Saving all documents..."));
3681 // We cannot use a for loop as the buffer list cycles.
3684 if (!b->isClean()) {
3686 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
3688 b = theBufferList().next(b);
3689 } while (b != first);
3690 dr.setMessage(_("All documents saved."));
3694 case LFUN_BUFFER_CLOSE:
3698 case LFUN_BUFFER_CLOSE_ALL:
3702 case LFUN_TOOLBAR_TOGGLE: {
3703 string const name = cmd.getArg(0);
3704 if (GuiToolbar * t = toolbar(name))
3709 case LFUN_DIALOG_UPDATE: {
3710 string const name = to_utf8(cmd.argument());
3711 if (name == "prefs" || name == "document")
3712 updateDialog(name, string());
3713 else if (name == "paragraph")
3714 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
3715 else if (currentBufferView()) {
3716 Inset * inset = currentBufferView()->editedInset(name);
3717 // Can only update a dialog connected to an existing inset
3719 // FIXME: get rid of this indirection; GuiView ask the inset
3720 // if he is kind enough to update itself...
3721 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
3722 //FIXME: pass DispatchResult here?
3723 inset->dispatch(currentBufferView()->cursor(), fr);
3729 case LFUN_DIALOG_TOGGLE: {
3730 FuncCode const func_code = isDialogVisible(cmd.getArg(0))
3731 ? LFUN_DIALOG_HIDE : LFUN_DIALOG_SHOW;
3732 dispatch(FuncRequest(func_code, cmd.argument()), dr);
3736 case LFUN_DIALOG_DISCONNECT_INSET:
3737 disconnectDialog(to_utf8(cmd.argument()));
3740 case LFUN_DIALOG_HIDE: {
3741 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
3745 case LFUN_DIALOG_SHOW: {
3746 string const name = cmd.getArg(0);
3747 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
3749 if (name == "character") {
3750 data = freefont2string();
3752 showDialog("character", data);
3753 } else if (name == "latexlog") {
3754 Buffer::LogType type;
3755 string const logfile = doc_buffer->logName(&type);
3757 case Buffer::latexlog:
3760 case Buffer::buildlog:
3764 data += Lexer::quoteString(logfile);
3765 showDialog("log", data);
3766 } else if (name == "vclog") {
3767 string const data = "vc " +
3768 Lexer::quoteString(doc_buffer->lyxvc().getLogFile());
3769 showDialog("log", data);
3770 } else if (name == "symbols") {
3771 data = bv->cursor().getEncoding()->name();
3773 showDialog("symbols", data);
3775 } else if (name == "prefs" && isFullScreen()) {
3776 lfunUiToggle("fullscreen");
3777 showDialog("prefs", data);
3779 showDialog(name, data);
3784 dr.setMessage(cmd.argument());
3787 case LFUN_UI_TOGGLE: {
3788 string arg = cmd.getArg(0);
3789 if (!lfunUiToggle(arg)) {
3790 docstring const msg = "ui-toggle " + _("%1$s unknown command!");
3791 dr.setMessage(bformat(msg, from_utf8(arg)));
3793 // Make sure the keyboard focus stays in the work area.
3798 case LFUN_VIEW_SPLIT: {
3799 LASSERT(doc_buffer, break);
3800 string const orientation = cmd.getArg(0);
3801 d.splitter_->setOrientation(orientation == "vertical"
3802 ? Qt::Vertical : Qt::Horizontal);
3803 TabWorkArea * twa = addTabWorkArea();
3804 GuiWorkArea * wa = twa->addWorkArea(*doc_buffer, *this);
3805 setCurrentWorkArea(wa);
3808 case LFUN_TAB_GROUP_CLOSE:
3809 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3810 closeTabWorkArea(twa);
3811 d.current_work_area_ = 0;
3812 twa = d.currentTabWorkArea();
3813 // Switch to the next GuiWorkArea in the found TabWorkArea.
3815 // Make sure the work area is up to date.
3816 setCurrentWorkArea(twa->currentWorkArea());
3818 setCurrentWorkArea(0);
3823 case LFUN_VIEW_CLOSE:
3824 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3825 closeWorkArea(twa->currentWorkArea());
3826 d.current_work_area_ = 0;
3827 twa = d.currentTabWorkArea();
3828 // Switch to the next GuiWorkArea in the found TabWorkArea.
3830 // Make sure the work area is up to date.
3831 setCurrentWorkArea(twa->currentWorkArea());
3833 setCurrentWorkArea(0);
3838 case LFUN_COMPLETION_INLINE:
3839 if (d.current_work_area_)
3840 d.current_work_area_->completer().showInline();
3843 case LFUN_COMPLETION_POPUP:
3844 if (d.current_work_area_)
3845 d.current_work_area_->completer().showPopup();
3850 if (d.current_work_area_)
3851 d.current_work_area_->completer().tab();
3854 case LFUN_COMPLETION_CANCEL:
3855 if (d.current_work_area_) {
3856 if (d.current_work_area_->completer().popupVisible())
3857 d.current_work_area_->completer().hidePopup();
3859 d.current_work_area_->completer().hideInline();
3863 case LFUN_COMPLETION_ACCEPT:
3864 if (d.current_work_area_)
3865 d.current_work_area_->completer().activate();
3868 case LFUN_BUFFER_ZOOM_IN:
3869 case LFUN_BUFFER_ZOOM_OUT:
3870 if (cmd.argument().empty()) {
3871 if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
3876 lyxrc.zoom += convert<int>(cmd.argument());
3878 if (lyxrc.zoom < 10)
3881 // The global QPixmapCache is used in GuiPainter to cache text
3882 // painting so we must reset it.
3883 QPixmapCache::clear();
3884 guiApp->fontLoader().update();
3885 lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
3888 case LFUN_VC_REGISTER:
3889 case LFUN_VC_RENAME:
3891 case LFUN_VC_CHECK_IN:
3892 case LFUN_VC_CHECK_OUT:
3893 case LFUN_VC_REPO_UPDATE:
3894 case LFUN_VC_LOCKING_TOGGLE:
3895 case LFUN_VC_REVERT:
3896 case LFUN_VC_UNDO_LAST:
3897 case LFUN_VC_COMMAND:
3898 case LFUN_VC_COMPARE:
3899 dispatchVC(cmd, dr);
3902 case LFUN_SERVER_GOTO_FILE_ROW:
3903 goToFileRow(to_utf8(cmd.argument()));
3906 case LFUN_FORWARD_SEARCH: {
3907 Buffer const * doc_master = doc_buffer->masterBuffer();
3908 FileName const path(doc_master->temppath());
3909 string const texname = doc_master->isChild(doc_buffer)
3910 ? DocFileName(changeExtension(
3911 doc_buffer->absFileName(),
3912 "tex")).mangledFileName()
3913 : doc_buffer->latexName();
3914 string const fulltexname =
3915 support::makeAbsPath(texname, doc_master->temppath()).absFileName();
3916 string const mastername =
3917 removeExtension(doc_master->latexName());
3918 FileName const dviname(addName(path.absFileName(),
3919 addExtension(mastername, "dvi")));
3920 FileName const pdfname(addName(path.absFileName(),
3921 addExtension(mastername, "pdf")));
3922 bool const have_dvi = dviname.exists();
3923 bool const have_pdf = pdfname.exists();
3924 if (!have_dvi && !have_pdf) {
3925 dr.setMessage(_("Please, preview the document first."));
3928 string outname = dviname.onlyFileName();
3929 string command = lyxrc.forward_search_dvi;
3930 if (!have_dvi || (have_pdf &&
3931 pdfname.lastModified() > dviname.lastModified())) {
3932 outname = pdfname.onlyFileName();
3933 command = lyxrc.forward_search_pdf;
3936 DocIterator tmpcur = bv->cursor();
3938 while (tmpcur.inMathed())
3940 int row = tmpcur.inMathed() ? 0 : doc_buffer->texrow().getRowFromIdPos(
3941 tmpcur.paragraph().id(), tmpcur.pos());
3942 LYXERR(Debug::ACTION, "Forward search: row:" << row
3943 << " id:" << tmpcur.paragraph().id());
3944 if (!row || command.empty()) {
3945 dr.setMessage(_("Couldn't proceed."));
3948 string texrow = convert<string>(row);
3950 command = subst(command, "$$n", texrow);
3951 command = subst(command, "$$f", fulltexname);
3952 command = subst(command, "$$t", texname);
3953 command = subst(command, "$$o", outname);
3955 PathChanger p(path);
3957 one.startscript(Systemcall::DontWait, command);
3961 case LFUN_SPELLING_CONTINUOUSLY:
3962 lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously;
3963 dr.screenUpdate(Update::Force | Update::FitCursor);
3967 // The LFUN must be for one of BufferView, Buffer or Cursor;
3969 dispatchToBufferView(cmd, dr);
3973 // Part of automatic menu appearance feature.
3974 if (isFullScreen()) {
3975 if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
3979 // Need to update bv because many LFUNs here might have destroyed it
3980 bv = currentBufferView();
3982 // Clear non-empty selections
3983 // (e.g. from a "char-forward-select" followed by "char-backward-select")
3985 Cursor & cur = bv->cursor();
3986 if ((cur.selection() && cur.selBegin() == cur.selEnd())) {
3987 cur.clearSelection();
3993 bool GuiView::lfunUiToggle(string const & ui_component)
3995 if (ui_component == "scrollbar") {
3996 // hide() is of no help
3997 if (d.current_work_area_->verticalScrollBarPolicy() ==
3998 Qt::ScrollBarAlwaysOff)
4000 d.current_work_area_->setVerticalScrollBarPolicy(
4001 Qt::ScrollBarAsNeeded);
4003 d.current_work_area_->setVerticalScrollBarPolicy(
4004 Qt::ScrollBarAlwaysOff);
4005 } else if (ui_component == "statusbar") {
4006 statusBar()->setVisible(!statusBar()->isVisible());
4007 } else if (ui_component == "menubar") {
4008 menuBar()->setVisible(!menuBar()->isVisible());
4010 if (ui_component == "frame") {
4012 getContentsMargins(&l, &t, &r, &b);
4013 //are the frames in default state?
4014 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
4016 setContentsMargins(-2, -2, -2, -2);
4018 setContentsMargins(0, 0, 0, 0);
4021 if (ui_component == "fullscreen") {
4029 void GuiView::toggleFullScreen()
4031 if (isFullScreen()) {
4032 for (int i = 0; i != d.splitter_->count(); ++i)
4033 d.tabWorkArea(i)->setFullScreen(false);
4034 setContentsMargins(0, 0, 0, 0);
4035 setWindowState(windowState() ^ Qt::WindowFullScreen);
4038 statusBar()->show();
4041 hideDialogs("prefs", 0);
4042 for (int i = 0; i != d.splitter_->count(); ++i)
4043 d.tabWorkArea(i)->setFullScreen(true);
4044 setContentsMargins(-2, -2, -2, -2);
4046 setWindowState(windowState() ^ Qt::WindowFullScreen);
4047 if (lyxrc.full_screen_statusbar)
4048 statusBar()->hide();
4049 if (lyxrc.full_screen_menubar)
4051 if (lyxrc.full_screen_toolbars) {
4052 ToolbarMap::iterator end = d.toolbars_.end();
4053 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
4058 // give dialogs like the TOC a chance to adapt
4063 Buffer const * GuiView::updateInset(Inset const * inset)
4068 Buffer const * inset_buffer = &(inset->buffer());
4070 for (int i = 0; i != d.splitter_->count(); ++i) {
4071 GuiWorkArea * wa = d.tabWorkArea(i)->currentWorkArea();
4074 Buffer const * buffer = &(wa->bufferView().buffer());
4075 if (inset_buffer == buffer)
4076 wa->scheduleRedraw();
4078 return inset_buffer;
4082 void GuiView::restartCursor()
4084 /* When we move around, or type, it's nice to be able to see
4085 * the cursor immediately after the keypress.
4087 if (d.current_work_area_)
4088 d.current_work_area_->startBlinkingCursor();
4090 // Take this occasion to update the other GUI elements.
4096 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
4098 if (d.current_work_area_)
4099 d.current_work_area_->completer().updateVisibility(cur, start, keep);
4104 // This list should be kept in sync with the list of insets in
4105 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
4106 // dialog should have the same name as the inset.
4107 // Changes should be also recorded in LFUN_DIALOG_SHOW doxygen
4108 // docs in LyXAction.cpp.
4110 char const * const dialognames[] = {
4112 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
4113 "citation", "compare", "comparehistory", "document", "errorlist", "ert",
4114 "external", "file", "findreplace", "findreplaceadv", "float", "graphics",
4115 "href", "include", "index", "index_print", "info", "listings", "label", "line",
4116 "log", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
4117 "nomencl_print", "note", "paragraph", "phantom", "prefs", "print", "ref",
4118 "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
4119 "thesaurus", "texinfo", "toc", "view-source", "vspace", "wrap", "progress"};
4121 char const * const * const end_dialognames =
4122 dialognames + (sizeof(dialognames) / sizeof(char *));
4126 cmpCStr(char const * name) : name_(name) {}
4127 bool operator()(char const * other) {
4128 return strcmp(other, name_) == 0;
4135 bool isValidName(string const & name)
4137 return find_if(dialognames, end_dialognames,
4138 cmpCStr(name.c_str())) != end_dialognames;
4144 void GuiView::resetDialogs()
4146 // Make sure that no LFUN uses any GuiView.
4147 guiApp->setCurrentView(0);
4151 constructToolbars();
4152 guiApp->menus().fillMenuBar(menuBar(), this, false);
4153 d.layout_->updateContents(true);
4154 // Now update controls with current buffer.
4155 guiApp->setCurrentView(this);
4161 Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
4163 if (!isValidName(name))
4166 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
4168 if (it != d.dialogs_.end()) {
4170 it->second->hideView();
4171 return it->second.get();
4174 Dialog * dialog = build(name);
4175 d.dialogs_[name].reset(dialog);
4176 if (lyxrc.allow_geometry_session)
4177 dialog->restoreSession();
4184 void GuiView::showDialog(string const & name, string const & data,
4187 triggerShowDialog(toqstr(name), toqstr(data), inset);
4191 void GuiView::doShowDialog(QString const & qname, QString const & qdata,
4197 const string name = fromqstr(qname);
4198 const string data = fromqstr(qdata);
4202 Dialog * dialog = findOrBuild(name, false);
4204 bool const visible = dialog->isVisibleView();
4205 dialog->showData(data);
4206 if (inset && currentBufferView())
4207 currentBufferView()->editInset(name, inset);
4208 // We only set the focus to the new dialog if it was not yet
4209 // visible in order not to change the existing previous behaviour
4211 // activateWindow is needed for floating dockviews
4212 dialog->asQWidget()->raise();
4213 dialog->asQWidget()->activateWindow();
4214 dialog->asQWidget()->setFocus();
4218 catch (ExceptionMessage const & ex) {
4226 bool GuiView::isDialogVisible(string const & name) const
4228 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
4229 if (it == d.dialogs_.end())
4231 return it->second.get()->isVisibleView() && !it->second.get()->isClosing();
4235 void GuiView::hideDialog(string const & name, Inset * inset)
4237 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
4238 if (it == d.dialogs_.end())
4242 if (!currentBufferView())
4244 if (inset != currentBufferView()->editedInset(name))
4248 Dialog * const dialog = it->second.get();
4249 if (dialog->isVisibleView())
4251 if (currentBufferView())
4252 currentBufferView()->editInset(name, 0);
4256 void GuiView::disconnectDialog(string const & name)
4258 if (!isValidName(name))
4260 if (currentBufferView())
4261 currentBufferView()->editInset(name, 0);
4265 void GuiView::hideAll() const
4267 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
4268 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
4270 for(; it != end; ++it)
4271 it->second->hideView();
4275 void GuiView::updateDialogs()
4277 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
4278 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
4280 for(; it != end; ++it) {
4281 Dialog * dialog = it->second.get();
4283 if (dialog->needBufferOpen() && !documentBufferView())
4284 hideDialog(fromqstr(dialog->name()), 0);
4285 else if (dialog->isVisibleView())
4286 dialog->checkStatus();
4293 Dialog * createDialog(GuiView & lv, string const & name);
4295 // will be replaced by a proper factory...
4296 Dialog * createGuiAbout(GuiView & lv);
4297 Dialog * createGuiBibtex(GuiView & lv);
4298 Dialog * createGuiChanges(GuiView & lv);
4299 Dialog * createGuiCharacter(GuiView & lv);
4300 Dialog * createGuiCitation(GuiView & lv);
4301 Dialog * createGuiCompare(GuiView & lv);
4302 Dialog * createGuiCompareHistory(GuiView & lv);
4303 Dialog * createGuiDelimiter(GuiView & lv);
4304 Dialog * createGuiDocument(GuiView & lv);
4305 Dialog * createGuiErrorList(GuiView & lv);
4306 Dialog * createGuiExternal(GuiView & lv);
4307 Dialog * createGuiGraphics(GuiView & lv);
4308 Dialog * createGuiInclude(GuiView & lv);
4309 Dialog * createGuiIndex(GuiView & lv);
4310 Dialog * createGuiListings(GuiView & lv);
4311 Dialog * createGuiLog(GuiView & lv);
4312 Dialog * createGuiMathMatrix(GuiView & lv);
4313 Dialog * createGuiNote(GuiView & lv);
4314 Dialog * createGuiParagraph(GuiView & lv);
4315 Dialog * createGuiPhantom(GuiView & lv);
4316 Dialog * createGuiPreferences(GuiView & lv);
4317 Dialog * createGuiPrint(GuiView & lv);
4318 Dialog * createGuiPrintindex(GuiView & lv);
4319 Dialog * createGuiRef(GuiView & lv);
4320 Dialog * createGuiSearch(GuiView & lv);
4321 Dialog * createGuiSearchAdv(GuiView & lv);
4322 Dialog * createGuiSendTo(GuiView & lv);
4323 Dialog * createGuiShowFile(GuiView & lv);
4324 Dialog * createGuiSpellchecker(GuiView & lv);
4325 Dialog * createGuiSymbols(GuiView & lv);
4326 Dialog * createGuiTabularCreate(GuiView & lv);
4327 Dialog * createGuiTexInfo(GuiView & lv);
4328 Dialog * createGuiToc(GuiView & lv);
4329 Dialog * createGuiThesaurus(GuiView & lv);
4330 Dialog * createGuiViewSource(GuiView & lv);
4331 Dialog * createGuiWrap(GuiView & lv);
4332 Dialog * createGuiProgressView(GuiView & lv);
4336 Dialog * GuiView::build(string const & name)
4338 LASSERT(isValidName(name), return 0);
4340 Dialog * dialog = createDialog(*this, name);
4344 if (name == "aboutlyx")
4345 return createGuiAbout(*this);
4346 if (name == "bibtex")
4347 return createGuiBibtex(*this);
4348 if (name == "changes")
4349 return createGuiChanges(*this);
4350 if (name == "character")
4351 return createGuiCharacter(*this);
4352 if (name == "citation")
4353 return createGuiCitation(*this);
4354 if (name == "compare")
4355 return createGuiCompare(*this);
4356 if (name == "comparehistory")
4357 return createGuiCompareHistory(*this);
4358 if (name == "document")
4359 return createGuiDocument(*this);
4360 if (name == "errorlist")
4361 return createGuiErrorList(*this);
4362 if (name == "external")
4363 return createGuiExternal(*this);
4365 return createGuiShowFile(*this);
4366 if (name == "findreplace")
4367 return createGuiSearch(*this);
4368 if (name == "findreplaceadv")
4369 return createGuiSearchAdv(*this);
4370 if (name == "graphics")
4371 return createGuiGraphics(*this);
4372 if (name == "include")
4373 return createGuiInclude(*this);
4374 if (name == "index")
4375 return createGuiIndex(*this);
4376 if (name == "index_print")
4377 return createGuiPrintindex(*this);
4378 if (name == "listings")
4379 return createGuiListings(*this);
4381 return createGuiLog(*this);
4382 if (name == "mathdelimiter")
4383 return createGuiDelimiter(*this);
4384 if (name == "mathmatrix")
4385 return createGuiMathMatrix(*this);
4387 return createGuiNote(*this);
4388 if (name == "paragraph")
4389 return createGuiParagraph(*this);
4390 if (name == "phantom")
4391 return createGuiPhantom(*this);
4392 if (name == "prefs")
4393 return createGuiPreferences(*this);
4394 if (name == "print")
4395 return createGuiPrint(*this);
4397 return createGuiRef(*this);
4398 if (name == "sendto")
4399 return createGuiSendTo(*this);
4400 if (name == "spellchecker")
4401 return createGuiSpellchecker(*this);
4402 if (name == "symbols")
4403 return createGuiSymbols(*this);
4404 if (name == "tabularcreate")
4405 return createGuiTabularCreate(*this);
4406 if (name == "texinfo")
4407 return createGuiTexInfo(*this);
4408 if (name == "thesaurus")
4409 return createGuiThesaurus(*this);
4411 return createGuiToc(*this);
4412 if (name == "view-source")
4413 return createGuiViewSource(*this);
4415 return createGuiWrap(*this);
4416 if (name == "progress")
4417 return createGuiProgressView(*this);
4423 } // namespace frontend
4426 #include "moc_GuiView.cpp"