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