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