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