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