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