]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
Introducing GuiMenubar::init() to avoid destructing the object in order to re-initial...
[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 }
1225
1226
1227 Dialog * GuiView::find_or_build(string const & name)
1228 {
1229         if (!isValidName(name))
1230                 return 0;
1231
1232         std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1233
1234         if (it != d.dialogs_.end())
1235                 return it->second.get();
1236
1237         d.dialogs_[name].reset(build(name));
1238         return d.dialogs_[name].get();
1239 }
1240
1241
1242 void GuiView::showDialog(string const & name, string const & data,
1243         Inset * inset)
1244 {
1245         if (d.in_show_)
1246                 return;
1247
1248         d.in_show_ = true;
1249         Dialog * dialog = find_or_build(name);
1250         if (dialog) {
1251                 dialog->showData(data);
1252                 if (inset)
1253                         d.open_insets_[name] = inset;
1254         }
1255         d.in_show_ = false;
1256 }
1257
1258
1259 bool GuiView::isDialogVisible(string const & name) const
1260 {
1261         std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1262         if (it == d.dialogs_.end())
1263                 return false;
1264         return it->second.get()->isVisibleView();
1265 }
1266
1267
1268 void GuiView::hideDialog(string const & name, Inset * inset)
1269 {
1270         // Don't send the signal if we are quitting, because on MSVC it is
1271         // destructed before the cut stack in CutAndPaste.cpp, and this method
1272         // is called from some inset destructor if the cut stack is not empty
1273         // on exit.
1274         if (quitting)
1275                 return;
1276
1277         std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1278         if (it == d.dialogs_.end())
1279                 return;
1280
1281         if (inset && inset != getOpenInset(name))
1282                 return;
1283
1284         Dialog * const dialog = it->second.get();
1285         if (dialog->isVisibleView())
1286                 dialog->hide();
1287         d.open_insets_[name] = 0;
1288 }
1289
1290
1291 void GuiView::disconnectDialog(string const & name)
1292 {
1293         if (!isValidName(name))
1294                 return;
1295
1296         if (d.open_insets_.find(name) != d.open_insets_.end())
1297                 d.open_insets_[name] = 0;
1298 }
1299
1300
1301 Inset * GuiView::getOpenInset(string const & name) const
1302 {
1303         if (!isValidName(name))
1304                 return 0;
1305
1306         std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1307         return it == d.open_insets_.end() ? 0 : it->second;
1308 }
1309
1310
1311 void GuiView::hideAll() const
1312 {
1313         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1314         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1315
1316         for(; it != end; ++it)
1317                 it->second->hide();
1318 }
1319
1320
1321 void GuiView::hideBufferDependent() const
1322 {
1323         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1324         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1325
1326         for(; it != end; ++it) {
1327                 Dialog * dialog = it->second.get();
1328                 if (dialog->isBufferDependent())
1329                         dialog->hide();
1330         }
1331 }
1332
1333
1334 void GuiView::updateBufferDependent(bool switched) const
1335 {
1336         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1337         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1338
1339         for(; it != end; ++it) {
1340                 Dialog * dialog = it->second.get();
1341                 if (switched && dialog->isBufferDependent()) {
1342                         if (dialog->isVisibleView() && dialog->initialiseParams(""))
1343                                 dialog->updateView();
1344                         else
1345                                 dialog->hide();
1346                 } else {
1347                         // A bit clunky, but the dialog will request
1348                         // that the kernel provides it with the necessary
1349                         // data.
1350                         dialog->slotRestore();
1351                 }
1352         }
1353 }
1354
1355
1356 void GuiView::checkStatus()
1357 {
1358         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1359         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1360
1361         for(; it != end; ++it) {
1362                 Dialog * const dialog = it->second.get();
1363                 if (dialog && dialog->isVisibleView())
1364                         dialog->checkStatus();
1365         }
1366 }
1367
1368
1369
1370 // will be replaced by a proper factory...
1371 Dialog * createGuiAbout(LyXView & lv);
1372 Dialog * createGuiBibitem(LyXView & lv);
1373 Dialog * createGuiBibtex(LyXView & lv);
1374 Dialog * createGuiBox(LyXView & lv);
1375 Dialog * createGuiBranch(LyXView & lv);
1376 Dialog * createGuiChanges(LyXView & lv);
1377 Dialog * createGuiCharacter(LyXView & lv);
1378 Dialog * createGuiCitation(LyXView & lv);
1379 Dialog * createGuiDelimiter(LyXView & lv);
1380 Dialog * createGuiDocument(LyXView & lv);
1381 Dialog * createGuiErrorList(LyXView & lv);
1382 Dialog * createGuiERT(LyXView & lv);
1383 Dialog * createGuiExternal(LyXView & lv);
1384 Dialog * createGuiFloat(LyXView & lv);
1385 Dialog * createGuiGraphics(LyXView & lv);
1386 Dialog * createGuiInclude(LyXView & lv);
1387 Dialog * createGuiIndex(LyXView & lv);
1388 Dialog * createGuiLabel(LyXView & lv);
1389 Dialog * createGuiListings(LyXView & lv);
1390 Dialog * createGuiLog(LyXView & lv);
1391 Dialog * createGuiMathMatrix(LyXView & lv);
1392 Dialog * createGuiNomenclature(LyXView & lv);
1393 Dialog * createGuiNote(LyXView & lv);
1394 Dialog * createGuiParagraph(LyXView & lv);
1395 Dialog * createGuiPreferences(LyXView & lv);
1396 Dialog * createGuiPrint(LyXView & lv);
1397 Dialog * createGuiRef(LyXView & lv);
1398 Dialog * createGuiSearch(LyXView & lv);
1399 Dialog * createGuiSendTo(LyXView & lv);
1400 Dialog * createGuiShowFile(LyXView & lv);
1401 Dialog * createGuiSpellchecker(LyXView & lv);
1402 Dialog * createGuiTabularCreate(LyXView & lv);
1403 Dialog * createGuiTabular(LyXView & lv);
1404 Dialog * createGuiTexInfo(LyXView & lv);
1405 Dialog * createGuiToc(LyXView & lv);
1406 Dialog * createGuiThesaurus(LyXView & lv);
1407 Dialog * createGuiHyperlink(LyXView & lv);
1408 Dialog * createGuiVSpace(LyXView & lv);
1409 Dialog * createGuiViewSource(LyXView & lv);
1410 Dialog * createGuiWrap(LyXView & lv);
1411
1412
1413 Dialog * GuiView::build(string const & name)
1414 {
1415         BOOST_ASSERT(isValidName(name));
1416
1417         if (name == "aboutlyx")
1418                 return createGuiAbout(*this);
1419         if (name == "bibitem")
1420                 return createGuiBibitem(*this);
1421         if (name == "bibtex")
1422                 return createGuiBibtex(*this);
1423         if (name == "box")
1424                 return createGuiBox(*this);
1425         if (name == "branch")
1426                 return createGuiBranch(*this);
1427         if (name == "changes")
1428                 return createGuiChanges(*this);
1429         if (name == "character")
1430                 return createGuiCharacter(*this);
1431         if (name == "citation")
1432                 return createGuiCitation(*this);
1433         if (name == "document")
1434                 return createGuiDocument(*this);
1435         if (name == "errorlist")
1436                 return createGuiErrorList(*this);
1437         if (name == "ert")
1438                 return createGuiERT(*this);
1439         if (name == "external")
1440                 return createGuiExternal(*this);
1441         if (name == "file")
1442                 return createGuiShowFile(*this);
1443         if (name == "findreplace")
1444                 return createGuiSearch(*this);
1445         if (name == "float")
1446                 return createGuiFloat(*this);
1447         if (name == "graphics")
1448                 return createGuiGraphics(*this);
1449         if (name == "include")
1450                 return createGuiInclude(*this);
1451         if (name == "index")
1452                 return createGuiIndex(*this);
1453         if (name == "nomenclature")
1454                 return createGuiNomenclature(*this);
1455         if (name == "label")
1456                 return createGuiLabel(*this);
1457         if (name == "log")
1458                 return createGuiLog(*this);
1459         if (name == "view-source")
1460                 return createGuiViewSource(*this);
1461         if (name == "mathdelimiter")
1462                 return createGuiDelimiter(*this);
1463         if (name == "mathmatrix")
1464                 return createGuiMathMatrix(*this);
1465         if (name == "note")
1466                 return createGuiNote(*this);
1467         if (name == "paragraph")
1468                 return createGuiParagraph(*this);
1469         if (name == "prefs")
1470                 return createGuiPreferences(*this);
1471         if (name == "print")
1472                 return createGuiPrint(*this);
1473         if (name == "ref")
1474                 return createGuiRef(*this);
1475         if (name == "sendto")
1476                 return createGuiSendTo(*this);
1477         if (name == "spellchecker")
1478                 return createGuiSpellchecker(*this);
1479         if (name == "tabular")
1480                 return createGuiTabular(*this);
1481         if (name == "tabularcreate")
1482                 return createGuiTabularCreate(*this);
1483         if (name == "texinfo")
1484                 return createGuiTexInfo(*this);
1485 #ifdef HAVE_LIBAIKSAURUS
1486         if (name == "thesaurus")
1487                 return createGuiThesaurus(*this);
1488 #endif
1489         if (name == "toc")
1490                 return createGuiToc(*this);
1491         if (name == "href")
1492                 return createGuiHyperlink(*this);
1493         if (name == "vspace")
1494                 return createGuiVSpace(*this);
1495         if (name == "wrap")
1496                 return createGuiWrap(*this);
1497         if (name == "listings")
1498                 return createGuiListings(*this);
1499
1500         return 0;
1501 }
1502
1503
1504 } // namespace frontend
1505 } // namespace lyx
1506
1507 #include "GuiView_moc.cpp"