]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
* make sure the Mac special menu item are only created once per QMenuBar.
[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 "GuiWorkArea.h"
22 #include "GuiKeySymbol.h"
23 #include "GuiToolbar.h"
24 #include "GuiToolbars.h"
25 #include "Menus.h"
26
27 #include "qt_helpers.h"
28
29 #include "frontends/alert.h"
30
31 #include "buffer_funcs.h"
32 #include "Buffer.h"
33 #include "BufferList.h"
34 #include "BufferParams.h"
35 #include "BufferView.h"
36 #include "Converter.h"
37 #include "Cursor.h"
38 #include "ErrorList.h"
39 #include "Format.h"
40 #include "FuncStatus.h"
41 #include "FuncRequest.h"
42 #include "support/gettext.h"
43 #include "Intl.h"
44 #include "Layout.h"
45 #include "Lexer.h"
46 #include "LyXFunc.h"
47 #include "LyX.h"
48 #include "LyXRC.h"
49 #include "LyXVC.h"
50 #include "Paragraph.h"
51 #include "TextClass.h"
52 #include "Text.h"
53 #include "ToolbarBackend.h"
54 #include "version.h"
55
56 #include "support/debug.h"
57 #include "support/FileFilterList.h"
58 #include "support/FileName.h"
59 #include "support/filetools.h"
60 #include "support/ForkedCalls.h"
61 #include "support/lstrings.h"
62 #include "support/os.h"
63 #include "support/Package.h"
64 #include "support/Timeout.h"
65
66 #include <QAction>
67 #include <QApplication>
68 #include <QCloseEvent>
69 #include <QDebug>
70 #include <QDesktopWidget>
71 #include <QDragEnterEvent>
72 #include <QDropEvent>
73 #include <QList>
74 #include <QMenu>
75 #include <QMenuBar>
76 #include <QPainter>
77 #include <QPixmap>
78 #include <QPoint>
79 #include <QPushButton>
80 #include <QSettings>
81 #include <QShowEvent>
82 #include <QSplitter>
83 #include <QStackedWidget>
84 #include <QStatusBar>
85 #include <QTimer>
86 #include <QToolBar>
87 #include <QUrl>
88 #include <QScrollBar>
89
90 #include <boost/assert.hpp>
91 #include <boost/bind.hpp>
92
93 #ifdef HAVE_SYS_TIME_H
94 # include <sys/time.h>
95 #endif
96 #ifdef HAVE_UNISTD_H
97 # include <unistd.h>
98 #endif
99
100 using namespace std;
101 using namespace lyx::support;
102
103 namespace lyx {
104 namespace frontend {
105
106 namespace {
107
108 class BackgroundWidget : public QWidget
109 {
110 public:
111         BackgroundWidget()
112         {
113                 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
114                 /// The text to be written on top of the pixmap
115                 QString const text = lyx_version ? lyx_version : qt_("unknown version");
116                 splash_ = QPixmap(":/images/banner.png");
117
118                 QPainter pain(&splash_);
119                 pain.setPen(QColor(255, 255, 0));
120                 QFont font;
121                 // The font used to display the version info
122                 font.setStyleHint(QFont::SansSerif);
123                 font.setWeight(QFont::Bold);
124                 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
125                 pain.setFont(font);
126                 pain.drawText(260, 270, text);
127         }
128
129         void paintEvent(QPaintEvent *)
130         {
131                 int x = (width() - splash_.width()) / 2;
132                 int y = (height() - splash_.height()) / 2;
133                 QPainter pain(this);
134                 pain.drawPixmap(x, y, splash_);
135         }
136
137 private:
138         QPixmap splash_;
139 };
140
141 } // namespace anon
142
143
144 typedef boost::shared_ptr<Dialog> DialogPtr;
145
146 struct GuiView::GuiViewPrivate
147 {
148         GuiViewPrivate()
149                 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
150                 in_show_(false)
151         {
152                 // hardcode here the platform specific icon size
153                 smallIconSize = 14;     // scaling problems
154                 normalIconSize = 20;    // ok, default
155                 bigIconSize = 26;               // better for some math icons
156
157                 splitter_ = new QSplitter;
158                 bg_widget_ = new BackgroundWidget;
159                 stack_widget_ = new QStackedWidget;
160                 stack_widget_->addWidget(bg_widget_);
161                 stack_widget_->addWidget(splitter_);
162                 setBackground();
163         }
164
165         ~GuiViewPrivate()
166         {
167                 delete splitter_;
168                 delete bg_widget_;
169                 delete stack_widget_;
170                 delete toolbars_;
171         }
172
173         QMenu * toolBarPopup(GuiView * parent)
174         {
175                 // FIXME: translation
176                 QMenu * menu = new QMenu(parent);
177                 QActionGroup * iconSizeGroup = new QActionGroup(parent);
178
179                 QAction * smallIcons = new QAction(iconSizeGroup);
180                 smallIcons->setText(qt_("Small-sized icons"));
181                 smallIcons->setCheckable(true);
182                 QObject::connect(smallIcons, SIGNAL(triggered()),
183                         parent, SLOT(smallSizedIcons()));
184                 menu->addAction(smallIcons);
185
186                 QAction * normalIcons = new QAction(iconSizeGroup);
187                 normalIcons->setText(qt_("Normal-sized icons"));
188                 normalIcons->setCheckable(true);
189                 QObject::connect(normalIcons, SIGNAL(triggered()),
190                         parent, SLOT(normalSizedIcons()));
191                 menu->addAction(normalIcons);
192
193                 QAction * bigIcons = new QAction(iconSizeGroup);
194                 bigIcons->setText(qt_("Big-sized icons"));
195                 bigIcons->setCheckable(true);
196                 QObject::connect(bigIcons, SIGNAL(triggered()),
197                         parent, SLOT(bigSizedIcons()));
198                 menu->addAction(bigIcons);
199
200                 unsigned int cur = parent->iconSize().width();
201                 if ( cur == parent->d.smallIconSize)
202                         smallIcons->setChecked(true);
203                 else if (cur == parent->d.normalIconSize)
204                         normalIcons->setChecked(true);
205                 else if (cur == parent->d.bigIconSize)
206                         bigIcons->setChecked(true);
207
208                 return menu;
209         }
210
211         void setBackground()
212         {
213                 stack_widget_->setCurrentWidget(bg_widget_);
214                 bg_widget_->setUpdatesEnabled(true);
215         }
216
217         TabWorkArea * tabWorkArea(int i)
218         {
219                 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
220         }
221
222         TabWorkArea * currentTabWorkArea()
223         {
224                 if (splitter_->count() == 1)
225                         // The first TabWorkArea is always the first one, if any.
226                         return tabWorkArea(0);
227
228                 for (int i = 0; i != splitter_->count(); ++i) {
229                         TabWorkArea * twa = tabWorkArea(i);
230                         if (current_work_area_ == twa->currentWorkArea())
231                                 return twa;
232                 }
233
234                 // None has the focus so we just take the first one.
235                 return tabWorkArea(0);
236         }
237
238 public:
239         GuiWorkArea * current_work_area_;
240         QSplitter * splitter_;
241         QStackedWidget * stack_widget_;
242         BackgroundWidget * bg_widget_;
243         /// view's toolbars
244         GuiToolbars * toolbars_;
245         /// The main layout box.
246         /** 
247          * \warning Don't Delete! The layout box is actually owned by
248          * whichever toolbar contains it. All the GuiView class needs is a
249          * means of accessing it.
250          *
251          * FIXME: replace that with a proper model so that we are not limited
252          * to only one dialog.
253          */
254         GuiLayoutBox * layout_;
255
256         ///
257         map<string, Inset *> open_insets_;
258
259         ///
260         map<string, DialogPtr> dialogs_;
261
262         unsigned int smallIconSize;
263         unsigned int normalIconSize;
264         unsigned int bigIconSize;
265         ///
266         QTimer statusbar_timer_;
267         /// auto-saving of buffers
268         Timeout autosave_timeout_;
269         /// flag against a race condition due to multiclicks, see bug #1119
270         bool in_show_;
271 };
272
273
274 GuiView::GuiView(int id)
275         : d(*new GuiViewPrivate), id_(id)
276 {
277         // GuiToolbars *must* be initialised before the menu bar.
278         d.toolbars_ = new GuiToolbars(*this);
279
280         // set ourself as the current view. This is needed for the menu bar
281         // filling, at least for the static special menu item on Mac. Otherwise
282         // they are greyed out.
283         theLyXFunc().setLyXView(this);
284         
285         // Fill up the menu bar.
286         guiApp->menus().fillMenuBar(menuBar(), this, true);
287
288         setCentralWidget(d.stack_widget_);
289
290         // Start autosave timer
291         if (lyxrc.autosave) {
292                 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
293                 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
294                 d.autosave_timeout_.start();
295         }
296         connect(&d.statusbar_timer_, SIGNAL(timeout()),
297                 this, SLOT(clearMessage()));
298
299         // We don't want to keep the window in memory if it is closed.
300         setAttribute(Qt::WA_DeleteOnClose, true);
301
302 #ifndef Q_WS_MACX
303         // assign an icon to main form. We do not do it under Qt/Mac,
304         // since the icon is provided in the application bundle.
305         setWindowIcon(QPixmap(":/images/lyx.png"));
306 #endif
307
308         // For Drag&Drop.
309         setAcceptDrops(true);
310
311         statusBar()->setSizeGripEnabled(true);
312
313         // Forbid too small unresizable window because it can happen
314         // with some window manager under X11.
315         setMinimumSize(300, 200);
316
317         if (!lyxrc.allow_geometry_session)
318                 // No session handling, default to a sane size.
319                 setGeometry(50, 50, 690, 510);
320
321         // Now take care of session management.
322         QSettings settings;
323         QString const key = "view-" + QString::number(id_);
324 #ifdef Q_WS_X11
325         QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
326         QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
327         resize(size);
328         move(pos);
329 #else
330         if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
331                 setGeometry(50, 50, 690, 510);
332 #endif
333         setIconSize(settings.value(key + "/icon_size").toSize());
334 }
335
336
337 GuiView::~GuiView()
338 {
339         if (guiApp->currentView() == this)
340                 guiApp->setCurrentView(0);
341         theLyXFunc().setLyXView(0);
342         
343         delete &d;
344 }
345
346
347 void GuiView::setFocus()
348 {
349         if (d.current_work_area_)
350                 d.current_work_area_->setFocus();
351         else
352                 QWidget::setFocus();
353 }
354
355
356 QMenu * GuiView::createPopupMenu()
357 {
358         return d.toolBarPopup(this);
359 }
360
361
362 void GuiView::showEvent(QShowEvent * e)
363 {
364         LYXERR(Debug::GUI, "Passed Geometry "
365                 << size().height() << "x" << size().width()
366                 << "+" << pos().x() << "+" << pos().y());
367
368         if (d.splitter_->count() == 0)
369                 // No work area, switch to the background widget.
370                 d.setBackground();
371
372         QMainWindow::showEvent(e);
373 }
374
375
376 void GuiView::closeEvent(QCloseEvent * close_event)
377 {
378         // it can happen that this event arrives without selecting the view,
379         // e.g. when clicking the close button on a background window.
380         theLyXFunc().setLyXView(this);
381
382         while (Buffer * b = buffer()) {
383                 if (b->parent()) {
384                         // This is a child document, just close the tab after saving
385                         // but keep the file loaded.
386                         if (!saveBuffer(*b)) {
387                                 close_event->ignore();
388                                 return;
389                         }
390                         removeWorkArea(d.current_work_area_);
391                         continue;
392                 }
393
394                 std::vector<int> const & ids = guiApp->viewIds();
395                 for (size_type i = 0; i != ids.size(); ++i) {
396                         if (id_ == ids[i])
397                                 continue;
398                         if (guiApp->view(ids[i]).workArea(*b)) {
399                                 // FIXME 1: should we put an alert box here that the buffer
400                                 // is viewed elsewhere?
401                                 // FIXME 2: should we try to save this buffer in any case?
402                                 //saveBuffer(b);
403
404                                 // This buffer is also opened in another view, so
405                                 // but close the associated work area nevertheless.
406                                 removeWorkArea(d.current_work_area_);
407                                 // but don't close it.
408                                 b = 0;
409                                 break;
410                         }
411                 }
412                 if (b && !closeBuffer(*b)) {
413                         close_event->ignore();
414                         return;
415                 }
416         }
417
418         // Make sure that no LFUN use this close to be closed View.
419         theLyXFunc().setLyXView(0);
420
421         // Save toolbars configuration
422         if (isFullScreen()) {
423                 d.toolbars_->toggleFullScreen(!isFullScreen());
424                 updateToolbars();
425         }
426
427         // Make sure the timer time out will not trigger a statusbar update.
428         d.statusbar_timer_.stop();
429
430         // Saving fullscreen requires additional tweaks in the toolbar code.
431         // It wouldn't also work under linux natively.
432         if (lyxrc.allow_geometry_session && !isFullScreen()) {
433                 QSettings settings;
434                 QString const key = "view-" + QString::number(id_);
435 #ifdef Q_WS_X11
436                 settings.setValue(key + "/pos", pos());
437                 settings.setValue(key + "/size", size());
438 #else
439                 settings.setValue(key + "/geometry", saveGeometry());
440 #endif
441                 settings.setValue(key + "/icon_size", iconSize());
442                 d.toolbars_->saveToolbarInfo();
443                 // Now take care of all other dialogs:
444                 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
445                 for (; it!= d.dialogs_.end(); ++it)
446                         it->second->saveSession();
447         }
448
449         guiApp->unregisterView(id_);
450         close_event->accept();
451 }
452
453
454 void GuiView::dragEnterEvent(QDragEnterEvent * event)
455 {
456         if (event->mimeData()->hasUrls())
457                 event->accept();
458         /// \todo Ask lyx-devel is this is enough:
459         /// if (event->mimeData()->hasFormat("text/plain"))
460         ///     event->acceptProposedAction();
461 }
462
463
464 void GuiView::dropEvent(QDropEvent* event)
465 {
466         QList<QUrl> files = event->mimeData()->urls();
467         if (files.isEmpty())
468                 return;
469
470         LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
471         for (int i = 0; i != files.size(); ++i) {
472                 string const file = os::internal_path(fromqstr(
473                         files.at(i).toLocalFile()));
474                 if (!file.empty())
475                         lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
476         }
477 }
478
479
480 void GuiView::message(docstring const & str)
481 {
482         if (ForkedProcess::iAmAChild())
483                 return;
484
485         statusBar()->showMessage(toqstr(str));
486         d.statusbar_timer_.stop();
487         d.statusbar_timer_.start(3000);
488 }
489
490
491 void GuiView::smallSizedIcons()
492 {
493         setIconSize(QSize(d.smallIconSize, d.smallIconSize));
494 }
495
496
497 void GuiView::normalSizedIcons()
498 {
499         setIconSize(QSize(d.normalIconSize, d.normalIconSize));
500 }
501
502
503 void GuiView::bigSizedIcons()
504 {
505         setIconSize(QSize(d.bigIconSize, d.bigIconSize));
506 }
507
508
509 void GuiView::clearMessage()
510 {
511         if (!hasFocus())
512                 return;
513         theLyXFunc().setLyXView(this);
514         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
515         d.statusbar_timer_.stop();
516 }
517
518
519 void GuiView::updateWindowTitle(GuiWorkArea * wa)
520 {
521         if (wa != d.current_work_area_)
522                 return;
523         setWindowTitle(qt_("LyX: ") + wa->windowTitle());
524         setWindowIconText(wa->windowIconText());
525 }
526
527
528 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
529 {
530         disconnectBuffer();
531         disconnectBufferView();
532         connectBufferView(wa->bufferView());
533         connectBuffer(wa->bufferView().buffer());
534         d.current_work_area_ = wa;
535         QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
536                 this, SLOT(updateWindowTitle(GuiWorkArea *)));
537         updateWindowTitle(wa);
538
539         updateToc();
540         // Buffer-dependent dialogs should be updated or
541         // hidden. This should go here because some dialogs (eg ToC)
542         // require bv_->text.
543         updateBufferDependent(true);
544         updateToolbars();
545         updateLayoutList();
546         updateStatusBar();
547 }
548
549
550 void GuiView::on_lastWorkAreaRemoved()
551 {
552 #ifdef Q_WS_MAC
553         // On Mac close the view if there is no Tab open anymore,
554         // but only if no splitter is visible
555         if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
556                 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
557                 if (twa && twa->count() == 0) {
558                         // close the view, as no tab is open anymore
559                         QTimer::singleShot(0, this, SLOT(close()));
560                 }
561         }
562 #endif
563 }
564
565
566 void GuiView::updateStatusBar()
567 {
568         // let the user see the explicit message
569         if (d.statusbar_timer_.isActive())
570                 return;
571
572         theLyXFunc().setLyXView(this);
573         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
574 }
575
576
577 bool GuiView::hasFocus() const
578 {
579         return qApp->activeWindow() == this;
580 }
581
582
583 bool GuiView::event(QEvent * e)
584 {
585         switch (e->type())
586         {
587         // Useful debug code:
588         //case QEvent::ActivationChange:
589         //case QEvent::WindowDeactivate:
590         //case QEvent::Paint:
591         //case QEvent::Enter:
592         //case QEvent::Leave:
593         //case QEvent::HoverEnter:
594         //case QEvent::HoverLeave:
595         //case QEvent::HoverMove:
596         //case QEvent::StatusTip:
597         //case QEvent::DragEnter:
598         //case QEvent::DragLeave:
599         //case QEvent::Drop:
600         //      break;
601
602         case QEvent::WindowActivate: {
603                 if (this == guiApp->currentView()) {
604                         setFocus();
605                         return QMainWindow::event(e);
606                 }
607                 guiApp->setCurrentView(this);
608                 if (d.current_work_area_) {
609                         BufferView & bv = d.current_work_area_->bufferView();
610                         connectBufferView(bv);
611                         connectBuffer(bv.buffer());
612                         // The document structure, name and dialogs might have
613                         // changed in another view.
614                         updateBufferDependent(true);
615                         updateToolbars();
616                         updateLayoutList();
617                         updateStatusBar();
618                 } else {
619                         setWindowTitle(qt_("LyX"));
620                         setWindowIconText(qt_("LyX"));
621                 }
622                 setFocus();
623                 return QMainWindow::event(e);
624         }
625
626         case QEvent::ShortcutOverride: {
627                 if (d.current_work_area_)
628                         // Nothing special to do.
629                         return QMainWindow::event(e);
630
631                 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
632
633                 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
634                 // between controls.
635                 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab 
636                         || ke->key() == Qt::Key_Backtab)
637                         return QMainWindow::event(e);
638
639                 // Allow processing of shortcuts that are allowed even when no Buffer
640                 // is viewed.
641                 theLyXFunc().setLyXView(this);
642                 KeySymbol sym;
643                 setKeySymbol(&sym, ke);
644                 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
645                 e->accept();
646                 return true;
647         }
648
649         default:
650                 return QMainWindow::event(e);
651         }
652 }
653
654
655 bool GuiView::focusNextPrevChild(bool /*next*/)
656 {
657         setFocus();
658         return true;
659 }
660
661
662 void GuiView::setBusy(bool busy)
663 {
664         if (d.current_work_area_) {
665                 d.current_work_area_->setUpdatesEnabled(!busy);
666                 if (busy)
667                         d.current_work_area_->stopBlinkingCursor();
668                 else
669                         d.current_work_area_->startBlinkingCursor();
670         }
671
672         if (busy)
673                 QApplication::setOverrideCursor(Qt::WaitCursor);
674         else
675                 QApplication::restoreOverrideCursor();
676 }
677
678
679 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
680 {
681         GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
682
683         if (tbinfo.flags & ToolbarInfo::TOP) {
684                 if (newline)
685                         addToolBarBreak(Qt::TopToolBarArea);
686                 addToolBar(Qt::TopToolBarArea, toolBar);
687         }
688
689         if (tbinfo.flags & ToolbarInfo::BOTTOM) {
690 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
691 #if (QT_VERSION >= 0x040202)
692                 if (newline)
693                         addToolBarBreak(Qt::BottomToolBarArea);
694 #endif
695                 addToolBar(Qt::BottomToolBarArea, toolBar);
696         }
697
698         if (tbinfo.flags & ToolbarInfo::LEFT) {
699 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
700 #if (QT_VERSION >= 0x040202)
701                 if (newline)
702                         addToolBarBreak(Qt::LeftToolBarArea);
703 #endif
704                 addToolBar(Qt::LeftToolBarArea, toolBar);
705         }
706
707         if (tbinfo.flags & ToolbarInfo::RIGHT) {
708 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
709 #if (QT_VERSION >= 0x040202)
710                 if (newline)
711                         addToolBarBreak(Qt::RightToolBarArea);
712 #endif
713                 addToolBar(Qt::RightToolBarArea, toolBar);
714         }
715
716         // The following does not work so I cannot restore to exact toolbar location
717         /*
718         ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
719         toolBar->move(tbinfo.posx, tbinfo.posy);
720         */
721
722         return toolBar;
723 }
724
725
726 GuiWorkArea * GuiView::workArea(Buffer & buffer)
727 {
728         if (TabWorkArea * twa = d.currentTabWorkArea())
729                 return twa->workArea(buffer);
730         return 0;
731 }
732
733
734 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
735 {
736         // Automatically create a TabWorkArea if there are none yet.
737         TabWorkArea * tab_widget = d.splitter_->count() 
738                 ? d.currentTabWorkArea() : addTabWorkArea();
739         return tab_widget->addWorkArea(buffer, *this);
740 }
741
742
743 TabWorkArea * GuiView::addTabWorkArea()
744 {
745         TabWorkArea * twa = new TabWorkArea;
746         QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
747                 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
748         QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
749                          this, SLOT(on_lastWorkAreaRemoved()));
750
751         d.splitter_->addWidget(twa);
752         d.stack_widget_->setCurrentWidget(d.splitter_);
753         return twa;
754 }
755
756
757 GuiWorkArea const * GuiView::currentWorkArea() const
758 {
759         return d.current_work_area_;
760 }
761
762
763 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
764 {
765         BOOST_ASSERT(wa);
766
767         // Changing work area can result from opening a file so
768         // update the toc in any case.
769         updateToc();
770
771         d.current_work_area_ = wa;
772         for (int i = 0; i != d.splitter_->count(); ++i) {
773                 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
774                         return;
775         }
776 }
777
778
779 void GuiView::removeWorkArea(GuiWorkArea * wa)
780 {
781         BOOST_ASSERT(wa);
782         if (wa == d.current_work_area_) {
783                 disconnectBuffer();
784                 disconnectBufferView();
785                 hideBufferDependent();
786                 d.current_work_area_ = 0;
787         }
788
789         for (int i = 0; i != d.splitter_->count(); ++i) {
790                 TabWorkArea * twa = d.tabWorkArea(i);
791                 if (!twa->removeWorkArea(wa))
792                         // Not found in this tab group.
793                         continue;
794
795                 // We found and removed the GuiWorkArea.
796                 if (!twa->count()) {
797                         // No more WorkAreas in this tab group, so delete it.
798                         delete twa;
799                         break;
800                 }
801
802                 if (d.current_work_area_)
803                         // This means that we are not closing the current GuiWorkArea;
804                         break;
805
806                 // Switch to the next GuiWorkArea in the found TabWorkArea.
807                 d.current_work_area_ = twa->currentWorkArea();
808                 break;
809         }
810
811         if (d.splitter_->count() == 0)
812                 // No more work area, switch to the background widget.
813                 d.setBackground();
814 }
815
816
817 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
818 {
819         d.layout_ = layout;
820 }
821
822
823 void GuiView::updateLayoutList()
824 {
825         if (d.layout_)
826                 d.layout_->updateContents(false);
827 }
828
829
830 void GuiView::updateToolbars()
831 {
832         if (d.current_work_area_) {
833                 bool const math =
834                         d.current_work_area_->bufferView().cursor().inMathed();
835                 bool const table =
836                         lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
837                 bool const review =
838                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
839                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
840                 bool const mathmacrotemplate =
841                         lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
842
843                 d.toolbars_->update(math, table, review, mathmacrotemplate);
844         } else
845                 d.toolbars_->update(false, false, false, false);
846
847         // update read-only status of open dialogs.
848         checkStatus();
849 }
850
851
852 Buffer * GuiView::buffer()
853 {
854         if (d.current_work_area_)
855                 return &d.current_work_area_->bufferView().buffer();
856         return 0;
857 }
858
859
860 Buffer const * GuiView::buffer() const
861 {
862         if (d.current_work_area_)
863                 return &d.current_work_area_->bufferView().buffer();
864         return 0;
865 }
866
867
868 void GuiView::setBuffer(Buffer * newBuffer)
869 {
870         BOOST_ASSERT(newBuffer);
871         setBusy(true);
872
873         GuiWorkArea * wa = workArea(*newBuffer);
874         if (wa == 0) {
875                 updateLabels(*newBuffer->masterBuffer());
876                 wa = addWorkArea(*newBuffer);
877         } else {
878                 //Disconnect the old buffer...there's no new one.
879                 disconnectBuffer();
880         }
881         connectBuffer(*newBuffer);
882         connectBufferView(wa->bufferView());
883         setCurrentWorkArea(wa);
884
885         setBusy(false);
886 }
887
888
889 void GuiView::connectBuffer(Buffer & buf)
890 {
891         buf.setGuiDelegate(this);
892 }
893
894
895 void GuiView::disconnectBuffer()
896 {
897         if (d.current_work_area_)
898                 d.current_work_area_->bufferView().setGuiDelegate(0);
899 }
900
901
902 void GuiView::connectBufferView(BufferView & bv)
903 {
904         bv.setGuiDelegate(this);
905 }
906
907
908 void GuiView::disconnectBufferView()
909 {
910         if (d.current_work_area_)
911                 d.current_work_area_->bufferView().setGuiDelegate(0);
912 }
913
914
915 void GuiView::errors(string const & error_type)
916 {
917         ErrorList & el = buffer()->errorList(error_type);
918         if (!el.empty())
919                 showDialog("errorlist", error_type);
920 }
921
922
923 void GuiView::updateDialog(string const & name, string const & data)
924 {
925         if (!isDialogVisible(name))
926                 return;
927
928         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
929         if (it == d.dialogs_.end())
930                 return;
931
932         Dialog * const dialog = it->second.get();
933         if (dialog->isVisibleView())
934                 dialog->updateData(data);
935 }
936
937
938 BufferView * GuiView::view()
939 {
940         return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
941 }
942
943
944 void GuiView::updateToc()
945 {
946         updateDialog("toc", "");
947 }
948
949
950 void GuiView::updateEmbeddedFiles()
951 {
952         updateDialog("embedding", "");
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_DIALOG_TOGGLE:
1011                 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1012                 // fall through to set "enable"
1013         case LFUN_DIALOG_SHOW: {
1014                 string const name = cmd.getArg(0);
1015                 if (!buf)
1016                         enable = name == "aboutlyx"
1017                                 || name == "file" //FIXME: should be removed.
1018                                 || name == "prefs"
1019                                 || name == "texinfo";
1020                 else if (name == "print")
1021                         enable = buf->isExportable("dvi")
1022                                 && lyxrc.print_command != "none";
1023                 else if (name == "character") {
1024                         if (!view())
1025                                 enable = false;
1026                         else {
1027                                 InsetCode ic = view()->cursor().inset().lyxCode();
1028                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1029                         }
1030                 }
1031                 else if (name == "symbols") {
1032                         if (!view() || view()->cursor().inMathed())
1033                                 enable = false;
1034                         else {
1035                                 InsetCode ic = view()->cursor().inset().lyxCode();
1036                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1037                         }
1038                 }
1039                 else if (name == "latexlog")
1040                         enable = FileName(buf->logName()).isReadableFile();
1041                 else if (name == "spellchecker")
1042 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1043                         enable = !buf->isReadonly();
1044 #else
1045                         enable = false;
1046 #endif
1047                 else if (name == "vclog")
1048                         enable = buf->lyxvc().inUse();
1049                 break;
1050         }
1051
1052         case LFUN_DIALOG_UPDATE: {
1053                 string const name = cmd.getArg(0);
1054                 if (!buf)
1055                         enable = name == "prefs";
1056                 break;
1057         }
1058
1059         case LFUN_INSET_APPLY: {
1060                 if (!buf) {
1061                         enable = false;
1062                         break;
1063                 }
1064                 string const name = cmd.getArg(0);
1065                 Inset * inset = getOpenInset(name);
1066                 if (inset) {
1067                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1068                         FuncStatus fs;
1069                         if (!inset->getStatus(view()->cursor(), fr, fs)) {
1070                                 // Every inset is supposed to handle this
1071                                 BOOST_ASSERT(false);
1072                         }
1073                         flag |= fs;
1074                 } else {
1075                         FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1076                         flag |= getStatus(fr);
1077                 }
1078                 enable = flag.enabled();
1079                 break;
1080         }
1081
1082         case LFUN_COMPLETION_INLINE:
1083                 if (!d.current_work_area_
1084                     || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1085                     enable = false;
1086                 break;
1087
1088         case LFUN_COMPLETION_POPUP:
1089                 if (!d.current_work_area_
1090                     || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1091                     enable = false;
1092                 break;
1093
1094         case LFUN_COMPLETION_COMPLETE:
1095                 if (!d.current_work_area_
1096                         || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1097                     enable = false;
1098                 break;
1099
1100         default:
1101                 if (!view()) {
1102                         enable = false;
1103                         break;
1104                 }
1105         }
1106
1107         if (!enable)
1108                 flag.enabled(false);
1109
1110         return flag;
1111 }
1112
1113
1114 static FileName selectTemplateFile()
1115 {
1116         FileDialog dlg(qt_("Select template file"));
1117         dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1118         dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1119
1120         FileDialog::Result result =
1121                 dlg.open(toqstr(lyxrc.template_path),
1122                              FileFilterList(_("LyX Documents (*.lyx)")));
1123
1124         if (result.first == FileDialog::Later)
1125                 return FileName();
1126         if (result.second.isEmpty())
1127                 return FileName();
1128         return FileName(fromqstr(result.second));
1129 }
1130
1131
1132 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1133 {
1134         setBusy(true);
1135
1136         Buffer * newBuffer = checkAndLoadLyXFile(filename);
1137
1138         if (!newBuffer) {
1139                 message(_("Document not loaded."));
1140                 setBusy(false);
1141                 return 0;
1142         }
1143         
1144         setBuffer(newBuffer);
1145
1146         // scroll to the position when the file was last closed
1147         if (lyxrc.use_lastfilepos) {
1148                 LastFilePosSection::FilePos filepos =
1149                         LyX::ref().session().lastFilePos().load(filename);
1150                 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1151         }
1152
1153         if (tolastfiles)
1154                 LyX::ref().session().lastFiles().add(filename);
1155
1156         setBusy(false);
1157         return newBuffer;
1158 }
1159
1160
1161 void GuiView::openDocument(string const & fname)
1162 {
1163         string initpath = lyxrc.document_path;
1164
1165         if (buffer()) {
1166                 string const trypath = buffer()->filePath();
1167                 // If directory is writeable, use this as default.
1168                 if (FileName(trypath).isDirWritable())
1169                         initpath = trypath;
1170         }
1171
1172         string filename;
1173
1174         if (fname.empty()) {
1175                 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1176                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1177                 dlg.setButton2(qt_("Examples|#E#e"),
1178                                 toqstr(addPath(package().system_support().absFilename(), "examples")));
1179
1180                 FileDialog::Result result =
1181                         dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1182
1183                 if (result.first == FileDialog::Later)
1184                         return;
1185
1186                 filename = fromqstr(result.second);
1187
1188                 // check selected filename
1189                 if (filename.empty()) {
1190                         message(_("Canceled."));
1191                         return;
1192                 }
1193         } else
1194                 filename = fname;
1195
1196         // get absolute path of file and add ".lyx" to the filename if
1197         // necessary. 
1198         FileName const fullname = 
1199                         fileSearch(string(), filename, "lyx", support::may_not_exist);
1200         if (!fullname.empty())
1201                 filename = fullname.absFilename();
1202
1203         // if the file doesn't exist, let the user create one
1204         if (!fullname.exists()) {
1205                 // the user specifically chose this name. Believe him.
1206                 Buffer * const b = newFile(filename, string(), true);
1207                 if (b)
1208                         setBuffer(b);
1209                 return;
1210         }
1211
1212         docstring const disp_fn = makeDisplayPath(filename);
1213         message(bformat(_("Opening document %1$s..."), disp_fn));
1214
1215         docstring str2;
1216         Buffer * buf = loadDocument(fullname);
1217         if (buf) {
1218                 updateLabels(*buf);
1219                 
1220                 setBuffer(buf);
1221                 buf->errors("Parse");
1222                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1223         } else {
1224                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1225         }
1226         message(str2);
1227 }
1228
1229 // FIXME: clean that
1230 static bool import(GuiView * lv, FileName const & filename,
1231         string const & format, ErrorList & errorList)
1232 {
1233         FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1234
1235         string loader_format;
1236         vector<string> loaders = theConverters().loaders();
1237         if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1238                 for (vector<string>::const_iterator it = loaders.begin();
1239                      it != loaders.end(); ++it) {
1240                         if (!theConverters().isReachable(format, *it))
1241                                 continue;
1242
1243                         string const tofile =
1244                                 support::changeExtension(filename.absFilename(),
1245                                 formats.extension(*it));
1246                         if (!theConverters().convert(0, filename, FileName(tofile),
1247                                 filename, format, *it, errorList))
1248                                 return false;
1249                         loader_format = *it;
1250                         break;
1251                 }
1252                 if (loader_format.empty()) {
1253                         frontend::Alert::error(_("Couldn't import file"),
1254                                      bformat(_("No information for importing the format %1$s."),
1255                                          formats.prettyName(format)));
1256                         return false;
1257                 }
1258         } else
1259                 loader_format = format;
1260
1261         if (loader_format == "lyx") {
1262                 Buffer * buf = lv->loadDocument(lyxfile);
1263                 if (!buf)
1264                         return false;
1265                 updateLabels(*buf);
1266                 lv->setBuffer(buf);
1267                 buf->errors("Parse");
1268         } else {
1269                 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1270                 if (!b)
1271                         return false;
1272                 lv->setBuffer(b);
1273                 bool as_paragraphs = loader_format == "textparagraph";
1274                 string filename2 = (loader_format == format) ? filename.absFilename()
1275                         : support::changeExtension(filename.absFilename(),
1276                                           formats.extension(loader_format));
1277                 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1278                 theLyXFunc().setLyXView(lv);
1279                 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1280         }
1281
1282         return true;
1283 }
1284
1285
1286 void GuiView::importDocument(string const & argument)
1287 {
1288         string format;
1289         string filename = split(argument, format, ' ');
1290
1291         LYXERR(Debug::INFO, format << " file: " << filename);
1292
1293         // need user interaction
1294         if (filename.empty()) {
1295                 string initpath = lyxrc.document_path;
1296
1297                 Buffer const * buf = buffer();
1298                 if (buf) {
1299                         string const trypath = buf->filePath();
1300                         // If directory is writeable, use this as default.
1301                         if (FileName(trypath).isDirWritable())
1302                                 initpath = trypath;
1303                 }
1304
1305                 docstring const text = bformat(_("Select %1$s file to import"),
1306                         formats.prettyName(format));
1307
1308                 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1309                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1310                 dlg.setButton2(qt_("Examples|#E#e"),
1311                         toqstr(addPath(package().system_support().absFilename(), "examples")));
1312
1313                 docstring filter = formats.prettyName(format);
1314                 filter += " (*.";
1315                 // FIXME UNICODE
1316                 filter += from_utf8(formats.extension(format));
1317                 filter += ')';
1318
1319                 FileDialog::Result result =
1320                         dlg.open(toqstr(initpath), FileFilterList(filter));
1321
1322                 if (result.first == FileDialog::Later)
1323                         return;
1324
1325                 filename = fromqstr(result.second);
1326
1327                 // check selected filename
1328                 if (filename.empty())
1329                         message(_("Canceled."));
1330         }
1331
1332         if (filename.empty())
1333                 return;
1334
1335         // get absolute path of file
1336         FileName const fullname(makeAbsPath(filename));
1337
1338         FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1339
1340         // Check if the document already is open
1341         Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1342         if (buf) {
1343                 setBuffer(buf);
1344                 if (!closeBuffer()) {
1345                         message(_("Canceled."));
1346                         return;
1347                 }
1348         }
1349
1350         docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1351
1352         // if the file exists already, and we didn't do
1353         // -i lyx thefile.lyx, warn
1354         if (lyxfile.exists() && fullname != lyxfile) {
1355
1356                 docstring text = bformat(_("The document %1$s already exists.\n\n"
1357                         "Do you want to overwrite that document?"), displaypath);
1358                 int const ret = Alert::prompt(_("Overwrite document?"),
1359                         text, 0, 1, _("&Overwrite"), _("&Cancel"));
1360
1361                 if (ret == 1) {
1362                         message(_("Canceled."));
1363                         return;
1364                 }
1365         }
1366
1367         message(bformat(_("Importing %1$s..."), displaypath));
1368         ErrorList errorList;
1369         if (import(this, fullname, format, errorList))
1370                 message(_("imported."));
1371         else
1372                 message(_("file not imported!"));
1373
1374         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1375 }
1376
1377
1378 void GuiView::newDocument(string const & filename, bool from_template)
1379 {
1380         FileName initpath(lyxrc.document_path);
1381         Buffer * buf = buffer();
1382         if (buf) {
1383                 FileName const trypath(buf->filePath());
1384                 // If directory is writeable, use this as default.
1385                 if (trypath.isDirWritable())
1386                         initpath = trypath;
1387         }
1388
1389         string templatefile = from_template ?
1390                 selectTemplateFile().absFilename() : string();
1391         Buffer * b;
1392         if (filename.empty())
1393                 b = newUnnamedFile(templatefile, initpath);
1394         else
1395                 b = newFile(filename, templatefile, true);
1396
1397         if (b)
1398                 setBuffer(b);
1399         // Ensure the cursor is correctly positionned on screen.
1400         view()->showCursor();
1401 }
1402
1403
1404 void GuiView::insertLyXFile(docstring const & fname)
1405 {
1406         BufferView * bv = view();
1407         if (!bv)
1408                 return;
1409
1410         // FIXME UNICODE
1411         FileName filename(to_utf8(fname));
1412         
1413         if (!filename.empty()) {
1414                 bv->insertLyXFile(filename);
1415                 return;
1416         }
1417
1418         // Launch a file browser
1419         // FIXME UNICODE
1420         string initpath = lyxrc.document_path;
1421         string const trypath = bv->buffer().filePath();
1422         // If directory is writeable, use this as default.
1423         if (FileName(trypath).isDirWritable())
1424                 initpath = trypath;
1425
1426         // FIXME UNICODE
1427         FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1428         dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1429         dlg.setButton2(qt_("Examples|#E#e"),
1430                 toqstr(addPath(package().system_support().absFilename(),
1431                 "examples")));
1432
1433         FileDialog::Result result =
1434                 dlg.open(toqstr(initpath),
1435                              FileFilterList(_("LyX Documents (*.lyx)")));
1436
1437         if (result.first == FileDialog::Later)
1438                 return;
1439
1440         // FIXME UNICODE
1441         filename.set(fromqstr(result.second));
1442
1443         // check selected filename
1444         if (filename.empty()) {
1445                 // emit message signal.
1446                 message(_("Canceled."));
1447                 return;
1448         }
1449
1450         bv->insertLyXFile(filename);
1451 }
1452
1453
1454 void GuiView::insertPlaintextFile(docstring const & fname,
1455         bool asParagraph)
1456 {
1457         BufferView * bv = view();
1458         if (!bv)
1459                 return;
1460
1461         // FIXME UNICODE
1462         FileName filename(to_utf8(fname));
1463         
1464         if (!filename.empty()) {
1465                 bv->insertPlaintextFile(filename, asParagraph);
1466                 return;
1467         }
1468
1469         FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1470                 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1471
1472         FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1473                 FileFilterList());
1474
1475         if (result.first == FileDialog::Later)
1476                 return;
1477
1478         // FIXME UNICODE
1479         filename.set(fromqstr(result.second));
1480
1481         // check selected filename
1482         if (filename.empty()) {
1483                 // emit message signal.
1484                 message(_("Canceled."));
1485                 return;
1486         }
1487
1488         bv->insertPlaintextFile(filename, asParagraph);
1489 }
1490
1491
1492 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1493 {
1494         FileName fname = b.fileName();
1495         FileName const oldname = fname;
1496
1497         if (!newname.empty()) {
1498                 // FIXME UNICODE
1499                 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1500         } else {
1501                 // Switch to this Buffer.
1502                 setBuffer(&b);
1503
1504                 /// No argument? Ask user through dialog.
1505                 // FIXME UNICODE
1506                 FileDialog dlg(qt_("Choose a filename to save document as"),
1507                                    LFUN_BUFFER_WRITE_AS);
1508                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1509                 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1510
1511                 if (!isLyXFilename(fname.absFilename()))
1512                         fname.changeExtension(".lyx");
1513
1514                 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1515
1516                 FileDialog::Result result =
1517                         dlg.save(toqstr(fname.onlyPath().absFilename()),
1518                                      filter,
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)
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)
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)
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                                         continue;
1736                                 saveBuffer(*b);
1737                                 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
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                 showNormal();
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                 showFullScreen();
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         updateLayoutList();
1996         updateToolbars();
1997         updateStatusBar();
1998 }
1999
2000
2001 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2002 {
2003         if (d.current_work_area_)
2004                 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2005 }
2006
2007 namespace {
2008
2009 // This list should be kept in sync with the list of insets in
2010 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
2011 // dialog should have the same name as the inset.
2012
2013 char const * const dialognames[] = {
2014 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2015 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
2016 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2017 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", 
2018 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
2019
2020 #ifdef HAVE_LIBAIKSAURUS
2021 "thesaurus",
2022 #endif
2023
2024 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2025
2026 char const * const * const end_dialognames =
2027         dialognames + (sizeof(dialognames) / sizeof(char *));
2028
2029 class cmpCStr {
2030 public:
2031         cmpCStr(char const * name) : name_(name) {}
2032         bool operator()(char const * other) {
2033                 return strcmp(other, name_) == 0;
2034         }
2035 private:
2036         char const * name_;
2037 };
2038
2039
2040 bool isValidName(string const & name)
2041 {
2042         return find_if(dialognames, end_dialognames,
2043                             cmpCStr(name.c_str())) != end_dialognames;
2044 }
2045
2046 } // namespace anon
2047
2048
2049 void GuiView::resetDialogs()
2050 {
2051         // Make sure that no LFUN uses any LyXView.
2052         theLyXFunc().setLyXView(0);
2053         // FIXME: the "math panels" toolbar takes an awful lot of time to
2054         // initialise so we don't do that for the time being.
2055         //d.toolbars_->init();
2056         guiApp->menus().fillMenuBar(menuBar(), this);
2057         if (d.layout_)
2058                 d.layout_->updateContents(true);
2059         // Now update controls with current buffer.
2060         theLyXFunc().setLyXView(this);
2061         restartCursor();
2062 }
2063
2064
2065 Dialog * GuiView::find_or_build(string const & name)
2066 {
2067         if (!isValidName(name))
2068                 return 0;
2069
2070         map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2071
2072         if (it != d.dialogs_.end())
2073                 return it->second.get();
2074
2075         Dialog * dialog = build(name);
2076         d.dialogs_[name].reset(dialog);
2077         if (lyxrc.allow_geometry_session)
2078                 dialog->restoreSession();
2079         return dialog;
2080 }
2081
2082
2083 void GuiView::showDialog(string const & name, string const & data,
2084         Inset * inset)
2085 {
2086         if (d.in_show_)
2087                 return;
2088
2089         d.in_show_ = true;
2090         Dialog * dialog = find_or_build(name);
2091         if (dialog) {
2092                 dialog->showData(data);
2093                 if (inset)
2094                         d.open_insets_[name] = inset;
2095         }
2096         d.in_show_ = false;
2097 }
2098
2099
2100 bool GuiView::isDialogVisible(string const & name) const
2101 {
2102         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2103         if (it == d.dialogs_.end())
2104                 return false;
2105         return it->second.get()->isVisibleView();
2106 }
2107
2108
2109 void GuiView::hideDialog(string const & name, Inset * inset)
2110 {
2111         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2112         if (it == d.dialogs_.end())
2113                 return;
2114
2115         if (inset && inset != getOpenInset(name))
2116                 return;
2117
2118         Dialog * const dialog = it->second.get();
2119         if (dialog->isVisibleView())
2120                 dialog->hideView();
2121         d.open_insets_[name] = 0;
2122 }
2123
2124
2125 void GuiView::disconnectDialog(string const & name)
2126 {
2127         if (!isValidName(name))
2128                 return;
2129
2130         if (d.open_insets_.find(name) != d.open_insets_.end())
2131                 d.open_insets_[name] = 0;
2132 }
2133
2134
2135 Inset * GuiView::getOpenInset(string const & name) const
2136 {
2137         if (!isValidName(name))
2138                 return 0;
2139
2140         map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2141         return it == d.open_insets_.end() ? 0 : it->second;
2142 }
2143
2144
2145 void GuiView::hideAll() const
2146 {
2147         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2148         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2149
2150         for(; it != end; ++it)
2151                 it->second->hideView();
2152 }
2153
2154
2155 void GuiView::hideBufferDependent() const
2156 {
2157         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2158         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2159
2160         for(; it != end; ++it) {
2161                 Dialog * dialog = it->second.get();
2162                 if (dialog->isBufferDependent())
2163                         dialog->hideView();
2164         }
2165 }
2166
2167
2168 void GuiView::updateBufferDependent(bool switched) const
2169 {
2170         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2171         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2172
2173         for(; it != end; ++it) {
2174                 Dialog * dialog = it->second.get();
2175                 if (!dialog->isVisibleView())
2176                         continue;
2177                 if (switched && dialog->isBufferDependent()) {
2178                         if (dialog->initialiseParams(""))
2179                                 dialog->updateView();
2180                         else
2181                                 dialog->hideView();
2182                 } else {
2183                         // A bit clunky, but the dialog will request
2184                         // that the kernel provides it with the necessary
2185                         // data.
2186                         dialog->updateDialog();
2187                 }
2188         }
2189 }
2190
2191
2192 void GuiView::checkStatus()
2193 {
2194         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2195         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2196
2197         for(; it != end; ++it) {
2198                 Dialog * const dialog = it->second.get();
2199                 if (dialog && dialog->isVisibleView())
2200                         dialog->checkStatus();
2201         }
2202 }
2203
2204
2205
2206 // will be replaced by a proper factory...
2207 Dialog * createGuiAbout(GuiView & lv);
2208 Dialog * createGuiBibitem(GuiView & lv);
2209 Dialog * createGuiBibtex(GuiView & lv);
2210 Dialog * createGuiBox(GuiView & lv);
2211 Dialog * createGuiBranch(GuiView & lv);
2212 Dialog * createGuiChanges(GuiView & lv);
2213 Dialog * createGuiCharacter(GuiView & lv);
2214 Dialog * createGuiCitation(GuiView & lv);
2215 Dialog * createGuiDelimiter(GuiView & lv);
2216 Dialog * createGuiDocument(GuiView & lv);
2217 Dialog * createGuiErrorList(GuiView & lv);
2218 Dialog * createGuiERT(GuiView & lv);
2219 Dialog * createGuiExternal(GuiView & lv);
2220 Dialog * createGuiFloat(GuiView & lv);
2221 Dialog * createGuiGraphics(GuiView & lv);
2222 Dialog * createGuiInclude(GuiView & lv);
2223 Dialog * createGuiLabel(GuiView & lv);
2224 Dialog * createGuiListings(GuiView & lv);
2225 Dialog * createGuiLog(GuiView & lv);
2226 Dialog * createGuiMathMatrix(GuiView & lv);
2227 Dialog * createGuiNomenclature(GuiView & lv);
2228 Dialog * createGuiNote(GuiView & lv);
2229 Dialog * createGuiParagraph(GuiView & lv);
2230 Dialog * createGuiPreferences(GuiView & lv);
2231 Dialog * createGuiPrint(GuiView & lv);
2232 Dialog * createGuiRef(GuiView & lv);
2233 Dialog * createGuiSearch(GuiView & lv);
2234 Dialog * createGuiSendTo(GuiView & lv);
2235 Dialog * createGuiShowFile(GuiView & lv);
2236 Dialog * createGuiSpellchecker(GuiView & lv);
2237 Dialog * createGuiSymbols(GuiView & lv);
2238 Dialog * createGuiTabularCreate(GuiView & lv);
2239 Dialog * createGuiTabular(GuiView & lv);
2240 Dialog * createGuiTexInfo(GuiView & lv);
2241 Dialog * createGuiToc(GuiView & lv);
2242 Dialog * createGuiThesaurus(GuiView & lv);
2243 Dialog * createGuiHyperlink(GuiView & lv);
2244 Dialog * createGuiVSpace(GuiView & lv);
2245 Dialog * createGuiViewSource(GuiView & lv);
2246 Dialog * createGuiWrap(GuiView & lv);
2247
2248
2249 Dialog * GuiView::build(string const & name)
2250 {
2251         BOOST_ASSERT(isValidName(name));
2252
2253         if (name == "aboutlyx")
2254                 return createGuiAbout(*this);
2255         if (name == "bibitem")
2256                 return createGuiBibitem(*this);
2257         if (name == "bibtex")
2258                 return createGuiBibtex(*this);
2259         if (name == "box")
2260                 return createGuiBox(*this);
2261         if (name == "branch")
2262                 return createGuiBranch(*this);
2263         if (name == "changes")
2264                 return createGuiChanges(*this);
2265         if (name == "character")
2266                 return createGuiCharacter(*this);
2267         if (name == "citation")
2268                 return createGuiCitation(*this);
2269         if (name == "document")
2270                 return createGuiDocument(*this);
2271         if (name == "errorlist")
2272                 return createGuiErrorList(*this);
2273         if (name == "ert")
2274                 return createGuiERT(*this);
2275         if (name == "external")
2276                 return createGuiExternal(*this);
2277         if (name == "file")
2278                 return createGuiShowFile(*this);
2279         if (name == "findreplace")
2280                 return createGuiSearch(*this);
2281         if (name == "float")
2282                 return createGuiFloat(*this);
2283         if (name == "graphics")
2284                 return createGuiGraphics(*this);
2285         if (name == "include")
2286                 return createGuiInclude(*this);
2287         if (name == "nomenclature")
2288                 return createGuiNomenclature(*this);
2289         if (name == "label")
2290                 return createGuiLabel(*this);
2291         if (name == "log")
2292                 return createGuiLog(*this);
2293         if (name == "view-source")
2294                 return createGuiViewSource(*this);
2295         if (name == "mathdelimiter")
2296                 return createGuiDelimiter(*this);
2297         if (name == "mathmatrix")
2298                 return createGuiMathMatrix(*this);
2299         if (name == "note")
2300                 return createGuiNote(*this);
2301         if (name == "paragraph")
2302                 return createGuiParagraph(*this);
2303         if (name == "prefs")
2304                 return createGuiPreferences(*this);
2305         if (name == "print")
2306                 return createGuiPrint(*this);
2307         if (name == "ref")
2308                 return createGuiRef(*this);
2309         if (name == "sendto")
2310                 return createGuiSendTo(*this);
2311         if (name == "spellchecker")
2312                 return createGuiSpellchecker(*this);
2313         if (name == "symbols")
2314                 return createGuiSymbols(*this);
2315         if (name == "tabular")
2316                 return createGuiTabular(*this);
2317         if (name == "tabularcreate")
2318                 return createGuiTabularCreate(*this);
2319         if (name == "texinfo")
2320                 return createGuiTexInfo(*this);
2321 #ifdef HAVE_LIBAIKSAURUS
2322         if (name == "thesaurus")
2323                 return createGuiThesaurus(*this);
2324 #endif
2325         if (name == "toc")
2326                 return createGuiToc(*this);
2327         if (name == "href")
2328                 return createGuiHyperlink(*this);
2329         if (name == "vspace")
2330                 return createGuiVSpace(*this);
2331         if (name == "wrap")
2332                 return createGuiWrap(*this);
2333         if (name == "listings")
2334                 return createGuiListings(*this);
2335
2336         return 0;
2337 }
2338
2339
2340 } // namespace frontend
2341 } // namespace lyx
2342
2343 #include "GuiView_moc.cpp"