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