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