]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
c2bcf1b8e9897cc748af0dc47cc1380465f0a738
[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         case LFUN_COMPLETION_INLINE:
1048                 if (!d.current_work_area_
1049                     || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1050                     enable = false;
1051                 break;
1052
1053         case LFUN_COMPLETION_POPUP:
1054                 if (!d.current_work_area_
1055                     || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1056                     enable = false;
1057                 break;
1058
1059         case LFUN_COMPLETION_COMPLETE:
1060                 if (!d.current_work_area_
1061                         || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1062                     enable = false;
1063                 break;
1064
1065         default:
1066                 if (!view()) {
1067                         enable = false;
1068                         break;
1069                 }
1070         }
1071
1072         if (!enable)
1073                 flag.enabled(false);
1074
1075         return flag;
1076 }
1077
1078
1079 static FileName selectTemplateFile()
1080 {
1081         FileDialog dlg(_("Select template file"));
1082         dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1083         dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1084
1085         FileDialog::Result result =
1086                 dlg.open(from_utf8(lyxrc.template_path),
1087                              FileFilterList(_("LyX Documents (*.lyx)")),
1088                              docstring());
1089
1090         if (result.first == FileDialog::Later)
1091                 return FileName();
1092         if (result.second.empty())
1093                 return FileName();
1094         return FileName(to_utf8(result.second));
1095 }
1096
1097
1098 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1099 {
1100         setBusy(true);
1101
1102         Buffer * newBuffer = checkAndLoadLyXFile(filename);
1103
1104         if (!newBuffer) {
1105                 message(_("Document not loaded."));
1106                 setBusy(false);
1107                 return 0;
1108         }
1109
1110         setBuffer(newBuffer);
1111
1112         // scroll to the position when the file was last closed
1113         if (lyxrc.use_lastfilepos) {
1114                 LastFilePosSection::FilePos filepos =
1115                         LyX::ref().session().lastFilePos().load(filename);
1116                 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1117         }
1118
1119         if (tolastfiles)
1120                 LyX::ref().session().lastFiles().add(filename);
1121
1122         setBusy(false);
1123         return newBuffer;
1124 }
1125
1126
1127 void GuiView::openDocument(string const & fname)
1128 {
1129         string initpath = lyxrc.document_path;
1130
1131         if (buffer()) {
1132                 string const trypath = buffer()->filePath();
1133                 // If directory is writeable, use this as default.
1134                 if (FileName(trypath).isDirWritable())
1135                         initpath = trypath;
1136         }
1137
1138         string filename;
1139
1140         if (fname.empty()) {
1141                 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
1142                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1143                 dlg.setButton2(_("Examples|#E#e"),
1144                                 from_utf8(addPath(package().system_support().absFilename(), "examples")));
1145
1146                 FileDialog::Result result =
1147                         dlg.open(from_utf8(initpath),
1148                                      FileFilterList(_("LyX Documents (*.lyx)")),
1149                                      docstring());
1150
1151                 if (result.first == FileDialog::Later)
1152                         return;
1153
1154                 filename = to_utf8(result.second);
1155
1156                 // check selected filename
1157                 if (filename.empty()) {
1158                         message(_("Canceled."));
1159                         return;
1160                 }
1161         } else
1162                 filename = fname;
1163
1164         // get absolute path of file and add ".lyx" to the filename if
1165         // necessary. 
1166         FileName const fullname = 
1167                         fileSearch(string(), filename, "lyx", support::may_not_exist);
1168         if (!fullname.empty())
1169                 filename = fullname.absFilename();
1170
1171         // if the file doesn't exist, let the user create one
1172         if (!fullname.exists()) {
1173                 // the user specifically chose this name. Believe him.
1174                 Buffer * const b = newFile(filename, string(), true);
1175                 if (b)
1176                         setBuffer(b);
1177                 return;
1178         }
1179
1180         docstring const disp_fn = makeDisplayPath(filename);
1181         message(bformat(_("Opening document %1$s..."), disp_fn));
1182
1183         docstring str2;
1184         Buffer * buf = loadDocument(fullname);
1185         if (buf) {
1186                 updateLabels(*buf);
1187                 setBuffer(buf);
1188                 buf->errors("Parse");
1189                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1190         } else {
1191                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1192         }
1193         message(str2);
1194 }
1195
1196 // FIXME: clean that
1197 static bool import(GuiView * lv, FileName const & filename,
1198         string const & format, ErrorList & errorList)
1199 {
1200         FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
1201
1202         string loader_format;
1203         vector<string> loaders = theConverters().loaders();
1204         if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1205                 for (vector<string>::const_iterator it = loaders.begin();
1206                      it != loaders.end(); ++it) {
1207                         if (!theConverters().isReachable(format, *it))
1208                                 continue;
1209
1210                         string const tofile =
1211                                 changeExtension(filename.absFilename(),
1212                                 formats.extension(*it));
1213                         if (!theConverters().convert(0, filename, FileName(tofile),
1214                                 filename, format, *it, errorList))
1215                                 return false;
1216                         loader_format = *it;
1217                         break;
1218                 }
1219                 if (loader_format.empty()) {
1220                         frontend::Alert::error(_("Couldn't import file"),
1221                                      bformat(_("No information for importing the format %1$s."),
1222                                          formats.prettyName(format)));
1223                         return false;
1224                 }
1225         } else
1226                 loader_format = format;
1227
1228         if (loader_format == "lyx") {
1229                 Buffer * buf = lv->loadDocument(lyxfile);
1230                 if (!buf)
1231                         return false;
1232                 updateLabels(*buf);
1233                 lv->setBuffer(buf);
1234                 buf->errors("Parse");
1235         } else {
1236                 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1237                 if (!b)
1238                         return false;
1239                 lv->setBuffer(b);
1240                 bool as_paragraphs = loader_format == "textparagraph";
1241                 string filename2 = (loader_format == format) ? filename.absFilename()
1242                         : changeExtension(filename.absFilename(),
1243                                           formats.extension(loader_format));
1244                 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1245                 theLyXFunc().setLyXView(lv);
1246                 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1247         }
1248
1249         return true;
1250 }
1251
1252
1253 void GuiView::importDocument(string const & argument)
1254 {
1255         string format;
1256         string filename = split(argument, format, ' ');
1257
1258         LYXERR(Debug::INFO, format << " file: " << filename);
1259
1260         // need user interaction
1261         if (filename.empty()) {
1262                 string initpath = lyxrc.document_path;
1263
1264                 Buffer const * buf = buffer();
1265                 if (buf) {
1266                         string const trypath = buf->filePath();
1267                         // If directory is writeable, use this as default.
1268                         if (FileName(trypath).isDirWritable())
1269                                 initpath = trypath;
1270                 }
1271
1272                 docstring const text = bformat(_("Select %1$s file to import"),
1273                         formats.prettyName(format));
1274
1275                 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
1276                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1277                 dlg.setButton2(_("Examples|#E#e"),
1278                         from_utf8(addPath(package().system_support().absFilename(), "examples")));
1279
1280                 docstring filter = formats.prettyName(format);
1281                 filter += " (*.";
1282                 // FIXME UNICODE
1283                 filter += from_utf8(formats.extension(format));
1284                 filter += ')';
1285
1286                 FileDialog::Result result =
1287                         dlg.open(from_utf8(initpath),
1288                                      FileFilterList(filter),
1289                                      docstring());
1290
1291                 if (result.first == FileDialog::Later)
1292                         return;
1293
1294                 filename = to_utf8(result.second);
1295
1296                 // check selected filename
1297                 if (filename.empty())
1298                         message(_("Canceled."));
1299         }
1300
1301         if (filename.empty())
1302                 return;
1303
1304         // get absolute path of file
1305         FileName const fullname(makeAbsPath(filename));
1306
1307         FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
1308
1309         // Check if the document already is open
1310         Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1311         if (buf) {
1312                 setBuffer(buf);
1313                 if (!closeBuffer()) {
1314                         message(_("Canceled."));
1315                         return;
1316                 }
1317         }
1318
1319         docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1320
1321         // if the file exists already, and we didn't do
1322         // -i lyx thefile.lyx, warn
1323         if (lyxfile.exists() && fullname != lyxfile) {
1324
1325                 docstring text = bformat(_("The document %1$s already exists.\n\n"
1326                         "Do you want to overwrite that document?"), displaypath);
1327                 int const ret = Alert::prompt(_("Overwrite document?"),
1328                         text, 0, 1, _("&Overwrite"), _("&Cancel"));
1329
1330                 if (ret == 1) {
1331                         message(_("Canceled."));
1332                         return;
1333                 }
1334         }
1335
1336         message(bformat(_("Importing %1$s..."), displaypath));
1337         ErrorList errorList;
1338         if (import(this, fullname, format, errorList))
1339                 message(_("imported."));
1340         else
1341                 message(_("file not imported!"));
1342
1343         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1344 }
1345
1346
1347 void GuiView::newDocument(string const & filename, bool from_template)
1348 {
1349         FileName initpath(lyxrc.document_path);
1350         Buffer * buf = buffer();
1351         if (buf) {
1352                 FileName const trypath(buf->filePath());
1353                 // If directory is writeable, use this as default.
1354                 if (trypath.isDirWritable())
1355                         initpath = trypath;
1356         }
1357
1358         string templatefile = from_template ?
1359                 selectTemplateFile().absFilename() : string();
1360         Buffer * b;
1361         if (filename.empty())
1362                 b = newUnnamedFile(templatefile, initpath);
1363         else
1364                 b = newFile(filename, templatefile, true);
1365
1366         if (b)
1367                 setBuffer(b);
1368         // Ensure the cursor is correctly positionned on screen.
1369         view()->showCursor();
1370 }
1371
1372
1373 void GuiView::insertLyXFile(docstring const & fname)
1374 {
1375         BufferView * bv = view();
1376         if (!bv)
1377                 return;
1378
1379         // FIXME UNICODE
1380         FileName filename(to_utf8(fname));
1381         
1382         if (!filename.empty()) {
1383                 bv->insertLyXFile(filename);
1384                 return;
1385         }
1386
1387         // Launch a file browser
1388         // FIXME UNICODE
1389         string initpath = lyxrc.document_path;
1390         string const trypath = bv->buffer().filePath();
1391         // If directory is writeable, use this as default.
1392         if (FileName(trypath).isDirWritable())
1393                 initpath = trypath;
1394
1395         // FIXME UNICODE
1396         FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT);
1397         dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1398         dlg.setButton2(_("Examples|#E#e"),
1399                 from_utf8(addPath(package().system_support().absFilename(),
1400                 "examples")));
1401
1402         FileDialog::Result result =
1403                 dlg.open(from_utf8(initpath),
1404                              FileFilterList(_("LyX Documents (*.lyx)")),
1405                              docstring());
1406
1407         if (result.first == FileDialog::Later)
1408                 return;
1409
1410         // FIXME UNICODE
1411         filename.set(to_utf8(result.second));
1412
1413         // check selected filename
1414         if (filename.empty()) {
1415                 // emit message signal.
1416                 message(_("Canceled."));
1417                 return;
1418         }
1419
1420         bv->insertLyXFile(filename);
1421 }
1422
1423
1424 void GuiView::insertPlaintextFile(docstring const & fname,
1425         bool asParagraph)
1426 {
1427         BufferView * bv = view();
1428         if (!bv)
1429                 return;
1430
1431         // FIXME UNICODE
1432         FileName filename(to_utf8(fname));
1433         
1434         if (!filename.empty()) {
1435                 bv->insertPlaintextFile(filename, asParagraph);
1436                 return;
1437         }
1438
1439         FileDialog dlg(_("Select file to insert"), (asParagraph ?
1440                 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1441
1442         FileDialog::Result result = dlg.open(from_utf8(bv->buffer().filePath()),
1443                 FileFilterList(), docstring());
1444
1445         if (result.first == FileDialog::Later)
1446                 return;
1447
1448         // FIXME UNICODE
1449         filename.set(to_utf8(result.second));
1450
1451         // check selected filename
1452         if (filename.empty()) {
1453                 // emit message signal.
1454                 message(_("Canceled."));
1455                 return;
1456         }
1457
1458         bv->insertPlaintextFile(filename, asParagraph);
1459 }
1460
1461
1462 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1463 {
1464         FileName fname = b.fileName();
1465         FileName const oldname = fname;
1466
1467         if (!newname.empty()) {
1468                 // FIXME UNICODE
1469                 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1470         } else {
1471                 // Switch to this Buffer.
1472                 setBuffer(&b);
1473
1474                 /// No argument? Ask user through dialog.
1475                 // FIXME UNICODE
1476                 FileDialog dlg(_("Choose a filename to save document as"),
1477                                    LFUN_BUFFER_WRITE_AS);
1478                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1479                 dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1480
1481                 if (!isLyXFilename(fname.absFilename()))
1482                         fname.changeExtension(".lyx");
1483
1484                 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1485
1486                 FileDialog::Result result =
1487                         dlg.save(from_utf8(fname.onlyPath().absFilename()),
1488                                      filter,
1489                                      from_utf8(fname.onlyFileName()));
1490
1491                 if (result.first == FileDialog::Later)
1492                         return false;
1493
1494                 fname.set(to_utf8(result.second));
1495
1496                 if (fname.empty())
1497                         return false;
1498
1499                 if (!isLyXFilename(fname.absFilename()))
1500                         fname.changeExtension(".lyx");
1501         }
1502
1503         if (FileName(fname).exists()) {
1504                 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1505                 docstring text = bformat(_("The document %1$s already "
1506                                            "exists.\n\nDo you want to "
1507                                            "overwrite that document?"), 
1508                                          file);
1509                 int const ret = Alert::prompt(_("Overwrite document?"),
1510                         text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1511                 switch (ret) {
1512                 case 0: break;
1513                 case 1: return renameBuffer(b, docstring());
1514                 case 2: return false;
1515                 }
1516         }
1517
1518         // Ok, change the name of the buffer
1519         b.setFileName(fname.absFilename());
1520         b.markDirty();
1521         bool unnamed = b.isUnnamed();
1522         b.setUnnamed(false);
1523         b.saveCheckSum(fname);
1524
1525         if (!saveBuffer(b)) {
1526                 b.setFileName(oldname.absFilename());
1527                 b.setUnnamed(unnamed);
1528                 b.saveCheckSum(oldname);
1529                 return false;
1530         }
1531
1532         return true;
1533 }
1534
1535
1536 bool GuiView::saveBuffer(Buffer & b)
1537 {
1538         if (b.isUnnamed())
1539                 return renameBuffer(b, docstring());
1540
1541         if (b.save()) {
1542                 LyX::ref().session().lastFiles().add(b.fileName());
1543                 return true;
1544         }
1545
1546         // Switch to this Buffer.
1547         setBuffer(&b);
1548
1549         // FIXME: we don't tell the user *WHY* the save failed !!
1550         docstring const file = makeDisplayPath(b.absFileName(), 30);
1551         docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1552                                    "Do you want to rename the document and "
1553                                    "try again?"), file);
1554         int const ret = Alert::prompt(_("Rename and save?"),
1555                 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1556         switch (ret) {
1557         case 0:
1558                 if (!renameBuffer(b, docstring()))
1559                         return false;
1560                 break;
1561         case 1:
1562                 break;
1563         case 2:
1564                 return false;
1565         }
1566
1567         return saveBuffer(b);
1568 }
1569
1570
1571 bool GuiView::closeBuffer()
1572 {
1573         Buffer * buf = buffer();
1574         return buf && closeBuffer(*buf);
1575 }
1576
1577
1578 bool GuiView::closeBuffer(Buffer & buf)
1579 {
1580         if (buf.isClean() || buf.paragraphs().empty()) {
1581                 theBufferList().release(&buf);
1582                 return true;
1583         }
1584         // Switch to this Buffer.
1585         setBuffer(&buf);
1586
1587         docstring file;
1588         // FIXME: Unicode?
1589         if (buf.isUnnamed())
1590                 file = from_utf8(buf.fileName().onlyFileName());
1591         else
1592                 file = buf.fileName().displayName(30);
1593
1594         docstring const text = bformat(_("The document %1$s has unsaved changes."
1595                 "\n\nDo you want to save the document or discard the changes?"), file);
1596         int const ret = Alert::prompt(_("Save changed document?"),
1597                 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1598
1599         switch (ret) {
1600         case 0:
1601                 if (!saveBuffer(buf))
1602                         return false;
1603                 break;
1604         case 1:
1605                 // if we crash after this we could
1606                 // have no autosave file but I guess
1607                 // this is really improbable (Jug)
1608                 removeAutosaveFile(buf.absFileName());
1609                 break;
1610         case 2:
1611                 return false;
1612         }
1613
1614         // save file names to .lyx/session
1615         // if master/slave are both open, do not save slave since it
1616         // will be automatically loaded when the master is loaded
1617         if (buf.masterBuffer() == &buf)
1618                 LyX::ref().session().lastOpened().add(buf.fileName());
1619
1620         theBufferList().release(&buf);
1621         return true;
1622 }
1623
1624
1625 bool GuiView::quitWriteAll()
1626 {
1627         while (!theBufferList().empty()) {
1628                 Buffer * b = theBufferList().first();
1629                 if (!closeBuffer(*b))
1630                         return false;
1631         }
1632         return true;
1633 }
1634
1635
1636 bool GuiView::dispatch(FuncRequest const & cmd)
1637 {
1638         BufferView * bv = view();       
1639         // By default we won't need any update.
1640         if (bv)
1641                 bv->cursor().updateFlags(Update::None);
1642
1643         switch(cmd.action) {
1644                 case LFUN_FILE_OPEN:
1645                         openDocument(to_utf8(cmd.argument()));
1646                         break;
1647
1648                 case LFUN_BUFFER_IMPORT:
1649                         importDocument(to_utf8(cmd.argument()));
1650                         break;
1651
1652                 case LFUN_BUFFER_SWITCH:
1653                         setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1654                         break;
1655
1656                 case LFUN_BUFFER_NEXT:
1657                         setBuffer(theBufferList().next(buffer()));
1658                         break;
1659
1660                 case LFUN_BUFFER_PREVIOUS:
1661                         setBuffer(theBufferList().previous(buffer()));
1662                         break;
1663
1664                 case LFUN_COMMAND_EXECUTE: {
1665                         bool const show_it = cmd.argument() != "off";
1666                         d.toolbars_->showCommandBuffer(show_it);
1667                         break;
1668                 }
1669                 case LFUN_DROP_LAYOUTS_CHOICE:
1670                         if (d.layout_)
1671                                 d.layout_->showPopup();
1672                         break;
1673
1674                 case LFUN_MENU_OPEN:
1675                         if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument())))
1676                                 menu->exec(QCursor::pos());
1677                         break;
1678
1679                 case LFUN_FILE_INSERT:
1680                         insertLyXFile(cmd.argument());
1681                         break;
1682                 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1683                         insertPlaintextFile(cmd.argument(), true);
1684                         break;
1685
1686                 case LFUN_FILE_INSERT_PLAINTEXT:
1687                         insertPlaintextFile(cmd.argument(), false);
1688                         break;
1689
1690                 case LFUN_BUFFER_WRITE:
1691                         if (bv)
1692                                 saveBuffer(bv->buffer());
1693                         break;
1694
1695                 case LFUN_BUFFER_WRITE_AS:
1696                         if (bv)
1697                                 renameBuffer(bv->buffer(), cmd.argument());
1698                         break;
1699
1700                 case LFUN_BUFFER_WRITE_ALL: {
1701                         Buffer * first = theBufferList().first();
1702                         if (!first)
1703                                 break;
1704                         message(_("Saving all documents..."));
1705                         // We cannot use a for loop as the buffer list cycles.
1706                         Buffer * b = first;
1707                         do {
1708                                 if (b->isClean())
1709                                         continue;
1710                                 saveBuffer(*b);
1711                                 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1712                                 b = theBufferList().next(b);
1713                         } while (b != first); 
1714                         message(_("All documents saved."));
1715                         break;
1716                 }
1717
1718                 case LFUN_TOOLBAR_TOGGLE: {
1719                         string const name = cmd.getArg(0);
1720                         bool const allowauto = cmd.getArg(1) == "allowauto";
1721                         // it is possible to get current toolbar status like this,...
1722                         // but I decide to obey the order of ToolbarBackend::flags
1723                         // and disregard real toolbar status.
1724                         // toolbars_->saveToolbarInfo();
1725                         //
1726                         // toggle state on/off/auto
1727                         d.toolbars_->toggleToolbarState(name, allowauto);
1728                         // update toolbar
1729                         updateToolbars();
1730
1731                         ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1732                         if (!tbi) {
1733                                 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1734                                 break;
1735                         }
1736                         docstring state;
1737                         if (tbi->flags & ToolbarInfo::ON)
1738                                 state = _("on");
1739                         else if (tbi->flags & ToolbarInfo::OFF)
1740                                 state = _("off");
1741                         else if (tbi->flags & ToolbarInfo::AUTO)
1742                                 state = _("auto");
1743
1744                         message(bformat(_("Toolbar \"%1$s\" state set to %2$s"), 
1745                                            _(tbi->gui_name), state));
1746                         break;
1747                 }
1748
1749                 case LFUN_DIALOG_UPDATE: {
1750                         string const name = to_utf8(cmd.argument());
1751                         // Can only update a dialog connected to an existing inset
1752                         Inset * inset = getOpenInset(name);
1753                         if (inset) {
1754                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1755                                 inset->dispatch(view()->cursor(), fr);
1756                         } else if (name == "paragraph") {
1757                                 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1758                         } else if (name == "prefs") {
1759                                 updateDialog(name, string());
1760                         }
1761                         break;
1762                 }
1763
1764                 case LFUN_DIALOG_TOGGLE: {
1765                         if (isDialogVisible(cmd.getArg(0)))
1766                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1767                         else
1768                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1769                         break;
1770                 }
1771
1772                 case LFUN_DIALOG_DISCONNECT_INSET:
1773                         disconnectDialog(to_utf8(cmd.argument()));
1774                         break;
1775
1776                 case LFUN_DIALOG_HIDE: {
1777                         if (quitting)
1778                                 break;
1779                         guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1780                         break;
1781                 }
1782
1783                 case LFUN_DIALOG_SHOW: {
1784                         string const name = cmd.getArg(0);
1785                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1786
1787                         if (name == "character") {
1788                                 data = freefont2string();
1789                                 if (!data.empty())
1790                                         showDialog("character", data);
1791                         } else if (name == "latexlog") {
1792                                 Buffer::LogType type; 
1793                                 string const logfile = buffer()->logName(&type);
1794                                 switch (type) {
1795                                 case Buffer::latexlog:
1796                                         data = "latex ";
1797                                         break;
1798                                 case Buffer::buildlog:
1799                                         data = "literate ";
1800                                         break;
1801                                 }
1802                                 data += Lexer::quoteString(logfile);
1803                                 showDialog("log", data);
1804                         } else if (name == "vclog") {
1805                                 string const data = "vc " +
1806                                         Lexer::quoteString(buffer()->lyxvc().getLogFile());
1807                                 showDialog("log", data);
1808                         } else if (name == "symbols") {
1809                                 data = bv->cursor().getEncoding()->name();
1810                                 if (!data.empty())
1811                                         showDialog("symbols", data);
1812                         } else
1813                                 showDialog(name, data);
1814                         break;
1815                 }
1816
1817                 case LFUN_INSET_APPLY: {
1818                         string const name = cmd.getArg(0);
1819                         Inset * inset = getOpenInset(name);
1820                         if (inset) {
1821                                 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1822                                 inset->dispatch(view()->cursor(), fr);
1823                         } else {
1824                                 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1825                                 lyx::dispatch(fr);
1826                         }
1827                         break;
1828                 }
1829
1830                 case LFUN_UI_TOGGLE:
1831                         lfunUiToggle(cmd);
1832                         // Make sure the keyboard focus stays in the work area.
1833                         setFocus();
1834                         break;
1835
1836                 case LFUN_COMPLETION_INLINE:
1837                         if (d.current_work_area_)
1838                                 d.current_work_area_->completer().showInline();
1839                         break;
1840
1841                 case LFUN_SPLIT_VIEW:
1842                         if (Buffer * buf = buffer()) {
1843                                 string const orientation = cmd.getArg(0);
1844                                 d.splitter_->setOrientation(orientation == "vertical"
1845                                         ? Qt::Vertical : Qt::Horizontal);
1846                                 TabWorkArea * twa = addTabWorkArea();
1847                                 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1848                                 setCurrentWorkArea(wa);
1849                         }
1850                         break;
1851
1852                 case LFUN_CLOSE_TAB_GROUP:
1853                         if (TabWorkArea * twa = d.currentTabWorkArea()) {
1854                                 delete twa;
1855                                 twa = d.currentTabWorkArea();
1856                                 // Switch to the next GuiWorkArea in the found TabWorkArea.
1857                                 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1858                                 if (d.splitter_->count() == 0)
1859                                         // No more work area, switch to the background widget.
1860                                         d.setBackground();
1861                         }
1862                         break;
1863                         
1864                 case LFUN_COMPLETION_POPUP:
1865                         if (d.current_work_area_)
1866                                 d.current_work_area_->completer().showPopup();
1867                         break;
1868
1869
1870                 case LFUN_COMPLETION_COMPLETE:
1871                         if (d.current_work_area_)
1872                                 d.current_work_area_->completer().tab();
1873                         break;
1874
1875                 default:
1876                         return false;
1877         }
1878
1879         return true;
1880 }
1881
1882
1883 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1884 {
1885         string const arg = cmd.getArg(0);
1886         if (arg == "scrollbar") {
1887                 // hide() is of no help
1888                 if (d.current_work_area_->verticalScrollBarPolicy() ==
1889                         Qt::ScrollBarAlwaysOff)
1890
1891                         d.current_work_area_->setVerticalScrollBarPolicy(
1892                                 Qt::ScrollBarAsNeeded);
1893                 else
1894                         d.current_work_area_->setVerticalScrollBarPolicy(
1895                                 Qt::ScrollBarAlwaysOff);
1896                 return;
1897         }
1898         if (arg == "statusbar") {
1899                 statusBar()->setVisible(!statusBar()->isVisible());
1900                 return;
1901         }
1902         if (arg == "menubar") {
1903                 menuBar()->setVisible(!menuBar()->isVisible());
1904                 return;
1905         }
1906 #if QT_VERSION >= 0x040300
1907         if (arg == "frame") {
1908                 int l, t, r, b;
1909                 getContentsMargins(&l, &t, &r, &b);
1910                 //are the frames in default state?
1911                 if (l == 0) {
1912                         d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1913                         setContentsMargins(-2, -2, -2, -2);
1914                 } else {
1915                         d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1916                         setContentsMargins(0, 0, 0, 0);
1917                 }
1918                 return;
1919         }
1920 #endif
1921         if (arg != "fullscreen") {
1922                 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1923                 return;
1924         }
1925
1926         if (lyxrc.full_screen_toolbars)
1927                 d.toolbars_->toggleFullScreen(!isFullScreen());
1928
1929         if (isFullScreen()) {
1930                 for (int i = 0; i != d.splitter_->count(); ++i)
1931                         d.tabWorkArea(i)->setFullScreen(false);
1932 #if QT_VERSION >= 0x040300
1933                 setContentsMargins(0, 0, 0, 0);
1934 #endif
1935                 showNormal();
1936                 menuBar()->show();
1937                 statusBar()->show();
1938         } else {
1939                 for (int i = 0; i != d.splitter_->count(); ++i)
1940                         d.tabWorkArea(i)->setFullScreen(true);
1941 #if QT_VERSION >= 0x040300
1942                 setContentsMargins(-2, -2, -2, -2);
1943 #endif
1944                 showFullScreen();
1945                 statusBar()->hide();
1946                 menuBar()->hide();
1947         }
1948 }
1949
1950
1951 Buffer const * GuiView::updateInset(Inset const * inset)
1952 {
1953         if (!d.current_work_area_)
1954                 return 0;
1955
1956         if (inset)
1957                 d.current_work_area_->scheduleRedraw();
1958
1959         return &d.current_work_area_->bufferView().buffer();
1960 }
1961
1962
1963 void GuiView::restartCursor()
1964 {
1965         /* When we move around, or type, it's nice to be able to see
1966          * the cursor immediately after the keypress.
1967          */
1968         if (d.current_work_area_)
1969                 d.current_work_area_->startBlinkingCursor();
1970
1971         // Take this occasion to update the toobars and layout list.
1972         updateLayoutList();
1973         updateToolbars();
1974 }
1975
1976
1977 void GuiView::updateCompletion(bool start, bool keep)
1978 {
1979         if (d.current_work_area_)
1980                 d.current_work_area_->completer().updateVisibility(start, keep);
1981 }
1982
1983 namespace {
1984
1985 // This list should be kept in sync with the list of insets in
1986 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
1987 // dialog should have the same name as the inset.
1988
1989 char const * const dialognames[] = {
1990 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1991 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1992 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1993 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", 
1994 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1995
1996 #ifdef HAVE_LIBAIKSAURUS
1997 "thesaurus",
1998 #endif
1999
2000 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2001
2002 char const * const * const end_dialognames =
2003         dialognames + (sizeof(dialognames) / sizeof(char *));
2004
2005 class cmpCStr {
2006 public:
2007         cmpCStr(char const * name) : name_(name) {}
2008         bool operator()(char const * other) {
2009                 return strcmp(other, name_) == 0;
2010         }
2011 private:
2012         char const * name_;
2013 };
2014
2015
2016 bool isValidName(string const & name)
2017 {
2018         return find_if(dialognames, end_dialognames,
2019                             cmpCStr(name.c_str())) != end_dialognames;
2020 }
2021
2022 } // namespace anon
2023
2024
2025 void GuiView::resetDialogs()
2026 {
2027         // Make sure that no LFUN uses any LyXView.
2028         theLyXFunc().setLyXView(0);
2029         // FIXME: the "math panels" toolbar takes an awful lot of time to
2030         // initialise so we don't do that for the time being.
2031         //d.toolbars_->init();
2032         guiApp->menus().fillMenuBar(this);
2033         if (d.layout_)
2034                 d.layout_->updateContents(true);
2035         // Now update controls with current buffer.
2036         theLyXFunc().setLyXView(this);
2037         restartCursor();
2038 }
2039
2040
2041 Dialog * GuiView::find_or_build(string const & name)
2042 {
2043         if (!isValidName(name))
2044                 return 0;
2045
2046         map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2047
2048         if (it != d.dialogs_.end())
2049                 return it->second.get();
2050
2051         Dialog * dialog = build(name);
2052         d.dialogs_[name].reset(dialog);
2053         if (lyxrc.allow_geometry_session)
2054                 dialog->restoreSession();
2055         return dialog;
2056 }
2057
2058
2059 void GuiView::showDialog(string const & name, string const & data,
2060         Inset * inset)
2061 {
2062         if (d.in_show_)
2063                 return;
2064
2065         d.in_show_ = true;
2066         Dialog * dialog = find_or_build(name);
2067         if (dialog) {
2068                 dialog->showData(data);
2069                 if (inset)
2070                         d.open_insets_[name] = inset;
2071         }
2072         d.in_show_ = false;
2073 }
2074
2075
2076 bool GuiView::isDialogVisible(string const & name) const
2077 {
2078         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2079         if (it == d.dialogs_.end())
2080                 return false;
2081         return it->second.get()->isVisibleView();
2082 }
2083
2084
2085 void GuiView::hideDialog(string const & name, Inset * inset)
2086 {
2087         // Don't send the signal if we are quitting, because on MSVC it is
2088         // destructed before the cut stack in CutAndPaste.cpp, and this method
2089         // is called from some inset destructor if the cut stack is not empty
2090         // on exit.
2091         if (quitting)
2092                 return;
2093
2094         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2095         if (it == d.dialogs_.end())
2096                 return;
2097
2098         if (inset && inset != getOpenInset(name))
2099                 return;
2100
2101         Dialog * const dialog = it->second.get();
2102         if (dialog->isVisibleView())
2103                 dialog->hideView();
2104         d.open_insets_[name] = 0;
2105 }
2106
2107
2108 void GuiView::disconnectDialog(string const & name)
2109 {
2110         if (!isValidName(name))
2111                 return;
2112
2113         if (d.open_insets_.find(name) != d.open_insets_.end())
2114                 d.open_insets_[name] = 0;
2115 }
2116
2117
2118 Inset * GuiView::getOpenInset(string const & name) const
2119 {
2120         if (!isValidName(name))
2121                 return 0;
2122
2123         map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2124         return it == d.open_insets_.end() ? 0 : it->second;
2125 }
2126
2127
2128 void GuiView::hideAll() const
2129 {
2130         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2131         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2132
2133         for(; it != end; ++it)
2134                 it->second->hideView();
2135 }
2136
2137
2138 void GuiView::hideBufferDependent() const
2139 {
2140         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2141         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2142
2143         for(; it != end; ++it) {
2144                 Dialog * dialog = it->second.get();
2145                 if (dialog->isBufferDependent())
2146                         dialog->hideView();
2147         }
2148 }
2149
2150
2151 void GuiView::updateBufferDependent(bool switched) const
2152 {
2153         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2154         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2155
2156         for(; it != end; ++it) {
2157                 Dialog * dialog = it->second.get();
2158                 if (!dialog->isVisibleView())
2159                         continue;
2160                 if (switched && dialog->isBufferDependent()) {
2161                         if (dialog->initialiseParams(""))
2162                                 dialog->updateView();
2163                         else
2164                                 dialog->hideView();
2165                 } else {
2166                         // A bit clunky, but the dialog will request
2167                         // that the kernel provides it with the necessary
2168                         // data.
2169                         dialog->updateDialog();
2170                 }
2171         }
2172 }
2173
2174
2175 void GuiView::checkStatus()
2176 {
2177         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2178         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2179
2180         for(; it != end; ++it) {
2181                 Dialog * const dialog = it->second.get();
2182                 if (dialog && dialog->isVisibleView())
2183                         dialog->checkStatus();
2184         }
2185 }
2186
2187
2188
2189 // will be replaced by a proper factory...
2190 Dialog * createGuiAbout(GuiView & lv);
2191 Dialog * createGuiBibitem(GuiView & lv);
2192 Dialog * createGuiBibtex(GuiView & lv);
2193 Dialog * createGuiBox(GuiView & lv);
2194 Dialog * createGuiBranch(GuiView & lv);
2195 Dialog * createGuiChanges(GuiView & lv);
2196 Dialog * createGuiCharacter(GuiView & lv);
2197 Dialog * createGuiCitation(GuiView & lv);
2198 Dialog * createGuiDelimiter(GuiView & lv);
2199 Dialog * createGuiDocument(GuiView & lv);
2200 Dialog * createGuiErrorList(GuiView & lv);
2201 Dialog * createGuiERT(GuiView & lv);
2202 Dialog * createGuiExternal(GuiView & lv);
2203 Dialog * createGuiFloat(GuiView & lv);
2204 Dialog * createGuiGraphics(GuiView & lv);
2205 Dialog * createGuiInclude(GuiView & lv);
2206 Dialog * createGuiLabel(GuiView & lv);
2207 Dialog * createGuiListings(GuiView & lv);
2208 Dialog * createGuiLog(GuiView & lv);
2209 Dialog * createGuiMathMatrix(GuiView & lv);
2210 Dialog * createGuiNomenclature(GuiView & lv);
2211 Dialog * createGuiNote(GuiView & lv);
2212 Dialog * createGuiParagraph(GuiView & lv);
2213 Dialog * createGuiPreferences(GuiView & lv);
2214 Dialog * createGuiPrint(GuiView & lv);
2215 Dialog * createGuiRef(GuiView & lv);
2216 Dialog * createGuiSearch(GuiView & lv);
2217 Dialog * createGuiSendTo(GuiView & lv);
2218 Dialog * createGuiShowFile(GuiView & lv);
2219 Dialog * createGuiSpellchecker(GuiView & lv);
2220 Dialog * createGuiSymbols(GuiView & lv);
2221 Dialog * createGuiTabularCreate(GuiView & lv);
2222 Dialog * createGuiTabular(GuiView & lv);
2223 Dialog * createGuiTexInfo(GuiView & lv);
2224 Dialog * createGuiToc(GuiView & lv);
2225 Dialog * createGuiThesaurus(GuiView & lv);
2226 Dialog * createGuiHyperlink(GuiView & lv);
2227 Dialog * createGuiVSpace(GuiView & lv);
2228 Dialog * createGuiViewSource(GuiView & lv);
2229 Dialog * createGuiWrap(GuiView & lv);
2230
2231
2232 Dialog * GuiView::build(string const & name)
2233 {
2234         BOOST_ASSERT(isValidName(name));
2235
2236         if (name == "aboutlyx")
2237                 return createGuiAbout(*this);
2238         if (name == "bibitem")
2239                 return createGuiBibitem(*this);
2240         if (name == "bibtex")
2241                 return createGuiBibtex(*this);
2242         if (name == "box")
2243                 return createGuiBox(*this);
2244         if (name == "branch")
2245                 return createGuiBranch(*this);
2246         if (name == "changes")
2247                 return createGuiChanges(*this);
2248         if (name == "character")
2249                 return createGuiCharacter(*this);
2250         if (name == "citation")
2251                 return createGuiCitation(*this);
2252         if (name == "document")
2253                 return createGuiDocument(*this);
2254         if (name == "errorlist")
2255                 return createGuiErrorList(*this);
2256         if (name == "ert")
2257                 return createGuiERT(*this);
2258         if (name == "external")
2259                 return createGuiExternal(*this);
2260         if (name == "file")
2261                 return createGuiShowFile(*this);
2262         if (name == "findreplace")
2263                 return createGuiSearch(*this);
2264         if (name == "float")
2265                 return createGuiFloat(*this);
2266         if (name == "graphics")
2267                 return createGuiGraphics(*this);
2268         if (name == "include")
2269                 return createGuiInclude(*this);
2270         if (name == "nomenclature")
2271                 return createGuiNomenclature(*this);
2272         if (name == "label")
2273                 return createGuiLabel(*this);
2274         if (name == "log")
2275                 return createGuiLog(*this);
2276         if (name == "view-source")
2277                 return createGuiViewSource(*this);
2278         if (name == "mathdelimiter")
2279                 return createGuiDelimiter(*this);
2280         if (name == "mathmatrix")
2281                 return createGuiMathMatrix(*this);
2282         if (name == "note")
2283                 return createGuiNote(*this);
2284         if (name == "paragraph")
2285                 return createGuiParagraph(*this);
2286         if (name == "prefs")
2287                 return createGuiPreferences(*this);
2288         if (name == "print")
2289                 return createGuiPrint(*this);
2290         if (name == "ref")
2291                 return createGuiRef(*this);
2292         if (name == "sendto")
2293                 return createGuiSendTo(*this);
2294         if (name == "spellchecker")
2295                 return createGuiSpellchecker(*this);
2296         if (name == "symbols")
2297                 return createGuiSymbols(*this);
2298         if (name == "tabular")
2299                 return createGuiTabular(*this);
2300         if (name == "tabularcreate")
2301                 return createGuiTabularCreate(*this);
2302         if (name == "texinfo")
2303                 return createGuiTexInfo(*this);
2304 #ifdef HAVE_LIBAIKSAURUS
2305         if (name == "thesaurus")
2306                 return createGuiThesaurus(*this);
2307 #endif
2308         if (name == "toc")
2309                 return createGuiToc(*this);
2310         if (name == "href")
2311                 return createGuiHyperlink(*this);
2312         if (name == "vspace")
2313                 return createGuiVSpace(*this);
2314         if (name == "wrap")
2315                 return createGuiWrap(*this);
2316         if (name == "listings")
2317                 return createGuiListings(*this);
2318
2319         return 0;
2320 }
2321
2322
2323 } // namespace frontend
2324 } // namespace lyx
2325
2326 #include "GuiView_moc.cpp"