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 "FileDialog.h"
20 #include "FontLoader.h"
21 #include "GuiApplication.h"
22 #include "GuiCommandBuffer.h"
23 #include "GuiCompleter.h"
24 #include "GuiWorkArea.h"
25 #include "GuiKeySymbol.h"
27 #include "GuiToolbar.h"
31 #include "qt_helpers.h"
33 #include "frontends/alert.h"
35 #include "buffer_funcs.h"
37 #include "BufferList.h"
38 #include "BufferParams.h"
39 #include "BufferView.h"
40 #include "Converter.h"
43 #include "ErrorList.h"
45 #include "FuncStatus.h"
46 #include "FuncRequest.h"
54 #include "Paragraph.h"
55 #include "TextClass.h"
60 #include "support/convert.h"
61 #include "support/debug.h"
62 #include "support/ExceptionMessage.h"
63 #include "support/FileName.h"
64 #include "support/filetools.h"
65 #include "support/gettext.h"
66 #include "support/ForkedCalls.h"
67 #include "support/lassert.h"
68 #include "support/lstrings.h"
69 #include "support/os.h"
70 #include "support/Package.h"
71 #include "support/Timeout.h"
74 #include <QApplication>
75 #include <QCloseEvent>
77 #include <QDesktopWidget>
78 #include <QDragEnterEvent>
85 #include <QPixmapCache>
87 #include <QPushButton>
91 #include <QStackedWidget>
98 #include <boost/bind.hpp>
100 #ifdef HAVE_SYS_TIME_H
101 # include <sys/time.h>
108 using namespace lyx::support;
115 class BackgroundWidget : public QWidget
120 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
121 /// The text to be written on top of the pixmap
122 QString const text = lyx_version ?
123 qt_("version ") + lyx_version : qt_("unknown version");
124 splash_ = getPixmap("images/", "banner", "png");
126 QPainter pain(&splash_);
127 pain.setPen(QColor(0, 0, 0));
129 // The font used to display the version info
130 font.setStyleHint(QFont::SansSerif);
131 font.setWeight(QFont::Bold);
132 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
134 pain.drawText(260, 15, text);
137 void paintEvent(QPaintEvent *)
139 int x = (width() - splash_.width()) / 2;
140 int y = (height() - splash_.height()) / 2;
142 pain.drawPixmap(x, y, splash_);
150 /// Toolbar store providing access to individual toolbars by name.
151 typedef std::map<std::string, GuiToolbar *> ToolbarMap;
153 typedef boost::shared_ptr<Dialog> DialogPtr;
158 struct GuiView::GuiViewPrivate
161 : current_work_area_(0), current_main_work_area_(0),
162 layout_(0), autosave_timeout_(5000),
165 // hardcode here the platform specific icon size
166 smallIconSize = 14; // scaling problems
167 normalIconSize = 20; // ok, default
168 bigIconSize = 26; // better for some math icons
170 splitter_ = new QSplitter;
171 bg_widget_ = new BackgroundWidget;
172 stack_widget_ = new QStackedWidget;
173 stack_widget_->addWidget(bg_widget_);
174 stack_widget_->addWidget(splitter_);
182 delete stack_widget_;
185 QMenu * toolBarPopup(GuiView * parent)
187 // FIXME: translation
188 QMenu * menu = new QMenu(parent);
189 QActionGroup * iconSizeGroup = new QActionGroup(parent);
191 QAction * smallIcons = new QAction(iconSizeGroup);
192 smallIcons->setText(qt_("Small-sized icons"));
193 smallIcons->setCheckable(true);
194 QObject::connect(smallIcons, SIGNAL(triggered()),
195 parent, SLOT(smallSizedIcons()));
196 menu->addAction(smallIcons);
198 QAction * normalIcons = new QAction(iconSizeGroup);
199 normalIcons->setText(qt_("Normal-sized icons"));
200 normalIcons->setCheckable(true);
201 QObject::connect(normalIcons, SIGNAL(triggered()),
202 parent, SLOT(normalSizedIcons()));
203 menu->addAction(normalIcons);
205 QAction * bigIcons = new QAction(iconSizeGroup);
206 bigIcons->setText(qt_("Big-sized icons"));
207 bigIcons->setCheckable(true);
208 QObject::connect(bigIcons, SIGNAL(triggered()),
209 parent, SLOT(bigSizedIcons()));
210 menu->addAction(bigIcons);
212 unsigned int cur = parent->iconSize().width();
213 if ( cur == parent->d.smallIconSize)
214 smallIcons->setChecked(true);
215 else if (cur == parent->d.normalIconSize)
216 normalIcons->setChecked(true);
217 else if (cur == parent->d.bigIconSize)
218 bigIcons->setChecked(true);
225 stack_widget_->setCurrentWidget(bg_widget_);
226 bg_widget_->setUpdatesEnabled(true);
229 TabWorkArea * tabWorkArea(int i)
231 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
234 TabWorkArea * currentTabWorkArea()
236 if (splitter_->count() == 1)
237 // The first TabWorkArea is always the first one, if any.
238 return tabWorkArea(0);
240 for (int i = 0; i != splitter_->count(); ++i) {
241 TabWorkArea * twa = tabWorkArea(i);
242 if (current_main_work_area_ == twa->currentWorkArea())
246 // None has the focus so we just take the first one.
247 return tabWorkArea(0);
251 GuiWorkArea * current_work_area_;
252 GuiWorkArea * current_main_work_area_;
253 QSplitter * splitter_;
254 QStackedWidget * stack_widget_;
255 BackgroundWidget * bg_widget_;
257 ToolbarMap toolbars_;
258 /// The main layout box.
260 * \warning Don't Delete! The layout box is actually owned by
261 * whichever toolbar contains it. All the GuiView class needs is a
262 * means of accessing it.
264 * FIXME: replace that with a proper model so that we are not limited
265 * to only one dialog.
267 GuiLayoutBox * layout_;
270 map<string, Inset *> open_insets_;
273 map<string, DialogPtr> dialogs_;
275 unsigned int smallIconSize;
276 unsigned int normalIconSize;
277 unsigned int bigIconSize;
279 QTimer statusbar_timer_;
280 /// auto-saving of buffers
281 Timeout autosave_timeout_;
282 /// flag against a race condition due to multiclicks, see bug #1119
286 TocModels toc_models_;
290 GuiView::GuiView(int id)
291 : d(*new GuiViewPrivate), id_(id), closing_(false)
293 // GuiToolbars *must* be initialised before the menu bar.
294 normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge
297 // set ourself as the current view. This is needed for the menu bar
298 // filling, at least for the static special menu item on Mac. Otherwise
299 // they are greyed out.
300 theLyXFunc().setLyXView(this);
302 // Fill up the menu bar.
303 guiApp->menus().fillMenuBar(menuBar(), this, true);
305 setCentralWidget(d.stack_widget_);
307 // Start autosave timer
308 if (lyxrc.autosave) {
309 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
310 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
311 d.autosave_timeout_.start();
313 connect(&d.statusbar_timer_, SIGNAL(timeout()),
314 this, SLOT(clearMessage()));
316 // We don't want to keep the window in memory if it is closed.
317 setAttribute(Qt::WA_DeleteOnClose, true);
319 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
320 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
321 // since the icon is provided in the application bundle.
322 setWindowIcon(getPixmap("images/", "lyx", "png"));
326 setAcceptDrops(true);
328 statusBar()->setSizeGripEnabled(true);
330 // Forbid too small unresizable window because it can happen
331 // with some window manager under X11.
332 setMinimumSize(300, 200);
334 if (lyxrc.allow_geometry_session) {
335 // Now take care of session management.
340 // no session handling, default to a sane size.
341 setGeometry(50, 50, 690, 510);
344 // clear session data if any.
346 settings.remove("views");
356 void GuiView::saveLayout() const
359 settings.beginGroup("views");
360 settings.beginGroup(QString::number(id_));
362 settings.setValue("pos", pos());
363 settings.setValue("size", size());
365 settings.setValue("geometry", saveGeometry());
367 settings.setValue("layout", saveState(0));
368 settings.setValue("icon_size", iconSize());
372 bool GuiView::restoreLayout()
375 settings.beginGroup("views");
376 settings.beginGroup(QString::number(id_));
377 QString const icon_key = "icon_size";
378 if (!settings.contains(icon_key))
381 //code below is skipped when when ~/.config/LyX is (re)created
382 setIconSize(settings.value(icon_key).toSize());
384 QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
385 QSize size = settings.value("size", QSize(690, 510)).toSize();
389 if (!restoreGeometry(settings.value("geometry").toByteArray()))
390 setGeometry(50, 50, 690, 510);
392 // Make sure layout is correctly oriented.
393 setLayoutDirection(qApp->layoutDirection());
395 // Allow the toc and view-source dock widget to be restored if needed.
397 if ((dialog = findOrBuild("toc", true)))
398 // see bug 5082. At least setup title and enabled state.
399 // Visibility will be adjusted by restoreState below.
400 dialog->prepareView();
401 if ((dialog = findOrBuild("view-source", true)))
402 dialog->prepareView();
404 if (!restoreState(settings.value("layout").toByteArray(), 0))
411 GuiToolbar * GuiView::toolbar(string const & name)
413 ToolbarMap::iterator it = d.toolbars_.find(name);
414 if (it != d.toolbars_.end())
417 LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
418 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
423 void GuiView::constructToolbars()
425 ToolbarMap::iterator it = d.toolbars_.begin();
426 for (; it != d.toolbars_.end(); ++it)
431 // extracts the toolbars from the backend
432 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
433 Toolbars::Infos::iterator end = guiApp->toolbars().end();
434 for (; cit != end; ++cit)
435 d.toolbars_[cit->name] = new GuiToolbar(*cit, *this);
439 void GuiView::initToolbars()
441 // extracts the toolbars from the backend
442 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
443 Toolbars::Infos::iterator end = guiApp->toolbars().end();
444 for (; cit != end; ++cit) {
445 GuiToolbar * tb = toolbar(cit->name);
448 int const visibility = guiApp->toolbars().defaultVisibility(cit->name);
450 tb->setVisible(false);
451 tb->setVisibility(visibility);
453 if (visibility & Toolbars::TOP) {
455 addToolBarBreak(Qt::TopToolBarArea);
456 addToolBar(Qt::TopToolBarArea, tb);
459 if (visibility & Toolbars::BOTTOM) {
460 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
461 #if (QT_VERSION >= 0x040202)
462 addToolBarBreak(Qt::BottomToolBarArea);
464 addToolBar(Qt::BottomToolBarArea, tb);
467 if (visibility & Toolbars::LEFT) {
468 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
469 #if (QT_VERSION >= 0x040202)
470 addToolBarBreak(Qt::LeftToolBarArea);
472 addToolBar(Qt::LeftToolBarArea, tb);
475 if (visibility & Toolbars::RIGHT) {
476 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
477 #if (QT_VERSION >= 0x040202)
478 addToolBarBreak(Qt::RightToolBarArea);
480 addToolBar(Qt::RightToolBarArea, tb);
483 if (visibility & Toolbars::ON)
484 tb->setVisible(true);
489 TocModels & GuiView::tocModels()
491 return d.toc_models_;
495 void GuiView::setFocus()
497 LYXERR(Debug::DEBUG, "GuiView::setFocus()" << this);
498 // Make sure LyXFunc points to the correct view.
499 guiApp->setCurrentView(this);
500 theLyXFunc().setLyXView(this);
501 QMainWindow::setFocus();
502 if (d.current_work_area_)
503 d.current_work_area_->setFocus();
507 QMenu * GuiView::createPopupMenu()
509 return d.toolBarPopup(this);
513 void GuiView::showEvent(QShowEvent * e)
515 LYXERR(Debug::GUI, "Passed Geometry "
516 << size().height() << "x" << size().width()
517 << "+" << pos().x() << "+" << pos().y());
519 if (d.splitter_->count() == 0)
520 // No work area, switch to the background widget.
523 QMainWindow::showEvent(e);
527 /** Destroy only all tabbed WorkAreas. Destruction of other WorkAreas
528 ** is responsibility of the container (e.g., dialog)
530 void GuiView::closeEvent(QCloseEvent * close_event)
532 LYXERR(Debug::DEBUG, "GuiView::closeEvent()");
535 // it can happen that this event arrives without selecting the view,
536 // e.g. when clicking the close button on a background window.
538 GuiWorkArea * active_wa = currentMainWorkArea();
539 setCurrentWorkArea(active_wa);
541 // We might be in a situation that there is still a tabWorkArea, but
542 // there are no tabs anymore. This can happen when we get here after a
543 // TabWorkArea::lastWorkAreaRemoved() signal. Therefore we count how
544 // many TabWorkArea's have no documents anymore.
547 // We have to call count() each time, because it can happen that
548 // more than one splitter will disappear in one iteration (bug 5998).
549 for (; d.splitter_->count() > empty_twa; ) {
550 TabWorkArea * twa = d.tabWorkArea(empty_twa);
552 int twa_count = twa->count();
553 if (twa->count() == 0)
556 for (; twa_count; --twa_count) {
557 twa->setCurrentIndex(twa_count-1);
559 GuiWorkArea * wa = twa->currentWorkArea();
560 bool const is_active_wa = active_wa == wa;
561 Buffer * b = &wa->bufferView().buffer();
563 // This is a child document, just close the tab
564 // after saving but keep the file loaded.
565 if (!closeBuffer(*b, true, is_active_wa)) {
567 close_event->ignore();
573 vector<Buffer *> clist = b->getChildren();
574 for (vector<Buffer *>::const_iterator it = clist.begin();
575 it != clist.end(); ++it) {
576 if ((*it)->isClean())
579 // If a child is dirty, do not close
580 // without user intervention
581 if (!closeBuffer(*c, false)) {
583 close_event->ignore();
588 QList<int> const ids = guiApp->viewIds();
589 for (int i = 0; i != ids.size(); ++i) {
592 if (guiApp->view(ids[i]).workArea(*b)) {
593 // FIXME 1: should we put an alert box here
594 // that the buffer is viewed elsewhere?
595 // FIXME 2: should we try to save this buffer in any case?
598 // This buffer is also opened in another view, so
599 // close the associated work area...
601 // ... but don't close the buffer.
606 // closeBuffer() needs buffer workArea still alive and
607 // set as currrent one, and destroys it
608 if (b && !closeBuffer(*b, true, is_active_wa)) {
610 close_event->ignore();
615 // Make sure that nothing will use this close to be closed View.
616 guiApp->unregisterView(this);
618 if (isFullScreen()) {
619 // Switch off fullscreen before closing.
624 // Make sure the timer time out will not trigger a statusbar update.
625 d.statusbar_timer_.stop();
627 // Saving fullscreen requires additional tweaks in the toolbar code.
628 // It wouldn't also work under linux natively.
629 if (lyxrc.allow_geometry_session) {
630 // Save this window geometry and layout.
632 // Then the toolbar private states.
633 ToolbarMap::iterator end = d.toolbars_.end();
634 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
635 it->second->saveSession();
636 // Now take care of all other dialogs:
637 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
638 for (; it!= d.dialogs_.end(); ++it)
639 it->second->saveSession();
642 close_event->accept();
646 void GuiView::dragEnterEvent(QDragEnterEvent * event)
648 if (event->mimeData()->hasUrls())
650 /// \todo Ask lyx-devel is this is enough:
651 /// if (event->mimeData()->hasFormat("text/plain"))
652 /// event->acceptProposedAction();
656 void GuiView::dropEvent(QDropEvent * event)
658 QList<QUrl> files = event->mimeData()->urls();
662 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
663 for (int i = 0; i != files.size(); ++i) {
664 string const file = os::internal_path(fromqstr(
665 files.at(i).toLocalFile()));
667 // Asynchronously post the event. DropEvent usually come
668 // from the BufferView. But reloading a file might close
669 // the BufferView from within its own event handler.
670 guiApp->dispatchDelayed(FuncRequest(LFUN_FILE_OPEN, file));
677 void GuiView::message(docstring const & str)
679 if (ForkedProcess::iAmAChild())
682 statusBar()->showMessage(toqstr(str));
683 d.statusbar_timer_.stop();
684 d.statusbar_timer_.start(3000);
688 void GuiView::smallSizedIcons()
690 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
694 void GuiView::normalSizedIcons()
696 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
700 void GuiView::bigSizedIcons()
702 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
706 void GuiView::clearMessage()
710 theLyXFunc().setLyXView(this);
711 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
712 d.statusbar_timer_.stop();
716 void GuiView::updateWindowTitle(GuiWorkArea * wa)
718 if (wa != d.current_work_area_)
720 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
721 setWindowIconText(wa->windowIconText());
725 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
728 disconnectBufferView();
729 connectBufferView(wa->bufferView());
730 connectBuffer(wa->bufferView().buffer());
731 d.current_work_area_ = wa;
732 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
733 this, SLOT(updateWindowTitle(GuiWorkArea *)));
734 updateWindowTitle(wa);
738 // The document settings needs to be reinitialised.
739 updateDialog("document", "");
741 // Buffer-dependent dialogs must be updated. This is done here because
742 // some dialogs require buffer()->text.
747 void GuiView::on_lastWorkAreaRemoved()
750 // We already are in a close event. Nothing more to do.
753 if (d.splitter_->count() > 1)
754 // We have a splitter so don't close anything.
757 // Reset and updates the dialogs.
758 d.toc_models_.reset(0);
759 updateDialog("document", "");
762 resetWindowTitleAndIconText();
764 if (lyxrc.open_buffers_in_tabs)
765 // Nothing more to do, the window should stay open.
768 if (guiApp->viewIds().size() > 1) {
774 // On Mac we also close the last window because the application stay
775 // resident in memory. On other platforms we don't close the last
776 // window because this would quit the application.
782 void GuiView::updateStatusBar()
784 // let the user see the explicit message
785 if (d.statusbar_timer_.isActive())
788 theLyXFunc().setLyXView(this);
789 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
793 bool GuiView::hasFocus() const
795 return qApp->activeWindow() == this;
799 bool GuiView::event(QEvent * e)
803 // Useful debug code:
804 //case QEvent::ActivationChange:
805 //case QEvent::WindowDeactivate:
806 //case QEvent::Paint:
807 //case QEvent::Enter:
808 //case QEvent::Leave:
809 //case QEvent::HoverEnter:
810 //case QEvent::HoverLeave:
811 //case QEvent::HoverMove:
812 //case QEvent::StatusTip:
813 //case QEvent::DragEnter:
814 //case QEvent::DragLeave:
818 case QEvent::WindowActivate: {
819 if (this == guiApp->currentView()) {
821 return QMainWindow::event(e);
823 guiApp->setCurrentView(this);
824 theLyXFunc().setLyXView(this);
825 if (d.current_work_area_) {
826 BufferView & bv = d.current_work_area_->bufferView();
827 connectBufferView(bv);
828 connectBuffer(bv.buffer());
829 // The document structure, name and dialogs might have
830 // changed in another view.
832 // The document settings needs to be reinitialised.
833 updateDialog("document", "");
836 resetWindowTitleAndIconText();
839 return QMainWindow::event(e);
842 case QEvent::ShortcutOverride: {
845 #if (!defined Q_WS_X11) || (QT_VERSION >= 0x040500)
846 if (isFullScreen() && menuBar()->isHidden()) {
847 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
848 // FIXME: we should also try to detect special LyX shortcut such as
849 // Alt-P and Alt-M. Right now there is a hack in
850 // GuiWorkArea::processKeySym() that hides again the menubar for
852 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt) {
854 return QMainWindow::event(e);
859 if (d.current_work_area_)
860 // Nothing special to do.
861 return QMainWindow::event(e);
863 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
864 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
866 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
867 || ke->key() == Qt::Key_Backtab)
868 return QMainWindow::event(e);
870 // Allow processing of shortcuts that are allowed even when no Buffer
872 theLyXFunc().setLyXView(this);
874 setKeySymbol(&sym, ke);
875 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
881 return QMainWindow::event(e);
885 void GuiView::resetWindowTitleAndIconText()
887 setWindowTitle(qt_("LyX"));
888 setWindowIconText(qt_("LyX"));
891 bool GuiView::focusNextPrevChild(bool /*next*/)
898 void GuiView::setBusy(bool busy)
900 if (d.current_work_area_) {
901 d.current_work_area_->setUpdatesEnabled(!busy);
903 d.current_work_area_->stopBlinkingCursor();
905 d.current_work_area_->startBlinkingCursor();
909 QApplication::setOverrideCursor(Qt::WaitCursor);
911 QApplication::restoreOverrideCursor();
915 GuiWorkArea * GuiView::workArea(Buffer & buffer)
917 if (currentWorkArea()
918 && ¤tWorkArea()->bufferView().buffer() == &buffer)
919 return (GuiWorkArea *) currentWorkArea();
920 if (TabWorkArea * twa = d.currentTabWorkArea())
921 return twa->workArea(buffer);
926 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
928 // Automatically create a TabWorkArea if there are none yet.
929 TabWorkArea * tab_widget = d.splitter_->count()
930 ? d.currentTabWorkArea() : addTabWorkArea();
931 return tab_widget->addWorkArea(buffer, *this);
935 TabWorkArea * GuiView::addTabWorkArea()
937 TabWorkArea * twa = new TabWorkArea;
938 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
939 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
940 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
941 this, SLOT(on_lastWorkAreaRemoved()));
943 d.splitter_->addWidget(twa);
944 d.stack_widget_->setCurrentWidget(d.splitter_);
949 GuiWorkArea const * GuiView::currentWorkArea() const
951 return d.current_work_area_;
955 GuiWorkArea * GuiView::currentWorkArea()
957 return d.current_work_area_;
961 GuiWorkArea const * GuiView::currentMainWorkArea() const
963 if (d.currentTabWorkArea() == NULL)
965 return d.currentTabWorkArea()->currentWorkArea();
969 GuiWorkArea * GuiView::currentMainWorkArea()
971 if (d.currentTabWorkArea() == NULL)
973 return d.currentTabWorkArea()->currentWorkArea();
977 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
979 LYXERR(Debug::DEBUG, "Setting current wa: " << wa << endl);
981 d.current_work_area_ = NULL;
985 GuiWorkArea * old_gwa = theGuiApp()->currentView()->currentWorkArea();
989 theGuiApp()->setCurrentView(this);
990 d.current_work_area_ = wa;
991 for (int i = 0; i != d.splitter_->count(); ++i) {
992 if (d.tabWorkArea(i)->setCurrentWorkArea(wa)) {
993 //if (d.current_main_work_area_)
994 // d.current_main_work_area_->setFrameStyle(QFrame::NoFrame);
995 d.current_main_work_area_ = wa;
996 //d.current_main_work_area_->setFrameStyle(QFrame::Box | QFrame::Plain);
997 //d.current_main_work_area_->setLineWidth(2);
998 LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
1002 LYXERR(Debug::DEBUG, "This is not a tabbed wa");
1003 on_currentWorkAreaChanged(wa);
1004 BufferView & bv = wa->bufferView();
1005 bv.cursor().fixIfBroken();
1007 wa->setUpdatesEnabled(true);
1008 LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
1012 void GuiView::removeWorkArea(GuiWorkArea * wa)
1014 LASSERT(wa, return);
1015 if (wa == d.current_work_area_) {
1017 disconnectBufferView();
1018 d.current_work_area_ = 0;
1019 d.current_main_work_area_ = 0;
1022 bool found_twa = false;
1023 for (int i = 0; i != d.splitter_->count(); ++i) {
1024 TabWorkArea * twa = d.tabWorkArea(i);
1025 if (twa->removeWorkArea(wa)) {
1026 // Found in this tab group, and deleted the GuiWorkArea.
1028 if (twa->count() != 0) {
1029 if (d.current_work_area_ == 0)
1030 // This means that we are closing the current GuiWorkArea, so
1031 // switch to the next GuiWorkArea in the found TabWorkArea.
1032 setCurrentWorkArea(twa->currentWorkArea());
1034 // No more WorkAreas in this tab group, so delete it.
1041 // It is not a tabbed work area (i.e., the search work area), so it
1042 // should be deleted by other means.
1043 LASSERT(found_twa, /* */);
1045 if (d.current_work_area_ == 0) {
1046 if (d.splitter_->count() != 0) {
1047 TabWorkArea * twa = d.currentTabWorkArea();
1048 setCurrentWorkArea(twa->currentWorkArea());
1050 // No more work areas, switch to the background widget.
1051 setCurrentWorkArea(0);
1057 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
1063 void GuiView::updateLayoutList()
1066 d.layout_->updateContents(false);
1070 void GuiView::updateToolbars()
1072 ToolbarMap::iterator end = d.toolbars_.end();
1073 if (d.current_work_area_) {
1075 d.current_work_area_->bufferView().cursor().inMathed();
1077 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
1079 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
1080 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
1081 bool const mathmacrotemplate =
1082 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
1084 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1085 it->second->update(math, table, review, mathmacrotemplate);
1087 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1088 it->second->update(false, false, false, false);
1092 Buffer * GuiView::buffer()
1094 if (d.current_work_area_)
1095 return &d.current_work_area_->bufferView().buffer();
1100 Buffer const * GuiView::buffer() const
1102 if (d.current_work_area_)
1103 return &d.current_work_area_->bufferView().buffer();
1108 void GuiView::setBuffer(Buffer * newBuffer)
1110 LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << std::endl);
1111 LASSERT(newBuffer, return);
1114 GuiWorkArea * wa = workArea(*newBuffer);
1116 newBuffer->masterBuffer()->updateLabels();
1117 wa = addWorkArea(*newBuffer);
1119 //Disconnect the old buffer...there's no new one.
1122 connectBuffer(*newBuffer);
1123 connectBufferView(wa->bufferView());
1124 setCurrentWorkArea(wa);
1130 void GuiView::connectBuffer(Buffer & buf)
1132 buf.setGuiDelegate(this);
1136 void GuiView::disconnectBuffer()
1138 if (d.current_work_area_)
1139 d.current_work_area_->bufferView().setGuiDelegate(0);
1143 void GuiView::connectBufferView(BufferView & bv)
1145 bv.setGuiDelegate(this);
1149 void GuiView::disconnectBufferView()
1151 if (d.current_work_area_)
1152 d.current_work_area_->bufferView().setGuiDelegate(0);
1156 void GuiView::errors(string const & error_type, bool from_master)
1158 ErrorList & el = from_master ?
1159 buffer()->masterBuffer()->errorList(error_type)
1160 : buffer()->errorList(error_type);
1161 string data = error_type;
1163 data = "from_master|" + error_type;
1165 showDialog("errorlist", data);
1169 void GuiView::updateTocItem(std::string const & type, DocIterator const & dit)
1171 d.toc_models_.updateItem(toqstr(type), dit);
1175 void GuiView::structureChanged()
1177 d.toc_models_.reset(view());
1178 // Navigator needs more than a simple update in this case. It needs to be
1180 updateDialog("toc", "");
1184 void GuiView::updateDialog(string const & name, string const & data)
1186 if (!isDialogVisible(name))
1189 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1190 if (it == d.dialogs_.end())
1193 Dialog * const dialog = it->second.get();
1194 if (dialog->isVisibleView())
1195 dialog->initialiseParams(data);
1199 BufferView * GuiView::view()
1201 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1205 void GuiView::autoSave()
1207 LYXERR(Debug::INFO, "Running autoSave()");
1210 view()->buffer().autoSave();
1214 void GuiView::resetAutosaveTimers()
1217 d.autosave_timeout_.restart();
1221 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1224 Buffer * buf = buffer();
1226 /* In LyX/Mac, when a dialog is open, the menus of the
1227 application can still be accessed without giving focus to
1228 the main window. In this case, we want to disable the menu
1229 entries that are buffer-related.
1231 Note that this code is not perfect, as bug 1941 attests:
1232 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1234 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1237 if (cmd.origin == FuncRequest::TOC) {
1238 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
1240 if (toc->getStatus(view()->cursor(), cmd, fs))
1243 flag.setEnabled(false);
1247 switch(cmd.action) {
1248 case LFUN_BUFFER_WRITE:
1249 enable = buf && (buf->isUnnamed() || !buf->isClean());
1252 case LFUN_BUFFER_WRITE_AS:
1256 case LFUN_SPLIT_VIEW:
1257 if (cmd.getArg(0) == "vertical")
1258 enable = buf && (d.splitter_->count() == 1 ||
1259 d.splitter_->orientation() == Qt::Vertical);
1261 enable = buf && (d.splitter_->count() == 1 ||
1262 d.splitter_->orientation() == Qt::Horizontal);
1265 case LFUN_CLOSE_TAB_GROUP:
1266 enable = d.currentTabWorkArea();
1269 case LFUN_TOOLBAR_TOGGLE:
1270 if (GuiToolbar * t = toolbar(cmd.getArg(0)))
1271 flag.setOnOff(t->isVisible());
1274 case LFUN_UI_TOGGLE:
1275 flag.setOnOff(isFullScreen());
1278 case LFUN_DIALOG_TOGGLE:
1279 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1280 // fall through to set "enable"
1281 case LFUN_DIALOG_SHOW: {
1282 string const name = cmd.getArg(0);
1284 enable = name == "aboutlyx"
1285 || name == "file" //FIXME: should be removed.
1287 || name == "texinfo";
1288 else if (name == "print")
1289 enable = buf->isExportable("dvi")
1290 && lyxrc.print_command != "none";
1291 else if (name == "character") {
1295 InsetCode ic = view()->cursor().inset().lyxCode();
1296 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1299 else if (name == "symbols") {
1300 if (!view() || view()->cursor().inMathed())
1303 InsetCode ic = view()->cursor().inset().lyxCode();
1304 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1307 else if (name == "latexlog")
1308 enable = FileName(buf->logName()).isReadableFile();
1309 else if (name == "spellchecker")
1310 #if defined (USE_ASPELL)
1311 enable = !buf->isReadonly();
1315 else if (name == "vclog")
1316 enable = buf->lyxvc().inUse();
1320 case LFUN_DIALOG_UPDATE: {
1321 string const name = cmd.getArg(0);
1323 enable = name == "prefs";
1327 case LFUN_INSET_APPLY: {
1328 string const name = cmd.getArg(0);
1329 Inset * inset = getOpenInset(name);
1331 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1333 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1334 // Every inset is supposed to handle this
1335 LASSERT(false, break);
1339 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1340 flag |= lyx::getStatus(fr);
1342 enable = flag.enabled();
1346 case LFUN_COMPLETION_INLINE:
1347 if (!d.current_work_area_
1348 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1352 case LFUN_COMPLETION_POPUP:
1353 if (!d.current_work_area_
1354 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1358 case LFUN_COMPLETION_COMPLETE:
1359 if (!d.current_work_area_
1360 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1364 case LFUN_COMPLETION_ACCEPT:
1365 if (!d.current_work_area_
1366 || (!d.current_work_area_->completer().popupVisible()
1367 && !d.current_work_area_->completer().inlineVisible()
1368 && !d.current_work_area_->completer().completionAvailable()))
1372 case LFUN_COMPLETION_CANCEL:
1373 if (!d.current_work_area_
1374 || (!d.current_work_area_->completer().popupVisible()
1375 && !d.current_work_area_->completer().inlineVisible()))
1379 case LFUN_BUFFER_ZOOM_OUT:
1380 enable = buf && lyxrc.zoom > 10;
1383 case LFUN_BUFFER_ZOOM_IN:
1392 flag.setEnabled(false);
1398 static FileName selectTemplateFile()
1400 FileDialog dlg(qt_("Select template file"));
1401 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1402 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1404 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1405 QStringList(qt_("LyX Documents (*.lyx)")));
1407 if (result.first == FileDialog::Later)
1409 if (result.second.isEmpty())
1411 return FileName(fromqstr(result.second));
1415 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1419 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1422 message(_("Document not loaded."));
1427 setBuffer(newBuffer);
1429 // scroll to the position when the file was last closed
1430 if (lyxrc.use_lastfilepos) {
1431 LastFilePosSection::FilePos filepos =
1432 theSession().lastFilePos().load(filename);
1433 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1437 theSession().lastFiles().add(filename);
1444 void GuiView::openDocument(string const & fname)
1446 string initpath = lyxrc.document_path;
1449 string const trypath = buffer()->filePath();
1450 // If directory is writeable, use this as default.
1451 if (FileName(trypath).isDirWritable())
1457 if (fname.empty()) {
1458 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1459 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1460 dlg.setButton2(qt_("Examples|#E#e"),
1461 toqstr(addPath(package().system_support().absFilename(), "examples")));
1463 QStringList filter(qt_("LyX Documents (*.lyx)"));
1464 filter << qt_("LyX-1.3.x Documents (*.lyx13)")
1465 << qt_("LyX-1.4.x Documents (*.lyx14)")
1466 << qt_("LyX-1.5.x Documents (*.lyx15)")
1467 << qt_("LyX-1.6.x Documents (*.lyx16)");
1468 FileDialog::Result result =
1469 dlg.open(toqstr(initpath), filter);
1471 if (result.first == FileDialog::Later)
1474 filename = fromqstr(result.second);
1476 // check selected filename
1477 if (filename.empty()) {
1478 message(_("Canceled."));
1484 // get absolute path of file and add ".lyx" to the filename if
1486 FileName const fullname =
1487 fileSearch(string(), filename, "lyx", support::may_not_exist);
1488 if (!fullname.empty())
1489 filename = fullname.absFilename();
1491 if (!fullname.onlyPath().isDirectory()) {
1492 Alert::warning(_("Invalid filename"),
1493 bformat(_("The directory in the given path\n%1$s\ndoes not exist."),
1494 from_utf8(fullname.absFilename())));
1497 // if the file doesn't exist, let the user create one
1498 if (!fullname.exists()) {
1499 // the user specifically chose this name. Believe him.
1500 Buffer * const b = newFile(filename, string(), true);
1506 docstring const disp_fn = makeDisplayPath(filename);
1507 message(bformat(_("Opening document %1$s..."), disp_fn));
1510 Buffer * buf = loadDocument(fullname);
1512 buf->updateLabels();
1514 buf->errors("Parse");
1515 str2 = bformat(_("Document %1$s opened."), disp_fn);
1516 if (buf->lyxvc().inUse())
1517 str2 += " " + from_utf8(buf->lyxvc().versionString()) +
1518 " " + _("Version control detected.");
1520 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1525 // FIXME: clean that
1526 static bool import(GuiView * lv, FileName const & filename,
1527 string const & format, ErrorList & errorList)
1529 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1531 string loader_format;
1532 vector<string> loaders = theConverters().loaders();
1533 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1534 for (vector<string>::const_iterator it = loaders.begin();
1535 it != loaders.end(); ++it) {
1536 if (!theConverters().isReachable(format, *it))
1539 string const tofile =
1540 support::changeExtension(filename.absFilename(),
1541 formats.extension(*it));
1542 if (!theConverters().convert(0, filename, FileName(tofile),
1543 filename, format, *it, errorList))
1545 loader_format = *it;
1548 if (loader_format.empty()) {
1549 frontend::Alert::error(_("Couldn't import file"),
1550 bformat(_("No information for importing the format %1$s."),
1551 formats.prettyName(format)));
1555 loader_format = format;
1557 if (loader_format == "lyx") {
1558 Buffer * buf = lv->loadDocument(lyxfile);
1561 buf->updateLabels();
1563 buf->errors("Parse");
1565 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1569 bool as_paragraphs = loader_format == "textparagraph";
1570 string filename2 = (loader_format == format) ? filename.absFilename()
1571 : support::changeExtension(filename.absFilename(),
1572 formats.extension(loader_format));
1573 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1574 theLyXFunc().setLyXView(lv);
1575 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1582 void GuiView::importDocument(string const & argument)
1585 string filename = split(argument, format, ' ');
1587 LYXERR(Debug::INFO, format << " file: " << filename);
1589 // need user interaction
1590 if (filename.empty()) {
1591 string initpath = lyxrc.document_path;
1593 Buffer const * buf = buffer();
1595 string const trypath = buf->filePath();
1596 // If directory is writeable, use this as default.
1597 if (FileName(trypath).isDirWritable())
1601 docstring const text = bformat(_("Select %1$s file to import"),
1602 formats.prettyName(format));
1604 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1605 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1606 dlg.setButton2(qt_("Examples|#E#e"),
1607 toqstr(addPath(package().system_support().absFilename(), "examples")));
1609 docstring filter = formats.prettyName(format);
1612 filter += from_utf8(formats.extension(format));
1615 FileDialog::Result result =
1616 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1618 if (result.first == FileDialog::Later)
1621 filename = fromqstr(result.second);
1623 // check selected filename
1624 if (filename.empty())
1625 message(_("Canceled."));
1628 if (filename.empty())
1631 // get absolute path of file
1632 FileName const fullname(support::makeAbsPath(filename));
1634 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1636 // Check if the document already is open
1637 Buffer * buf = theBufferList().getBuffer(lyxfile);
1640 if (!closeBuffer()) {
1641 message(_("Canceled."));
1646 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1648 // if the file exists already, and we didn't do
1649 // -i lyx thefile.lyx, warn
1650 if (lyxfile.exists() && fullname != lyxfile) {
1652 docstring text = bformat(_("The document %1$s already exists.\n\n"
1653 "Do you want to overwrite that document?"), displaypath);
1654 int const ret = Alert::prompt(_("Overwrite document?"),
1655 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1658 message(_("Canceled."));
1663 message(bformat(_("Importing %1$s..."), displaypath));
1664 ErrorList errorList;
1665 if (import(this, fullname, format, errorList))
1666 message(_("imported."));
1668 message(_("file not imported!"));
1670 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1674 void GuiView::newDocument(string const & filename, bool from_template)
1676 FileName initpath(lyxrc.document_path);
1677 Buffer * buf = buffer();
1679 FileName const trypath(buf->filePath());
1680 // If directory is writeable, use this as default.
1681 if (trypath.isDirWritable())
1685 string templatefile;
1686 if (from_template) {
1687 templatefile = selectTemplateFile().absFilename();
1688 if (templatefile.empty())
1693 if (filename.empty())
1694 b = newUnnamedFile(templatefile, initpath);
1696 b = newFile(filename, templatefile, true);
1701 // If no new document could be created, it is unsure
1702 // whether there is a valid BufferView.
1704 // Ensure the cursor is correctly positioned on screen.
1705 view()->showCursor();
1709 void GuiView::insertLyXFile(docstring const & fname)
1711 BufferView * bv = view();
1716 FileName filename(to_utf8(fname));
1718 if (!filename.empty()) {
1719 bv->insertLyXFile(filename);
1723 // Launch a file browser
1725 string initpath = lyxrc.document_path;
1726 string const trypath = bv->buffer().filePath();
1727 // If directory is writeable, use this as default.
1728 if (FileName(trypath).isDirWritable())
1732 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1733 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1734 dlg.setButton2(qt_("Examples|#E#e"),
1735 toqstr(addPath(package().system_support().absFilename(),
1738 FileDialog::Result result = dlg.open(toqstr(initpath),
1739 QStringList(qt_("LyX Documents (*.lyx)")));
1741 if (result.first == FileDialog::Later)
1745 filename.set(fromqstr(result.second));
1747 // check selected filename
1748 if (filename.empty()) {
1749 // emit message signal.
1750 message(_("Canceled."));
1754 bv->insertLyXFile(filename);
1758 void GuiView::insertPlaintextFile(docstring const & fname,
1761 BufferView * bv = view();
1765 if (!fname.empty() && !FileName::isAbsolute(to_utf8(fname))) {
1766 message(_("Absolute filename expected."));
1771 FileName filename(to_utf8(fname));
1773 if (!filename.empty()) {
1774 bv->insertPlaintextFile(filename, asParagraph);
1778 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1779 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1781 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1782 QStringList(qt_("All Files (*)")));
1784 if (result.first == FileDialog::Later)
1788 filename.set(fromqstr(result.second));
1790 // check selected filename
1791 if (filename.empty()) {
1792 // emit message signal.
1793 message(_("Canceled."));
1797 bv->insertPlaintextFile(filename, asParagraph);
1801 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1803 FileName fname = b.fileName();
1804 FileName const oldname = fname;
1806 if (!newname.empty()) {
1808 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1810 // Switch to this Buffer.
1813 // No argument? Ask user through dialog.
1815 FileDialog dlg(qt_("Choose a filename to save document as"),
1816 LFUN_BUFFER_WRITE_AS);
1817 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1818 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1820 if (!isLyXFilename(fname.absFilename()))
1821 fname.changeExtension(".lyx");
1823 FileDialog::Result result =
1824 dlg.save(toqstr(fname.onlyPath().absFilename()),
1825 QStringList(qt_("LyX Documents (*.lyx)")),
1826 toqstr(fname.onlyFileName()));
1828 if (result.first == FileDialog::Later)
1831 fname.set(fromqstr(result.second));
1836 if (!isLyXFilename(fname.absFilename()))
1837 fname.changeExtension(".lyx");
1840 if (FileName(fname).exists()) {
1841 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1842 docstring text = bformat(_("The document %1$s already "
1843 "exists.\n\nDo you want to "
1844 "overwrite that document?"),
1846 int const ret = Alert::prompt(_("Overwrite document?"),
1847 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1850 case 1: return renameBuffer(b, docstring());
1851 case 2: return false;
1855 FileName oldauto = b.getAutosaveFilename();
1857 // Ok, change the name of the buffer
1858 b.setFileName(fname.absFilename());
1860 bool unnamed = b.isUnnamed();
1861 b.setUnnamed(false);
1862 b.saveCheckSum(fname);
1864 // bring the autosave file with us, just in case.
1865 b.moveAutosaveFile(oldauto);
1867 if (!saveBuffer(b)) {
1868 oldauto = b.getAutosaveFilename();
1869 b.setFileName(oldname.absFilename());
1870 b.setUnnamed(unnamed);
1871 b.saveCheckSum(oldname);
1872 b.moveAutosaveFile(oldauto);
1880 bool GuiView::saveBuffer(Buffer & b)
1882 if (workArea(b) && workArea(b)->inDialogMode())
1886 return renameBuffer(b, docstring());
1889 theSession().lastFiles().add(b.fileName());
1893 // Switch to this Buffer.
1896 // FIXME: we don't tell the user *WHY* the save failed !!
1897 docstring const file = makeDisplayPath(b.absFileName(), 30);
1898 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1899 "Do you want to rename the document and "
1900 "try again?"), file);
1901 int const ret = Alert::prompt(_("Rename and save?"),
1902 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1905 if (!renameBuffer(b, docstring()))
1914 return saveBuffer(b);
1918 bool GuiView::closeBuffer()
1920 Buffer * buf = buffer();
1921 return buf && closeBuffer(*buf);
1925 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened, bool mark_active)
1927 // goto bookmark to update bookmark pit.
1928 //FIXME: we should update only the bookmarks related to this buffer!
1929 LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
1930 for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
1931 theLyXFunc().gotoBookmark(i+1, false, false);
1933 if (buf.isClean() || buf.paragraphs().empty()) {
1934 // save in sessions if requested
1935 // do not save childs if their master
1936 // is opened as well
1938 theSession().lastOpened().add(buf.fileName(), mark_active);
1940 // Don't close child documents.
1941 removeWorkArea(currentMainWorkArea());
1943 theBufferList().release(&buf);
1946 // Switch to this Buffer.
1951 if (buf.isUnnamed())
1952 file = from_utf8(buf.fileName().onlyFileName());
1954 file = buf.fileName().displayName(30);
1956 // Bring this window to top before asking questions.
1960 docstring const text = bformat(_("The document %1$s has unsaved changes."
1961 "\n\nDo you want to save the document or discard the changes?"), file);
1962 int const ret = Alert::prompt(_("Save changed document?"),
1963 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1967 if (!saveBuffer(buf))
1971 // if we crash after this we could
1972 // have no autosave file but I guess
1973 // this is really improbable (Jug)
1974 buf.removeAutosaveFile();
1980 // save file names to .lyx/session
1982 theSession().lastOpened().add(buf.fileName(), mark_active);
1985 // Don't close child documents.
1986 removeWorkArea(currentMainWorkArea());
1988 theBufferList().release(&buf);
1994 void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np)
1996 Buffer * const curbuf = buffer();
1997 Buffer * nextbuf = curbuf;
1999 if (np == NEXTBUFFER)
2000 nextbuf = theBufferList().next(nextbuf);
2002 nextbuf = theBufferList().previous(nextbuf);
2003 if (nextbuf == curbuf)
2009 if (workArea(*nextbuf))
2016 bool GuiView::dispatch(FuncRequest const & cmd)
2018 BufferView * bv = view();
2019 // By default we won't need any update.
2021 bv->cursor().updateFlags(Update::None);
2022 bool dispatched = true;
2024 if (cmd.origin == FuncRequest::TOC) {
2025 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
2026 toc->doDispatch(bv->cursor(), cmd);
2030 switch(cmd.action) {
2031 case LFUN_BUFFER_IMPORT:
2032 importDocument(to_utf8(cmd.argument()));
2035 case LFUN_BUFFER_SWITCH:
2036 if (FileName::isAbsolute(to_utf8(cmd.argument()))) {
2038 theBufferList().getBuffer(FileName(to_utf8(cmd.argument())));
2042 bv->cursor().message(_("Document not loaded"));
2046 case LFUN_BUFFER_NEXT:
2047 gotoNextOrPreviousBuffer(NEXTBUFFER);
2050 case LFUN_BUFFER_PREVIOUS:
2051 gotoNextOrPreviousBuffer(PREVBUFFER);
2054 case LFUN_COMMAND_EXECUTE: {
2055 bool const show_it = cmd.argument() != "off";
2056 // FIXME: this is a hack, "minibuffer" should not be
2058 if (GuiToolbar * t = toolbar("minibuffer")) {
2059 t->setVisible(show_it);
2060 if (show_it && t->commandBuffer())
2061 t->commandBuffer()->setFocus();
2065 case LFUN_DROP_LAYOUTS_CHOICE:
2067 d.layout_->showPopup();
2070 case LFUN_MENU_OPEN:
2071 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
2072 menu->exec(QCursor::pos());
2075 case LFUN_FILE_INSERT:
2076 insertLyXFile(cmd.argument());
2078 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
2079 insertPlaintextFile(cmd.argument(), true);
2082 case LFUN_FILE_INSERT_PLAINTEXT:
2083 insertPlaintextFile(cmd.argument(), false);
2086 case LFUN_BUFFER_WRITE:
2088 saveBuffer(bv->buffer());
2091 case LFUN_BUFFER_WRITE_AS:
2093 renameBuffer(bv->buffer(), cmd.argument());
2096 case LFUN_BUFFER_WRITE_ALL: {
2097 Buffer * first = theBufferList().first();
2100 message(_("Saving all documents..."));
2101 // We cannot use a for loop as the buffer list cycles.
2104 if (!b->isClean()) {
2106 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
2108 b = theBufferList().next(b);
2109 } while (b != first);
2110 message(_("All documents saved."));
2114 case LFUN_TOOLBAR_TOGGLE: {
2115 string const name = cmd.getArg(0);
2116 if (GuiToolbar * t = toolbar(name))
2121 case LFUN_DIALOG_UPDATE: {
2122 string const name = to_utf8(cmd.argument());
2123 // Can only update a dialog connected to an existing inset
2124 Inset * inset = getOpenInset(name);
2126 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
2127 inset->dispatch(view()->cursor(), fr);
2128 } else if (name == "paragraph") {
2129 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
2130 } else if (name == "prefs" || name == "document") {
2131 updateDialog(name, string());
2136 case LFUN_DIALOG_TOGGLE: {
2137 if (isDialogVisible(cmd.getArg(0)))
2138 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
2140 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
2144 case LFUN_DIALOG_DISCONNECT_INSET:
2145 disconnectDialog(to_utf8(cmd.argument()));
2148 case LFUN_DIALOG_HIDE: {
2149 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
2153 case LFUN_DIALOG_SHOW: {
2154 string const name = cmd.getArg(0);
2155 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
2157 if (name == "character") {
2158 data = freefont2string();
2160 showDialog("character", data);
2161 } else if (name == "latexlog") {
2162 Buffer::LogType type;
2163 string const logfile = buffer()->logName(&type);
2165 case Buffer::latexlog:
2168 case Buffer::buildlog:
2172 data += Lexer::quoteString(logfile);
2173 showDialog("log", data);
2174 } else if (name == "vclog") {
2175 string const data = "vc " +
2176 Lexer::quoteString(buffer()->lyxvc().getLogFile());
2177 showDialog("log", data);
2178 } else if (name == "symbols") {
2179 data = bv->cursor().getEncoding()->name();
2181 showDialog("symbols", data);
2183 } else if (name == "prefs" && isFullScreen()) {
2184 FuncRequest fr(LFUN_INSET_INSERT, "fullscreen");
2186 showDialog("prefs", data);
2188 showDialog(name, data);
2192 case LFUN_INSET_APPLY: {
2193 string const name = cmd.getArg(0);
2194 Inset * inset = getOpenInset(name);
2196 // put cursor in front of inset.
2197 if (!view()->setCursorFromInset(inset)) {
2198 LASSERT(false, break);
2201 // useful if we are called from a dialog.
2202 view()->cursor().beginUndoGroup();
2203 view()->cursor().recordUndo();
2204 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
2205 inset->dispatch(view()->cursor(), fr);
2206 view()->cursor().endUndoGroup();
2208 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
2214 case LFUN_UI_TOGGLE:
2216 // Make sure the keyboard focus stays in the work area.
2220 case LFUN_SPLIT_VIEW:
2221 if (Buffer * buf = buffer()) {
2222 string const orientation = cmd.getArg(0);
2223 d.splitter_->setOrientation(orientation == "vertical"
2224 ? Qt::Vertical : Qt::Horizontal);
2225 TabWorkArea * twa = addTabWorkArea();
2226 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
2227 setCurrentWorkArea(wa);
2231 case LFUN_CLOSE_TAB_GROUP:
2232 if (TabWorkArea * twa = d.currentTabWorkArea()) {
2234 twa = d.currentTabWorkArea();
2235 // Switch to the next GuiWorkArea in the found TabWorkArea.
2237 // Make sure the work area is up to date.
2238 setCurrentWorkArea(twa->currentWorkArea());
2240 setCurrentWorkArea(0);
2245 case LFUN_COMPLETION_INLINE:
2246 if (d.current_work_area_)
2247 d.current_work_area_->completer().showInline();
2250 case LFUN_COMPLETION_POPUP:
2251 if (d.current_work_area_)
2252 d.current_work_area_->completer().showPopup();
2256 case LFUN_COMPLETION_COMPLETE:
2257 if (d.current_work_area_)
2258 d.current_work_area_->completer().tab();
2261 case LFUN_COMPLETION_CANCEL:
2262 if (d.current_work_area_) {
2263 if (d.current_work_area_->completer().popupVisible())
2264 d.current_work_area_->completer().hidePopup();
2266 d.current_work_area_->completer().hideInline();
2270 case LFUN_COMPLETION_ACCEPT:
2271 if (d.current_work_area_)
2272 d.current_work_area_->completer().activate();
2275 case LFUN_BUFFER_ZOOM_IN:
2276 case LFUN_BUFFER_ZOOM_OUT:
2277 if (cmd.argument().empty()) {
2278 if (cmd.action == LFUN_BUFFER_ZOOM_IN)
2283 lyxrc.zoom += convert<int>(cmd.argument());
2285 if (lyxrc.zoom < 10)
2288 // The global QPixmapCache is used in GuiPainter to cache text
2289 // painting so we must reset it.
2290 QPixmapCache::clear();
2291 guiApp->fontLoader().update();
2292 lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
2300 // Part of automatic menu appearance feature.
2301 if (isFullScreen()) {
2302 if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
2304 if (statusBar()->isVisible())
2305 statusBar()->hide();
2312 void GuiView::lfunUiToggle(FuncRequest const & cmd)
2314 string const arg = cmd.getArg(0);
2315 if (arg == "scrollbar") {
2316 // hide() is of no help
2317 if (d.current_work_area_->verticalScrollBarPolicy() ==
2318 Qt::ScrollBarAlwaysOff)
2320 d.current_work_area_->setVerticalScrollBarPolicy(
2321 Qt::ScrollBarAsNeeded);
2323 d.current_work_area_->setVerticalScrollBarPolicy(
2324 Qt::ScrollBarAlwaysOff);
2327 if (arg == "statusbar") {
2328 statusBar()->setVisible(!statusBar()->isVisible());
2331 if (arg == "menubar") {
2332 menuBar()->setVisible(!menuBar()->isVisible());
2335 #if QT_VERSION >= 0x040300
2336 if (arg == "frame") {
2338 getContentsMargins(&l, &t, &r, &b);
2339 //are the frames in default state?
2340 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
2342 setContentsMargins(-2, -2, -2, -2);
2344 setContentsMargins(0, 0, 0, 0);
2349 if (arg == "fullscreen") {
2354 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
2358 void GuiView::toggleFullScreen()
2360 if (isFullScreen()) {
2361 for (int i = 0; i != d.splitter_->count(); ++i)
2362 d.tabWorkArea(i)->setFullScreen(false);
2363 #if QT_VERSION >= 0x040300
2364 setContentsMargins(0, 0, 0, 0);
2366 setWindowState(windowState() ^ Qt::WindowFullScreen);
2369 statusBar()->show();
2372 hideDialogs("prefs", 0);
2373 for (int i = 0; i != d.splitter_->count(); ++i)
2374 d.tabWorkArea(i)->setFullScreen(true);
2375 #if QT_VERSION >= 0x040300
2376 setContentsMargins(-2, -2, -2, -2);
2379 setWindowState(windowState() ^ Qt::WindowFullScreen);
2380 statusBar()->hide();
2381 if (lyxrc.full_screen_menubar)
2383 if (lyxrc.full_screen_toolbars) {
2384 ToolbarMap::iterator end = d.toolbars_.end();
2385 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
2390 // give dialogs like the TOC a chance to adapt
2395 Buffer const * GuiView::updateInset(Inset const * inset)
2397 if (!d.current_work_area_)
2401 d.current_work_area_->scheduleRedraw();
2403 return &d.current_work_area_->bufferView().buffer();
2407 void GuiView::restartCursor()
2409 /* When we move around, or type, it's nice to be able to see
2410 * the cursor immediately after the keypress.
2412 if (d.current_work_area_)
2413 d.current_work_area_->startBlinkingCursor();
2415 // Take this occasion to update the other GUI elements.
2421 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2423 if (d.current_work_area_)
2424 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2429 // This list should be kept in sync with the list of insets in
2430 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2431 // dialog should have the same name as the inset.
2432 // Changes should be also recorded in LFUN_DIALOG_SHOW doxygen
2433 // docs in LyXAction.cpp.
2435 char const * const dialognames[] = {
2436 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2437 "citation", "document", "errorlist", "ert", "external", "file", "findreplace",
2438 "findreplaceadv", "float", "graphics", "href", "include", "index",
2439 "index_print", "info", "listings", "label", "log", "mathdelimiter",
2440 "mathmatrix", "mathspace", "nomenclature", "nomencl_print", "note",
2441 "paragraph", "phantom", "prefs", "print", "ref", "sendto", "space",
2442 "spellchecker", "symbols", "tabular", "tabularcreate", "thesaurus", "texinfo",
2443 "toc", "view-source", "vspace", "wrap" };
2445 char const * const * const end_dialognames =
2446 dialognames + (sizeof(dialognames) / sizeof(char *));
2450 cmpCStr(char const * name) : name_(name) {}
2451 bool operator()(char const * other) {
2452 return strcmp(other, name_) == 0;
2459 bool isValidName(string const & name)
2461 return find_if(dialognames, end_dialognames,
2462 cmpCStr(name.c_str())) != end_dialognames;
2468 void GuiView::resetDialogs()
2470 // Make sure that no LFUN uses any LyXView.
2471 theLyXFunc().setLyXView(0);
2474 constructToolbars();
2475 guiApp->menus().fillMenuBar(menuBar(), this, false);
2477 d.layout_->updateContents(true);
2478 // Now update controls with current buffer.
2479 theLyXFunc().setLyXView(this);
2485 Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
2487 if (!isValidName(name))
2490 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2492 if (it != d.dialogs_.end()) {
2494 it->second->hideView();
2495 return it->second.get();
2498 Dialog * dialog = build(name);
2499 d.dialogs_[name].reset(dialog);
2500 if (lyxrc.allow_geometry_session)
2501 dialog->restoreSession();
2508 void GuiView::showDialog(string const & name, string const & data,
2516 Dialog * dialog = findOrBuild(name, false);
2518 dialog->showData(data);
2520 d.open_insets_[name] = inset;
2523 catch (ExceptionMessage const & ex) {
2531 bool GuiView::isDialogVisible(string const & name) const
2533 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2534 if (it == d.dialogs_.end())
2536 return it->second.get()->isVisibleView() && !it->second.get()->isClosing();
2540 void GuiView::hideDialog(string const & name, Inset * inset)
2542 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2543 if (it == d.dialogs_.end())
2546 if (inset && inset != getOpenInset(name))
2549 Dialog * const dialog = it->second.get();
2550 if (dialog->isVisibleView())
2552 d.open_insets_[name] = 0;
2556 void GuiView::disconnectDialog(string const & name)
2558 if (!isValidName(name))
2561 if (d.open_insets_.find(name) != d.open_insets_.end())
2562 d.open_insets_[name] = 0;
2566 Inset * GuiView::getOpenInset(string const & name) const
2568 if (!isValidName(name))
2571 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2572 return it == d.open_insets_.end() ? 0 : it->second;
2576 void GuiView::hideAll() const
2578 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2579 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2581 for(; it != end; ++it)
2582 it->second->hideView();
2586 void GuiView::updateDialogs()
2588 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2589 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2591 for(; it != end; ++it) {
2592 Dialog * dialog = it->second.get();
2593 if (dialog && dialog->isVisibleView())
2594 dialog->checkStatus();
2601 // will be replaced by a proper factory...
2602 Dialog * createGuiAbout(GuiView & lv);
2603 Dialog * createGuiBibitem(GuiView & lv);
2604 Dialog * createGuiBibtex(GuiView & lv);
2605 Dialog * createGuiBox(GuiView & lv);
2606 Dialog * createGuiBranch(GuiView & lv);
2607 Dialog * createGuiChanges(GuiView & lv);
2608 Dialog * createGuiCharacter(GuiView & lv);
2609 Dialog * createGuiCitation(GuiView & lv);
2610 Dialog * createGuiDelimiter(GuiView & lv);
2611 Dialog * createGuiDocument(GuiView & lv);
2612 Dialog * createGuiErrorList(GuiView & lv);
2613 Dialog * createGuiERT(GuiView & lv);
2614 Dialog * createGuiExternal(GuiView & lv);
2615 Dialog * createGuiFloat(GuiView & lv);
2616 Dialog * createGuiGraphics(GuiView & lv);
2617 Dialog * createGuiInclude(GuiView & lv);
2618 Dialog * createGuiIndex(GuiView & lv);
2619 Dialog * createGuiInfo(GuiView & lv);
2620 Dialog * createGuiLabel(GuiView & lv);
2621 Dialog * createGuiListings(GuiView & lv);
2622 Dialog * createGuiLog(GuiView & lv);
2623 Dialog * createGuiMathHSpace(GuiView & lv);
2624 Dialog * createGuiMathMatrix(GuiView & lv);
2625 Dialog * createGuiNomenclature(GuiView & lv);
2626 Dialog * createGuiNote(GuiView & lv);
2627 Dialog * createGuiParagraph(GuiView & lv);
2628 Dialog * createGuiPhantom(GuiView & lv);
2629 Dialog * createGuiPreferences(GuiView & lv);
2630 Dialog * createGuiPrint(GuiView & lv);
2631 Dialog * createGuiPrintindex(GuiView & lv);
2632 Dialog * createGuiPrintNomencl(GuiView & lv);
2633 Dialog * createGuiRef(GuiView & lv);
2634 Dialog * createGuiSearch(GuiView & lv);
2635 Dialog * createGuiSearchAdv(GuiView & lv);
2636 Dialog * createGuiSendTo(GuiView & lv);
2637 Dialog * createGuiShowFile(GuiView & lv);
2638 Dialog * createGuiSpellchecker(GuiView & lv);
2639 Dialog * createGuiSymbols(GuiView & lv);
2640 Dialog * createGuiTabularCreate(GuiView & lv);
2641 Dialog * createGuiTabular(GuiView & lv);
2642 Dialog * createGuiTexInfo(GuiView & lv);
2643 Dialog * createGuiTextHSpace(GuiView & lv);
2644 Dialog * createGuiToc(GuiView & lv);
2645 Dialog * createGuiThesaurus(GuiView & lv);
2646 Dialog * createGuiHyperlink(GuiView & lv);
2647 Dialog * createGuiVSpace(GuiView & lv);
2648 Dialog * createGuiViewSource(GuiView & lv);
2649 Dialog * createGuiWrap(GuiView & lv);
2652 Dialog * GuiView::build(string const & name)
2654 LASSERT(isValidName(name), return 0);
2656 if (name == "aboutlyx")
2657 return createGuiAbout(*this);
2658 if (name == "bibitem")
2659 return createGuiBibitem(*this);
2660 if (name == "bibtex")
2661 return createGuiBibtex(*this);
2663 return createGuiBox(*this);
2664 if (name == "branch")
2665 return createGuiBranch(*this);
2666 if (name == "changes")
2667 return createGuiChanges(*this);
2668 if (name == "character")
2669 return createGuiCharacter(*this);
2670 if (name == "citation")
2671 return createGuiCitation(*this);
2672 if (name == "document")
2673 return createGuiDocument(*this);
2674 if (name == "errorlist")
2675 return createGuiErrorList(*this);
2677 return createGuiERT(*this);
2678 if (name == "external")
2679 return createGuiExternal(*this);
2681 return createGuiShowFile(*this);
2682 if (name == "findreplace")
2683 return createGuiSearch(*this);
2684 if (name == "findreplaceadv")
2685 return createGuiSearchAdv(*this);
2686 if (name == "float")
2687 return createGuiFloat(*this);
2688 if (name == "graphics")
2689 return createGuiGraphics(*this);
2691 return createGuiHyperlink(*this);
2692 if (name == "include")
2693 return createGuiInclude(*this);
2694 if (name == "index")
2695 return createGuiIndex(*this);
2696 if (name == "index_print")
2697 return createGuiPrintindex(*this);
2699 return createGuiInfo(*this);
2700 if (name == "label")
2701 return createGuiLabel(*this);
2702 if (name == "listings")
2703 return createGuiListings(*this);
2705 return createGuiLog(*this);
2706 if (name == "mathdelimiter")
2707 return createGuiDelimiter(*this);
2708 if (name == "mathspace")
2709 return createGuiMathHSpace(*this);
2710 if (name == "mathmatrix")
2711 return createGuiMathMatrix(*this);
2712 if (name == "nomenclature")
2713 return createGuiNomenclature(*this);
2714 if (name == "nomencl_print")
2715 return createGuiPrintNomencl(*this);
2717 return createGuiNote(*this);
2718 if (name == "paragraph")
2719 return createGuiParagraph(*this);
2720 if (name == "phantom")
2721 return createGuiPhantom(*this);
2722 if (name == "prefs")
2723 return createGuiPreferences(*this);
2724 if (name == "print")
2725 return createGuiPrint(*this);
2727 return createGuiRef(*this);
2728 if (name == "sendto")
2729 return createGuiSendTo(*this);
2730 if (name == "space")
2731 return createGuiTextHSpace(*this);
2732 if (name == "spellchecker")
2733 return createGuiSpellchecker(*this);
2734 if (name == "symbols")
2735 return createGuiSymbols(*this);
2736 if (name == "tabular")
2737 return createGuiTabular(*this);
2738 if (name == "tabularcreate")
2739 return createGuiTabularCreate(*this);
2740 if (name == "texinfo")
2741 return createGuiTexInfo(*this);
2742 if (name == "thesaurus")
2743 return createGuiThesaurus(*this);
2745 return createGuiToc(*this);
2746 if (name == "view-source")
2747 return createGuiViewSource(*this);
2748 if (name == "vspace")
2749 return createGuiVSpace(*this);
2751 return createGuiWrap(*this);
2757 } // namespace frontend
2760 #include "moc_GuiView.cpp"