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