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