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