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