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