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