]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
basic context menu for InsetExternal.
[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 "GuiCompleter.h"
22 #include "GuiWorkArea.h"
23 #include "GuiKeySymbol.h"
24 #include "GuiToolbar.h"
25 #include "GuiToolbars.h"
26 #include "Menus.h"
27
28 #include "qt_helpers.h"
29
30 #include "frontends/alert.h"
31
32 #include "buffer_funcs.h"
33 #include "Buffer.h"
34 #include "BufferList.h"
35 #include "BufferParams.h"
36 #include "BufferView.h"
37 #include "Converter.h"
38 #include "Cursor.h"
39 #include "Encoding.h"
40 #include "ErrorList.h"
41 #include "Format.h"
42 #include "FuncStatus.h"
43 #include "FuncRequest.h"
44 #include "Intl.h"
45 #include "Layout.h"
46 #include "Lexer.h"
47 #include "LyXFunc.h"
48 #include "LyX.h"
49 #include "LyXRC.h"
50 #include "LyXVC.h"
51 #include "Paragraph.h"
52 #include "TextClass.h"
53 #include "Text.h"
54 #include "ToolbarBackend.h"
55 #include "version.h"
56
57 #include "support/assert.h"
58 #include "support/debug.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, true)) {
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         // Navigator needs more than a simple update in this case. It needs to be
542         // rebuilt.
543         structureChanged();
544
545         // Buffer-dependent dialogs must be updated. This is done here because
546         // some dialogs require buffer()->text.
547         updateDialogs();
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 #else
564         structureChanged();
565         updateDialogs();
566 #endif
567 }
568
569
570 void GuiView::updateStatusBar()
571 {
572         // let the user see the explicit message
573         if (d.statusbar_timer_.isActive())
574                 return;
575
576         theLyXFunc().setLyXView(this);
577         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
578 }
579
580
581 bool GuiView::hasFocus() const
582 {
583         return qApp->activeWindow() == this;
584 }
585
586
587 bool GuiView::event(QEvent * e)
588 {
589         switch (e->type())
590         {
591         // Useful debug code:
592         //case QEvent::ActivationChange:
593         //case QEvent::WindowDeactivate:
594         //case QEvent::Paint:
595         //case QEvent::Enter:
596         //case QEvent::Leave:
597         //case QEvent::HoverEnter:
598         //case QEvent::HoverLeave:
599         //case QEvent::HoverMove:
600         //case QEvent::StatusTip:
601         //case QEvent::DragEnter:
602         //case QEvent::DragLeave:
603         //case QEvent::Drop:
604         //      break;
605
606         case QEvent::WindowActivate: {
607                 if (this == guiApp->currentView()) {
608                         setFocus();
609                         return QMainWindow::event(e);
610                 }
611                 guiApp->setCurrentView(this);
612                 if (d.current_work_area_) {
613                         BufferView & bv = d.current_work_area_->bufferView();
614                         connectBufferView(bv);
615                         connectBuffer(bv.buffer());
616                         // The document structure, name and dialogs might have
617                         // changed in another view.
618                         structureChanged();
619                         updateDialogs();
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         d.current_work_area_ = wa;
769         for (int i = 0; i != d.splitter_->count(); ++i) {
770                 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
771                         return;
772         }
773 }
774
775
776 void GuiView::removeWorkArea(GuiWorkArea * wa)
777 {
778         LASSERT(wa, /**/);
779         if (wa == d.current_work_area_) {
780                 disconnectBuffer();
781                 disconnectBufferView();
782                 d.current_work_area_ = 0;
783         }
784
785         for (int i = 0; i != d.splitter_->count(); ++i) {
786                 TabWorkArea * twa = d.tabWorkArea(i);
787                 if (!twa->removeWorkArea(wa))
788                         // Not found in this tab group.
789                         continue;
790
791                 // We found and removed the GuiWorkArea.
792                 if (!twa->count()) {
793                         // No more WorkAreas in this tab group, so delete it.
794                         delete twa;
795                         break;
796                 }
797
798                 if (d.current_work_area_)
799                         // This means that we are not closing the current GuiWorkArea;
800                         break;
801
802                 // Switch to the next GuiWorkArea in the found TabWorkArea.
803                 d.current_work_area_ = twa->currentWorkArea();
804                 break;
805         }
806
807         if (d.splitter_->count() == 0)
808                 // No more work area, switch to the background widget.
809                 d.setBackground();
810 }
811
812
813 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
814 {
815         d.layout_ = layout;
816 }
817
818
819 void GuiView::updateLayoutList()
820 {
821         if (d.layout_)
822                 d.layout_->updateContents(false);
823 }
824
825
826 void GuiView::updateToolbars()
827 {
828         if (d.current_work_area_) {
829                 bool const math =
830                         d.current_work_area_->bufferView().cursor().inMathed();
831                 bool const table =
832                         lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
833                 bool const review =
834                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
835                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
836                 bool const mathmacrotemplate =
837                         lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
838
839                 d.toolbars_->update(math, table, review, mathmacrotemplate);
840         } else
841                 d.toolbars_->update(false, false, false, false);
842
843         // update read-only status of open dialogs.
844         checkStatus();
845 }
846
847
848 Buffer * GuiView::buffer()
849 {
850         if (d.current_work_area_)
851                 return &d.current_work_area_->bufferView().buffer();
852         return 0;
853 }
854
855
856 Buffer const * GuiView::buffer() const
857 {
858         if (d.current_work_area_)
859                 return &d.current_work_area_->bufferView().buffer();
860         return 0;
861 }
862
863
864 void GuiView::setBuffer(Buffer * newBuffer)
865 {
866         LASSERT(newBuffer, /**/);
867         setBusy(true);
868
869         GuiWorkArea * wa = workArea(*newBuffer);
870         if (wa == 0) {
871                 updateLabels(*newBuffer->masterBuffer());
872                 wa = addWorkArea(*newBuffer);
873         } else {
874                 //Disconnect the old buffer...there's no new one.
875                 disconnectBuffer();
876         }
877         connectBuffer(*newBuffer);
878         connectBufferView(wa->bufferView());
879         setCurrentWorkArea(wa);
880
881         setBusy(false);
882 }
883
884
885 void GuiView::connectBuffer(Buffer & buf)
886 {
887         buf.setGuiDelegate(this);
888 }
889
890
891 void GuiView::disconnectBuffer()
892 {
893         if (d.current_work_area_)
894                 d.current_work_area_->bufferView().setGuiDelegate(0);
895 }
896
897
898 void GuiView::connectBufferView(BufferView & bv)
899 {
900         bv.setGuiDelegate(this);
901 }
902
903
904 void GuiView::disconnectBufferView()
905 {
906         if (d.current_work_area_)
907                 d.current_work_area_->bufferView().setGuiDelegate(0);
908 }
909
910
911 void GuiView::errors(string const & error_type)
912 {
913         ErrorList & el = buffer()->errorList(error_type);
914         if (!el.empty())
915                 showDialog("errorlist", error_type);
916 }
917
918
919 void GuiView::structureChanged()
920 {
921         updateDialog("toc", "");
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::autoSave()
947 {
948         LYXERR(Debug::INFO, "Running autoSave()");
949
950         if (buffer())
951                 view()->buffer().autoSave();
952 }
953
954
955 void GuiView::resetAutosaveTimers()
956 {
957         if (lyxrc.autosave)
958                 d.autosave_timeout_.restart();
959 }
960
961
962 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
963 {
964         FuncStatus flag;
965         bool enable = true;
966         Buffer * buf = buffer();
967
968         /* In LyX/Mac, when a dialog is open, the menus of the
969            application can still be accessed without giving focus to
970            the main window. In this case, we want to disable the menu
971            entries that are buffer-related.
972
973            Note that this code is not perfect, as bug 1941 attests:
974            http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
975         */
976         if (cmd.origin == FuncRequest::MENU && !hasFocus())
977                 buf = 0;
978
979         switch(cmd.action) {
980         case LFUN_BUFFER_WRITE:
981                 enable = buf && (buf->isUnnamed() || !buf->isClean());
982                 break;
983
984         case LFUN_BUFFER_WRITE_AS:
985                 enable = buf;
986                 break;
987
988         case LFUN_SPLIT_VIEW:
989                 enable = buf;
990                 break;
991
992         case LFUN_CLOSE_TAB_GROUP:
993                 enable = d.currentTabWorkArea();
994                 break;
995
996         case LFUN_TOOLBAR_TOGGLE:
997                 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
998                 break;
999
1000         case LFUN_UI_TOGGLE:
1001                 flag.setOnOff(isFullScreen());
1002                 break;
1003
1004         case LFUN_DIALOG_TOGGLE:
1005                 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1006                 // fall through to set "enable"
1007         case LFUN_DIALOG_SHOW: {
1008                 string const name = cmd.getArg(0);
1009                 if (!buf)
1010                         enable = name == "aboutlyx"
1011                                 || name == "file" //FIXME: should be removed.
1012                                 || name == "prefs"
1013                                 || name == "texinfo";
1014                 else if (name == "print")
1015                         enable = buf->isExportable("dvi")
1016                                 && lyxrc.print_command != "none";
1017                 else if (name == "character") {
1018                         if (!view())
1019                                 enable = false;
1020                         else {
1021                                 InsetCode ic = view()->cursor().inset().lyxCode();
1022                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1023                         }
1024                 }
1025                 else if (name == "symbols") {
1026                         if (!view() || view()->cursor().inMathed())
1027                                 enable = false;
1028                         else {
1029                                 InsetCode ic = view()->cursor().inset().lyxCode();
1030                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1031                         }
1032                 }
1033                 else if (name == "latexlog")
1034                         enable = FileName(buf->logName()).isReadableFile();
1035                 else if (name == "spellchecker")
1036 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1037                         enable = !buf->isReadonly();
1038 #else
1039                         enable = false;
1040 #endif
1041                 else if (name == "vclog")
1042                         enable = buf->lyxvc().inUse();
1043                 break;
1044         }
1045
1046         case LFUN_DIALOG_UPDATE: {
1047                 string const name = cmd.getArg(0);
1048                 if (!buf)
1049                         enable = name == "prefs";
1050                 break;
1051         }
1052
1053         case LFUN_INSET_APPLY: {
1054                 if (!buf) {
1055                         enable = false;
1056                         break;
1057                 }
1058                 string const name = cmd.getArg(0);
1059                 Inset * inset = getOpenInset(name);
1060                 if (inset) {
1061                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1062                         FuncStatus fs;
1063                         if (!inset->getStatus(view()->cursor(), fr, fs)) {
1064                                 // Every inset is supposed to handle this
1065                                 LASSERT(false, /**/);
1066                         }
1067                         flag |= fs;
1068                 } else {
1069                         FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1070                         flag |= getStatus(fr);
1071                 }
1072                 enable = flag.enabled();
1073                 break;
1074         }
1075
1076         case LFUN_COMPLETION_INLINE:
1077                 if (!d.current_work_area_
1078                     || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1079                     enable = false;
1080                 break;
1081
1082         case LFUN_COMPLETION_POPUP:
1083                 if (!d.current_work_area_
1084                     || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1085                     enable = false;
1086                 break;
1087
1088         case LFUN_COMPLETION_COMPLETE:
1089                 if (!d.current_work_area_
1090                         || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1091                     enable = false;
1092                 break;
1093
1094         default:
1095                 if (!view()) {
1096                         enable = false;
1097                         break;
1098                 }
1099         }
1100
1101         if (!enable)
1102                 flag.enabled(false);
1103
1104         return flag;
1105 }
1106
1107
1108 static FileName selectTemplateFile()
1109 {
1110         FileDialog dlg(qt_("Select template file"));
1111         dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1112         dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1113
1114         FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1115                              QStringList(qt_("LyX Documents (*.lyx)")));
1116
1117         if (result.first == FileDialog::Later)
1118                 return FileName();
1119         if (result.second.isEmpty())
1120                 return FileName();
1121         return FileName(fromqstr(result.second));
1122 }
1123
1124
1125 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1126 {
1127         setBusy(true);
1128
1129         Buffer * newBuffer = checkAndLoadLyXFile(filename);
1130
1131         if (!newBuffer) {
1132                 message(_("Document not loaded."));
1133                 setBusy(false);
1134                 return 0;
1135         }
1136         
1137         setBuffer(newBuffer);
1138
1139         // scroll to the position when the file was last closed
1140         if (lyxrc.use_lastfilepos) {
1141                 LastFilePosSection::FilePos filepos =
1142                         LyX::ref().session().lastFilePos().load(filename);
1143                 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1144         }
1145
1146         if (tolastfiles)
1147                 LyX::ref().session().lastFiles().add(filename);
1148
1149         setBusy(false);
1150         return newBuffer;
1151 }
1152
1153
1154 void GuiView::openDocument(string const & fname)
1155 {
1156         string initpath = lyxrc.document_path;
1157
1158         if (buffer()) {
1159                 string const trypath = buffer()->filePath();
1160                 // If directory is writeable, use this as default.
1161                 if (FileName(trypath).isDirWritable())
1162                         initpath = trypath;
1163         }
1164
1165         string filename;
1166
1167         if (fname.empty()) {
1168                 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1169                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1170                 dlg.setButton2(qt_("Examples|#E#e"),
1171                                 toqstr(addPath(package().system_support().absFilename(), "examples")));
1172
1173                 FileDialog::Result result =
1174                         dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1175
1176                 if (result.first == FileDialog::Later)
1177                         return;
1178
1179                 filename = fromqstr(result.second);
1180
1181                 // check selected filename
1182                 if (filename.empty()) {
1183                         message(_("Canceled."));
1184                         return;
1185                 }
1186         } else
1187                 filename = fname;
1188
1189         // get absolute path of file and add ".lyx" to the filename if
1190         // necessary. 
1191         FileName const fullname = 
1192                         fileSearch(string(), filename, "lyx", support::may_not_exist);
1193         if (!fullname.empty())
1194                 filename = fullname.absFilename();
1195
1196         // if the file doesn't exist, let the user create one
1197         if (!fullname.exists()) {
1198                 // the user specifically chose this name. Believe him.
1199                 Buffer * const b = newFile(filename, string(), true);
1200                 if (b)
1201                         setBuffer(b);
1202                 return;
1203         }
1204
1205         docstring const disp_fn = makeDisplayPath(filename);
1206         message(bformat(_("Opening document %1$s..."), disp_fn));
1207
1208         docstring str2;
1209         Buffer * buf = loadDocument(fullname);
1210         if (buf) {
1211                 updateLabels(*buf);
1212                 
1213                 setBuffer(buf);
1214                 buf->errors("Parse");
1215                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1216         } else {
1217                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1218         }
1219         message(str2);
1220 }
1221
1222 // FIXME: clean that
1223 static bool import(GuiView * lv, FileName const & filename,
1224         string const & format, ErrorList & errorList)
1225 {
1226         FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1227
1228         string loader_format;
1229         vector<string> loaders = theConverters().loaders();
1230         if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1231                 for (vector<string>::const_iterator it = loaders.begin();
1232                      it != loaders.end(); ++it) {
1233                         if (!theConverters().isReachable(format, *it))
1234                                 continue;
1235
1236                         string const tofile =
1237                                 support::changeExtension(filename.absFilename(),
1238                                 formats.extension(*it));
1239                         if (!theConverters().convert(0, filename, FileName(tofile),
1240                                 filename, format, *it, errorList))
1241                                 return false;
1242                         loader_format = *it;
1243                         break;
1244                 }
1245                 if (loader_format.empty()) {
1246                         frontend::Alert::error(_("Couldn't import file"),
1247                                      bformat(_("No information for importing the format %1$s."),
1248                                          formats.prettyName(format)));
1249                         return false;
1250                 }
1251         } else
1252                 loader_format = format;
1253
1254         if (loader_format == "lyx") {
1255                 Buffer * buf = lv->loadDocument(lyxfile);
1256                 if (!buf)
1257                         return false;
1258                 updateLabels(*buf);
1259                 lv->setBuffer(buf);
1260                 buf->errors("Parse");
1261         } else {
1262                 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1263                 if (!b)
1264                         return false;
1265                 lv->setBuffer(b);
1266                 bool as_paragraphs = loader_format == "textparagraph";
1267                 string filename2 = (loader_format == format) ? filename.absFilename()
1268                         : support::changeExtension(filename.absFilename(),
1269                                           formats.extension(loader_format));
1270                 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1271                 theLyXFunc().setLyXView(lv);
1272                 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1273         }
1274
1275         return true;
1276 }
1277
1278
1279 void GuiView::importDocument(string const & argument)
1280 {
1281         string format;
1282         string filename = split(argument, format, ' ');
1283
1284         LYXERR(Debug::INFO, format << " file: " << filename);
1285
1286         // need user interaction
1287         if (filename.empty()) {
1288                 string initpath = lyxrc.document_path;
1289
1290                 Buffer const * buf = buffer();
1291                 if (buf) {
1292                         string const trypath = buf->filePath();
1293                         // If directory is writeable, use this as default.
1294                         if (FileName(trypath).isDirWritable())
1295                                 initpath = trypath;
1296                 }
1297
1298                 docstring const text = bformat(_("Select %1$s file to import"),
1299                         formats.prettyName(format));
1300
1301                 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1302                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1303                 dlg.setButton2(qt_("Examples|#E#e"),
1304                         toqstr(addPath(package().system_support().absFilename(), "examples")));
1305
1306                 docstring filter = formats.prettyName(format);
1307                 filter += " (*.";
1308                 // FIXME UNICODE
1309                 filter += from_utf8(formats.extension(format));
1310                 filter += ')';
1311
1312                 FileDialog::Result result =
1313                         dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1314
1315                 if (result.first == FileDialog::Later)
1316                         return;
1317
1318                 filename = fromqstr(result.second);
1319
1320                 // check selected filename
1321                 if (filename.empty())
1322                         message(_("Canceled."));
1323         }
1324
1325         if (filename.empty())
1326                 return;
1327
1328         // get absolute path of file
1329         FileName const fullname(support::makeAbsPath(filename));
1330
1331         FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1332
1333         // Check if the document already is open
1334         Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1335         if (buf) {
1336                 setBuffer(buf);
1337                 if (!closeBuffer()) {
1338                         message(_("Canceled."));
1339                         return;
1340                 }
1341         }
1342
1343         docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1344
1345         // if the file exists already, and we didn't do
1346         // -i lyx thefile.lyx, warn
1347         if (lyxfile.exists() && fullname != lyxfile) {
1348
1349                 docstring text = bformat(_("The document %1$s already exists.\n\n"
1350                         "Do you want to overwrite that document?"), displaypath);
1351                 int const ret = Alert::prompt(_("Overwrite document?"),
1352                         text, 0, 1, _("&Overwrite"), _("&Cancel"));
1353
1354                 if (ret == 1) {
1355                         message(_("Canceled."));
1356                         return;
1357                 }
1358         }
1359
1360         message(bformat(_("Importing %1$s..."), displaypath));
1361         ErrorList errorList;
1362         if (import(this, fullname, format, errorList))
1363                 message(_("imported."));
1364         else
1365                 message(_("file not imported!"));
1366
1367         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1368 }
1369
1370
1371 void GuiView::newDocument(string const & filename, bool from_template)
1372 {
1373         FileName initpath(lyxrc.document_path);
1374         Buffer * buf = buffer();
1375         if (buf) {
1376                 FileName const trypath(buf->filePath());
1377                 // If directory is writeable, use this as default.
1378                 if (trypath.isDirWritable())
1379                         initpath = trypath;
1380         }
1381
1382         string templatefile = from_template ?
1383                 selectTemplateFile().absFilename() : string();
1384         Buffer * b;
1385         if (filename.empty())
1386                 b = newUnnamedFile(templatefile, initpath);
1387         else
1388                 b = newFile(filename, templatefile, true);
1389
1390         if (b)
1391                 setBuffer(b);
1392         // Ensure the cursor is correctly positionned on screen.
1393         view()->showCursor();
1394 }
1395
1396
1397 void GuiView::insertLyXFile(docstring const & fname)
1398 {
1399         BufferView * bv = view();
1400         if (!bv)
1401                 return;
1402
1403         // FIXME UNICODE
1404         FileName filename(to_utf8(fname));
1405         
1406         if (!filename.empty()) {
1407                 bv->insertLyXFile(filename);
1408                 return;
1409         }
1410
1411         // Launch a file browser
1412         // FIXME UNICODE
1413         string initpath = lyxrc.document_path;
1414         string const trypath = bv->buffer().filePath();
1415         // If directory is writeable, use this as default.
1416         if (FileName(trypath).isDirWritable())
1417                 initpath = trypath;
1418
1419         // FIXME UNICODE
1420         FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1421         dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1422         dlg.setButton2(qt_("Examples|#E#e"),
1423                 toqstr(addPath(package().system_support().absFilename(),
1424                 "examples")));
1425
1426         FileDialog::Result result = dlg.open(toqstr(initpath),
1427                              QStringList(qt_("LyX Documents (*.lyx)")));
1428
1429         if (result.first == FileDialog::Later)
1430                 return;
1431
1432         // FIXME UNICODE
1433         filename.set(fromqstr(result.second));
1434
1435         // check selected filename
1436         if (filename.empty()) {
1437                 // emit message signal.
1438                 message(_("Canceled."));
1439                 return;
1440         }
1441
1442         bv->insertLyXFile(filename);
1443 }
1444
1445
1446 void GuiView::insertPlaintextFile(docstring const & fname,
1447         bool asParagraph)
1448 {
1449         BufferView * bv = view();
1450         if (!bv)
1451                 return;
1452
1453         // FIXME UNICODE
1454         FileName filename(to_utf8(fname));
1455         
1456         if (!filename.empty()) {
1457                 bv->insertPlaintextFile(filename, asParagraph);
1458                 return;
1459         }
1460
1461         FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1462                 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1463
1464         FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1465                 QStringList());
1466
1467         if (result.first == FileDialog::Later)
1468                 return;
1469
1470         // FIXME UNICODE
1471         filename.set(fromqstr(result.second));
1472
1473         // check selected filename
1474         if (filename.empty()) {
1475                 // emit message signal.
1476                 message(_("Canceled."));
1477                 return;
1478         }
1479
1480         bv->insertPlaintextFile(filename, asParagraph);
1481 }
1482
1483
1484 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1485 {
1486         FileName fname = b.fileName();
1487         FileName const oldname = fname;
1488
1489         if (!newname.empty()) {
1490                 // FIXME UNICODE
1491                 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1492         } else {
1493                 // Switch to this Buffer.
1494                 setBuffer(&b);
1495
1496                 /// No argument? Ask user through dialog.
1497                 // FIXME UNICODE
1498                 FileDialog dlg(qt_("Choose a filename to save document as"),
1499                                    LFUN_BUFFER_WRITE_AS);
1500                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1501                 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1502
1503                 if (!isLyXFilename(fname.absFilename()))
1504                         fname.changeExtension(".lyx");
1505
1506                 FileDialog::Result result =
1507                         dlg.save(toqstr(fname.onlyPath().absFilename()),
1508                                QStringList(qt_("LyX Documents (*.lyx)")),
1509                                      toqstr(fname.onlyFileName()));
1510
1511                 if (result.first == FileDialog::Later)
1512                         return false;
1513
1514                 fname.set(fromqstr(result.second));
1515
1516                 if (fname.empty())
1517                         return false;
1518
1519                 if (!isLyXFilename(fname.absFilename()))
1520                         fname.changeExtension(".lyx");
1521         }
1522
1523         if (FileName(fname).exists()) {
1524                 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1525                 docstring text = bformat(_("The document %1$s already "
1526                                            "exists.\n\nDo you want to "
1527                                            "overwrite that document?"), 
1528                                          file);
1529                 int const ret = Alert::prompt(_("Overwrite document?"),
1530                         text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1531                 switch (ret) {
1532                 case 0: break;
1533                 case 1: return renameBuffer(b, docstring());
1534                 case 2: return false;
1535                 }
1536         }
1537
1538         // Ok, change the name of the buffer
1539         b.setFileName(fname.absFilename());
1540         b.markDirty();
1541         bool unnamed = b.isUnnamed();
1542         b.setUnnamed(false);
1543         b.saveCheckSum(fname);
1544
1545         if (!saveBuffer(b)) {
1546                 b.setFileName(oldname.absFilename());
1547                 b.setUnnamed(unnamed);
1548                 b.saveCheckSum(oldname);
1549                 return false;
1550         }
1551
1552         return true;
1553 }
1554
1555
1556 bool GuiView::saveBuffer(Buffer & b)
1557 {
1558         if (b.isUnnamed())
1559                 return renameBuffer(b, docstring());
1560
1561         if (b.save()) {
1562                 LyX::ref().session().lastFiles().add(b.fileName());
1563                 return true;
1564         }
1565
1566         // Switch to this Buffer.
1567         setBuffer(&b);
1568
1569         // FIXME: we don't tell the user *WHY* the save failed !!
1570         docstring const file = makeDisplayPath(b.absFileName(), 30);
1571         docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1572                                    "Do you want to rename the document and "
1573                                    "try again?"), file);
1574         int const ret = Alert::prompt(_("Rename and save?"),
1575                 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1576         switch (ret) {
1577         case 0:
1578                 if (!renameBuffer(b, docstring()))
1579                         return false;
1580                 break;
1581         case 1:
1582                 break;
1583         case 2:
1584                 return false;
1585         }
1586
1587         return saveBuffer(b);
1588 }
1589
1590
1591 bool GuiView::closeBuffer()
1592 {
1593         Buffer * buf = buffer();
1594         return buf && closeBuffer(*buf);
1595 }
1596
1597
1598 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1599 {
1600         // goto bookmark to update bookmark pit.
1601         //FIXME: we should update only the bookmarks related to this buffer!
1602         for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1603                 theLyXFunc().gotoBookmark(i+1, false, false);
1604
1605         if (buf.isClean() || buf.paragraphs().empty()) {
1606                 if (buf.masterBuffer() == &buf && tolastopened)
1607                         LyX::ref().session().lastOpened().add(buf.fileName());
1608                 theBufferList().release(&buf);
1609                 return true;
1610         }
1611         // Switch to this Buffer.
1612         setBuffer(&buf);
1613
1614         docstring file;
1615         // FIXME: Unicode?
1616         if (buf.isUnnamed())
1617                 file = from_utf8(buf.fileName().onlyFileName());
1618         else
1619                 file = buf.fileName().displayName(30);
1620
1621         // Bring this window to top before asking questions.
1622         raise();
1623         activateWindow();
1624
1625         docstring const text = bformat(_("The document %1$s has unsaved changes."
1626                 "\n\nDo you want to save the document or discard the changes?"), file);
1627         int const ret = Alert::prompt(_("Save changed document?"),
1628                 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1629
1630         switch (ret) {
1631         case 0:
1632                 if (!saveBuffer(buf))
1633                         return false;
1634                 break;
1635         case 1:
1636                 // if we crash after this we could
1637                 // have no autosave file but I guess
1638                 // this is really improbable (Jug)
1639                 removeAutosaveFile(buf.absFileName());
1640                 break;
1641         case 2:
1642                 return false;
1643         }
1644
1645         // save file names to .lyx/session
1646         // if master/slave are both open, do not save slave since it
1647         // will be automatically loaded when the master is loaded
1648         if (buf.masterBuffer() == &buf && tolastopened)
1649                 LyX::ref().session().lastOpened().add(buf.fileName());
1650
1651         theBufferList().release(&buf);
1652         return true;
1653 }
1654
1655
1656 bool GuiView::dispatch(FuncRequest const & cmd)
1657 {
1658         BufferView * bv = view();       
1659         // By default we won't need any update.
1660         if (bv)
1661                 bv->cursor().updateFlags(Update::None);
1662
1663         switch(cmd.action) {
1664                 case LFUN_BUFFER_IMPORT:
1665                         importDocument(to_utf8(cmd.argument()));
1666                         break;
1667
1668                 case LFUN_BUFFER_SWITCH:
1669                         setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1670                         break;
1671
1672                 case LFUN_BUFFER_NEXT:
1673                         setBuffer(theBufferList().next(buffer()));
1674                         break;
1675
1676                 case LFUN_BUFFER_PREVIOUS:
1677                         setBuffer(theBufferList().previous(buffer()));
1678                         break;
1679
1680                 case LFUN_COMMAND_EXECUTE: {
1681                         bool const show_it = cmd.argument() != "off";
1682                         d.toolbars_->showCommandBuffer(show_it);
1683                         break;
1684                 }
1685                 case LFUN_DROP_LAYOUTS_CHOICE:
1686                         if (d.layout_)
1687                                 d.layout_->showPopup();
1688                         break;
1689
1690                 case LFUN_MENU_OPEN:
1691                         if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1692                                 menu->exec(QCursor::pos());
1693                         break;
1694
1695                 case LFUN_FILE_INSERT:
1696                         insertLyXFile(cmd.argument());
1697                         break;
1698                 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1699                         insertPlaintextFile(cmd.argument(), true);
1700                         break;
1701
1702                 case LFUN_FILE_INSERT_PLAINTEXT:
1703                         insertPlaintextFile(cmd.argument(), false);
1704                         break;
1705
1706                 case LFUN_BUFFER_WRITE:
1707                         if (bv)
1708                                 saveBuffer(bv->buffer());
1709                         break;
1710
1711                 case LFUN_BUFFER_WRITE_AS:
1712                         if (bv)
1713                                 renameBuffer(bv->buffer(), cmd.argument());
1714                         break;
1715
1716                 case LFUN_BUFFER_WRITE_ALL: {
1717                         Buffer * first = theBufferList().first();
1718                         if (!first)
1719                                 break;
1720                         message(_("Saving all documents..."));
1721                         // We cannot use a for loop as the buffer list cycles.
1722                         Buffer * b = first;
1723                         do {
1724                                 if (!b->isClean()) {
1725                                         saveBuffer(*b);
1726                                         LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1727                                 }
1728                                 b = theBufferList().next(b);
1729                         } while (b != first); 
1730                         message(_("All documents saved."));
1731                         break;
1732                 }
1733
1734                 case LFUN_TOOLBAR_TOGGLE: {
1735                         string const name = cmd.getArg(0);
1736                         bool const allowauto = cmd.getArg(1) == "allowauto";
1737                         // it is possible to get current toolbar status like this,...
1738                         // but I decide to obey the order of ToolbarBackend::flags
1739                         // and disregard real toolbar status.
1740                         // toolbars_->saveToolbarInfo();
1741                         //
1742                         // toggle state on/off/auto
1743                         d.toolbars_->toggleToolbarState(name, allowauto);
1744                         // update toolbar
1745                         updateToolbars();
1746
1747                         ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1748                         if (!tbi) {
1749                                 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1750                                 break;
1751                         }
1752                         docstring state;
1753                         if (tbi->flags & ToolbarInfo::ON)
1754                                 state = _("on");
1755                         else if (tbi->flags & ToolbarInfo::OFF)
1756                                 state = _("off");
1757                         else if (tbi->flags & ToolbarInfo::AUTO)
1758                                 state = _("auto");
1759
1760                         message(bformat(_("Toolbar \"%1$s\" state set to %2$s"), 
1761                                            _(tbi->gui_name), state));
1762                         break;
1763                 }
1764
1765                 case LFUN_DIALOG_UPDATE: {
1766                         string const name = to_utf8(cmd.argument());
1767                         // Can only update a dialog connected to an existing inset
1768                         Inset * inset = getOpenInset(name);
1769                         if (inset) {
1770                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1771                                 inset->dispatch(view()->cursor(), fr);
1772                         } else if (name == "paragraph") {
1773                                 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1774                         } else if (name == "prefs") {
1775                                 updateDialog(name, string());
1776                         }
1777                         break;
1778                 }
1779
1780                 case LFUN_DIALOG_TOGGLE: {
1781                         if (isDialogVisible(cmd.getArg(0)))
1782                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1783                         else
1784                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1785                         break;
1786                 }
1787
1788                 case LFUN_DIALOG_DISCONNECT_INSET:
1789                         disconnectDialog(to_utf8(cmd.argument()));
1790                         break;
1791
1792                 case LFUN_DIALOG_HIDE: {
1793                         guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1794                         break;
1795                 }
1796
1797                 case LFUN_DIALOG_SHOW: {
1798                         string const name = cmd.getArg(0);
1799                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1800
1801                         if (name == "character") {
1802                                 data = freefont2string();
1803                                 if (!data.empty())
1804                                         showDialog("character", data);
1805                         } else if (name == "latexlog") {
1806                                 Buffer::LogType type; 
1807                                 string const logfile = buffer()->logName(&type);
1808                                 switch (type) {
1809                                 case Buffer::latexlog:
1810                                         data = "latex ";
1811                                         break;
1812                                 case Buffer::buildlog:
1813                                         data = "literate ";
1814                                         break;
1815                                 }
1816                                 data += Lexer::quoteString(logfile);
1817                                 showDialog("log", data);
1818                         } else if (name == "vclog") {
1819                                 string const data = "vc " +
1820                                         Lexer::quoteString(buffer()->lyxvc().getLogFile());
1821                                 showDialog("log", data);
1822                         } else if (name == "symbols") {
1823                                 data = bv->cursor().getEncoding()->name();
1824                                 if (!data.empty())
1825                                         showDialog("symbols", data);
1826                         } else
1827                                 showDialog(name, data);
1828                         break;
1829                 }
1830
1831                 case LFUN_INSET_APPLY: {
1832                         string const name = cmd.getArg(0);
1833                         Inset * inset = getOpenInset(name);
1834                         if (inset) {
1835                                 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1836                                 inset->dispatch(view()->cursor(), fr);
1837                         } else {
1838                                 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1839                                 lyx::dispatch(fr);
1840                         }
1841                         break;
1842                 }
1843
1844                 case LFUN_UI_TOGGLE:
1845                         lfunUiToggle(cmd);
1846                         // Make sure the keyboard focus stays in the work area.
1847                         setFocus();
1848                         break;
1849
1850                 case LFUN_COMPLETION_INLINE:
1851                         if (d.current_work_area_)
1852                                 d.current_work_area_->completer().showInline();
1853                         break;
1854
1855                 case LFUN_SPLIT_VIEW:
1856                         if (Buffer * buf = buffer()) {
1857                                 string const orientation = cmd.getArg(0);
1858                                 d.splitter_->setOrientation(orientation == "vertical"
1859                                         ? Qt::Vertical : Qt::Horizontal);
1860                                 TabWorkArea * twa = addTabWorkArea();
1861                                 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1862                                 setCurrentWorkArea(wa);
1863                         }
1864                         break;
1865
1866                 case LFUN_CLOSE_TAB_GROUP:
1867                         if (TabWorkArea * twa = d.currentTabWorkArea()) {
1868                                 delete twa;
1869                                 twa = d.currentTabWorkArea();
1870                                 // Switch to the next GuiWorkArea in the found TabWorkArea.
1871                                 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1872                                 if (d.splitter_->count() == 0)
1873                                         // No more work area, switch to the background widget.
1874                                         d.setBackground();
1875                         }
1876                         break;
1877                         
1878                 case LFUN_COMPLETION_POPUP:
1879                         if (d.current_work_area_)
1880                                 d.current_work_area_->completer().showPopup();
1881                         break;
1882
1883
1884                 case LFUN_COMPLETION_COMPLETE:
1885                         if (d.current_work_area_)
1886                                 d.current_work_area_->completer().tab();
1887                         break;
1888
1889                 default:
1890                         return false;
1891         }
1892
1893         return true;
1894 }
1895
1896
1897 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1898 {
1899         string const arg = cmd.getArg(0);
1900         if (arg == "scrollbar") {
1901                 // hide() is of no help
1902                 if (d.current_work_area_->verticalScrollBarPolicy() ==
1903                         Qt::ScrollBarAlwaysOff)
1904
1905                         d.current_work_area_->setVerticalScrollBarPolicy(
1906                                 Qt::ScrollBarAsNeeded);
1907                 else
1908                         d.current_work_area_->setVerticalScrollBarPolicy(
1909                                 Qt::ScrollBarAlwaysOff);
1910                 return;
1911         }
1912         if (arg == "statusbar") {
1913                 statusBar()->setVisible(!statusBar()->isVisible());
1914                 return;
1915         }
1916         if (arg == "menubar") {
1917                 menuBar()->setVisible(!menuBar()->isVisible());
1918                 return;
1919         }
1920 #if QT_VERSION >= 0x040300
1921         if (arg == "frame") {
1922                 int l, t, r, b;
1923                 getContentsMargins(&l, &t, &r, &b);
1924                 //are the frames in default state?
1925                 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1926                 if (l == 0) {
1927                         setContentsMargins(-2, -2, -2, -2);
1928                 } else {
1929                         setContentsMargins(0, 0, 0, 0);
1930                 }
1931                 return;
1932         }
1933 #endif
1934         if (arg != "fullscreen") {
1935                 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1936                 return;
1937         }
1938
1939         if (lyxrc.full_screen_toolbars)
1940                 d.toolbars_->toggleFullScreen(!isFullScreen());
1941
1942         if (isFullScreen()) {
1943                 for (int i = 0; i != d.splitter_->count(); ++i)
1944                         d.tabWorkArea(i)->setFullScreen(false);
1945 #if QT_VERSION >= 0x040300
1946                 setContentsMargins(0, 0, 0, 0);
1947 #endif
1948                 setWindowState(windowState() ^ Qt::WindowFullScreen);
1949                 menuBar()->show();
1950                 statusBar()->show();
1951         } else {
1952                 for (int i = 0; i != d.splitter_->count(); ++i)
1953                         d.tabWorkArea(i)->setFullScreen(true);
1954 #if QT_VERSION >= 0x040300
1955                 setContentsMargins(-2, -2, -2, -2);
1956 #endif
1957                 setWindowState(windowState() ^ Qt::WindowFullScreen);
1958                 statusBar()->hide();
1959                 menuBar()->hide();
1960         }
1961 }
1962
1963
1964 Buffer const * GuiView::updateInset(Inset const * inset)
1965 {
1966         if (!d.current_work_area_)
1967                 return 0;
1968
1969         if (inset)
1970                 d.current_work_area_->scheduleRedraw();
1971
1972         return &d.current_work_area_->bufferView().buffer();
1973 }
1974
1975
1976 void GuiView::restartCursor()
1977 {
1978         /* When we move around, or type, it's nice to be able to see
1979          * the cursor immediately after the keypress.
1980          */
1981         if (d.current_work_area_)
1982                 d.current_work_area_->startBlinkingCursor();
1983
1984         // Take this occasion to update the other GUI elements.
1985         updateLayoutList();
1986         updateToolbars();
1987         updateStatusBar();
1988 }
1989
1990
1991 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1992 {
1993         if (d.current_work_area_)
1994                 d.current_work_area_->completer().updateVisibility(cur, start, keep);
1995 }
1996
1997 namespace {
1998
1999 // This list should be kept in sync with the list of insets in
2000 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
2001 // dialog should have the same name as the inset.
2002
2003 char const * const dialognames[] = {
2004 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2005 "citation", "document", "errorlist", "ert", "external", "file",
2006 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2007 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", 
2008 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2009
2010 #ifdef HAVE_LIBAIKSAURUS
2011 "thesaurus",
2012 #endif
2013
2014 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2015
2016 char const * const * const end_dialognames =
2017         dialognames + (sizeof(dialognames) / sizeof(char *));
2018
2019 class cmpCStr {
2020 public:
2021         cmpCStr(char const * name) : name_(name) {}
2022         bool operator()(char const * other) {
2023                 return strcmp(other, name_) == 0;
2024         }
2025 private:
2026         char const * name_;
2027 };
2028
2029
2030 bool isValidName(string const & name)
2031 {
2032         return find_if(dialognames, end_dialognames,
2033                             cmpCStr(name.c_str())) != end_dialognames;
2034 }
2035
2036 } // namespace anon
2037
2038
2039 void GuiView::resetDialogs()
2040 {
2041         // Make sure that no LFUN uses any LyXView.
2042         theLyXFunc().setLyXView(0);
2043         // FIXME: the "math panels" toolbar takes an awful lot of time to
2044         // initialise so we don't do that for the time being.
2045         //d.toolbars_->init();
2046         guiApp->menus().fillMenuBar(menuBar(), this);
2047         if (d.layout_)
2048                 d.layout_->updateContents(true);
2049         // Now update controls with current buffer.
2050         theLyXFunc().setLyXView(this);
2051         restartCursor();
2052 }
2053
2054
2055 Dialog * GuiView::find_or_build(string const & name)
2056 {
2057         if (!isValidName(name))
2058                 return 0;
2059
2060         map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2061
2062         if (it != d.dialogs_.end())
2063                 return it->second.get();
2064
2065         Dialog * dialog = build(name);
2066         d.dialogs_[name].reset(dialog);
2067         if (lyxrc.allow_geometry_session)
2068                 dialog->restoreSession();
2069         return dialog;
2070 }
2071
2072
2073 void GuiView::showDialog(string const & name, string const & data,
2074         Inset * inset)
2075 {
2076         if (d.in_show_)
2077                 return;
2078
2079         d.in_show_ = true;
2080         Dialog * dialog = find_or_build(name);
2081         if (dialog) {
2082                 dialog->showData(data);
2083                 if (inset)
2084                         d.open_insets_[name] = inset;
2085         }
2086         d.in_show_ = false;
2087 }
2088
2089
2090 bool GuiView::isDialogVisible(string const & name) const
2091 {
2092         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2093         if (it == d.dialogs_.end())
2094                 return false;
2095         return it->second.get()->isVisibleView();
2096 }
2097
2098
2099 void GuiView::hideDialog(string const & name, Inset * inset)
2100 {
2101         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2102         if (it == d.dialogs_.end())
2103                 return;
2104
2105         if (inset && inset != getOpenInset(name))
2106                 return;
2107
2108         Dialog * const dialog = it->second.get();
2109         if (dialog->isVisibleView())
2110                 dialog->hideView();
2111         d.open_insets_[name] = 0;
2112 }
2113
2114
2115 void GuiView::disconnectDialog(string const & name)
2116 {
2117         if (!isValidName(name))
2118                 return;
2119
2120         if (d.open_insets_.find(name) != d.open_insets_.end())
2121                 d.open_insets_[name] = 0;
2122 }
2123
2124
2125 Inset * GuiView::getOpenInset(string const & name) const
2126 {
2127         if (!isValidName(name))
2128                 return 0;
2129
2130         map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2131         return it == d.open_insets_.end() ? 0 : it->second;
2132 }
2133
2134
2135 void GuiView::hideAll() const
2136 {
2137         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2138         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2139
2140         for(; it != end; ++it)
2141                 it->second->hideView();
2142 }
2143
2144
2145 void GuiView::updateDialogs()
2146 {
2147         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2148         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2149
2150         for(; it != end; ++it) {
2151                 Dialog * dialog = it->second.get();
2152                 if (!dialog->isVisibleView())
2153                         continue;
2154                 if (dialog->isBufferDependent()) {
2155                         if (buffer())
2156                                 dialog->updateView();
2157                         else
2158                                 dialog->enableView(false);
2159                 } else {
2160                         // A bit clunky, but the dialog will request
2161                         // that the kernel provides it with the necessary
2162                         // data.
2163                         dialog->updateDialog();
2164                 }
2165         }
2166         updateToolbars();
2167         updateLayoutList();
2168         updateStatusBar();
2169 }
2170
2171
2172 void GuiView::checkStatus()
2173 {
2174         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2175         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2176
2177         for(; it != end; ++it) {
2178                 Dialog * const dialog = it->second.get();
2179                 if (dialog && dialog->isVisibleView())
2180                         dialog->checkStatus();
2181         }
2182 }
2183
2184
2185
2186 // will be replaced by a proper factory...
2187 Dialog * createGuiAbout(GuiView & lv);
2188 Dialog * createGuiBibitem(GuiView & lv);
2189 Dialog * createGuiBibtex(GuiView & lv);
2190 Dialog * createGuiBox(GuiView & lv);
2191 Dialog * createGuiBranch(GuiView & lv);
2192 Dialog * createGuiChanges(GuiView & lv);
2193 Dialog * createGuiCharacter(GuiView & lv);
2194 Dialog * createGuiCitation(GuiView & lv);
2195 Dialog * createGuiDelimiter(GuiView & lv);
2196 Dialog * createGuiDocument(GuiView & lv);
2197 Dialog * createGuiErrorList(GuiView & lv);
2198 Dialog * createGuiERT(GuiView & lv);
2199 Dialog * createGuiExternal(GuiView & lv);
2200 Dialog * createGuiFloat(GuiView & lv);
2201 Dialog * createGuiGraphics(GuiView & lv);
2202 Dialog * createGuiHSpace(GuiView & lv);
2203 Dialog * createGuiInclude(GuiView & lv);
2204 Dialog * createGuiLabel(GuiView & lv);
2205 Dialog * createGuiListings(GuiView & lv);
2206 Dialog * createGuiLog(GuiView & lv);
2207 Dialog * createGuiMathMatrix(GuiView & lv);
2208 Dialog * createGuiNomenclature(GuiView & lv);
2209 Dialog * createGuiNote(GuiView & lv);
2210 Dialog * createGuiParagraph(GuiView & lv);
2211 Dialog * createGuiPreferences(GuiView & lv);
2212 Dialog * createGuiPrint(GuiView & lv);
2213 Dialog * createGuiRef(GuiView & lv);
2214 Dialog * createGuiSearch(GuiView & lv);
2215 Dialog * createGuiSendTo(GuiView & lv);
2216 Dialog * createGuiShowFile(GuiView & lv);
2217 Dialog * createGuiSpellchecker(GuiView & lv);
2218 Dialog * createGuiSymbols(GuiView & lv);
2219 Dialog * createGuiTabularCreate(GuiView & lv);
2220 Dialog * createGuiTabular(GuiView & lv);
2221 Dialog * createGuiTexInfo(GuiView & lv);
2222 Dialog * createGuiToc(GuiView & lv);
2223 Dialog * createGuiThesaurus(GuiView & lv);
2224 Dialog * createGuiHyperlink(GuiView & lv);
2225 Dialog * createGuiVSpace(GuiView & lv);
2226 Dialog * createGuiViewSource(GuiView & lv);
2227 Dialog * createGuiWrap(GuiView & lv);
2228
2229
2230 Dialog * GuiView::build(string const & name)
2231 {
2232         LASSERT(isValidName(name), /**/);
2233
2234         if (name == "aboutlyx")
2235                 return createGuiAbout(*this);
2236         if (name == "bibitem")
2237                 return createGuiBibitem(*this);
2238         if (name == "bibtex")
2239                 return createGuiBibtex(*this);
2240         if (name == "box")
2241                 return createGuiBox(*this);
2242         if (name == "branch")
2243                 return createGuiBranch(*this);
2244         if (name == "changes")
2245                 return createGuiChanges(*this);
2246         if (name == "character")
2247                 return createGuiCharacter(*this);
2248         if (name == "citation")
2249                 return createGuiCitation(*this);
2250         if (name == "document")
2251                 return createGuiDocument(*this);
2252         if (name == "errorlist")
2253                 return createGuiErrorList(*this);
2254         if (name == "ert")
2255                 return createGuiERT(*this);
2256         if (name == "external")
2257                 return createGuiExternal(*this);
2258         if (name == "file")
2259                 return createGuiShowFile(*this);
2260         if (name == "findreplace")
2261                 return createGuiSearch(*this);
2262         if (name == "float")
2263                 return createGuiFloat(*this);
2264         if (name == "graphics")
2265                 return createGuiGraphics(*this);
2266         if (name == "include")
2267                 return createGuiInclude(*this);
2268         if (name == "nomenclature")
2269                 return createGuiNomenclature(*this);
2270         if (name == "label")
2271                 return createGuiLabel(*this);
2272         if (name == "log")
2273                 return createGuiLog(*this);
2274         if (name == "view-source")
2275                 return createGuiViewSource(*this);
2276         if (name == "mathdelimiter")
2277                 return createGuiDelimiter(*this);
2278         if (name == "mathmatrix")
2279                 return createGuiMathMatrix(*this);
2280         if (name == "note")
2281                 return createGuiNote(*this);
2282         if (name == "paragraph")
2283                 return createGuiParagraph(*this);
2284         if (name == "prefs")
2285                 return createGuiPreferences(*this);
2286         if (name == "print")
2287                 return createGuiPrint(*this);
2288         if (name == "ref")
2289                 return createGuiRef(*this);
2290         if (name == "sendto")
2291                 return createGuiSendTo(*this);
2292         if (name == "space")
2293                 return createGuiHSpace(*this);
2294         if (name == "spellchecker")
2295                 return createGuiSpellchecker(*this);
2296         if (name == "symbols")
2297                 return createGuiSymbols(*this);
2298         if (name == "tabular")
2299                 return createGuiTabular(*this);
2300         if (name == "tabularcreate")
2301                 return createGuiTabularCreate(*this);
2302         if (name == "texinfo")
2303                 return createGuiTexInfo(*this);
2304 #ifdef HAVE_LIBAIKSAURUS
2305         if (name == "thesaurus")
2306                 return createGuiThesaurus(*this);
2307 #endif
2308         if (name == "toc")
2309                 return createGuiToc(*this);
2310         if (name == "href")
2311                 return createGuiHyperlink(*this);
2312         if (name == "vspace")
2313                 return createGuiVSpace(*this);
2314         if (name == "wrap")
2315                 return createGuiWrap(*this);
2316         if (name == "listings")
2317                 return createGuiListings(*this);
2318
2319         return 0;
2320 }
2321
2322
2323 } // namespace frontend
2324 } // namespace lyx
2325
2326 #include "GuiView_moc.cpp"