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