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