3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "DispatchResult.h"
20 #include "FileDialog.h"
21 #include "FontLoader.h"
22 #include "GuiApplication.h"
23 #include "GuiCommandBuffer.h"
24 #include "GuiCompleter.h"
25 #include "GuiKeySymbol.h"
27 #include "GuiToolbar.h"
28 #include "GuiWorkArea.h"
29 #include "GuiProgress.h"
30 #include "LayoutBox.h"
34 #include "qt_helpers.h"
35 #include "support/filetools.h"
37 #include "frontends/alert.h"
38 #include "frontends/KeySymbol.h"
40 #include "buffer_funcs.h"
42 #include "BufferList.h"
43 #include "BufferParams.h"
44 #include "BufferView.h"
46 #include "Converter.h"
48 #include "CutAndPaste.h"
50 #include "ErrorList.h"
52 #include "FuncStatus.h"
53 #include "FuncRequest.h"
57 #include "LyXAction.h"
61 #include "Paragraph.h"
62 #include "SpellChecker.h"
65 #include "TextClass.h"
70 #include "support/convert.h"
71 #include "support/debug.h"
72 #include "support/ExceptionMessage.h"
73 #include "support/FileName.h"
74 #include "support/filetools.h"
75 #include "support/gettext.h"
76 #include "support/filetools.h"
77 #include "support/ForkedCalls.h"
78 #include "support/lassert.h"
79 #include "support/lstrings.h"
80 #include "support/os.h"
81 #include "support/Package.h"
82 #include "support/PathChanger.h"
83 #include "support/Systemcall.h"
84 #include "support/Timeout.h"
85 #include "support/ProgressInterface.h"
88 #include <QApplication>
89 #include <QCloseEvent>
91 #include <QDesktopWidget>
92 #include <QDragEnterEvent>
95 #include <QFutureWatcher>
104 #include <QPixmapCache>
106 #include <QPushButton>
107 #include <QScrollBar>
109 #include <QShowEvent>
111 #include <QStackedWidget>
112 #include <QStatusBar>
113 #if QT_VERSION >= 0x050000
114 #include <QSvgRenderer>
116 #include <QtConcurrentRun>
124 // sync with GuiAlert.cpp
125 #define EXPORT_in_THREAD 1
128 #include "support/bind.h"
132 #ifdef HAVE_SYS_TIME_H
133 # include <sys/time.h>
141 using namespace lyx::support;
145 using support::addExtension;
146 using support::changeExtension;
147 using support::removeExtension;
153 class BackgroundWidget : public QWidget
156 BackgroundWidget(int width, int height)
157 : width_(width), height_(height)
159 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
160 if (!lyxrc.show_banner)
162 /// The text to be written on top of the pixmap
163 QString const text = lyx_version ?
164 qt_("version ") + lyx_version : qt_("unknown version");
165 #if QT_VERSION >= 0x050000
166 QString imagedir = "images/";
167 FileName fname = imageLibFileSearch(imagedir, "banner", "svgz");
168 QSvgRenderer svgRenderer(toqstr(fname.absFileName()));
169 if (svgRenderer.isValid()) {
170 splash_ = QPixmap(splashSize());
171 QPainter painter(&splash_);
172 svgRenderer.render(&painter);
173 splash_.setDevicePixelRatio(pixelRatio());
175 splash_ = getPixmap("images/", "banner", "png");
178 splash_ = getPixmap("images/", "banner", "svgz,png");
181 QPainter pain(&splash_);
182 pain.setPen(QColor(0, 0, 0));
183 qreal const fsize = fontSize();
184 QPointF const position = textPosition();
186 "widget pixel ratio: " << pixelRatio() <<
187 " splash pixel ratio: " << splashPixelRatio() <<
188 " version text size,position: " << fsize << "@" << position.x() << "+" << position.y());
190 // The font used to display the version info
191 font.setStyleHint(QFont::SansSerif);
192 font.setWeight(QFont::Bold);
193 font.setPointSizeF(fsize);
195 pain.drawText(position, text);
196 setFocusPolicy(Qt::StrongFocus);
199 void paintEvent(QPaintEvent *)
201 int const w = width_;
202 int const h = height_;
203 int const x = (width() - w) / 2;
204 int const y = (height() - h) / 2;
206 "widget pixel ratio: " << pixelRatio() <<
207 " splash pixel ratio: " << splashPixelRatio() <<
208 " paint pixmap: " << w << "x" << h << "@" << x << "+" << y);
210 pain.drawPixmap(x, y, w, h, splash_);
213 void keyPressEvent(QKeyEvent * ev)
216 setKeySymbol(&sym, ev);
218 guiApp->processKeySym(sym, q_key_state(ev->modifiers()));
230 /// Current ratio between physical pixels and device-independent pixels
231 double pixelRatio() const {
232 #if QT_VERSION >= 0x050000
233 return devicePixelRatio();
239 qreal fontSize() const {
240 return toqstr(lyxrc.font_sizes[FONT_SIZE_NORMAL]).toDouble();
243 QPointF textPosition() const {
244 return QPointF(width_/2 - 18, height_/2 + 45);
247 QSize splashSize() const {
249 static_cast<unsigned int>(width_ * pixelRatio()),
250 static_cast<unsigned int>(height_ * pixelRatio()));
253 /// Ratio between physical pixels and device-independent pixels of splash image
254 double splashPixelRatio() const {
255 #if QT_VERSION >= 0x050000
256 return splash_.devicePixelRatio();
264 /// Toolbar store providing access to individual toolbars by name.
265 typedef map<string, GuiToolbar *> ToolbarMap;
267 typedef shared_ptr<Dialog> DialogPtr;
272 class GuiView::GuiViewPrivate
275 GuiViewPrivate(GuiViewPrivate const &);
276 void operator=(GuiViewPrivate const &);
278 GuiViewPrivate(GuiView * gv)
279 : gv_(gv), current_work_area_(0), current_main_work_area_(0),
280 layout_(0), autosave_timeout_(5000),
283 // hardcode here the platform specific icon size
284 smallIconSize = 16; // scaling problems
285 normalIconSize = 20; // ok, default if iconsize.png is missing
286 bigIconSize = 26; // better for some math icons
287 hugeIconSize = 32; // better for hires displays
290 // if it exists, use width of iconsize.png as normal size
291 QString const dir = toqstr(addPath("images", lyxrc.icon_set));
292 FileName const fn = lyx::libFileSearch(dir, "iconsize.png");
294 QImage image(toqstr(fn.absFileName()));
295 if (image.width() < int(smallIconSize))
296 normalIconSize = smallIconSize;
297 else if (image.width() > int(giantIconSize))
298 normalIconSize = giantIconSize;
300 normalIconSize = image.width();
303 splitter_ = new QSplitter;
304 bg_widget_ = new BackgroundWidget(400, 250);
305 stack_widget_ = new QStackedWidget;
306 stack_widget_->addWidget(bg_widget_);
307 stack_widget_->addWidget(splitter_);
310 // TODO cleanup, remove the singleton, handle multiple Windows?
311 progress_ = ProgressInterface::instance();
312 if (!dynamic_cast<GuiProgress*>(progress_)) {
313 progress_ = new GuiProgress; // TODO who deletes it
314 ProgressInterface::setInstance(progress_);
317 dynamic_cast<GuiProgress*>(progress_),
318 SIGNAL(updateStatusBarMessage(QString const&)),
319 gv, SLOT(updateStatusBarMessage(QString const&)));
321 dynamic_cast<GuiProgress*>(progress_),
322 SIGNAL(clearMessageText()),
323 gv, SLOT(clearMessageText()));
330 delete stack_widget_;
333 QMenu * toolBarPopup(GuiView * parent)
335 // FIXME: translation
336 QMenu * menu = new QMenu(parent);
337 QActionGroup * iconSizeGroup = new QActionGroup(parent);
339 QAction * smallIcons = new QAction(iconSizeGroup);
340 smallIcons->setText(qt_("Small-sized icons"));
341 smallIcons->setCheckable(true);
342 QObject::connect(smallIcons, SIGNAL(triggered()),
343 parent, SLOT(smallSizedIcons()));
344 menu->addAction(smallIcons);
346 QAction * normalIcons = new QAction(iconSizeGroup);
347 normalIcons->setText(qt_("Normal-sized icons"));
348 normalIcons->setCheckable(true);
349 QObject::connect(normalIcons, SIGNAL(triggered()),
350 parent, SLOT(normalSizedIcons()));
351 menu->addAction(normalIcons);
353 QAction * bigIcons = new QAction(iconSizeGroup);
354 bigIcons->setText(qt_("Big-sized icons"));
355 bigIcons->setCheckable(true);
356 QObject::connect(bigIcons, SIGNAL(triggered()),
357 parent, SLOT(bigSizedIcons()));
358 menu->addAction(bigIcons);
360 QAction * hugeIcons = new QAction(iconSizeGroup);
361 hugeIcons->setText(qt_("Huge-sized icons"));
362 hugeIcons->setCheckable(true);
363 QObject::connect(hugeIcons, SIGNAL(triggered()),
364 parent, SLOT(hugeSizedIcons()));
365 menu->addAction(hugeIcons);
367 QAction * giantIcons = new QAction(iconSizeGroup);
368 giantIcons->setText(qt_("Giant-sized icons"));
369 giantIcons->setCheckable(true);
370 QObject::connect(giantIcons, SIGNAL(triggered()),
371 parent, SLOT(giantSizedIcons()));
372 menu->addAction(giantIcons);
374 unsigned int cur = parent->iconSize().width();
375 if ( cur == parent->d.smallIconSize)
376 smallIcons->setChecked(true);
377 else if (cur == parent->d.normalIconSize)
378 normalIcons->setChecked(true);
379 else if (cur == parent->d.bigIconSize)
380 bigIcons->setChecked(true);
381 else if (cur == parent->d.hugeIconSize)
382 hugeIcons->setChecked(true);
383 else if (cur == parent->d.giantIconSize)
384 giantIcons->setChecked(true);
391 stack_widget_->setCurrentWidget(bg_widget_);
392 bg_widget_->setUpdatesEnabled(true);
393 bg_widget_->setFocus();
396 int tabWorkAreaCount()
398 return splitter_->count();
401 TabWorkArea * tabWorkArea(int i)
403 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
406 TabWorkArea * currentTabWorkArea()
408 int areas = tabWorkAreaCount();
410 // The first TabWorkArea is always the first one, if any.
411 return tabWorkArea(0);
413 for (int i = 0; i != areas; ++i) {
414 TabWorkArea * twa = tabWorkArea(i);
415 if (current_main_work_area_ == twa->currentWorkArea())
419 // None has the focus so we just take the first one.
420 return tabWorkArea(0);
423 int countWorkAreasOf(Buffer & buf)
425 int areas = tabWorkAreaCount();
427 for (int i = 0; i != areas; ++i) {
428 TabWorkArea * twa = tabWorkArea(i);
429 if (twa->workArea(buf))
435 void setPreviewFuture(QFuture<Buffer::ExportStatus> const & f)
437 if (processing_thread_watcher_.isRunning()) {
438 // we prefer to cancel this preview in order to keep a snappy
442 processing_thread_watcher_.setFuture(f);
447 GuiWorkArea * current_work_area_;
448 GuiWorkArea * current_main_work_area_;
449 QSplitter * splitter_;
450 QStackedWidget * stack_widget_;
451 BackgroundWidget * bg_widget_;
453 ToolbarMap toolbars_;
454 ProgressInterface* progress_;
455 /// The main layout box.
457 * \warning Don't Delete! The layout box is actually owned by
458 * whichever toolbar contains it. All the GuiView class needs is a
459 * means of accessing it.
461 * FIXME: replace that with a proper model so that we are not limited
462 * to only one dialog.
467 map<string, DialogPtr> dialogs_;
469 unsigned int smallIconSize;
470 unsigned int normalIconSize;
471 unsigned int bigIconSize;
472 unsigned int hugeIconSize;
473 unsigned int giantIconSize;
475 QTimer statusbar_timer_;
476 /// auto-saving of buffers
477 Timeout autosave_timeout_;
478 /// flag against a race condition due to multiclicks, see bug #1119
482 TocModels toc_models_;
485 QFutureWatcher<docstring> autosave_watcher_;
486 QFutureWatcher<Buffer::ExportStatus> processing_thread_watcher_;
488 string last_export_format;
489 string processing_format;
491 static QSet<Buffer const *> busyBuffers;
492 static Buffer::ExportStatus previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
493 static Buffer::ExportStatus exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
494 static Buffer::ExportStatus compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
495 static docstring autosaveAndDestroy(Buffer const * orig, Buffer * buffer);
498 static Buffer::ExportStatus runAndDestroy(const T& func, Buffer const * orig, Buffer * buffer, string const & format);
500 // TODO syncFunc/previewFunc: use bind
501 bool asyncBufferProcessing(string const & argument,
502 Buffer const * used_buffer,
503 docstring const & msg,
504 Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
505 Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
506 Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const);
508 QVector<GuiWorkArea*> guiWorkAreas();
511 QSet<Buffer const *> GuiView::GuiViewPrivate::busyBuffers;
514 GuiView::GuiView(int id)
515 : d(*new GuiViewPrivate(this)), id_(id), closing_(false), busy_(0),
516 command_execute_(false)
518 // GuiToolbars *must* be initialised before the menu bar.
519 normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge
522 // set ourself as the current view. This is needed for the menu bar
523 // filling, at least for the static special menu item on Mac. Otherwise
524 // they are greyed out.
525 guiApp->setCurrentView(this);
527 // Fill up the menu bar.
528 guiApp->menus().fillMenuBar(menuBar(), this, true);
530 setCentralWidget(d.stack_widget_);
532 // Start autosave timer
533 if (lyxrc.autosave) {
534 d.autosave_timeout_.timeout.connect(bind(&GuiView::autoSave, this));
535 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
536 d.autosave_timeout_.start();
538 connect(&d.statusbar_timer_, SIGNAL(timeout()),
539 this, SLOT(clearMessage()));
541 // We don't want to keep the window in memory if it is closed.
542 setAttribute(Qt::WA_DeleteOnClose, true);
544 #if !(defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)) && !defined(Q_OS_MAC)
545 // QIcon::fromTheme was introduced in Qt 4.6
546 #if (QT_VERSION >= 0x040600)
547 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
548 // since the icon is provided in the application bundle. We use a themed
549 // version when available and use the bundled one as fallback.
550 setWindowIcon(QIcon::fromTheme("lyx", getPixmap("images/", "lyx", "svg,png")));
552 setWindowIcon(getPixmap("images/", "lyx", "svg,png"));
556 resetWindowTitleAndIconText();
558 // use tabbed dock area for multiple docks
559 // (such as "source" and "messages")
560 setDockOptions(QMainWindow::ForceTabbedDocks);
563 setAcceptDrops(true);
565 // add busy indicator to statusbar
566 QLabel * busylabel = new QLabel(statusBar());
567 statusBar()->addPermanentWidget(busylabel);
568 search_mode mode = theGuiApp()->imageSearchMode();
569 QString fn = toqstr(lyx::libFileSearch("images", "busy", "gif", mode).absFileName());
570 QMovie * busyanim = new QMovie(fn, QByteArray(), busylabel);
571 busylabel->setMovie(busyanim);
575 connect(&d.processing_thread_watcher_, SIGNAL(started()),
576 busylabel, SLOT(show()));
577 connect(&d.processing_thread_watcher_, SIGNAL(finished()),
578 busylabel, SLOT(hide()));
580 statusBar()->setSizeGripEnabled(true);
583 connect(&d.autosave_watcher_, SIGNAL(finished()), this,
584 SLOT(autoSaveThreadFinished()));
586 connect(&d.processing_thread_watcher_, SIGNAL(started()), this,
587 SLOT(processingThreadStarted()));
588 connect(&d.processing_thread_watcher_, SIGNAL(finished()), this,
589 SLOT(processingThreadFinished()));
591 connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)),
592 SLOT(doShowDialog(QString const &, QString const &, Inset *)));
594 // Forbid too small unresizable window because it can happen
595 // with some window manager under X11.
596 setMinimumSize(300, 200);
598 if (lyxrc.allow_geometry_session) {
599 // Now take care of session management.
604 // no session handling, default to a sane size.
605 setGeometry(50, 50, 690, 510);
608 // clear session data if any.
610 settings.remove("views");
620 QVector<GuiWorkArea*> GuiView::GuiViewPrivate::guiWorkAreas()
622 QVector<GuiWorkArea*> areas;
623 for (int i = 0; i < tabWorkAreaCount(); i++) {
624 TabWorkArea* ta = tabWorkArea(i);
625 for (int u = 0; u < ta->count(); u++) {
626 areas << ta->workArea(u);
632 static void handleExportStatus(GuiView * view, Buffer::ExportStatus status,
633 string const & format)
635 docstring const fmt = formats.prettyName(format);
638 case Buffer::ExportSuccess:
639 msg = bformat(_("Successful export to format: %1$s"), fmt);
641 case Buffer::ExportCancel:
642 msg = _("Document export cancelled.");
644 case Buffer::ExportError:
645 case Buffer::ExportNoPathToFormat:
646 case Buffer::ExportTexPathHasSpaces:
647 case Buffer::ExportConverterError:
648 msg = bformat(_("Error while exporting format: %1$s"), fmt);
650 case Buffer::PreviewSuccess:
651 msg = bformat(_("Successful preview of format: %1$s"), fmt);
653 case Buffer::PreviewError:
654 msg = bformat(_("Error while previewing format: %1$s"), fmt);
661 void GuiView::processingThreadStarted()
666 void GuiView::processingThreadFinished()
668 QFutureWatcher<Buffer::ExportStatus> const * watcher =
669 static_cast<QFutureWatcher<Buffer::ExportStatus> const *>(sender());
671 Buffer::ExportStatus const status = watcher->result();
672 handleExportStatus(this, status, d.processing_format);
675 BufferView const * const bv = currentBufferView();
676 if (bv && !bv->buffer().errorList("Export").empty()) {
680 errors(d.last_export_format);
684 void GuiView::autoSaveThreadFinished()
686 QFutureWatcher<docstring> const * watcher =
687 static_cast<QFutureWatcher<docstring> const *>(sender());
688 message(watcher->result());
693 void GuiView::saveLayout() const
696 settings.beginGroup("views");
697 settings.beginGroup(QString::number(id_));
698 #if defined(Q_WS_X11) || defined(QPA_XCB)
699 settings.setValue("pos", pos());
700 settings.setValue("size", size());
702 settings.setValue("geometry", saveGeometry());
704 settings.setValue("layout", saveState(0));
705 settings.setValue("icon_size", iconSize());
709 void GuiView::saveUISettings() const
711 // Save the toolbar private states
712 ToolbarMap::iterator end = d.toolbars_.end();
713 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
714 it->second->saveSession();
715 // Now take care of all other dialogs
716 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
717 for (; it!= d.dialogs_.end(); ++it)
718 it->second->saveSession();
722 bool GuiView::restoreLayout()
725 settings.beginGroup("views");
726 settings.beginGroup(QString::number(id_));
727 QString const icon_key = "icon_size";
728 if (!settings.contains(icon_key))
731 //code below is skipped when when ~/.config/LyX is (re)created
732 QSize icon_size = settings.value(icon_key).toSize();
733 // Check whether session size changed.
734 if (icon_size.width() != int(d.smallIconSize) &&
735 icon_size.width() != int(d.normalIconSize) &&
736 icon_size.width() != int(d.bigIconSize) &&
737 icon_size.width() != int(d.hugeIconSize) &&
738 icon_size.width() != int(d.giantIconSize)) {
739 icon_size.setWidth(d.normalIconSize);
740 icon_size.setHeight(d.normalIconSize);
742 setIconSize(icon_size);
744 #if defined(Q_WS_X11) || defined(QPA_XCB)
745 QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
746 QSize size = settings.value("size", QSize(690, 510)).toSize();
750 // Work-around for bug #6034: the window ends up in an undetermined
751 // state when trying to restore a maximized window when it is
752 // already maximized.
753 if (!(windowState() & Qt::WindowMaximized))
754 if (!restoreGeometry(settings.value("geometry").toByteArray()))
755 setGeometry(50, 50, 690, 510);
757 // Make sure layout is correctly oriented.
758 setLayoutDirection(qApp->layoutDirection());
760 // Allow the toc and view-source dock widget to be restored if needed.
762 if ((dialog = findOrBuild("toc", true)))
763 // see bug 5082. At least setup title and enabled state.
764 // Visibility will be adjusted by restoreState below.
765 dialog->prepareView();
766 if ((dialog = findOrBuild("view-source", true)))
767 dialog->prepareView();
768 if ((dialog = findOrBuild("progress", true)))
769 dialog->prepareView();
771 if (!restoreState(settings.value("layout").toByteArray(), 0))
774 // init the toolbars that have not been restored
775 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
776 Toolbars::Infos::iterator end = guiApp->toolbars().end();
777 for (; cit != end; ++cit) {
778 GuiToolbar * tb = toolbar(cit->name);
779 if (tb && !tb->isRestored())
780 initToolbar(cit->name);
788 GuiToolbar * GuiView::toolbar(string const & name)
790 ToolbarMap::iterator it = d.toolbars_.find(name);
791 if (it != d.toolbars_.end())
794 LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
799 void GuiView::constructToolbars()
801 ToolbarMap::iterator it = d.toolbars_.begin();
802 for (; it != d.toolbars_.end(); ++it)
806 // I don't like doing this here, but the standard toolbar
807 // destroys this object when it's destroyed itself (vfr)
808 d.layout_ = new LayoutBox(*this);
809 d.stack_widget_->addWidget(d.layout_);
810 d.layout_->move(0,0);
812 // extracts the toolbars from the backend
813 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
814 Toolbars::Infos::iterator end = guiApp->toolbars().end();
815 for (; cit != end; ++cit)
816 d.toolbars_[cit->name] = new GuiToolbar(*cit, *this);
820 void GuiView::initToolbars()
822 // extracts the toolbars from the backend
823 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
824 Toolbars::Infos::iterator end = guiApp->toolbars().end();
825 for (; cit != end; ++cit)
826 initToolbar(cit->name);
830 void GuiView::initToolbar(string const & name)
832 GuiToolbar * tb = toolbar(name);
835 int const visibility = guiApp->toolbars().defaultVisibility(name);
836 bool newline = !(visibility & Toolbars::SAMEROW);
837 tb->setVisible(false);
838 tb->setVisibility(visibility);
840 if (visibility & Toolbars::TOP) {
842 addToolBarBreak(Qt::TopToolBarArea);
843 addToolBar(Qt::TopToolBarArea, tb);
846 if (visibility & Toolbars::BOTTOM) {
848 addToolBarBreak(Qt::BottomToolBarArea);
849 addToolBar(Qt::BottomToolBarArea, tb);
852 if (visibility & Toolbars::LEFT) {
854 addToolBarBreak(Qt::LeftToolBarArea);
855 addToolBar(Qt::LeftToolBarArea, tb);
858 if (visibility & Toolbars::RIGHT) {
860 addToolBarBreak(Qt::RightToolBarArea);
861 addToolBar(Qt::RightToolBarArea, tb);
864 if (visibility & Toolbars::ON)
865 tb->setVisible(true);
869 TocModels & GuiView::tocModels()
871 return d.toc_models_;
875 void GuiView::setFocus()
877 LYXERR(Debug::DEBUG, "GuiView::setFocus()" << this);
878 QMainWindow::setFocus();
882 bool GuiView::hasFocus() const
884 if (currentWorkArea())
885 return currentWorkArea()->hasFocus();
886 if (currentMainWorkArea())
887 return currentMainWorkArea()->hasFocus();
888 return d.bg_widget_->hasFocus();
892 void GuiView::focusInEvent(QFocusEvent * e)
894 LYXERR(Debug::DEBUG, "GuiView::focusInEvent()" << this);
895 QMainWindow::focusInEvent(e);
896 // Make sure guiApp points to the correct view.
897 guiApp->setCurrentView(this);
898 if (currentWorkArea())
899 currentWorkArea()->setFocus();
900 else if (currentMainWorkArea())
901 currentMainWorkArea()->setFocus();
903 d.bg_widget_->setFocus();
907 QMenu * GuiView::createPopupMenu()
909 return d.toolBarPopup(this);
913 void GuiView::showEvent(QShowEvent * e)
915 LYXERR(Debug::GUI, "Passed Geometry "
916 << size().height() << "x" << size().width()
917 << "+" << pos().x() << "+" << pos().y());
919 if (d.splitter_->count() == 0)
920 // No work area, switch to the background widget.
924 QMainWindow::showEvent(e);
928 bool GuiView::closeScheduled()
935 bool GuiView::prepareAllBuffersForLogout()
937 Buffer * first = theBufferList().first();
941 // First, iterate over all buffers and ask the users if unsaved
942 // changes should be saved.
943 // We cannot use a for loop as the buffer list cycles.
946 if (!saveBufferIfNeeded(const_cast<Buffer &>(*b), false))
948 b = theBufferList().next(b);
949 } while (b != first);
951 // Next, save session state
952 // When a view/window was closed before without quitting LyX, there
953 // are already entries in the lastOpened list.
954 theSession().lastOpened().clear();
961 /** Destroy only all tabbed WorkAreas. Destruction of other WorkAreas
962 ** is responsibility of the container (e.g., dialog)
964 void GuiView::closeEvent(QCloseEvent * close_event)
966 LYXERR(Debug::DEBUG, "GuiView::closeEvent()");
968 if (!GuiViewPrivate::busyBuffers.isEmpty()) {
969 Alert::warning(_("Exit LyX"),
970 _("LyX could not be closed because documents are being processed by LyX."));
971 close_event->setAccepted(false);
975 // If the user pressed the x (so we didn't call closeView
976 // programmatically), we want to clear all existing entries.
978 theSession().lastOpened().clear();
983 // it can happen that this event arrives without selecting the view,
984 // e.g. when clicking the close button on a background window.
986 if (!closeWorkAreaAll()) {
988 close_event->ignore();
992 // Make sure that nothing will use this to be closed View.
993 guiApp->unregisterView(this);
995 if (isFullScreen()) {
996 // Switch off fullscreen before closing.
1001 // Make sure the timer time out will not trigger a statusbar update.
1002 d.statusbar_timer_.stop();
1004 // Saving fullscreen requires additional tweaks in the toolbar code.
1005 // It wouldn't also work under linux natively.
1006 if (lyxrc.allow_geometry_session) {
1011 close_event->accept();
1015 void GuiView::dragEnterEvent(QDragEnterEvent * event)
1017 if (event->mimeData()->hasUrls())
1019 /// \todo Ask lyx-devel is this is enough:
1020 /// if (event->mimeData()->hasFormat("text/plain"))
1021 /// event->acceptProposedAction();
1025 void GuiView::dropEvent(QDropEvent * event)
1027 QList<QUrl> files = event->mimeData()->urls();
1028 if (files.isEmpty())
1031 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
1032 for (int i = 0; i != files.size(); ++i) {
1033 string const file = os::internal_path(fromqstr(
1034 files.at(i).toLocalFile()));
1038 string const ext = support::getExtension(file);
1039 vector<const Format *> found_formats;
1041 // Find all formats that have the correct extension.
1042 vector<const Format *> const & import_formats
1043 = theConverters().importableFormats();
1044 vector<const Format *>::const_iterator it = import_formats.begin();
1045 for (; it != import_formats.end(); ++it)
1046 if ((*it)->hasExtension(ext))
1047 found_formats.push_back(*it);
1050 if (found_formats.size() >= 1) {
1051 if (found_formats.size() > 1) {
1052 //FIXME: show a dialog to choose the correct importable format
1053 LYXERR(Debug::FILES,
1054 "Multiple importable formats found, selecting first");
1056 string const arg = found_formats[0]->name() + " " + file;
1057 cmd = FuncRequest(LFUN_BUFFER_IMPORT, arg);
1060 //FIXME: do we have to explicitly check whether it's a lyx file?
1061 LYXERR(Debug::FILES,
1062 "No formats found, trying to open it as a lyx file");
1063 cmd = FuncRequest(LFUN_FILE_OPEN, file);
1065 // add the functions to the queue
1066 guiApp->addToFuncRequestQueue(cmd);
1069 // now process the collected functions. We perform the events
1070 // asynchronously. This prevents potential problems in case the
1071 // BufferView is closed within an event.
1072 guiApp->processFuncRequestQueueAsync();
1076 void GuiView::message(docstring const & str)
1078 if (ForkedProcess::iAmAChild())
1081 // call is moved to GUI-thread by GuiProgress
1082 d.progress_->appendMessage(toqstr(str));
1086 void GuiView::clearMessageText()
1088 message(docstring());
1092 void GuiView::updateStatusBarMessage(QString const & str)
1094 statusBar()->showMessage(str);
1095 d.statusbar_timer_.stop();
1096 d.statusbar_timer_.start(3000);
1100 void GuiView::smallSizedIcons()
1102 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
1106 void GuiView::normalSizedIcons()
1108 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
1112 void GuiView::bigSizedIcons()
1114 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
1118 void GuiView::hugeSizedIcons()
1120 setIconSize(QSize(d.hugeIconSize, d.hugeIconSize));
1124 void GuiView::giantSizedIcons()
1126 setIconSize(QSize(d.giantIconSize, d.giantIconSize));
1130 void GuiView::clearMessage()
1132 // FIXME: This code was introduced in r19643 to fix bug #4123. However,
1133 // the hasFocus function mostly returns false, even if the focus is on
1134 // a workarea in this view.
1138 d.statusbar_timer_.stop();
1142 void GuiView::updateWindowTitle(GuiWorkArea * wa)
1144 if (wa != d.current_work_area_
1145 || wa->bufferView().buffer().isInternal())
1147 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
1148 setWindowIconText(wa->windowIconText());
1149 #if (QT_VERSION >= 0x040400)
1150 // Sets the path for the window: this is used by OSX to
1151 // allow a context click on the title bar showing a menu
1152 // with the path up to the file
1153 setWindowFilePath(toqstr(wa->bufferView().buffer().absFileName()));
1158 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
1160 if (d.current_work_area_)
1161 QObject::disconnect(d.current_work_area_, SIGNAL(busy(bool)),
1162 this, SLOT(setBusy(bool)));
1164 disconnectBufferView();
1165 connectBufferView(wa->bufferView());
1166 connectBuffer(wa->bufferView().buffer());
1167 d.current_work_area_ = wa;
1168 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
1169 this, SLOT(updateWindowTitle(GuiWorkArea *)));
1170 QObject::connect(wa, SIGNAL(busy(bool)), this, SLOT(setBusy(bool)));
1171 updateWindowTitle(wa);
1175 // The document settings needs to be reinitialised.
1176 updateDialog("document", "");
1178 // Buffer-dependent dialogs must be updated. This is done here because
1179 // some dialogs require buffer()->text.
1184 void GuiView::on_lastWorkAreaRemoved()
1187 // We already are in a close event. Nothing more to do.
1190 if (d.splitter_->count() > 1)
1191 // We have a splitter so don't close anything.
1194 // Reset and updates the dialogs.
1195 d.toc_models_.reset(0);
1196 updateDialog("document", "");
1199 resetWindowTitleAndIconText();
1202 if (lyxrc.open_buffers_in_tabs)
1203 // Nothing more to do, the window should stay open.
1206 if (guiApp->viewIds().size() > 1) {
1212 // On Mac we also close the last window because the application stay
1213 // resident in memory. On other platforms we don't close the last
1214 // window because this would quit the application.
1220 void GuiView::updateStatusBar()
1222 // let the user see the explicit message
1223 if (d.statusbar_timer_.isActive())
1230 void GuiView::showMessage()
1234 QString msg = toqstr(theGuiApp()->viewStatusMessage());
1235 if (msg.isEmpty()) {
1236 BufferView const * bv = currentBufferView();
1238 msg = toqstr(bv->cursor().currentState());
1240 msg = qt_("Welcome to LyX!");
1242 statusBar()->showMessage(msg);
1246 bool GuiView::event(QEvent * e)
1250 // Useful debug code:
1251 //case QEvent::ActivationChange:
1252 //case QEvent::WindowDeactivate:
1253 //case QEvent::Paint:
1254 //case QEvent::Enter:
1255 //case QEvent::Leave:
1256 //case QEvent::HoverEnter:
1257 //case QEvent::HoverLeave:
1258 //case QEvent::HoverMove:
1259 //case QEvent::StatusTip:
1260 //case QEvent::DragEnter:
1261 //case QEvent::DragLeave:
1262 //case QEvent::Drop:
1265 case QEvent::WindowActivate: {
1266 GuiView * old_view = guiApp->currentView();
1267 if (this == old_view) {
1269 return QMainWindow::event(e);
1271 if (old_view && old_view->currentBufferView()) {
1272 // save current selection to the selection buffer to allow
1273 // middle-button paste in this window.
1274 cap::saveSelection(old_view->currentBufferView()->cursor());
1276 guiApp->setCurrentView(this);
1277 if (d.current_work_area_) {
1278 BufferView & bv = d.current_work_area_->bufferView();
1279 connectBufferView(bv);
1280 connectBuffer(bv.buffer());
1281 // The document structure, name and dialogs might have
1282 // changed in another view.
1284 // The document settings needs to be reinitialised.
1285 updateDialog("document", "");
1288 resetWindowTitleAndIconText();
1291 return QMainWindow::event(e);
1294 case QEvent::ShortcutOverride: {
1296 if (isFullScreen() && menuBar()->isHidden()) {
1297 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
1298 // FIXME: we should also try to detect special LyX shortcut such as
1299 // Alt-P and Alt-M. Right now there is a hack in
1300 // GuiWorkArea::processKeySym() that hides again the menubar for
1302 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt) {
1304 return QMainWindow::event(e);
1307 return QMainWindow::event(e);
1311 return QMainWindow::event(e);
1315 void GuiView::resetWindowTitleAndIconText()
1317 setWindowTitle(qt_("LyX"));
1318 setWindowIconText(qt_("LyX"));
1321 bool GuiView::focusNextPrevChild(bool /*next*/)
1328 bool GuiView::busy() const
1334 void GuiView::setBusy(bool busy)
1336 bool const busy_before = busy_ > 0;
1337 busy ? ++busy_ : --busy_;
1338 if ((busy_ > 0) == busy_before)
1339 // busy state didn't change
1343 QApplication::setOverrideCursor(Qt::WaitCursor);
1346 QApplication::restoreOverrideCursor();
1351 void GuiView::resetCommandExecute()
1353 command_execute_ = false;
1358 double GuiView::pixelRatio() const
1360 #if QT_VERSION >= 0x050000
1361 return devicePixelRatio();
1368 GuiWorkArea * GuiView::workArea(int index)
1370 if (TabWorkArea * twa = d.currentTabWorkArea())
1371 if (index < twa->count())
1372 return dynamic_cast<GuiWorkArea *>(twa->widget(index));
1377 GuiWorkArea * GuiView::workArea(Buffer & buffer)
1379 if (currentWorkArea()
1380 && ¤tWorkArea()->bufferView().buffer() == &buffer)
1381 return currentWorkArea();
1382 if (TabWorkArea * twa = d.currentTabWorkArea())
1383 return twa->workArea(buffer);
1388 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
1390 // Automatically create a TabWorkArea if there are none yet.
1391 TabWorkArea * tab_widget = d.splitter_->count()
1392 ? d.currentTabWorkArea() : addTabWorkArea();
1393 return tab_widget->addWorkArea(buffer, *this);
1397 TabWorkArea * GuiView::addTabWorkArea()
1399 TabWorkArea * twa = new TabWorkArea;
1400 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
1401 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
1402 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
1403 this, SLOT(on_lastWorkAreaRemoved()));
1405 d.splitter_->addWidget(twa);
1406 d.stack_widget_->setCurrentWidget(d.splitter_);
1411 GuiWorkArea const * GuiView::currentWorkArea() const
1413 return d.current_work_area_;
1417 GuiWorkArea * GuiView::currentWorkArea()
1419 return d.current_work_area_;
1423 GuiWorkArea const * GuiView::currentMainWorkArea() const
1425 if (!d.currentTabWorkArea())
1427 return d.currentTabWorkArea()->currentWorkArea();
1431 GuiWorkArea * GuiView::currentMainWorkArea()
1433 if (!d.currentTabWorkArea())
1435 return d.currentTabWorkArea()->currentWorkArea();
1439 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
1441 LYXERR(Debug::DEBUG, "Setting current wa: " << wa << endl);
1443 d.current_work_area_ = 0;
1448 // FIXME: I've no clue why this is here and why it accesses
1449 // theGuiApp()->currentView, which might be 0 (bug 6464).
1450 // See also 27525 (vfr).
1451 if (theGuiApp()->currentView() == this
1452 && theGuiApp()->currentView()->currentWorkArea() == wa)
1455 if (currentBufferView())
1456 cap::saveSelection(currentBufferView()->cursor());
1458 theGuiApp()->setCurrentView(this);
1459 d.current_work_area_ = wa;
1461 // We need to reset this now, because it will need to be
1462 // right if the tabWorkArea gets reset in the for loop. We
1463 // will change it back if we aren't in that case.
1464 GuiWorkArea * const old_cmwa = d.current_main_work_area_;
1465 d.current_main_work_area_ = wa;
1467 for (int i = 0; i != d.splitter_->count(); ++i) {
1468 if (d.tabWorkArea(i)->setCurrentWorkArea(wa)) {
1469 LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea()
1470 << ", Current main wa: " << currentMainWorkArea());
1475 d.current_main_work_area_ = old_cmwa;
1477 LYXERR(Debug::DEBUG, "This is not a tabbed wa");
1478 on_currentWorkAreaChanged(wa);
1479 BufferView & bv = wa->bufferView();
1480 bv.cursor().fixIfBroken();
1482 wa->setUpdatesEnabled(true);
1483 LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
1487 void GuiView::removeWorkArea(GuiWorkArea * wa)
1489 LASSERT(wa, return);
1490 if (wa == d.current_work_area_) {
1492 disconnectBufferView();
1493 d.current_work_area_ = 0;
1494 d.current_main_work_area_ = 0;
1497 bool found_twa = false;
1498 for (int i = 0; i != d.splitter_->count(); ++i) {
1499 TabWorkArea * twa = d.tabWorkArea(i);
1500 if (twa->removeWorkArea(wa)) {
1501 // Found in this tab group, and deleted the GuiWorkArea.
1503 if (twa->count() != 0) {
1504 if (d.current_work_area_ == 0)
1505 // This means that we are closing the current GuiWorkArea, so
1506 // switch to the next GuiWorkArea in the found TabWorkArea.
1507 setCurrentWorkArea(twa->currentWorkArea());
1509 // No more WorkAreas in this tab group, so delete it.
1516 // It is not a tabbed work area (i.e., the search work area), so it
1517 // should be deleted by other means.
1518 LASSERT(found_twa, return);
1520 if (d.current_work_area_ == 0) {
1521 if (d.splitter_->count() != 0) {
1522 TabWorkArea * twa = d.currentTabWorkArea();
1523 setCurrentWorkArea(twa->currentWorkArea());
1525 // No more work areas, switch to the background widget.
1526 setCurrentWorkArea(0);
1532 LayoutBox * GuiView::getLayoutDialog() const
1538 void GuiView::updateLayoutList()
1541 d.layout_->updateContents(false);
1545 void GuiView::updateToolbars()
1547 ToolbarMap::iterator end = d.toolbars_.end();
1548 if (d.current_work_area_) {
1550 if (d.current_work_area_->bufferView().cursor().inMathed()
1551 && !d.current_work_area_->bufferView().cursor().inRegexped())
1552 context |= Toolbars::MATH;
1553 if (lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled())
1554 context |= Toolbars::TABLE;
1555 if (currentBufferView()->buffer().areChangesPresent()
1556 || (lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled()
1557 && lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onOff(true)))
1558 context |= Toolbars::REVIEW;
1559 if (lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled())
1560 context |= Toolbars::MATHMACROTEMPLATE;
1561 if (lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled())
1562 context |= Toolbars::IPA;
1563 if (command_execute_)
1564 context |= Toolbars::MINIBUFFER;
1566 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1567 it->second->update(context);
1569 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1570 it->second->update();
1574 void GuiView::setBuffer(Buffer * newBuffer)
1576 LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << endl);
1577 LASSERT(newBuffer, return);
1579 GuiWorkArea * wa = workArea(*newBuffer);
1582 newBuffer->masterBuffer()->updateBuffer();
1584 wa = addWorkArea(*newBuffer);
1585 // scroll to the position when the BufferView was last closed
1586 if (lyxrc.use_lastfilepos) {
1587 LastFilePosSection::FilePos filepos =
1588 theSession().lastFilePos().load(newBuffer->fileName());
1589 wa->bufferView().moveToPosition(filepos.pit, filepos.pos, 0, 0);
1592 //Disconnect the old buffer...there's no new one.
1595 connectBuffer(*newBuffer);
1596 connectBufferView(wa->bufferView());
1597 setCurrentWorkArea(wa);
1601 void GuiView::connectBuffer(Buffer & buf)
1603 buf.setGuiDelegate(this);
1607 void GuiView::disconnectBuffer()
1609 if (d.current_work_area_)
1610 d.current_work_area_->bufferView().buffer().setGuiDelegate(0);
1614 void GuiView::connectBufferView(BufferView & bv)
1616 bv.setGuiDelegate(this);
1620 void GuiView::disconnectBufferView()
1622 if (d.current_work_area_)
1623 d.current_work_area_->bufferView().setGuiDelegate(0);
1627 void GuiView::errors(string const & error_type, bool from_master)
1629 BufferView const * const bv = currentBufferView();
1633 #if EXPORT_in_THREAD
1634 // We are called with from_master == false by default, so we
1635 // have to figure out whether that is the case or not.
1636 ErrorList & el = bv->buffer().errorList(error_type);
1638 el = bv->buffer().masterBuffer()->errorList(error_type);
1642 ErrorList const & el = from_master ?
1643 bv->buffer().masterBuffer()->errorList(error_type) :
1644 bv->buffer().errorList(error_type);
1650 string data = error_type;
1652 data = "from_master|" + error_type;
1653 showDialog("errorlist", data);
1657 void GuiView::updateTocItem(string const & type, DocIterator const & dit)
1659 d.toc_models_.updateItem(toqstr(type), dit);
1663 void GuiView::structureChanged()
1665 d.toc_models_.reset(documentBufferView());
1666 // Navigator needs more than a simple update in this case. It needs to be
1668 updateDialog("toc", "");
1672 void GuiView::updateDialog(string const & name, string const & data)
1674 if (!isDialogVisible(name))
1677 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1678 if (it == d.dialogs_.end())
1681 Dialog * const dialog = it->second.get();
1682 if (dialog->isVisibleView())
1683 dialog->initialiseParams(data);
1687 BufferView * GuiView::documentBufferView()
1689 return currentMainWorkArea()
1690 ? ¤tMainWorkArea()->bufferView()
1695 BufferView const * GuiView::documentBufferView() const
1697 return currentMainWorkArea()
1698 ? ¤tMainWorkArea()->bufferView()
1703 BufferView * GuiView::currentBufferView()
1705 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1709 BufferView const * GuiView::currentBufferView() const
1711 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1715 docstring GuiView::GuiViewPrivate::autosaveAndDestroy(
1716 Buffer const * orig, Buffer * clone)
1718 bool const success = clone->autoSave();
1720 busyBuffers.remove(orig);
1722 ? _("Automatic save done.")
1723 : _("Automatic save failed!");
1727 void GuiView::autoSave()
1729 LYXERR(Debug::INFO, "Running autoSave()");
1731 Buffer * buffer = documentBufferView()
1732 ? &documentBufferView()->buffer() : 0;
1734 resetAutosaveTimers();
1738 GuiViewPrivate::busyBuffers.insert(buffer);
1739 QFuture<docstring> f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy,
1740 buffer, buffer->cloneBufferOnly());
1741 d.autosave_watcher_.setFuture(f);
1742 resetAutosaveTimers();
1746 void GuiView::resetAutosaveTimers()
1749 d.autosave_timeout_.restart();
1753 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1756 Buffer * buf = currentBufferView()
1757 ? ¤tBufferView()->buffer() : 0;
1758 Buffer * doc_buffer = documentBufferView()
1759 ? &(documentBufferView()->buffer()) : 0;
1762 /* In LyX/Mac, when a dialog is open, the menus of the
1763 application can still be accessed without giving focus to
1764 the main window. In this case, we want to disable the menu
1765 entries that are buffer-related.
1766 This code must not be used on Linux and Windows, since it
1767 would disable buffer-related entries when hovering over the
1768 menu (see bug #9574).
1770 if (cmd.origin() == FuncRequest::MENU && !hasFocus()) {
1776 // Check whether we need a buffer
1777 if (!lyxaction.funcHasFlag(cmd.action(), LyXAction::NoBuffer) && !buf) {
1778 // no, exit directly
1779 flag.message(from_utf8(N_("Command not allowed with"
1780 "out any document open")));
1781 flag.setEnabled(false);
1785 if (cmd.origin() == FuncRequest::TOC) {
1786 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
1787 if (!toc || !toc->getStatus(documentBufferView()->cursor(), cmd, flag))
1788 flag.setEnabled(false);
1792 switch(cmd.action()) {
1793 case LFUN_BUFFER_IMPORT:
1796 case LFUN_MASTER_BUFFER_UPDATE:
1797 case LFUN_MASTER_BUFFER_VIEW:
1799 && (doc_buffer->parent() != 0
1800 || doc_buffer->hasChildren())
1801 && !d.processing_thread_watcher_.isRunning();
1804 case LFUN_BUFFER_UPDATE:
1805 case LFUN_BUFFER_VIEW: {
1806 if (!doc_buffer || d.processing_thread_watcher_.isRunning()) {
1810 string format = to_utf8(cmd.argument());
1811 if (cmd.argument().empty())
1812 format = doc_buffer->params().getDefaultOutputFormat();
1813 enable = doc_buffer->params().isExportableFormat(format);
1817 case LFUN_BUFFER_RELOAD:
1818 enable = doc_buffer && !doc_buffer->isUnnamed()
1819 && doc_buffer->fileName().exists()
1820 && (!doc_buffer->isClean()
1821 || doc_buffer->isExternallyModified(Buffer::timestamp_method));
1824 case LFUN_BUFFER_CHILD_OPEN:
1825 enable = doc_buffer != 0;
1828 case LFUN_BUFFER_WRITE:
1829 enable = doc_buffer && (doc_buffer->isUnnamed() || !doc_buffer->isClean());
1832 //FIXME: This LFUN should be moved to GuiApplication.
1833 case LFUN_BUFFER_WRITE_ALL: {
1834 // We enable the command only if there are some modified buffers
1835 Buffer * first = theBufferList().first();
1840 // We cannot use a for loop as the buffer list is a cycle.
1842 if (!b->isClean()) {
1846 b = theBufferList().next(b);
1847 } while (b != first);
1851 case LFUN_BUFFER_WRITE_AS:
1852 case LFUN_BUFFER_EXPORT_AS:
1853 enable = doc_buffer != 0;
1856 case LFUN_BUFFER_CLOSE:
1857 case LFUN_VIEW_CLOSE:
1858 enable = doc_buffer != 0;
1861 case LFUN_BUFFER_CLOSE_ALL:
1862 enable = theBufferList().last() != theBufferList().first();
1865 case LFUN_VIEW_SPLIT:
1866 if (cmd.getArg(0) == "vertical")
1867 enable = doc_buffer && (d.splitter_->count() == 1 ||
1868 d.splitter_->orientation() == Qt::Vertical);
1870 enable = doc_buffer && (d.splitter_->count() == 1 ||
1871 d.splitter_->orientation() == Qt::Horizontal);
1874 case LFUN_TAB_GROUP_CLOSE:
1875 enable = d.tabWorkAreaCount() > 1;
1878 case LFUN_TOOLBAR_TOGGLE: {
1879 string const name = cmd.getArg(0);
1880 if (GuiToolbar * t = toolbar(name))
1881 flag.setOnOff(t->isVisible());
1884 docstring const msg =
1885 bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name));
1891 case LFUN_DROP_LAYOUTS_CHOICE:
1895 case LFUN_UI_TOGGLE:
1896 flag.setOnOff(isFullScreen());
1899 case LFUN_DIALOG_DISCONNECT_INSET:
1902 case LFUN_DIALOG_HIDE:
1903 // FIXME: should we check if the dialog is shown?
1906 case LFUN_DIALOG_TOGGLE:
1907 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1908 // fall through to set "enable"
1909 case LFUN_DIALOG_SHOW: {
1910 string const name = cmd.getArg(0);
1912 enable = name == "aboutlyx"
1913 || name == "file" //FIXME: should be removed.
1915 || name == "texinfo"
1916 || name == "progress"
1917 || name == "compare";
1918 else if (name == "character" || name == "symbols"
1919 || name == "mathdelimiter" || name == "mathmatrix") {
1920 if (!buf || buf->isReadonly())
1923 Cursor const & cur = currentBufferView()->cursor();
1924 enable = !(cur.inTexted() && cur.paragraph().isPassThru());
1927 else if (name == "latexlog")
1928 enable = FileName(doc_buffer->logName()).isReadableFile();
1929 else if (name == "spellchecker")
1930 enable = theSpellChecker()
1931 && !doc_buffer->isReadonly()
1932 && !doc_buffer->text().empty();
1933 else if (name == "vclog")
1934 enable = doc_buffer->lyxvc().inUse();
1938 case LFUN_DIALOG_UPDATE: {
1939 string const name = cmd.getArg(0);
1941 enable = name == "prefs";
1945 case LFUN_COMMAND_EXECUTE:
1947 case LFUN_MENU_OPEN:
1948 // Nothing to check.
1951 case LFUN_COMPLETION_INLINE:
1952 if (!d.current_work_area_
1953 || !d.current_work_area_->completer().inlinePossible(
1954 currentBufferView()->cursor()))
1958 case LFUN_COMPLETION_POPUP:
1959 if (!d.current_work_area_
1960 || !d.current_work_area_->completer().popupPossible(
1961 currentBufferView()->cursor()))
1966 if (!d.current_work_area_
1967 || !d.current_work_area_->completer().inlinePossible(
1968 currentBufferView()->cursor()))
1972 case LFUN_COMPLETION_ACCEPT:
1973 if (!d.current_work_area_
1974 || (!d.current_work_area_->completer().popupVisible()
1975 && !d.current_work_area_->completer().inlineVisible()
1976 && !d.current_work_area_->completer().completionAvailable()))
1980 case LFUN_COMPLETION_CANCEL:
1981 if (!d.current_work_area_
1982 || (!d.current_work_area_->completer().popupVisible()
1983 && !d.current_work_area_->completer().inlineVisible()))
1987 case LFUN_BUFFER_ZOOM_OUT:
1988 enable = doc_buffer && lyxrc.zoom > 10;
1991 case LFUN_BUFFER_ZOOM_IN:
1992 enable = doc_buffer != 0;
1995 case LFUN_BUFFER_MOVE_NEXT:
1996 case LFUN_BUFFER_MOVE_PREVIOUS:
1997 // we do not cycle when moving
1998 case LFUN_BUFFER_NEXT:
1999 case LFUN_BUFFER_PREVIOUS:
2000 // because we cycle, it doesn't matter whether on first or last
2001 enable = (d.currentTabWorkArea()->count() > 1);
2003 case LFUN_BUFFER_SWITCH:
2004 // toggle on the current buffer, but do not toggle off
2005 // the other ones (is that a good idea?)
2007 && to_utf8(cmd.argument()) == doc_buffer->absFileName())
2008 flag.setOnOff(true);
2011 case LFUN_VC_REGISTER:
2012 enable = doc_buffer && !doc_buffer->lyxvc().inUse();
2014 case LFUN_VC_RENAME:
2015 enable = doc_buffer && doc_buffer->lyxvc().renameEnabled();
2018 enable = doc_buffer && doc_buffer->lyxvc().copyEnabled();
2020 case LFUN_VC_CHECK_IN:
2021 enable = doc_buffer && doc_buffer->lyxvc().checkInEnabled();
2023 case LFUN_VC_CHECK_OUT:
2024 enable = doc_buffer && doc_buffer->lyxvc().checkOutEnabled();
2026 case LFUN_VC_LOCKING_TOGGLE:
2027 enable = doc_buffer && !doc_buffer->isReadonly()
2028 && doc_buffer->lyxvc().lockingToggleEnabled();
2029 flag.setOnOff(enable && doc_buffer->lyxvc().locking());
2031 case LFUN_VC_REVERT:
2032 enable = doc_buffer && doc_buffer->lyxvc().inUse() && !doc_buffer->isReadonly();
2034 case LFUN_VC_UNDO_LAST:
2035 enable = doc_buffer && doc_buffer->lyxvc().undoLastEnabled();
2037 case LFUN_VC_REPO_UPDATE:
2038 enable = doc_buffer && doc_buffer->lyxvc().repoUpdateEnabled();
2040 case LFUN_VC_COMMAND: {
2041 if (cmd.argument().empty())
2043 if (!doc_buffer && contains(cmd.getArg(0), 'D'))
2047 case LFUN_VC_COMPARE:
2048 enable = doc_buffer && doc_buffer->lyxvc().prepareFileRevisionEnabled();
2051 case LFUN_SERVER_GOTO_FILE_ROW:
2053 case LFUN_FORWARD_SEARCH:
2054 enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty());
2057 case LFUN_FILE_INSERT_PLAINTEXT:
2058 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
2059 enable = documentBufferView() && documentBufferView()->cursor().inTexted();
2062 case LFUN_SPELLING_CONTINUOUSLY:
2063 flag.setOnOff(lyxrc.spellcheck_continuously);
2071 flag.setEnabled(false);
2077 static FileName selectTemplateFile()
2079 FileDialog dlg(qt_("Select template file"));
2080 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2081 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2083 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
2084 QStringList(qt_("LyX Documents (*.lyx)")));
2086 if (result.first == FileDialog::Later)
2088 if (result.second.isEmpty())
2090 return FileName(fromqstr(result.second));
2094 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
2098 Buffer * newBuffer = 0;
2100 newBuffer = checkAndLoadLyXFile(filename);
2101 } catch (ExceptionMessage const & e) {
2108 message(_("Document not loaded."));
2112 setBuffer(newBuffer);
2113 newBuffer->errors("Parse");
2116 theSession().lastFiles().add(filename);
2122 void GuiView::openDocument(string const & fname)
2124 string initpath = lyxrc.document_path;
2126 if (documentBufferView()) {
2127 string const trypath = documentBufferView()->buffer().filePath();
2128 // If directory is writeable, use this as default.
2129 if (FileName(trypath).isDirWritable())
2135 if (fname.empty()) {
2136 FileDialog dlg(qt_("Select document to open"));
2137 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2138 dlg.setButton2(qt_("Examples|#E#e"),
2139 toqstr(addPath(package().system_support().absFileName(), "examples")));
2141 QStringList const filter(qt_("LyX Documents (*.lyx)"));
2142 FileDialog::Result result =
2143 dlg.open(toqstr(initpath), filter);
2145 if (result.first == FileDialog::Later)
2148 filename = fromqstr(result.second);
2150 // check selected filename
2151 if (filename.empty()) {
2152 message(_("Canceled."));
2158 // get absolute path of file and add ".lyx" to the filename if
2160 FileName const fullname =
2161 fileSearch(string(), filename, "lyx", support::may_not_exist);
2162 if (!fullname.empty())
2163 filename = fullname.absFileName();
2165 if (!fullname.onlyPath().isDirectory()) {
2166 Alert::warning(_("Invalid filename"),
2167 bformat(_("The directory in the given path\n%1$s\ndoes not exist."),
2168 from_utf8(fullname.absFileName())));
2172 // if the file doesn't exist and isn't already open (bug 6645),
2173 // let the user create one
2174 if (!fullname.exists() && !theBufferList().exists(fullname) &&
2175 !LyXVC::file_not_found_hook(fullname)) {
2176 // the user specifically chose this name. Believe him.
2177 Buffer * const b = newFile(filename, string(), true);
2183 docstring const disp_fn = makeDisplayPath(filename);
2184 message(bformat(_("Opening document %1$s..."), disp_fn));
2187 Buffer * buf = loadDocument(fullname);
2189 str2 = bformat(_("Document %1$s opened."), disp_fn);
2190 if (buf->lyxvc().inUse())
2191 str2 += " " + from_utf8(buf->lyxvc().versionString()) +
2192 " " + _("Version control detected.");
2194 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2199 // FIXME: clean that
2200 static bool import(GuiView * lv, FileName const & filename,
2201 string const & format, ErrorList & errorList)
2203 FileName const lyxfile(support::changeExtension(filename.absFileName(), ".lyx"));
2205 string loader_format;
2206 vector<string> loaders = theConverters().loaders();
2207 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
2208 vector<string>::const_iterator it = loaders.begin();
2209 vector<string>::const_iterator en = loaders.end();
2210 for (; it != en; ++it) {
2211 if (!theConverters().isReachable(format, *it))
2214 string const tofile =
2215 support::changeExtension(filename.absFileName(),
2216 formats.extension(*it));
2217 if (!theConverters().convert(0, filename, FileName(tofile),
2218 filename, format, *it, errorList))
2220 loader_format = *it;
2223 if (loader_format.empty()) {
2224 frontend::Alert::error(_("Couldn't import file"),
2225 bformat(_("No information for importing the format %1$s."),
2226 formats.prettyName(format)));
2230 loader_format = format;
2232 if (loader_format == "lyx") {
2233 Buffer * buf = lv->loadDocument(lyxfile);
2237 Buffer * const b = newFile(lyxfile.absFileName(), string(), true);
2241 bool as_paragraphs = loader_format == "textparagraph";
2242 string filename2 = (loader_format == format) ? filename.absFileName()
2243 : support::changeExtension(filename.absFileName(),
2244 formats.extension(loader_format));
2245 lv->currentBufferView()->insertPlaintextFile(FileName(filename2),
2247 guiApp->setCurrentView(lv);
2248 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
2255 void GuiView::importDocument(string const & argument)
2258 string filename = split(argument, format, ' ');
2260 LYXERR(Debug::INFO, format << " file: " << filename);
2262 // need user interaction
2263 if (filename.empty()) {
2264 string initpath = lyxrc.document_path;
2265 if (documentBufferView()) {
2266 string const trypath = documentBufferView()->buffer().filePath();
2267 // If directory is writeable, use this as default.
2268 if (FileName(trypath).isDirWritable())
2272 docstring const text = bformat(_("Select %1$s file to import"),
2273 formats.prettyName(format));
2275 FileDialog dlg(toqstr(text));
2276 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2277 dlg.setButton2(qt_("Examples|#E#e"),
2278 toqstr(addPath(package().system_support().absFileName(), "examples")));
2280 docstring filter = formats.prettyName(format);
2283 filter += from_utf8(formats.extensions(format));
2286 FileDialog::Result result =
2287 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
2289 if (result.first == FileDialog::Later)
2292 filename = fromqstr(result.second);
2294 // check selected filename
2295 if (filename.empty())
2296 message(_("Canceled."));
2299 if (filename.empty())
2302 // get absolute path of file
2303 FileName const fullname(support::makeAbsPath(filename));
2305 // Can happen if the user entered a path into the dialog
2307 if (fullname.onlyFileName().empty()) {
2308 docstring msg = bformat(_("The file name '%1$s' is invalid!\n"
2309 "Aborting import."),
2310 from_utf8(fullname.absFileName()));
2311 frontend::Alert::error(_("File name error"), msg);
2312 message(_("Canceled."));
2317 FileName const lyxfile(support::changeExtension(fullname.absFileName(), ".lyx"));
2319 // Check if the document already is open
2320 Buffer * buf = theBufferList().getBuffer(lyxfile);
2323 if (!closeBuffer()) {
2324 message(_("Canceled."));
2329 docstring const displaypath = makeDisplayPath(lyxfile.absFileName(), 30);
2331 // if the file exists already, and we didn't do
2332 // -i lyx thefile.lyx, warn
2333 if (lyxfile.exists() && fullname != lyxfile) {
2335 docstring text = bformat(_("The document %1$s already exists.\n\n"
2336 "Do you want to overwrite that document?"), displaypath);
2337 int const ret = Alert::prompt(_("Overwrite document?"),
2338 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2341 message(_("Canceled."));
2346 message(bformat(_("Importing %1$s..."), displaypath));
2347 ErrorList errorList;
2348 if (import(this, fullname, format, errorList))
2349 message(_("imported."));
2351 message(_("file not imported!"));
2353 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2357 void GuiView::newDocument(string const & filename, bool from_template)
2359 FileName initpath(lyxrc.document_path);
2360 if (documentBufferView()) {
2361 FileName const trypath(documentBufferView()->buffer().filePath());
2362 // If directory is writeable, use this as default.
2363 if (trypath.isDirWritable())
2367 string templatefile;
2368 if (from_template) {
2369 templatefile = selectTemplateFile().absFileName();
2370 if (templatefile.empty())
2375 if (filename.empty())
2376 b = newUnnamedFile(initpath, to_utf8(_("newfile")), templatefile);
2378 b = newFile(filename, templatefile, true);
2383 // If no new document could be created, it is unsure
2384 // whether there is a valid BufferView.
2385 if (currentBufferView())
2386 // Ensure the cursor is correctly positioned on screen.
2387 currentBufferView()->showCursor();
2391 void GuiView::insertLyXFile(docstring const & fname)
2393 BufferView * bv = documentBufferView();
2398 FileName filename(to_utf8(fname));
2399 if (filename.empty()) {
2400 // Launch a file browser
2402 string initpath = lyxrc.document_path;
2403 string const trypath = bv->buffer().filePath();
2404 // If directory is writeable, use this as default.
2405 if (FileName(trypath).isDirWritable())
2409 FileDialog dlg(qt_("Select LyX document to insert"));
2410 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2411 dlg.setButton2(qt_("Examples|#E#e"),
2412 toqstr(addPath(package().system_support().absFileName(),
2415 FileDialog::Result result = dlg.open(toqstr(initpath),
2416 QStringList(qt_("LyX Documents (*.lyx)")));
2418 if (result.first == FileDialog::Later)
2422 filename.set(fromqstr(result.second));
2424 // check selected filename
2425 if (filename.empty()) {
2426 // emit message signal.
2427 message(_("Canceled."));
2432 bv->insertLyXFile(filename);
2433 bv->buffer().errors("Parse");
2437 bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kind)
2439 FileName fname = b.fileName();
2440 FileName const oldname = fname;
2442 if (!newname.empty()) {
2444 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFileName());
2446 // Switch to this Buffer.
2449 // No argument? Ask user through dialog.
2451 FileDialog dlg(qt_("Choose a filename to save document as"));
2452 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2453 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2455 if (!isLyXFileName(fname.absFileName()))
2456 fname.changeExtension(".lyx");
2458 FileDialog::Result result =
2459 dlg.save(toqstr(fname.onlyPath().absFileName()),
2460 QStringList(qt_("LyX Documents (*.lyx)")),
2461 toqstr(fname.onlyFileName()));
2463 if (result.first == FileDialog::Later)
2466 fname.set(fromqstr(result.second));
2471 if (!isLyXFileName(fname.absFileName()))
2472 fname.changeExtension(".lyx");
2475 // fname is now the new Buffer location.
2477 // if there is already a Buffer open with this name, we do not want
2478 // to have another one. (the second test makes sure we're not just
2479 // trying to overwrite ourselves, which is fine.)
2480 if (theBufferList().exists(fname) && fname != oldname
2481 && theBufferList().getBuffer(fname) != &b) {
2482 docstring const text =
2483 bformat(_("The file\n%1$s\nis already open in your current session.\n"
2484 "Please close it before attempting to overwrite it.\n"
2485 "Do you want to choose a new filename?"),
2486 from_utf8(fname.absFileName()));
2487 int const ret = Alert::prompt(_("Chosen File Already Open"),
2488 text, 0, 1, _("&Rename"), _("&Cancel"));
2490 case 0: return renameBuffer(b, docstring(), kind);
2491 case 1: return false;
2496 bool const existsLocal = fname.exists();
2497 bool const existsInVC = LyXVC::fileInVC(fname);
2498 if (existsLocal || existsInVC) {
2499 docstring const file = makeDisplayPath(fname.absFileName(), 30);
2500 if (kind != LV_WRITE_AS && existsInVC) {
2501 // renaming to a name that is already in VC
2503 docstring text = bformat(_("The document %1$s "
2504 "is already registered.\n\n"
2505 "Do you want to choose a new name?"),
2507 docstring const title = (kind == LV_VC_RENAME) ?
2508 _("Rename document?") : _("Copy document?");
2509 docstring const button = (kind == LV_VC_RENAME) ?
2510 _("&Rename") : _("&Copy");
2511 int const ret = Alert::prompt(title, text, 0, 1,
2512 button, _("&Cancel"));
2514 case 0: return renameBuffer(b, docstring(), kind);
2515 case 1: return false;
2520 docstring text = bformat(_("The document %1$s "
2521 "already exists.\n\n"
2522 "Do you want to overwrite that document?"),
2524 int const ret = Alert::prompt(_("Overwrite document?"),
2525 text, 0, 2, _("&Overwrite"),
2526 _("&Rename"), _("&Cancel"));
2529 case 1: return renameBuffer(b, docstring(), kind);
2530 case 2: return false;
2536 case LV_VC_RENAME: {
2537 string msg = b.lyxvc().rename(fname);
2540 message(from_utf8(msg));
2544 string msg = b.lyxvc().copy(fname);
2547 message(from_utf8(msg));
2553 // LyXVC created the file already in case of LV_VC_RENAME or
2554 // LV_VC_COPY, but call saveBuffer() nevertheless to get
2555 // relative paths of included stuff right if we moved e.g. from
2556 // /a/b.lyx to /a/c/b.lyx.
2558 bool const saved = saveBuffer(b, fname);
2565 struct PrettyNameComparator
2567 bool operator()(Format const *first, Format const *second) const {
2568 return compare_no_case(translateIfPossible(from_ascii(first->prettyname())),
2569 translateIfPossible(from_ascii(second->prettyname()))) <= 0;
2574 bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
2576 FileName fname = b.fileName();
2578 FileDialog dlg(qt_("Choose a filename to export the document as"));
2579 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2582 QString const anyformat = qt_("Guess from extension (*.*)");
2584 Formats::const_iterator it = formats.begin();
2585 vector<Format const *> export_formats;
2586 for (; it != formats.end(); ++it)
2587 if (it->documentFormat())
2588 export_formats.push_back(&(*it));
2589 PrettyNameComparator cmp;
2590 sort(export_formats.begin(), export_formats.end(), cmp);
2591 vector<Format const *>::const_iterator fit = export_formats.begin();
2592 map<QString, string> fmap;
2595 for (; fit != export_formats.end(); ++fit) {
2596 docstring const loc_prettyname =
2597 translateIfPossible(from_utf8((*fit)->prettyname()));
2598 QString const loc_filter = toqstr(bformat(from_ascii("%1$s (*.%2$s)"),
2600 from_ascii((*fit)->extension())));
2601 types << loc_filter;
2602 fmap[loc_filter] = (*fit)->name();
2603 if (from_ascii((*fit)->name()) == iformat) {
2604 filter = loc_filter;
2605 ext = (*fit)->extension();
2608 string ofname = fname.onlyFileName();
2610 ofname = support::changeExtension(ofname, ext);
2611 FileDialog::Result result =
2612 dlg.save(toqstr(fname.onlyPath().absFileName()),
2616 if (result.first != FileDialog::Chosen)
2620 fname.set(fromqstr(result.second));
2621 if (filter == anyformat)
2622 fmt_name = formats.getFormatFromExtension(fname.extension());
2624 fmt_name = fmap[filter];
2625 LYXERR(Debug::FILES, "filter=" << fromqstr(filter)
2626 << ", fmt_name=" << fmt_name << ", fname=" << fname.absFileName());
2628 if (fmt_name.empty() || fname.empty())
2631 // fname is now the new Buffer location.
2632 if (FileName(fname).exists()) {
2633 docstring const file = makeDisplayPath(fname.absFileName(), 30);
2634 docstring text = bformat(_("The document %1$s already "
2635 "exists.\n\nDo you want to "
2636 "overwrite that document?"),
2638 int const ret = Alert::prompt(_("Overwrite document?"),
2639 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
2642 case 1: return exportBufferAs(b, from_ascii(fmt_name));
2643 case 2: return false;
2647 FuncRequest cmd(LFUN_BUFFER_EXPORT, fmt_name + " " + fname.absFileName());
2650 return dr.dispatched();
2654 bool GuiView::saveBuffer(Buffer & b)
2656 return saveBuffer(b, FileName());
2660 bool GuiView::saveBuffer(Buffer & b, FileName const & fn)
2662 if (workArea(b) && workArea(b)->inDialogMode())
2665 if (fn.empty() && b.isUnnamed())
2666 return renameBuffer(b, docstring());
2668 bool const success = (fn.empty() ? b.save() : b.saveAs(fn));
2670 theSession().lastFiles().add(b.fileName());
2674 // Switch to this Buffer.
2677 // FIXME: we don't tell the user *WHY* the save failed !!
2678 docstring const file = makeDisplayPath(b.absFileName(), 30);
2679 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
2680 "Do you want to rename the document and "
2681 "try again?"), file);
2682 int const ret = Alert::prompt(_("Rename and save?"),
2683 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
2686 if (!renameBuffer(b, docstring()))
2695 return saveBuffer(b, fn);
2699 bool GuiView::hideWorkArea(GuiWorkArea * wa)
2701 return closeWorkArea(wa, false);
2705 // We only want to close the buffer if it is not visible in other workareas
2706 // of the same view, nor in other views, and if this is not a child
2707 bool GuiView::closeWorkArea(GuiWorkArea * wa)
2709 Buffer & buf = wa->bufferView().buffer();
2711 bool last_wa = d.countWorkAreasOf(buf) == 1
2712 && !inOtherView(buf) && !buf.parent();
2714 bool close_buffer = last_wa;
2717 if (lyxrc.close_buffer_with_last_view == "yes")
2719 else if (lyxrc.close_buffer_with_last_view == "no")
2720 close_buffer = false;
2723 if (buf.isUnnamed())
2724 file = from_utf8(buf.fileName().onlyFileName());
2726 file = buf.fileName().displayName(30);
2727 docstring const text = bformat(
2728 _("Last view on document %1$s is being closed.\n"
2729 "Would you like to close or hide the document?\n"
2731 "Hidden documents can be displayed back through\n"
2732 "the menu: View->Hidden->...\n"
2734 "To remove this question, set your preference in:\n"
2735 " Tools->Preferences->Look&Feel->UserInterface\n"
2737 int ret = Alert::prompt(_("Close or hide document?"),
2738 text, 0, 1, _("&Close"), _("&Hide"));
2739 close_buffer = (ret == 0);
2743 return closeWorkArea(wa, close_buffer);
2747 bool GuiView::closeBuffer()
2749 GuiWorkArea * wa = currentMainWorkArea();
2750 setCurrentWorkArea(wa);
2751 Buffer & buf = wa->bufferView().buffer();
2752 return wa && closeWorkArea(wa, !buf.parent());
2756 void GuiView::writeSession() const {
2757 GuiWorkArea const * active_wa = currentMainWorkArea();
2758 for (int i = 0; i < d.splitter_->count(); ++i) {
2759 TabWorkArea * twa = d.tabWorkArea(i);
2760 for (int j = 0; j < twa->count(); ++j) {
2761 GuiWorkArea * wa = static_cast<GuiWorkArea *>(twa->widget(j));
2762 Buffer & buf = wa->bufferView().buffer();
2763 theSession().lastOpened().add(buf.fileName(), wa == active_wa);
2769 bool GuiView::closeBufferAll()
2771 // Close the workareas in all other views
2772 QList<int> const ids = guiApp->viewIds();
2773 for (int i = 0; i != ids.size(); ++i) {
2774 if (id_ != ids[i] && !guiApp->view(ids[i]).closeWorkAreaAll())
2778 // Close our own workareas
2779 if (!closeWorkAreaAll())
2782 // Now close the hidden buffers. We prevent hidden buffers from being
2783 // dirty, so we can just close them.
2784 theBufferList().closeAll();
2789 bool GuiView::closeWorkAreaAll()
2791 setCurrentWorkArea(currentMainWorkArea());
2793 // We might be in a situation that there is still a tabWorkArea, but
2794 // there are no tabs anymore. This can happen when we get here after a
2795 // TabWorkArea::lastWorkAreaRemoved() signal. Therefore we count how
2796 // many TabWorkArea's have no documents anymore.
2799 // We have to call count() each time, because it can happen that
2800 // more than one splitter will disappear in one iteration (bug 5998).
2801 while (d.splitter_->count() > empty_twa) {
2802 TabWorkArea * twa = d.tabWorkArea(empty_twa);
2804 if (twa->count() == 0)
2807 setCurrentWorkArea(twa->currentWorkArea());
2808 if (!closeTabWorkArea(twa))
2816 bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
2821 Buffer & buf = wa->bufferView().buffer();
2823 if (GuiViewPrivate::busyBuffers.contains(&buf)) {
2824 Alert::warning(_("Close document"),
2825 _("Document could not be closed because it is being processed by LyX."));
2830 return closeBuffer(buf);
2832 if (!inMultiTabs(wa))
2833 if (!saveBufferIfNeeded(buf, true))
2841 bool GuiView::closeBuffer(Buffer & buf)
2843 // If we are in a close_event all children will be closed in some time,
2844 // so no need to do it here. This will ensure that the children end up
2845 // in the session file in the correct order. If we close the master
2846 // buffer, we can close or release the child buffers here too.
2847 bool success = true;
2849 ListOfBuffers clist = buf.getChildren();
2850 ListOfBuffers::const_iterator it = clist.begin();
2851 ListOfBuffers::const_iterator const bend = clist.end();
2852 for (; it != bend; ++it) {
2853 Buffer * child_buf = *it;
2854 if (theBufferList().isOthersChild(&buf, child_buf)) {
2855 child_buf->setParent(0);
2859 // FIXME: should we look in other tabworkareas?
2860 // ANSWER: I don't think so. I've tested, and if the child is
2861 // open in some other window, it closes without a problem.
2862 GuiWorkArea * child_wa = workArea(*child_buf);
2864 success = closeWorkArea(child_wa, true);
2868 // In this case the child buffer is open but hidden.
2869 // It therefore should not (MUST NOT) be dirty!
2870 LATTEST(child_buf->isClean());
2871 theBufferList().release(child_buf);
2876 // goto bookmark to update bookmark pit.
2877 // FIXME: we should update only the bookmarks related to this buffer!
2878 LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
2879 for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
2880 guiApp->gotoBookmark(i+1, false, false);
2882 if (saveBufferIfNeeded(buf, false)) {
2883 buf.removeAutosaveFile();
2884 theBufferList().release(&buf);
2888 // open all children again to avoid a crash because of dangling
2889 // pointers (bug 6603)
2895 bool GuiView::closeTabWorkArea(TabWorkArea * twa)
2897 while (twa == d.currentTabWorkArea()) {
2898 twa->setCurrentIndex(twa->count() - 1);
2900 GuiWorkArea * wa = twa->currentWorkArea();
2901 Buffer & b = wa->bufferView().buffer();
2903 // We only want to close the buffer if the same buffer is not visible
2904 // in another view, and if this is not a child and if we are closing
2905 // a view (not a tabgroup).
2906 bool const close_buffer =
2907 !inOtherView(b) && !b.parent() && closing_;
2909 if (!closeWorkArea(wa, close_buffer))
2916 bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding)
2918 if (buf.isClean() || buf.paragraphs().empty())
2921 // Switch to this Buffer.
2926 if (buf.isUnnamed())
2927 file = from_utf8(buf.fileName().onlyFileName());
2929 file = buf.fileName().displayName(30);
2931 // Bring this window to top before asking questions.
2936 if (hiding && buf.isUnnamed()) {
2937 docstring const text = bformat(_("The document %1$s has not been "
2938 "saved yet.\n\nDo you want to save "
2939 "the document?"), file);
2940 ret = Alert::prompt(_("Save new document?"),
2941 text, 0, 1, _("&Save"), _("&Cancel"));
2945 docstring const text = bformat(_("The document %1$s has unsaved changes."
2946 "\n\nDo you want to save the document or discard the changes?"), file);
2947 ret = Alert::prompt(_("Save changed document?"),
2948 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
2953 if (!saveBuffer(buf))
2957 // If we crash after this we could have no autosave file
2958 // but I guess this is really improbable (Jug).
2959 // Sometimes improbable things happen:
2960 // - see bug http://www.lyx.org/trac/ticket/6587 (ps)
2961 // buf.removeAutosaveFile();
2963 // revert all changes
2974 bool GuiView::inMultiTabs(GuiWorkArea * wa)
2976 Buffer & buf = wa->bufferView().buffer();
2978 for (int i = 0; i != d.splitter_->count(); ++i) {
2979 GuiWorkArea * wa_ = d.tabWorkArea(i)->workArea(buf);
2980 if (wa_ && wa_ != wa)
2983 return inOtherView(buf);
2987 bool GuiView::inOtherView(Buffer & buf)
2989 QList<int> const ids = guiApp->viewIds();
2991 for (int i = 0; i != ids.size(); ++i) {
2995 if (guiApp->view(ids[i]).workArea(buf))
3002 void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np, bool const move)
3004 if (!documentBufferView())
3007 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3008 Buffer * const curbuf = &documentBufferView()->buffer();
3009 int nwa = twa->count();
3010 for (int i = 0; i < nwa; ++i) {
3011 if (&workArea(i)->bufferView().buffer() == curbuf) {
3013 if (np == NEXTBUFFER)
3014 next_index = (i == nwa - 1 ? 0 : i + 1);
3016 next_index = (i == 0 ? nwa - 1 : i - 1);
3018 twa->moveTab(i, next_index);
3020 setBuffer(&workArea(next_index)->bufferView().buffer());
3028 /// make sure the document is saved
3029 static bool ensureBufferClean(Buffer * buffer)
3031 LASSERT(buffer, return false);
3032 if (buffer->isClean() && !buffer->isUnnamed())
3035 docstring const file = buffer->fileName().displayName(30);
3038 if (!buffer->isUnnamed()) {
3039 text = bformat(_("The document %1$s has unsaved "
3040 "changes.\n\nDo you want to save "
3041 "the document?"), file);
3042 title = _("Save changed document?");
3045 text = bformat(_("The document %1$s has not been "
3046 "saved yet.\n\nDo you want to save "
3047 "the document?"), file);
3048 title = _("Save new document?");
3050 int const ret = Alert::prompt(title, text, 0, 1, _("&Save"), _("&Cancel"));
3053 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
3055 return buffer->isClean() && !buffer->isUnnamed();
3059 bool GuiView::reloadBuffer(Buffer & buf)
3061 Buffer::ReadStatus status = buf.reload();
3062 return status == Buffer::ReadSuccess;
3066 void GuiView::checkExternallyModifiedBuffers()
3068 BufferList::iterator bit = theBufferList().begin();
3069 BufferList::iterator const bend = theBufferList().end();
3070 for (; bit != bend; ++bit) {
3071 Buffer * buf = *bit;
3072 if (buf->fileName().exists()
3073 && buf->isExternallyModified(Buffer::checksum_method)) {
3074 docstring text = bformat(_("Document \n%1$s\n has been externally modified."
3075 " Reload now? Any local changes will be lost."),
3076 from_utf8(buf->absFileName()));
3077 int const ret = Alert::prompt(_("Reload externally changed document?"),
3078 text, 0, 1, _("&Reload"), _("&Cancel"));
3086 void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
3088 Buffer * buffer = documentBufferView()
3089 ? &(documentBufferView()->buffer()) : 0;
3091 switch (cmd.action()) {
3092 case LFUN_VC_REGISTER:
3093 if (!buffer || !ensureBufferClean(buffer))
3095 if (!buffer->lyxvc().inUse()) {
3096 if (buffer->lyxvc().registrer()) {
3097 reloadBuffer(*buffer);
3098 dr.clearMessageUpdate();
3103 case LFUN_VC_RENAME:
3104 case LFUN_VC_COPY: {
3105 if (!buffer || !ensureBufferClean(buffer))
3107 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
3108 if (buffer->lyxvc().isCheckInWithConfirmation()) {
3109 // Some changes are not yet committed.
3110 // We test here and not in getStatus(), since
3111 // this test is expensive.
3113 LyXVC::CommandResult ret =
3114 buffer->lyxvc().checkIn(log);
3116 if (ret == LyXVC::ErrorCommand ||
3117 ret == LyXVC::VCSuccess)
3118 reloadBuffer(*buffer);
3119 if (buffer->lyxvc().isCheckInWithConfirmation()) {
3120 frontend::Alert::error(
3121 _("Revision control error."),
3122 _("Document could not be checked in."));
3126 RenameKind const kind = (cmd.action() == LFUN_VC_RENAME) ?
3127 LV_VC_RENAME : LV_VC_COPY;
3128 renameBuffer(*buffer, cmd.argument(), kind);
3133 case LFUN_VC_CHECK_IN:
3134 if (!buffer || !ensureBufferClean(buffer))
3136 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
3138 LyXVC::CommandResult ret = buffer->lyxvc().checkIn(log);
3140 // Only skip reloading if the checkin was cancelled or
3141 // an error occurred before the real checkin VCS command
3142 // was executed, since the VCS might have changed the
3143 // file even if it could not checkin successfully.
3144 if (ret == LyXVC::ErrorCommand || ret == LyXVC::VCSuccess)
3145 reloadBuffer(*buffer);
3149 case LFUN_VC_CHECK_OUT:
3150 if (!buffer || !ensureBufferClean(buffer))
3152 if (buffer->lyxvc().inUse()) {
3153 dr.setMessage(buffer->lyxvc().checkOut());
3154 reloadBuffer(*buffer);
3158 case LFUN_VC_LOCKING_TOGGLE:
3159 LASSERT(buffer, return);
3160 if (!ensureBufferClean(buffer) || buffer->isReadonly())
3162 if (buffer->lyxvc().inUse()) {
3163 string res = buffer->lyxvc().lockingToggle();
3165 frontend::Alert::error(_("Revision control error."),
3166 _("Error when setting the locking property."));
3169 reloadBuffer(*buffer);
3174 case LFUN_VC_REVERT:
3175 LASSERT(buffer, return);
3176 if (buffer->lyxvc().revert()) {
3177 reloadBuffer(*buffer);
3178 dr.clearMessageUpdate();
3182 case LFUN_VC_UNDO_LAST:
3183 LASSERT(buffer, return);
3184 buffer->lyxvc().undoLast();
3185 reloadBuffer(*buffer);
3186 dr.clearMessageUpdate();
3189 case LFUN_VC_REPO_UPDATE:
3190 LASSERT(buffer, return);
3191 if (ensureBufferClean(buffer)) {
3192 dr.setMessage(buffer->lyxvc().repoUpdate());
3193 checkExternallyModifiedBuffers();
3197 case LFUN_VC_COMMAND: {
3198 string flag = cmd.getArg(0);
3199 if (buffer && contains(flag, 'R') && !ensureBufferClean(buffer))
3202 if (contains(flag, 'M')) {
3203 if (!Alert::askForText(message, _("LyX VC: Log Message")))
3206 string path = cmd.getArg(1);
3207 if (contains(path, "$$p") && buffer)
3208 path = subst(path, "$$p", buffer->filePath());
3209 LYXERR(Debug::LYXVC, "Directory: " << path);
3211 if (!pp.isReadableDirectory()) {
3212 lyxerr << _("Directory is not accessible.") << endl;
3215 support::PathChanger p(pp);
3217 string command = cmd.getArg(2);
3218 if (command.empty())
3221 command = subst(command, "$$i", buffer->absFileName());
3222 command = subst(command, "$$p", buffer->filePath());
3224 command = subst(command, "$$m", to_utf8(message));
3225 LYXERR(Debug::LYXVC, "Command: " << command);
3227 one.startscript(Systemcall::Wait, command);
3231 if (contains(flag, 'I'))
3232 buffer->markDirty();
3233 if (contains(flag, 'R'))
3234 reloadBuffer(*buffer);
3239 case LFUN_VC_COMPARE: {
3241 if (cmd.argument().empty()) {
3242 lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "comparehistory"));
3246 string rev1 = cmd.getArg(0);
3250 if (!buffer->lyxvc().prepareFileRevision(rev1, f1))
3253 if (isStrInt(rev1) && convert<int>(rev1) <= 0) {
3254 f2 = buffer->absFileName();
3256 string rev2 = cmd.getArg(1);
3260 if (!buffer->lyxvc().prepareFileRevision(rev2, f2))
3264 LYXERR(Debug::LYXVC, "Launching comparison for fetched revisions:\n" <<
3265 f1 << "\n" << f2 << "\n" );
3266 string par = "compare run " + quoteName(f1) + " " + quoteName(f2);
3267 lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, par));
3277 void GuiView::openChildDocument(string const & fname)
3279 LASSERT(documentBufferView(), return);
3280 Buffer & buffer = documentBufferView()->buffer();
3281 FileName const filename = support::makeAbsPath(fname, buffer.filePath());
3282 documentBufferView()->saveBookmark(false);
3284 if (theBufferList().exists(filename)) {
3285 child = theBufferList().getBuffer(filename);
3288 message(bformat(_("Opening child document %1$s..."),
3289 makeDisplayPath(filename.absFileName())));
3290 child = loadDocument(filename, false);
3292 // Set the parent name of the child document.
3293 // This makes insertion of citations and references in the child work,
3294 // when the target is in the parent or another child document.
3296 child->setParent(&buffer);
3300 bool GuiView::goToFileRow(string const & argument)
3304 size_t i = argument.find_last_of(' ');
3305 if (i != string::npos) {
3306 file_name = os::internal_path(trim(argument.substr(0, i)));
3307 istringstream is(argument.substr(i + 1));
3312 if (i == string::npos) {
3313 LYXERR0("Wrong argument: " << argument);
3317 string const abstmp = package().temp_dir().absFileName();
3318 string const realtmp = package().temp_dir().realPath();
3319 // We have to use os::path_prefix_is() here, instead of
3320 // simply prefixIs(), because the file name comes from
3321 // an external application and may need case adjustment.
3322 if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
3323 || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
3324 // Needed by inverse dvi search. If it is a file
3325 // in tmpdir, call the apropriated function.
3326 // If tmpdir is a symlink, we may have the real
3327 // path passed back, so we correct for that.
3328 if (!prefixIs(file_name, abstmp))
3329 file_name = subst(file_name, realtmp, abstmp);
3330 buf = theBufferList().getBufferFromTmp(file_name);
3332 // Must replace extension of the file to be .lyx
3333 // and get full path
3334 FileName const s = fileSearch(string(),
3335 support::changeExtension(file_name, ".lyx"), "lyx");
3336 // Either change buffer or load the file
3337 if (theBufferList().exists(s))
3338 buf = theBufferList().getBuffer(s);
3339 else if (s.exists()) {
3340 buf = loadDocument(s);
3345 _("File does not exist: %1$s"),
3346 makeDisplayPath(file_name)));
3352 _("No buffer for file: %1$s."),
3353 makeDisplayPath(file_name))
3358 documentBufferView()->setCursorFromRow(row);
3364 Buffer::ExportStatus GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * clone, string const & format)
3366 Buffer::ExportStatus const status = func(format);
3368 // the cloning operation will have produced a clone of the entire set of
3369 // documents, starting from the master. so we must delete those.
3370 Buffer * mbuf = const_cast<Buffer *>(clone->masterBuffer());
3372 busyBuffers.remove(orig);
3377 Buffer::ExportStatus GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3379 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
3380 return runAndDestroy(lyx::bind(mem_func, clone, _1, true), orig, clone, format);
3384 Buffer::ExportStatus GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3386 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
3387 return runAndDestroy(lyx::bind(mem_func, clone, _1, false), orig, clone, format);
3391 Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3393 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &) const = &Buffer::preview;
3394 return runAndDestroy(lyx::bind(mem_func, clone, _1), orig, clone, format);
3398 bool GuiView::GuiViewPrivate::asyncBufferProcessing(
3399 string const & argument,
3400 Buffer const * used_buffer,
3401 docstring const & msg,
3402 Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
3403 Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
3404 Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const)
3409 string format = argument;
3411 format = used_buffer->params().getDefaultOutputFormat();
3412 processing_format = format;
3414 progress_->clearMessages();
3417 #if EXPORT_in_THREAD
3418 GuiViewPrivate::busyBuffers.insert(used_buffer);
3419 Buffer * cloned_buffer = used_buffer->cloneFromMaster();
3420 if (!cloned_buffer) {
3421 Alert::error(_("Export Error"),
3422 _("Error cloning the Buffer."));
3425 QFuture<Buffer::ExportStatus> f = QtConcurrent::run(
3430 setPreviewFuture(f);
3431 last_export_format = used_buffer->params().bufferFormat();
3434 // We are asynchronous, so we don't know here anything about the success
3437 Buffer::ExportStatus status;
3439 // TODO check here if it breaks exporting with Qt < 4.4
3440 status = (used_buffer->*syncFunc)(format, true);
3441 } else if (previewFunc) {
3442 status = (used_buffer->*previewFunc)(format);
3445 handleExportStatus(gv_, status, format);
3447 return (status == Buffer::ExportSuccess
3448 || status == Buffer::PreviewSuccess);
3452 void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr)
3454 BufferView * bv = currentBufferView();
3455 LASSERT(bv, return);
3457 // Let the current BufferView dispatch its own actions.
3458 bv->dispatch(cmd, dr);
3459 if (dr.dispatched())
3462 // Try with the document BufferView dispatch if any.
3463 BufferView * doc_bv = documentBufferView();
3464 if (doc_bv && doc_bv != bv) {
3465 doc_bv->dispatch(cmd, dr);
3466 if (dr.dispatched())
3470 // Then let the current Cursor dispatch its own actions.
3471 bv->cursor().dispatch(cmd);
3473 // update completion. We do it here and not in
3474 // processKeySym to avoid another redraw just for a
3475 // changed inline completion
3476 if (cmd.origin() == FuncRequest::KEYBOARD) {
3477 if (cmd.action() == LFUN_SELF_INSERT
3478 || (cmd.action() == LFUN_ERT_INSERT && bv->cursor().inMathed()))
3479 updateCompletion(bv->cursor(), true, true);
3480 else if (cmd.action() == LFUN_CHAR_DELETE_BACKWARD)
3481 updateCompletion(bv->cursor(), false, true);
3483 updateCompletion(bv->cursor(), false, false);
3486 dr = bv->cursor().result();
3490 void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
3492 BufferView * bv = currentBufferView();
3493 // By default we won't need any update.
3494 dr.screenUpdate(Update::None);
3495 // assume cmd will be dispatched
3496 dr.dispatched(true);
3498 Buffer * doc_buffer = documentBufferView()
3499 ? &(documentBufferView()->buffer()) : 0;
3501 if (cmd.origin() == FuncRequest::TOC) {
3502 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
3503 // FIXME: do we need to pass a DispatchResult object here?
3504 toc->doDispatch(bv->cursor(), cmd);
3508 string const argument = to_utf8(cmd.argument());
3510 switch(cmd.action()) {
3511 case LFUN_BUFFER_CHILD_OPEN:
3512 openChildDocument(to_utf8(cmd.argument()));
3515 case LFUN_BUFFER_IMPORT:
3516 importDocument(to_utf8(cmd.argument()));
3519 case LFUN_BUFFER_EXPORT: {
3522 FileName target_dir = doc_buffer->fileName().onlyPath();
3523 string const dest = cmd.getArg(1);
3524 if (!dest.empty() && FileName::isAbsolute(dest))
3525 target_dir = FileName(support::onlyPath(dest));
3526 // GCC only sees strfwd.h when building merged
3527 if (::lyx::operator==(cmd.argument(), "custom")) {
3528 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
3531 if (!target_dir.isDirWritable()) {
3532 exportBufferAs(*doc_buffer, cmd.argument());
3535 /* TODO/Review: Is it a problem to also export the children?
3536 See the update_unincluded flag */
3537 d.asyncBufferProcessing(argument,
3540 &GuiViewPrivate::exportAndDestroy,
3543 // TODO Inform user about success
3547 case LFUN_BUFFER_EXPORT_AS: {
3548 LASSERT(doc_buffer, break);
3549 docstring f = cmd.argument();
3551 f = from_ascii(doc_buffer->params().getDefaultOutputFormat());
3552 exportBufferAs(*doc_buffer, f);
3556 case LFUN_BUFFER_UPDATE: {
3557 d.asyncBufferProcessing(argument,
3560 &GuiViewPrivate::compileAndDestroy,
3565 case LFUN_BUFFER_VIEW: {
3566 d.asyncBufferProcessing(argument,
3568 _("Previewing ..."),
3569 &GuiViewPrivate::previewAndDestroy,
3574 case LFUN_MASTER_BUFFER_UPDATE: {
3575 d.asyncBufferProcessing(argument,
3576 (doc_buffer ? doc_buffer->masterBuffer() : 0),
3578 &GuiViewPrivate::compileAndDestroy,
3583 case LFUN_MASTER_BUFFER_VIEW: {
3584 d.asyncBufferProcessing(argument,
3585 (doc_buffer ? doc_buffer->masterBuffer() : 0),
3587 &GuiViewPrivate::previewAndDestroy,
3588 0, &Buffer::preview);
3591 case LFUN_BUFFER_SWITCH: {
3592 string const file_name = to_utf8(cmd.argument());
3593 if (!FileName::isAbsolute(file_name)) {
3595 dr.setMessage(_("Absolute filename expected."));
3599 Buffer * buffer = theBufferList().getBuffer(FileName(file_name));
3602 dr.setMessage(_("Document not loaded"));
3606 // Do we open or switch to the buffer in this view ?
3607 if (workArea(*buffer)
3608 || lyxrc.open_buffers_in_tabs || !documentBufferView()) {
3613 // Look for the buffer in other views
3614 QList<int> const ids = guiApp->viewIds();
3616 for (; i != ids.size(); ++i) {
3617 GuiView & gv = guiApp->view(ids[i]);
3618 if (gv.workArea(*buffer)) {
3620 gv.activateWindow();
3622 gv.setBuffer(buffer);
3627 // If necessary, open a new window as a last resort
3628 if (i == ids.size()) {
3629 lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW));
3635 case LFUN_BUFFER_NEXT:
3636 gotoNextOrPreviousBuffer(NEXTBUFFER, false);
3639 case LFUN_BUFFER_MOVE_NEXT:
3640 gotoNextOrPreviousBuffer(NEXTBUFFER, true);
3643 case LFUN_BUFFER_PREVIOUS:
3644 gotoNextOrPreviousBuffer(PREVBUFFER, false);
3647 case LFUN_BUFFER_MOVE_PREVIOUS:
3648 gotoNextOrPreviousBuffer(PREVBUFFER, true);
3651 case LFUN_COMMAND_EXECUTE: {
3652 command_execute_ = true;
3655 case LFUN_DROP_LAYOUTS_CHOICE:
3656 d.layout_->showPopup();
3659 case LFUN_MENU_OPEN:
3660 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
3661 menu->exec(QCursor::pos());
3664 case LFUN_FILE_INSERT:
3665 insertLyXFile(cmd.argument());
3668 case LFUN_FILE_INSERT_PLAINTEXT:
3669 case LFUN_FILE_INSERT_PLAINTEXT_PARA: {
3670 string const fname = to_utf8(cmd.argument());
3671 if (!fname.empty() && !FileName::isAbsolute(fname)) {
3672 dr.setMessage(_("Absolute filename expected."));
3676 FileName filename(fname);
3677 if (fname.empty()) {
3678 FileDialog dlg(qt_("Select file to insert"));
3680 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
3681 QStringList(qt_("All Files (*)")));
3683 if (result.first == FileDialog::Later || result.second.isEmpty()) {
3684 dr.setMessage(_("Canceled."));
3688 filename.set(fromqstr(result.second));
3692 FuncRequest const new_cmd(cmd, filename.absoluteFilePath());
3693 bv->dispatch(new_cmd, dr);
3698 case LFUN_BUFFER_RELOAD: {
3699 LASSERT(doc_buffer, break);
3702 if (!doc_buffer->isClean()) {
3703 docstring const file =
3704 makeDisplayPath(doc_buffer->absFileName(), 20);
3705 docstring text = bformat(_("Any changes will be lost. "
3706 "Are you sure you want to revert to the saved version "
3707 "of the document %1$s?"), file);
3708 ret = Alert::prompt(_("Revert to saved document?"),
3709 text, 1, 1, _("&Revert"), _("&Cancel"));
3713 doc_buffer->markClean();
3714 reloadBuffer(*doc_buffer);
3715 dr.forceBufferUpdate();
3720 case LFUN_BUFFER_WRITE:
3721 LASSERT(doc_buffer, break);
3722 saveBuffer(*doc_buffer);
3725 case LFUN_BUFFER_WRITE_AS:
3726 LASSERT(doc_buffer, break);
3727 renameBuffer(*doc_buffer, cmd.argument());
3730 case LFUN_BUFFER_WRITE_ALL: {
3731 Buffer * first = theBufferList().first();
3734 message(_("Saving all documents..."));
3735 // We cannot use a for loop as the buffer list cycles.
3738 if (!b->isClean()) {
3740 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
3742 b = theBufferList().next(b);
3743 } while (b != first);
3744 dr.setMessage(_("All documents saved."));
3748 case LFUN_BUFFER_CLOSE:
3752 case LFUN_BUFFER_CLOSE_ALL:
3756 case LFUN_TOOLBAR_TOGGLE: {
3757 string const name = cmd.getArg(0);
3758 if (GuiToolbar * t = toolbar(name))
3763 case LFUN_DIALOG_UPDATE: {
3764 string const name = to_utf8(cmd.argument());
3765 if (name == "prefs" || name == "document")
3766 updateDialog(name, string());
3767 else if (name == "paragraph")
3768 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
3769 else if (currentBufferView()) {
3770 Inset * inset = currentBufferView()->editedInset(name);
3771 // Can only update a dialog connected to an existing inset
3773 // FIXME: get rid of this indirection; GuiView ask the inset
3774 // if he is kind enough to update itself...
3775 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
3776 //FIXME: pass DispatchResult here?
3777 inset->dispatch(currentBufferView()->cursor(), fr);
3783 case LFUN_DIALOG_TOGGLE: {
3784 FuncCode const func_code = isDialogVisible(cmd.getArg(0))
3785 ? LFUN_DIALOG_HIDE : LFUN_DIALOG_SHOW;
3786 dispatch(FuncRequest(func_code, cmd.argument()), dr);
3790 case LFUN_DIALOG_DISCONNECT_INSET:
3791 disconnectDialog(to_utf8(cmd.argument()));
3794 case LFUN_DIALOG_HIDE: {
3795 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
3799 case LFUN_DIALOG_SHOW: {
3800 string const name = cmd.getArg(0);
3801 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
3803 if (name == "character") {
3804 data = freefont2string();
3806 showDialog("character", data);
3807 } else if (name == "latexlog") {
3808 Buffer::LogType type;
3809 string const logfile = doc_buffer->logName(&type);
3811 case Buffer::latexlog:
3814 case Buffer::buildlog:
3818 data += Lexer::quoteString(logfile);
3819 showDialog("log", data);
3820 } else if (name == "vclog") {
3821 string const data = "vc " +
3822 Lexer::quoteString(doc_buffer->lyxvc().getLogFile());
3823 showDialog("log", data);
3824 } else if (name == "symbols") {
3825 data = bv->cursor().getEncoding()->name();
3827 showDialog("symbols", data);
3829 } else if (name == "prefs" && isFullScreen()) {
3830 lfunUiToggle("fullscreen");
3831 showDialog("prefs", data);
3833 showDialog(name, data);
3838 dr.setMessage(cmd.argument());
3841 case LFUN_UI_TOGGLE: {
3842 string arg = cmd.getArg(0);
3843 if (!lfunUiToggle(arg)) {
3844 docstring const msg = "ui-toggle " + _("%1$s unknown command!");
3845 dr.setMessage(bformat(msg, from_utf8(arg)));
3847 // Make sure the keyboard focus stays in the work area.
3852 case LFUN_VIEW_SPLIT: {
3853 LASSERT(doc_buffer, break);
3854 string const orientation = cmd.getArg(0);
3855 d.splitter_->setOrientation(orientation == "vertical"
3856 ? Qt::Vertical : Qt::Horizontal);
3857 TabWorkArea * twa = addTabWorkArea();
3858 GuiWorkArea * wa = twa->addWorkArea(*doc_buffer, *this);
3859 setCurrentWorkArea(wa);
3862 case LFUN_TAB_GROUP_CLOSE:
3863 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3864 closeTabWorkArea(twa);
3865 d.current_work_area_ = 0;
3866 twa = d.currentTabWorkArea();
3867 // Switch to the next GuiWorkArea in the found TabWorkArea.
3869 // Make sure the work area is up to date.
3870 setCurrentWorkArea(twa->currentWorkArea());
3872 setCurrentWorkArea(0);
3877 case LFUN_VIEW_CLOSE:
3878 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3879 closeWorkArea(twa->currentWorkArea());
3880 d.current_work_area_ = 0;
3881 twa = d.currentTabWorkArea();
3882 // Switch to the next GuiWorkArea in the found TabWorkArea.
3884 // Make sure the work area is up to date.
3885 setCurrentWorkArea(twa->currentWorkArea());
3887 setCurrentWorkArea(0);
3892 case LFUN_COMPLETION_INLINE:
3893 if (d.current_work_area_)
3894 d.current_work_area_->completer().showInline();
3897 case LFUN_COMPLETION_POPUP:
3898 if (d.current_work_area_)
3899 d.current_work_area_->completer().showPopup();
3904 if (d.current_work_area_)
3905 d.current_work_area_->completer().tab();
3908 case LFUN_COMPLETION_CANCEL:
3909 if (d.current_work_area_) {
3910 if (d.current_work_area_->completer().popupVisible())
3911 d.current_work_area_->completer().hidePopup();
3913 d.current_work_area_->completer().hideInline();
3917 case LFUN_COMPLETION_ACCEPT:
3918 if (d.current_work_area_)
3919 d.current_work_area_->completer().activate();
3922 case LFUN_BUFFER_ZOOM_IN:
3923 case LFUN_BUFFER_ZOOM_OUT:
3924 if (cmd.argument().empty()) {
3925 if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
3930 lyxrc.zoom += convert<int>(cmd.argument());
3932 if (lyxrc.zoom < 10)
3935 // The global QPixmapCache is used in GuiPainter to cache text
3936 // painting so we must reset it.
3937 QPixmapCache::clear();
3938 guiApp->fontLoader().update();
3939 lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
3942 case LFUN_VC_REGISTER:
3943 case LFUN_VC_RENAME:
3945 case LFUN_VC_CHECK_IN:
3946 case LFUN_VC_CHECK_OUT:
3947 case LFUN_VC_REPO_UPDATE:
3948 case LFUN_VC_LOCKING_TOGGLE:
3949 case LFUN_VC_REVERT:
3950 case LFUN_VC_UNDO_LAST:
3951 case LFUN_VC_COMMAND:
3952 case LFUN_VC_COMPARE:
3953 dispatchVC(cmd, dr);
3956 case LFUN_SERVER_GOTO_FILE_ROW:
3957 goToFileRow(to_utf8(cmd.argument()));
3960 case LFUN_FORWARD_SEARCH: {
3961 Buffer const * doc_master = doc_buffer->masterBuffer();
3962 FileName const path(doc_master->temppath());
3963 string const texname = doc_master->isChild(doc_buffer)
3964 ? DocFileName(changeExtension(
3965 doc_buffer->absFileName(),
3966 "tex")).mangledFileName()
3967 : doc_buffer->latexName();
3968 string const fulltexname =
3969 support::makeAbsPath(texname, doc_master->temppath()).absFileName();
3970 string const mastername =
3971 removeExtension(doc_master->latexName());
3972 FileName const dviname(addName(path.absFileName(),
3973 addExtension(mastername, "dvi")));
3974 FileName const pdfname(addName(path.absFileName(),
3975 addExtension(mastername, "pdf")));
3976 bool const have_dvi = dviname.exists();
3977 bool const have_pdf = pdfname.exists();
3978 if (!have_dvi && !have_pdf) {
3979 dr.setMessage(_("Please, preview the document first."));
3982 string outname = dviname.onlyFileName();
3983 string command = lyxrc.forward_search_dvi;
3984 if (!have_dvi || (have_pdf &&
3985 pdfname.lastModified() > dviname.lastModified())) {
3986 outname = pdfname.onlyFileName();
3987 command = lyxrc.forward_search_pdf;
3990 DocIterator cur = bv->cursor();
3991 int row = doc_buffer->texrow().rowFromDocIterator(cur).first;
3992 LYXERR(Debug::ACTION, "Forward search: row:" << row
3994 if (row == -1 || command.empty()) {
3995 dr.setMessage(_("Couldn't proceed."));
3998 string texrow = convert<string>(row);
4000 command = subst(command, "$$n", texrow);
4001 command = subst(command, "$$f", fulltexname);
4002 command = subst(command, "$$t", texname);
4003 command = subst(command, "$$o", outname);
4005 PathChanger p(path);
4007 one.startscript(Systemcall::DontWait, command);
4011 case LFUN_SPELLING_CONTINUOUSLY:
4012 lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously;
4013 dr.screenUpdate(Update::Force | Update::FitCursor);
4017 // The LFUN must be for one of BufferView, Buffer or Cursor;
4019 dispatchToBufferView(cmd, dr);
4023 // Part of automatic menu appearance feature.
4024 if (isFullScreen()) {
4025 if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
4029 // Need to update bv because many LFUNs here might have destroyed it
4030 bv = currentBufferView();
4032 // Clear non-empty selections
4033 // (e.g. from a "char-forward-select" followed by "char-backward-select")
4035 Cursor & cur = bv->cursor();
4036 if ((cur.selection() && cur.selBegin() == cur.selEnd())) {
4037 cur.clearSelection();
4043 bool GuiView::lfunUiToggle(string const & ui_component)
4045 if (ui_component == "scrollbar") {
4046 // hide() is of no help
4047 if (d.current_work_area_->verticalScrollBarPolicy() ==
4048 Qt::ScrollBarAlwaysOff)
4050 d.current_work_area_->setVerticalScrollBarPolicy(
4051 Qt::ScrollBarAsNeeded);
4053 d.current_work_area_->setVerticalScrollBarPolicy(
4054 Qt::ScrollBarAlwaysOff);
4055 } else if (ui_component == "statusbar") {
4056 statusBar()->setVisible(!statusBar()->isVisible());
4057 } else if (ui_component == "menubar") {
4058 menuBar()->setVisible(!menuBar()->isVisible());
4060 if (ui_component == "frame") {
4062 getContentsMargins(&l, &t, &r, &b);
4063 //are the frames in default state?
4064 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
4066 setContentsMargins(-2, -2, -2, -2);
4068 setContentsMargins(0, 0, 0, 0);
4071 if (ui_component == "fullscreen") {
4079 void GuiView::toggleFullScreen()
4081 if (isFullScreen()) {
4082 for (int i = 0; i != d.splitter_->count(); ++i)
4083 d.tabWorkArea(i)->setFullScreen(false);
4084 setContentsMargins(0, 0, 0, 0);
4085 setWindowState(windowState() ^ Qt::WindowFullScreen);
4088 statusBar()->show();
4091 hideDialogs("prefs", 0);
4092 for (int i = 0; i != d.splitter_->count(); ++i)
4093 d.tabWorkArea(i)->setFullScreen(true);
4094 setContentsMargins(-2, -2, -2, -2);
4096 setWindowState(windowState() ^ Qt::WindowFullScreen);
4097 if (lyxrc.full_screen_statusbar)
4098 statusBar()->hide();
4099 if (lyxrc.full_screen_menubar)
4101 if (lyxrc.full_screen_toolbars) {
4102 ToolbarMap::iterator end = d.toolbars_.end();
4103 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
4108 // give dialogs like the TOC a chance to adapt
4113 Buffer const * GuiView::updateInset(Inset const * inset)
4118 Buffer const * inset_buffer = &(inset->buffer());
4120 for (int i = 0; i != d.splitter_->count(); ++i) {
4121 GuiWorkArea * wa = d.tabWorkArea(i)->currentWorkArea();
4124 Buffer const * buffer = &(wa->bufferView().buffer());
4125 if (inset_buffer == buffer)
4126 wa->scheduleRedraw();
4128 return inset_buffer;
4132 void GuiView::restartCursor()
4134 /* When we move around, or type, it's nice to be able to see
4135 * the cursor immediately after the keypress.
4137 if (d.current_work_area_)
4138 d.current_work_area_->startBlinkingCursor();
4140 // Take this occasion to update the other GUI elements.
4146 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
4148 if (d.current_work_area_)
4149 d.current_work_area_->completer().updateVisibility(cur, start, keep);
4154 // This list should be kept in sync with the list of insets in
4155 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
4156 // dialog should have the same name as the inset.
4157 // Changes should be also recorded in LFUN_DIALOG_SHOW doxygen
4158 // docs in LyXAction.cpp.
4160 char const * const dialognames[] = {
4162 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
4163 "citation", "compare", "comparehistory", "document", "errorlist", "ert",
4164 "external", "file", "findreplace", "findreplaceadv", "float", "graphics",
4165 "href", "include", "index", "index_print", "info", "listings", "label", "line",
4166 "log", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
4167 "nomencl_print", "note", "paragraph", "phantom", "prefs", "ref",
4168 "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
4169 "thesaurus", "texinfo", "toc", "view-source", "vspace", "wrap", "progress"};
4171 char const * const * const end_dialognames =
4172 dialognames + (sizeof(dialognames) / sizeof(char *));
4176 cmpCStr(char const * name) : name_(name) {}
4177 bool operator()(char const * other) {
4178 return strcmp(other, name_) == 0;
4185 bool isValidName(string const & name)
4187 return find_if(dialognames, end_dialognames,
4188 cmpCStr(name.c_str())) != end_dialognames;
4194 void GuiView::resetDialogs()
4196 // Make sure that no LFUN uses any GuiView.
4197 guiApp->setCurrentView(0);
4201 constructToolbars();
4202 guiApp->menus().fillMenuBar(menuBar(), this, false);
4203 d.layout_->updateContents(true);
4204 // Now update controls with current buffer.
4205 guiApp->setCurrentView(this);
4211 Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
4213 if (!isValidName(name))
4216 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
4218 if (it != d.dialogs_.end()) {
4220 it->second->hideView();
4221 return it->second.get();
4224 Dialog * dialog = build(name);
4225 d.dialogs_[name].reset(dialog);
4226 if (lyxrc.allow_geometry_session)
4227 dialog->restoreSession();
4234 void GuiView::showDialog(string const & name, string const & data,
4237 triggerShowDialog(toqstr(name), toqstr(data), inset);
4241 void GuiView::doShowDialog(QString const & qname, QString const & qdata,
4247 const string name = fromqstr(qname);
4248 const string data = fromqstr(qdata);
4252 Dialog * dialog = findOrBuild(name, false);
4254 bool const visible = dialog->isVisibleView();
4255 dialog->showData(data);
4256 if (inset && currentBufferView())
4257 currentBufferView()->editInset(name, inset);
4258 // We only set the focus to the new dialog if it was not yet
4259 // visible in order not to change the existing previous behaviour
4261 // activateWindow is needed for floating dockviews
4262 dialog->asQWidget()->raise();
4263 dialog->asQWidget()->activateWindow();
4264 dialog->asQWidget()->setFocus();
4268 catch (ExceptionMessage const & ex) {
4276 bool GuiView::isDialogVisible(string const & name) const
4278 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
4279 if (it == d.dialogs_.end())
4281 return it->second.get()->isVisibleView() && !it->second.get()->isClosing();
4285 void GuiView::hideDialog(string const & name, Inset * inset)
4287 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
4288 if (it == d.dialogs_.end())
4292 if (!currentBufferView())
4294 if (inset != currentBufferView()->editedInset(name))
4298 Dialog * const dialog = it->second.get();
4299 if (dialog->isVisibleView())
4301 if (currentBufferView())
4302 currentBufferView()->editInset(name, 0);
4306 void GuiView::disconnectDialog(string const & name)
4308 if (!isValidName(name))
4310 if (currentBufferView())
4311 currentBufferView()->editInset(name, 0);
4315 void GuiView::hideAll() const
4317 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
4318 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
4320 for(; it != end; ++it)
4321 it->second->hideView();
4325 void GuiView::updateDialogs()
4327 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
4328 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
4330 for(; it != end; ++it) {
4331 Dialog * dialog = it->second.get();
4333 if (dialog->needBufferOpen() && !documentBufferView())
4334 hideDialog(fromqstr(dialog->name()), 0);
4335 else if (dialog->isVisibleView())
4336 dialog->checkStatus();
4343 Dialog * createDialog(GuiView & lv, string const & name);
4345 // will be replaced by a proper factory...
4346 Dialog * createGuiAbout(GuiView & lv);
4347 Dialog * createGuiBibtex(GuiView & lv);
4348 Dialog * createGuiChanges(GuiView & lv);
4349 Dialog * createGuiCharacter(GuiView & lv);
4350 Dialog * createGuiCitation(GuiView & lv);
4351 Dialog * createGuiCompare(GuiView & lv);
4352 Dialog * createGuiCompareHistory(GuiView & lv);
4353 Dialog * createGuiDelimiter(GuiView & lv);
4354 Dialog * createGuiDocument(GuiView & lv);
4355 Dialog * createGuiErrorList(GuiView & lv);
4356 Dialog * createGuiExternal(GuiView & lv);
4357 Dialog * createGuiGraphics(GuiView & lv);
4358 Dialog * createGuiInclude(GuiView & lv);
4359 Dialog * createGuiIndex(GuiView & lv);
4360 Dialog * createGuiListings(GuiView & lv);
4361 Dialog * createGuiLog(GuiView & lv);
4362 Dialog * createGuiMathMatrix(GuiView & lv);
4363 Dialog * createGuiNote(GuiView & lv);
4364 Dialog * createGuiParagraph(GuiView & lv);
4365 Dialog * createGuiPhantom(GuiView & lv);
4366 Dialog * createGuiPreferences(GuiView & lv);
4367 Dialog * createGuiPrint(GuiView & lv);
4368 Dialog * createGuiPrintindex(GuiView & lv);
4369 Dialog * createGuiRef(GuiView & lv);
4370 Dialog * createGuiSearch(GuiView & lv);
4371 Dialog * createGuiSearchAdv(GuiView & lv);
4372 Dialog * createGuiSendTo(GuiView & lv);
4373 Dialog * createGuiShowFile(GuiView & lv);
4374 Dialog * createGuiSpellchecker(GuiView & lv);
4375 Dialog * createGuiSymbols(GuiView & lv);
4376 Dialog * createGuiTabularCreate(GuiView & lv);
4377 Dialog * createGuiTexInfo(GuiView & lv);
4378 Dialog * createGuiToc(GuiView & lv);
4379 Dialog * createGuiThesaurus(GuiView & lv);
4380 Dialog * createGuiViewSource(GuiView & lv);
4381 Dialog * createGuiWrap(GuiView & lv);
4382 Dialog * createGuiProgressView(GuiView & lv);
4386 Dialog * GuiView::build(string const & name)
4388 LASSERT(isValidName(name), return 0);
4390 Dialog * dialog = createDialog(*this, name);
4394 if (name == "aboutlyx")
4395 return createGuiAbout(*this);
4396 if (name == "bibtex")
4397 return createGuiBibtex(*this);
4398 if (name == "changes")
4399 return createGuiChanges(*this);
4400 if (name == "character")
4401 return createGuiCharacter(*this);
4402 if (name == "citation")
4403 return createGuiCitation(*this);
4404 if (name == "compare")
4405 return createGuiCompare(*this);
4406 if (name == "comparehistory")
4407 return createGuiCompareHistory(*this);
4408 if (name == "document")
4409 return createGuiDocument(*this);
4410 if (name == "errorlist")
4411 return createGuiErrorList(*this);
4412 if (name == "external")
4413 return createGuiExternal(*this);
4415 return createGuiShowFile(*this);
4416 if (name == "findreplace")
4417 return createGuiSearch(*this);
4418 if (name == "findreplaceadv")
4419 return createGuiSearchAdv(*this);
4420 if (name == "graphics")
4421 return createGuiGraphics(*this);
4422 if (name == "include")
4423 return createGuiInclude(*this);
4424 if (name == "index")
4425 return createGuiIndex(*this);
4426 if (name == "index_print")
4427 return createGuiPrintindex(*this);
4428 if (name == "listings")
4429 return createGuiListings(*this);
4431 return createGuiLog(*this);
4432 if (name == "mathdelimiter")
4433 return createGuiDelimiter(*this);
4434 if (name == "mathmatrix")
4435 return createGuiMathMatrix(*this);
4437 return createGuiNote(*this);
4438 if (name == "paragraph")
4439 return createGuiParagraph(*this);
4440 if (name == "phantom")
4441 return createGuiPhantom(*this);
4442 if (name == "prefs")
4443 return createGuiPreferences(*this);
4445 return createGuiRef(*this);
4446 if (name == "sendto")
4447 return createGuiSendTo(*this);
4448 if (name == "spellchecker")
4449 return createGuiSpellchecker(*this);
4450 if (name == "symbols")
4451 return createGuiSymbols(*this);
4452 if (name == "tabularcreate")
4453 return createGuiTabularCreate(*this);
4454 if (name == "texinfo")
4455 return createGuiTexInfo(*this);
4456 if (name == "thesaurus")
4457 return createGuiThesaurus(*this);
4459 return createGuiToc(*this);
4460 if (name == "view-source")
4461 return createGuiViewSource(*this);
4463 return createGuiWrap(*this);
4464 if (name == "progress")
4465 return createGuiProgressView(*this);
4471 } // namespace frontend
4474 #include "moc_GuiView.cpp"