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