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