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