]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
compile fix. Sorry.
[lyx.git] / src / frontends / qt4 / GuiView.cpp
1 /**
2  * \file GuiView.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author John Levon
8  * \author Abdelrazak Younes
9  * \author Peter Kümmel
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "GuiView.h"
17 #include "Dialog.h"
18
19 #include <boost/assert.hpp>
20
21 using std::string;
22
23 #include "GuiView.h"
24
25 #include "GuiApplication.h"
26 #include "GuiWorkArea.h"
27 #include "GuiKeySymbol.h"
28 #include "GuiMenubar.h"
29 #include "GuiToolbar.h"
30 #include "GuiToolbars.h"
31
32 #include "qt_helpers.h"
33
34 #include "buffer_funcs.h"
35 #include "Buffer.h"
36 #include "BufferList.h"
37 #include "BufferParams.h"
38 #include "BufferView.h"
39 #include "Cursor.h"
40 #include "debug.h"
41 #include "ErrorList.h"
42 #include "FuncRequest.h"
43 #include "gettext.h"
44 #include "Intl.h"
45 #include "Layout.h"
46 #include "Lexer.h"
47 #include "LyXFunc.h"
48 #include "LyX.h"
49 #include "LyXRC.h"
50 #include "LyXVC.h"
51 #include "MenuBackend.h"
52 #include "Paragraph.h"
53 #include "TextClass.h"
54 #include "Text.h"
55 #include "ToolbarBackend.h"
56 #include "version.h"
57
58 #include "support/convert.h"
59 #include "support/FileName.h"
60 #include "support/lstrings.h"
61 #include "support/os.h"
62 #include "support/Timeout.h"
63
64 #include <QAction>
65 #include <QApplication>
66 #include <QCloseEvent>
67 #include <QDesktopWidget>
68 #include <QDragEnterEvent>
69 #include <QDropEvent>
70 #include <QList>
71 #include <QMenu>
72 #include <QPainter>
73 #include <QPixmap>
74 #include <QPoint>
75 #include <QPushButton>
76 #include <QSettings>
77 #include <QShowEvent>
78 #include <QSplitter>
79 #include <QStackedWidget>
80 #include <QStatusBar>
81 #include <QTimer>
82 #include <QToolBar>
83 #include <QUrl>
84
85 #include <boost/bind.hpp>
86 #include <boost/current_function.hpp>
87
88 #ifdef HAVE_SYS_TIME_H
89 # include <sys/time.h>
90 #endif
91 #ifdef HAVE_UNISTD_H
92 # include <unistd.h>
93 #endif
94
95 using std::endl;
96 using std::string;
97 using std::vector;
98
99 namespace lyx {
100
101 extern bool quitting;
102
103 namespace frontend {
104
105 using support::bformat;
106 using support::FileName;
107 using support::trim;
108
109 namespace {
110
111 int const statusbar_timer_value = 3000;
112
113 class BackgroundWidget : public QWidget
114 {
115 public:
116         BackgroundWidget(QString const & file, QString const & text)
117         {
118                 splash_ = new QPixmap(file);
119                 if (!splash_) {
120                         lyxerr << "could not load splash screen: '" << fromqstr(file) << "'" << endl;
121                         return;
122                 }
123
124                 QPainter pain(splash_);
125                 pain.setPen(QColor(255, 255, 0));
126                 QFont font;
127                 // The font used to display the version info
128                 font.setStyleHint(QFont::SansSerif);
129                 font.setWeight(QFont::Bold);
130                 font.setPointSize(convert<int>(lyxrc.font_sizes[FONT_SIZE_LARGE]));
131                 pain.setFont(font);
132                 pain.drawText(260, 270, text);
133         }
134
135         void paintEvent(QPaintEvent *)
136         {
137                 if (!splash_)
138                         return;
139
140                 int x = (width() - splash_->width()) / 2;
141                 int y = (height() - splash_->height()) / 2;
142                 QPainter pain(this);
143                 pain.drawPixmap(x, y, *splash_);
144         }
145
146 private:
147         QPixmap * splash_;
148 };
149
150 } // namespace anon
151
152
153 typedef boost::shared_ptr<Dialog> DialogPtr;
154
155 struct GuiView::GuiViewPrivate
156 {
157         GuiViewPrivate()
158                 : current_work_area_(0), layout_(0),
159                 autosave_timeout_(new Timeout(5000)), quitting_by_menu_(false),
160                 in_show_(false)
161         {
162                 // hardcode here the platform specific icon size
163                 smallIconSize = 14;     // scaling problems
164                 normalIconSize = 20;    // ok, default
165                 bigIconSize = 26;               // better for some math icons
166
167                 splitter_ = new QSplitter;
168                 initBackground();
169                 stack_widget_ = new QStackedWidget;
170                 stack_widget_->addWidget(bg_widget_);
171                 stack_widget_->addWidget(splitter_);
172                 setBackground();
173         }
174
175         ~GuiViewPrivate()
176         {
177                 delete splitter_;
178                 delete bg_widget_;
179                 delete stack_widget_;
180                 delete menubar_;
181                 delete toolbars_;
182                 delete autosave_timeout_;
183         }
184
185         QMenu * toolBarPopup(GuiView * parent)
186         {
187                 // FIXME: translation
188                 QMenu * menu = new QMenu(parent);
189                 QActionGroup * iconSizeGroup = new QActionGroup(parent);
190
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);
197
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);
204
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);
211
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);
219
220                 return menu;
221         }
222
223         void initBackground()
224         {
225                 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
226                 /// The text to be written on top of the pixmap
227                 QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
228                 bg_widget_ = new BackgroundWidget(":/images/banner.png", text);
229         }
230
231         void setBackground()
232         {
233                 stack_widget_->setCurrentWidget(bg_widget_);
234                 bg_widget_->setUpdatesEnabled(true);
235         }
236
237         TabWorkArea * tabWorkArea(int i)
238         {
239                 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
240         }
241
242         TabWorkArea * currentTabWorkArea()
243         {
244                 if (splitter_->count() == 1)
245                         // The first TabWorkArea is always the first one, if any.
246                         return tabWorkArea(0);
247
248                 TabWorkArea * tab_widget = 0;
249                 for (int i = 0; i != splitter_->count(); ++i) {
250                         QWidget * w = splitter_->widget(i);
251                         if (!w->hasFocus())
252                                 continue;
253                         tab_widget = dynamic_cast<TabWorkArea *>(w);
254                         if (tab_widget)
255                                 break;
256                 }
257
258                 return tab_widget;
259         }
260
261 public:
262         ///
263         string cur_title;
264
265         GuiWorkArea * current_work_area_;
266         QSplitter * splitter_;
267         QStackedWidget * stack_widget_;
268         BackgroundWidget * bg_widget_;
269         /// view's menubar
270         GuiMenubar * menubar_;
271         /// view's toolbars
272         GuiToolbars * toolbars_;
273         /// The main layout box.
274         /** 
275          * \warning Don't Delete! The layout box is actually owned by
276          * whichever toolbar contains it. All the GuiView class needs is a
277          * means of accessing it.
278          *
279          * FIXME: replace that with a proper model so that we are not limited
280          * to only one dialog.
281          */
282         GuiLayoutBox * layout_;
283
284         ///
285         std::map<std::string, Inset *> open_insets_;
286
287         ///
288         std::map<std::string, DialogPtr> dialogs_;
289
290         unsigned int smallIconSize;
291         unsigned int normalIconSize;
292         unsigned int bigIconSize;
293         ///
294         QTimer statusbar_timer_;
295         /// are we quitting by the menu?
296         bool quitting_by_menu_;
297         /// auto-saving of buffers
298         Timeout * const autosave_timeout_;
299         ///
300         /// flag against a race condition due to multiclicks in Qt frontend,
301         /// see bug #1119
302         bool in_show_;
303 };
304
305
306 GuiView::GuiView(int id)
307         : d(*new GuiViewPrivate),  id_(id)
308 {
309         // GuiToolbars *must* be initialised before GuiMenubar.
310         d.toolbars_ = new GuiToolbars(*this);
311         d.menubar_ = new GuiMenubar(this, menubackend);
312
313         setCentralWidget(d.stack_widget_);
314
315         // Start autosave timer
316         if (lyxrc.autosave) {
317                 d.autosave_timeout_->timeout.connect(boost::bind(&GuiView::autoSave, this));
318                 d.autosave_timeout_->setTimeout(lyxrc.autosave * 1000);
319                 d.autosave_timeout_->start();
320         }
321         QObject::connect(&d.statusbar_timer_, SIGNAL(timeout()),
322                 this, SLOT(clearMessage()));
323
324         // Qt bug? signal lastWindowClosed does not work
325         setAttribute(Qt::WA_QuitOnClose, false);
326         setAttribute(Qt::WA_DeleteOnClose, true);
327 #ifndef Q_WS_MACX
328         // assign an icon to main form. We do not do it under Qt/Mac,
329         // since the icon is provided in the application bundle.
330         setWindowIcon(QPixmap(":/images/lyx.png"));
331 #endif
332
333         // For Drag&Drop.
334         setAcceptDrops(true);
335
336         statusBar()->setSizeGripEnabled(true);
337
338         // Forbid too small unresizable window because it can happen
339         // with some window manager under X11.
340         setMinimumSize(300, 200);
341
342         if (!lyxrc.allow_geometry_session)
343                 // No session handling, default to a sane size.
344                 setGeometry(50, 50, 690, 510);
345
346         // Now take care of session management.
347         QSettings settings;
348         QString const key = "view-" + QString::number(id_);
349 #ifdef Q_WS_X11
350         QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
351         QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
352         resize(size);
353         move(pos);
354 #else
355         if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
356                 setGeometry(50, 50, 690, 510);
357 #endif
358         setIconSize(settings.value(key + "/icon_size").toSize());
359 }
360
361
362 GuiView::~GuiView()
363 {
364         delete &d;
365 }
366
367
368 void GuiView::close()
369 {
370         d.quitting_by_menu_ = true;
371         d.current_work_area_ = 0;
372         for (int i = 0; i != d.splitter_->count(); ++i) {
373                 TabWorkArea * twa = d.tabWorkArea(i);
374                 if (twa)
375                         twa->closeAll();
376         }
377         QMainWindow::close();
378         d.quitting_by_menu_ = false;
379 }
380
381
382 void GuiView::setFocus()
383 {
384         if (d.current_work_area_)
385                 d.current_work_area_->setFocus();
386         else
387                 QWidget::setFocus();
388 }
389
390
391 QMenu* GuiView::createPopupMenu()
392 {
393         return d.toolBarPopup(this);
394 }
395
396
397 void GuiView::showEvent(QShowEvent * e)
398 {
399         LYXERR(Debug::GUI, "Passed Geometry "
400                 << size().height() << "x" << size().width()
401                 << "+" << pos().x() << "+" << pos().y());
402
403         if (d.splitter_->count() == 0)
404                 // No work area, switch to the background widget.
405                 d.setBackground();
406
407         QMainWindow::showEvent(e);
408 }
409
410
411 void GuiView::closeEvent(QCloseEvent * close_event)
412 {
413         // we may have been called through the close window button
414         // which bypasses the LFUN machinery.
415         if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
416                 if (!theBufferList().quitWriteAll()) {
417                         close_event->ignore();
418                         return;
419                 }
420         }
421
422         // Make sure that no LFUN use this close to be closed View.
423         theLyXFunc().setLyXView(0);
424         // Make sure the timer time out will not trigger a statusbar update.
425         d.statusbar_timer_.stop();
426
427         if (lyxrc.allow_geometry_session) {
428                 QSettings settings;
429                 QString const key = "view-" + QString::number(id_);
430 #ifdef Q_WS_X11
431                 settings.setValue(key + "/pos", pos());
432                 settings.setValue(key + "/size", size());
433 #else
434                 settings.setValue(key + "/geometry", saveGeometry());
435 #endif
436                 settings.setValue(key + "/icon_size", iconSize());
437                 d.toolbars_->saveToolbarInfo();
438         }
439
440         guiApp->unregisterView(id_);
441         if (guiApp->viewCount() > 0) {
442                 // Just close the window and do nothing else if this is not the
443                 // last window.
444                 close_event->accept();
445                 return;
446         }
447
448         quitting = true;
449
450         // this is the place where we leave the frontend.
451         // it is the only point at which we start quitting.
452         close_event->accept();
453         // quit the event loop
454         qApp->quit();
455 }
456
457
458 void GuiView::dragEnterEvent(QDragEnterEvent * event)
459 {
460         if (event->mimeData()->hasUrls())
461                 event->accept();
462         /// \todo Ask lyx-devel is this is enough:
463         /// if (event->mimeData()->hasFormat("text/plain"))
464         ///     event->acceptProposedAction();
465 }
466
467
468 void GuiView::dropEvent(QDropEvent* event)
469 {
470         QList<QUrl> files = event->mimeData()->urls();
471         if (files.isEmpty())
472                 return;
473
474         LYXERR(Debug::GUI, BOOST_CURRENT_FUNCTION << " got URLs!");
475         for (int i = 0; i != files.size(); ++i) {
476                 string const file = support::os::internal_path(fromqstr(
477                         files.at(i).toLocalFile()));
478                 if (!file.empty())
479                         dispatch(FuncRequest(LFUN_FILE_OPEN, file));
480         }
481 }
482
483
484 void GuiView::message(docstring const & str)
485 {
486         statusBar()->showMessage(toqstr(str));
487         d.statusbar_timer_.stop();
488         d.statusbar_timer_.start(statusbar_timer_value);
489 }
490
491
492 void GuiView::smallSizedIcons()
493 {
494         setIconSize(QSize(d.smallIconSize, d.smallIconSize));
495 }
496
497
498 void GuiView::normalSizedIcons()
499 {
500         setIconSize(QSize(d.normalIconSize, d.normalIconSize));
501 }
502
503
504 void GuiView::bigSizedIcons()
505 {
506         setIconSize(QSize(d.bigIconSize, d.bigIconSize));
507 }
508
509
510 void GuiView::clearMessage()
511 {
512         if (!hasFocus())
513                 return;
514         theLyXFunc().setLyXView(this);
515         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
516         d.statusbar_timer_.stop();
517 }
518
519
520 void GuiView::updateWindowTitle(GuiWorkArea * wa)
521 {
522         if (wa != d.current_work_area_)
523                 return;
524         setWindowTitle(qt_("LyX: ") + wa->windowTitle());
525         setWindowIconText(wa->windowIconText());
526 }
527
528
529 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
530 {
531         disconnectBuffer();
532         disconnectBufferView();
533         connectBufferView(wa->bufferView());
534         connectBuffer(wa->bufferView().buffer());
535         d.current_work_area_ = wa;
536         QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
537                 this, SLOT(updateWindowTitle(GuiWorkArea *)));
538         updateWindowTitle(wa);
539
540         updateToc();
541         // Buffer-dependent dialogs should be updated or
542         // hidden. This should go here because some dialogs (eg ToC)
543         // require bv_->text.
544         updateBufferDependent(true);
545         updateToolbars();
546         updateLayoutList();
547         updateStatusBar();
548 }
549
550
551 void GuiView::updateStatusBar()
552 {
553         // let the user see the explicit message
554         if (d.statusbar_timer_.isActive())
555                 return;
556
557         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
558 }
559
560
561 bool GuiView::hasFocus() const
562 {
563         return qApp->activeWindow() == this;
564 }
565
566
567 bool GuiView::event(QEvent * e)
568 {
569         switch (e->type())
570         {
571         // Useful debug code:
572         //case QEvent::ActivationChange:
573         //case QEvent::WindowDeactivate:
574         //case QEvent::Paint:
575         //case QEvent::Enter:
576         //case QEvent::Leave:
577         //case QEvent::HoverEnter:
578         //case QEvent::HoverLeave:
579         //case QEvent::HoverMove:
580         //case QEvent::StatusTip:
581         //case QEvent::DragEnter:
582         //case QEvent::DragLeave:
583         //case QEvent::Drop:
584         //      break;
585
586         case QEvent::WindowActivate: {
587                 guiApp->setCurrentView(*this);
588                 if (d.current_work_area_) {
589                         BufferView & bv = d.current_work_area_->bufferView();
590                         connectBufferView(bv);
591                         connectBuffer(bv.buffer());
592                         // The document structure, name and dialogs might have
593                         // changed in another view.
594                         updateBufferDependent(true);
595                 } else {
596                         setWindowTitle(qt_("LyX"));
597                         setWindowIconText(qt_("LyX"));
598                 }
599                 return QMainWindow::event(e);
600         }
601         case QEvent::ShortcutOverride: {
602                 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
603                 if (!d.current_work_area_) {
604                         theLyXFunc().setLyXView(this);
605                         KeySymbol sym;
606                         setKeySymbol(&sym, ke);
607                         theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
608                         e->accept();
609                         return true;
610                 }
611                 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
612                         KeySymbol sym;
613                         setKeySymbol(&sym, ke);
614                         d.current_work_area_->processKeySym(sym, NoModifier);
615                         e->accept();
616                         return true;
617                 }
618         }
619         default:
620                 return QMainWindow::event(e);
621         }
622 }
623
624
625 bool GuiView::focusNextPrevChild(bool /*next*/)
626 {
627         setFocus();
628         return true;
629 }
630
631
632 void GuiView::setBusy(bool yes)
633 {
634         if (d.current_work_area_) {
635                 d.current_work_area_->setUpdatesEnabled(!yes);
636                 if (yes)
637                         d.current_work_area_->stopBlinkingCursor();
638                 else
639                         d.current_work_area_->startBlinkingCursor();
640         }
641
642         if (yes)
643                 QApplication::setOverrideCursor(Qt::WaitCursor);
644         else
645                 QApplication::restoreOverrideCursor();
646 }
647
648
649 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
650 {
651         GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
652
653         if (tbinfo.flags & ToolbarInfo::TOP) {
654                 if (newline)
655                         addToolBarBreak(Qt::TopToolBarArea);
656                 addToolBar(Qt::TopToolBarArea, toolBar);
657         }
658
659         if (tbinfo.flags & ToolbarInfo::BOTTOM) {
660 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
661 #if (QT_VERSION >= 0x040202)
662                 if (newline)
663                         addToolBarBreak(Qt::BottomToolBarArea);
664 #endif
665                 addToolBar(Qt::BottomToolBarArea, toolBar);
666         }
667
668         if (tbinfo.flags & ToolbarInfo::LEFT) {
669 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
670 #if (QT_VERSION >= 0x040202)
671                 if (newline)
672                         addToolBarBreak(Qt::LeftToolBarArea);
673 #endif
674                 addToolBar(Qt::LeftToolBarArea, toolBar);
675         }
676
677         if (tbinfo.flags & ToolbarInfo::RIGHT) {
678 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
679 #if (QT_VERSION >= 0x040202)
680                 if (newline)
681                         addToolBarBreak(Qt::RightToolBarArea);
682 #endif
683                 addToolBar(Qt::RightToolBarArea, toolBar);
684         }
685
686         // The following does not work so I cannot restore to exact toolbar location
687         /*
688         ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
689         toolBar->move(tbinfo.posx, tbinfo.posy);
690         */
691
692         return toolBar;
693 }
694
695
696 GuiWorkArea * GuiView::workArea(Buffer & buffer)
697 {
698         for (int i = 0; i != d.splitter_->count(); ++i) {
699                 GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
700                 if (wa)
701                         return wa;
702         }
703         return 0;
704 }
705
706
707 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
708 {
709
710         // Automatically create a TabWorkArea if there are none yet.
711         if (!d.splitter_->count())
712                 addTabWorkArea();
713
714         TabWorkArea * tab_widget = d.currentTabWorkArea();
715         return tab_widget->addWorkArea(buffer, *this);
716 }
717
718
719 void GuiView::addTabWorkArea()
720 {
721         TabWorkArea * twa = new TabWorkArea;
722         QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
723                 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
724         d.splitter_->addWidget(twa);
725         d.stack_widget_->setCurrentWidget(d.splitter_);
726 }
727
728
729 GuiWorkArea const * GuiView::currentWorkArea() const
730 {
731         return d.current_work_area_;
732 }
733
734
735 void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
736 {
737         BOOST_ASSERT(work_area);
738
739         // Changing work area can result from opening a file so
740         // update the toc in any case.
741         updateToc();
742
743         GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
744         d.current_work_area_ = wa;
745         for (int i = 0; i != d.splitter_->count(); ++i) {
746                 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
747                         return;
748         }
749 }
750
751
752 void GuiView::removeWorkArea(GuiWorkArea * work_area)
753 {
754         BOOST_ASSERT(work_area);
755         GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
756         if (gwa == d.current_work_area_) {
757                 disconnectBuffer();
758                 disconnectBufferView();
759                 hideBufferDependent();
760                 d.current_work_area_ = 0;
761         }
762
763         // removing a work area often results from closing a file so
764         // update the toc in any case.
765         updateToc();
766
767         for (int i = 0; i != d.splitter_->count(); ++i) {
768                 TabWorkArea * twa = d.tabWorkArea(i);
769                 if (!twa->removeWorkArea(gwa))
770                         // Not found in this tab group.
771                         continue;
772
773                 // We found and removed the GuiWorkArea.
774                 if (!twa->count()) {
775                         // No more WorkAreas in this tab group, so delete it.
776                         delete twa;
777                         break;
778                 }
779
780                 if (d.current_work_area_)
781                         // This means that we are not closing the current GuiWorkArea;
782                         break;
783
784                 // Switch to the next GuiWorkArea in the found TabWorkArea.
785                 d.current_work_area_ = twa->currentWorkArea();
786                 break;
787         }
788
789         if (d.splitter_->count() == 0)
790                 // No more work area, switch to the background widget.
791                 d.setBackground();
792 }
793
794
795 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
796 {
797         d.layout_ = layout;
798 }
799
800
801 void GuiView::updateLayoutList()
802 {
803         if (d.layout_)
804                 d.layout_->updateContents(false);
805 }
806
807
808 void GuiView::updateToolbars()
809 {
810         if (d.current_work_area_) {
811                 bool const math =
812                         d.current_work_area_->bufferView().cursor().inMathed();
813                 bool const table =
814                         lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
815                 bool const review =
816                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
817                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
818
819                 d.toolbars_->update(math, table, review);
820         } else
821                 d.toolbars_->update(false, false, false);
822
823         // update read-only status of open dialogs.
824         checkStatus();
825 }
826
827
828 Buffer * GuiView::buffer()
829 {
830         if (d.current_work_area_)
831                 return &d.current_work_area_->bufferView().buffer();
832         return 0;
833 }
834
835
836 Buffer const * GuiView::buffer() const
837 {
838         if (d.current_work_area_)
839                 return &d.current_work_area_->bufferView().buffer();
840         return 0;
841 }
842
843
844 void GuiView::setBuffer(Buffer * newBuffer)
845 {
846         BOOST_ASSERT(newBuffer);
847         setBusy(true);
848
849         GuiWorkArea * wa = workArea(*newBuffer);
850         if (wa == 0) {
851                 updateLabels(*newBuffer->masterBuffer());
852                 wa = addWorkArea(*newBuffer);
853         } else {
854                 //Disconnect the old buffer...there's no new one.
855                 disconnectBuffer();
856         }
857         connectBuffer(*newBuffer);
858         connectBufferView(wa->bufferView());
859         setCurrentWorkArea(wa);
860
861         setBusy(false);
862 }
863
864
865 void GuiView::connectBuffer(Buffer & buf)
866 {
867         buf.setGuiDelegate(this);
868 }
869
870
871 void GuiView::disconnectBuffer()
872 {
873         if (d.current_work_area_)
874                 d.current_work_area_->bufferView().setGuiDelegate(0);
875 }
876
877
878 void GuiView::connectBufferView(BufferView & bv)
879 {
880         bv.setGuiDelegate(this);
881 }
882
883
884 void GuiView::disconnectBufferView()
885 {
886         if (d.current_work_area_)
887                 d.current_work_area_->bufferView().setGuiDelegate(0);
888 }
889
890
891 void GuiView::errors(string const & error_type)
892 {
893         ErrorList & el = buffer()->errorList(error_type);
894         if (!el.empty())
895                 showDialog("errorlist", error_type);
896 }
897
898
899 void GuiView::updateDialog(string const & name, string const & data)
900 {
901         if (!isDialogVisible(name))
902                 return;
903
904         std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
905         if (it == d.dialogs_.end())
906                 return;
907
908         Dialog * const dialog = it->second.get();
909         if (dialog->isVisibleView())
910                 dialog->updateData(data);
911 }
912
913
914 BufferView * GuiView::view()
915 {
916         return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
917 }
918
919
920 void GuiView::updateToc()
921 {
922         updateDialog("toc", "");
923 }
924
925
926 void GuiView::updateEmbeddedFiles()
927 {
928         updateDialog("embedding", "");
929 }
930
931
932 void GuiView::autoSave()
933 {
934         LYXERR(Debug::INFO, "Running autoSave()");
935
936         if (buffer())
937                 view()->buffer().autoSave();
938 }
939
940
941 void GuiView::resetAutosaveTimers()
942 {
943         if (lyxrc.autosave)
944                 d.autosave_timeout_->restart();
945 }
946
947
948 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
949 {
950         FuncStatus flag;
951         bool enable = true;
952         Buffer * buf = buffer();
953
954         /* In LyX/Mac, when a dialog is open, the menus of the
955            application can still be accessed without giving focus to
956            the main window. In this case, we want to disable the menu
957            entries that are buffer-related.
958
959            Note that this code is not perfect, as bug 1941 attests:
960            http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
961         */
962         if (cmd.origin == FuncRequest::MENU && !hasFocus())
963                 buf = 0;
964
965         switch(cmd.action) {
966         case LFUN_TOOLBAR_TOGGLE:
967                 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
968                 break;
969
970         case LFUN_DIALOG_TOGGLE:
971                 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
972                 // fall through to set "enable"
973         case LFUN_DIALOG_SHOW: {
974                 string const name = cmd.getArg(0);
975                 if (!buf)
976                         enable = name == "aboutlyx"
977                                 || name == "file" //FIXME: should be removed.
978                                 || name == "prefs"
979                                 || name == "texinfo";
980                 else if (name == "print")
981                         enable = buf->isExportable("dvi")
982                                 && lyxrc.print_command != "none";
983                 else if (name == "character") {
984                         if (!view())
985                                 enable = false;
986                         else {
987                                 InsetCode ic = view()->cursor().inset().lyxCode();
988                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
989                         }
990                 }
991                 else if (name == "latexlog")
992                         enable = FileName(buf->logName()).isFileReadable();
993                 else if (name == "spellchecker")
994 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
995                         enable = !buf->isReadonly();
996 #else
997                         enable = false;
998 #endif
999                 else if (name == "vclog")
1000                         enable = buf->lyxvc().inUse();
1001                 break;
1002         }
1003
1004         case LFUN_DIALOG_UPDATE: {
1005                 string const name = cmd.getArg(0);
1006                 if (!buf)
1007                         enable = name == "prefs";
1008                 break;
1009         }
1010
1011         default:
1012                 if (!view()) {
1013                         enable = false;
1014                         break;
1015                 }
1016         }
1017
1018         if (!enable)
1019                 flag.enabled(false);
1020
1021         return flag;
1022 }
1023
1024
1025 void GuiView::dispatch(FuncRequest const & cmd)
1026 {
1027         Buffer * buf = buffer();
1028         switch(cmd.action) {
1029                 case LFUN_BUFFER_SWITCH:
1030                         setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1031                         break;
1032
1033                 case LFUN_COMMAND_EXECUTE: {
1034                         bool const show_it = cmd.argument() != "off";
1035                         d.toolbars_->showCommandBuffer(show_it);
1036                         break;
1037                 }
1038                 case LFUN_DROP_LAYOUTS_CHOICE:
1039                         if (d.layout_)
1040                                 d.layout_->showPopup();
1041                         break;
1042
1043                 case LFUN_MENU_OPEN:
1044                         d.menubar_->openByName(toqstr(cmd.argument()));
1045                         break;
1046
1047                 case LFUN_TOOLBAR_TOGGLE: {
1048                         string const name = cmd.getArg(0);
1049                         bool const allowauto = cmd.getArg(1) == "allowauto";
1050                         // it is possible to get current toolbar status like this,...
1051                         // but I decide to obey the order of ToolbarBackend::flags
1052                         // and disregard real toolbar status.
1053                         // toolbars_->saveToolbarInfo();
1054                         //
1055                         // toggle state on/off/auto
1056                         d.toolbars_->toggleToolbarState(name, allowauto);
1057                         // update toolbar
1058                         updateToolbars();
1059
1060                         ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1061                         if (!tbi) {
1062                                 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1063                                 break;
1064                         }
1065                         docstring state;
1066                         if (tbi->flags & ToolbarInfo::ON)
1067                                 state = _("on");
1068                         else if (tbi->flags & ToolbarInfo::OFF)
1069                                 state = _("off");
1070                         else if (tbi->flags & ToolbarInfo::AUTO)
1071                                 state = _("auto");
1072
1073                         message(bformat(_("Toolbar \"%1$s\" state set to %2$s"), 
1074                                            _(tbi->gui_name), state));
1075                         break;
1076                 }
1077
1078                 case LFUN_DIALOG_UPDATE: {
1079                         string const name = to_utf8(cmd.argument());
1080                         // Can only update a dialog connected to an existing inset
1081                         Inset * inset = getOpenInset(name);
1082                         if (inset) {
1083                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1084                                 inset->dispatch(view()->cursor(), fr);
1085                         } else if (name == "paragraph") {
1086                                 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1087                         } else if (name == "prefs") {
1088                                 updateDialog(name, string());
1089                         }
1090                         break;
1091                 }
1092
1093                 case LFUN_DIALOG_TOGGLE: {
1094                         if (isDialogVisible(cmd.getArg(0)))
1095                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1096                         else
1097                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1098                         break;
1099                 }
1100
1101                 case LFUN_DIALOG_DISCONNECT_INSET:
1102                         disconnectDialog(to_utf8(cmd.argument()));
1103                         break;
1104
1105                 case LFUN_DIALOG_HIDE: {
1106                         if (quitting)
1107                                 break;
1108                         guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1109                         break;
1110                 }
1111
1112                 case LFUN_DIALOG_SHOW: {
1113                         string const name = cmd.getArg(0);
1114                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1115
1116                         if (name == "character") {
1117                                 data = freefont2string();
1118                                 if (!data.empty())
1119                                         showDialog("character", data);
1120                         } else if (name == "latexlog") {
1121                                 Buffer::LogType type; 
1122                                 string const logfile = buf->logName(&type);
1123                                 switch (type) {
1124                                 case Buffer::latexlog:
1125                                         data = "latex ";
1126                                         break;
1127                                 case Buffer::buildlog:
1128                                         data = "literate ";
1129                                         break;
1130                                 }
1131                                 data += Lexer::quoteString(logfile);
1132                                 showDialog("log", data);
1133                         } else if (name == "vclog") {
1134                                 string const data = "vc " +
1135                                         Lexer::quoteString(buf->lyxvc().getLogFile());
1136                                 showDialog("log", data);
1137                         } else
1138                                 showDialog(name, data);
1139                         break;
1140                 }
1141
1142                 default:
1143                         theLyXFunc().setLyXView(this);
1144                         lyx::dispatch(cmd);
1145         }
1146 }
1147
1148
1149 Buffer const * GuiView::updateInset(Inset const * inset)
1150 {
1151         if (!d.current_work_area_)
1152                 return 0;
1153
1154         if (inset)
1155                 d.current_work_area_->scheduleRedraw();
1156
1157         return &d.current_work_area_->bufferView().buffer();
1158 }
1159
1160
1161 void GuiView::restartCursor()
1162 {
1163         /* When we move around, or type, it's nice to be able to see
1164          * the cursor immediately after the keypress.
1165          */
1166         if (d.current_work_area_)
1167                 d.current_work_area_->startBlinkingCursor();
1168
1169         // Take this occasion to update the toobars and layout list.
1170         updateLayoutList();
1171         updateToolbars();
1172 }
1173
1174 namespace {
1175
1176 // This list should be kept in sync with the list of insets in
1177 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
1178 // dialog should have the same name as the inset.
1179
1180 char const * const dialognames[] = {
1181 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1182 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1183 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1184 "mathdelimiter", "mathmatrix", "note", "paragraph",
1185 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1186
1187 #ifdef HAVE_LIBAIKSAURUS
1188 "thesaurus",
1189 #endif
1190
1191 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1192
1193 char const * const * const end_dialognames =
1194         dialognames + (sizeof(dialognames) / sizeof(char *));
1195
1196 class cmpCStr {
1197 public:
1198         cmpCStr(char const * name) : name_(name) {}
1199         bool operator()(char const * other) {
1200                 return strcmp(other, name_) == 0;
1201         }
1202 private:
1203         char const * name_;
1204 };
1205
1206
1207 bool isValidName(string const & name)
1208 {
1209         return std::find_if(dialognames, end_dialognames,
1210                             cmpCStr(name.c_str())) != end_dialognames;
1211 }
1212
1213 } // namespace anon
1214
1215
1216 void GuiView::resetDialogs()
1217 {
1218         // Make sure that no LFUN uses any LyXView.
1219         theLyXFunc().setLyXView(0);
1220         d.toolbars_->init();
1221         d.menubar_->init();
1222         if (d.layout_)
1223                 d.layout_->updateContents(true);
1224         // Now update controls with current buffer.
1225         theLyXFunc().setLyXView(this);
1226         restartCursor();
1227 }
1228
1229
1230 Dialog * GuiView::find_or_build(string const & name)
1231 {
1232         if (!isValidName(name))
1233                 return 0;
1234
1235         std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1236
1237         if (it != d.dialogs_.end())
1238                 return it->second.get();
1239
1240         d.dialogs_[name].reset(build(name));
1241         return d.dialogs_[name].get();
1242 }
1243
1244
1245 void GuiView::showDialog(string const & name, string const & data,
1246         Inset * inset)
1247 {
1248         if (d.in_show_)
1249                 return;
1250
1251         d.in_show_ = true;
1252         Dialog * dialog = find_or_build(name);
1253         if (dialog) {
1254                 dialog->showData(data);
1255                 if (inset)
1256                         d.open_insets_[name] = inset;
1257         }
1258         d.in_show_ = false;
1259 }
1260
1261
1262 bool GuiView::isDialogVisible(string const & name) const
1263 {
1264         std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1265         if (it == d.dialogs_.end())
1266                 return false;
1267         return it->second.get()->isVisibleView();
1268 }
1269
1270
1271 void GuiView::hideDialog(string const & name, Inset * inset)
1272 {
1273         // Don't send the signal if we are quitting, because on MSVC it is
1274         // destructed before the cut stack in CutAndPaste.cpp, and this method
1275         // is called from some inset destructor if the cut stack is not empty
1276         // on exit.
1277         if (quitting)
1278                 return;
1279
1280         std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1281         if (it == d.dialogs_.end())
1282                 return;
1283
1284         if (inset && inset != getOpenInset(name))
1285                 return;
1286
1287         Dialog * const dialog = it->second.get();
1288         if (dialog->isVisibleView())
1289                 dialog->hide();
1290         d.open_insets_[name] = 0;
1291 }
1292
1293
1294 void GuiView::disconnectDialog(string const & name)
1295 {
1296         if (!isValidName(name))
1297                 return;
1298
1299         if (d.open_insets_.find(name) != d.open_insets_.end())
1300                 d.open_insets_[name] = 0;
1301 }
1302
1303
1304 Inset * GuiView::getOpenInset(string const & name) const
1305 {
1306         if (!isValidName(name))
1307                 return 0;
1308
1309         std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1310         return it == d.open_insets_.end() ? 0 : it->second;
1311 }
1312
1313
1314 void GuiView::hideAll() const
1315 {
1316         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1317         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1318
1319         for(; it != end; ++it)
1320                 it->second->hide();
1321 }
1322
1323
1324 void GuiView::hideBufferDependent() const
1325 {
1326         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1327         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1328
1329         for(; it != end; ++it) {
1330                 Dialog * dialog = it->second.get();
1331                 if (dialog->isBufferDependent())
1332                         dialog->hide();
1333         }
1334 }
1335
1336
1337 void GuiView::updateBufferDependent(bool switched) const
1338 {
1339         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1340         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1341
1342         for(; it != end; ++it) {
1343                 Dialog * dialog = it->second.get();
1344                 if (switched && dialog->isBufferDependent()) {
1345                         if (dialog->isVisibleView() && dialog->initialiseParams(""))
1346                                 dialog->updateView();
1347                         else
1348                                 dialog->hide();
1349                 } else {
1350                         // A bit clunky, but the dialog will request
1351                         // that the kernel provides it with the necessary
1352                         // data.
1353                         dialog->updateDialog(dialog->name());
1354                 }
1355         }
1356 }
1357
1358
1359 void GuiView::checkStatus()
1360 {
1361         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1362         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1363
1364         for(; it != end; ++it) {
1365                 Dialog * const dialog = it->second.get();
1366                 if (dialog && dialog->isVisibleView())
1367                         dialog->checkStatus();
1368         }
1369 }
1370
1371
1372
1373 // will be replaced by a proper factory...
1374 Dialog * createGuiAbout(LyXView & lv);
1375 Dialog * createGuiBibitem(LyXView & lv);
1376 Dialog * createGuiBibtex(LyXView & lv);
1377 Dialog * createGuiBox(LyXView & lv);
1378 Dialog * createGuiBranch(LyXView & lv);
1379 Dialog * createGuiChanges(LyXView & lv);
1380 Dialog * createGuiCharacter(LyXView & lv);
1381 Dialog * createGuiCitation(LyXView & lv);
1382 Dialog * createGuiDelimiter(LyXView & lv);
1383 Dialog * createGuiDocument(LyXView & lv);
1384 Dialog * createGuiErrorList(LyXView & lv);
1385 Dialog * createGuiERT(LyXView & lv);
1386 Dialog * createGuiExternal(LyXView & lv);
1387 Dialog * createGuiFloat(LyXView & lv);
1388 Dialog * createGuiGraphics(LyXView & lv);
1389 Dialog * createGuiInclude(LyXView & lv);
1390 Dialog * createGuiIndex(LyXView & lv);
1391 Dialog * createGuiLabel(LyXView & lv);
1392 Dialog * createGuiListings(LyXView & lv);
1393 Dialog * createGuiLog(LyXView & lv);
1394 Dialog * createGuiMathMatrix(LyXView & lv);
1395 Dialog * createGuiNomenclature(LyXView & lv);
1396 Dialog * createGuiNote(LyXView & lv);
1397 Dialog * createGuiParagraph(LyXView & lv);
1398 Dialog * createGuiPreferences(LyXView & lv);
1399 Dialog * createGuiPrint(LyXView & lv);
1400 Dialog * createGuiRef(LyXView & lv);
1401 Dialog * createGuiSearch(LyXView & lv);
1402 Dialog * createGuiSendTo(LyXView & lv);
1403 Dialog * createGuiShowFile(LyXView & lv);
1404 Dialog * createGuiSpellchecker(LyXView & lv);
1405 Dialog * createGuiTabularCreate(LyXView & lv);
1406 Dialog * createGuiTabular(LyXView & lv);
1407 Dialog * createGuiTexInfo(LyXView & lv);
1408 Dialog * createGuiToc(LyXView & lv);
1409 Dialog * createGuiThesaurus(LyXView & lv);
1410 Dialog * createGuiHyperlink(LyXView & lv);
1411 Dialog * createGuiVSpace(LyXView & lv);
1412 Dialog * createGuiViewSource(LyXView & lv);
1413 Dialog * createGuiWrap(LyXView & lv);
1414
1415
1416 Dialog * GuiView::build(string const & name)
1417 {
1418         BOOST_ASSERT(isValidName(name));
1419
1420         if (name == "aboutlyx")
1421                 return createGuiAbout(*this);
1422         if (name == "bibitem")
1423                 return createGuiBibitem(*this);
1424         if (name == "bibtex")
1425                 return createGuiBibtex(*this);
1426         if (name == "box")
1427                 return createGuiBox(*this);
1428         if (name == "branch")
1429                 return createGuiBranch(*this);
1430         if (name == "changes")
1431                 return createGuiChanges(*this);
1432         if (name == "character")
1433                 return createGuiCharacter(*this);
1434         if (name == "citation")
1435                 return createGuiCitation(*this);
1436         if (name == "document")
1437                 return createGuiDocument(*this);
1438         if (name == "errorlist")
1439                 return createGuiErrorList(*this);
1440         if (name == "ert")
1441                 return createGuiERT(*this);
1442         if (name == "external")
1443                 return createGuiExternal(*this);
1444         if (name == "file")
1445                 return createGuiShowFile(*this);
1446         if (name == "findreplace")
1447                 return createGuiSearch(*this);
1448         if (name == "float")
1449                 return createGuiFloat(*this);
1450         if (name == "graphics")
1451                 return createGuiGraphics(*this);
1452         if (name == "include")
1453                 return createGuiInclude(*this);
1454         if (name == "index")
1455                 return createGuiIndex(*this);
1456         if (name == "nomenclature")
1457                 return createGuiNomenclature(*this);
1458         if (name == "label")
1459                 return createGuiLabel(*this);
1460         if (name == "log")
1461                 return createGuiLog(*this);
1462         if (name == "view-source")
1463                 return createGuiViewSource(*this);
1464         if (name == "mathdelimiter")
1465                 return createGuiDelimiter(*this);
1466         if (name == "mathmatrix")
1467                 return createGuiMathMatrix(*this);
1468         if (name == "note")
1469                 return createGuiNote(*this);
1470         if (name == "paragraph")
1471                 return createGuiParagraph(*this);
1472         if (name == "prefs")
1473                 return createGuiPreferences(*this);
1474         if (name == "print")
1475                 return createGuiPrint(*this);
1476         if (name == "ref")
1477                 return createGuiRef(*this);
1478         if (name == "sendto")
1479                 return createGuiSendTo(*this);
1480         if (name == "spellchecker")
1481                 return createGuiSpellchecker(*this);
1482         if (name == "tabular")
1483                 return createGuiTabular(*this);
1484         if (name == "tabularcreate")
1485                 return createGuiTabularCreate(*this);
1486         if (name == "texinfo")
1487                 return createGuiTexInfo(*this);
1488 #ifdef HAVE_LIBAIKSAURUS
1489         if (name == "thesaurus")
1490                 return createGuiThesaurus(*this);
1491 #endif
1492         if (name == "toc")
1493                 return createGuiToc(*this);
1494         if (name == "href")
1495                 return createGuiHyperlink(*this);
1496         if (name == "vspace")
1497                 return createGuiVSpace(*this);
1498         if (name == "wrap")
1499                 return createGuiWrap(*this);
1500         if (name == "listings")
1501                 return createGuiListings(*this);
1502
1503         return 0;
1504 }
1505
1506
1507 } // namespace frontend
1508 } // namespace lyx
1509
1510 #include "GuiView_moc.cpp"