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