]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
c51f7176bbcc1b231d681c97054633658125f455
[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_CLOSE_TAB_GROUP:
968                 enable = d.currentTabWorkArea();
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                 case LFUN_SPLIT_VIEW:
1819                         if (Buffer * buf = buffer()) {
1820                                 string const orientation = cmd.getArg(0);
1821                                 d.splitter_->setOrientation(orientation == "vertical"
1822                                         ? Qt::Vertical : Qt::Horizontal);
1823                                 TabWorkArea * twa = addTabWorkArea();
1824                                 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1825                                 setCurrentWorkArea(wa);
1826                         }
1827                         break;
1828
1829                 case LFUN_CLOSE_TAB_GROUP:
1830                         if (TabWorkArea * twa = d.currentTabWorkArea())
1831                                 delete twa;
1832                         break;
1833
1834                 default:
1835                         return false;
1836         }
1837
1838         return true;
1839 }
1840
1841
1842 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1843 {
1844         string const arg = cmd.getArg(0);
1845         if (arg == "scrollbar") {
1846                 // hide() is of no help
1847                 if (d.current_work_area_->verticalScrollBarPolicy() ==
1848                         Qt::ScrollBarAlwaysOff)
1849
1850                         d.current_work_area_->setVerticalScrollBarPolicy(
1851                                 Qt::ScrollBarAsNeeded);
1852                 else
1853                         d.current_work_area_->setVerticalScrollBarPolicy(
1854                                 Qt::ScrollBarAlwaysOff);
1855                 return;
1856         }
1857         if (arg == "statusbar") {
1858                 statusBar()->setVisible(!statusBar()->isVisible());
1859                 return;
1860         }
1861         if (arg == "menubar") {
1862                 menuBar()->setVisible(!menuBar()->isVisible());
1863                 return;
1864         }
1865 #if QT_VERSION >= 0x040300
1866         if (arg == "frame") {
1867                 int l, t, r, b;
1868                 getContentsMargins(&l, &t, &r, &b);
1869                 //are the frames in default state?
1870                 if (l == 0) {
1871                         d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1872                         setContentsMargins(-2, -2, -2, -2);
1873                 } else {
1874                         d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1875                         setContentsMargins(0, 0, 0, 0);
1876                 }
1877                 return;
1878         }
1879 #endif
1880         if (arg != "fullscreen") {
1881                 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1882                 return;
1883         }
1884
1885         if (lyxrc.full_screen_toolbars)
1886                 d.toolbars_->toggleFullScreen(!isFullScreen());
1887
1888         if (isFullScreen()) {
1889                 for (int i = 0; i != d.splitter_->count(); ++i)
1890                         d.tabWorkArea(i)->setFullScreen(false);
1891 #if QT_VERSION >= 0x040300
1892                 setContentsMargins(0, 0, 0, 0);
1893 #endif
1894                 showNormal();
1895                 menuBar()->show();
1896                 statusBar()->show();
1897         } else {
1898                 for (int i = 0; i != d.splitter_->count(); ++i)
1899                         d.tabWorkArea(i)->setFullScreen(true);
1900 #if QT_VERSION >= 0x040300
1901                 setContentsMargins(-2, -2, -2, -2);
1902 #endif
1903                 showFullScreen();
1904                 statusBar()->hide();
1905                 menuBar()->hide();
1906         }
1907 }
1908
1909
1910 Buffer const * GuiView::updateInset(Inset const * inset)
1911 {
1912         if (!d.current_work_area_)
1913                 return 0;
1914
1915         if (inset)
1916                 d.current_work_area_->scheduleRedraw();
1917
1918         return &d.current_work_area_->bufferView().buffer();
1919 }
1920
1921
1922 void GuiView::restartCursor()
1923 {
1924         /* When we move around, or type, it's nice to be able to see
1925          * the cursor immediately after the keypress.
1926          */
1927         if (d.current_work_area_)
1928                 d.current_work_area_->startBlinkingCursor();
1929
1930         // Take this occasion to update the toobars and layout list.
1931         updateLayoutList();
1932         updateToolbars();
1933 }
1934
1935 namespace {
1936
1937 // This list should be kept in sync with the list of insets in
1938 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
1939 // dialog should have the same name as the inset.
1940
1941 char const * const dialognames[] = {
1942 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1943 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1944 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1945 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", 
1946 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1947
1948 #ifdef HAVE_LIBAIKSAURUS
1949 "thesaurus",
1950 #endif
1951
1952 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1953
1954 char const * const * const end_dialognames =
1955         dialognames + (sizeof(dialognames) / sizeof(char *));
1956
1957 class cmpCStr {
1958 public:
1959         cmpCStr(char const * name) : name_(name) {}
1960         bool operator()(char const * other) {
1961                 return strcmp(other, name_) == 0;
1962         }
1963 private:
1964         char const * name_;
1965 };
1966
1967
1968 bool isValidName(string const & name)
1969 {
1970         return find_if(dialognames, end_dialognames,
1971                             cmpCStr(name.c_str())) != end_dialognames;
1972 }
1973
1974 } // namespace anon
1975
1976
1977 void GuiView::resetDialogs()
1978 {
1979         // Make sure that no LFUN uses any LyXView.
1980         theLyXFunc().setLyXView(0);
1981         // FIXME: the "math panels" toolbar takes an awful lot of time to
1982         // initialise so we don't do that for the time being.
1983         //d.toolbars_->init();
1984         guiApp->menus().fillMenuBar(this);
1985         if (d.layout_)
1986                 d.layout_->updateContents(true);
1987         // Now update controls with current buffer.
1988         theLyXFunc().setLyXView(this);
1989         restartCursor();
1990 }
1991
1992
1993 Dialog * GuiView::find_or_build(string const & name)
1994 {
1995         if (!isValidName(name))
1996                 return 0;
1997
1998         map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1999
2000         if (it != d.dialogs_.end())
2001                 return it->second.get();
2002
2003         Dialog * dialog = build(name);
2004         d.dialogs_[name].reset(dialog);
2005         if (lyxrc.allow_geometry_session)
2006                 dialog->restoreSession();
2007         return dialog;
2008 }
2009
2010
2011 void GuiView::showDialog(string const & name, string const & data,
2012         Inset * inset)
2013 {
2014         if (d.in_show_)
2015                 return;
2016
2017         d.in_show_ = true;
2018         Dialog * dialog = find_or_build(name);
2019         if (dialog) {
2020                 dialog->showData(data);
2021                 if (inset)
2022                         d.open_insets_[name] = inset;
2023         }
2024         d.in_show_ = false;
2025 }
2026
2027
2028 bool GuiView::isDialogVisible(string const & name) const
2029 {
2030         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2031         if (it == d.dialogs_.end())
2032                 return false;
2033         return it->second.get()->isVisibleView();
2034 }
2035
2036
2037 void GuiView::hideDialog(string const & name, Inset * inset)
2038 {
2039         // Don't send the signal if we are quitting, because on MSVC it is
2040         // destructed before the cut stack in CutAndPaste.cpp, and this method
2041         // is called from some inset destructor if the cut stack is not empty
2042         // on exit.
2043         if (quitting)
2044                 return;
2045
2046         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2047         if (it == d.dialogs_.end())
2048                 return;
2049
2050         if (inset && inset != getOpenInset(name))
2051                 return;
2052
2053         Dialog * const dialog = it->second.get();
2054         if (dialog->isVisibleView())
2055                 dialog->hideView();
2056         d.open_insets_[name] = 0;
2057 }
2058
2059
2060 void GuiView::disconnectDialog(string const & name)
2061 {
2062         if (!isValidName(name))
2063                 return;
2064
2065         if (d.open_insets_.find(name) != d.open_insets_.end())
2066                 d.open_insets_[name] = 0;
2067 }
2068
2069
2070 Inset * GuiView::getOpenInset(string const & name) const
2071 {
2072         if (!isValidName(name))
2073                 return 0;
2074
2075         map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2076         return it == d.open_insets_.end() ? 0 : it->second;
2077 }
2078
2079
2080 void GuiView::hideAll() const
2081 {
2082         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2083         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2084
2085         for(; it != end; ++it)
2086                 it->second->hideView();
2087 }
2088
2089
2090 void GuiView::hideBufferDependent() const
2091 {
2092         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2093         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2094
2095         for(; it != end; ++it) {
2096                 Dialog * dialog = it->second.get();
2097                 if (dialog->isBufferDependent())
2098                         dialog->hideView();
2099         }
2100 }
2101
2102
2103 void GuiView::updateBufferDependent(bool switched) const
2104 {
2105         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2106         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2107
2108         for(; it != end; ++it) {
2109                 Dialog * dialog = it->second.get();
2110                 if (!dialog->isVisibleView())
2111                         continue;
2112                 if (switched && dialog->isBufferDependent()) {
2113                         if (dialog->initialiseParams(""))
2114                                 dialog->updateView();
2115                         else
2116                                 dialog->hideView();
2117                 } else {
2118                         // A bit clunky, but the dialog will request
2119                         // that the kernel provides it with the necessary
2120                         // data.
2121                         dialog->updateDialog();
2122                 }
2123         }
2124 }
2125
2126
2127 void GuiView::checkStatus()
2128 {
2129         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2130         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2131
2132         for(; it != end; ++it) {
2133                 Dialog * const dialog = it->second.get();
2134                 if (dialog && dialog->isVisibleView())
2135                         dialog->checkStatus();
2136         }
2137 }
2138
2139
2140
2141 // will be replaced by a proper factory...
2142 Dialog * createGuiAbout(GuiView & lv);
2143 Dialog * createGuiBibitem(GuiView & lv);
2144 Dialog * createGuiBibtex(GuiView & lv);
2145 Dialog * createGuiBox(GuiView & lv);
2146 Dialog * createGuiBranch(GuiView & lv);
2147 Dialog * createGuiChanges(GuiView & lv);
2148 Dialog * createGuiCharacter(GuiView & lv);
2149 Dialog * createGuiCitation(GuiView & lv);
2150 Dialog * createGuiDelimiter(GuiView & lv);
2151 Dialog * createGuiDocument(GuiView & lv);
2152 Dialog * createGuiErrorList(GuiView & lv);
2153 Dialog * createGuiERT(GuiView & lv);
2154 Dialog * createGuiExternal(GuiView & lv);
2155 Dialog * createGuiFloat(GuiView & lv);
2156 Dialog * createGuiGraphics(GuiView & lv);
2157 Dialog * createGuiInclude(GuiView & lv);
2158 Dialog * createGuiLabel(GuiView & lv);
2159 Dialog * createGuiListings(GuiView & lv);
2160 Dialog * createGuiLog(GuiView & lv);
2161 Dialog * createGuiMathMatrix(GuiView & lv);
2162 Dialog * createGuiNomenclature(GuiView & lv);
2163 Dialog * createGuiNote(GuiView & lv);
2164 Dialog * createGuiParagraph(GuiView & lv);
2165 Dialog * createGuiPreferences(GuiView & lv);
2166 Dialog * createGuiPrint(GuiView & lv);
2167 Dialog * createGuiRef(GuiView & lv);
2168 Dialog * createGuiSearch(GuiView & lv);
2169 Dialog * createGuiSendTo(GuiView & lv);
2170 Dialog * createGuiShowFile(GuiView & lv);
2171 Dialog * createGuiSpellchecker(GuiView & lv);
2172 Dialog * createGuiSymbols(GuiView & lv);
2173 Dialog * createGuiTabularCreate(GuiView & lv);
2174 Dialog * createGuiTabular(GuiView & lv);
2175 Dialog * createGuiTexInfo(GuiView & lv);
2176 Dialog * createGuiToc(GuiView & lv);
2177 Dialog * createGuiThesaurus(GuiView & lv);
2178 Dialog * createGuiHyperlink(GuiView & lv);
2179 Dialog * createGuiVSpace(GuiView & lv);
2180 Dialog * createGuiViewSource(GuiView & lv);
2181 Dialog * createGuiWrap(GuiView & lv);
2182
2183
2184 Dialog * GuiView::build(string const & name)
2185 {
2186         BOOST_ASSERT(isValidName(name));
2187
2188         if (name == "aboutlyx")
2189                 return createGuiAbout(*this);
2190         if (name == "bibitem")
2191                 return createGuiBibitem(*this);
2192         if (name == "bibtex")
2193                 return createGuiBibtex(*this);
2194         if (name == "box")
2195                 return createGuiBox(*this);
2196         if (name == "branch")
2197                 return createGuiBranch(*this);
2198         if (name == "changes")
2199                 return createGuiChanges(*this);
2200         if (name == "character")
2201                 return createGuiCharacter(*this);
2202         if (name == "citation")
2203                 return createGuiCitation(*this);
2204         if (name == "document")
2205                 return createGuiDocument(*this);
2206         if (name == "errorlist")
2207                 return createGuiErrorList(*this);
2208         if (name == "ert")
2209                 return createGuiERT(*this);
2210         if (name == "external")
2211                 return createGuiExternal(*this);
2212         if (name == "file")
2213                 return createGuiShowFile(*this);
2214         if (name == "findreplace")
2215                 return createGuiSearch(*this);
2216         if (name == "float")
2217                 return createGuiFloat(*this);
2218         if (name == "graphics")
2219                 return createGuiGraphics(*this);
2220         if (name == "include")
2221                 return createGuiInclude(*this);
2222         if (name == "nomenclature")
2223                 return createGuiNomenclature(*this);
2224         if (name == "label")
2225                 return createGuiLabel(*this);
2226         if (name == "log")
2227                 return createGuiLog(*this);
2228         if (name == "view-source")
2229                 return createGuiViewSource(*this);
2230         if (name == "mathdelimiter")
2231                 return createGuiDelimiter(*this);
2232         if (name == "mathmatrix")
2233                 return createGuiMathMatrix(*this);
2234         if (name == "note")
2235                 return createGuiNote(*this);
2236         if (name == "paragraph")
2237                 return createGuiParagraph(*this);
2238         if (name == "prefs")
2239                 return createGuiPreferences(*this);
2240         if (name == "print")
2241                 return createGuiPrint(*this);
2242         if (name == "ref")
2243                 return createGuiRef(*this);
2244         if (name == "sendto")
2245                 return createGuiSendTo(*this);
2246         if (name == "spellchecker")
2247                 return createGuiSpellchecker(*this);
2248         if (name == "symbols")
2249                 return createGuiSymbols(*this);
2250         if (name == "tabular")
2251                 return createGuiTabular(*this);
2252         if (name == "tabularcreate")
2253                 return createGuiTabularCreate(*this);
2254         if (name == "texinfo")
2255                 return createGuiTexInfo(*this);
2256 #ifdef HAVE_LIBAIKSAURUS
2257         if (name == "thesaurus")
2258                 return createGuiThesaurus(*this);
2259 #endif
2260         if (name == "toc")
2261                 return createGuiToc(*this);
2262         if (name == "href")
2263                 return createGuiHyperlink(*this);
2264         if (name == "vspace")
2265                 return createGuiVSpace(*this);
2266         if (name == "wrap")
2267                 return createGuiWrap(*this);
2268         if (name == "listings")
2269                 return createGuiListings(*this);
2270
2271         return 0;
2272 }
2273
2274
2275 } // namespace frontend
2276 } // namespace lyx
2277
2278 #include "GuiView_moc.cpp"