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