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