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