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 || (lyx::getStatus(FuncRequest(LFUN_CHANGES_OUTPUT)).enabled()
1559 && lyx::getStatus(FuncRequest(LFUN_CHANGES_OUTPUT)).onOff(true)))
1560 context |= Toolbars::REVIEW;
1561 if (lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled())
1562 context |= Toolbars::MATHMACROTEMPLATE;
1563 if (lyx::getStatus(FuncRequest(LFUN_IN_IPA)).enabled())
1564 context |= Toolbars::IPA;
1565 if (command_execute_)
1566 context |= Toolbars::MINIBUFFER;
1568 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1569 it->second->update(context);
1571 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1572 it->second->update();
1576 void GuiView::setBuffer(Buffer * newBuffer)
1578 LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << endl);
1579 LASSERT(newBuffer, return);
1581 GuiWorkArea * wa = workArea(*newBuffer);
1584 newBuffer->masterBuffer()->updateBuffer();
1586 wa = addWorkArea(*newBuffer);
1587 // scroll to the position when the BufferView was last closed
1588 if (lyxrc.use_lastfilepos) {
1589 LastFilePosSection::FilePos filepos =
1590 theSession().lastFilePos().load(newBuffer->fileName());
1591 wa->bufferView().moveToPosition(filepos.pit, filepos.pos, 0, 0);
1594 //Disconnect the old buffer...there's no new one.
1597 connectBuffer(*newBuffer);
1598 connectBufferView(wa->bufferView());
1599 setCurrentWorkArea(wa);
1603 void GuiView::connectBuffer(Buffer & buf)
1605 buf.setGuiDelegate(this);
1609 void GuiView::disconnectBuffer()
1611 if (d.current_work_area_)
1612 d.current_work_area_->bufferView().buffer().setGuiDelegate(0);
1616 void GuiView::connectBufferView(BufferView & bv)
1618 bv.setGuiDelegate(this);
1622 void GuiView::disconnectBufferView()
1624 if (d.current_work_area_)
1625 d.current_work_area_->bufferView().setGuiDelegate(0);
1629 void GuiView::errors(string const & error_type, bool from_master)
1631 BufferView const * const bv = currentBufferView();
1635 #if EXPORT_in_THREAD
1636 // We are called with from_master == false by default, so we
1637 // have to figure out whether that is the case or not.
1638 ErrorList & el = bv->buffer().errorList(error_type);
1640 el = bv->buffer().masterBuffer()->errorList(error_type);
1644 ErrorList const & el = from_master ?
1645 bv->buffer().masterBuffer()->errorList(error_type) :
1646 bv->buffer().errorList(error_type);
1652 string data = error_type;
1654 data = "from_master|" + error_type;
1655 showDialog("errorlist", data);
1659 void GuiView::updateTocItem(string const & type, DocIterator const & dit)
1661 d.toc_models_.updateItem(toqstr(type), dit);
1665 void GuiView::structureChanged()
1667 d.toc_models_.reset(documentBufferView());
1668 // Navigator needs more than a simple update in this case. It needs to be
1670 updateDialog("toc", "");
1674 void GuiView::updateDialog(string const & name, string const & data)
1676 if (!isDialogVisible(name))
1679 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1680 if (it == d.dialogs_.end())
1683 Dialog * const dialog = it->second.get();
1684 if (dialog->isVisibleView())
1685 dialog->initialiseParams(data);
1689 BufferView * GuiView::documentBufferView()
1691 return currentMainWorkArea()
1692 ? ¤tMainWorkArea()->bufferView()
1697 BufferView const * GuiView::documentBufferView() const
1699 return currentMainWorkArea()
1700 ? ¤tMainWorkArea()->bufferView()
1705 BufferView * GuiView::currentBufferView()
1707 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1711 BufferView const * GuiView::currentBufferView() const
1713 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1717 docstring GuiView::GuiViewPrivate::autosaveAndDestroy(
1718 Buffer const * orig, Buffer * clone)
1720 bool const success = clone->autoSave();
1722 busyBuffers.remove(orig);
1724 ? _("Automatic save done.")
1725 : _("Automatic save failed!");
1729 void GuiView::autoSave()
1731 LYXERR(Debug::INFO, "Running autoSave()");
1733 Buffer * buffer = documentBufferView()
1734 ? &documentBufferView()->buffer() : 0;
1736 resetAutosaveTimers();
1740 GuiViewPrivate::busyBuffers.insert(buffer);
1741 QFuture<docstring> f = QtConcurrent::run(GuiViewPrivate::autosaveAndDestroy,
1742 buffer, buffer->cloneBufferOnly());
1743 d.autosave_watcher_.setFuture(f);
1744 resetAutosaveTimers();
1748 void GuiView::resetAutosaveTimers()
1751 d.autosave_timeout_.restart();
1755 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1758 Buffer * buf = currentBufferView()
1759 ? ¤tBufferView()->buffer() : 0;
1760 Buffer * doc_buffer = documentBufferView()
1761 ? &(documentBufferView()->buffer()) : 0;
1764 /* In LyX/Mac, when a dialog is open, the menus of the
1765 application can still be accessed without giving focus to
1766 the main window. In this case, we want to disable the menu
1767 entries that are buffer-related.
1768 This code must not be used on Linux and Windows, since it
1769 would disable buffer-related entries when hovering over the
1770 menu (see bug #9574).
1772 if (cmd.origin() == FuncRequest::MENU && !hasFocus()) {
1778 // Check whether we need a buffer
1779 if (!lyxaction.funcHasFlag(cmd.action(), LyXAction::NoBuffer) && !buf) {
1780 // no, exit directly
1781 flag.message(from_utf8(N_("Command not allowed with"
1782 "out any document open")));
1783 flag.setEnabled(false);
1787 if (cmd.origin() == FuncRequest::TOC) {
1788 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
1789 if (!toc || !toc->getStatus(documentBufferView()->cursor(), cmd, flag))
1790 flag.setEnabled(false);
1794 switch(cmd.action()) {
1795 case LFUN_BUFFER_IMPORT:
1798 case LFUN_MASTER_BUFFER_UPDATE:
1799 case LFUN_MASTER_BUFFER_VIEW:
1801 && (doc_buffer->parent() != 0
1802 || doc_buffer->hasChildren())
1803 && !d.processing_thread_watcher_.isRunning();
1806 case LFUN_BUFFER_UPDATE:
1807 case LFUN_BUFFER_VIEW: {
1808 if (!doc_buffer || d.processing_thread_watcher_.isRunning()) {
1812 string format = to_utf8(cmd.argument());
1813 if (cmd.argument().empty())
1814 format = doc_buffer->params().getDefaultOutputFormat();
1815 enable = doc_buffer->params().isExportableFormat(format);
1819 case LFUN_BUFFER_RELOAD:
1820 enable = doc_buffer && !doc_buffer->isUnnamed()
1821 && doc_buffer->fileName().exists()
1822 && (!doc_buffer->isClean()
1823 || doc_buffer->isExternallyModified(Buffer::timestamp_method));
1826 case LFUN_BUFFER_CHILD_OPEN:
1827 enable = doc_buffer != 0;
1830 case LFUN_BUFFER_WRITE:
1831 enable = doc_buffer && (doc_buffer->isUnnamed() || !doc_buffer->isClean());
1834 //FIXME: This LFUN should be moved to GuiApplication.
1835 case LFUN_BUFFER_WRITE_ALL: {
1836 // We enable the command only if there are some modified buffers
1837 Buffer * first = theBufferList().first();
1842 // We cannot use a for loop as the buffer list is a cycle.
1844 if (!b->isClean()) {
1848 b = theBufferList().next(b);
1849 } while (b != first);
1853 case LFUN_BUFFER_WRITE_AS:
1854 case LFUN_BUFFER_EXPORT_AS:
1855 enable = doc_buffer != 0;
1858 case LFUN_BUFFER_CLOSE:
1859 case LFUN_VIEW_CLOSE:
1860 enable = doc_buffer != 0;
1863 case LFUN_BUFFER_CLOSE_ALL:
1864 enable = theBufferList().last() != theBufferList().first();
1867 case LFUN_VIEW_SPLIT:
1868 if (cmd.getArg(0) == "vertical")
1869 enable = doc_buffer && (d.splitter_->count() == 1 ||
1870 d.splitter_->orientation() == Qt::Vertical);
1872 enable = doc_buffer && (d.splitter_->count() == 1 ||
1873 d.splitter_->orientation() == Qt::Horizontal);
1876 case LFUN_TAB_GROUP_CLOSE:
1877 enable = d.tabWorkAreaCount() > 1;
1880 case LFUN_TOOLBAR_TOGGLE: {
1881 string const name = cmd.getArg(0);
1882 if (GuiToolbar * t = toolbar(name))
1883 flag.setOnOff(t->isVisible());
1886 docstring const msg =
1887 bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name));
1893 case LFUN_DROP_LAYOUTS_CHOICE:
1897 case LFUN_UI_TOGGLE:
1898 flag.setOnOff(isFullScreen());
1901 case LFUN_DIALOG_DISCONNECT_INSET:
1904 case LFUN_DIALOG_HIDE:
1905 // FIXME: should we check if the dialog is shown?
1908 case LFUN_DIALOG_TOGGLE:
1909 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1910 // fall through to set "enable"
1911 case LFUN_DIALOG_SHOW: {
1912 string const name = cmd.getArg(0);
1914 enable = name == "aboutlyx"
1915 || name == "file" //FIXME: should be removed.
1917 || name == "texinfo"
1918 || name == "progress"
1919 || name == "compare";
1920 else if (name == "character" || name == "symbols"
1921 || name == "mathdelimiter" || name == "mathmatrix") {
1922 if (!buf || buf->isReadonly())
1925 Cursor const & cur = currentBufferView()->cursor();
1926 enable = !(cur.inTexted() && cur.paragraph().isPassThru());
1929 else if (name == "latexlog")
1930 enable = FileName(doc_buffer->logName()).isReadableFile();
1931 else if (name == "spellchecker")
1932 enable = theSpellChecker()
1933 && !doc_buffer->isReadonly()
1934 && !doc_buffer->text().empty();
1935 else if (name == "vclog")
1936 enable = doc_buffer->lyxvc().inUse();
1940 case LFUN_DIALOG_UPDATE: {
1941 string const name = cmd.getArg(0);
1943 enable = name == "prefs";
1947 case LFUN_COMMAND_EXECUTE:
1949 case LFUN_MENU_OPEN:
1950 // Nothing to check.
1953 case LFUN_COMPLETION_INLINE:
1954 if (!d.current_work_area_
1955 || !d.current_work_area_->completer().inlinePossible(
1956 currentBufferView()->cursor()))
1960 case LFUN_COMPLETION_POPUP:
1961 if (!d.current_work_area_
1962 || !d.current_work_area_->completer().popupPossible(
1963 currentBufferView()->cursor()))
1968 if (!d.current_work_area_
1969 || !d.current_work_area_->completer().inlinePossible(
1970 currentBufferView()->cursor()))
1974 case LFUN_COMPLETION_ACCEPT:
1975 if (!d.current_work_area_
1976 || (!d.current_work_area_->completer().popupVisible()
1977 && !d.current_work_area_->completer().inlineVisible()
1978 && !d.current_work_area_->completer().completionAvailable()))
1982 case LFUN_COMPLETION_CANCEL:
1983 if (!d.current_work_area_
1984 || (!d.current_work_area_->completer().popupVisible()
1985 && !d.current_work_area_->completer().inlineVisible()))
1989 case LFUN_BUFFER_ZOOM_OUT:
1990 enable = doc_buffer && lyxrc.zoom > 10;
1993 case LFUN_BUFFER_ZOOM_IN:
1994 enable = doc_buffer != 0;
1997 case LFUN_BUFFER_MOVE_NEXT:
1998 case LFUN_BUFFER_MOVE_PREVIOUS:
1999 // we do not cycle when moving
2000 case LFUN_BUFFER_NEXT:
2001 case LFUN_BUFFER_PREVIOUS:
2002 // because we cycle, it doesn't matter whether on first or last
2003 enable = (d.currentTabWorkArea()->count() > 1);
2005 case LFUN_BUFFER_SWITCH:
2006 // toggle on the current buffer, but do not toggle off
2007 // the other ones (is that a good idea?)
2009 && to_utf8(cmd.argument()) == doc_buffer->absFileName())
2010 flag.setOnOff(true);
2013 case LFUN_VC_REGISTER:
2014 enable = doc_buffer && !doc_buffer->lyxvc().inUse();
2016 case LFUN_VC_RENAME:
2017 enable = doc_buffer && doc_buffer->lyxvc().renameEnabled();
2020 enable = doc_buffer && doc_buffer->lyxvc().copyEnabled();
2022 case LFUN_VC_CHECK_IN:
2023 enable = doc_buffer && doc_buffer->lyxvc().checkInEnabled();
2025 case LFUN_VC_CHECK_OUT:
2026 enable = doc_buffer && doc_buffer->lyxvc().checkOutEnabled();
2028 case LFUN_VC_LOCKING_TOGGLE:
2029 enable = doc_buffer && !doc_buffer->isReadonly()
2030 && doc_buffer->lyxvc().lockingToggleEnabled();
2031 flag.setOnOff(enable && doc_buffer->lyxvc().locking());
2033 case LFUN_VC_REVERT:
2034 enable = doc_buffer && doc_buffer->lyxvc().inUse() && !doc_buffer->isReadonly();
2036 case LFUN_VC_UNDO_LAST:
2037 enable = doc_buffer && doc_buffer->lyxvc().undoLastEnabled();
2039 case LFUN_VC_REPO_UPDATE:
2040 enable = doc_buffer && doc_buffer->lyxvc().repoUpdateEnabled();
2042 case LFUN_VC_COMMAND: {
2043 if (cmd.argument().empty())
2045 if (!doc_buffer && contains(cmd.getArg(0), 'D'))
2049 case LFUN_VC_COMPARE:
2050 enable = doc_buffer && doc_buffer->lyxvc().prepareFileRevisionEnabled();
2053 case LFUN_SERVER_GOTO_FILE_ROW:
2055 case LFUN_FORWARD_SEARCH:
2056 enable = !(lyxrc.forward_search_dvi.empty() && lyxrc.forward_search_pdf.empty());
2059 case LFUN_FILE_INSERT_PLAINTEXT:
2060 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
2061 enable = documentBufferView() && documentBufferView()->cursor().inTexted();
2064 case LFUN_SPELLING_CONTINUOUSLY:
2065 flag.setOnOff(lyxrc.spellcheck_continuously);
2073 flag.setEnabled(false);
2079 static FileName selectTemplateFile()
2081 FileDialog dlg(qt_("Select template file"));
2082 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2083 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2085 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
2086 QStringList(qt_("LyX Documents (*.lyx)")));
2088 if (result.first == FileDialog::Later)
2090 if (result.second.isEmpty())
2092 return FileName(fromqstr(result.second));
2096 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
2100 Buffer * newBuffer = 0;
2102 newBuffer = checkAndLoadLyXFile(filename);
2103 } catch (ExceptionMessage const & e) {
2110 message(_("Document not loaded."));
2114 setBuffer(newBuffer);
2115 newBuffer->errors("Parse");
2118 theSession().lastFiles().add(filename);
2124 void GuiView::openDocument(string const & fname)
2126 string initpath = lyxrc.document_path;
2128 if (documentBufferView()) {
2129 string const trypath = documentBufferView()->buffer().filePath();
2130 // If directory is writeable, use this as default.
2131 if (FileName(trypath).isDirWritable())
2137 if (fname.empty()) {
2138 FileDialog dlg(qt_("Select document to open"));
2139 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2140 dlg.setButton2(qt_("Examples|#E#e"),
2141 toqstr(addPath(package().system_support().absFileName(), "examples")));
2143 QStringList const filter(qt_("LyX Documents (*.lyx)"));
2144 FileDialog::Result result =
2145 dlg.open(toqstr(initpath), filter);
2147 if (result.first == FileDialog::Later)
2150 filename = fromqstr(result.second);
2152 // check selected filename
2153 if (filename.empty()) {
2154 message(_("Canceled."));
2160 // get absolute path of file and add ".lyx" to the filename if
2162 FileName const fullname =
2163 fileSearch(string(), filename, "lyx", support::may_not_exist);
2164 if (!fullname.empty())
2165 filename = fullname.absFileName();
2167 if (!fullname.onlyPath().isDirectory()) {
2168 Alert::warning(_("Invalid filename"),
2169 bformat(_("The directory in the given path\n%1$s\ndoes not exist."),
2170 from_utf8(fullname.absFileName())));
2174 // if the file doesn't exist and isn't already open (bug 6645),
2175 // let the user create one
2176 if (!fullname.exists() && !theBufferList().exists(fullname) &&
2177 !LyXVC::file_not_found_hook(fullname)) {
2178 // the user specifically chose this name. Believe him.
2179 Buffer * const b = newFile(filename, string(), true);
2185 docstring const disp_fn = makeDisplayPath(filename);
2186 message(bformat(_("Opening document %1$s..."), disp_fn));
2189 Buffer * buf = loadDocument(fullname);
2191 str2 = bformat(_("Document %1$s opened."), disp_fn);
2192 if (buf->lyxvc().inUse())
2193 str2 += " " + from_utf8(buf->lyxvc().versionString()) +
2194 " " + _("Version control detected.");
2196 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2201 // FIXME: clean that
2202 static bool import(GuiView * lv, FileName const & filename,
2203 string const & format, ErrorList & errorList)
2205 FileName const lyxfile(support::changeExtension(filename.absFileName(), ".lyx"));
2207 string loader_format;
2208 vector<string> loaders = theConverters().loaders();
2209 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
2210 vector<string>::const_iterator it = loaders.begin();
2211 vector<string>::const_iterator en = loaders.end();
2212 for (; it != en; ++it) {
2213 if (!theConverters().isReachable(format, *it))
2216 string const tofile =
2217 support::changeExtension(filename.absFileName(),
2218 formats.extension(*it));
2219 if (!theConverters().convert(0, filename, FileName(tofile),
2220 filename, format, *it, errorList))
2222 loader_format = *it;
2225 if (loader_format.empty()) {
2226 frontend::Alert::error(_("Couldn't import file"),
2227 bformat(_("No information for importing the format %1$s."),
2228 formats.prettyName(format)));
2232 loader_format = format;
2234 if (loader_format == "lyx") {
2235 Buffer * buf = lv->loadDocument(lyxfile);
2239 Buffer * const b = newFile(lyxfile.absFileName(), string(), true);
2243 bool as_paragraphs = loader_format == "textparagraph";
2244 string filename2 = (loader_format == format) ? filename.absFileName()
2245 : support::changeExtension(filename.absFileName(),
2246 formats.extension(loader_format));
2247 lv->currentBufferView()->insertPlaintextFile(FileName(filename2),
2249 guiApp->setCurrentView(lv);
2250 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
2257 void GuiView::importDocument(string const & argument)
2260 string filename = split(argument, format, ' ');
2262 LYXERR(Debug::INFO, format << " file: " << filename);
2264 // need user interaction
2265 if (filename.empty()) {
2266 string initpath = lyxrc.document_path;
2267 if (documentBufferView()) {
2268 string const trypath = documentBufferView()->buffer().filePath();
2269 // If directory is writeable, use this as default.
2270 if (FileName(trypath).isDirWritable())
2274 docstring const text = bformat(_("Select %1$s file to import"),
2275 formats.prettyName(format));
2277 FileDialog dlg(toqstr(text));
2278 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2279 dlg.setButton2(qt_("Examples|#E#e"),
2280 toqstr(addPath(package().system_support().absFileName(), "examples")));
2282 docstring filter = formats.prettyName(format);
2285 filter += from_utf8(formats.extensions(format));
2288 FileDialog::Result result =
2289 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
2291 if (result.first == FileDialog::Later)
2294 filename = fromqstr(result.second);
2296 // check selected filename
2297 if (filename.empty())
2298 message(_("Canceled."));
2301 if (filename.empty())
2304 // get absolute path of file
2305 FileName const fullname(support::makeAbsPath(filename));
2307 // Can happen if the user entered a path into the dialog
2309 if (fullname.onlyFileName().empty()) {
2310 docstring msg = bformat(_("The file name '%1$s' is invalid!\n"
2311 "Aborting import."),
2312 from_utf8(fullname.absFileName()));
2313 frontend::Alert::error(_("File name error"), msg);
2314 message(_("Canceled."));
2319 FileName const lyxfile(support::changeExtension(fullname.absFileName(), ".lyx"));
2321 // Check if the document already is open
2322 Buffer * buf = theBufferList().getBuffer(lyxfile);
2325 if (!closeBuffer()) {
2326 message(_("Canceled."));
2331 docstring const displaypath = makeDisplayPath(lyxfile.absFileName(), 30);
2333 // if the file exists already, and we didn't do
2334 // -i lyx thefile.lyx, warn
2335 if (lyxfile.exists() && fullname != lyxfile) {
2337 docstring text = bformat(_("The document %1$s already exists.\n\n"
2338 "Do you want to overwrite that document?"), displaypath);
2339 int const ret = Alert::prompt(_("Overwrite document?"),
2340 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2343 message(_("Canceled."));
2348 message(bformat(_("Importing %1$s..."), displaypath));
2349 ErrorList errorList;
2350 if (import(this, fullname, format, errorList))
2351 message(_("imported."));
2353 message(_("file not imported!"));
2355 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2359 void GuiView::newDocument(string const & filename, bool from_template)
2361 FileName initpath(lyxrc.document_path);
2362 if (documentBufferView()) {
2363 FileName const trypath(documentBufferView()->buffer().filePath());
2364 // If directory is writeable, use this as default.
2365 if (trypath.isDirWritable())
2369 string templatefile;
2370 if (from_template) {
2371 templatefile = selectTemplateFile().absFileName();
2372 if (templatefile.empty())
2377 if (filename.empty())
2378 b = newUnnamedFile(initpath, to_utf8(_("newfile")), templatefile);
2380 b = newFile(filename, templatefile, true);
2385 // If no new document could be created, it is unsure
2386 // whether there is a valid BufferView.
2387 if (currentBufferView())
2388 // Ensure the cursor is correctly positioned on screen.
2389 currentBufferView()->showCursor();
2393 void GuiView::insertLyXFile(docstring const & fname)
2395 BufferView * bv = documentBufferView();
2400 FileName filename(to_utf8(fname));
2401 if (filename.empty()) {
2402 // Launch a file browser
2404 string initpath = lyxrc.document_path;
2405 string const trypath = bv->buffer().filePath();
2406 // If directory is writeable, use this as default.
2407 if (FileName(trypath).isDirWritable())
2411 FileDialog dlg(qt_("Select LyX document to insert"));
2412 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2413 dlg.setButton2(qt_("Examples|#E#e"),
2414 toqstr(addPath(package().system_support().absFileName(),
2417 FileDialog::Result result = dlg.open(toqstr(initpath),
2418 QStringList(qt_("LyX Documents (*.lyx)")));
2420 if (result.first == FileDialog::Later)
2424 filename.set(fromqstr(result.second));
2426 // check selected filename
2427 if (filename.empty()) {
2428 // emit message signal.
2429 message(_("Canceled."));
2434 bv->insertLyXFile(filename);
2435 bv->buffer().errors("Parse");
2439 bool GuiView::renameBuffer(Buffer & b, docstring const & newname, RenameKind kind)
2441 FileName fname = b.fileName();
2442 FileName const oldname = fname;
2444 if (!newname.empty()) {
2446 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFileName());
2448 // Switch to this Buffer.
2451 // No argument? Ask user through dialog.
2453 FileDialog dlg(qt_("Choose a filename to save document as"));
2454 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2455 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2457 if (!isLyXFileName(fname.absFileName()))
2458 fname.changeExtension(".lyx");
2460 FileDialog::Result result =
2461 dlg.save(toqstr(fname.onlyPath().absFileName()),
2462 QStringList(qt_("LyX Documents (*.lyx)")),
2463 toqstr(fname.onlyFileName()));
2465 if (result.first == FileDialog::Later)
2468 fname.set(fromqstr(result.second));
2473 if (!isLyXFileName(fname.absFileName()))
2474 fname.changeExtension(".lyx");
2477 // fname is now the new Buffer location.
2479 // if there is already a Buffer open with this name, we do not want
2480 // to have another one. (the second test makes sure we're not just
2481 // trying to overwrite ourselves, which is fine.)
2482 if (theBufferList().exists(fname) && fname != oldname
2483 && theBufferList().getBuffer(fname) != &b) {
2484 docstring const text =
2485 bformat(_("The file\n%1$s\nis already open in your current session.\n"
2486 "Please close it before attempting to overwrite it.\n"
2487 "Do you want to choose a new filename?"),
2488 from_utf8(fname.absFileName()));
2489 int const ret = Alert::prompt(_("Chosen File Already Open"),
2490 text, 0, 1, _("&Rename"), _("&Cancel"));
2492 case 0: return renameBuffer(b, docstring(), kind);
2493 case 1: return false;
2498 bool const existsLocal = fname.exists();
2499 bool const existsInVC = LyXVC::fileInVC(fname);
2500 if (existsLocal || existsInVC) {
2501 docstring const file = makeDisplayPath(fname.absFileName(), 30);
2502 if (kind != LV_WRITE_AS && existsInVC) {
2503 // renaming to a name that is already in VC
2505 docstring text = bformat(_("The document %1$s "
2506 "is already registered.\n\n"
2507 "Do you want to choose a new name?"),
2509 docstring const title = (kind == LV_VC_RENAME) ?
2510 _("Rename document?") : _("Copy document?");
2511 docstring const button = (kind == LV_VC_RENAME) ?
2512 _("&Rename") : _("&Copy");
2513 int const ret = Alert::prompt(title, text, 0, 1,
2514 button, _("&Cancel"));
2516 case 0: return renameBuffer(b, docstring(), kind);
2517 case 1: return false;
2522 docstring text = bformat(_("The document %1$s "
2523 "already exists.\n\n"
2524 "Do you want to overwrite that document?"),
2526 int const ret = Alert::prompt(_("Overwrite document?"),
2527 text, 0, 2, _("&Overwrite"),
2528 _("&Rename"), _("&Cancel"));
2531 case 1: return renameBuffer(b, docstring(), kind);
2532 case 2: return false;
2538 case LV_VC_RENAME: {
2539 string msg = b.lyxvc().rename(fname);
2542 message(from_utf8(msg));
2546 string msg = b.lyxvc().copy(fname);
2549 message(from_utf8(msg));
2555 // LyXVC created the file already in case of LV_VC_RENAME or
2556 // LV_VC_COPY, but call saveBuffer() nevertheless to get
2557 // relative paths of included stuff right if we moved e.g. from
2558 // /a/b.lyx to /a/c/b.lyx.
2560 bool const saved = saveBuffer(b, fname);
2567 struct PrettyNameComparator
2569 bool operator()(Format const *first, Format const *second) const {
2570 return compare_no_case(translateIfPossible(from_ascii(first->prettyname())),
2571 translateIfPossible(from_ascii(second->prettyname()))) <= 0;
2576 bool GuiView::exportBufferAs(Buffer & b, docstring const & iformat)
2578 FileName fname = b.fileName();
2580 FileDialog dlg(qt_("Choose a filename to export the document as"));
2581 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2584 QString const anyformat = qt_("Guess from extension (*.*)");
2586 Formats::const_iterator it = formats.begin();
2587 vector<Format const *> export_formats;
2588 for (; it != formats.end(); ++it)
2589 if (it->documentFormat())
2590 export_formats.push_back(&(*it));
2591 PrettyNameComparator cmp;
2592 sort(export_formats.begin(), export_formats.end(), cmp);
2593 vector<Format const *>::const_iterator fit = export_formats.begin();
2594 map<QString, string> fmap;
2597 for (; fit != export_formats.end(); ++fit) {
2598 docstring const loc_prettyname =
2599 translateIfPossible(from_utf8((*fit)->prettyname()));
2600 QString const loc_filter = toqstr(bformat(from_ascii("%1$s (*.%2$s)"),
2602 from_ascii((*fit)->extension())));
2603 types << loc_filter;
2604 fmap[loc_filter] = (*fit)->name();
2605 if (from_ascii((*fit)->name()) == iformat) {
2606 filter = loc_filter;
2607 ext = (*fit)->extension();
2610 string ofname = fname.onlyFileName();
2612 ofname = support::changeExtension(ofname, ext);
2613 FileDialog::Result result =
2614 dlg.save(toqstr(fname.onlyPath().absFileName()),
2618 if (result.first != FileDialog::Chosen)
2622 fname.set(fromqstr(result.second));
2623 if (filter == anyformat)
2624 fmt_name = formats.getFormatFromExtension(fname.extension());
2626 fmt_name = fmap[filter];
2627 LYXERR(Debug::FILES, "filter=" << fromqstr(filter)
2628 << ", fmt_name=" << fmt_name << ", fname=" << fname.absFileName());
2630 if (fmt_name.empty() || fname.empty())
2633 // fname is now the new Buffer location.
2634 if (FileName(fname).exists()) {
2635 docstring const file = makeDisplayPath(fname.absFileName(), 30);
2636 docstring text = bformat(_("The document %1$s already "
2637 "exists.\n\nDo you want to "
2638 "overwrite that document?"),
2640 int const ret = Alert::prompt(_("Overwrite document?"),
2641 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
2644 case 1: return exportBufferAs(b, from_ascii(fmt_name));
2645 case 2: return false;
2649 FuncRequest cmd(LFUN_BUFFER_EXPORT, fmt_name + " " + fname.absFileName());
2652 return dr.dispatched();
2656 bool GuiView::saveBuffer(Buffer & b)
2658 return saveBuffer(b, FileName());
2662 bool GuiView::saveBuffer(Buffer & b, FileName const & fn)
2664 if (workArea(b) && workArea(b)->inDialogMode())
2667 if (fn.empty() && b.isUnnamed())
2668 return renameBuffer(b, docstring());
2670 bool const success = (fn.empty() ? b.save() : b.saveAs(fn));
2672 theSession().lastFiles().add(b.fileName());
2676 // Switch to this Buffer.
2679 // FIXME: we don't tell the user *WHY* the save failed !!
2680 docstring const file = makeDisplayPath(b.absFileName(), 30);
2681 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
2682 "Do you want to rename the document and "
2683 "try again?"), file);
2684 int const ret = Alert::prompt(_("Rename and save?"),
2685 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
2688 if (!renameBuffer(b, docstring()))
2697 return saveBuffer(b, fn);
2701 bool GuiView::hideWorkArea(GuiWorkArea * wa)
2703 return closeWorkArea(wa, false);
2707 // We only want to close the buffer if it is not visible in other workareas
2708 // of the same view, nor in other views, and if this is not a child
2709 bool GuiView::closeWorkArea(GuiWorkArea * wa)
2711 Buffer & buf = wa->bufferView().buffer();
2713 bool last_wa = d.countWorkAreasOf(buf) == 1
2714 && !inOtherView(buf) && !buf.parent();
2716 bool close_buffer = last_wa;
2719 if (lyxrc.close_buffer_with_last_view == "yes")
2721 else if (lyxrc.close_buffer_with_last_view == "no")
2722 close_buffer = false;
2725 if (buf.isUnnamed())
2726 file = from_utf8(buf.fileName().onlyFileName());
2728 file = buf.fileName().displayName(30);
2729 docstring const text = bformat(
2730 _("Last view on document %1$s is being closed.\n"
2731 "Would you like to close or hide the document?\n"
2733 "Hidden documents can be displayed back through\n"
2734 "the menu: View->Hidden->...\n"
2736 "To remove this question, set your preference in:\n"
2737 " Tools->Preferences->Look&Feel->UserInterface\n"
2739 int ret = Alert::prompt(_("Close or hide document?"),
2740 text, 0, 1, _("&Close"), _("&Hide"));
2741 close_buffer = (ret == 0);
2745 return closeWorkArea(wa, close_buffer);
2749 bool GuiView::closeBuffer()
2751 GuiWorkArea * wa = currentMainWorkArea();
2752 setCurrentWorkArea(wa);
2753 Buffer & buf = wa->bufferView().buffer();
2754 return wa && closeWorkArea(wa, !buf.parent());
2758 void GuiView::writeSession() const {
2759 GuiWorkArea const * active_wa = currentMainWorkArea();
2760 for (int i = 0; i < d.splitter_->count(); ++i) {
2761 TabWorkArea * twa = d.tabWorkArea(i);
2762 for (int j = 0; j < twa->count(); ++j) {
2763 GuiWorkArea * wa = static_cast<GuiWorkArea *>(twa->widget(j));
2764 Buffer & buf = wa->bufferView().buffer();
2765 theSession().lastOpened().add(buf.fileName(), wa == active_wa);
2771 bool GuiView::closeBufferAll()
2773 // Close the workareas in all other views
2774 QList<int> const ids = guiApp->viewIds();
2775 for (int i = 0; i != ids.size(); ++i) {
2776 if (id_ != ids[i] && !guiApp->view(ids[i]).closeWorkAreaAll())
2780 // Close our own workareas
2781 if (!closeWorkAreaAll())
2784 // Now close the hidden buffers. We prevent hidden buffers from being
2785 // dirty, so we can just close them.
2786 theBufferList().closeAll();
2791 bool GuiView::closeWorkAreaAll()
2793 setCurrentWorkArea(currentMainWorkArea());
2795 // We might be in a situation that there is still a tabWorkArea, but
2796 // there are no tabs anymore. This can happen when we get here after a
2797 // TabWorkArea::lastWorkAreaRemoved() signal. Therefore we count how
2798 // many TabWorkArea's have no documents anymore.
2801 // We have to call count() each time, because it can happen that
2802 // more than one splitter will disappear in one iteration (bug 5998).
2803 while (d.splitter_->count() > empty_twa) {
2804 TabWorkArea * twa = d.tabWorkArea(empty_twa);
2806 if (twa->count() == 0)
2809 setCurrentWorkArea(twa->currentWorkArea());
2810 if (!closeTabWorkArea(twa))
2818 bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
2823 Buffer & buf = wa->bufferView().buffer();
2825 if (GuiViewPrivate::busyBuffers.contains(&buf)) {
2826 Alert::warning(_("Close document"),
2827 _("Document could not be closed because it is being processed by LyX."));
2832 return closeBuffer(buf);
2834 if (!inMultiTabs(wa))
2835 if (!saveBufferIfNeeded(buf, true))
2843 bool GuiView::closeBuffer(Buffer & buf)
2845 // If we are in a close_event all children will be closed in some time,
2846 // so no need to do it here. This will ensure that the children end up
2847 // in the session file in the correct order. If we close the master
2848 // buffer, we can close or release the child buffers here too.
2849 bool success = true;
2851 ListOfBuffers clist = buf.getChildren();
2852 ListOfBuffers::const_iterator it = clist.begin();
2853 ListOfBuffers::const_iterator const bend = clist.end();
2854 for (; it != bend; ++it) {
2855 Buffer * child_buf = *it;
2856 if (theBufferList().isOthersChild(&buf, child_buf)) {
2857 child_buf->setParent(0);
2861 // FIXME: should we look in other tabworkareas?
2862 // ANSWER: I don't think so. I've tested, and if the child is
2863 // open in some other window, it closes without a problem.
2864 GuiWorkArea * child_wa = workArea(*child_buf);
2866 success = closeWorkArea(child_wa, true);
2870 // In this case the child buffer is open but hidden.
2871 // It therefore should not (MUST NOT) be dirty!
2872 LATTEST(child_buf->isClean());
2873 theBufferList().release(child_buf);
2878 // goto bookmark to update bookmark pit.
2879 // FIXME: we should update only the bookmarks related to this buffer!
2880 LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
2881 for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
2882 guiApp->gotoBookmark(i+1, false, false);
2884 if (saveBufferIfNeeded(buf, false)) {
2885 buf.removeAutosaveFile();
2886 theBufferList().release(&buf);
2890 // open all children again to avoid a crash because of dangling
2891 // pointers (bug 6603)
2897 bool GuiView::closeTabWorkArea(TabWorkArea * twa)
2899 while (twa == d.currentTabWorkArea()) {
2900 twa->setCurrentIndex(twa->count() - 1);
2902 GuiWorkArea * wa = twa->currentWorkArea();
2903 Buffer & b = wa->bufferView().buffer();
2905 // We only want to close the buffer if the same buffer is not visible
2906 // in another view, and if this is not a child and if we are closing
2907 // a view (not a tabgroup).
2908 bool const close_buffer =
2909 !inOtherView(b) && !b.parent() && closing_;
2911 if (!closeWorkArea(wa, close_buffer))
2918 bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding)
2920 if (buf.isClean() || buf.paragraphs().empty())
2923 // Switch to this Buffer.
2928 if (buf.isUnnamed())
2929 file = from_utf8(buf.fileName().onlyFileName());
2931 file = buf.fileName().displayName(30);
2933 // Bring this window to top before asking questions.
2938 if (hiding && buf.isUnnamed()) {
2939 docstring const text = bformat(_("The document %1$s has not been "
2940 "saved yet.\n\nDo you want to save "
2941 "the document?"), file);
2942 ret = Alert::prompt(_("Save new document?"),
2943 text, 0, 1, _("&Save"), _("&Cancel"));
2947 docstring const text = bformat(_("The document %1$s has unsaved changes."
2948 "\n\nDo you want to save the document or discard the changes?"), file);
2949 ret = Alert::prompt(_("Save changed document?"),
2950 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
2955 if (!saveBuffer(buf))
2959 // If we crash after this we could have no autosave file
2960 // but I guess this is really improbable (Jug).
2961 // Sometimes improbable things happen:
2962 // - see bug http://www.lyx.org/trac/ticket/6587 (ps)
2963 // buf.removeAutosaveFile();
2965 // revert all changes
2976 bool GuiView::inMultiTabs(GuiWorkArea * wa)
2978 Buffer & buf = wa->bufferView().buffer();
2980 for (int i = 0; i != d.splitter_->count(); ++i) {
2981 GuiWorkArea * wa_ = d.tabWorkArea(i)->workArea(buf);
2982 if (wa_ && wa_ != wa)
2985 return inOtherView(buf);
2989 bool GuiView::inOtherView(Buffer & buf)
2991 QList<int> const ids = guiApp->viewIds();
2993 for (int i = 0; i != ids.size(); ++i) {
2997 if (guiApp->view(ids[i]).workArea(buf))
3004 void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np, bool const move)
3006 if (!documentBufferView())
3009 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3010 Buffer * const curbuf = &documentBufferView()->buffer();
3011 int nwa = twa->count();
3012 for (int i = 0; i < nwa; ++i) {
3013 if (&workArea(i)->bufferView().buffer() == curbuf) {
3015 if (np == NEXTBUFFER)
3016 next_index = (i == nwa - 1 ? 0 : i + 1);
3018 next_index = (i == 0 ? nwa - 1 : i - 1);
3020 twa->moveTab(i, next_index);
3022 setBuffer(&workArea(next_index)->bufferView().buffer());
3030 /// make sure the document is saved
3031 static bool ensureBufferClean(Buffer * buffer)
3033 LASSERT(buffer, return false);
3034 if (buffer->isClean() && !buffer->isUnnamed())
3037 docstring const file = buffer->fileName().displayName(30);
3040 if (!buffer->isUnnamed()) {
3041 text = bformat(_("The document %1$s has unsaved "
3042 "changes.\n\nDo you want to save "
3043 "the document?"), file);
3044 title = _("Save changed document?");
3047 text = bformat(_("The document %1$s has not been "
3048 "saved yet.\n\nDo you want to save "
3049 "the document?"), file);
3050 title = _("Save new document?");
3052 int const ret = Alert::prompt(title, text, 0, 1, _("&Save"), _("&Cancel"));
3055 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
3057 return buffer->isClean() && !buffer->isUnnamed();
3061 bool GuiView::reloadBuffer(Buffer & buf)
3063 Buffer::ReadStatus status = buf.reload();
3064 return status == Buffer::ReadSuccess;
3068 void GuiView::checkExternallyModifiedBuffers()
3070 BufferList::iterator bit = theBufferList().begin();
3071 BufferList::iterator const bend = theBufferList().end();
3072 for (; bit != bend; ++bit) {
3073 Buffer * buf = *bit;
3074 if (buf->fileName().exists()
3075 && buf->isExternallyModified(Buffer::checksum_method)) {
3076 docstring text = bformat(_("Document \n%1$s\n has been externally modified."
3077 " Reload now? Any local changes will be lost."),
3078 from_utf8(buf->absFileName()));
3079 int const ret = Alert::prompt(_("Reload externally changed document?"),
3080 text, 0, 1, _("&Reload"), _("&Cancel"));
3088 void GuiView::dispatchVC(FuncRequest const & cmd, DispatchResult & dr)
3090 Buffer * buffer = documentBufferView()
3091 ? &(documentBufferView()->buffer()) : 0;
3093 switch (cmd.action()) {
3094 case LFUN_VC_REGISTER:
3095 if (!buffer || !ensureBufferClean(buffer))
3097 if (!buffer->lyxvc().inUse()) {
3098 if (buffer->lyxvc().registrer()) {
3099 reloadBuffer(*buffer);
3100 dr.clearMessageUpdate();
3105 case LFUN_VC_RENAME:
3106 case LFUN_VC_COPY: {
3107 if (!buffer || !ensureBufferClean(buffer))
3109 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
3110 if (buffer->lyxvc().isCheckInWithConfirmation()) {
3111 // Some changes are not yet committed.
3112 // We test here and not in getStatus(), since
3113 // this test is expensive.
3115 LyXVC::CommandResult ret =
3116 buffer->lyxvc().checkIn(log);
3118 if (ret == LyXVC::ErrorCommand ||
3119 ret == LyXVC::VCSuccess)
3120 reloadBuffer(*buffer);
3121 if (buffer->lyxvc().isCheckInWithConfirmation()) {
3122 frontend::Alert::error(
3123 _("Revision control error."),
3124 _("Document could not be checked in."));
3128 RenameKind const kind = (cmd.action() == LFUN_VC_RENAME) ?
3129 LV_VC_RENAME : LV_VC_COPY;
3130 renameBuffer(*buffer, cmd.argument(), kind);
3135 case LFUN_VC_CHECK_IN:
3136 if (!buffer || !ensureBufferClean(buffer))
3138 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
3140 LyXVC::CommandResult ret = buffer->lyxvc().checkIn(log);
3142 // Only skip reloading if the checkin was cancelled or
3143 // an error occurred before the real checkin VCS command
3144 // was executed, since the VCS might have changed the
3145 // file even if it could not checkin successfully.
3146 if (ret == LyXVC::ErrorCommand || ret == LyXVC::VCSuccess)
3147 reloadBuffer(*buffer);
3151 case LFUN_VC_CHECK_OUT:
3152 if (!buffer || !ensureBufferClean(buffer))
3154 if (buffer->lyxvc().inUse()) {
3155 dr.setMessage(buffer->lyxvc().checkOut());
3156 reloadBuffer(*buffer);
3160 case LFUN_VC_LOCKING_TOGGLE:
3161 LASSERT(buffer, return);
3162 if (!ensureBufferClean(buffer) || buffer->isReadonly())
3164 if (buffer->lyxvc().inUse()) {
3165 string res = buffer->lyxvc().lockingToggle();
3167 frontend::Alert::error(_("Revision control error."),
3168 _("Error when setting the locking property."));
3171 reloadBuffer(*buffer);
3176 case LFUN_VC_REVERT:
3177 LASSERT(buffer, return);
3178 if (buffer->lyxvc().revert()) {
3179 reloadBuffer(*buffer);
3180 dr.clearMessageUpdate();
3184 case LFUN_VC_UNDO_LAST:
3185 LASSERT(buffer, return);
3186 buffer->lyxvc().undoLast();
3187 reloadBuffer(*buffer);
3188 dr.clearMessageUpdate();
3191 case LFUN_VC_REPO_UPDATE:
3192 LASSERT(buffer, return);
3193 if (ensureBufferClean(buffer)) {
3194 dr.setMessage(buffer->lyxvc().repoUpdate());
3195 checkExternallyModifiedBuffers();
3199 case LFUN_VC_COMMAND: {
3200 string flag = cmd.getArg(0);
3201 if (buffer && contains(flag, 'R') && !ensureBufferClean(buffer))
3204 if (contains(flag, 'M')) {
3205 if (!Alert::askForText(message, _("LyX VC: Log Message")))
3208 string path = cmd.getArg(1);
3209 if (contains(path, "$$p") && buffer)
3210 path = subst(path, "$$p", buffer->filePath());
3211 LYXERR(Debug::LYXVC, "Directory: " << path);
3213 if (!pp.isReadableDirectory()) {
3214 lyxerr << _("Directory is not accessible.") << endl;
3217 support::PathChanger p(pp);
3219 string command = cmd.getArg(2);
3220 if (command.empty())
3223 command = subst(command, "$$i", buffer->absFileName());
3224 command = subst(command, "$$p", buffer->filePath());
3226 command = subst(command, "$$m", to_utf8(message));
3227 LYXERR(Debug::LYXVC, "Command: " << command);
3229 one.startscript(Systemcall::Wait, command);
3233 if (contains(flag, 'I'))
3234 buffer->markDirty();
3235 if (contains(flag, 'R'))
3236 reloadBuffer(*buffer);
3241 case LFUN_VC_COMPARE: {
3243 if (cmd.argument().empty()) {
3244 lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "comparehistory"));
3248 string rev1 = cmd.getArg(0);
3252 if (!buffer->lyxvc().prepareFileRevision(rev1, f1))
3255 if (isStrInt(rev1) && convert<int>(rev1) <= 0) {
3256 f2 = buffer->absFileName();
3258 string rev2 = cmd.getArg(1);
3262 if (!buffer->lyxvc().prepareFileRevision(rev2, f2))
3266 LYXERR(Debug::LYXVC, "Launching comparison for fetched revisions:\n" <<
3267 f1 << "\n" << f2 << "\n" );
3268 string par = "compare run " + quoteName(f1) + " " + quoteName(f2);
3269 lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, par));
3279 void GuiView::openChildDocument(string const & fname)
3281 LASSERT(documentBufferView(), return);
3282 Buffer & buffer = documentBufferView()->buffer();
3283 FileName const filename = support::makeAbsPath(fname, buffer.filePath());
3284 documentBufferView()->saveBookmark(false);
3286 if (theBufferList().exists(filename)) {
3287 child = theBufferList().getBuffer(filename);
3290 message(bformat(_("Opening child document %1$s..."),
3291 makeDisplayPath(filename.absFileName())));
3292 child = loadDocument(filename, false);
3294 // Set the parent name of the child document.
3295 // This makes insertion of citations and references in the child work,
3296 // when the target is in the parent or another child document.
3298 child->setParent(&buffer);
3302 bool GuiView::goToFileRow(string const & argument)
3306 size_t i = argument.find_last_of(' ');
3307 if (i != string::npos) {
3308 file_name = os::internal_path(trim(argument.substr(0, i)));
3309 istringstream is(argument.substr(i + 1));
3314 if (i == string::npos) {
3315 LYXERR0("Wrong argument: " << argument);
3319 string const abstmp = package().temp_dir().absFileName();
3320 string const realtmp = package().temp_dir().realPath();
3321 // We have to use os::path_prefix_is() here, instead of
3322 // simply prefixIs(), because the file name comes from
3323 // an external application and may need case adjustment.
3324 if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
3325 || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
3326 // Needed by inverse dvi search. If it is a file
3327 // in tmpdir, call the apropriated function.
3328 // If tmpdir is a symlink, we may have the real
3329 // path passed back, so we correct for that.
3330 if (!prefixIs(file_name, abstmp))
3331 file_name = subst(file_name, realtmp, abstmp);
3332 buf = theBufferList().getBufferFromTmp(file_name);
3334 // Must replace extension of the file to be .lyx
3335 // and get full path
3336 FileName const s = fileSearch(string(),
3337 support::changeExtension(file_name, ".lyx"), "lyx");
3338 // Either change buffer or load the file
3339 if (theBufferList().exists(s))
3340 buf = theBufferList().getBuffer(s);
3341 else if (s.exists()) {
3342 buf = loadDocument(s);
3347 _("File does not exist: %1$s"),
3348 makeDisplayPath(file_name)));
3354 _("No buffer for file: %1$s."),
3355 makeDisplayPath(file_name))
3360 documentBufferView()->setCursorFromRow(row);
3366 Buffer::ExportStatus GuiView::GuiViewPrivate::runAndDestroy(const T& func, Buffer const * orig, Buffer * clone, string const & format)
3368 Buffer::ExportStatus const status = func(format);
3370 // the cloning operation will have produced a clone of the entire set of
3371 // documents, starting from the master. so we must delete those.
3372 Buffer * mbuf = const_cast<Buffer *>(clone->masterBuffer());
3374 busyBuffers.remove(orig);
3379 Buffer::ExportStatus GuiView::GuiViewPrivate::compileAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3381 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
3382 return runAndDestroy(lyx::bind(mem_func, clone, _1, true), orig, clone, format);
3386 Buffer::ExportStatus GuiView::GuiViewPrivate::exportAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3388 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &, bool) const = &Buffer::doExport;
3389 return runAndDestroy(lyx::bind(mem_func, clone, _1, false), orig, clone, format);
3393 Buffer::ExportStatus GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * clone, string const & format)
3395 Buffer::ExportStatus (Buffer::* mem_func)(std::string const &) const = &Buffer::preview;
3396 return runAndDestroy(lyx::bind(mem_func, clone, _1), orig, clone, format);
3400 bool GuiView::GuiViewPrivate::asyncBufferProcessing(
3401 string const & argument,
3402 Buffer const * used_buffer,
3403 docstring const & msg,
3404 Buffer::ExportStatus (*asyncFunc)(Buffer const *, Buffer *, string const &),
3405 Buffer::ExportStatus (Buffer::*syncFunc)(string const &, bool) const,
3406 Buffer::ExportStatus (Buffer::*previewFunc)(string const &) const)
3411 string format = argument;
3413 format = used_buffer->params().getDefaultOutputFormat();
3414 processing_format = format;
3416 progress_->clearMessages();
3419 #if EXPORT_in_THREAD
3420 GuiViewPrivate::busyBuffers.insert(used_buffer);
3421 Buffer * cloned_buffer = used_buffer->cloneFromMaster();
3422 if (!cloned_buffer) {
3423 Alert::error(_("Export Error"),
3424 _("Error cloning the Buffer."));
3427 QFuture<Buffer::ExportStatus> f = QtConcurrent::run(
3432 setPreviewFuture(f);
3433 last_export_format = used_buffer->params().bufferFormat();
3436 // We are asynchronous, so we don't know here anything about the success
3439 Buffer::ExportStatus status;
3441 // TODO check here if it breaks exporting with Qt < 4.4
3442 status = (used_buffer->*syncFunc)(format, true);
3443 } else if (previewFunc) {
3444 status = (used_buffer->*previewFunc)(format);
3447 handleExportStatus(gv_, status, format);
3449 return (status == Buffer::ExportSuccess
3450 || status == Buffer::PreviewSuccess);
3454 void GuiView::dispatchToBufferView(FuncRequest const & cmd, DispatchResult & dr)
3456 BufferView * bv = currentBufferView();
3457 LASSERT(bv, return);
3459 // Let the current BufferView dispatch its own actions.
3460 bv->dispatch(cmd, dr);
3461 if (dr.dispatched())
3464 // Try with the document BufferView dispatch if any.
3465 BufferView * doc_bv = documentBufferView();
3466 if (doc_bv && doc_bv != bv) {
3467 doc_bv->dispatch(cmd, dr);
3468 if (dr.dispatched())
3472 // Then let the current Cursor dispatch its own actions.
3473 bv->cursor().dispatch(cmd);
3475 // update completion. We do it here and not in
3476 // processKeySym to avoid another redraw just for a
3477 // changed inline completion
3478 if (cmd.origin() == FuncRequest::KEYBOARD) {
3479 if (cmd.action() == LFUN_SELF_INSERT
3480 || (cmd.action() == LFUN_ERT_INSERT && bv->cursor().inMathed()))
3481 updateCompletion(bv->cursor(), true, true);
3482 else if (cmd.action() == LFUN_CHAR_DELETE_BACKWARD)
3483 updateCompletion(bv->cursor(), false, true);
3485 updateCompletion(bv->cursor(), false, false);
3488 dr = bv->cursor().result();
3492 void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
3494 BufferView * bv = currentBufferView();
3495 // By default we won't need any update.
3496 dr.screenUpdate(Update::None);
3497 // assume cmd will be dispatched
3498 dr.dispatched(true);
3500 Buffer * doc_buffer = documentBufferView()
3501 ? &(documentBufferView()->buffer()) : 0;
3503 if (cmd.origin() == FuncRequest::TOC) {
3504 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
3505 // FIXME: do we need to pass a DispatchResult object here?
3506 toc->doDispatch(bv->cursor(), cmd);
3510 string const argument = to_utf8(cmd.argument());
3512 switch(cmd.action()) {
3513 case LFUN_BUFFER_CHILD_OPEN:
3514 openChildDocument(to_utf8(cmd.argument()));
3517 case LFUN_BUFFER_IMPORT:
3518 importDocument(to_utf8(cmd.argument()));
3521 case LFUN_BUFFER_EXPORT: {
3524 FileName target_dir = doc_buffer->fileName().onlyPath();
3525 string const dest = cmd.getArg(1);
3526 if (!dest.empty() && FileName::isAbsolute(dest))
3527 target_dir = FileName(support::onlyPath(dest));
3528 // GCC only sees strfwd.h when building merged
3529 if (::lyx::operator==(cmd.argument(), "custom")) {
3530 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
3533 if ((dest.empty() && doc_buffer->isUnnamed())
3534 || !target_dir.isDirWritable()) {
3535 exportBufferAs(*doc_buffer, cmd.argument());
3538 /* TODO/Review: Is it a problem to also export the children?
3539 See the update_unincluded flag */
3540 d.asyncBufferProcessing(argument,
3543 &GuiViewPrivate::exportAndDestroy,
3546 // TODO Inform user about success
3550 case LFUN_BUFFER_EXPORT_AS: {
3551 LASSERT(doc_buffer, break);
3552 docstring f = cmd.argument();
3554 f = from_ascii(doc_buffer->params().getDefaultOutputFormat());
3555 exportBufferAs(*doc_buffer, f);
3559 case LFUN_BUFFER_UPDATE: {
3560 d.asyncBufferProcessing(argument,
3563 &GuiViewPrivate::compileAndDestroy,
3568 case LFUN_BUFFER_VIEW: {
3569 d.asyncBufferProcessing(argument,
3571 _("Previewing ..."),
3572 &GuiViewPrivate::previewAndDestroy,
3577 case LFUN_MASTER_BUFFER_UPDATE: {
3578 d.asyncBufferProcessing(argument,
3579 (doc_buffer ? doc_buffer->masterBuffer() : 0),
3581 &GuiViewPrivate::compileAndDestroy,
3586 case LFUN_MASTER_BUFFER_VIEW: {
3587 d.asyncBufferProcessing(argument,
3588 (doc_buffer ? doc_buffer->masterBuffer() : 0),
3590 &GuiViewPrivate::previewAndDestroy,
3591 0, &Buffer::preview);
3594 case LFUN_BUFFER_SWITCH: {
3595 string const file_name = to_utf8(cmd.argument());
3596 if (!FileName::isAbsolute(file_name)) {
3598 dr.setMessage(_("Absolute filename expected."));
3602 Buffer * buffer = theBufferList().getBuffer(FileName(file_name));
3605 dr.setMessage(_("Document not loaded"));
3609 // Do we open or switch to the buffer in this view ?
3610 if (workArea(*buffer)
3611 || lyxrc.open_buffers_in_tabs || !documentBufferView()) {
3616 // Look for the buffer in other views
3617 QList<int> const ids = guiApp->viewIds();
3619 for (; i != ids.size(); ++i) {
3620 GuiView & gv = guiApp->view(ids[i]);
3621 if (gv.workArea(*buffer)) {
3623 gv.activateWindow();
3625 gv.setBuffer(buffer);
3630 // If necessary, open a new window as a last resort
3631 if (i == ids.size()) {
3632 lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW));
3638 case LFUN_BUFFER_NEXT:
3639 gotoNextOrPreviousBuffer(NEXTBUFFER, false);
3642 case LFUN_BUFFER_MOVE_NEXT:
3643 gotoNextOrPreviousBuffer(NEXTBUFFER, true);
3646 case LFUN_BUFFER_PREVIOUS:
3647 gotoNextOrPreviousBuffer(PREVBUFFER, false);
3650 case LFUN_BUFFER_MOVE_PREVIOUS:
3651 gotoNextOrPreviousBuffer(PREVBUFFER, true);
3654 case LFUN_COMMAND_EXECUTE: {
3655 command_execute_ = true;
3658 case LFUN_DROP_LAYOUTS_CHOICE:
3659 d.layout_->showPopup();
3662 case LFUN_MENU_OPEN:
3663 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
3664 menu->exec(QCursor::pos());
3667 case LFUN_FILE_INSERT:
3668 insertLyXFile(cmd.argument());
3671 case LFUN_FILE_INSERT_PLAINTEXT:
3672 case LFUN_FILE_INSERT_PLAINTEXT_PARA: {
3673 string const fname = to_utf8(cmd.argument());
3674 if (!fname.empty() && !FileName::isAbsolute(fname)) {
3675 dr.setMessage(_("Absolute filename expected."));
3679 FileName filename(fname);
3680 if (fname.empty()) {
3681 FileDialog dlg(qt_("Select file to insert"));
3683 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
3684 QStringList(qt_("All Files (*)")));
3686 if (result.first == FileDialog::Later || result.second.isEmpty()) {
3687 dr.setMessage(_("Canceled."));
3691 filename.set(fromqstr(result.second));
3695 FuncRequest const new_cmd(cmd, filename.absoluteFilePath());
3696 bv->dispatch(new_cmd, dr);
3701 case LFUN_BUFFER_RELOAD: {
3702 LASSERT(doc_buffer, break);
3705 if (!doc_buffer->isClean()) {
3706 docstring const file =
3707 makeDisplayPath(doc_buffer->absFileName(), 20);
3708 docstring text = bformat(_("Any changes will be lost. "
3709 "Are you sure you want to revert to the saved version "
3710 "of the document %1$s?"), file);
3711 ret = Alert::prompt(_("Revert to saved document?"),
3712 text, 1, 1, _("&Revert"), _("&Cancel"));
3716 doc_buffer->markClean();
3717 reloadBuffer(*doc_buffer);
3718 dr.forceBufferUpdate();
3723 case LFUN_BUFFER_WRITE:
3724 LASSERT(doc_buffer, break);
3725 saveBuffer(*doc_buffer);
3728 case LFUN_BUFFER_WRITE_AS:
3729 LASSERT(doc_buffer, break);
3730 renameBuffer(*doc_buffer, cmd.argument());
3733 case LFUN_BUFFER_WRITE_ALL: {
3734 Buffer * first = theBufferList().first();
3737 message(_("Saving all documents..."));
3738 // We cannot use a for loop as the buffer list cycles.
3741 if (!b->isClean()) {
3743 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
3745 b = theBufferList().next(b);
3746 } while (b != first);
3747 dr.setMessage(_("All documents saved."));
3751 case LFUN_BUFFER_CLOSE:
3755 case LFUN_BUFFER_CLOSE_ALL:
3759 case LFUN_TOOLBAR_TOGGLE: {
3760 string const name = cmd.getArg(0);
3761 if (GuiToolbar * t = toolbar(name))
3766 case LFUN_DIALOG_UPDATE: {
3767 string const name = to_utf8(cmd.argument());
3768 if (name == "prefs" || name == "document")
3769 updateDialog(name, string());
3770 else if (name == "paragraph")
3771 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
3772 else if (currentBufferView()) {
3773 Inset * inset = currentBufferView()->editedInset(name);
3774 // Can only update a dialog connected to an existing inset
3776 // FIXME: get rid of this indirection; GuiView ask the inset
3777 // if he is kind enough to update itself...
3778 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
3779 //FIXME: pass DispatchResult here?
3780 inset->dispatch(currentBufferView()->cursor(), fr);
3786 case LFUN_DIALOG_TOGGLE: {
3787 FuncCode const func_code = isDialogVisible(cmd.getArg(0))
3788 ? LFUN_DIALOG_HIDE : LFUN_DIALOG_SHOW;
3789 dispatch(FuncRequest(func_code, cmd.argument()), dr);
3793 case LFUN_DIALOG_DISCONNECT_INSET:
3794 disconnectDialog(to_utf8(cmd.argument()));
3797 case LFUN_DIALOG_HIDE: {
3798 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
3802 case LFUN_DIALOG_SHOW: {
3803 string const name = cmd.getArg(0);
3804 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
3806 if (name == "character") {
3807 data = freefont2string();
3809 showDialog("character", data);
3810 } else if (name == "latexlog") {
3811 Buffer::LogType type;
3812 string const logfile = doc_buffer->logName(&type);
3814 case Buffer::latexlog:
3817 case Buffer::buildlog:
3821 data += Lexer::quoteString(logfile);
3822 showDialog("log", data);
3823 } else if (name == "vclog") {
3824 string const data = "vc " +
3825 Lexer::quoteString(doc_buffer->lyxvc().getLogFile());
3826 showDialog("log", data);
3827 } else if (name == "symbols") {
3828 data = bv->cursor().getEncoding()->name();
3830 showDialog("symbols", data);
3832 } else if (name == "prefs" && isFullScreen()) {
3833 lfunUiToggle("fullscreen");
3834 showDialog("prefs", data);
3836 showDialog(name, data);
3841 dr.setMessage(cmd.argument());
3844 case LFUN_UI_TOGGLE: {
3845 string arg = cmd.getArg(0);
3846 if (!lfunUiToggle(arg)) {
3847 docstring const msg = "ui-toggle " + _("%1$s unknown command!");
3848 dr.setMessage(bformat(msg, from_utf8(arg)));
3850 // Make sure the keyboard focus stays in the work area.
3855 case LFUN_VIEW_SPLIT: {
3856 LASSERT(doc_buffer, break);
3857 string const orientation = cmd.getArg(0);
3858 d.splitter_->setOrientation(orientation == "vertical"
3859 ? Qt::Vertical : Qt::Horizontal);
3860 TabWorkArea * twa = addTabWorkArea();
3861 GuiWorkArea * wa = twa->addWorkArea(*doc_buffer, *this);
3862 setCurrentWorkArea(wa);
3865 case LFUN_TAB_GROUP_CLOSE:
3866 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3867 closeTabWorkArea(twa);
3868 d.current_work_area_ = 0;
3869 twa = d.currentTabWorkArea();
3870 // Switch to the next GuiWorkArea in the found TabWorkArea.
3872 // Make sure the work area is up to date.
3873 setCurrentWorkArea(twa->currentWorkArea());
3875 setCurrentWorkArea(0);
3880 case LFUN_VIEW_CLOSE:
3881 if (TabWorkArea * twa = d.currentTabWorkArea()) {
3882 closeWorkArea(twa->currentWorkArea());
3883 d.current_work_area_ = 0;
3884 twa = d.currentTabWorkArea();
3885 // Switch to the next GuiWorkArea in the found TabWorkArea.
3887 // Make sure the work area is up to date.
3888 setCurrentWorkArea(twa->currentWorkArea());
3890 setCurrentWorkArea(0);
3895 case LFUN_COMPLETION_INLINE:
3896 if (d.current_work_area_)
3897 d.current_work_area_->completer().showInline();
3900 case LFUN_COMPLETION_POPUP:
3901 if (d.current_work_area_)
3902 d.current_work_area_->completer().showPopup();
3907 if (d.current_work_area_)
3908 d.current_work_area_->completer().tab();
3911 case LFUN_COMPLETION_CANCEL:
3912 if (d.current_work_area_) {
3913 if (d.current_work_area_->completer().popupVisible())
3914 d.current_work_area_->completer().hidePopup();
3916 d.current_work_area_->completer().hideInline();
3920 case LFUN_COMPLETION_ACCEPT:
3921 if (d.current_work_area_)
3922 d.current_work_area_->completer().activate();
3925 case LFUN_BUFFER_ZOOM_IN:
3926 case LFUN_BUFFER_ZOOM_OUT:
3927 if (cmd.argument().empty()) {
3928 if (cmd.action() == LFUN_BUFFER_ZOOM_IN)
3933 lyxrc.zoom += convert<int>(cmd.argument());
3935 if (lyxrc.zoom < 10)
3938 // The global QPixmapCache is used in GuiPainter to cache text
3939 // painting so we must reset it.
3940 QPixmapCache::clear();
3941 guiApp->fontLoader().update();
3942 lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
3945 case LFUN_VC_REGISTER:
3946 case LFUN_VC_RENAME:
3948 case LFUN_VC_CHECK_IN:
3949 case LFUN_VC_CHECK_OUT:
3950 case LFUN_VC_REPO_UPDATE:
3951 case LFUN_VC_LOCKING_TOGGLE:
3952 case LFUN_VC_REVERT:
3953 case LFUN_VC_UNDO_LAST:
3954 case LFUN_VC_COMMAND:
3955 case LFUN_VC_COMPARE:
3956 dispatchVC(cmd, dr);
3959 case LFUN_SERVER_GOTO_FILE_ROW:
3960 goToFileRow(to_utf8(cmd.argument()));
3963 case LFUN_FORWARD_SEARCH: {
3964 Buffer const * doc_master = doc_buffer->masterBuffer();
3965 FileName const path(doc_master->temppath());
3966 string const texname = doc_master->isChild(doc_buffer)
3967 ? DocFileName(changeExtension(
3968 doc_buffer->absFileName(),
3969 "tex")).mangledFileName()
3970 : doc_buffer->latexName();
3971 string const fulltexname =
3972 support::makeAbsPath(texname, doc_master->temppath()).absFileName();
3973 string const mastername =
3974 removeExtension(doc_master->latexName());
3975 FileName const dviname(addName(path.absFileName(),
3976 addExtension(mastername, "dvi")));
3977 FileName const pdfname(addName(path.absFileName(),
3978 addExtension(mastername, "pdf")));
3979 bool const have_dvi = dviname.exists();
3980 bool const have_pdf = pdfname.exists();
3981 if (!have_dvi && !have_pdf) {
3982 dr.setMessage(_("Please, preview the document first."));
3985 string outname = dviname.onlyFileName();
3986 string command = lyxrc.forward_search_dvi;
3987 if (!have_dvi || (have_pdf &&
3988 pdfname.lastModified() > dviname.lastModified())) {
3989 outname = pdfname.onlyFileName();
3990 command = lyxrc.forward_search_pdf;
3993 DocIterator cur = bv->cursor();
3994 int row = doc_buffer->texrow().rowFromDocIterator(cur).first;
3995 LYXERR(Debug::ACTION, "Forward search: row:" << row
3997 if (row == -1 || command.empty()) {
3998 dr.setMessage(_("Couldn't proceed."));
4001 string texrow = convert<string>(row);
4003 command = subst(command, "$$n", texrow);
4004 command = subst(command, "$$f", fulltexname);
4005 command = subst(command, "$$t", texname);
4006 command = subst(command, "$$o", outname);
4008 PathChanger p(path);
4010 one.startscript(Systemcall::DontWait, command);
4014 case LFUN_SPELLING_CONTINUOUSLY:
4015 lyxrc.spellcheck_continuously = !lyxrc.spellcheck_continuously;
4016 dr.screenUpdate(Update::Force | Update::FitCursor);
4020 // The LFUN must be for one of BufferView, Buffer or Cursor;
4022 dispatchToBufferView(cmd, dr);
4026 // Part of automatic menu appearance feature.
4027 if (isFullScreen()) {
4028 if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
4032 // Need to update bv because many LFUNs here might have destroyed it
4033 bv = currentBufferView();
4035 // Clear non-empty selections
4036 // (e.g. from a "char-forward-select" followed by "char-backward-select")
4038 Cursor & cur = bv->cursor();
4039 if ((cur.selection() && cur.selBegin() == cur.selEnd())) {
4040 cur.clearSelection();
4046 bool GuiView::lfunUiToggle(string const & ui_component)
4048 if (ui_component == "scrollbar") {
4049 // hide() is of no help
4050 if (d.current_work_area_->verticalScrollBarPolicy() ==
4051 Qt::ScrollBarAlwaysOff)
4053 d.current_work_area_->setVerticalScrollBarPolicy(
4054 Qt::ScrollBarAsNeeded);
4056 d.current_work_area_->setVerticalScrollBarPolicy(
4057 Qt::ScrollBarAlwaysOff);
4058 } else if (ui_component == "statusbar") {
4059 statusBar()->setVisible(!statusBar()->isVisible());
4060 } else if (ui_component == "menubar") {
4061 menuBar()->setVisible(!menuBar()->isVisible());
4063 if (ui_component == "frame") {
4065 getContentsMargins(&l, &t, &r, &b);
4066 //are the frames in default state?
4067 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
4069 setContentsMargins(-2, -2, -2, -2);
4071 setContentsMargins(0, 0, 0, 0);
4074 if (ui_component == "fullscreen") {
4082 void GuiView::toggleFullScreen()
4084 if (isFullScreen()) {
4085 for (int i = 0; i != d.splitter_->count(); ++i)
4086 d.tabWorkArea(i)->setFullScreen(false);
4087 setContentsMargins(0, 0, 0, 0);
4088 setWindowState(windowState() ^ Qt::WindowFullScreen);
4091 statusBar()->show();
4094 hideDialogs("prefs", 0);
4095 for (int i = 0; i != d.splitter_->count(); ++i)
4096 d.tabWorkArea(i)->setFullScreen(true);
4097 setContentsMargins(-2, -2, -2, -2);
4099 setWindowState(windowState() ^ Qt::WindowFullScreen);
4100 if (lyxrc.full_screen_statusbar)
4101 statusBar()->hide();
4102 if (lyxrc.full_screen_menubar)
4104 if (lyxrc.full_screen_toolbars) {
4105 ToolbarMap::iterator end = d.toolbars_.end();
4106 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
4111 // give dialogs like the TOC a chance to adapt
4116 Buffer const * GuiView::updateInset(Inset const * inset)
4121 Buffer const * inset_buffer = &(inset->buffer());
4123 for (int i = 0; i != d.splitter_->count(); ++i) {
4124 GuiWorkArea * wa = d.tabWorkArea(i)->currentWorkArea();
4127 Buffer const * buffer = &(wa->bufferView().buffer());
4128 if (inset_buffer == buffer)
4129 wa->scheduleRedraw();
4131 return inset_buffer;
4135 void GuiView::restartCursor()
4137 /* When we move around, or type, it's nice to be able to see
4138 * the cursor immediately after the keypress.
4140 if (d.current_work_area_)
4141 d.current_work_area_->startBlinkingCursor();
4143 // Take this occasion to update the other GUI elements.
4149 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
4151 if (d.current_work_area_)
4152 d.current_work_area_->completer().updateVisibility(cur, start, keep);
4157 // This list should be kept in sync with the list of insets in
4158 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
4159 // dialog should have the same name as the inset.
4160 // Changes should be also recorded in LFUN_DIALOG_SHOW doxygen
4161 // docs in LyXAction.cpp.
4163 char const * const dialognames[] = {
4165 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
4166 "citation", "compare", "comparehistory", "document", "errorlist", "ert",
4167 "external", "file", "findreplace", "findreplaceadv", "float", "graphics",
4168 "href", "include", "index", "index_print", "info", "listings", "label", "line",
4169 "log", "mathdelimiter", "mathmatrix", "mathspace", "nomenclature",
4170 "nomencl_print", "note", "paragraph", "phantom", "prefs", "ref",
4171 "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
4172 "thesaurus", "texinfo", "toc", "view-source", "vspace", "wrap", "progress"};
4174 char const * const * const end_dialognames =
4175 dialognames + (sizeof(dialognames) / sizeof(char *));
4179 cmpCStr(char const * name) : name_(name) {}
4180 bool operator()(char const * other) {
4181 return strcmp(other, name_) == 0;
4188 bool isValidName(string const & name)
4190 return find_if(dialognames, end_dialognames,
4191 cmpCStr(name.c_str())) != end_dialognames;
4197 void GuiView::resetDialogs()
4199 // Make sure that no LFUN uses any GuiView.
4200 guiApp->setCurrentView(0);
4204 constructToolbars();
4205 guiApp->menus().fillMenuBar(menuBar(), this, false);
4206 d.layout_->updateContents(true);
4207 // Now update controls with current buffer.
4208 guiApp->setCurrentView(this);
4214 Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
4216 if (!isValidName(name))
4219 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
4221 if (it != d.dialogs_.end()) {
4223 it->second->hideView();
4224 return it->second.get();
4227 Dialog * dialog = build(name);
4228 d.dialogs_[name].reset(dialog);
4229 if (lyxrc.allow_geometry_session)
4230 dialog->restoreSession();
4237 void GuiView::showDialog(string const & name, string const & data,
4240 triggerShowDialog(toqstr(name), toqstr(data), inset);
4244 void GuiView::doShowDialog(QString const & qname, QString const & qdata,
4250 const string name = fromqstr(qname);
4251 const string data = fromqstr(qdata);
4255 Dialog * dialog = findOrBuild(name, false);
4257 bool const visible = dialog->isVisibleView();
4258 dialog->showData(data);
4259 if (inset && currentBufferView())
4260 currentBufferView()->editInset(name, inset);
4261 // We only set the focus to the new dialog if it was not yet
4262 // visible in order not to change the existing previous behaviour
4264 // activateWindow is needed for floating dockviews
4265 dialog->asQWidget()->raise();
4266 dialog->asQWidget()->activateWindow();
4267 dialog->asQWidget()->setFocus();
4271 catch (ExceptionMessage const & ex) {
4279 bool GuiView::isDialogVisible(string const & name) const
4281 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
4282 if (it == d.dialogs_.end())
4284 return it->second.get()->isVisibleView() && !it->second.get()->isClosing();
4288 void GuiView::hideDialog(string const & name, Inset * inset)
4290 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
4291 if (it == d.dialogs_.end())
4295 if (!currentBufferView())
4297 if (inset != currentBufferView()->editedInset(name))
4301 Dialog * const dialog = it->second.get();
4302 if (dialog->isVisibleView())
4304 if (currentBufferView())
4305 currentBufferView()->editInset(name, 0);
4309 void GuiView::disconnectDialog(string const & name)
4311 if (!isValidName(name))
4313 if (currentBufferView())
4314 currentBufferView()->editInset(name, 0);
4318 void GuiView::hideAll() const
4320 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
4321 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
4323 for(; it != end; ++it)
4324 it->second->hideView();
4328 void GuiView::updateDialogs()
4330 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
4331 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
4333 for(; it != end; ++it) {
4334 Dialog * dialog = it->second.get();
4336 if (dialog->needBufferOpen() && !documentBufferView())
4337 hideDialog(fromqstr(dialog->name()), 0);
4338 else if (dialog->isVisibleView())
4339 dialog->checkStatus();
4346 Dialog * createDialog(GuiView & lv, string const & name);
4348 // will be replaced by a proper factory...
4349 Dialog * createGuiAbout(GuiView & lv);
4350 Dialog * createGuiBibtex(GuiView & lv);
4351 Dialog * createGuiChanges(GuiView & lv);
4352 Dialog * createGuiCharacter(GuiView & lv);
4353 Dialog * createGuiCitation(GuiView & lv);
4354 Dialog * createGuiCompare(GuiView & lv);
4355 Dialog * createGuiCompareHistory(GuiView & lv);
4356 Dialog * createGuiDelimiter(GuiView & lv);
4357 Dialog * createGuiDocument(GuiView & lv);
4358 Dialog * createGuiErrorList(GuiView & lv);
4359 Dialog * createGuiExternal(GuiView & lv);
4360 Dialog * createGuiGraphics(GuiView & lv);
4361 Dialog * createGuiInclude(GuiView & lv);
4362 Dialog * createGuiIndex(GuiView & lv);
4363 Dialog * createGuiListings(GuiView & lv);
4364 Dialog * createGuiLog(GuiView & lv);
4365 Dialog * createGuiMathMatrix(GuiView & lv);
4366 Dialog * createGuiNote(GuiView & lv);
4367 Dialog * createGuiParagraph(GuiView & lv);
4368 Dialog * createGuiPhantom(GuiView & lv);
4369 Dialog * createGuiPreferences(GuiView & lv);
4370 Dialog * createGuiPrint(GuiView & lv);
4371 Dialog * createGuiPrintindex(GuiView & lv);
4372 Dialog * createGuiRef(GuiView & lv);
4373 Dialog * createGuiSearch(GuiView & lv);
4374 Dialog * createGuiSearchAdv(GuiView & lv);
4375 Dialog * createGuiSendTo(GuiView & lv);
4376 Dialog * createGuiShowFile(GuiView & lv);
4377 Dialog * createGuiSpellchecker(GuiView & lv);
4378 Dialog * createGuiSymbols(GuiView & lv);
4379 Dialog * createGuiTabularCreate(GuiView & lv);
4380 Dialog * createGuiTexInfo(GuiView & lv);
4381 Dialog * createGuiToc(GuiView & lv);
4382 Dialog * createGuiThesaurus(GuiView & lv);
4383 Dialog * createGuiViewSource(GuiView & lv);
4384 Dialog * createGuiWrap(GuiView & lv);
4385 Dialog * createGuiProgressView(GuiView & lv);
4389 Dialog * GuiView::build(string const & name)
4391 LASSERT(isValidName(name), return 0);
4393 Dialog * dialog = createDialog(*this, name);
4397 if (name == "aboutlyx")
4398 return createGuiAbout(*this);
4399 if (name == "bibtex")
4400 return createGuiBibtex(*this);
4401 if (name == "changes")
4402 return createGuiChanges(*this);
4403 if (name == "character")
4404 return createGuiCharacter(*this);
4405 if (name == "citation")
4406 return createGuiCitation(*this);
4407 if (name == "compare")
4408 return createGuiCompare(*this);
4409 if (name == "comparehistory")
4410 return createGuiCompareHistory(*this);
4411 if (name == "document")
4412 return createGuiDocument(*this);
4413 if (name == "errorlist")
4414 return createGuiErrorList(*this);
4415 if (name == "external")
4416 return createGuiExternal(*this);
4418 return createGuiShowFile(*this);
4419 if (name == "findreplace")
4420 return createGuiSearch(*this);
4421 if (name == "findreplaceadv")
4422 return createGuiSearchAdv(*this);
4423 if (name == "graphics")
4424 return createGuiGraphics(*this);
4425 if (name == "include")
4426 return createGuiInclude(*this);
4427 if (name == "index")
4428 return createGuiIndex(*this);
4429 if (name == "index_print")
4430 return createGuiPrintindex(*this);
4431 if (name == "listings")
4432 return createGuiListings(*this);
4434 return createGuiLog(*this);
4435 if (name == "mathdelimiter")
4436 return createGuiDelimiter(*this);
4437 if (name == "mathmatrix")
4438 return createGuiMathMatrix(*this);
4440 return createGuiNote(*this);
4441 if (name == "paragraph")
4442 return createGuiParagraph(*this);
4443 if (name == "phantom")
4444 return createGuiPhantom(*this);
4445 if (name == "prefs")
4446 return createGuiPreferences(*this);
4448 return createGuiRef(*this);
4449 if (name == "sendto")
4450 return createGuiSendTo(*this);
4451 if (name == "spellchecker")
4452 return createGuiSpellchecker(*this);
4453 if (name == "symbols")
4454 return createGuiSymbols(*this);
4455 if (name == "tabularcreate")
4456 return createGuiTabularCreate(*this);
4457 if (name == "texinfo")
4458 return createGuiTexInfo(*this);
4459 if (name == "thesaurus")
4460 return createGuiThesaurus(*this);
4462 return createGuiToc(*this);
4463 if (name == "view-source")
4464 return createGuiViewSource(*this);
4466 return createGuiWrap(*this);
4467 if (name == "progress")
4468 return createGuiProgressView(*this);
4474 } // namespace frontend
4477 #include "moc_GuiView.cpp"