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