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