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