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