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