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