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