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