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