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