]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
Simplify Dialog::name() handling.
[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 stack_widget_;
166                 delete bg_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         // By default we won't need any new update.
1024         Update::flags update_flags = Update::None;
1025
1026         switch(cmd.action) {
1027                 case LFUN_BUFFER_SWITCH:
1028                         setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1029                         break;
1030
1031                 case LFUN_COMMAND_EXECUTE: {
1032                         bool const show_it = cmd.argument() != "off";
1033                         d.toolbars_->showCommandBuffer(show_it);
1034                         break;
1035                 }
1036                 case LFUN_DROP_LAYOUTS_CHOICE:
1037                         if (d.layout_)
1038                                 d.layout_->showPopup();
1039                         break;
1040
1041                 case LFUN_MENU_OPEN:
1042                         d.menubar_->openByName(toqstr(cmd.argument()));
1043                         break;
1044
1045                 case LFUN_TOOLBAR_TOGGLE: {
1046                         string const name = cmd.getArg(0);
1047                         bool const allowauto = cmd.getArg(1) == "allowauto";
1048                         // it is possible to get current toolbar status like this,...
1049                         // but I decide to obey the order of ToolbarBackend::flags
1050                         // and disregard real toolbar status.
1051                         // toolbars_->saveToolbarInfo();
1052                         //
1053                         // toggle state on/off/auto
1054                         d.toolbars_->toggleToolbarState(name, allowauto);
1055                         // update toolbar
1056                         updateToolbars();
1057
1058                         ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1059                         if (!tbi) {
1060                                 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1061                                 break;
1062                         }
1063                         docstring state;
1064                         if (tbi->flags & ToolbarInfo::ON)
1065                                 state = _("on");
1066                         else if (tbi->flags & ToolbarInfo::OFF)
1067                                 state = _("off");
1068                         else if (tbi->flags & ToolbarInfo::AUTO)
1069                                 state = _("auto");
1070
1071                         message(bformat(_("Toolbar \"%1$s\" state set to %2$s"), 
1072                                            _(tbi->gui_name), state));
1073                         break;
1074                 }
1075
1076                 case LFUN_DIALOG_UPDATE: {
1077                         string const name = to_utf8(cmd.argument());
1078                         // Can only update a dialog connected to an existing inset
1079                         Inset * inset = getOpenInset(name);
1080                         if (inset) {
1081                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1082                                 inset->dispatch(view()->cursor(), fr);
1083                         } else if (name == "paragraph") {
1084                                 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1085                         } else if (name == "prefs") {
1086                                 updateDialog(name, string());
1087                         }
1088                         break;
1089                 }
1090
1091                 case LFUN_DIALOG_TOGGLE: {
1092                         if (isDialogVisible(cmd.getArg(0)))
1093                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1094                         else
1095                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1096                         break;
1097                 }
1098
1099                 case LFUN_DIALOG_DISCONNECT_INSET:
1100                         disconnectDialog(to_utf8(cmd.argument()));
1101                         break;
1102
1103                 case LFUN_DIALOG_HIDE: {
1104                         if (quitting)
1105                                 break;
1106                         guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1107                         break;
1108                 }
1109
1110                 case LFUN_DIALOG_SHOW: {
1111                         string const name = cmd.getArg(0);
1112                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1113
1114                         if (name == "character") {
1115                                 data = freefont2string();
1116                                 if (!data.empty())
1117                                         showDialog("character", data);
1118                         } else if (name == "latexlog") {
1119                                 Buffer::LogType type; 
1120                                 string const logfile = buffer()->logName(&type);
1121                                 switch (type) {
1122                                 case Buffer::latexlog:
1123                                         data = "latex ";
1124                                         break;
1125                                 case Buffer::buildlog:
1126                                         data = "literate ";
1127                                         break;
1128                                 }
1129                                 data += Lexer::quoteString(logfile);
1130                                 showDialog("log", data);
1131                         } else if (name == "vclog") {
1132                                 string const data = "vc " +
1133                                         Lexer::quoteString(buffer()->lyxvc().getLogFile());
1134                                 showDialog("log", data);
1135                         } else
1136                                 showDialog(name, data);
1137                         break;
1138                 }
1139
1140                 case LFUN_INSET_APPLY: {
1141                         string const name = cmd.getArg(0);
1142                         Inset * inset = getOpenInset(name);
1143                         if (inset) {
1144                                 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1145                                 inset->dispatch(view()->cursor(), fr);
1146                                 // ideally, the update flag should be set by the insets,
1147                                 // but this is not possible currently
1148                                 update_flags = Update::Force | Update::FitCursor;
1149                         } else {
1150                                 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1151                                 lyx::dispatch(fr);
1152                         }
1153                         break;
1154                 }
1155
1156                 default:
1157                         theLyXFunc().setLyXView(this);
1158                         lyx::dispatch(cmd);
1159         }
1160
1161         if (view())
1162                 view()->cursor().updateFlags(update_flags);
1163 }
1164
1165
1166 Buffer const * GuiView::updateInset(Inset const * inset)
1167 {
1168         if (!d.current_work_area_)
1169                 return 0;
1170
1171         if (inset)
1172                 d.current_work_area_->scheduleRedraw();
1173
1174         return &d.current_work_area_->bufferView().buffer();
1175 }
1176
1177
1178 void GuiView::restartCursor()
1179 {
1180         /* When we move around, or type, it's nice to be able to see
1181          * the cursor immediately after the keypress.
1182          */
1183         if (d.current_work_area_)
1184                 d.current_work_area_->startBlinkingCursor();
1185
1186         // Take this occasion to update the toobars and layout list.
1187         updateLayoutList();
1188         updateToolbars();
1189 }
1190
1191 namespace {
1192
1193 // This list should be kept in sync with the list of insets in
1194 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
1195 // dialog should have the same name as the inset.
1196
1197 char const * const dialognames[] = {
1198 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1199 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1200 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1201 "mathdelimiter", "mathmatrix", "note", "paragraph",
1202 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1203
1204 #ifdef HAVE_LIBAIKSAURUS
1205 "thesaurus",
1206 #endif
1207
1208 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1209
1210 char const * const * const end_dialognames =
1211         dialognames + (sizeof(dialognames) / sizeof(char *));
1212
1213 class cmpCStr {
1214 public:
1215         cmpCStr(char const * name) : name_(name) {}
1216         bool operator()(char const * other) {
1217                 return strcmp(other, name_) == 0;
1218         }
1219 private:
1220         char const * name_;
1221 };
1222
1223
1224 bool isValidName(string const & name)
1225 {
1226         return std::find_if(dialognames, end_dialognames,
1227                             cmpCStr(name.c_str())) != end_dialognames;
1228 }
1229
1230 } // namespace anon
1231
1232
1233 void GuiView::resetDialogs()
1234 {
1235         // Make sure that no LFUN uses any LyXView.
1236         theLyXFunc().setLyXView(0);
1237         d.toolbars_->init();
1238         d.menubar_->init();
1239         if (d.layout_)
1240                 d.layout_->updateContents(true);
1241         // Now update controls with current buffer.
1242         theLyXFunc().setLyXView(this);
1243         restartCursor();
1244 }
1245
1246
1247 Dialog * GuiView::find_or_build(string const & name)
1248 {
1249         if (!isValidName(name))
1250                 return 0;
1251
1252         std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1253
1254         if (it != d.dialogs_.end())
1255                 return it->second.get();
1256
1257         d.dialogs_[name].reset(build(name));
1258         return d.dialogs_[name].get();
1259 }
1260
1261
1262 void GuiView::showDialog(string const & name, string const & data,
1263         Inset * inset)
1264 {
1265         if (d.in_show_)
1266                 return;
1267
1268         d.in_show_ = true;
1269         Dialog * dialog = find_or_build(name);
1270         if (dialog) {
1271                 dialog->showData(data);
1272                 if (inset)
1273                         d.open_insets_[name] = inset;
1274         }
1275         d.in_show_ = false;
1276 }
1277
1278
1279 bool GuiView::isDialogVisible(string const & name) const
1280 {
1281         std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1282         if (it == d.dialogs_.end())
1283                 return false;
1284         return it->second.get()->isVisibleView();
1285 }
1286
1287
1288 void GuiView::hideDialog(string const & name, Inset * inset)
1289 {
1290         // Don't send the signal if we are quitting, because on MSVC it is
1291         // destructed before the cut stack in CutAndPaste.cpp, and this method
1292         // is called from some inset destructor if the cut stack is not empty
1293         // on exit.
1294         if (quitting)
1295                 return;
1296
1297         std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1298         if (it == d.dialogs_.end())
1299                 return;
1300
1301         if (inset && inset != getOpenInset(name))
1302                 return;
1303
1304         Dialog * const dialog = it->second.get();
1305         if (dialog->isVisibleView())
1306                 dialog->hide();
1307         d.open_insets_[name] = 0;
1308 }
1309
1310
1311 void GuiView::disconnectDialog(string const & name)
1312 {
1313         if (!isValidName(name))
1314                 return;
1315
1316         if (d.open_insets_.find(name) != d.open_insets_.end())
1317                 d.open_insets_[name] = 0;
1318 }
1319
1320
1321 Inset * GuiView::getOpenInset(string const & name) const
1322 {
1323         if (!isValidName(name))
1324                 return 0;
1325
1326         std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1327         return it == d.open_insets_.end() ? 0 : it->second;
1328 }
1329
1330
1331 void GuiView::hideAll() const
1332 {
1333         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1334         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1335
1336         for(; it != end; ++it)
1337                 it->second->hide();
1338 }
1339
1340
1341 void GuiView::hideBufferDependent() const
1342 {
1343         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1344         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1345
1346         for(; it != end; ++it) {
1347                 Dialog * dialog = it->second.get();
1348                 if (dialog->isBufferDependent())
1349                         dialog->hide();
1350         }
1351 }
1352
1353
1354 void GuiView::updateBufferDependent(bool switched) const
1355 {
1356         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1357         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1358
1359         for(; it != end; ++it) {
1360                 Dialog * dialog = it->second.get();
1361                 if (switched && dialog->isBufferDependent()) {
1362                         if (dialog->isVisibleView() && dialog->initialiseParams(""))
1363                                 dialog->updateView();
1364                         else
1365                                 dialog->hide();
1366                 } else {
1367                         // A bit clunky, but the dialog will request
1368                         // that the kernel provides it with the necessary
1369                         // data.
1370                         dialog->updateDialog();
1371                 }
1372         }
1373 }
1374
1375
1376 void GuiView::checkStatus()
1377 {
1378         std::map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
1379         std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1380
1381         for(; it != end; ++it) {
1382                 Dialog * const dialog = it->second.get();
1383                 if (dialog && dialog->isVisibleView())
1384                         dialog->checkStatus();
1385         }
1386 }
1387
1388
1389
1390 // will be replaced by a proper factory...
1391 Dialog * createGuiAbout(GuiView & lv);
1392 Dialog * createGuiBibitem(GuiView & lv);
1393 Dialog * createGuiBibtex(GuiView & lv);
1394 Dialog * createGuiBox(GuiView & lv);
1395 Dialog * createGuiBranch(GuiView & lv);
1396 Dialog * createGuiChanges(GuiView & lv);
1397 Dialog * createGuiCharacter(GuiView & lv);
1398 Dialog * createGuiCitation(GuiView & lv);
1399 Dialog * createGuiDelimiter(GuiView & lv);
1400 Dialog * createGuiDocument(GuiView & lv);
1401 Dialog * createGuiErrorList(GuiView & lv);
1402 Dialog * createGuiERT(GuiView & lv);
1403 Dialog * createGuiExternal(GuiView & lv);
1404 Dialog * createGuiFloat(GuiView & lv);
1405 Dialog * createGuiGraphics(GuiView & lv);
1406 Dialog * createGuiInclude(GuiView & lv);
1407 Dialog * createGuiIndex(GuiView & lv);
1408 Dialog * createGuiLabel(GuiView & lv);
1409 Dialog * createGuiListings(GuiView & lv);
1410 Dialog * createGuiLog(GuiView & lv);
1411 Dialog * createGuiMathMatrix(GuiView & lv);
1412 Dialog * createGuiNomenclature(GuiView & lv);
1413 Dialog * createGuiNote(GuiView & lv);
1414 Dialog * createGuiParagraph(GuiView & lv);
1415 Dialog * createGuiPreferences(GuiView & lv);
1416 Dialog * createGuiPrint(GuiView & lv);
1417 Dialog * createGuiRef(GuiView & lv);
1418 Dialog * createGuiSearch(GuiView & lv);
1419 Dialog * createGuiSendTo(GuiView & lv);
1420 Dialog * createGuiShowFile(GuiView & lv);
1421 Dialog * createGuiSpellchecker(GuiView & lv);
1422 Dialog * createGuiTabularCreate(GuiView & lv);
1423 Dialog * createGuiTabular(GuiView & lv);
1424 Dialog * createGuiTexInfo(GuiView & lv);
1425 Dialog * createGuiToc(GuiView & lv);
1426 Dialog * createGuiThesaurus(GuiView & lv);
1427 Dialog * createGuiHyperlink(GuiView & lv);
1428 Dialog * createGuiVSpace(GuiView & lv);
1429 Dialog * createGuiViewSource(GuiView & lv);
1430 Dialog * createGuiWrap(GuiView & lv);
1431
1432
1433 Dialog * GuiView::build(string const & name)
1434 {
1435         BOOST_ASSERT(isValidName(name));
1436
1437         if (name == "aboutlyx")
1438                 return createGuiAbout(*this);
1439         if (name == "bibitem")
1440                 return createGuiBibitem(*this);
1441         if (name == "bibtex")
1442                 return createGuiBibtex(*this);
1443         if (name == "box")
1444                 return createGuiBox(*this);
1445         if (name == "branch")
1446                 return createGuiBranch(*this);
1447         if (name == "changes")
1448                 return createGuiChanges(*this);
1449         if (name == "character")
1450                 return createGuiCharacter(*this);
1451         if (name == "citation")
1452                 return createGuiCitation(*this);
1453         if (name == "document")
1454                 return createGuiDocument(*this);
1455         if (name == "errorlist")
1456                 return createGuiErrorList(*this);
1457         if (name == "ert")
1458                 return createGuiERT(*this);
1459         if (name == "external")
1460                 return createGuiExternal(*this);
1461         if (name == "file")
1462                 return createGuiShowFile(*this);
1463         if (name == "findreplace")
1464                 return createGuiSearch(*this);
1465         if (name == "float")
1466                 return createGuiFloat(*this);
1467         if (name == "graphics")
1468                 return createGuiGraphics(*this);
1469         if (name == "include")
1470                 return createGuiInclude(*this);
1471         if (name == "index")
1472                 return createGuiIndex(*this);
1473         if (name == "nomenclature")
1474                 return createGuiNomenclature(*this);
1475         if (name == "label")
1476                 return createGuiLabel(*this);
1477         if (name == "log")
1478                 return createGuiLog(*this);
1479         if (name == "view-source")
1480                 return createGuiViewSource(*this);
1481         if (name == "mathdelimiter")
1482                 return createGuiDelimiter(*this);
1483         if (name == "mathmatrix")
1484                 return createGuiMathMatrix(*this);
1485         if (name == "note")
1486                 return createGuiNote(*this);
1487         if (name == "paragraph")
1488                 return createGuiParagraph(*this);
1489         if (name == "prefs")
1490                 return createGuiPreferences(*this);
1491         if (name == "print")
1492                 return createGuiPrint(*this);
1493         if (name == "ref")
1494                 return createGuiRef(*this);
1495         if (name == "sendto")
1496                 return createGuiSendTo(*this);
1497         if (name == "spellchecker")
1498                 return createGuiSpellchecker(*this);
1499         if (name == "tabular")
1500                 return createGuiTabular(*this);
1501         if (name == "tabularcreate")
1502                 return createGuiTabularCreate(*this);
1503         if (name == "texinfo")
1504                 return createGuiTexInfo(*this);
1505 #ifdef HAVE_LIBAIKSAURUS
1506         if (name == "thesaurus")
1507                 return createGuiThesaurus(*this);
1508 #endif
1509         if (name == "toc")
1510                 return createGuiToc(*this);
1511         if (name == "href")
1512                 return createGuiHyperlink(*this);
1513         if (name == "vspace")
1514                 return createGuiVSpace(*this);
1515         if (name == "wrap")
1516                 return createGuiWrap(*this);
1517         if (name == "listings")
1518                 return createGuiListings(*this);
1519
1520         return 0;
1521 }
1522
1523
1524 } // namespace frontend
1525 } // namespace lyx
1526
1527 #include "GuiView_moc.cpp"