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