]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
Handle full screen mode for all work areas.
[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 "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiWorkArea.h"
22 #include "GuiKeySymbol.h"
23 #include "GuiToolbar.h"
24 #include "GuiToolbars.h"
25 #include "Menus.h"
26
27 #include "qt_helpers.h"
28
29 #include "frontends/alert.h"
30
31 #include "buffer_funcs.h"
32 #include "Buffer.h"
33 #include "BufferList.h"
34 #include "BufferParams.h"
35 #include "BufferView.h"
36 #include "Converter.h"
37 #include "Cursor.h"
38 #include "ErrorList.h"
39 #include "Format.h"
40 #include "FuncRequest.h"
41 #include "support/gettext.h"
42 #include "Intl.h"
43 #include "Layout.h"
44 #include "Lexer.h"
45 #include "LyXFunc.h"
46 #include "LyX.h"
47 #include "LyXRC.h"
48 #include "LyXVC.h"
49 #include "Paragraph.h"
50 #include "TextClass.h"
51 #include "Text.h"
52 #include "ToolbarBackend.h"
53 #include "version.h"
54
55 #include "support/debug.h"
56 #include "support/FileFilterList.h"
57 #include "support/FileName.h"
58 #include "support/filetools.h"
59 #include "support/ForkedCalls.h"
60 #include "support/lstrings.h"
61 #include "support/os.h"
62 #include "support/Package.h"
63 #include "support/Timeout.h"
64
65 #include <QAction>
66 #include <QApplication>
67 #include <QCloseEvent>
68 #include <QDebug>
69 #include <QDesktopWidget>
70 #include <QDragEnterEvent>
71 #include <QDropEvent>
72 #include <QList>
73 #include <QMenu>
74 #include <QMenuBar>
75 #include <QPainter>
76 #include <QPixmap>
77 #include <QPoint>
78 #include <QPushButton>
79 #include <QSettings>
80 #include <QShowEvent>
81 #include <QSplitter>
82 #include <QStackedWidget>
83 #include <QStatusBar>
84 #include <QTimer>
85 #include <QToolBar>
86 #include <QUrl>
87
88 #include <boost/assert.hpp>
89 #include <boost/bind.hpp>
90
91 #ifdef HAVE_SYS_TIME_H
92 # include <sys/time.h>
93 #endif
94 #ifdef HAVE_UNISTD_H
95 # include <unistd.h>
96 #endif
97
98 using namespace std;
99 using namespace lyx::support;
100
101 namespace lyx {
102
103 extern bool quitting;
104
105 namespace frontend {
106
107 namespace {
108
109 class BackgroundWidget : public QWidget
110 {
111 public:
112         BackgroundWidget()
113         {
114                 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
115                 /// The text to be written on top of the pixmap
116                 QString const text = lyx_version ? lyx_version : qt_("unknown version");
117                 splash_ = QPixmap(":/images/banner.png");
118
119                 QPainter pain(&splash_);
120                 pain.setPen(QColor(255, 255, 0));
121                 QFont font;
122                 // The font used to display the version info
123                 font.setStyleHint(QFont::SansSerif);
124                 font.setWeight(QFont::Bold);
125                 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
126                 pain.setFont(font);
127                 pain.drawText(260, 270, text);
128         }
129
130         void paintEvent(QPaintEvent *)
131         {
132                 int x = (width() - splash_.width()) / 2;
133                 int y = (height() - splash_.height()) / 2;
134                 QPainter pain(this);
135                 pain.drawPixmap(x, y, splash_);
136         }
137
138 private:
139         QPixmap splash_;
140 };
141
142 } // namespace anon
143
144
145 typedef boost::shared_ptr<Dialog> DialogPtr;
146
147 struct GuiView::GuiViewPrivate
148 {
149         GuiViewPrivate()
150                 : current_work_area_(0), layout_(0),
151                 quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false)
152         {
153                 // hardcode here the platform specific icon size
154                 smallIconSize = 14;     // scaling problems
155                 normalIconSize = 20;    // ok, default
156                 bigIconSize = 26;               // better for some math icons
157
158                 splitter_ = new QSplitter;
159                 bg_widget_ = new BackgroundWidget;
160                 stack_widget_ = new QStackedWidget;
161                 stack_widget_->addWidget(bg_widget_);
162                 stack_widget_->addWidget(splitter_);
163                 setBackground();
164         }
165
166         ~GuiViewPrivate()
167         {
168                 delete splitter_;
169                 delete bg_widget_;
170                 delete stack_widget_;
171                 delete toolbars_;
172         }
173
174         QMenu * toolBarPopup(GuiView * parent)
175         {
176                 // FIXME: translation
177                 QMenu * menu = new QMenu(parent);
178                 QActionGroup * iconSizeGroup = new QActionGroup(parent);
179
180                 QAction * smallIcons = new QAction(iconSizeGroup);
181                 smallIcons->setText(qt_("Small-sized icons"));
182                 smallIcons->setCheckable(true);
183                 QObject::connect(smallIcons, SIGNAL(triggered()),
184                         parent, SLOT(smallSizedIcons()));
185                 menu->addAction(smallIcons);
186
187                 QAction * normalIcons = new QAction(iconSizeGroup);
188                 normalIcons->setText(qt_("Normal-sized icons"));
189                 normalIcons->setCheckable(true);
190                 QObject::connect(normalIcons, SIGNAL(triggered()),
191                         parent, SLOT(normalSizedIcons()));
192                 menu->addAction(normalIcons);
193
194                 QAction * bigIcons = new QAction(iconSizeGroup);
195                 bigIcons->setText(qt_("Big-sized icons"));
196                 bigIcons->setCheckable(true);
197                 QObject::connect(bigIcons, SIGNAL(triggered()),
198                         parent, SLOT(bigSizedIcons()));
199                 menu->addAction(bigIcons);
200
201                 unsigned int cur = parent->iconSize().width();
202                 if ( cur == parent->d.smallIconSize)
203                         smallIcons->setChecked(true);
204                 else if (cur == parent->d.normalIconSize)
205                         normalIcons->setChecked(true);
206                 else if (cur == parent->d.bigIconSize)
207                         bigIcons->setChecked(true);
208
209                 return menu;
210         }
211
212         void setBackground()
213         {
214                 stack_widget_->setCurrentWidget(bg_widget_);
215                 bg_widget_->setUpdatesEnabled(true);
216         }
217
218         TabWorkArea * tabWorkArea(int i)
219         {
220                 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
221         }
222
223         TabWorkArea * currentTabWorkArea()
224         {
225                 if (splitter_->count() == 1)
226                         // The first TabWorkArea is always the first one, if any.
227                         return tabWorkArea(0);
228
229                 TabWorkArea * tab_widget = 0;
230                 for (int i = 0; i != splitter_->count(); ++i) {
231                         QWidget * w = splitter_->widget(i);
232                         if (!w->hasFocus())
233                                 continue;
234                         tab_widget = dynamic_cast<TabWorkArea *>(w);
235                         if (tab_widget)
236                                 break;
237                 }
238
239                 return tab_widget;
240         }
241
242 public:
243         GuiWorkArea * current_work_area_;
244         QSplitter * splitter_;
245         QStackedWidget * stack_widget_;
246         BackgroundWidget * bg_widget_;
247         /// view's toolbars
248         GuiToolbars * toolbars_;
249         /// The main layout box.
250         /** 
251          * \warning Don't Delete! The layout box is actually owned by
252          * whichever toolbar contains it. All the GuiView class needs is a
253          * means of accessing it.
254          *
255          * FIXME: replace that with a proper model so that we are not limited
256          * to only one dialog.
257          */
258         GuiLayoutBox * layout_;
259
260         ///
261         map<string, Inset *> open_insets_;
262
263         ///
264         map<string, DialogPtr> dialogs_;
265
266         unsigned int smallIconSize;
267         unsigned int normalIconSize;
268         unsigned int bigIconSize;
269         ///
270         QTimer statusbar_timer_;
271         /// are we quitting by the menu?
272         bool quitting_by_menu_;
273         /// auto-saving of buffers
274         Timeout autosave_timeout_;
275         /// flag against a race condition due to multiclicks, see bug #1119
276         bool in_show_;
277 };
278
279
280 GuiView::GuiView(int id)
281         : d(*new GuiViewPrivate), id_(id)
282 {
283         // GuiToolbars *must* be initialised before the menu bar.
284         d.toolbars_ = new GuiToolbars(*this);
285
286         // Fill up the menu bar.
287         guiApp->menus().fillMenuBar(this);
288
289         setCentralWidget(d.stack_widget_);
290
291         // Start autosave timer
292         if (lyxrc.autosave) {
293                 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
294                 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
295                 d.autosave_timeout_.start();
296         }
297         connect(&d.statusbar_timer_, SIGNAL(timeout()),
298                 this, SLOT(clearMessage()));
299
300         // Qt bug? signal lastWindowClosed does not work
301         setAttribute(Qt::WA_QuitOnClose, false);
302         setAttribute(Qt::WA_DeleteOnClose, true);
303 #ifndef Q_WS_MACX
304         // assign an icon to main form. We do not do it under Qt/Mac,
305         // since the icon is provided in the application bundle.
306         setWindowIcon(QPixmap(":/images/lyx.png"));
307 #endif
308
309         // For Drag&Drop.
310         setAcceptDrops(true);
311
312         statusBar()->setSizeGripEnabled(true);
313
314         // Forbid too small unresizable window because it can happen
315         // with some window manager under X11.
316         setMinimumSize(300, 200);
317
318         if (!lyxrc.allow_geometry_session)
319                 // No session handling, default to a sane size.
320                 setGeometry(50, 50, 690, 510);
321
322         // Now take care of session management.
323         QSettings settings;
324         QString const key = "view-" + QString::number(id_);
325 #ifdef Q_WS_X11
326         QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
327         QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
328         resize(size);
329         move(pos);
330 #else
331         if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
332                 setGeometry(50, 50, 690, 510);
333 #endif
334         setIconSize(settings.value(key + "/icon_size").toSize());
335 }
336
337
338 GuiView::~GuiView()
339 {
340         delete &d;
341 }
342
343
344 void GuiView::close()
345 {
346         d.quitting_by_menu_ = true;
347         d.current_work_area_ = 0;
348         for (int i = 0; i != d.splitter_->count(); ++i) {
349                 TabWorkArea * twa = d.tabWorkArea(i);
350                 if (twa)
351                         twa->closeAll();
352         }
353         QMainWindow::close();
354         d.quitting_by_menu_ = false;
355 }
356
357
358 void GuiView::setFocus()
359 {
360         if (d.current_work_area_)
361                 d.current_work_area_->setFocus();
362         else
363                 QWidget::setFocus();
364 }
365
366
367 QMenu * GuiView::createPopupMenu()
368 {
369         return d.toolBarPopup(this);
370 }
371
372
373 void GuiView::showEvent(QShowEvent * e)
374 {
375         LYXERR(Debug::GUI, "Passed Geometry "
376                 << size().height() << "x" << size().width()
377                 << "+" << pos().x() << "+" << pos().y());
378
379         if (d.splitter_->count() == 0)
380                 // No work area, switch to the background widget.
381                 d.setBackground();
382
383         QMainWindow::showEvent(e);
384 }
385
386
387 void GuiView::closeEvent(QCloseEvent * close_event)
388 {
389         // we may have been called through the close window button
390         // which bypasses the LFUN machinery.
391         if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
392                 if (!quitWriteAll()) {
393                         close_event->ignore();
394                         return;
395                 }
396         }
397
398         // Make sure that no LFUN use this close to be closed View.
399         theLyXFunc().setLyXView(0);
400         // Make sure the timer time out will not trigger a statusbar update.
401         d.statusbar_timer_.stop();
402
403         if (lyxrc.allow_geometry_session) {
404                 QSettings settings;
405                 QString const key = "view-" + QString::number(id_);
406 #ifdef Q_WS_X11
407                 settings.setValue(key + "/pos", pos());
408                 settings.setValue(key + "/size", size());
409 #else
410                 settings.setValue(key + "/geometry", saveGeometry());
411 #endif
412                 settings.setValue(key + "/icon_size", iconSize());
413                 d.toolbars_->saveToolbarInfo();
414                 // Now take care of all other dialogs:
415                 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
416                 for (; it!= d.dialogs_.end(); ++it)
417                         it->second->saveSession();
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 = os::internal_path(fromqstr(
457                         files.at(i).toLocalFile()));
458                 if (!file.empty())
459                         lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
460         }
461 }
462
463
464 void GuiView::message(docstring const & str)
465 {
466         if (ForkedProcess::iAmAChild())
467                 return;
468
469         statusBar()->showMessage(toqstr(str));
470         d.statusbar_timer_.stop();
471         d.statusbar_timer_.start(3000);
472 }
473
474
475 void GuiView::smallSizedIcons()
476 {
477         setIconSize(QSize(d.smallIconSize, d.smallIconSize));
478 }
479
480
481 void GuiView::normalSizedIcons()
482 {
483         setIconSize(QSize(d.normalIconSize, d.normalIconSize));
484 }
485
486
487 void GuiView::bigSizedIcons()
488 {
489         setIconSize(QSize(d.bigIconSize, d.bigIconSize));
490 }
491
492
493 void GuiView::clearMessage()
494 {
495         if (!hasFocus())
496                 return;
497         theLyXFunc().setLyXView(this);
498         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
499         d.statusbar_timer_.stop();
500 }
501
502
503 void GuiView::updateWindowTitle(GuiWorkArea * wa)
504 {
505         if (wa != d.current_work_area_)
506                 return;
507         setWindowTitle(qt_("LyX: ") + wa->windowTitle());
508         setWindowIconText(wa->windowIconText());
509 }
510
511
512 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
513 {
514         disconnectBuffer();
515         disconnectBufferView();
516         connectBufferView(wa->bufferView());
517         connectBuffer(wa->bufferView().buffer());
518         d.current_work_area_ = wa;
519         QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
520                 this, SLOT(updateWindowTitle(GuiWorkArea *)));
521         updateWindowTitle(wa);
522
523         updateToc();
524         // Buffer-dependent dialogs should be updated or
525         // hidden. This should go here because some dialogs (eg ToC)
526         // require bv_->text.
527         updateBufferDependent(true);
528         updateToolbars();
529         updateLayoutList();
530         updateStatusBar();
531 }
532
533
534 void GuiView::updateStatusBar()
535 {
536         // let the user see the explicit message
537         if (d.statusbar_timer_.isActive())
538                 return;
539
540         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
541 }
542
543
544 bool GuiView::hasFocus() const
545 {
546         return qApp->activeWindow() == this;
547 }
548
549
550 bool GuiView::event(QEvent * e)
551 {
552         switch (e->type())
553         {
554         // Useful debug code:
555         //case QEvent::ActivationChange:
556         //case QEvent::WindowDeactivate:
557         //case QEvent::Paint:
558         //case QEvent::Enter:
559         //case QEvent::Leave:
560         //case QEvent::HoverEnter:
561         //case QEvent::HoverLeave:
562         //case QEvent::HoverMove:
563         //case QEvent::StatusTip:
564         //case QEvent::DragEnter:
565         //case QEvent::DragLeave:
566         //case QEvent::Drop:
567         //      break;
568
569         case QEvent::WindowActivate: {
570                 guiApp->setCurrentView(*this);
571                 if (d.current_work_area_) {
572                         BufferView & bv = d.current_work_area_->bufferView();
573                         connectBufferView(bv);
574                         connectBuffer(bv.buffer());
575                         // The document structure, name and dialogs might have
576                         // changed in another view.
577                         updateBufferDependent(true);
578                         updateToolbars();
579                         updateLayoutList();
580                         updateStatusBar();
581                 } else {
582                         setWindowTitle(qt_("LyX"));
583                         setWindowIconText(qt_("LyX"));
584                 }
585                 return QMainWindow::event(e);
586         }
587
588         case QEvent::ShortcutOverride: {
589                 if (d.current_work_area_)
590                         // Nothing special to do.
591                         return QMainWindow::event(e);
592
593                 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
594
595                 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
596                 // between controls.
597                 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab 
598                         || ke->key() == Qt::Key_Backtab)
599                         return QMainWindow::event(e);
600
601                 // Allow processing of shortcuts that are allowed even when no Buffer
602                 // is viewed.
603                 theLyXFunc().setLyXView(this);
604                 KeySymbol sym;
605                 setKeySymbol(&sym, ke);
606                 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
607                 e->accept();
608                 return true;
609         }
610
611         default:
612                 return QMainWindow::event(e);
613         }
614 }
615
616
617 bool GuiView::focusNextPrevChild(bool /*next*/)
618 {
619         setFocus();
620         return true;
621 }
622
623
624 void GuiView::setBusy(bool busy)
625 {
626         if (d.current_work_area_) {
627                 d.current_work_area_->setUpdatesEnabled(!busy);
628                 if (busy)
629                         d.current_work_area_->stopBlinkingCursor();
630                 else
631                         d.current_work_area_->startBlinkingCursor();
632         }
633
634         if (busy)
635                 QApplication::setOverrideCursor(Qt::WaitCursor);
636         else
637                 QApplication::restoreOverrideCursor();
638 }
639
640
641 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
642 {
643         GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
644
645         if (tbinfo.flags & ToolbarInfo::TOP) {
646                 if (newline)
647                         addToolBarBreak(Qt::TopToolBarArea);
648                 addToolBar(Qt::TopToolBarArea, toolBar);
649         }
650
651         if (tbinfo.flags & ToolbarInfo::BOTTOM) {
652 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
653 #if (QT_VERSION >= 0x040202)
654                 if (newline)
655                         addToolBarBreak(Qt::BottomToolBarArea);
656 #endif
657                 addToolBar(Qt::BottomToolBarArea, toolBar);
658         }
659
660         if (tbinfo.flags & ToolbarInfo::LEFT) {
661 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
662 #if (QT_VERSION >= 0x040202)
663                 if (newline)
664                         addToolBarBreak(Qt::LeftToolBarArea);
665 #endif
666                 addToolBar(Qt::LeftToolBarArea, toolBar);
667         }
668
669         if (tbinfo.flags & ToolbarInfo::RIGHT) {
670 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
671 #if (QT_VERSION >= 0x040202)
672                 if (newline)
673                         addToolBarBreak(Qt::RightToolBarArea);
674 #endif
675                 addToolBar(Qt::RightToolBarArea, toolBar);
676         }
677
678         // The following does not work so I cannot restore to exact toolbar location
679         /*
680         ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
681         toolBar->move(tbinfo.posx, tbinfo.posy);
682         */
683
684         return toolBar;
685 }
686
687
688 GuiWorkArea * GuiView::workArea(Buffer & buffer)
689 {
690         for (int i = 0; i != d.splitter_->count(); ++i) {
691                 GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
692                 if (wa)
693                         return wa;
694         }
695         return 0;
696 }
697
698
699 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
700 {
701
702         // Automatically create a TabWorkArea if there are none yet.
703         if (!d.splitter_->count())
704                 addTabWorkArea();
705
706         TabWorkArea * tab_widget = d.currentTabWorkArea();
707         return tab_widget->addWorkArea(buffer, *this);
708 }
709
710
711 void GuiView::addTabWorkArea()
712 {
713         TabWorkArea * twa = new TabWorkArea;
714         QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
715                 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
716         d.splitter_->addWidget(twa);
717         d.stack_widget_->setCurrentWidget(d.splitter_);
718 }
719
720
721 GuiWorkArea const * GuiView::currentWorkArea() const
722 {
723         return d.current_work_area_;
724 }
725
726
727 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
728 {
729         BOOST_ASSERT(wa);
730
731         // Changing work area can result from opening a file so
732         // update the toc in any case.
733         updateToc();
734
735         d.current_work_area_ = wa;
736         for (int i = 0; i != d.splitter_->count(); ++i) {
737                 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
738                         return;
739         }
740 }
741
742
743 void GuiView::removeWorkArea(GuiWorkArea * wa)
744 {
745         BOOST_ASSERT(wa);
746         if (wa == d.current_work_area_) {
747                 disconnectBuffer();
748                 disconnectBufferView();
749                 hideBufferDependent();
750                 d.current_work_area_ = 0;
751         }
752
753         for (int i = 0; i != d.splitter_->count(); ++i) {
754                 TabWorkArea * twa = d.tabWorkArea(i);
755                 if (!twa->removeWorkArea(wa))
756                         // Not found in this tab group.
757                         continue;
758
759                 // We found and removed the GuiWorkArea.
760                 if (!twa->count()) {
761                         // No more WorkAreas in this tab group, so delete it.
762                         delete twa;
763                         break;
764                 }
765
766                 if (d.current_work_area_)
767                         // This means that we are not closing the current GuiWorkArea;
768                         break;
769
770                 // Switch to the next GuiWorkArea in the found TabWorkArea.
771                 d.current_work_area_ = twa->currentWorkArea();
772                 break;
773         }
774
775         if (d.splitter_->count() == 0)
776                 // No more work area, switch to the background widget.
777                 d.setBackground();
778 }
779
780
781 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
782 {
783         d.layout_ = layout;
784 }
785
786
787 void GuiView::updateLayoutList()
788 {
789         if (d.layout_)
790                 d.layout_->updateContents(false);
791 }
792
793
794 void GuiView::updateToolbars()
795 {
796         if (d.current_work_area_) {
797                 bool const math =
798                         d.current_work_area_->bufferView().cursor().inMathed();
799                 bool const table =
800                         lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
801                 bool const review =
802                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
803                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
804                 bool const mathmacrotemplate =
805                         lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
806
807                 d.toolbars_->update(math, table, review, mathmacrotemplate);
808         } else
809                 d.toolbars_->update(false, false, false, false);
810
811         // update read-only status of open dialogs.
812         checkStatus();
813 }
814
815
816 Buffer * GuiView::buffer()
817 {
818         if (d.current_work_area_)
819                 return &d.current_work_area_->bufferView().buffer();
820         return 0;
821 }
822
823
824 Buffer const * GuiView::buffer() const
825 {
826         if (d.current_work_area_)
827                 return &d.current_work_area_->bufferView().buffer();
828         return 0;
829 }
830
831
832 void GuiView::setBuffer(Buffer * newBuffer)
833 {
834         BOOST_ASSERT(newBuffer);
835         setBusy(true);
836
837         GuiWorkArea * wa = workArea(*newBuffer);
838         if (wa == 0) {
839                 updateLabels(*newBuffer->masterBuffer());
840                 wa = addWorkArea(*newBuffer);
841         } else {
842                 //Disconnect the old buffer...there's no new one.
843                 disconnectBuffer();
844         }
845         connectBuffer(*newBuffer);
846         connectBufferView(wa->bufferView());
847         setCurrentWorkArea(wa);
848
849         setBusy(false);
850 }
851
852
853 void GuiView::connectBuffer(Buffer & buf)
854 {
855         buf.setGuiDelegate(this);
856 }
857
858
859 void GuiView::disconnectBuffer()
860 {
861         if (d.current_work_area_)
862                 d.current_work_area_->bufferView().setGuiDelegate(0);
863 }
864
865
866 void GuiView::connectBufferView(BufferView & bv)
867 {
868         bv.setGuiDelegate(this);
869 }
870
871
872 void GuiView::disconnectBufferView()
873 {
874         if (d.current_work_area_)
875                 d.current_work_area_->bufferView().setGuiDelegate(0);
876 }
877
878
879 void GuiView::errors(string const & error_type)
880 {
881         ErrorList & el = buffer()->errorList(error_type);
882         if (!el.empty())
883                 showDialog("errorlist", error_type);
884 }
885
886
887 void GuiView::updateDialog(string const & name, string const & data)
888 {
889         if (!isDialogVisible(name))
890                 return;
891
892         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
893         if (it == d.dialogs_.end())
894                 return;
895
896         Dialog * const dialog = it->second.get();
897         if (dialog->isVisibleView())
898                 dialog->updateData(data);
899 }
900
901
902 BufferView * GuiView::view()
903 {
904         return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
905 }
906
907
908 void GuiView::updateToc()
909 {
910         updateDialog("toc", "");
911 }
912
913
914 void GuiView::updateEmbeddedFiles()
915 {
916         updateDialog("embedding", "");
917 }
918
919
920 void GuiView::autoSave()
921 {
922         LYXERR(Debug::INFO, "Running autoSave()");
923
924         if (buffer())
925                 view()->buffer().autoSave();
926 }
927
928
929 void GuiView::resetAutosaveTimers()
930 {
931         if (lyxrc.autosave)
932                 d.autosave_timeout_.restart();
933 }
934
935
936 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
937 {
938         FuncStatus flag;
939         bool enable = true;
940         Buffer * buf = buffer();
941
942         /* In LyX/Mac, when a dialog is open, the menus of the
943            application can still be accessed without giving focus to
944            the main window. In this case, we want to disable the menu
945            entries that are buffer-related.
946
947            Note that this code is not perfect, as bug 1941 attests:
948            http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
949         */
950         if (cmd.origin == FuncRequest::MENU && !hasFocus())
951                 buf = 0;
952
953         switch(cmd.action) {
954         case LFUN_BUFFER_WRITE:
955                 enable = buf && (buf->isUnnamed() || !buf->isClean());
956                 break;
957
958         case LFUN_BUFFER_WRITE_AS:
959                 enable = buf;
960                 break;
961
962         case LFUN_TOOLBAR_TOGGLE:
963                 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
964                 break;
965
966         case LFUN_DIALOG_TOGGLE:
967                 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
968                 // fall through to set "enable"
969         case LFUN_DIALOG_SHOW: {
970                 string const name = cmd.getArg(0);
971                 if (!buf)
972                         enable = name == "aboutlyx"
973                                 || name == "file" //FIXME: should be removed.
974                                 || name == "prefs"
975                                 || name == "texinfo";
976                 else if (name == "print")
977                         enable = buf->isExportable("dvi")
978                                 && lyxrc.print_command != "none";
979                 else if (name == "character") {
980                         if (!view())
981                                 enable = false;
982                         else {
983                                 InsetCode ic = view()->cursor().inset().lyxCode();
984                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
985                         }
986                 }
987                 else if (name == "symbols") {
988                         if (!view() || view()->cursor().inMathed())
989                                 enable = false;
990                         else {
991                                 InsetCode ic = view()->cursor().inset().lyxCode();
992                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
993                         }
994                 }
995                 else if (name == "latexlog")
996                         enable = FileName(buf->logName()).isReadableFile();
997                 else if (name == "spellchecker")
998 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
999                         enable = !buf->isReadonly();
1000 #else
1001                         enable = false;
1002 #endif
1003                 else if (name == "vclog")
1004                         enable = buf->lyxvc().inUse();
1005                 break;
1006         }
1007
1008         case LFUN_DIALOG_UPDATE: {
1009                 string const name = cmd.getArg(0);
1010                 if (!buf)
1011                         enable = name == "prefs";
1012                 break;
1013         }
1014
1015         case LFUN_INSET_APPLY: {
1016                 if (!buf) {
1017                         enable = false;
1018                         break;
1019                 }
1020                 string const name = cmd.getArg(0);
1021                 Inset * inset = getOpenInset(name);
1022                 if (inset) {
1023                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1024                         FuncStatus fs;
1025                         if (!inset->getStatus(view()->cursor(), fr, fs)) {
1026                                 // Every inset is supposed to handle this
1027                                 BOOST_ASSERT(false);
1028                         }
1029                         flag |= fs;
1030                 } else {
1031                         FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1032                         flag |= getStatus(fr);
1033                 }
1034                 enable = flag.enabled();
1035                 break;
1036         }
1037
1038         default:
1039                 if (!view()) {
1040                         enable = false;
1041                         break;
1042                 }
1043         }
1044
1045         if (!enable)
1046                 flag.enabled(false);
1047
1048         return flag;
1049 }
1050
1051
1052 static FileName selectTemplateFile()
1053 {
1054         FileDialog dlg(_("Select template file"));
1055         dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1056         dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1057
1058         FileDialog::Result result =
1059                 dlg.open(from_utf8(lyxrc.template_path),
1060                              FileFilterList(_("LyX Documents (*.lyx)")),
1061                              docstring());
1062
1063         if (result.first == FileDialog::Later)
1064                 return FileName();
1065         if (result.second.empty())
1066                 return FileName();
1067         return FileName(to_utf8(result.second));
1068 }
1069
1070
1071 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1072 {
1073         setBusy(true);
1074
1075         Buffer * newBuffer = checkAndLoadLyXFile(filename);
1076
1077         if (!newBuffer) {
1078                 message(_("Document not loaded."));
1079                 setBusy(false);
1080                 return 0;
1081         }
1082
1083         setBuffer(newBuffer);
1084
1085         // scroll to the position when the file was last closed
1086         if (lyxrc.use_lastfilepos) {
1087                 LastFilePosSection::FilePos filepos =
1088                         LyX::ref().session().lastFilePos().load(filename);
1089                 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1090         }
1091
1092         if (tolastfiles)
1093                 LyX::ref().session().lastFiles().add(filename);
1094
1095         setBusy(false);
1096         return newBuffer;
1097 }
1098
1099
1100 void GuiView::openDocument(string const & fname)
1101 {
1102         string initpath = lyxrc.document_path;
1103
1104         if (buffer()) {
1105                 string const trypath = buffer()->filePath();
1106                 // If directory is writeable, use this as default.
1107                 if (FileName(trypath).isDirWritable())
1108                         initpath = trypath;
1109         }
1110
1111         string filename;
1112
1113         if (fname.empty()) {
1114                 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
1115                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1116                 dlg.setButton2(_("Examples|#E#e"),
1117                                 from_utf8(addPath(package().system_support().absFilename(), "examples")));
1118
1119                 FileDialog::Result result =
1120                         dlg.open(from_utf8(initpath),
1121                                      FileFilterList(_("LyX Documents (*.lyx)")),
1122                                      docstring());
1123
1124                 if (result.first == FileDialog::Later)
1125                         return;
1126
1127                 filename = to_utf8(result.second);
1128
1129                 // check selected filename
1130                 if (filename.empty()) {
1131                         message(_("Canceled."));
1132                         return;
1133                 }
1134         } else
1135                 filename = fname;
1136
1137         // get absolute path of file and add ".lyx" to the filename if
1138         // necessary. 
1139         FileName const fullname = 
1140                         fileSearch(string(), filename, "lyx", support::may_not_exist);
1141         if (!fullname.empty())
1142                 filename = fullname.absFilename();
1143
1144         // if the file doesn't exist, let the user create one
1145         if (!fullname.exists()) {
1146                 // the user specifically chose this name. Believe him.
1147                 Buffer * const b = newFile(filename, string(), true);
1148                 if (b)
1149                         setBuffer(b);
1150                 return;
1151         }
1152
1153         docstring const disp_fn = makeDisplayPath(filename);
1154         message(bformat(_("Opening document %1$s..."), disp_fn));
1155
1156         docstring str2;
1157         Buffer * buf = loadDocument(fullname);
1158         if (buf) {
1159                 updateLabels(*buf);
1160                 setBuffer(buf);
1161                 buf->errors("Parse");
1162                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1163         } else {
1164                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1165         }
1166         message(str2);
1167 }
1168
1169 // FIXME: clean that
1170 static bool import(GuiView * lv, FileName const & filename,
1171         string const & format, ErrorList & errorList)
1172 {
1173         FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
1174
1175         string loader_format;
1176         vector<string> loaders = theConverters().loaders();
1177         if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1178                 for (vector<string>::const_iterator it = loaders.begin();
1179                      it != loaders.end(); ++it) {
1180                         if (!theConverters().isReachable(format, *it))
1181                                 continue;
1182
1183                         string const tofile =
1184                                 changeExtension(filename.absFilename(),
1185                                 formats.extension(*it));
1186                         if (!theConverters().convert(0, filename, FileName(tofile),
1187                                 filename, format, *it, errorList))
1188                                 return false;
1189                         loader_format = *it;
1190                         break;
1191                 }
1192                 if (loader_format.empty()) {
1193                         frontend::Alert::error(_("Couldn't import file"),
1194                                      bformat(_("No information for importing the format %1$s."),
1195                                          formats.prettyName(format)));
1196                         return false;
1197                 }
1198         } else
1199                 loader_format = format;
1200
1201         if (loader_format == "lyx") {
1202                 Buffer * buf = lv->loadDocument(lyxfile);
1203                 if (!buf)
1204                         return false;
1205                 updateLabels(*buf);
1206                 lv->setBuffer(buf);
1207                 buf->errors("Parse");
1208         } else {
1209                 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1210                 if (!b)
1211                         return false;
1212                 lv->setBuffer(b);
1213                 bool as_paragraphs = loader_format == "textparagraph";
1214                 string filename2 = (loader_format == format) ? filename.absFilename()
1215                         : changeExtension(filename.absFilename(),
1216                                           formats.extension(loader_format));
1217                 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1218                 theLyXFunc().setLyXView(lv);
1219                 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1220         }
1221
1222         return true;
1223 }
1224
1225
1226 void GuiView::importDocument(string const & argument)
1227 {
1228         string format;
1229         string filename = split(argument, format, ' ');
1230
1231         LYXERR(Debug::INFO, format << " file: " << filename);
1232
1233         // need user interaction
1234         if (filename.empty()) {
1235                 string initpath = lyxrc.document_path;
1236
1237                 Buffer const * buf = buffer();
1238                 if (buf) {
1239                         string const trypath = buf->filePath();
1240                         // If directory is writeable, use this as default.
1241                         if (FileName(trypath).isDirWritable())
1242                                 initpath = trypath;
1243                 }
1244
1245                 docstring const text = bformat(_("Select %1$s file to import"),
1246                         formats.prettyName(format));
1247
1248                 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
1249                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1250                 dlg.setButton2(_("Examples|#E#e"),
1251                         from_utf8(addPath(package().system_support().absFilename(), "examples")));
1252
1253                 docstring filter = formats.prettyName(format);
1254                 filter += " (*.";
1255                 // FIXME UNICODE
1256                 filter += from_utf8(formats.extension(format));
1257                 filter += ')';
1258
1259                 FileDialog::Result result =
1260                         dlg.open(from_utf8(initpath),
1261                                      FileFilterList(filter),
1262                                      docstring());
1263
1264                 if (result.first == FileDialog::Later)
1265                         return;
1266
1267                 filename = to_utf8(result.second);
1268
1269                 // check selected filename
1270                 if (filename.empty())
1271                         message(_("Canceled."));
1272         }
1273
1274         if (filename.empty())
1275                 return;
1276
1277         // get absolute path of file
1278         FileName const fullname(makeAbsPath(filename));
1279
1280         FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
1281
1282         // Check if the document already is open
1283         Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1284         if (buf) {
1285                 setBuffer(buf);
1286                 if (!closeBuffer()) {
1287                         message(_("Canceled."));
1288                         return;
1289                 }
1290         }
1291
1292         docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1293
1294         // if the file exists already, and we didn't do
1295         // -i lyx thefile.lyx, warn
1296         if (lyxfile.exists() && fullname != lyxfile) {
1297
1298                 docstring text = bformat(_("The document %1$s already exists.\n\n"
1299                         "Do you want to overwrite that document?"), displaypath);
1300                 int const ret = Alert::prompt(_("Overwrite document?"),
1301                         text, 0, 1, _("&Overwrite"), _("&Cancel"));
1302
1303                 if (ret == 1) {
1304                         message(_("Canceled."));
1305                         return;
1306                 }
1307         }
1308
1309         message(bformat(_("Importing %1$s..."), displaypath));
1310         ErrorList errorList;
1311         if (import(this, fullname, format, errorList))
1312                 message(_("imported."));
1313         else
1314                 message(_("file not imported!"));
1315
1316         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1317 }
1318
1319
1320 void GuiView::newDocument(string const & filename, bool from_template)
1321 {
1322         FileName initpath(lyxrc.document_path);
1323         Buffer * buf = buffer();
1324         if (buf) {
1325                 FileName const trypath(buf->filePath());
1326                 // If directory is writeable, use this as default.
1327                 if (trypath.isDirWritable())
1328                         initpath = trypath;
1329         }
1330
1331         string templatefile = from_template ?
1332                 selectTemplateFile().absFilename() : string();
1333         Buffer * b;
1334         if (filename.empty())
1335                 b = newUnnamedFile(templatefile, initpath);
1336         else
1337                 b = newFile(filename, templatefile, true);
1338
1339         if (b)
1340                 setBuffer(b);
1341         // Ensure the cursor is correctly positionned on screen.
1342         view()->showCursor();
1343 }
1344
1345
1346 void GuiView::insertLyXFile(docstring const & fname)
1347 {
1348         BufferView * bv = view();
1349         if (!bv)
1350                 return;
1351
1352         // FIXME UNICODE
1353         FileName filename(to_utf8(fname));
1354         
1355         if (!filename.empty()) {
1356                 bv->insertLyXFile(filename);
1357                 return;
1358         }
1359
1360         // Launch a file browser
1361         // FIXME UNICODE
1362         string initpath = lyxrc.document_path;
1363         string const trypath = bv->buffer().filePath();
1364         // If directory is writeable, use this as default.
1365         if (FileName(trypath).isDirWritable())
1366                 initpath = trypath;
1367
1368         // FIXME UNICODE
1369         FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT);
1370         dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1371         dlg.setButton2(_("Examples|#E#e"),
1372                 from_utf8(addPath(package().system_support().absFilename(),
1373                 "examples")));
1374
1375         FileDialog::Result result =
1376                 dlg.open(from_utf8(initpath),
1377                              FileFilterList(_("LyX Documents (*.lyx)")),
1378                              docstring());
1379
1380         if (result.first == FileDialog::Later)
1381                 return;
1382
1383         // FIXME UNICODE
1384         filename.set(to_utf8(result.second));
1385
1386         // check selected filename
1387         if (filename.empty()) {
1388                 // emit message signal.
1389                 message(_("Canceled."));
1390                 return;
1391         }
1392
1393         bv->insertLyXFile(filename);
1394 }
1395
1396
1397 void GuiView::insertPlaintextFile(docstring const & fname,
1398         bool asParagraph)
1399 {
1400         BufferView * bv = view();
1401         if (!bv)
1402                 return;
1403
1404         // FIXME UNICODE
1405         FileName filename(to_utf8(fname));
1406         
1407         if (!filename.empty()) {
1408                 bv->insertPlaintextFile(filename, asParagraph);
1409                 return;
1410         }
1411
1412         FileDialog dlg(_("Select file to insert"), (asParagraph ?
1413                 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1414
1415         FileDialog::Result result = dlg.open(from_utf8(bv->buffer().filePath()),
1416                 FileFilterList(), docstring());
1417
1418         if (result.first == FileDialog::Later)
1419                 return;
1420
1421         // FIXME UNICODE
1422         filename.set(to_utf8(result.second));
1423
1424         // check selected filename
1425         if (filename.empty()) {
1426                 // emit message signal.
1427                 message(_("Canceled."));
1428                 return;
1429         }
1430
1431         bv->insertPlaintextFile(filename, asParagraph);
1432 }
1433
1434
1435 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1436 {
1437         FileName fname = b.fileName();
1438         FileName const oldname = fname;
1439
1440         if (!newname.empty()) {
1441                 // FIXME UNICODE
1442                 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1443         } else {
1444                 // Switch to this Buffer.
1445                 setBuffer(&b);
1446
1447                 /// No argument? Ask user through dialog.
1448                 // FIXME UNICODE
1449                 FileDialog dlg(_("Choose a filename to save document as"),
1450                                    LFUN_BUFFER_WRITE_AS);
1451                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1452                 dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1453
1454                 if (!isLyXFilename(fname.absFilename()))
1455                         fname.changeExtension(".lyx");
1456
1457                 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1458
1459                 FileDialog::Result result =
1460                         dlg.save(from_utf8(fname.onlyPath().absFilename()),
1461                                      filter,
1462                                      from_utf8(fname.onlyFileName()));
1463
1464                 if (result.first == FileDialog::Later)
1465                         return false;
1466
1467                 fname.set(to_utf8(result.second));
1468
1469                 if (fname.empty())
1470                         return false;
1471
1472                 if (!isLyXFilename(fname.absFilename()))
1473                         fname.changeExtension(".lyx");
1474         }
1475
1476         if (FileName(fname).exists()) {
1477                 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1478                 docstring text = bformat(_("The document %1$s already "
1479                                            "exists.\n\nDo you want to "
1480                                            "overwrite that document?"), 
1481                                          file);
1482                 int const ret = Alert::prompt(_("Overwrite document?"),
1483                         text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1484                 switch (ret) {
1485                 case 0: break;
1486                 case 1: return renameBuffer(b, docstring());
1487                 case 2: return false;
1488                 }
1489         }
1490
1491         // Ok, change the name of the buffer
1492         b.setFileName(fname.absFilename());
1493         b.markDirty();
1494         bool unnamed = b.isUnnamed();
1495         b.setUnnamed(false);
1496         b.saveCheckSum(fname);
1497
1498         if (!saveBuffer(b)) {
1499                 b.setFileName(oldname.absFilename());
1500                 b.setUnnamed(unnamed);
1501                 b.saveCheckSum(oldname);
1502                 return false;
1503         }
1504
1505         return true;
1506 }
1507
1508
1509 bool GuiView::saveBuffer(Buffer & b)
1510 {
1511         if (b.isUnnamed())
1512                 return renameBuffer(b, docstring());
1513
1514         if (b.save()) {
1515                 LyX::ref().session().lastFiles().add(b.fileName());
1516                 return true;
1517         }
1518
1519         // Switch to this Buffer.
1520         setBuffer(&b);
1521
1522         // FIXME: we don't tell the user *WHY* the save failed !!
1523         docstring const file = makeDisplayPath(b.absFileName(), 30);
1524         docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1525                                    "Do you want to rename the document and "
1526                                    "try again?"), file);
1527         int const ret = Alert::prompt(_("Rename and save?"),
1528                 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1529         switch (ret) {
1530         case 0:
1531                 if (!renameBuffer(b, docstring()))
1532                         return false;
1533                 break;
1534         case 1:
1535                 break;
1536         case 2:
1537                 return false;
1538         }
1539
1540         return saveBuffer(b);
1541 }
1542
1543
1544 bool GuiView::closeBuffer()
1545 {
1546         Buffer * buf = buffer();
1547         return buf && closeBuffer(*buf);
1548 }
1549
1550
1551 bool GuiView::closeBuffer(Buffer & buf)
1552 {
1553         if (buf.isClean() || buf.paragraphs().empty()) {
1554                 theBufferList().release(&buf);
1555                 return true;
1556         }
1557         // Switch to this Buffer.
1558         setBuffer(&buf);
1559
1560         docstring file;
1561         // FIXME: Unicode?
1562         if (buf.isUnnamed())
1563                 file = from_utf8(buf.fileName().onlyFileName());
1564         else
1565                 file = buf.fileName().displayName(30);
1566
1567         docstring const text = bformat(_("The document %1$s has unsaved changes."
1568                 "\n\nDo you want to save the document or discard the changes?"), file);
1569         int const ret = Alert::prompt(_("Save changed document?"),
1570                 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1571
1572         switch (ret) {
1573         case 0:
1574                 if (!saveBuffer(buf))
1575                         return false;
1576                 break;
1577         case 1:
1578                 // if we crash after this we could
1579                 // have no autosave file but I guess
1580                 // this is really improbable (Jug)
1581                 removeAutosaveFile(buf.absFileName());
1582                 break;
1583         case 2:
1584                 return false;
1585         }
1586
1587         // save file names to .lyx/session
1588         // if master/slave are both open, do not save slave since it
1589         // will be automatically loaded when the master is loaded
1590         if (buf.masterBuffer() == &buf)
1591                 LyX::ref().session().lastOpened().add(buf.fileName());
1592
1593         theBufferList().release(&buf);
1594         return true;
1595 }
1596
1597
1598 bool GuiView::quitWriteAll()
1599 {
1600         while (!theBufferList().empty()) {
1601                 Buffer * b = theBufferList().first();
1602                 if (!closeBuffer(*b))
1603                         return false;
1604         }
1605         return true;
1606 }
1607
1608
1609 bool GuiView::dispatch(FuncRequest const & cmd)
1610 {
1611         BufferView * bv = view();       
1612         // By default we won't need any update.
1613         if (bv)
1614                 bv->cursor().updateFlags(Update::None);
1615
1616         switch(cmd.action) {
1617                 case LFUN_FILE_OPEN:
1618                         openDocument(to_utf8(cmd.argument()));
1619                         break;
1620
1621                 case LFUN_BUFFER_IMPORT:
1622                         importDocument(to_utf8(cmd.argument()));
1623                         break;
1624
1625                 case LFUN_BUFFER_SWITCH:
1626                         setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1627                         break;
1628
1629                 case LFUN_BUFFER_NEXT:
1630                         setBuffer(theBufferList().next(buffer()));
1631                         break;
1632
1633                 case LFUN_BUFFER_PREVIOUS:
1634                         setBuffer(theBufferList().previous(buffer()));
1635                         break;
1636
1637                 case LFUN_COMMAND_EXECUTE: {
1638                         bool const show_it = cmd.argument() != "off";
1639                         d.toolbars_->showCommandBuffer(show_it);
1640                         break;
1641                 }
1642                 case LFUN_DROP_LAYOUTS_CHOICE:
1643                         if (d.layout_)
1644                                 d.layout_->showPopup();
1645                         break;
1646
1647                 case LFUN_MENU_OPEN:
1648                         if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument())))
1649                                 menu->exec(QCursor::pos());
1650                         break;
1651
1652                 case LFUN_FILE_INSERT:
1653                         insertLyXFile(cmd.argument());
1654                         break;
1655                 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1656                         insertPlaintextFile(cmd.argument(), true);
1657                         break;
1658
1659                 case LFUN_FILE_INSERT_PLAINTEXT:
1660                         insertPlaintextFile(cmd.argument(), false);
1661                         break;
1662
1663                 case LFUN_BUFFER_WRITE:
1664                         if (bv)
1665                                 saveBuffer(bv->buffer());
1666                         break;
1667
1668                 case LFUN_BUFFER_WRITE_AS:
1669                         if (bv)
1670                                 renameBuffer(bv->buffer(), cmd.argument());
1671                         break;
1672
1673                 case LFUN_BUFFER_WRITE_ALL: {
1674                         Buffer * first = theBufferList().first();
1675                         if (!first)
1676                                 break;
1677                         message(_("Saving all documents..."));
1678                         // We cannot use a for loop as the buffer list cycles.
1679                         Buffer * b = first;
1680                         do {
1681                                 if (b->isClean())
1682                                         continue;
1683                                 saveBuffer(*b);
1684                                 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1685                                 b = theBufferList().next(b);
1686                         } while (b != first); 
1687                         message(_("All documents saved."));
1688                         break;
1689                 }
1690
1691                 case LFUN_TOOLBAR_TOGGLE: {
1692                         string const name = cmd.getArg(0);
1693                         bool const allowauto = cmd.getArg(1) == "allowauto";
1694                         // it is possible to get current toolbar status like this,...
1695                         // but I decide to obey the order of ToolbarBackend::flags
1696                         // and disregard real toolbar status.
1697                         // toolbars_->saveToolbarInfo();
1698                         //
1699                         // toggle state on/off/auto
1700                         d.toolbars_->toggleToolbarState(name, allowauto);
1701                         // update toolbar
1702                         updateToolbars();
1703
1704                         ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1705                         if (!tbi) {
1706                                 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1707                                 break;
1708                         }
1709                         docstring state;
1710                         if (tbi->flags & ToolbarInfo::ON)
1711                                 state = _("on");
1712                         else if (tbi->flags & ToolbarInfo::OFF)
1713                                 state = _("off");
1714                         else if (tbi->flags & ToolbarInfo::AUTO)
1715                                 state = _("auto");
1716
1717                         message(bformat(_("Toolbar \"%1$s\" state set to %2$s"), 
1718                                            _(tbi->gui_name), state));
1719                         break;
1720                 }
1721
1722                 case LFUN_DIALOG_UPDATE: {
1723                         string const name = to_utf8(cmd.argument());
1724                         // Can only update a dialog connected to an existing inset
1725                         Inset * inset = getOpenInset(name);
1726                         if (inset) {
1727                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1728                                 inset->dispatch(view()->cursor(), fr);
1729                         } else if (name == "paragraph") {
1730                                 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1731                         } else if (name == "prefs") {
1732                                 updateDialog(name, string());
1733                         }
1734                         break;
1735                 }
1736
1737                 case LFUN_DIALOG_TOGGLE: {
1738                         if (isDialogVisible(cmd.getArg(0)))
1739                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1740                         else
1741                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1742                         break;
1743                 }
1744
1745                 case LFUN_DIALOG_DISCONNECT_INSET:
1746                         disconnectDialog(to_utf8(cmd.argument()));
1747                         break;
1748
1749                 case LFUN_DIALOG_HIDE: {
1750                         if (quitting)
1751                                 break;
1752                         guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1753                         break;
1754                 }
1755
1756                 case LFUN_DIALOG_SHOW: {
1757                         string const name = cmd.getArg(0);
1758                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1759
1760                         if (name == "character") {
1761                                 data = freefont2string();
1762                                 if (!data.empty())
1763                                         showDialog("character", data);
1764                         } else if (name == "latexlog") {
1765                                 Buffer::LogType type; 
1766                                 string const logfile = buffer()->logName(&type);
1767                                 switch (type) {
1768                                 case Buffer::latexlog:
1769                                         data = "latex ";
1770                                         break;
1771                                 case Buffer::buildlog:
1772                                         data = "literate ";
1773                                         break;
1774                                 }
1775                                 data += Lexer::quoteString(logfile);
1776                                 showDialog("log", data);
1777                         } else if (name == "vclog") {
1778                                 string const data = "vc " +
1779                                         Lexer::quoteString(buffer()->lyxvc().getLogFile());
1780                                 showDialog("log", data);
1781                         } else if (name == "symbols") {
1782                                 data = bv->cursor().getEncoding()->name();
1783                                 if (!data.empty())
1784                                         showDialog("symbols", data);
1785                         } else
1786                                 showDialog(name, data);
1787                         break;
1788                 }
1789
1790                 case LFUN_INSET_APPLY: {
1791                         string const name = cmd.getArg(0);
1792                         Inset * inset = getOpenInset(name);
1793                         if (inset) {
1794                                 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1795                                 inset->dispatch(view()->cursor(), fr);
1796                         } else {
1797                                 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1798                                 lyx::dispatch(fr);
1799                         }
1800                         break;
1801                 }
1802
1803                 case LFUN_UI_TOGGLE:
1804                         lfunUiToggle(cmd);
1805                         break;
1806
1807                 default:
1808                         return false;
1809         }
1810
1811         return true;
1812 }
1813
1814
1815 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1816 {
1817         string const arg = cmd.getArg(0);
1818         if (arg == "statusbar") {
1819                 statusBar()->setVisible(!statusBar()->isVisible());
1820                 return;
1821         }
1822         if (arg == "menubar") {
1823                 menuBar()->setVisible(!menuBar()->isVisible());
1824                 return;
1825         }
1826 #if QT_VERSION >= 0x040300
1827         if (arg == "frame") {
1828                 int l, t, r, b;
1829                 getContentsMargins(&l, &t, &r, &b);
1830                 //are the frames in default state?
1831                 if (l == 0) {
1832                         d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1833                         setContentsMargins(-2, -2, -2, -2);
1834                 } else {
1835                         d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1836                         setContentsMargins(0, 0, 0, 0);
1837                 }
1838                 return;
1839         }
1840 #endif
1841         if (arg != "fullscreen") {
1842                 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1843                 return;
1844         }
1845
1846         if (isFullScreen()) {
1847                 showNormal();
1848 #if QT_VERSION >= 0x040300
1849                 setContentsMargins(0, 0, 0, 0);
1850 #endif
1851                 for (int i = 0; i != d.splitter_->count(); ++i)
1852                         d.tabWorkArea(i)->setFullScreen(false);
1853                 menuBar()->show();
1854                 statusBar()->show();
1855         } else {
1856                 statusBar()->hide();
1857                 menuBar()->hide();
1858                 for (int i = 0; i != d.splitter_->count(); ++i)
1859                         d.tabWorkArea(i)->setFullScreen(true);
1860 #if QT_VERSION >= 0x040300
1861                 setContentsMargins(-2, -2, -2, -2);
1862 #endif
1863                 showFullScreen();
1864         }
1865 }
1866
1867
1868 Buffer const * GuiView::updateInset(Inset const * inset)
1869 {
1870         if (!d.current_work_area_)
1871                 return 0;
1872
1873         if (inset)
1874                 d.current_work_area_->scheduleRedraw();
1875
1876         return &d.current_work_area_->bufferView().buffer();
1877 }
1878
1879
1880 void GuiView::restartCursor()
1881 {
1882         /* When we move around, or type, it's nice to be able to see
1883          * the cursor immediately after the keypress.
1884          */
1885         if (d.current_work_area_)
1886                 d.current_work_area_->startBlinkingCursor();
1887
1888         // Take this occasion to update the toobars and layout list.
1889         updateLayoutList();
1890         updateToolbars();
1891 }
1892
1893 namespace {
1894
1895 // This list should be kept in sync with the list of insets in
1896 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
1897 // dialog should have the same name as the inset.
1898
1899 char const * const dialognames[] = {
1900 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1901 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1902 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1903 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", 
1904 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1905
1906 #ifdef HAVE_LIBAIKSAURUS
1907 "thesaurus",
1908 #endif
1909
1910 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1911
1912 char const * const * const end_dialognames =
1913         dialognames + (sizeof(dialognames) / sizeof(char *));
1914
1915 class cmpCStr {
1916 public:
1917         cmpCStr(char const * name) : name_(name) {}
1918         bool operator()(char const * other) {
1919                 return strcmp(other, name_) == 0;
1920         }
1921 private:
1922         char const * name_;
1923 };
1924
1925
1926 bool isValidName(string const & name)
1927 {
1928         return find_if(dialognames, end_dialognames,
1929                             cmpCStr(name.c_str())) != end_dialognames;
1930 }
1931
1932 } // namespace anon
1933
1934
1935 void GuiView::resetDialogs()
1936 {
1937         // Make sure that no LFUN uses any LyXView.
1938         theLyXFunc().setLyXView(0);
1939         // FIXME: the "math panels" toolbar takes an awful lot of time to
1940         // initialise so we don't do that for the time being.
1941         //d.toolbars_->init();
1942         guiApp->menus().fillMenuBar(this);
1943         if (d.layout_)
1944                 d.layout_->updateContents(true);
1945         // Now update controls with current buffer.
1946         theLyXFunc().setLyXView(this);
1947         restartCursor();
1948 }
1949
1950
1951 Dialog * GuiView::find_or_build(string const & name)
1952 {
1953         if (!isValidName(name))
1954                 return 0;
1955
1956         map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1957
1958         if (it != d.dialogs_.end())
1959                 return it->second.get();
1960
1961         Dialog * dialog = build(name);
1962         d.dialogs_[name].reset(dialog);
1963         if (lyxrc.allow_geometry_session)
1964                 dialog->restoreSession();
1965         return dialog;
1966 }
1967
1968
1969 void GuiView::showDialog(string const & name, string const & data,
1970         Inset * inset)
1971 {
1972         if (d.in_show_)
1973                 return;
1974
1975         d.in_show_ = true;
1976         Dialog * dialog = find_or_build(name);
1977         if (dialog) {
1978                 dialog->showData(data);
1979                 if (inset)
1980                         d.open_insets_[name] = inset;
1981         }
1982         d.in_show_ = false;
1983 }
1984
1985
1986 bool GuiView::isDialogVisible(string const & name) const
1987 {
1988         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1989         if (it == d.dialogs_.end())
1990                 return false;
1991         return it->second.get()->isVisibleView();
1992 }
1993
1994
1995 void GuiView::hideDialog(string const & name, Inset * inset)
1996 {
1997         // Don't send the signal if we are quitting, because on MSVC it is
1998         // destructed before the cut stack in CutAndPaste.cpp, and this method
1999         // is called from some inset destructor if the cut stack is not empty
2000         // on exit.
2001         if (quitting)
2002                 return;
2003
2004         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2005         if (it == d.dialogs_.end())
2006                 return;
2007
2008         if (inset && inset != getOpenInset(name))
2009                 return;
2010
2011         Dialog * const dialog = it->second.get();
2012         if (dialog->isVisibleView())
2013                 dialog->hideView();
2014         d.open_insets_[name] = 0;
2015 }
2016
2017
2018 void GuiView::disconnectDialog(string const & name)
2019 {
2020         if (!isValidName(name))
2021                 return;
2022
2023         if (d.open_insets_.find(name) != d.open_insets_.end())
2024                 d.open_insets_[name] = 0;
2025 }
2026
2027
2028 Inset * GuiView::getOpenInset(string const & name) const
2029 {
2030         if (!isValidName(name))
2031                 return 0;
2032
2033         map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2034         return it == d.open_insets_.end() ? 0 : it->second;
2035 }
2036
2037
2038 void GuiView::hideAll() const
2039 {
2040         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2041         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2042
2043         for(; it != end; ++it)
2044                 it->second->hideView();
2045 }
2046
2047
2048 void GuiView::hideBufferDependent() const
2049 {
2050         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2051         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2052
2053         for(; it != end; ++it) {
2054                 Dialog * dialog = it->second.get();
2055                 if (dialog->isBufferDependent())
2056                         dialog->hideView();
2057         }
2058 }
2059
2060
2061 void GuiView::updateBufferDependent(bool switched) const
2062 {
2063         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2064         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2065
2066         for(; it != end; ++it) {
2067                 Dialog * dialog = it->second.get();
2068                 if (!dialog->isVisibleView())
2069                         continue;
2070                 if (switched && dialog->isBufferDependent()) {
2071                         if (dialog->initialiseParams(""))
2072                                 dialog->updateView();
2073                         else
2074                                 dialog->hideView();
2075                 } else {
2076                         // A bit clunky, but the dialog will request
2077                         // that the kernel provides it with the necessary
2078                         // data.
2079                         dialog->updateDialog();
2080                 }
2081         }
2082 }
2083
2084
2085 void GuiView::checkStatus()
2086 {
2087         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2088         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2089
2090         for(; it != end; ++it) {
2091                 Dialog * const dialog = it->second.get();
2092                 if (dialog && dialog->isVisibleView())
2093                         dialog->checkStatus();
2094         }
2095 }
2096
2097
2098
2099 // will be replaced by a proper factory...
2100 Dialog * createGuiAbout(GuiView & lv);
2101 Dialog * createGuiBibitem(GuiView & lv);
2102 Dialog * createGuiBibtex(GuiView & lv);
2103 Dialog * createGuiBox(GuiView & lv);
2104 Dialog * createGuiBranch(GuiView & lv);
2105 Dialog * createGuiChanges(GuiView & lv);
2106 Dialog * createGuiCharacter(GuiView & lv);
2107 Dialog * createGuiCitation(GuiView & lv);
2108 Dialog * createGuiDelimiter(GuiView & lv);
2109 Dialog * createGuiDocument(GuiView & lv);
2110 Dialog * createGuiErrorList(GuiView & lv);
2111 Dialog * createGuiERT(GuiView & lv);
2112 Dialog * createGuiExternal(GuiView & lv);
2113 Dialog * createGuiFloat(GuiView & lv);
2114 Dialog * createGuiGraphics(GuiView & lv);
2115 Dialog * createGuiInclude(GuiView & lv);
2116 Dialog * createGuiIndex(GuiView & lv);
2117 Dialog * createGuiLabel(GuiView & lv);
2118 Dialog * createGuiListings(GuiView & lv);
2119 Dialog * createGuiLog(GuiView & lv);
2120 Dialog * createGuiMathMatrix(GuiView & lv);
2121 Dialog * createGuiNomenclature(GuiView & lv);
2122 Dialog * createGuiNote(GuiView & lv);
2123 Dialog * createGuiParagraph(GuiView & lv);
2124 Dialog * createGuiPreferences(GuiView & lv);
2125 Dialog * createGuiPrint(GuiView & lv);
2126 Dialog * createGuiRef(GuiView & lv);
2127 Dialog * createGuiSearch(GuiView & lv);
2128 Dialog * createGuiSendTo(GuiView & lv);
2129 Dialog * createGuiShowFile(GuiView & lv);
2130 Dialog * createGuiSpellchecker(GuiView & lv);
2131 Dialog * createGuiSymbols(GuiView & lv);
2132 Dialog * createGuiTabularCreate(GuiView & lv);
2133 Dialog * createGuiTabular(GuiView & lv);
2134 Dialog * createGuiTexInfo(GuiView & lv);
2135 Dialog * createGuiToc(GuiView & lv);
2136 Dialog * createGuiThesaurus(GuiView & lv);
2137 Dialog * createGuiHyperlink(GuiView & lv);
2138 Dialog * createGuiVSpace(GuiView & lv);
2139 Dialog * createGuiViewSource(GuiView & lv);
2140 Dialog * createGuiWrap(GuiView & lv);
2141
2142
2143 Dialog * GuiView::build(string const & name)
2144 {
2145         BOOST_ASSERT(isValidName(name));
2146
2147         if (name == "aboutlyx")
2148                 return createGuiAbout(*this);
2149         if (name == "bibitem")
2150                 return createGuiBibitem(*this);
2151         if (name == "bibtex")
2152                 return createGuiBibtex(*this);
2153         if (name == "box")
2154                 return createGuiBox(*this);
2155         if (name == "branch")
2156                 return createGuiBranch(*this);
2157         if (name == "changes")
2158                 return createGuiChanges(*this);
2159         if (name == "character")
2160                 return createGuiCharacter(*this);
2161         if (name == "citation")
2162                 return createGuiCitation(*this);
2163         if (name == "document")
2164                 return createGuiDocument(*this);
2165         if (name == "errorlist")
2166                 return createGuiErrorList(*this);
2167         if (name == "ert")
2168                 return createGuiERT(*this);
2169         if (name == "external")
2170                 return createGuiExternal(*this);
2171         if (name == "file")
2172                 return createGuiShowFile(*this);
2173         if (name == "findreplace")
2174                 return createGuiSearch(*this);
2175         if (name == "float")
2176                 return createGuiFloat(*this);
2177         if (name == "graphics")
2178                 return createGuiGraphics(*this);
2179         if (name == "include")
2180                 return createGuiInclude(*this);
2181         if (name == "index")
2182                 return createGuiIndex(*this);
2183         if (name == "nomenclature")
2184                 return createGuiNomenclature(*this);
2185         if (name == "label")
2186                 return createGuiLabel(*this);
2187         if (name == "log")
2188                 return createGuiLog(*this);
2189         if (name == "view-source")
2190                 return createGuiViewSource(*this);
2191         if (name == "mathdelimiter")
2192                 return createGuiDelimiter(*this);
2193         if (name == "mathmatrix")
2194                 return createGuiMathMatrix(*this);
2195         if (name == "note")
2196                 return createGuiNote(*this);
2197         if (name == "paragraph")
2198                 return createGuiParagraph(*this);
2199         if (name == "prefs")
2200                 return createGuiPreferences(*this);
2201         if (name == "print")
2202                 return createGuiPrint(*this);
2203         if (name == "ref")
2204                 return createGuiRef(*this);
2205         if (name == "sendto")
2206                 return createGuiSendTo(*this);
2207         if (name == "spellchecker")
2208                 return createGuiSpellchecker(*this);
2209         if (name == "symbols")
2210                 return createGuiSymbols(*this);
2211         if (name == "tabular")
2212                 return createGuiTabular(*this);
2213         if (name == "tabularcreate")
2214                 return createGuiTabularCreate(*this);
2215         if (name == "texinfo")
2216                 return createGuiTexInfo(*this);
2217 #ifdef HAVE_LIBAIKSAURUS
2218         if (name == "thesaurus")
2219                 return createGuiThesaurus(*this);
2220 #endif
2221         if (name == "toc")
2222                 return createGuiToc(*this);
2223         if (name == "href")
2224                 return createGuiHyperlink(*this);
2225         if (name == "vspace")
2226                 return createGuiVSpace(*this);
2227         if (name == "wrap")
2228                 return createGuiWrap(*this);
2229         if (name == "listings")
2230                 return createGuiListings(*this);
2231
2232         return 0;
2233 }
2234
2235
2236 } // namespace frontend
2237 } // namespace lyx
2238
2239 #include "GuiView_moc.cpp"