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