]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
fix http://bugzilla.lyx.org/show_bug.cgi?id=5114
[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                 if (cmd.getArg(0) == "vertical")
1099                         enable = buf && (d.splitter_->count() == 1 ||
1100                                          d.splitter_->orientation() == Qt::Vertical);
1101                 else
1102                         enable = buf && (d.splitter_->count() == 1 ||
1103                                          d.splitter_->orientation() == Qt::Horizontal);
1104                 break;
1105
1106         case LFUN_CLOSE_TAB_GROUP:
1107                 enable = d.currentTabWorkArea();
1108                 break;
1109
1110         case LFUN_TOOLBAR_TOGGLE:
1111                 if (GuiToolbar * t = toolbar(cmd.getArg(0)))
1112                         flag.setOnOff(t->isVisible());
1113                 break;
1114
1115         case LFUN_UI_TOGGLE:
1116                 flag.setOnOff(isFullScreen());
1117                 break;
1118
1119         case LFUN_DIALOG_TOGGLE:
1120                 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1121                 // fall through to set "enable"
1122         case LFUN_DIALOG_SHOW: {
1123                 string const name = cmd.getArg(0);
1124                 if (!buf)
1125                         enable = name == "aboutlyx"
1126                                 || name == "file" //FIXME: should be removed.
1127                                 || name == "prefs"
1128                                 || name == "texinfo";
1129                 else if (name == "print")
1130                         enable = buf->isExportable("dvi")
1131                                 && lyxrc.print_command != "none";
1132                 else if (name == "character") {
1133                         if (!view())
1134                                 enable = false;
1135                         else {
1136                                 InsetCode ic = view()->cursor().inset().lyxCode();
1137                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1138                         }
1139                 }
1140                 else if (name == "symbols") {
1141                         if (!view() || view()->cursor().inMathed())
1142                                 enable = false;
1143                         else {
1144                                 InsetCode ic = view()->cursor().inset().lyxCode();
1145                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1146                         }
1147                 }
1148                 else if (name == "latexlog")
1149                         enable = FileName(buf->logName()).isReadableFile();
1150                 else if (name == "spellchecker")
1151 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1152                         enable = !buf->isReadonly();
1153 #else
1154                         enable = false;
1155 #endif
1156                 else if (name == "vclog")
1157                         enable = buf->lyxvc().inUse();
1158                 break;
1159         }
1160
1161         case LFUN_DIALOG_UPDATE: {
1162                 string const name = cmd.getArg(0);
1163                 if (!buf)
1164                         enable = name == "prefs";
1165                 break;
1166         }
1167
1168         case LFUN_INSET_APPLY: {
1169                 string const name = cmd.getArg(0);
1170                 Inset * inset = getOpenInset(name);
1171                 if (inset) {
1172                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1173                         FuncStatus fs;
1174                         if (!inset->getStatus(view()->cursor(), fr, fs)) {
1175                                 // Every inset is supposed to handle this
1176                                 LASSERT(false, /**/);
1177                         }
1178                         flag |= fs;
1179                 } else {
1180                         FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1181                         flag |= lyx::getStatus(fr);
1182                 }
1183                 enable = flag.enabled();
1184                 break;
1185         }
1186
1187         case LFUN_COMPLETION_INLINE:
1188                 if (!d.current_work_area_
1189                     || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1190                     enable = false;
1191                 break;
1192
1193         case LFUN_COMPLETION_POPUP:
1194                 if (!d.current_work_area_
1195                     || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1196                     enable = false;
1197                 break;
1198
1199         case LFUN_COMPLETION_COMPLETE:
1200                 if (!d.current_work_area_
1201                         || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1202                     enable = false;
1203                 break;
1204
1205         default:
1206                 return false;
1207         }
1208
1209         if (!enable)
1210                 flag.setEnabled(false);
1211
1212         return true;
1213 }
1214
1215
1216 static FileName selectTemplateFile()
1217 {
1218         FileDialog dlg(qt_("Select template file"));
1219         dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1220         dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1221
1222         FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1223                              QStringList(qt_("LyX Documents (*.lyx)")));
1224
1225         if (result.first == FileDialog::Later)
1226                 return FileName();
1227         if (result.second.isEmpty())
1228                 return FileName();
1229         return FileName(fromqstr(result.second));
1230 }
1231
1232
1233 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1234 {
1235         setBusy(true);
1236
1237         Buffer * newBuffer = checkAndLoadLyXFile(filename);
1238
1239         if (!newBuffer) {
1240                 message(_("Document not loaded."));
1241                 setBusy(false);
1242                 return 0;
1243         }
1244         
1245         setBuffer(newBuffer);
1246
1247         // scroll to the position when the file was last closed
1248         if (lyxrc.use_lastfilepos) {
1249                 LastFilePosSection::FilePos filepos =
1250                         theSession().lastFilePos().load(filename);
1251                 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1252         }
1253
1254         if (tolastfiles)
1255                 theSession().lastFiles().add(filename);
1256
1257         setBusy(false);
1258         return newBuffer;
1259 }
1260
1261
1262 void GuiView::openDocument(string const & fname)
1263 {
1264         string initpath = lyxrc.document_path;
1265
1266         if (buffer()) {
1267                 string const trypath = buffer()->filePath();
1268                 // If directory is writeable, use this as default.
1269                 if (FileName(trypath).isDirWritable())
1270                         initpath = trypath;
1271         }
1272
1273         string filename;
1274
1275         if (fname.empty()) {
1276                 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1277                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1278                 dlg.setButton2(qt_("Examples|#E#e"),
1279                                 toqstr(addPath(package().system_support().absFilename(), "examples")));
1280
1281                 QStringList filter(qt_("LyX Documents (*.lyx)"));
1282                 filter << qt_("LyX-1.3.x Documents (*.lyx13)")
1283                         << qt_("LyX-1.4.x Documents (*.lyx14)")
1284                         << qt_("LyX-1.5.x Documents (*.lyx15)");
1285                 FileDialog::Result result =
1286                         dlg.open(toqstr(initpath), filter);
1287
1288                 if (result.first == FileDialog::Later)
1289                         return;
1290
1291                 filename = fromqstr(result.second);
1292
1293                 // check selected filename
1294                 if (filename.empty()) {
1295                         message(_("Canceled."));
1296                         return;
1297                 }
1298         } else
1299                 filename = fname;
1300
1301         // get absolute path of file and add ".lyx" to the filename if
1302         // necessary. 
1303         FileName const fullname = 
1304                         fileSearch(string(), filename, "lyx", support::may_not_exist);
1305         if (!fullname.empty())
1306                 filename = fullname.absFilename();
1307
1308         // if the file doesn't exist, let the user create one
1309         if (!fullname.exists()) {
1310                 // the user specifically chose this name. Believe him.
1311                 Buffer * const b = newFile(filename, string(), true);
1312                 if (b)
1313                         setBuffer(b);
1314                 return;
1315         }
1316
1317         docstring const disp_fn = makeDisplayPath(filename);
1318         message(bformat(_("Opening document %1$s..."), disp_fn));
1319
1320         docstring str2;
1321         Buffer * buf = loadDocument(fullname);
1322         if (buf) {
1323                 updateLabels(*buf);
1324                 
1325                 setBuffer(buf);
1326                 buf->errors("Parse");
1327                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1328                 if (buf->lyxvc().inUse())
1329                         str2 += " " + from_utf8(buf->lyxvc().versionString()) +
1330                                 " " + _("Version control detected.");
1331         } else {
1332                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1333         }
1334         message(str2);
1335 }
1336
1337 // FIXME: clean that
1338 static bool import(GuiView * lv, FileName const & filename,
1339         string const & format, ErrorList & errorList)
1340 {
1341         FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1342
1343         string loader_format;
1344         vector<string> loaders = theConverters().loaders();
1345         if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1346                 for (vector<string>::const_iterator it = loaders.begin();
1347                      it != loaders.end(); ++it) {
1348                         if (!theConverters().isReachable(format, *it))
1349                                 continue;
1350
1351                         string const tofile =
1352                                 support::changeExtension(filename.absFilename(),
1353                                 formats.extension(*it));
1354                         if (!theConverters().convert(0, filename, FileName(tofile),
1355                                 filename, format, *it, errorList))
1356                                 return false;
1357                         loader_format = *it;
1358                         break;
1359                 }
1360                 if (loader_format.empty()) {
1361                         frontend::Alert::error(_("Couldn't import file"),
1362                                      bformat(_("No information for importing the format %1$s."),
1363                                          formats.prettyName(format)));
1364                         return false;
1365                 }
1366         } else
1367                 loader_format = format;
1368
1369         if (loader_format == "lyx") {
1370                 Buffer * buf = lv->loadDocument(lyxfile);
1371                 if (!buf)
1372                         return false;
1373                 updateLabels(*buf);
1374                 lv->setBuffer(buf);
1375                 buf->errors("Parse");
1376         } else {
1377                 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1378                 if (!b)
1379                         return false;
1380                 lv->setBuffer(b);
1381                 bool as_paragraphs = loader_format == "textparagraph";
1382                 string filename2 = (loader_format == format) ? filename.absFilename()
1383                         : support::changeExtension(filename.absFilename(),
1384                                           formats.extension(loader_format));
1385                 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1386                 theLyXFunc().setLyXView(lv);
1387                 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1388         }
1389
1390         return true;
1391 }
1392
1393
1394 void GuiView::importDocument(string const & argument)
1395 {
1396         string format;
1397         string filename = split(argument, format, ' ');
1398
1399         LYXERR(Debug::INFO, format << " file: " << filename);
1400
1401         // need user interaction
1402         if (filename.empty()) {
1403                 string initpath = lyxrc.document_path;
1404
1405                 Buffer const * buf = buffer();
1406                 if (buf) {
1407                         string const trypath = buf->filePath();
1408                         // If directory is writeable, use this as default.
1409                         if (FileName(trypath).isDirWritable())
1410                                 initpath = trypath;
1411                 }
1412
1413                 docstring const text = bformat(_("Select %1$s file to import"),
1414                         formats.prettyName(format));
1415
1416                 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1417                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1418                 dlg.setButton2(qt_("Examples|#E#e"),
1419                         toqstr(addPath(package().system_support().absFilename(), "examples")));
1420
1421                 docstring filter = formats.prettyName(format);
1422                 filter += " (*.";
1423                 // FIXME UNICODE
1424                 filter += from_utf8(formats.extension(format));
1425                 filter += ')';
1426
1427                 FileDialog::Result result =
1428                         dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1429
1430                 if (result.first == FileDialog::Later)
1431                         return;
1432
1433                 filename = fromqstr(result.second);
1434
1435                 // check selected filename
1436                 if (filename.empty())
1437                         message(_("Canceled."));
1438         }
1439
1440         if (filename.empty())
1441                 return;
1442
1443         // get absolute path of file
1444         FileName const fullname(support::makeAbsPath(filename));
1445
1446         FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1447
1448         // Check if the document already is open
1449         Buffer * buf = theBufferList().getBuffer(lyxfile);
1450         if (buf) {
1451                 setBuffer(buf);
1452                 if (!closeBuffer()) {
1453                         message(_("Canceled."));
1454                         return;
1455                 }
1456         }
1457
1458         docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1459
1460         // if the file exists already, and we didn't do
1461         // -i lyx thefile.lyx, warn
1462         if (lyxfile.exists() && fullname != lyxfile) {
1463
1464                 docstring text = bformat(_("The document %1$s already exists.\n\n"
1465                         "Do you want to overwrite that document?"), displaypath);
1466                 int const ret = Alert::prompt(_("Overwrite document?"),
1467                         text, 0, 1, _("&Overwrite"), _("&Cancel"));
1468
1469                 if (ret == 1) {
1470                         message(_("Canceled."));
1471                         return;
1472                 }
1473         }
1474
1475         message(bformat(_("Importing %1$s..."), displaypath));
1476         ErrorList errorList;
1477         if (import(this, fullname, format, errorList))
1478                 message(_("imported."));
1479         else
1480                 message(_("file not imported!"));
1481
1482         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1483 }
1484
1485
1486 void GuiView::newDocument(string const & filename, bool from_template)
1487 {
1488         FileName initpath(lyxrc.document_path);
1489         Buffer * buf = buffer();
1490         if (buf) {
1491                 FileName const trypath(buf->filePath());
1492                 // If directory is writeable, use this as default.
1493                 if (trypath.isDirWritable())
1494                         initpath = trypath;
1495         }
1496
1497         string templatefile = from_template ?
1498                 selectTemplateFile().absFilename() : string();
1499         Buffer * b;
1500         if (filename.empty())
1501                 b = newUnnamedFile(templatefile, initpath);
1502         else
1503                 b = newFile(filename, templatefile, true);
1504
1505         if (b)
1506                 setBuffer(b);
1507         // Ensure the cursor is correctly positionned on screen.
1508         view()->showCursor();
1509 }
1510
1511
1512 void GuiView::insertLyXFile(docstring const & fname)
1513 {
1514         BufferView * bv = view();
1515         if (!bv)
1516                 return;
1517
1518         // FIXME UNICODE
1519         FileName filename(to_utf8(fname));
1520         
1521         if (!filename.empty()) {
1522                 bv->insertLyXFile(filename);
1523                 return;
1524         }
1525
1526         // Launch a file browser
1527         // FIXME UNICODE
1528         string initpath = lyxrc.document_path;
1529         string const trypath = bv->buffer().filePath();
1530         // If directory is writeable, use this as default.
1531         if (FileName(trypath).isDirWritable())
1532                 initpath = trypath;
1533
1534         // FIXME UNICODE
1535         FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1536         dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1537         dlg.setButton2(qt_("Examples|#E#e"),
1538                 toqstr(addPath(package().system_support().absFilename(),
1539                 "examples")));
1540
1541         FileDialog::Result result = dlg.open(toqstr(initpath),
1542                              QStringList(qt_("LyX Documents (*.lyx)")));
1543
1544         if (result.first == FileDialog::Later)
1545                 return;
1546
1547         // FIXME UNICODE
1548         filename.set(fromqstr(result.second));
1549
1550         // check selected filename
1551         if (filename.empty()) {
1552                 // emit message signal.
1553                 message(_("Canceled."));
1554                 return;
1555         }
1556
1557         bv->insertLyXFile(filename);
1558 }
1559
1560
1561 void GuiView::insertPlaintextFile(docstring const & fname,
1562         bool asParagraph)
1563 {
1564         BufferView * bv = view();
1565         if (!bv)
1566                 return;
1567
1568         // FIXME UNICODE
1569         FileName filename(to_utf8(fname));
1570         
1571         if (!filename.empty()) {
1572                 bv->insertPlaintextFile(filename, asParagraph);
1573                 return;
1574         }
1575
1576         FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1577                 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1578
1579         FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1580                 QStringList());
1581
1582         if (result.first == FileDialog::Later)
1583                 return;
1584
1585         // FIXME UNICODE
1586         filename.set(fromqstr(result.second));
1587
1588         // check selected filename
1589         if (filename.empty()) {
1590                 // emit message signal.
1591                 message(_("Canceled."));
1592                 return;
1593         }
1594
1595         bv->insertPlaintextFile(filename, asParagraph);
1596 }
1597
1598
1599 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1600 {
1601         FileName fname = b.fileName();
1602         FileName const oldname = fname;
1603
1604         if (!newname.empty()) {
1605                 // FIXME UNICODE
1606                 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1607         } else {
1608                 // Switch to this Buffer.
1609                 setBuffer(&b);
1610
1611                 /// No argument? Ask user through dialog.
1612                 // FIXME UNICODE
1613                 FileDialog dlg(qt_("Choose a filename to save document as"),
1614                                    LFUN_BUFFER_WRITE_AS);
1615                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1616                 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1617
1618                 if (!isLyXFilename(fname.absFilename()))
1619                         fname.changeExtension(".lyx");
1620
1621                 FileDialog::Result result =
1622                         dlg.save(toqstr(fname.onlyPath().absFilename()),
1623                                QStringList(qt_("LyX Documents (*.lyx)")),
1624                                      toqstr(fname.onlyFileName()));
1625
1626                 if (result.first == FileDialog::Later)
1627                         return false;
1628
1629                 fname.set(fromqstr(result.second));
1630
1631                 if (fname.empty())
1632                         return false;
1633
1634                 if (!isLyXFilename(fname.absFilename()))
1635                         fname.changeExtension(".lyx");
1636         }
1637
1638         if (FileName(fname).exists()) {
1639                 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1640                 docstring text = bformat(_("The document %1$s already "
1641                                            "exists.\n\nDo you want to "
1642                                            "overwrite that document?"), 
1643                                          file);
1644                 int const ret = Alert::prompt(_("Overwrite document?"),
1645                         text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1646                 switch (ret) {
1647                 case 0: break;
1648                 case 1: return renameBuffer(b, docstring());
1649                 case 2: return false;
1650                 }
1651         }
1652
1653         // Ok, change the name of the buffer
1654         b.setFileName(fname.absFilename());
1655         b.markDirty();
1656         bool unnamed = b.isUnnamed();
1657         b.setUnnamed(false);
1658         b.saveCheckSum(fname);
1659
1660         if (!saveBuffer(b)) {
1661                 b.setFileName(oldname.absFilename());
1662                 b.setUnnamed(unnamed);
1663                 b.saveCheckSum(oldname);
1664                 return false;
1665         }
1666
1667         return true;
1668 }
1669
1670
1671 bool GuiView::saveBuffer(Buffer & b)
1672 {
1673         if (b.isUnnamed())
1674                 return renameBuffer(b, docstring());
1675
1676         if (b.save()) {
1677                 theSession().lastFiles().add(b.fileName());
1678                 return true;
1679         }
1680
1681         // Switch to this Buffer.
1682         setBuffer(&b);
1683
1684         // FIXME: we don't tell the user *WHY* the save failed !!
1685         docstring const file = makeDisplayPath(b.absFileName(), 30);
1686         docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1687                                    "Do you want to rename the document and "
1688                                    "try again?"), file);
1689         int const ret = Alert::prompt(_("Rename and save?"),
1690                 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1691         switch (ret) {
1692         case 0:
1693                 if (!renameBuffer(b, docstring()))
1694                         return false;
1695                 break;
1696         case 1:
1697                 break;
1698         case 2:
1699                 return false;
1700         }
1701
1702         return saveBuffer(b);
1703 }
1704
1705
1706 bool GuiView::closeBuffer()
1707 {
1708         Buffer * buf = buffer();
1709         return buf && closeBuffer(*buf);
1710 }
1711
1712
1713 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1714 {
1715         // goto bookmark to update bookmark pit.
1716         //FIXME: we should update only the bookmarks related to this buffer!
1717         for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
1718                 theLyXFunc().gotoBookmark(i+1, false, false);
1719
1720         if (buf.isClean() || buf.paragraphs().empty()) {
1721                 if (buf.masterBuffer() == &buf && tolastopened)
1722                         theSession().lastOpened().add(buf.fileName());
1723                 theBufferList().release(&buf);
1724                 return true;
1725         }
1726         // Switch to this Buffer.
1727         setBuffer(&buf);
1728
1729         docstring file;
1730         // FIXME: Unicode?
1731         if (buf.isUnnamed())
1732                 file = from_utf8(buf.fileName().onlyFileName());
1733         else
1734                 file = buf.fileName().displayName(30);
1735
1736         // Bring this window to top before asking questions.
1737         raise();
1738         activateWindow();
1739
1740         docstring const text = bformat(_("The document %1$s has unsaved changes."
1741                 "\n\nDo you want to save the document or discard the changes?"), file);
1742         int const ret = Alert::prompt(_("Save changed document?"),
1743                 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1744
1745         switch (ret) {
1746         case 0:
1747                 if (!saveBuffer(buf))
1748                         return false;
1749                 break;
1750         case 1:
1751                 // if we crash after this we could
1752                 // have no autosave file but I guess
1753                 // this is really improbable (Jug)
1754                 removeAutosaveFile(buf.absFileName());
1755                 break;
1756         case 2:
1757                 return false;
1758         }
1759
1760         // save file names to .lyx/session
1761         // if master/slave are both open, do not save slave since it
1762         // will be automatically loaded when the master is loaded
1763         if (buf.masterBuffer() == &buf && tolastopened)
1764                 theSession().lastOpened().add(buf.fileName());
1765
1766         if (buf.parent())
1767                 // Don't close child documents.
1768                 removeWorkArea(d.current_work_area_);
1769         else
1770                 theBufferList().release(&buf);
1771
1772         return true;
1773 }
1774
1775
1776 bool GuiView::dispatch(FuncRequest const & cmd)
1777 {
1778         BufferView * bv = view();
1779         // By default we won't need any update.
1780         if (bv)
1781                 bv->cursor().updateFlags(Update::None);
1782         bool dispatched = true;
1783
1784         switch(cmd.action) {
1785                 case LFUN_BUFFER_IMPORT:
1786                         importDocument(to_utf8(cmd.argument()));
1787                         break;
1788
1789                 case LFUN_BUFFER_SWITCH:
1790                         setBuffer(theBufferList().getBuffer(FileName(to_utf8(cmd.argument()))));
1791                         break;
1792
1793                 case LFUN_BUFFER_NEXT:
1794                         setBuffer(theBufferList().next(buffer()));
1795                         break;
1796
1797                 case LFUN_BUFFER_PREVIOUS:
1798                         setBuffer(theBufferList().previous(buffer()));
1799                         break;
1800
1801                 case LFUN_COMMAND_EXECUTE: {
1802                         bool const show_it = cmd.argument() != "off";
1803                         // FIXME: this is a hack, "minibuffer" should not be
1804                         // hardcoded.
1805                         if (GuiToolbar * t = toolbar("minibuffer")) {
1806                                 t->setVisible(show_it);
1807                                 if (show_it && t->commandBuffer())
1808                                         t->commandBuffer()->setFocus();
1809                         }
1810                         break;
1811                 }
1812                 case LFUN_DROP_LAYOUTS_CHOICE:
1813                         if (d.layout_)
1814                                 d.layout_->showPopup();
1815                         break;
1816
1817                 case LFUN_MENU_OPEN:
1818                         if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1819                                 menu->exec(QCursor::pos());
1820                         break;
1821
1822                 case LFUN_FILE_INSERT:
1823                         insertLyXFile(cmd.argument());
1824                         break;
1825                 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1826                         insertPlaintextFile(cmd.argument(), true);
1827                         break;
1828
1829                 case LFUN_FILE_INSERT_PLAINTEXT:
1830                         insertPlaintextFile(cmd.argument(), false);
1831                         break;
1832
1833                 case LFUN_BUFFER_WRITE:
1834                         if (bv)
1835                                 saveBuffer(bv->buffer());
1836                         break;
1837
1838                 case LFUN_BUFFER_WRITE_AS:
1839                         if (bv)
1840                                 renameBuffer(bv->buffer(), cmd.argument());
1841                         break;
1842
1843                 case LFUN_BUFFER_WRITE_ALL: {
1844                         Buffer * first = theBufferList().first();
1845                         if (!first)
1846                                 break;
1847                         message(_("Saving all documents..."));
1848                         // We cannot use a for loop as the buffer list cycles.
1849                         Buffer * b = first;
1850                         do {
1851                                 if (!b->isClean()) {
1852                                         saveBuffer(*b);
1853                                         LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1854                                 }
1855                                 b = theBufferList().next(b);
1856                         } while (b != first); 
1857                         message(_("All documents saved."));
1858                         break;
1859                 }
1860
1861                 case LFUN_TOOLBAR_TOGGLE: {
1862                         string const name = cmd.getArg(0);
1863                         if (GuiToolbar * t = toolbar(name))
1864                                 t->toggle();
1865                         break;
1866                 }
1867
1868                 case LFUN_DIALOG_UPDATE: {
1869                         string const name = to_utf8(cmd.argument());
1870                         // Can only update a dialog connected to an existing inset
1871                         Inset * inset = getOpenInset(name);
1872                         if (inset) {
1873                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1874                                 inset->dispatch(view()->cursor(), fr);
1875                         } else if (name == "paragraph") {
1876                                 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1877                         } else if (name == "prefs") {
1878                                 updateDialog(name, string());
1879                         }
1880                         break;
1881                 }
1882
1883                 case LFUN_DIALOG_TOGGLE: {
1884                         if (isDialogVisible(cmd.getArg(0)))
1885                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1886                         else
1887                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1888                         break;
1889                 }
1890
1891                 case LFUN_DIALOG_DISCONNECT_INSET:
1892                         disconnectDialog(to_utf8(cmd.argument()));
1893                         break;
1894
1895                 case LFUN_DIALOG_HIDE: {
1896                         guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1897                         break;
1898                 }
1899
1900                 case LFUN_DIALOG_SHOW: {
1901                         string const name = cmd.getArg(0);
1902                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1903
1904                         if (name == "character") {
1905                                 data = freefont2string();
1906                                 if (!data.empty())
1907                                         showDialog("character", data);
1908                         } else if (name == "latexlog") {
1909                                 Buffer::LogType type; 
1910                                 string const logfile = buffer()->logName(&type);
1911                                 switch (type) {
1912                                 case Buffer::latexlog:
1913                                         data = "latex ";
1914                                         break;
1915                                 case Buffer::buildlog:
1916                                         data = "literate ";
1917                                         break;
1918                                 }
1919                                 data += Lexer::quoteString(logfile);
1920                                 showDialog("log", data);
1921                         } else if (name == "vclog") {
1922                                 string const data = "vc " +
1923                                         Lexer::quoteString(buffer()->lyxvc().getLogFile());
1924                                 showDialog("log", data);
1925                         } else if (name == "symbols") {
1926                                 data = bv->cursor().getEncoding()->name();
1927                                 if (!data.empty())
1928                                         showDialog("symbols", data);
1929                         } else
1930                                 showDialog(name, data);
1931                         break;
1932                 }
1933
1934                 case LFUN_INSET_APPLY: {
1935                         view()->cursor().recordUndoFullDocument();
1936                         string const name = cmd.getArg(0);
1937                         Inset * inset = getOpenInset(name);
1938                         if (inset) {
1939                                 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1940                                 inset->dispatch(view()->cursor(), fr);
1941                         } else {
1942                                 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1943                                 lyx::dispatch(fr);
1944                         }
1945                         break;
1946                 }
1947
1948                 case LFUN_UI_TOGGLE:
1949                         lfunUiToggle(cmd);
1950                         // Make sure the keyboard focus stays in the work area.
1951                         setFocus();
1952                         break;
1953
1954                 case LFUN_COMPLETION_INLINE:
1955                         if (d.current_work_area_)
1956                                 d.current_work_area_->completer().showInline();
1957                         break;
1958
1959                 case LFUN_SPLIT_VIEW:
1960                         if (Buffer * buf = buffer()) {
1961                                 string const orientation = cmd.getArg(0);
1962                                 d.splitter_->setOrientation(orientation == "vertical"
1963                                         ? Qt::Vertical : Qt::Horizontal);
1964                                 TabWorkArea * twa = addTabWorkArea();
1965                                 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1966                                 setCurrentWorkArea(wa);
1967                         }
1968                         break;
1969
1970                 case LFUN_CLOSE_TAB_GROUP:
1971                         if (TabWorkArea * twa = d.currentTabWorkArea()) {
1972                                 delete twa;
1973                                 twa = d.currentTabWorkArea();
1974                                 // Switch to the next GuiWorkArea in the found TabWorkArea.
1975                                 if (twa) {
1976                                         d.current_work_area_ = twa->currentWorkArea();
1977                                         // Make sure the work area is up to date.
1978                                         twa->setCurrentWorkArea(d.current_work_area_);
1979                                 } else {
1980                                         d.current_work_area_ = 0;
1981                                 }
1982                                 if (d.splitter_->count() == 0)
1983                                         // No more work area, switch to the background widget.
1984                                         d.setBackground();
1985                         }
1986                         break;
1987                         
1988                 case LFUN_COMPLETION_POPUP:
1989                         if (d.current_work_area_)
1990                                 d.current_work_area_->completer().showPopup();
1991                         break;
1992
1993
1994                 case LFUN_COMPLETION_COMPLETE:
1995                         if (d.current_work_area_)
1996                                 d.current_work_area_->completer().tab();
1997                         break;
1998
1999                 default:
2000                         dispatched = false;
2001                         break;
2002         }
2003
2004         if (isFullScreen()) {
2005                 if (menuBar()->isVisible())
2006                         menuBar()->hide();
2007                 if (statusBar()->isVisible())
2008                         statusBar()->hide();
2009         }
2010
2011         return dispatched;
2012 }
2013
2014
2015 void GuiView::lfunUiToggle(FuncRequest const & cmd)
2016 {
2017         string const arg = cmd.getArg(0);
2018         if (arg == "scrollbar") {
2019                 // hide() is of no help
2020                 if (d.current_work_area_->verticalScrollBarPolicy() ==
2021                         Qt::ScrollBarAlwaysOff)
2022
2023                         d.current_work_area_->setVerticalScrollBarPolicy(
2024                                 Qt::ScrollBarAsNeeded);
2025                 else
2026                         d.current_work_area_->setVerticalScrollBarPolicy(
2027                                 Qt::ScrollBarAlwaysOff);
2028                 return;
2029         }
2030         if (arg == "statusbar") {
2031                 statusBar()->setVisible(!statusBar()->isVisible());
2032                 return;
2033         }
2034         if (arg == "menubar") {
2035                 menuBar()->setVisible(!menuBar()->isVisible());
2036                 return;
2037         }
2038 #if QT_VERSION >= 0x040300
2039         if (arg == "frame") {
2040                 int l, t, r, b;
2041                 getContentsMargins(&l, &t, &r, &b);
2042                 //are the frames in default state?
2043                 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
2044                 if (l == 0) {
2045                         setContentsMargins(-2, -2, -2, -2);
2046                 } else {
2047                         setContentsMargins(0, 0, 0, 0);
2048                 }
2049                 return;
2050         }
2051 #endif
2052         if (arg == "fullscreen") {
2053                 toggleFullScreen();
2054                 return;
2055         }
2056
2057         message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
2058 }
2059
2060
2061 void GuiView::toggleFullScreen()
2062 {
2063         if (isFullScreen()) {
2064                 for (int i = 0; i != d.splitter_->count(); ++i)
2065                         d.tabWorkArea(i)->setFullScreen(false);
2066 #if QT_VERSION >= 0x040300
2067                 setContentsMargins(0, 0, 0, 0);
2068 #endif
2069                 setWindowState(windowState() ^ Qt::WindowFullScreen);
2070                 restoreLayout();
2071                 menuBar()->show();
2072                 statusBar()->show();
2073         } else {
2074                 for (int i = 0; i != d.splitter_->count(); ++i)
2075                         d.tabWorkArea(i)->setFullScreen(true);
2076 #if QT_VERSION >= 0x040300
2077                 setContentsMargins(-2, -2, -2, -2);
2078 #endif
2079                 saveLayout();
2080                 setWindowState(windowState() ^ Qt::WindowFullScreen);
2081                 statusBar()->hide();
2082                 menuBar()->hide();
2083                 if (lyxrc.full_screen_toolbars) {
2084                         ToolbarMap::iterator end = d.toolbars_.end();
2085                         for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
2086                                 it->second->hide();
2087                 }
2088         }
2089 }
2090
2091
2092 Buffer const * GuiView::updateInset(Inset const * inset)
2093 {
2094         if (!d.current_work_area_)
2095                 return 0;
2096
2097         if (inset)
2098                 d.current_work_area_->scheduleRedraw();
2099
2100         return &d.current_work_area_->bufferView().buffer();
2101 }
2102
2103
2104 void GuiView::restartCursor()
2105 {
2106         /* When we move around, or type, it's nice to be able to see
2107          * the cursor immediately after the keypress.
2108          */
2109         if (d.current_work_area_)
2110                 d.current_work_area_->startBlinkingCursor();
2111
2112         // Take this occasion to update the other GUI elements.
2113         updateDialogs();
2114         updateStatusBar();
2115 }
2116
2117
2118 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2119 {
2120         if (d.current_work_area_)
2121                 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2122 }
2123
2124 namespace {
2125
2126 // This list should be kept in sync with the list of insets in
2127 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
2128 // dialog should have the same name as the inset.
2129 // Changes should be also recorded in LFUN_DIALOG_SHOW doxygen
2130 // docs in LyXAction.cpp.
2131
2132 char const * const dialognames[] = {
2133 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2134 "citation", "document", "errorlist", "ert", "external", "file",
2135 "findreplace", "float", "graphics", "include", "index", "info", "nomenclature", "label", "log",
2136 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print", 
2137 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2138
2139 #ifdef HAVE_LIBAIKSAURUS
2140 "thesaurus",
2141 #endif
2142
2143 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2144
2145 char const * const * const end_dialognames =
2146         dialognames + (sizeof(dialognames) / sizeof(char *));
2147
2148 class cmpCStr {
2149 public:
2150         cmpCStr(char const * name) : name_(name) {}
2151         bool operator()(char const * other) {
2152                 return strcmp(other, name_) == 0;
2153         }
2154 private:
2155         char const * name_;
2156 };
2157
2158
2159 bool isValidName(string const & name)
2160 {
2161         return find_if(dialognames, end_dialognames,
2162                             cmpCStr(name.c_str())) != end_dialognames;
2163 }
2164
2165 } // namespace anon
2166
2167
2168 void GuiView::resetDialogs()
2169 {
2170         // Make sure that no LFUN uses any LyXView.
2171         theLyXFunc().setLyXView(0);
2172         saveLayout();
2173         menuBar()->clear();
2174         constructToolbars();
2175         guiApp->menus().fillMenuBar(menuBar(), this, true);
2176         if (d.layout_)
2177                 d.layout_->updateContents(true);
2178         // Now update controls with current buffer.
2179         theLyXFunc().setLyXView(this);
2180         restoreLayout();
2181         restartCursor();
2182 }
2183
2184
2185 Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
2186 {
2187         if (!isValidName(name))
2188                 return 0;
2189
2190         map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2191
2192         if (it != d.dialogs_.end())
2193                 return it->second.get();
2194
2195         Dialog * dialog = build(name);
2196         d.dialogs_[name].reset(dialog);
2197         if (lyxrc.allow_geometry_session)
2198                 dialog->restoreSession();
2199         if (hide_it)
2200                 dialog->hideView();
2201         return dialog;
2202 }
2203
2204
2205 void GuiView::showDialog(string const & name, string const & data,
2206         Inset * inset)
2207 {
2208         if (d.in_show_)
2209                 return;
2210
2211         d.in_show_ = true;
2212         Dialog * dialog = findOrBuild(name, false);
2213         if (dialog) {
2214                 dialog->showData(data);
2215                 if (inset)
2216                         d.open_insets_[name] = inset;
2217         }
2218         d.in_show_ = false;
2219 }
2220
2221
2222 bool GuiView::isDialogVisible(string const & name) const
2223 {
2224         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2225         if (it == d.dialogs_.end())
2226                 return false;
2227         return it->second.get()->isVisibleView();
2228 }
2229
2230
2231 void GuiView::hideDialog(string const & name, Inset * inset)
2232 {
2233         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2234         if (it == d.dialogs_.end())
2235                 return;
2236
2237         if (inset && inset != getOpenInset(name))
2238                 return;
2239
2240         Dialog * const dialog = it->second.get();
2241         if (dialog->isVisibleView())
2242                 dialog->hideView();
2243         d.open_insets_[name] = 0;
2244 }
2245
2246
2247 void GuiView::disconnectDialog(string const & name)
2248 {
2249         if (!isValidName(name))
2250                 return;
2251
2252         if (d.open_insets_.find(name) != d.open_insets_.end())
2253                 d.open_insets_[name] = 0;
2254 }
2255
2256
2257 Inset * GuiView::getOpenInset(string const & name) const
2258 {
2259         if (!isValidName(name))
2260                 return 0;
2261
2262         map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2263         return it == d.open_insets_.end() ? 0 : it->second;
2264 }
2265
2266
2267 void GuiView::hideAll() const
2268 {
2269         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2270         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2271
2272         for(; it != end; ++it)
2273                 it->second->hideView();
2274 }
2275
2276
2277 void GuiView::updateDialogs()
2278 {
2279         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
2280         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2281
2282         for(; it != end; ++it) {
2283                 Dialog * dialog = it->second.get();
2284                 if (dialog && dialog->isVisibleView())
2285                         dialog->checkStatus();
2286         }
2287         updateToolbars();
2288         updateLayoutList();
2289 }
2290
2291
2292 // will be replaced by a proper factory...
2293 Dialog * createGuiAbout(GuiView & lv);
2294 Dialog * createGuiBibitem(GuiView & lv);
2295 Dialog * createGuiBibtex(GuiView & lv);
2296 Dialog * createGuiBox(GuiView & lv);
2297 Dialog * createGuiBranch(GuiView & lv);
2298 Dialog * createGuiChanges(GuiView & lv);
2299 Dialog * createGuiCharacter(GuiView & lv);
2300 Dialog * createGuiCitation(GuiView & lv);
2301 Dialog * createGuiDelimiter(GuiView & lv);
2302 Dialog * createGuiDocument(GuiView & lv);
2303 Dialog * createGuiErrorList(GuiView & lv);
2304 Dialog * createGuiERT(GuiView & lv);
2305 Dialog * createGuiExternal(GuiView & lv);
2306 Dialog * createGuiFloat(GuiView & lv);
2307 Dialog * createGuiGraphics(GuiView & lv);
2308 Dialog * createGuiHSpace(GuiView & lv);
2309 Dialog * createGuiInclude(GuiView & lv);
2310 Dialog * createGuiInfo(GuiView & lv);
2311 Dialog * createGuiLabel(GuiView & lv);
2312 Dialog * createGuiListings(GuiView & lv);
2313 Dialog * createGuiLog(GuiView & lv);
2314 Dialog * createGuiMathMatrix(GuiView & lv);
2315 Dialog * createGuiNomenclature(GuiView & lv);
2316 Dialog * createGuiNote(GuiView & lv);
2317 Dialog * createGuiParagraph(GuiView & lv);
2318 Dialog * createGuiPreferences(GuiView & lv);
2319 Dialog * createGuiPrint(GuiView & lv);
2320 Dialog * createGuiRef(GuiView & lv);
2321 Dialog * createGuiSearch(GuiView & lv);
2322 Dialog * createGuiSendTo(GuiView & lv);
2323 Dialog * createGuiShowFile(GuiView & lv);
2324 Dialog * createGuiSpellchecker(GuiView & lv);
2325 Dialog * createGuiSymbols(GuiView & lv);
2326 Dialog * createGuiTabularCreate(GuiView & lv);
2327 Dialog * createGuiTabular(GuiView & lv);
2328 Dialog * createGuiTexInfo(GuiView & lv);
2329 Dialog * createGuiToc(GuiView & lv);
2330 Dialog * createGuiThesaurus(GuiView & lv);
2331 Dialog * createGuiHyperlink(GuiView & lv);
2332 Dialog * createGuiVSpace(GuiView & lv);
2333 Dialog * createGuiViewSource(GuiView & lv);
2334 Dialog * createGuiWrap(GuiView & lv);
2335
2336
2337 Dialog * GuiView::build(string const & name)
2338 {
2339         LASSERT(isValidName(name), /**/);
2340
2341         if (name == "aboutlyx")
2342                 return createGuiAbout(*this);
2343         if (name == "bibitem")
2344                 return createGuiBibitem(*this);
2345         if (name == "bibtex")
2346                 return createGuiBibtex(*this);
2347         if (name == "box")
2348                 return createGuiBox(*this);
2349         if (name == "branch")
2350                 return createGuiBranch(*this);
2351         if (name == "changes")
2352                 return createGuiChanges(*this);
2353         if (name == "character")
2354                 return createGuiCharacter(*this);
2355         if (name == "citation")
2356                 return createGuiCitation(*this);
2357         if (name == "document")
2358                 return createGuiDocument(*this);
2359         if (name == "errorlist")
2360                 return createGuiErrorList(*this);
2361         if (name == "ert")
2362                 return createGuiERT(*this);
2363         if (name == "external")
2364                 return createGuiExternal(*this);
2365         if (name == "file")
2366                 return createGuiShowFile(*this);
2367         if (name == "findreplace")
2368                 return createGuiSearch(*this);
2369         if (name == "float")
2370                 return createGuiFloat(*this);
2371         if (name == "graphics")
2372                 return createGuiGraphics(*this);
2373         if (name == "include")
2374                 return createGuiInclude(*this);
2375         if (name == "info")
2376                 return createGuiInfo(*this);
2377         if (name == "nomenclature")
2378                 return createGuiNomenclature(*this);
2379         if (name == "label")
2380                 return createGuiLabel(*this);
2381         if (name == "log")
2382                 return createGuiLog(*this);
2383         if (name == "view-source")
2384                 return createGuiViewSource(*this);
2385         if (name == "mathdelimiter")
2386                 return createGuiDelimiter(*this);
2387         if (name == "mathmatrix")
2388                 return createGuiMathMatrix(*this);
2389         if (name == "note")
2390                 return createGuiNote(*this);
2391         if (name == "paragraph")
2392                 return createGuiParagraph(*this);
2393         if (name == "prefs")
2394                 return createGuiPreferences(*this);
2395         if (name == "print")
2396                 return createGuiPrint(*this);
2397         if (name == "ref")
2398                 return createGuiRef(*this);
2399         if (name == "sendto")
2400                 return createGuiSendTo(*this);
2401         if (name == "space")
2402                 return createGuiHSpace(*this);
2403         if (name == "spellchecker")
2404                 return createGuiSpellchecker(*this);
2405         if (name == "symbols")
2406                 return createGuiSymbols(*this);
2407         if (name == "tabular")
2408                 return createGuiTabular(*this);
2409         if (name == "tabularcreate")
2410                 return createGuiTabularCreate(*this);
2411         if (name == "texinfo")
2412                 return createGuiTexInfo(*this);
2413 #ifdef HAVE_LIBAIKSAURUS
2414         if (name == "thesaurus")
2415                 return createGuiThesaurus(*this);
2416 #endif
2417         if (name == "toc")
2418                 return createGuiToc(*this);
2419         if (name == "href")
2420                 return createGuiHyperlink(*this);
2421         if (name == "vspace")
2422                 return createGuiVSpace(*this);
2423         if (name == "wrap")
2424                 return createGuiWrap(*this);
2425         if (name == "listings")
2426                 return createGuiListings(*this);
2427
2428         return 0;
2429 }
2430
2431
2432 } // namespace frontend
2433 } // namespace lyx
2434
2435 #include "GuiView_moc.cpp"