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