]> git.lyx.org Git - features.git/blob - src/frontends/qt4/GuiView.cpp
s/updateLabels/updateBuffer/g, per a suggestion of Abdel's.
[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 "DispatchResult.h"
20 #include "FileDialog.h"
21 #include "FontLoader.h"
22 #include "GuiApplication.h"
23 #include "GuiCommandBuffer.h"
24 #include "GuiCompleter.h"
25 #include "GuiKeySymbol.h"
26 #include "GuiToc.h"
27 #include "GuiToolbar.h"
28 #include "GuiWorkArea.h"
29 #include "LayoutBox.h"
30 #include "Menus.h"
31 #include "TocModel.h"
32
33 #include "qt_helpers.h"
34
35 #include "frontends/alert.h"
36
37 #include "buffer_funcs.h"
38 #include "Buffer.h"
39 #include "BufferList.h"
40 #include "BufferParams.h"
41 #include "BufferView.h"
42 #include "Compare.h"
43 #include "Converter.h"
44 #include "Cursor.h"
45 #include "CutAndPaste.h"
46 #include "Encoding.h"
47 #include "ErrorList.h"
48 #include "Format.h"
49 #include "FuncStatus.h"
50 #include "FuncRequest.h"
51 #include "Intl.h"
52 #include "Layout.h"
53 #include "Lexer.h"
54 #include "LyXAction.h"
55 #include "LyX.h"
56 #include "LyXRC.h"
57 #include "LyXVC.h"
58 #include "Paragraph.h"
59 #include "SpellChecker.h"
60 #include "TextClass.h"
61 #include "Text.h"
62 #include "Toolbars.h"
63 #include "version.h"
64
65 #include "support/convert.h"
66 #include "support/debug.h"
67 #include "support/ExceptionMessage.h"
68 #include "support/FileName.h"
69 #include "support/filetools.h"
70 #include "support/gettext.h"
71 #include "support/filetools.h"
72 #include "support/ForkedCalls.h"
73 #include "support/lassert.h"
74 #include "support/lstrings.h"
75 #include "support/os.h"
76 #include "support/Package.h"
77 #include "support/Path.h"
78 #include "support/Systemcall.h"
79 #include "support/Timeout.h"
80 #include "support/ProgressInterface.h"
81 #include "GuiProgress.h"
82
83 #include <QAction>
84 #include <QApplication>
85 #include <QCloseEvent>
86 #include <QDebug>
87 #include <QDesktopWidget>
88 #include <QDragEnterEvent>
89 #include <QDropEvent>
90 #include <QList>
91 #include <QMenu>
92 #include <QMenuBar>
93 #include <QPainter>
94 #include <QPixmap>
95 #include <QPixmapCache>
96 #include <QPoint>
97 #include <QPushButton>
98 #include <QSettings>
99 #include <QShowEvent>
100 #include <QSplitter>
101 #include <QStackedWidget>
102 #include <QStatusBar>
103 #include <QTime>
104 #include <QTimer>
105 #include <QToolBar>
106 #include <QUrl>
107 #include <QScrollBar>
108
109 #define EXPORT_in_THREAD 1
110
111 // QtConcurrent was introduced in Qt 4.4
112 #if (QT_VERSION >= 0x040400)
113 #include <QFuture>
114 #include <QFutureWatcher>
115 #include <QtConcurrentRun>
116 #endif
117
118 #include <boost/bind.hpp>
119
120 #include <sstream>
121
122 #ifdef HAVE_SYS_TIME_H
123 # include <sys/time.h>
124 #endif
125 #ifdef HAVE_UNISTD_H
126 # include <unistd.h>
127 #endif
128
129 using namespace std;
130 using namespace lyx::support;
131
132 namespace lyx {
133 namespace frontend {
134
135 namespace {
136
137 class BackgroundWidget : public QWidget
138 {
139 public:
140         BackgroundWidget()
141         {
142                 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
143                 /// The text to be written on top of the pixmap
144                 QString const text = lyx_version ?
145                         qt_("version ") + lyx_version : qt_("unknown version");
146                 splash_ = getPixmap("images/", "banner", "png");
147
148                 QPainter pain(&splash_);
149                 pain.setPen(QColor(0, 0, 0));
150                 QFont font;
151                 // The font used to display the version info
152                 font.setStyleHint(QFont::SansSerif);
153                 font.setWeight(QFont::Bold);
154                 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
155                 pain.setFont(font);
156                 pain.drawText(260, 15, text);
157                 setFocusPolicy(Qt::StrongFocus);
158         }
159
160         void paintEvent(QPaintEvent *)
161         {
162                 int x = (width() - splash_.width()) / 2;
163                 int y = (height() - splash_.height()) / 2;
164                 QPainter pain(this);
165                 pain.drawPixmap(x, y, splash_);
166         }
167
168         void keyPressEvent(QKeyEvent * ev)
169         {
170                 KeySymbol sym;
171                 setKeySymbol(&sym, ev);
172                 if (sym.isOK()) {
173                         guiApp->processKeySym(sym, q_key_state(ev->modifiers()));
174                         ev->accept();
175                 } else {
176                         ev->ignore();
177                 }
178         }
179
180 private:
181         QPixmap splash_;
182 };
183
184
185 /// Toolbar store providing access to individual toolbars by name.
186 typedef map<string, GuiToolbar *> ToolbarMap;
187
188 typedef boost::shared_ptr<Dialog> DialogPtr;
189
190 } // namespace anon
191
192
193 struct GuiView::GuiViewPrivate
194 {
195         GuiViewPrivate(GuiView * gv)
196                 : gv_(gv), current_work_area_(0), current_main_work_area_(0),
197                 layout_(0), autosave_timeout_(5000),
198                 in_show_(false)
199         {
200                 // hardcode here the platform specific icon size
201                 smallIconSize = 14;  // scaling problems
202                 normalIconSize = 20; // ok, default
203                 bigIconSize = 26;    // better for some math icons
204
205                 splitter_ = new QSplitter;
206                 bg_widget_ = new BackgroundWidget;
207                 stack_widget_ = new QStackedWidget;
208                 stack_widget_->addWidget(bg_widget_);
209                 stack_widget_->addWidget(splitter_);
210                 setBackground();
211                 progress_ = new GuiProgress(gv);
212         }
213
214         ~GuiViewPrivate()
215         {
216                 delete splitter_;
217                 delete bg_widget_;
218                 delete stack_widget_;
219                 delete progress_;
220         }
221
222         QMenu * toolBarPopup(GuiView * parent)
223         {
224                 // FIXME: translation
225                 QMenu * menu = new QMenu(parent);
226                 QActionGroup * iconSizeGroup = new QActionGroup(parent);
227
228                 QAction * smallIcons = new QAction(iconSizeGroup);
229                 smallIcons->setText(qt_("Small-sized icons"));
230                 smallIcons->setCheckable(true);
231                 QObject::connect(smallIcons, SIGNAL(triggered()),
232                         parent, SLOT(smallSizedIcons()));
233                 menu->addAction(smallIcons);
234
235                 QAction * normalIcons = new QAction(iconSizeGroup);
236                 normalIcons->setText(qt_("Normal-sized icons"));
237                 normalIcons->setCheckable(true);
238                 QObject::connect(normalIcons, SIGNAL(triggered()),
239                         parent, SLOT(normalSizedIcons()));
240                 menu->addAction(normalIcons);
241
242                 QAction * bigIcons = new QAction(iconSizeGroup);
243                 bigIcons->setText(qt_("Big-sized icons"));
244                 bigIcons->setCheckable(true);
245                 QObject::connect(bigIcons, SIGNAL(triggered()),
246                         parent, SLOT(bigSizedIcons()));
247                 menu->addAction(bigIcons);
248
249                 unsigned int cur = parent->iconSize().width();
250                 if ( cur == parent->d.smallIconSize)
251                         smallIcons->setChecked(true);
252                 else if (cur == parent->d.normalIconSize)
253                         normalIcons->setChecked(true);
254                 else if (cur == parent->d.bigIconSize)
255                         bigIcons->setChecked(true);
256
257                 return menu;
258         }
259
260         void setBackground()
261         {
262                 stack_widget_->setCurrentWidget(bg_widget_);
263                 bg_widget_->setUpdatesEnabled(true);
264                 bg_widget_->setFocus();
265         }
266
267         TabWorkArea * tabWorkArea(int i)
268         {
269                 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
270         }
271
272         TabWorkArea * currentTabWorkArea()
273         {
274                 if (splitter_->count() == 1)
275                         // The first TabWorkArea is always the first one, if any.
276                         return tabWorkArea(0);
277
278                 for (int i = 0; i != splitter_->count(); ++i) {
279                         TabWorkArea * twa = tabWorkArea(i);
280                         if (current_main_work_area_ == twa->currentWorkArea())
281                                 return twa;
282                 }
283
284                 // None has the focus so we just take the first one.
285                 return tabWorkArea(0);
286         }
287
288 #if (QT_VERSION >= 0x040400)
289         void setPreviewFuture(QFuture<docstring> const & f)
290         {
291                 if (preview_watcher_.isRunning()) {
292                         // we prefer to cancel this preview in order to keep a snappy
293                         // interface.
294                         return;
295                 }
296                 preview_watcher_.setFuture(f);
297         }
298 #endif
299
300 public:
301         GuiView * gv_;
302         GuiWorkArea * current_work_area_;
303         GuiWorkArea * current_main_work_area_;
304         QSplitter * splitter_;
305         QStackedWidget * stack_widget_;
306         BackgroundWidget * bg_widget_;
307         /// view's toolbars
308         ToolbarMap toolbars_;
309         ProgressInterface* progress_;
310         /// The main layout box.
311         /** 
312          * \warning Don't Delete! The layout box is actually owned by
313          * whichever toolbar contains it. All the GuiView class needs is a
314          * means of accessing it.
315          *
316          * FIXME: replace that with a proper model so that we are not limited
317          * to only one dialog.
318          */
319         LayoutBox * layout_;
320
321         ///
322         map<string, DialogPtr> dialogs_;
323
324         unsigned int smallIconSize;
325         unsigned int normalIconSize;
326         unsigned int bigIconSize;
327         ///
328         QTimer statusbar_timer_;
329         /// auto-saving of buffers
330         Timeout autosave_timeout_;
331         /// flag against a race condition due to multiclicks, see bug #1119
332         bool in_show_;
333
334         ///
335         TocModels toc_models_;
336
337 #if (QT_VERSION >= 0x040400)
338         ///
339         QFutureWatcher<docstring> autosave_watcher_;
340         QFutureWatcher<docstring> preview_watcher_;
341 #else
342         struct DummyWatcher { bool isRunning(){return false;} }; 
343         DummyWatcher preview_watcher_;
344 #endif
345 };
346
347
348 GuiView::GuiView(int id)
349         : d(*new GuiViewPrivate(this)), id_(id), closing_(false)
350 {
351         // GuiToolbars *must* be initialised before the menu bar.
352         normalSizedIcons(); // at least on Mac the default is 32 otherwise, which is huge
353         constructToolbars();
354
355         // set ourself as the current view. This is needed for the menu bar
356         // filling, at least for the static special menu item on Mac. Otherwise
357         // they are greyed out.
358         guiApp->setCurrentView(this);
359         
360         // Fill up the menu bar.
361         guiApp->menus().fillMenuBar(menuBar(), this, true);
362
363         setCentralWidget(d.stack_widget_);
364
365         // Start autosave timer
366         if (lyxrc.autosave) {
367                 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
368                 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
369                 d.autosave_timeout_.start();
370         }
371         connect(&d.statusbar_timer_, SIGNAL(timeout()),
372                 this, SLOT(clearMessage()));
373
374         // We don't want to keep the window in memory if it is closed.
375         setAttribute(Qt::WA_DeleteOnClose, true);
376
377 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
378         // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
379         // since the icon is provided in the application bundle.
380         setWindowIcon(getPixmap("images/", "lyx", "png"));
381 #endif
382
383 #if (QT_VERSION >= 0x040300)
384         // use tabbed dock area for multiple docks
385         // (such as "source" and "messages")
386         setDockOptions(QMainWindow::ForceTabbedDocks);
387 #endif
388
389         // For Drag&Drop.
390         setAcceptDrops(true);
391
392         statusBar()->setSizeGripEnabled(true);
393         updateStatusBar();
394
395 #if (QT_VERSION >= 0x040400)
396         connect(&d.autosave_watcher_, SIGNAL(finished()), this,
397                 SLOT(threadFinished()));
398         connect(&d.preview_watcher_, SIGNAL(finished()), this,
399                 SLOT(threadFinished()));
400 #endif
401
402         connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)),
403                 SLOT(doShowDialog(QString const &, QString const &, Inset *)));
404
405         // Forbid too small unresizable window because it can happen
406         // with some window manager under X11.
407         setMinimumSize(300, 200);
408
409         if (lyxrc.allow_geometry_session) {
410                 // Now take care of session management.
411                 if (restoreLayout())
412                         return;
413         }
414
415         // no session handling, default to a sane size.
416         setGeometry(50, 50, 690, 510);
417         initToolbars();
418
419         // clear session data if any.
420         QSettings settings;
421         settings.remove("views");
422 }
423
424
425 GuiView::~GuiView()
426 {
427         delete &d;
428 }
429
430
431 void GuiView::threadFinished()
432 {
433 #if (QT_VERSION >= 0x040400)
434         QFutureWatcher<docstring> const * watcher =
435                 static_cast<QFutureWatcher<docstring> const *>(sender());
436         message(watcher->result());
437 #endif
438 }
439
440
441 void GuiView::saveLayout() const
442 {
443         QSettings settings;
444         settings.beginGroup("views");
445         settings.beginGroup(QString::number(id_));
446 #ifdef Q_WS_X11
447         settings.setValue("pos", pos());
448         settings.setValue("size", size());
449 #else
450         settings.setValue("geometry", saveGeometry());
451 #endif
452         settings.setValue("layout", saveState(0));
453         settings.setValue("icon_size", iconSize());
454 }
455
456
457 bool GuiView::restoreLayout()
458 {
459         QSettings settings;
460         settings.beginGroup("views");
461         settings.beginGroup(QString::number(id_));
462         QString const icon_key = "icon_size";
463         if (!settings.contains(icon_key))
464                 return false;
465
466         //code below is skipped when when ~/.config/LyX is (re)created
467         setIconSize(settings.value(icon_key).toSize());
468 #ifdef Q_WS_X11
469         QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
470         QSize size = settings.value("size", QSize(690, 510)).toSize();
471         resize(size);
472         move(pos);
473 #else
474         // Work-around for bug #6034: the window ends up in an undetermined
475         // state when trying to restore a maximized window when it is
476         // already maximized.
477         if (!(windowState() & Qt::WindowMaximized))
478                 if (!restoreGeometry(settings.value("geometry").toByteArray()))
479                         setGeometry(50, 50, 690, 510);
480 #endif
481         // Make sure layout is correctly oriented.
482         setLayoutDirection(qApp->layoutDirection());
483
484         // Allow the toc and view-source dock widget to be restored if needed.
485         Dialog * dialog;
486         if ((dialog = findOrBuild("toc", true)))
487                 // see bug 5082. At least setup title and enabled state.
488                 // Visibility will be adjusted by restoreState below.
489                 dialog->prepareView();
490         if ((dialog = findOrBuild("view-source", true)))
491                 dialog->prepareView();
492         if ((dialog = findOrBuild("progress", true)))
493                 dialog->prepareView();
494
495         if (!restoreState(settings.value("layout").toByteArray(), 0))
496                 initToolbars();
497         updateDialogs();
498         return true;
499 }
500
501
502 GuiToolbar * GuiView::toolbar(string const & name)
503 {
504         ToolbarMap::iterator it = d.toolbars_.find(name);
505         if (it != d.toolbars_.end())
506                 return it->second;
507
508         LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
509         return 0;
510 }
511
512
513 void GuiView::constructToolbars()
514 {
515         ToolbarMap::iterator it = d.toolbars_.begin();
516         for (; it != d.toolbars_.end(); ++it)
517                 delete it->second;
518         d.toolbars_.clear();
519
520         // I don't like doing this here, but the standard toolbar
521         // destroys this object when it's destroyed itself (vfr)
522         d.layout_ = new LayoutBox(*this);
523         d.stack_widget_->addWidget(d.layout_);
524         d.layout_->move(0,0);
525
526         // extracts the toolbars from the backend
527         Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
528         Toolbars::Infos::iterator end = guiApp->toolbars().end();
529         for (; cit != end; ++cit)
530                 d.toolbars_[cit->name] =  new GuiToolbar(*cit, *this);
531 }
532
533
534 void GuiView::initToolbars()
535 {
536         // extracts the toolbars from the backend
537         Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
538         Toolbars::Infos::iterator end = guiApp->toolbars().end();
539         for (; cit != end; ++cit) {
540                 GuiToolbar * tb = toolbar(cit->name);
541                 if (!tb)
542                         continue;
543                 int const visibility = guiApp->toolbars().defaultVisibility(cit->name);
544                 bool newline = !(visibility & Toolbars::SAMEROW);
545                 tb->setVisible(false);
546                 tb->setVisibility(visibility);
547
548                 if (visibility & Toolbars::TOP) {
549                         if (newline)
550                                 addToolBarBreak(Qt::TopToolBarArea);
551                         addToolBar(Qt::TopToolBarArea, tb);
552                 }
553
554                 if (visibility & Toolbars::BOTTOM) {
555                         // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
556 #if (QT_VERSION >= 0x040202)
557                         if (newline)
558                                 addToolBarBreak(Qt::BottomToolBarArea);
559 #endif
560                         addToolBar(Qt::BottomToolBarArea, tb);
561                 }
562
563                 if (visibility & Toolbars::LEFT) {
564                         // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
565 #if (QT_VERSION >= 0x040202)
566                         if (newline)
567                                 addToolBarBreak(Qt::LeftToolBarArea);
568 #endif
569                         addToolBar(Qt::LeftToolBarArea, tb);
570                 }
571
572                 if (visibility & Toolbars::RIGHT) {
573                         // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
574 #if (QT_VERSION >= 0x040202)
575                         if (newline)
576                                 addToolBarBreak(Qt::RightToolBarArea);
577 #endif
578                         addToolBar(Qt::RightToolBarArea, tb);
579                 }
580
581                 if (visibility & Toolbars::ON)
582                         tb->setVisible(true);
583         }
584 }
585
586
587 TocModels & GuiView::tocModels()
588 {
589         return d.toc_models_;
590 }
591
592
593 void GuiView::setFocus()
594 {
595         LYXERR(Debug::DEBUG, "GuiView::setFocus()" << this);
596         QMainWindow::setFocus();
597 }
598
599
600 void GuiView::focusInEvent(QFocusEvent * e)
601 {
602         LYXERR(Debug::DEBUG, "GuiView::focusInEvent()" << this);
603         QMainWindow::focusInEvent(e);
604         // Make sure guiApp points to the correct view.
605         guiApp->setCurrentView(this);
606         if (currentMainWorkArea())
607                 currentMainWorkArea()->setFocus();
608         else if (currentWorkArea())
609                 currentWorkArea()->setFocus();
610         else
611                 d.bg_widget_->setFocus();
612 }
613
614
615 QMenu * GuiView::createPopupMenu()
616 {
617         return d.toolBarPopup(this);
618 }
619
620
621 void GuiView::showEvent(QShowEvent * e)
622 {
623         LYXERR(Debug::GUI, "Passed Geometry "
624                 << size().height() << "x" << size().width()
625                 << "+" << pos().x() << "+" << pos().y());
626
627         if (d.splitter_->count() == 0)
628                 // No work area, switch to the background widget.
629                 d.setBackground();
630
631         QMainWindow::showEvent(e);
632 }
633
634
635 /** Destroy only all tabbed WorkAreas. Destruction of other WorkAreas
636  ** is responsibility of the container (e.g., dialog)
637  **/
638 void GuiView::closeEvent(QCloseEvent * close_event)
639 {
640         LYXERR(Debug::DEBUG, "GuiView::closeEvent()");
641         closing_ = true;
642
643         writeSession();
644
645         // it can happen that this event arrives without selecting the view,
646         // e.g. when clicking the close button on a background window.
647         setFocus();
648         if (!closeWorkAreaAll()) {
649                 closing_ = false;
650                 close_event->ignore();
651                 return;
652         }
653
654         // Make sure that nothing will use this to be closed View.
655         guiApp->unregisterView(this);
656
657         if (isFullScreen()) {
658                 // Switch off fullscreen before closing.
659                 toggleFullScreen();
660                 updateDialogs();
661         }
662
663         // Make sure the timer time out will not trigger a statusbar update.
664         d.statusbar_timer_.stop();
665
666         // Saving fullscreen requires additional tweaks in the toolbar code.
667         // It wouldn't also work under linux natively.
668         if (lyxrc.allow_geometry_session) {
669                 // Save this window geometry and layout.
670                 saveLayout();
671                 // Then the toolbar private states.
672                 ToolbarMap::iterator end = d.toolbars_.end();
673                 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
674                         it->second->saveSession();
675                 // Now take care of all other dialogs:
676                 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
677                 for (; it!= d.dialogs_.end(); ++it)
678                         it->second->saveSession();
679         }
680
681         close_event->accept();
682 }
683
684
685 void GuiView::dragEnterEvent(QDragEnterEvent * event)
686 {
687         if (event->mimeData()->hasUrls())
688                 event->accept();
689         /// \todo Ask lyx-devel is this is enough:
690         /// if (event->mimeData()->hasFormat("text/plain"))
691         ///     event->acceptProposedAction();
692 }
693
694
695 void GuiView::dropEvent(QDropEvent * event)
696 {
697         QList<QUrl> files = event->mimeData()->urls();
698         if (files.isEmpty())
699                 return;
700
701         LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
702         for (int i = 0; i != files.size(); ++i) {
703                 string const file = os::internal_path(fromqstr(
704                         files.at(i).toLocalFile()));
705                 if (file.empty())
706                         continue;
707
708                 string const ext = support::getExtension(file);
709                 vector<const Format *> found_formats;
710
711                 // Find all formats that have the correct extension.
712                 vector<const Format *> const & import_formats 
713                         = theConverters().importableFormats();
714                 vector<const Format *>::const_iterator it = import_formats.begin();
715                 for (; it != import_formats.end(); ++it)
716                         if ((*it)->extension() == ext)
717                                 found_formats.push_back(*it);
718
719                 FuncRequest cmd;
720                 if (found_formats.size() >= 1) {
721                         if (found_formats.size() > 1) {
722                                 //FIXME: show a dialog to choose the correct importable format
723                                 LYXERR(Debug::FILES,
724                                         "Multiple importable formats found, selecting first");
725                         }
726                         string const arg = found_formats[0]->name() + " " + file;
727                         cmd = FuncRequest(LFUN_BUFFER_IMPORT, arg);
728                 } 
729                 else {
730                         //FIXME: do we have to explicitly check whether it's a lyx file?
731                         LYXERR(Debug::FILES,
732                                 "No formats found, trying to open it as a lyx file");
733                         cmd = FuncRequest(LFUN_FILE_OPEN, file);
734                 }
735
736                 // Asynchronously post the event. DropEvent usually comes
737                 // from the BufferView. But reloading a file might close
738                 // the BufferView from within its own event handler.
739                 guiApp->dispatchDelayed(cmd);
740                 event->accept();
741         }
742 }
743
744
745 void GuiView::message(docstring const & str)
746 {
747         if (ForkedProcess::iAmAChild())
748                 return;
749         
750         // call is moved to GUI-thread by GuiProgress
751         d.progress_->appendMessage(toqstr(str));
752 }
753
754
755 void GuiView::updateMessage(QString const & str)
756 {
757         statusBar()->showMessage(str);
758         d.statusbar_timer_.stop();
759         d.statusbar_timer_.start(3000);
760 }
761
762
763 void GuiView::smallSizedIcons()
764 {
765         setIconSize(QSize(d.smallIconSize, d.smallIconSize));
766 }
767
768
769 void GuiView::normalSizedIcons()
770 {
771         setIconSize(QSize(d.normalIconSize, d.normalIconSize));
772 }
773
774
775 void GuiView::bigSizedIcons()
776 {
777         setIconSize(QSize(d.bigIconSize, d.bigIconSize));
778 }
779
780
781 void GuiView::clearMessage()
782 {
783         // FIXME: This code was introduced in r19643 to fix bug #4123. However,
784         // the hasFocus function mostly returns false, even if the focus is on
785         // a workarea in this view.
786         //if (!hasFocus())
787         //      return;
788         showMessage();
789         d.statusbar_timer_.stop();
790 }
791
792
793 void GuiView::updateWindowTitle(GuiWorkArea * wa)
794 {
795         if (wa != d.current_work_area_
796             || wa->bufferView().buffer().isInternal())
797                 return;
798         setWindowTitle(qt_("LyX: ") + wa->windowTitle());
799         setWindowIconText(wa->windowIconText());
800 }
801
802
803 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
804 {
805         disconnectBuffer();
806         disconnectBufferView();
807         connectBufferView(wa->bufferView());
808         connectBuffer(wa->bufferView().buffer());
809         d.current_work_area_ = wa;
810         QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
811                 this, SLOT(updateWindowTitle(GuiWorkArea *)));
812         updateWindowTitle(wa);
813
814         structureChanged();
815
816         // The document settings needs to be reinitialised.
817         updateDialog("document", "");
818
819         // Buffer-dependent dialogs must be updated. This is done here because
820         // some dialogs require buffer()->text.
821         updateDialogs();
822 }
823
824
825 void GuiView::on_lastWorkAreaRemoved()
826 {
827         if (closing_)
828                 // We already are in a close event. Nothing more to do.
829                 return;
830
831         if (d.splitter_->count() > 1)
832                 // We have a splitter so don't close anything.
833                 return;
834
835         // Reset and updates the dialogs.
836         d.toc_models_.reset(0);
837         updateDialog("document", "");
838         updateDialogs();
839
840         resetWindowTitleAndIconText();
841         updateStatusBar();
842
843         if (lyxrc.open_buffers_in_tabs)
844                 // Nothing more to do, the window should stay open.
845                 return;
846
847         if (guiApp->viewIds().size() > 1) {
848                 close();
849                 return;
850         }
851
852 #ifdef Q_WS_MACX
853         // On Mac we also close the last window because the application stay
854         // resident in memory. On other platforms we don't close the last
855         // window because this would quit the application.
856         close();
857 #endif
858 }
859
860
861 void GuiView::updateStatusBar()
862 {
863         // let the user see the explicit message
864         if (d.statusbar_timer_.isActive())
865                 return;
866
867         showMessage();
868 }
869
870
871 void GuiView::showMessage()
872 {
873         QString msg = toqstr(theGuiApp()->viewStatusMessage());
874         if (msg.isEmpty()) {
875                 BufferView const * bv = currentBufferView();
876                 if (bv)
877                         msg = toqstr(bv->cursor().currentState());
878                 else
879                         msg = qt_("Welcome to LyX!");
880         }
881         statusBar()->showMessage(msg);
882 }
883
884
885 bool GuiView::event(QEvent * e)
886 {
887         switch (e->type())
888         {
889         // Useful debug code:
890         //case QEvent::ActivationChange:
891         //case QEvent::WindowDeactivate:
892         //case QEvent::Paint:
893         //case QEvent::Enter:
894         //case QEvent::Leave:
895         //case QEvent::HoverEnter:
896         //case QEvent::HoverLeave:
897         //case QEvent::HoverMove:
898         //case QEvent::StatusTip:
899         //case QEvent::DragEnter:
900         //case QEvent::DragLeave:
901         //case QEvent::Drop:
902         //      break;
903
904         case QEvent::WindowActivate: {
905                 GuiView * old_view = guiApp->currentView();
906                 if (this == old_view) {
907                         setFocus();
908                         return QMainWindow::event(e);
909                 }
910                 if (old_view && old_view->currentBufferView()) {
911                         // save current selection to the selection buffer to allow
912                         // middle-button paste in this window.
913                         cap::saveSelection(old_view->currentBufferView()->cursor());
914                 }
915                 guiApp->setCurrentView(this);
916                 if (d.current_work_area_) {
917                         BufferView & bv = d.current_work_area_->bufferView();
918                         connectBufferView(bv);
919                         connectBuffer(bv.buffer());
920                         // The document structure, name and dialogs might have
921                         // changed in another view.
922                         structureChanged();
923                         // The document settings needs to be reinitialised.
924                         updateDialog("document", "");
925                         updateDialogs();
926                 } else {
927                         resetWindowTitleAndIconText();
928                 }
929                 setFocus();
930                 return QMainWindow::event(e);
931         }
932
933         case QEvent::ShortcutOverride: {
934
935 // See bug 4888
936 #if (!defined Q_WS_X11) || (QT_VERSION >= 0x040500)
937                 if (isFullScreen() && menuBar()->isHidden()) {
938                         QKeyEvent * ke = static_cast<QKeyEvent*>(e);
939                         // FIXME: we should also try to detect special LyX shortcut such as
940                         // Alt-P and Alt-M. Right now there is a hack in
941                         // GuiWorkArea::processKeySym() that hides again the menubar for
942                         // those cases.
943                         if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt) {
944                                 menuBar()->show();
945                                 return QMainWindow::event(e);
946                         }
947                 }
948 #endif
949                 return QMainWindow::event(e);
950         }
951
952         default:
953                 return QMainWindow::event(e);
954         }
955 }
956
957 void GuiView::resetWindowTitleAndIconText()
958 {
959     setWindowTitle(qt_("LyX"));
960     setWindowIconText(qt_("LyX"));
961 }
962
963 bool GuiView::focusNextPrevChild(bool /*next*/)
964 {
965         setFocus();
966         return true;
967 }
968
969
970 void GuiView::setBusy(bool busy)
971 {
972         if (d.current_work_area_) {
973                 d.current_work_area_->setUpdatesEnabled(!busy);
974                 if (busy)
975                         d.current_work_area_->stopBlinkingCursor();
976                 else
977                         d.current_work_area_->startBlinkingCursor();
978         }
979
980         if (busy)
981                 QApplication::setOverrideCursor(Qt::WaitCursor);
982         else
983                 QApplication::restoreOverrideCursor();
984 }
985
986
987 GuiWorkArea * GuiView::workArea(Buffer & buffer)
988 {
989         if (currentWorkArea()
990             && &currentWorkArea()->bufferView().buffer() == &buffer)
991                 return (GuiWorkArea *) currentWorkArea();
992         if (TabWorkArea * twa = d.currentTabWorkArea())
993                 return twa->workArea(buffer);
994         return 0;
995 }
996
997
998 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
999 {
1000         // Automatically create a TabWorkArea if there are none yet.
1001         TabWorkArea * tab_widget = d.splitter_->count() 
1002                 ? d.currentTabWorkArea() : addTabWorkArea();
1003         return tab_widget->addWorkArea(buffer, *this);
1004 }
1005
1006
1007 TabWorkArea * GuiView::addTabWorkArea()
1008 {
1009         TabWorkArea * twa = new TabWorkArea;
1010         QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
1011                 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
1012         QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
1013                          this, SLOT(on_lastWorkAreaRemoved()));
1014
1015         d.splitter_->addWidget(twa);
1016         d.stack_widget_->setCurrentWidget(d.splitter_);
1017         return twa;
1018 }
1019
1020
1021 GuiWorkArea const * GuiView::currentWorkArea() const
1022 {
1023         return d.current_work_area_;
1024 }
1025
1026
1027 GuiWorkArea * GuiView::currentWorkArea()
1028 {
1029         return d.current_work_area_;
1030 }
1031
1032
1033 GuiWorkArea const * GuiView::currentMainWorkArea() const
1034 {
1035         if (!d.currentTabWorkArea())
1036                 return 0;
1037         return d.currentTabWorkArea()->currentWorkArea();
1038 }
1039
1040
1041 GuiWorkArea * GuiView::currentMainWorkArea()
1042 {
1043         if (!d.currentTabWorkArea())
1044                 return 0;
1045         return d.currentTabWorkArea()->currentWorkArea();
1046 }
1047
1048
1049 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
1050 {
1051         LYXERR(Debug::DEBUG, "Setting current wa: " << wa << endl);
1052         if (!wa) {
1053                 d.current_work_area_ = 0;
1054                 d.setBackground();
1055                 return;
1056         }
1057
1058         // FIXME: I've no clue why this is here and why it accesses
1059         //  theGuiApp()->currentView, which might be 0 (bug 6464).
1060         //  See also 27525 (vfr).
1061         if (theGuiApp()->currentView() == this 
1062                   && theGuiApp()->currentView()->currentWorkArea() == wa) 
1063                 return;
1064
1065         if (currentBufferView())
1066                 cap::saveSelection(currentBufferView()->cursor());
1067
1068         theGuiApp()->setCurrentView(this);
1069         d.current_work_area_ = wa;
1070         for (int i = 0; i != d.splitter_->count(); ++i) {
1071                 if (d.tabWorkArea(i)->setCurrentWorkArea(wa)) {
1072                         //if (d.current_main_work_area_)
1073                         //      d.current_main_work_area_->setFrameStyle(QFrame::NoFrame);
1074                         d.current_main_work_area_ = wa;
1075                         //d.current_main_work_area_->setFrameStyle(QFrame::Box | QFrame::Plain);
1076                         //d.current_main_work_area_->setLineWidth(2);
1077                         LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
1078                         return;
1079                 }
1080         }
1081         LYXERR(Debug::DEBUG, "This is not a tabbed wa");
1082         on_currentWorkAreaChanged(wa);
1083         BufferView & bv = wa->bufferView();
1084         bv.cursor().fixIfBroken();
1085         bv.updateMetrics();
1086         wa->setUpdatesEnabled(true);
1087         LYXERR(Debug::DEBUG, "Current wa: " << currentWorkArea() << ", Current main wa: " << currentMainWorkArea());
1088 }
1089
1090
1091 void GuiView::removeWorkArea(GuiWorkArea * wa)
1092 {
1093         LASSERT(wa, return);
1094         if (wa == d.current_work_area_) {
1095                 disconnectBuffer();
1096                 disconnectBufferView();
1097                 d.current_work_area_ = 0;
1098                 d.current_main_work_area_ = 0;
1099         }
1100
1101         bool found_twa = false;
1102         for (int i = 0; i != d.splitter_->count(); ++i) {
1103                 TabWorkArea * twa = d.tabWorkArea(i);
1104                 if (twa->removeWorkArea(wa)) {
1105                         // Found in this tab group, and deleted the GuiWorkArea.
1106                         found_twa = true;
1107                         if (twa->count() != 0) {
1108                                 if (d.current_work_area_ == 0)
1109                                         // This means that we are closing the current GuiWorkArea, so
1110                                         // switch to the next GuiWorkArea in the found TabWorkArea.
1111                                         setCurrentWorkArea(twa->currentWorkArea());
1112                         } else {
1113                                 // No more WorkAreas in this tab group, so delete it.
1114                                 delete twa;
1115                         }
1116                         break;
1117                 }
1118         }
1119
1120         // It is not a tabbed work area (i.e., the search work area), so it
1121         // should be deleted by other means.
1122         LASSERT(found_twa, /* */);
1123
1124         if (d.current_work_area_ == 0) {
1125                 if (d.splitter_->count() != 0) {
1126                         TabWorkArea * twa = d.currentTabWorkArea();
1127                         setCurrentWorkArea(twa->currentWorkArea());
1128                 } else {
1129                         // No more work areas, switch to the background widget.
1130                         setCurrentWorkArea(0);
1131                 }
1132         }
1133 }
1134
1135
1136 LayoutBox * GuiView::getLayoutDialog() const
1137 {
1138         return d.layout_;
1139 }
1140
1141
1142 void GuiView::updateLayoutList()
1143 {
1144         if (d.layout_)
1145                 d.layout_->updateContents(false);
1146 }
1147
1148
1149 void GuiView::updateToolbars()
1150 {
1151         ToolbarMap::iterator end = d.toolbars_.end();
1152         if (d.current_work_area_) {
1153                 bool const math =
1154                         d.current_work_area_->bufferView().cursor().inMathed();
1155                 bool const table =
1156                         lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
1157                 bool const review =
1158                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
1159                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
1160                 bool const mathmacrotemplate =
1161                         lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
1162
1163                 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1164                         it->second->update(math, table, review, mathmacrotemplate);
1165         } else
1166                 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1167                         it->second->update(false, false, false, false);
1168 }
1169
1170
1171 void GuiView::setBuffer(Buffer * newBuffer)
1172 {
1173         LYXERR(Debug::DEBUG, "Setting buffer: " << newBuffer << endl);
1174         LASSERT(newBuffer, return);
1175         setBusy(true);
1176
1177         GuiWorkArea * wa = workArea(*newBuffer);
1178         if (wa == 0) {
1179                 newBuffer->masterBuffer()->updateBuffer();
1180                 wa = addWorkArea(*newBuffer);
1181         } else {
1182                 //Disconnect the old buffer...there's no new one.
1183                 disconnectBuffer();
1184         }
1185         connectBuffer(*newBuffer);
1186         connectBufferView(wa->bufferView());
1187         setCurrentWorkArea(wa);
1188
1189         setBusy(false);
1190 }
1191
1192
1193 void GuiView::connectBuffer(Buffer & buf)
1194 {
1195         buf.setGuiDelegate(this);
1196 }
1197
1198
1199 void GuiView::disconnectBuffer()
1200 {
1201         if (d.current_work_area_)
1202                 d.current_work_area_->bufferView().buffer().setGuiDelegate(0);
1203 }
1204
1205
1206 void GuiView::connectBufferView(BufferView & bv)
1207 {
1208         bv.setGuiDelegate(this);
1209 }
1210
1211
1212 void GuiView::disconnectBufferView()
1213 {
1214         if (d.current_work_area_)
1215                 d.current_work_area_->bufferView().setGuiDelegate(0);
1216 }
1217
1218
1219 void GuiView::errors(string const & error_type, bool from_master)
1220 {
1221         ErrorList & el = from_master ? 
1222                 documentBufferView()->buffer().masterBuffer()->errorList(error_type)
1223                 : documentBufferView()->buffer().errorList(error_type);
1224         string data = error_type;
1225         if (from_master)
1226                 data = "from_master|" + error_type;
1227         if (!el.empty())
1228                 showDialog("errorlist", data);
1229 }
1230
1231
1232 void GuiView::updateTocItem(string const & type, DocIterator const & dit)
1233 {
1234         d.toc_models_.updateItem(toqstr(type), dit);
1235 }
1236
1237
1238 void GuiView::structureChanged()
1239 {
1240         d.toc_models_.reset(documentBufferView());
1241         // Navigator needs more than a simple update in this case. It needs to be
1242         // rebuilt.
1243         updateDialog("toc", "");
1244 }
1245
1246
1247 void GuiView::updateDialog(string const & name, string const & data)
1248 {
1249         if (!isDialogVisible(name))
1250                 return;
1251
1252         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1253         if (it == d.dialogs_.end())
1254                 return;
1255
1256         Dialog * const dialog = it->second.get();
1257         if (dialog->isVisibleView())
1258                 dialog->initialiseParams(data);
1259 }
1260
1261
1262 BufferView * GuiView::documentBufferView()
1263 {
1264         return currentMainWorkArea()
1265                 ? &currentMainWorkArea()->bufferView()
1266                 : 0;
1267 }
1268
1269
1270 BufferView const * GuiView::documentBufferView() const 
1271 {
1272         return currentMainWorkArea()
1273                 ? &currentMainWorkArea()->bufferView()
1274                 : 0;
1275 }
1276
1277
1278 BufferView * GuiView::currentBufferView()
1279 {
1280         return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1281 }
1282
1283
1284 BufferView const * GuiView::currentBufferView() const
1285 {
1286         return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1287 }
1288
1289
1290 #if (QT_VERSION >= 0x040400)
1291 static docstring saveAndDestroyBuffer(Buffer * buffer, FileName const & fname)
1292 {
1293         bool failed = true;
1294         FileName const tmp_ret = FileName::tempName("lyxauto");
1295         if (!tmp_ret.empty()) {
1296                 if (buffer->writeFile(tmp_ret))
1297                         failed = !tmp_ret.moveTo(fname);
1298         }
1299         if (failed) {
1300                 // failed to write/rename tmp_ret so try writing direct
1301                 failed = buffer->writeFile(fname);
1302         }
1303         delete buffer;
1304         return failed
1305                 ? _("Automatic save failed!")
1306                 : _("Automatic save done.");
1307 }
1308 #endif
1309
1310
1311 void GuiView::autoSave()
1312 {
1313         LYXERR(Debug::INFO, "Running autoSave()");
1314
1315         Buffer * buffer = documentBufferView()
1316                 ? &documentBufferView()->buffer() : 0;
1317         if (!buffer)
1318                 return;
1319
1320 #if (QT_VERSION >= 0x040400)
1321         QFuture<docstring> f = QtConcurrent::run(saveAndDestroyBuffer, buffer->clone(),
1322                 buffer->getAutosaveFilename());
1323         d.autosave_watcher_.setFuture(f);
1324 #else
1325         buffer->autoSave();
1326 #endif
1327 }
1328
1329
1330 void GuiView::resetAutosaveTimers()
1331 {
1332         if (lyxrc.autosave)
1333                 d.autosave_timeout_.restart();
1334 }
1335
1336
1337 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1338 {
1339         bool enable = true;
1340         Buffer * buf = currentBufferView()
1341                 ? &currentBufferView()->buffer() : 0;
1342         Buffer * doc_buffer = documentBufferView()
1343                 ? &(documentBufferView()->buffer()) : 0;
1344
1345         // Check whether we need a buffer
1346         if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
1347                 // no, exit directly
1348                 flag.message(from_utf8(N_("Command not allowed with"
1349                                     "out any document open")));
1350                 flag.setEnabled(false);
1351                 return true;
1352         }
1353
1354         if (cmd.origin == FuncRequest::TOC) {
1355                 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
1356                 FuncStatus fs;
1357                 if (toc->getStatus(documentBufferView()->cursor(), cmd, fs))
1358                         flag |= fs;
1359                 else
1360                         flag.setEnabled(false);
1361                 return true;
1362         }
1363
1364         switch(cmd.action) {
1365         case LFUN_BUFFER_IMPORT:
1366                 break;
1367
1368         case LFUN_MASTER_BUFFER_UPDATE:
1369         case LFUN_MASTER_BUFFER_VIEW: 
1370                 enable = doc_buffer && doc_buffer->parent() != 0
1371                         && !d.preview_watcher_.isRunning();
1372                 break;
1373
1374         case LFUN_BUFFER_UPDATE:
1375         case LFUN_BUFFER_VIEW: {
1376                 if (!doc_buffer || d.preview_watcher_.isRunning()) {
1377                         enable = false;
1378                         break;
1379                 }
1380                 string format = to_utf8(cmd.argument());
1381                 if (cmd.argument().empty())
1382                         format = doc_buffer->getDefaultOutputFormat();
1383                 enable = doc_buffer->isExportableFormat(format);
1384                 break;
1385         }
1386
1387         case LFUN_BUFFER_RELOAD:
1388                 enable = doc_buffer && !doc_buffer->isUnnamed()
1389                         && doc_buffer->fileName().exists()
1390                         && (!doc_buffer->isClean()
1391                            || doc_buffer->isExternallyModified(Buffer::timestamp_method));
1392                 break;
1393
1394         case LFUN_BUFFER_CHILD_OPEN:
1395                 enable = doc_buffer;
1396                 break;
1397
1398         case LFUN_BUFFER_WRITE:
1399                 enable = doc_buffer && (doc_buffer->isUnnamed() || !doc_buffer->isClean());
1400                 break;
1401
1402         //FIXME: This LFUN should be moved to GuiApplication.
1403         case LFUN_BUFFER_WRITE_ALL: {
1404                 // We enable the command only if there are some modified buffers
1405                 Buffer * first = theBufferList().first();
1406                 enable = false;
1407                 if (!first)
1408                         break;
1409                 Buffer * b = first;
1410                 // We cannot use a for loop as the buffer list is a cycle.
1411                 do {
1412                         if (!b->isClean()) {
1413                                 enable = true;
1414                                 break;
1415                         }
1416                         b = theBufferList().next(b);
1417                 } while (b != first); 
1418                 break;
1419         }
1420
1421         case LFUN_BUFFER_WRITE_AS:
1422                 enable = doc_buffer;
1423                 break;
1424
1425         case LFUN_BUFFER_CLOSE:
1426                 enable = doc_buffer;
1427                 break;
1428
1429         case LFUN_BUFFER_CLOSE_ALL:
1430                 enable = theBufferList().last() != theBufferList().first();
1431                 break;
1432
1433         case LFUN_SPLIT_VIEW:
1434                 if (cmd.getArg(0) == "vertical")
1435                         enable = doc_buffer && (d.splitter_->count() == 1 ||
1436                                          d.splitter_->orientation() == Qt::Vertical);
1437                 else
1438                         enable = doc_buffer && (d.splitter_->count() == 1 ||
1439                                          d.splitter_->orientation() == Qt::Horizontal);
1440                 break;
1441
1442         case LFUN_CLOSE_TAB_GROUP:
1443                 enable = d.currentTabWorkArea();
1444                 break;
1445
1446         case LFUN_TOOLBAR_TOGGLE: {
1447                 string const name = cmd.getArg(0);
1448                 if (GuiToolbar * t = toolbar(name))
1449                         flag.setOnOff(t->isVisible());
1450                 else {
1451                         enable = false;
1452                         docstring const msg = 
1453                                 bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name));
1454                         flag.message(msg);
1455                 }
1456                 break;
1457         }
1458
1459         case LFUN_DROP_LAYOUTS_CHOICE:
1460                 enable = buf; 
1461                 break;
1462
1463         case LFUN_UI_TOGGLE:
1464                 flag.setOnOff(isFullScreen());
1465                 break;
1466
1467         case LFUN_DIALOG_DISCONNECT_INSET:
1468                 break;
1469
1470         case LFUN_DIALOG_HIDE:
1471                 // FIXME: should we check if the dialog is shown?
1472                 break;
1473
1474         case LFUN_DIALOG_TOGGLE:
1475                 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1476                 // fall through to set "enable"
1477         case LFUN_DIALOG_SHOW: {
1478                 string const name = cmd.getArg(0);
1479                 if (!doc_buffer)
1480                         enable = name == "aboutlyx"
1481                                 || name == "file" //FIXME: should be removed.
1482                                 || name == "prefs"
1483                                 || name == "texinfo"
1484                                 || name == "progress"
1485                                 || name == "compare";
1486                 else if (name == "print")
1487                         enable = doc_buffer->isExportable("dvi")
1488                                 && lyxrc.print_command != "none";
1489                 else if (name == "character" || name == "symbols") {
1490                         if (!buf || buf->isReadonly()
1491                                 || !currentBufferView()->cursor().inTexted())
1492                                 enable = false;
1493                         else {
1494                                 // FIXME we should consider passthru
1495                                 // paragraphs too.
1496                                 Inset const & in = currentBufferView()->cursor().inset();
1497                                 enable = !in.getLayout().isPassThru();
1498                         }
1499                 }
1500                 else if (name == "latexlog")
1501                         enable = FileName(doc_buffer->logName()).isReadableFile();
1502                 else if (name == "spellchecker")
1503                         enable = theSpellChecker() && !doc_buffer->isReadonly();
1504                 else if (name == "vclog")
1505                         enable = doc_buffer->lyxvc().inUse();
1506                 break;
1507         }
1508
1509         case LFUN_DIALOG_UPDATE: {
1510                 string const name = cmd.getArg(0);
1511                 if (!buf)
1512                         enable = name == "prefs";
1513                 break;
1514         }
1515
1516         case LFUN_COMMAND_EXECUTE:
1517         case LFUN_MESSAGE:
1518         case LFUN_MENU_OPEN:
1519                 // Nothing to check.
1520                 break;
1521
1522         case LFUN_COMPLETION_INLINE:
1523                 if (!d.current_work_area_
1524                     || !d.current_work_area_->completer().inlinePossible(
1525                         currentBufferView()->cursor()))
1526                     enable = false;
1527                 break;
1528
1529         case LFUN_COMPLETION_POPUP:
1530                 if (!d.current_work_area_
1531                     || !d.current_work_area_->completer().popupPossible(
1532                         currentBufferView()->cursor()))
1533                     enable = false;
1534                 break;
1535
1536         case LFUN_COMPLETION_COMPLETE:
1537                 if (!d.current_work_area_
1538                         || !d.current_work_area_->completer().inlinePossible(
1539                         currentBufferView()->cursor()))
1540                     enable = false;
1541                 break;
1542
1543         case LFUN_COMPLETION_ACCEPT:
1544                 if (!d.current_work_area_
1545                     || (!d.current_work_area_->completer().popupVisible()
1546                         && !d.current_work_area_->completer().inlineVisible()
1547                         && !d.current_work_area_->completer().completionAvailable()))
1548                         enable = false;
1549                 break;
1550
1551         case LFUN_COMPLETION_CANCEL:
1552                 if (!d.current_work_area_
1553                     || (!d.current_work_area_->completer().popupVisible()
1554                         && !d.current_work_area_->completer().inlineVisible()))
1555                         enable = false;
1556                 break;
1557
1558         case LFUN_BUFFER_ZOOM_OUT:
1559                 enable = doc_buffer && lyxrc.zoom > 10;
1560                 break;
1561
1562         case LFUN_BUFFER_ZOOM_IN:
1563                 enable = doc_buffer;
1564                 break;
1565         
1566         case LFUN_BUFFER_NEXT:
1567         case LFUN_BUFFER_PREVIOUS:
1568                 // FIXME: should we check is there is an previous or next buffer?
1569                 break;
1570         case LFUN_BUFFER_SWITCH:
1571                 // toggle on the current buffer, but do not toggle off
1572                 // the other ones (is that a good idea?)
1573                 if (doc_buffer
1574                         && to_utf8(cmd.argument()) == doc_buffer->absFileName())
1575                         flag.setOnOff(true);
1576                 break;
1577
1578         case LFUN_VC_REGISTER:
1579                 enable = doc_buffer && !doc_buffer->lyxvc().inUse();
1580                 break;
1581         case LFUN_VC_CHECK_IN:
1582                 enable = doc_buffer && doc_buffer->lyxvc().checkInEnabled();
1583                 break;
1584         case LFUN_VC_CHECK_OUT:
1585                 enable = doc_buffer && doc_buffer->lyxvc().checkOutEnabled();
1586                 break;
1587         case LFUN_VC_LOCKING_TOGGLE:
1588                 enable = doc_buffer && !doc_buffer->isReadonly()
1589                         && doc_buffer->lyxvc().lockingToggleEnabled();
1590                 flag.setOnOff(enable && doc_buffer->lyxvc().locking());
1591                 break;
1592         case LFUN_VC_REVERT:
1593                 enable = doc_buffer && doc_buffer->lyxvc().inUse();
1594                 break;
1595         case LFUN_VC_UNDO_LAST:
1596                 enable = doc_buffer && doc_buffer->lyxvc().undoLastEnabled();
1597                 break;
1598         case LFUN_VC_REPO_UPDATE:
1599                 enable = doc_buffer && doc_buffer->lyxvc().inUse();
1600                 break;
1601         case LFUN_VC_COMMAND: {
1602                 if (cmd.argument().empty())
1603                         enable = false;
1604                 if (!doc_buffer && contains(cmd.getArg(0), 'D'))
1605                         enable = false;
1606                 break;
1607         }
1608         case LFUN_VC_COMPARE:
1609                 enable = doc_buffer && !cmd.argument().empty()
1610                          && doc_buffer->lyxvc().prepareFileRevisionEnabled();
1611                 break;
1612
1613         case LFUN_SERVER_GOTO_FILE_ROW:
1614                 break;
1615
1616         default:
1617                 return false;
1618         }
1619
1620         if (!enable)
1621                 flag.setEnabled(false);
1622
1623         return true;
1624 }
1625
1626
1627 static FileName selectTemplateFile()
1628 {
1629         FileDialog dlg(qt_("Select template file"));
1630         dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1631         dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1632
1633         FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1634                              QStringList(qt_("LyX Documents (*.lyx)")));
1635
1636         if (result.first == FileDialog::Later)
1637                 return FileName();
1638         if (result.second.isEmpty())
1639                 return FileName();
1640         return FileName(fromqstr(result.second));
1641 }
1642
1643
1644 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1645 {
1646         setBusy(true);
1647
1648         Buffer * newBuffer = checkAndLoadLyXFile(filename);
1649
1650         if (!newBuffer) {
1651                 message(_("Document not loaded."));
1652                 setBusy(false);
1653                 return 0;
1654         }
1655         
1656         setBuffer(newBuffer);
1657
1658         // scroll to the position when the file was last closed
1659         if (lyxrc.use_lastfilepos) {
1660                 LastFilePosSection::FilePos filepos =
1661                         theSession().lastFilePos().load(filename);
1662                 documentBufferView()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1663         }
1664
1665         if (tolastfiles)
1666                 theSession().lastFiles().add(filename);
1667
1668         setBusy(false);
1669         return newBuffer;
1670 }
1671
1672
1673 void GuiView::openDocument(string const & fname)
1674 {
1675         string initpath = lyxrc.document_path;
1676
1677         if (documentBufferView()) {
1678                 string const trypath = documentBufferView()->buffer().filePath();
1679                 // If directory is writeable, use this as default.
1680                 if (FileName(trypath).isDirWritable())
1681                         initpath = trypath;
1682         }
1683
1684         string filename;
1685
1686         if (fname.empty()) {
1687                 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1688                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1689                 dlg.setButton2(qt_("Examples|#E#e"),
1690                                 toqstr(addPath(package().system_support().absFilename(), "examples")));
1691
1692                 QStringList filter(qt_("LyX Documents (*.lyx)"));
1693                 filter << qt_("LyX-1.3.x Documents (*.lyx13)")
1694                         << qt_("LyX-1.4.x Documents (*.lyx14)")
1695                         << qt_("LyX-1.5.x Documents (*.lyx15)")
1696                         << qt_("LyX-1.6.x Documents (*.lyx16)");
1697                 FileDialog::Result result =
1698                         dlg.open(toqstr(initpath), filter);
1699
1700                 if (result.first == FileDialog::Later)
1701                         return;
1702
1703                 filename = fromqstr(result.second);
1704
1705                 // check selected filename
1706                 if (filename.empty()) {
1707                         message(_("Canceled."));
1708                         return;
1709                 }
1710         } else
1711                 filename = fname;
1712
1713         // get absolute path of file and add ".lyx" to the filename if
1714         // necessary. 
1715         FileName const fullname = 
1716                         fileSearch(string(), filename, "lyx", support::may_not_exist);
1717         if (!fullname.empty())
1718                 filename = fullname.absFilename();
1719
1720         if (!fullname.onlyPath().isDirectory()) {
1721                 Alert::warning(_("Invalid filename"),
1722                                 bformat(_("The directory in the given path\n%1$s\ndoes not exist."),
1723                                 from_utf8(fullname.absFilename())));
1724                 return;
1725         }
1726         // if the file doesn't exist, let the user create one
1727         if (!fullname.exists()) {
1728                 // the user specifically chose this name. Believe him.
1729                 Buffer * const b = newFile(filename, string(), true);
1730                 if (b)
1731                         setBuffer(b);
1732                 return;
1733         }
1734
1735         docstring const disp_fn = makeDisplayPath(filename);
1736         message(bformat(_("Opening document %1$s..."), disp_fn));
1737
1738         docstring str2;
1739         Buffer * buf = loadDocument(fullname);
1740         if (buf) {
1741                 buf->updateBuffer();
1742                 setBuffer(buf);
1743                 buf->errors("Parse");
1744                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1745                 if (buf->lyxvc().inUse())
1746                         str2 += " " + from_utf8(buf->lyxvc().versionString()) +
1747                                 " " + _("Version control detected.");
1748         } else {
1749                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1750         }
1751         message(str2);
1752 }
1753
1754 // FIXME: clean that
1755 static bool import(GuiView * lv, FileName const & filename,
1756         string const & format, ErrorList & errorList)
1757 {
1758         FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1759
1760         string loader_format;
1761         vector<string> loaders = theConverters().loaders();
1762         if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1763                 for (vector<string>::const_iterator it = loaders.begin();
1764                      it != loaders.end(); ++it) {
1765                         if (!theConverters().isReachable(format, *it))
1766                                 continue;
1767
1768                         string const tofile =
1769                                 support::changeExtension(filename.absFilename(),
1770                                 formats.extension(*it));
1771                         if (!theConverters().convert(0, filename, FileName(tofile),
1772                                 filename, format, *it, errorList))
1773                                 return false;
1774                         loader_format = *it;
1775                         break;
1776                 }
1777                 if (loader_format.empty()) {
1778                         frontend::Alert::error(_("Couldn't import file"),
1779                                      bformat(_("No information for importing the format %1$s."),
1780                                          formats.prettyName(format)));
1781                         return false;
1782                 }
1783         } else
1784                 loader_format = format;
1785
1786         if (loader_format == "lyx") {
1787                 Buffer * buf = lv->loadDocument(lyxfile);
1788                 if (!buf)
1789                         return false;
1790                 buf->updateBuffer();
1791                 lv->setBuffer(buf);
1792                 buf->errors("Parse");
1793         } else {
1794                 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1795                 if (!b)
1796                         return false;
1797                 lv->setBuffer(b);
1798                 bool as_paragraphs = loader_format == "textparagraph";
1799                 string filename2 = (loader_format == format) ? filename.absFilename()
1800                         : support::changeExtension(filename.absFilename(),
1801                                           formats.extension(loader_format));
1802                 lv->currentBufferView()->insertPlaintextFile(FileName(filename2),
1803                         as_paragraphs);
1804                 guiApp->setCurrentView(lv);
1805                 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1806         }
1807
1808         return true;
1809 }
1810
1811
1812 void GuiView::importDocument(string const & argument)
1813 {
1814         string format;
1815         string filename = split(argument, format, ' ');
1816
1817         LYXERR(Debug::INFO, format << " file: " << filename);
1818
1819         // need user interaction
1820         if (filename.empty()) {
1821                 string initpath = lyxrc.document_path;
1822                 if (documentBufferView()) {
1823                         string const trypath = documentBufferView()->buffer().filePath();
1824                         // If directory is writeable, use this as default.
1825                         if (FileName(trypath).isDirWritable())
1826                                 initpath = trypath;
1827                 }
1828
1829                 docstring const text = bformat(_("Select %1$s file to import"),
1830                         formats.prettyName(format));
1831
1832                 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1833                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1834                 dlg.setButton2(qt_("Examples|#E#e"),
1835                         toqstr(addPath(package().system_support().absFilename(), "examples")));
1836
1837                 docstring filter = formats.prettyName(format);
1838                 filter += " (*.";
1839                 // FIXME UNICODE
1840                 filter += from_utf8(formats.extension(format));
1841                 filter += ')';
1842
1843                 FileDialog::Result result =
1844                         dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1845
1846                 if (result.first == FileDialog::Later)
1847                         return;
1848
1849                 filename = fromqstr(result.second);
1850
1851                 // check selected filename
1852                 if (filename.empty())
1853                         message(_("Canceled."));
1854         }
1855
1856         if (filename.empty())
1857                 return;
1858
1859         // get absolute path of file
1860         FileName const fullname(support::makeAbsPath(filename));
1861
1862         FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1863
1864         // Check if the document already is open
1865         Buffer * buf = theBufferList().getBuffer(lyxfile);
1866         if (buf) {
1867                 setBuffer(buf);
1868                 if (!closeBuffer()) {
1869                         message(_("Canceled."));
1870                         return;
1871                 }
1872         }
1873
1874         docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1875
1876         // if the file exists already, and we didn't do
1877         // -i lyx thefile.lyx, warn
1878         if (lyxfile.exists() && fullname != lyxfile) {
1879
1880                 docstring text = bformat(_("The document %1$s already exists.\n\n"
1881                         "Do you want to overwrite that document?"), displaypath);
1882                 int const ret = Alert::prompt(_("Overwrite document?"),
1883                         text, 0, 1, _("&Overwrite"), _("&Cancel"));
1884
1885                 if (ret == 1) {
1886                         message(_("Canceled."));
1887                         return;
1888                 }
1889         }
1890
1891         message(bformat(_("Importing %1$s..."), displaypath));
1892         ErrorList errorList;
1893         if (import(this, fullname, format, errorList))
1894                 message(_("imported."));
1895         else
1896                 message(_("file not imported!"));
1897
1898         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1899 }
1900
1901
1902 void GuiView::newDocument(string const & filename, bool from_template)
1903 {
1904         FileName initpath(lyxrc.document_path);
1905         if (documentBufferView()) {
1906                 FileName const trypath(documentBufferView()->buffer().filePath());
1907                 // If directory is writeable, use this as default.
1908                 if (trypath.isDirWritable())
1909                         initpath = trypath;
1910         }
1911
1912         string templatefile;
1913         if (from_template) {
1914                 templatefile = selectTemplateFile().absFilename();
1915                 if (templatefile.empty())
1916                         return;
1917         }
1918         
1919         Buffer * b;
1920         if (filename.empty())
1921                 b = newUnnamedFile(initpath, to_utf8(_("newfile")), templatefile);
1922         else
1923                 b = newFile(filename, templatefile, true);
1924
1925         if (b)
1926                 setBuffer(b);
1927
1928         // If no new document could be created, it is unsure 
1929         // whether there is a valid BufferView.
1930         if (currentBufferView())
1931                 // Ensure the cursor is correctly positioned on screen.
1932                 currentBufferView()->showCursor();
1933 }
1934
1935
1936 void GuiView::insertLyXFile(docstring const & fname)
1937 {
1938         BufferView * bv = documentBufferView();
1939         if (!bv)
1940                 return;
1941
1942         // FIXME UNICODE
1943         FileName filename(to_utf8(fname));
1944         
1945         if (!filename.empty()) {
1946                 bv->insertLyXFile(filename);
1947                 return;
1948         }
1949
1950         // Launch a file browser
1951         // FIXME UNICODE
1952         string initpath = lyxrc.document_path;
1953         string const trypath = bv->buffer().filePath();
1954         // If directory is writeable, use this as default.
1955         if (FileName(trypath).isDirWritable())
1956                 initpath = trypath;
1957
1958         // FIXME UNICODE
1959         FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1960         dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1961         dlg.setButton2(qt_("Examples|#E#e"),
1962                 toqstr(addPath(package().system_support().absFilename(),
1963                 "examples")));
1964
1965         FileDialog::Result result = dlg.open(toqstr(initpath),
1966                              QStringList(qt_("LyX Documents (*.lyx)")));
1967
1968         if (result.first == FileDialog::Later)
1969                 return;
1970
1971         // FIXME UNICODE
1972         filename.set(fromqstr(result.second));
1973
1974         // check selected filename
1975         if (filename.empty()) {
1976                 // emit message signal.
1977                 message(_("Canceled."));
1978                 return;
1979         }
1980
1981         bv->insertLyXFile(filename);
1982 }
1983
1984
1985 void GuiView::insertPlaintextFile(docstring const & fname,
1986         bool asParagraph)
1987 {
1988         BufferView * bv = documentBufferView();
1989         if (!bv)
1990                 return;
1991
1992         if (!fname.empty() && !FileName::isAbsolute(to_utf8(fname))) {
1993                 message(_("Absolute filename expected."));
1994                 return;
1995         }
1996
1997         // FIXME UNICODE
1998         FileName filename(to_utf8(fname));
1999         
2000         if (!filename.empty()) {
2001                 bv->insertPlaintextFile(filename, asParagraph);
2002                 return;
2003         }
2004
2005         FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
2006                 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
2007
2008         FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
2009                 QStringList(qt_("All Files (*)")));
2010
2011         if (result.first == FileDialog::Later)
2012                 return;
2013
2014         // FIXME UNICODE
2015         filename.set(fromqstr(result.second));
2016
2017         // check selected filename
2018         if (filename.empty()) {
2019                 // emit message signal.
2020                 message(_("Canceled."));
2021                 return;
2022         }
2023
2024         bv->insertPlaintextFile(filename, asParagraph);
2025 }
2026
2027
2028 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
2029 {
2030         FileName fname = b.fileName();
2031         FileName const oldname = fname;
2032
2033         if (!newname.empty()) {
2034                 // FIXME UNICODE
2035                 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
2036         } else {
2037                 // Switch to this Buffer.
2038                 setBuffer(&b);
2039
2040                 // No argument? Ask user through dialog.
2041                 // FIXME UNICODE
2042                 FileDialog dlg(qt_("Choose a filename to save document as"),
2043                                    LFUN_BUFFER_WRITE_AS);
2044                 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
2045                 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
2046
2047                 if (!isLyXFilename(fname.absFilename()))
2048                         fname.changeExtension(".lyx");
2049
2050                 FileDialog::Result result =
2051                         dlg.save(toqstr(fname.onlyPath().absFilename()),
2052                                QStringList(qt_("LyX Documents (*.lyx)")),
2053                                      toqstr(fname.onlyFileName()));
2054
2055                 if (result.first == FileDialog::Later)
2056                         return false;
2057
2058                 fname.set(fromqstr(result.second));
2059
2060                 if (fname.empty())
2061                         return false;
2062
2063                 if (!isLyXFilename(fname.absFilename()))
2064                         fname.changeExtension(".lyx");
2065         }
2066
2067         if (FileName(fname).exists()) {
2068                 docstring const file = makeDisplayPath(fname.absFilename(), 30);
2069                 docstring text = bformat(_("The document %1$s already "
2070                                            "exists.\n\nDo you want to "
2071                                            "overwrite that document?"), 
2072                                          file);
2073                 int const ret = Alert::prompt(_("Overwrite document?"),
2074                         text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
2075                 switch (ret) {
2076                 case 0: break;
2077                 case 1: return renameBuffer(b, docstring());
2078                 case 2: return false;
2079                 }
2080         }
2081
2082         FileName oldauto = b.getAutosaveFilename();
2083
2084         // Ok, change the name of the buffer
2085         b.setFileName(fname.absFilename());
2086         b.markDirty();
2087         bool unnamed = b.isUnnamed();
2088         b.setUnnamed(false);
2089         b.saveCheckSum(fname);
2090
2091         // bring the autosave file with us, just in case.
2092         b.moveAutosaveFile(oldauto);
2093         
2094         if (!saveBuffer(b)) {
2095                 oldauto = b.getAutosaveFilename();
2096                 b.setFileName(oldname.absFilename());
2097                 b.setUnnamed(unnamed);
2098                 b.saveCheckSum(oldname);
2099                 b.moveAutosaveFile(oldauto);
2100                 return false;
2101         }
2102
2103         return true;
2104 }
2105
2106
2107 bool GuiView::saveBuffer(Buffer & b)
2108 {
2109         if (workArea(b) && workArea(b)->inDialogMode())
2110                 return true;
2111
2112         if (b.isUnnamed())
2113                 return renameBuffer(b, docstring());
2114
2115         if (b.save()) {
2116                 theSession().lastFiles().add(b.fileName());
2117                 return true;
2118         }
2119
2120         // Switch to this Buffer.
2121         setBuffer(&b);
2122
2123         // FIXME: we don't tell the user *WHY* the save failed !!
2124         docstring const file = makeDisplayPath(b.absFileName(), 30);
2125         docstring text = bformat(_("The document %1$s could not be saved.\n\n"
2126                                    "Do you want to rename the document and "
2127                                    "try again?"), file);
2128         int const ret = Alert::prompt(_("Rename and save?"),
2129                 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
2130         switch (ret) {
2131         case 0:
2132                 if (!renameBuffer(b, docstring()))
2133                         return false;
2134                 break;
2135         case 1:
2136                 break;
2137         case 2:
2138                 return false;
2139         }
2140
2141         return saveBuffer(b);
2142 }
2143
2144
2145 bool GuiView::hideWorkArea(GuiWorkArea * wa)
2146 {
2147         return closeWorkArea(wa, false);
2148 }
2149
2150
2151 bool GuiView::closeWorkArea(GuiWorkArea * wa)
2152 {
2153         Buffer & buf = wa->bufferView().buffer();
2154         return closeWorkArea(wa, !buf.parent());
2155 }
2156
2157
2158 bool GuiView::closeBuffer()
2159 {
2160         GuiWorkArea * wa = currentMainWorkArea();
2161         setCurrentWorkArea(wa);
2162         Buffer & buf = wa->bufferView().buffer();
2163         return wa && closeWorkArea(wa, !buf.parent());
2164 }
2165
2166
2167 void GuiView::writeSession() const {
2168         GuiWorkArea const * active_wa = currentMainWorkArea();
2169         for (int i = 0; i < d.splitter_->count(); ++i) {
2170                 TabWorkArea * twa = d.tabWorkArea(i);
2171                 for (int j = 0; j < twa->count(); ++j) {
2172                         GuiWorkArea * wa = static_cast<GuiWorkArea *>(twa->widget(j));
2173                         Buffer & buf = wa->bufferView().buffer();
2174                         theSession().lastOpened().add(buf.fileName(), wa == active_wa);
2175                 }
2176         }
2177 }
2178
2179
2180 bool GuiView::closeBufferAll()
2181 {
2182         // Close the workareas in all other views
2183         QList<int> const ids = guiApp->viewIds();
2184         for (int i = 0; i != ids.size(); ++i) {
2185                 if (id_ != ids[i] && !guiApp->view(ids[i]).closeWorkAreaAll())
2186                         return false;
2187         }
2188
2189         // Close our own workareas
2190         if (!closeWorkAreaAll())
2191                 return false;
2192
2193         // Now close the hidden buffers. We prevent hidden buffers from being
2194         // dirty, so we can just close them.
2195         theBufferList().closeAll();
2196         return true;
2197 }
2198
2199
2200 bool GuiView::closeWorkAreaAll()
2201 {
2202         setCurrentWorkArea(currentMainWorkArea());
2203
2204         // We might be in a situation that there is still a tabWorkArea, but
2205         // there are no tabs anymore. This can happen when we get here after a 
2206         // TabWorkArea::lastWorkAreaRemoved() signal. Therefore we count how
2207         // many TabWorkArea's have no documents anymore.
2208         int empty_twa = 0;
2209
2210         // We have to call count() each time, because it can happen that
2211         // more than one splitter will disappear in one iteration (bug 5998).
2212         for (; d.splitter_->count() > empty_twa; ) {
2213                 TabWorkArea * twa = d.tabWorkArea(empty_twa);
2214
2215                 if (twa->count() == 0)
2216                         ++empty_twa;
2217                 else {
2218                         setCurrentWorkArea(twa->currentWorkArea());
2219                         if (!closeTabWorkArea(twa))
2220                                 return false;
2221                 }
2222         }
2223         return true;
2224 }
2225
2226
2227 bool GuiView::closeWorkArea(GuiWorkArea * wa, bool close_buffer)
2228 {
2229         if (!wa)
2230                 return false;
2231
2232         Buffer & buf = wa->bufferView().buffer();
2233
2234         if (close_buffer)
2235                 return closeBuffer(buf);
2236         else {
2237                 if (!inMultiTabs(wa))
2238                         if (!saveBufferIfNeeded(buf, true))
2239                                 return false;
2240                 removeWorkArea(wa);
2241                 return true;
2242         }
2243 }
2244
2245
2246 bool GuiView::closeBuffer(Buffer & buf)
2247 {
2248         // If we are in a close_event all children will be closed in some time,
2249         // so no need to do it here. This will ensure that the children end up
2250         // in the session file in the correct order. If we close the master
2251         // buffer, we can close or release the child buffers here too.
2252         if (!closing_) {
2253                 vector<Buffer *> clist = buf.getChildren(false);
2254                 for (vector<Buffer *>::const_iterator it = clist.begin();
2255                          it != clist.end(); ++it) {
2256                         // If a child is dirty, do not close
2257                         // without user intervention
2258                         //FIXME: should we look in other tabworkareas?
2259                         Buffer * child_buf = *it;
2260                         GuiWorkArea * child_wa = workArea(*child_buf);
2261                         if (child_wa) {
2262                                 if (!closeWorkArea(child_wa, true))
2263                                         return false;
2264                         } else
2265                                 theBufferList().releaseChild(&buf, child_buf);
2266                 }
2267         }
2268         // goto bookmark to update bookmark pit.
2269         //FIXME: we should update only the bookmarks related to this buffer!
2270         LYXERR(Debug::DEBUG, "GuiView::closeBuffer()");
2271         for (size_t i = 0; i < theSession().bookmarks().size(); ++i)
2272                 guiApp->gotoBookmark(i+1, false, false);
2273
2274         if (saveBufferIfNeeded(buf, false)) {
2275                 theBufferList().release(&buf);
2276                 return true;
2277         }
2278         return false;
2279 }
2280
2281
2282 bool GuiView::closeTabWorkArea(TabWorkArea * twa)
2283 {
2284         while (twa == d.currentTabWorkArea()) {
2285                 twa->setCurrentIndex(twa->count()-1);
2286
2287                 GuiWorkArea * wa = twa->currentWorkArea();
2288                 Buffer & b = wa->bufferView().buffer();
2289
2290                 // We only want to close the buffer if the same buffer is not visible
2291                 // in another view, and if this is not a child and if we are closing
2292                 // a view (not a tabgroup).
2293                 bool const close_buffer = 
2294                         !inMultiViews(wa) && !b.parent() && closing_;
2295
2296                 if (!closeWorkArea(wa, close_buffer))
2297                         return false;
2298         }
2299         return true;
2300 }
2301
2302
2303 bool GuiView::saveBufferIfNeeded(Buffer & buf, bool hiding)
2304 {
2305         if (buf.isClean() || buf.paragraphs().empty())
2306                 return true;
2307
2308         // Switch to this Buffer.
2309         setBuffer(&buf);
2310
2311         docstring file;
2312         // FIXME: Unicode?
2313         if (buf.isUnnamed())
2314                 file = from_utf8(buf.fileName().onlyFileName());
2315         else
2316                 file = buf.fileName().displayName(30);
2317
2318         // Bring this window to top before asking questions.
2319         raise();
2320         activateWindow();
2321
2322         int ret;
2323         if (hiding && buf.isUnnamed()) {
2324                 docstring const text = bformat(_("The document %1$s has not been "
2325                                              "saved yet.\n\nDo you want to save "
2326                                              "the document?"), file);
2327                 ret = Alert::prompt(_("Save new document?"), 
2328                         text, 0, 1, _("&Save"), _("&Cancel"));
2329                 if (ret == 1)
2330                         ++ret;
2331         } else {
2332                 docstring const text = bformat(_("The document %1$s has unsaved changes."
2333                         "\n\nDo you want to save the document or discard the changes?"), file);
2334                 ret = Alert::prompt(_("Save changed document?"),
2335                         text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
2336         }
2337
2338         switch (ret) {
2339         case 0:
2340                 if (!saveBuffer(buf))
2341                         return false;
2342                 break;
2343         case 1:
2344                 // if we crash after this we could
2345                 // have no autosave file but I guess
2346                 // this is really improbable (Jug)
2347                 buf.removeAutosaveFile();
2348                 if (hiding)
2349                         // revert all changes
2350                         buf.reload();
2351                 buf.markClean();
2352                 break;
2353         case 2:
2354                 return false;
2355         }
2356         return true;
2357 }
2358
2359
2360 bool GuiView::inMultiTabs(GuiWorkArea * wa)
2361 {
2362         Buffer & buf = wa->bufferView().buffer();
2363
2364         for (int i = 0; i != d.splitter_->count(); ++i) {
2365                 GuiWorkArea * wa_ = d.tabWorkArea(i)->workArea(buf);
2366                 if (wa_ && wa_ != wa)
2367                         return true;
2368         }
2369         return inMultiViews(wa);
2370 }
2371
2372
2373 bool GuiView::inMultiViews(GuiWorkArea * wa)
2374 {
2375         QList<int> const ids = guiApp->viewIds();
2376         Buffer & buf = wa->bufferView().buffer();
2377
2378         int found_twa = 0;
2379         for (int i = 0; i != ids.size() && found_twa <= 1; ++i) {
2380                 if (id_ == ids[i])
2381                         continue;
2382                 
2383                 if (guiApp->view(ids[i]).workArea(buf))
2384                         return true;
2385         }
2386         return false;
2387 }
2388
2389
2390 void GuiView::gotoNextOrPreviousBuffer(NextOrPrevious np)
2391 {
2392         Buffer * const curbuf = documentBufferView()
2393                 ? &documentBufferView()->buffer() : 0;
2394         Buffer * nextbuf = curbuf;
2395         while (true) {
2396                 if (np == NEXTBUFFER)
2397                         nextbuf = theBufferList().next(nextbuf);
2398                 else
2399                         nextbuf = theBufferList().previous(nextbuf);
2400                 if (nextbuf == curbuf)
2401                         break;
2402                 if (nextbuf == 0) {
2403                         nextbuf = curbuf;
2404                         break;
2405                 }
2406                 if (workArea(*nextbuf))
2407                         break;
2408         }
2409         setBuffer(nextbuf);
2410 }
2411
2412
2413 /// make sure the document is saved
2414 static bool ensureBufferClean(Buffer * buffer)
2415 {
2416         LASSERT(buffer, return false);
2417         if (buffer->isClean() && !buffer->isUnnamed())
2418                 return true;
2419
2420         docstring const file = buffer->fileName().displayName(30);
2421         docstring title;
2422         docstring text;
2423         if (!buffer->isUnnamed()) {
2424                 text = bformat(_("The document %1$s has unsaved "
2425                                              "changes.\n\nDo you want to save "
2426                                              "the document?"), file);
2427                 title = _("Save changed document?");
2428                 
2429         } else {
2430                 text = bformat(_("The document %1$s has not been "
2431                                              "saved yet.\n\nDo you want to save "
2432                                              "the document?"), file);
2433                 title = _("Save new document?");
2434         }
2435         int const ret = Alert::prompt(title, text, 0, 1, _("&Save"), _("&Cancel"));
2436
2437         if (ret == 0)
2438                 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
2439
2440         return buffer->isClean() && !buffer->isUnnamed();
2441 }
2442
2443
2444 void GuiView::reloadBuffer()
2445 {
2446         Buffer * buf = &documentBufferView()->buffer();
2447         buf->reload();
2448 }
2449
2450
2451 void GuiView::checkExternallyModifiedBuffers()
2452 {
2453         BufferList::iterator bit = theBufferList().begin();
2454         BufferList::iterator const bend = theBufferList().end();
2455         for (; bit != bend; ++bit) {
2456                 if ((*bit)->fileName().exists()
2457                     && (*bit)->isExternallyModified(Buffer::checksum_method)) {
2458                         docstring text = bformat(_("Document \n%1$s\n has been externally modified."
2459                                         " Reload now? Any local changes will be lost."),
2460                                         from_utf8((*bit)->absFileName()));
2461                         int const ret = Alert::prompt(_("Reload externally changed document?"),
2462                                                 text, 0, 1, _("&Reload"), _("&Cancel"));
2463                         if (!ret)
2464                                 (*bit)->reload();
2465                 }
2466         }
2467 }
2468
2469
2470 //FIXME use a DispatchResult object to transmit messages
2471 void GuiView::dispatchVC(FuncRequest const & cmd)
2472 {
2473         // message for statusbar
2474         string msg;
2475         Buffer * buffer = documentBufferView()
2476                 ? &(documentBufferView()->buffer()) : 0;
2477
2478         switch (cmd.action) {
2479         case LFUN_VC_REGISTER:
2480                 if (!buffer || !ensureBufferClean(buffer))
2481                         break;
2482                 if (!buffer->lyxvc().inUse()) {
2483                         if (buffer->lyxvc().registrer())
2484                                 reloadBuffer();
2485                 }
2486                 break;
2487
2488         case LFUN_VC_CHECK_IN:
2489                 if (!buffer || !ensureBufferClean(buffer))
2490                         break;
2491                 if (buffer->lyxvc().inUse() && !buffer->isReadonly()) {
2492                         msg = buffer->lyxvc().checkIn();
2493                         if (!msg.empty())
2494                                 reloadBuffer();
2495                 }
2496                 break;
2497
2498         case LFUN_VC_CHECK_OUT:
2499                 if (!buffer || !ensureBufferClean(buffer))
2500                         break;
2501                 if (buffer->lyxvc().inUse()) {
2502                         msg = buffer->lyxvc().checkOut();
2503                         reloadBuffer();
2504                 }
2505                 break;
2506
2507         case LFUN_VC_LOCKING_TOGGLE:
2508                 LASSERT(buffer, return);
2509                 if (!ensureBufferClean(buffer) || buffer->isReadonly())
2510                         break;
2511                 if (buffer->lyxvc().inUse()) {
2512                         string res = buffer->lyxvc().lockingToggle();
2513                         if (res.empty()) {
2514                                 frontend::Alert::error(_("Revision control error."),
2515                                 _("Error when setting the locking property."));
2516                         } else {
2517                                 msg = res;
2518                                 reloadBuffer();
2519                         }
2520                 }
2521                 break;
2522
2523         case LFUN_VC_REVERT:
2524                 LASSERT(buffer, return);
2525                 buffer->lyxvc().revert();
2526                 reloadBuffer();
2527                 break;
2528
2529         case LFUN_VC_UNDO_LAST:
2530                 LASSERT(buffer, return);
2531                 buffer->lyxvc().undoLast();
2532                 reloadBuffer();
2533                 break;
2534
2535         case LFUN_VC_REPO_UPDATE:
2536                 LASSERT(buffer, return);
2537                 if (ensureBufferClean(buffer)) {
2538                         msg = buffer->lyxvc().repoUpdate();
2539                         checkExternallyModifiedBuffers();
2540                 }
2541                 break;
2542
2543         case LFUN_VC_COMMAND: {
2544                 string flag = cmd.getArg(0);
2545                 if (buffer && contains(flag, 'R') && !ensureBufferClean(buffer))
2546                         break;
2547                 docstring message;
2548                 if (contains(flag, 'M')) {
2549                         if (!Alert::askForText(message, _("LyX VC: Log Message")))
2550                                 break;
2551                 }
2552                 string path = cmd.getArg(1);
2553                 if (contains(path, "$$p") && buffer)
2554                         path = subst(path, "$$p", buffer->filePath());
2555                 LYXERR(Debug::LYXVC, "Directory: " << path);
2556                 FileName pp(path);
2557                 if (!pp.isReadableDirectory()) {
2558                         lyxerr << _("Directory is not accessible.") << endl;
2559                         break;
2560                 }
2561                 support::PathChanger p(pp);
2562
2563                 string command = cmd.getArg(2);
2564                 if (command.empty())
2565                         break;
2566                 if (buffer) {
2567                         command = subst(command, "$$i", buffer->absFileName());
2568                         command = subst(command, "$$p", buffer->filePath());
2569                 }
2570                 command = subst(command, "$$m", to_utf8(message));
2571                 LYXERR(Debug::LYXVC, "Command: " << command);
2572                 Systemcall one;
2573                 one.startscript(Systemcall::Wait, command);
2574
2575                 if (!buffer)
2576                         break;
2577                 if (contains(flag, 'I'))
2578                         buffer->markDirty();
2579                 if (contains(flag, 'R'))
2580                         reloadBuffer();
2581
2582                 break;
2583                 }
2584
2585         case LFUN_VC_COMPARE: {
2586
2587                 string rev1 = cmd.getArg(0);
2588                 string f1, f2;
2589
2590                 // f1
2591                 if (!buffer->lyxvc().prepareFileRevision(rev1, f1))
2592                         break;
2593
2594                 if (isStrInt(rev1) && convert<int>(rev1) <= 0) {
2595                         f2 = buffer->absFileName();
2596                 } else {
2597                         string rev2 = cmd.getArg(1);
2598                         if (rev2.empty())
2599                                 break;
2600                         // f2
2601                         if (!buffer->lyxvc().prepareFileRevision(rev2, f2))
2602                                 break;
2603                 }
2604                 // FIXME We need to call comparison feature here.
2605                 // This is quick and dirty code for testing VC.
2606                 // We need that comparison feature has some LFUN_COMPARE <FLAG> file1 file1
2607                 // where <FLAG> specifies whether we want GUI dialog or just launch
2608                 // running with defaults.
2609                 /*
2610                 FileName initpath(lyxrc.document_path);
2611                 Buffer * dest = newUnnamedFile(initpath, to_utf8(_("differences")));
2612                 CompareOptions options;
2613                 Compare * compare = new Compare(loadIfNeeded(FileName(f1)), loadIfNeeded(FileName(f2)), dest, options);
2614                 compare->start(QThread::LowPriority);
2615                 Sleep::millisec(200);
2616                 lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH, dest->absFileName()));
2617                 */
2618                 break;
2619         }
2620
2621         default:
2622                 break;
2623         }
2624
2625         if (!msg.empty())
2626                 message(from_utf8(msg));
2627 }
2628
2629
2630 void GuiView::openChildDocument(string const & fname)
2631 {
2632         LASSERT(documentBufferView(), return);
2633         Buffer & buffer = documentBufferView()->buffer();
2634         FileName const filename = support::makeAbsPath(fname, buffer.filePath());
2635         documentBufferView()->saveBookmark(false);
2636         Buffer * child = 0;
2637         bool parsed = false;
2638         if (theBufferList().exists(filename)) {
2639                 child = theBufferList().getBuffer(filename);
2640         } else {
2641                 message(bformat(_("Opening child document %1$s..."),
2642                 makeDisplayPath(filename.absFilename())));
2643                 child = loadDocument(filename, false);
2644                 parsed = true;
2645         }
2646         if (!child)
2647                 return;
2648
2649         // Set the parent name of the child document.
2650         // This makes insertion of citations and references in the child work,
2651         // when the target is in the parent or another child document.
2652         child->setParent(&buffer);
2653         child->masterBuffer()->updateBuffer();
2654         setBuffer(child);
2655         if (parsed)
2656                 child->errors("Parse");
2657 }
2658
2659
2660 bool GuiView::goToFileRow(string const & argument)
2661 {
2662         string file_name;
2663         int row;
2664         size_t i = argument.find_last_of(' ');
2665         if (i != string::npos) {
2666                 file_name = os::internal_path(trim(argument.substr(0, i)));
2667                 istringstream is(argument.substr(i + 1));
2668                 is >> row;
2669                 if (is.fail())
2670                         i = string::npos;
2671         }
2672         if (i == string::npos) {
2673                 LYXERR0("Wrong argument: " << argument);
2674                 return false;
2675         }
2676         Buffer * buf = 0;
2677         string const abstmp = package().temp_dir().absFilename();
2678         string const realtmp = package().temp_dir().realPath();
2679         // We have to use os::path_prefix_is() here, instead of
2680         // simply prefixIs(), because the file name comes from
2681         // an external application and may need case adjustment.
2682         if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
2683                 || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
2684                 // Needed by inverse dvi search. If it is a file
2685                 // in tmpdir, call the apropriated function.
2686                 // If tmpdir is a symlink, we may have the real
2687                 // path passed back, so we correct for that.
2688                 if (!prefixIs(file_name, abstmp))
2689                         file_name = subst(file_name, realtmp, abstmp);
2690                 buf = theBufferList().getBufferFromTmp(file_name);
2691         } else {
2692                 // Must replace extension of the file to be .lyx
2693                 // and get full path
2694                 FileName const s = fileSearch(string(),
2695                                               support::changeExtension(file_name, ".lyx"), "lyx");
2696                 // Either change buffer or load the file
2697                 if (theBufferList().exists(s))
2698                         buf = theBufferList().getBuffer(s);
2699                 else if (s.exists()) {
2700                         buf = loadDocument(s);
2701                         buf->updateBuffer();
2702                         buf->errors("Parse");
2703                 } else {
2704                         message(bformat(
2705                                         _("File does not exist: %1$s"),
2706                                         makeDisplayPath(file_name)));
2707                         return false;
2708                 }
2709         }
2710         setBuffer(buf);
2711         documentBufferView()->setCursorFromRow(row);
2712         return true;
2713 }
2714
2715
2716 #if (QT_VERSION >= 0x040400)
2717 static docstring exportAndDestroy(Buffer * buffer, string const & format)
2718 {
2719         bool const update_unincluded =
2720                                 buffer->params().maintain_unincluded_children
2721                                 && !buffer->params().getIncludedChildren().empty();
2722         bool const success = buffer->doExport(format, true, update_unincluded);
2723         delete buffer;
2724         return success
2725                 ? bformat(_("Successful export to format: %1$s"), from_utf8(format))
2726                 : bformat(_("Error exporting to format: %1$s"), from_utf8(format));
2727 }
2728
2729
2730 static docstring previewAndDestroy(Buffer * buffer, string const & format)
2731 {
2732         bool const update_unincluded =
2733                                 buffer->params().maintain_unincluded_children
2734                                 && !buffer->params().getIncludedChildren().empty();
2735         bool const success = buffer->preview(format, update_unincluded);
2736         delete buffer;
2737         return success
2738                 ? bformat(_("Successful preview of format: %1$s"), from_utf8(format))
2739                 : bformat(_("Error previewing format: %1$s"), from_utf8(format));
2740 }
2741 #endif
2742
2743
2744 void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
2745 {
2746         BufferView * bv = currentBufferView();
2747         // By default we won't need any update.
2748         dr.update(Update::None);
2749         // assume cmd will be dispatched
2750         dr.dispatched(true);
2751
2752         Buffer * doc_buffer = documentBufferView()
2753                 ? &(documentBufferView()->buffer()) : 0;
2754
2755         if (cmd.origin == FuncRequest::TOC) {
2756                 GuiToc * toc = static_cast<GuiToc*>(findOrBuild("toc", false));
2757                 // FIXME: do we need to pass a DispatchResult object here?
2758                 toc->doDispatch(bv->cursor(), cmd);
2759                 return;
2760         }
2761
2762         string const argument = to_utf8(cmd.argument());
2763
2764         switch(cmd.action) {
2765                 case LFUN_BUFFER_CHILD_OPEN:
2766                         openChildDocument(to_utf8(cmd.argument()));
2767                         break;
2768
2769                 case LFUN_BUFFER_IMPORT:
2770                         importDocument(to_utf8(cmd.argument()));
2771                         break;
2772
2773                 case LFUN_BUFFER_EXPORT: {
2774                         if (!doc_buffer)
2775                                 break;
2776                         // GCC only sees strfwd.h when building merged
2777                         if (::lyx::operator==(cmd.argument(), "custom")) {
2778                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), 
2779                                          dr);
2780                                 break;
2781                         }
2782                         if (!doc_buffer->doExport(argument, false)) {
2783                                 dr.setError(true);
2784                                 dr.setMessage(bformat(_("Error exporting to format: %1$s."),
2785                                         cmd.argument()));
2786                         }
2787                         break;
2788                 }
2789
2790                 case LFUN_BUFFER_UPDATE: {
2791                         if (!doc_buffer)
2792                                 break;
2793                         string format = argument;
2794                         if (argument.empty())
2795                                 format = doc_buffer->getDefaultOutputFormat();
2796 #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
2797                         d.progress_->clearMessages();
2798                         message(_("Exporting ..."));
2799                         QFuture<docstring> f = QtConcurrent::run(exportAndDestroy,
2800                                 doc_buffer->clone(), format);
2801                         d.setPreviewFuture(f);
2802 #else
2803                         bool const update_unincluded =
2804                                 doc_buffer->params().maintain_unincluded_children
2805                                 && !doc_buffer->params().getIncludedChildren().empty();
2806                         doc_buffer->doExport(format, true, update_unincluded);
2807 #endif
2808                         break;
2809                 }
2810                 case LFUN_BUFFER_VIEW: {
2811                         if (!doc_buffer)
2812                                 break;
2813                         string format = argument;
2814                         if (argument.empty())
2815                                 format = doc_buffer->getDefaultOutputFormat();
2816 #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
2817                         d.progress_->clearMessages();
2818                         message(_("Previewing ..."));
2819                         QFuture<docstring> f = QtConcurrent::run(previewAndDestroy,
2820                                 doc_buffer->clone(), format);
2821                         d.setPreviewFuture(f);
2822 #else
2823                         bool const update_unincluded =
2824                                 doc_buffer->params().maintain_unincluded_children
2825                                 && !doc_buffer->params().getIncludedChildren().empty();
2826                         doc_buffer->preview(format, update_unincluded);
2827 #endif
2828                         break;
2829                 }
2830                 case LFUN_MASTER_BUFFER_UPDATE: {
2831                         if (!doc_buffer)
2832                                 break;
2833                         string format = argument;
2834                         Buffer const * master = doc_buffer->masterBuffer();
2835                         if (argument.empty())
2836                                 format = master->getDefaultOutputFormat();
2837 #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
2838                         QFuture<docstring> f = QtConcurrent::run(exportAndDestroy,
2839                                 master->clone(), format);
2840                         d.setPreviewFuture(f);
2841 #else
2842                         bool const update_unincluded =
2843                                 master->params().maintain_unincluded_children
2844                                 && !master->params().getIncludedChildren().empty();
2845                         master->doExport(format, true);
2846 #endif
2847                         break;
2848                 }
2849                 case LFUN_MASTER_BUFFER_VIEW: {
2850                         string format = argument;
2851                         Buffer const * master = doc_buffer->masterBuffer();
2852                         if (argument.empty())
2853                                 format = master->getDefaultOutputFormat();
2854 #if EXPORT_in_THREAD && (QT_VERSION >= 0x040400)
2855                         QFuture<docstring> f = QtConcurrent::run(previewAndDestroy,
2856                                 master->clone(), format);
2857                         d.setPreviewFuture(f);
2858 #else
2859                         master->preview(format);
2860 #endif
2861                         break;
2862                 }
2863                 case LFUN_BUFFER_SWITCH:
2864                         if (FileName::isAbsolute(to_utf8(cmd.argument()))) {
2865                                 Buffer * buffer = 
2866                                         theBufferList().getBuffer(FileName(to_utf8(cmd.argument())));
2867                                 if (buffer)
2868                                         setBuffer(buffer);
2869                                 else {
2870                                         dr.setError(true);
2871                                         dr.setMessage(_("Document not loaded"));
2872                                 }
2873                         }
2874                         break;
2875
2876                 case LFUN_BUFFER_NEXT:
2877                         gotoNextOrPreviousBuffer(NEXTBUFFER);
2878                         break;
2879
2880                 case LFUN_BUFFER_PREVIOUS:
2881                         gotoNextOrPreviousBuffer(PREVBUFFER);
2882                         break;
2883
2884                 case LFUN_COMMAND_EXECUTE: {
2885                         bool const show_it = cmd.argument() != "off";
2886                         // FIXME: this is a hack, "minibuffer" should not be
2887                         // hardcoded.
2888                         if (GuiToolbar * t = toolbar("minibuffer")) {
2889                                 t->setVisible(show_it);
2890                                 if (show_it && t->commandBuffer())
2891                                         t->commandBuffer()->setFocus();
2892                         }
2893                         break;
2894                 }
2895                 case LFUN_DROP_LAYOUTS_CHOICE:
2896                         d.layout_->showPopup();
2897                         break;
2898
2899                 case LFUN_MENU_OPEN:
2900                         if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
2901                                 menu->exec(QCursor::pos());
2902                         break;
2903
2904                 case LFUN_FILE_INSERT:
2905                         insertLyXFile(cmd.argument());
2906                         break;
2907                 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
2908                         insertPlaintextFile(cmd.argument(), true);
2909                         break;
2910
2911                 case LFUN_FILE_INSERT_PLAINTEXT:
2912                         insertPlaintextFile(cmd.argument(), false);
2913                         break;
2914
2915                 case LFUN_BUFFER_RELOAD: {
2916                         LASSERT(doc_buffer, break);
2917                         docstring const file = makeDisplayPath(doc_buffer->absFileName(), 20);
2918                         docstring text = bformat(_("Any changes will be lost. Are you sure "
2919                                                              "you want to revert to the saved version of the document %1$s?"), file);
2920                         int const ret = Alert::prompt(_("Revert to saved document?"),
2921                                 text, 1, 1, _("&Revert"), _("&Cancel"));
2922
2923                         if (ret == 0) {
2924                                 doc_buffer->markClean();
2925                                 reloadBuffer();
2926                         }
2927                         break;
2928                 }
2929
2930                 case LFUN_BUFFER_WRITE:
2931                         LASSERT(doc_buffer, break);
2932                         saveBuffer(*doc_buffer);
2933                         break;
2934
2935                 case LFUN_BUFFER_WRITE_AS:
2936                         LASSERT(doc_buffer, break);
2937                         renameBuffer(*doc_buffer, cmd.argument());
2938                         break;
2939
2940                 case LFUN_BUFFER_WRITE_ALL: {
2941                         Buffer * first = theBufferList().first();
2942                         if (!first)
2943                                 break;
2944                         message(_("Saving all documents..."));
2945                         // We cannot use a for loop as the buffer list cycles.
2946                         Buffer * b = first;
2947                         do {
2948                                 if (!b->isClean()) {
2949                                         saveBuffer(*b);
2950                                         LYXERR(Debug::ACTION, "Saved " << b->absFileName());
2951                                 }
2952                                 b = theBufferList().next(b);
2953                         } while (b != first); 
2954                         dr.setMessage(_("All documents saved."));
2955                         break;
2956                 }
2957
2958                 case LFUN_BUFFER_CLOSE:
2959                         closeBuffer();
2960                         break;
2961
2962                 case LFUN_BUFFER_CLOSE_ALL:
2963                         closeBufferAll();
2964                         break;
2965
2966                 case LFUN_TOOLBAR_TOGGLE: {
2967                         string const name = cmd.getArg(0);
2968                         if (GuiToolbar * t = toolbar(name))
2969                                 t->toggle();
2970                         break;
2971                 }
2972
2973                 case LFUN_DIALOG_UPDATE: {
2974                         string const name = to_utf8(cmd.argument());
2975                         if (currentBufferView()) {
2976                                 Inset * inset = currentBufferView()->editedInset(name);
2977                                 // Can only update a dialog connected to an existing inset
2978                                 if (!inset)
2979                                         break;
2980                                 // FIXME: get rid of this indirection; GuiView ask the inset
2981                                 // if he is kind enough to update itself...
2982                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
2983                                 //FIXME: pass DispatchResult here?
2984                                 inset->dispatch(currentBufferView()->cursor(), fr);
2985                         } else if (name == "paragraph") {
2986                                 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
2987                         } else if (name == "prefs" || name == "document") {
2988                                 updateDialog(name, string());
2989                         }
2990                         break;
2991                 }
2992
2993                 case LFUN_DIALOG_TOGGLE: {
2994                         if (isDialogVisible(cmd.getArg(0)))
2995                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()), dr);
2996                         else
2997                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()), dr);
2998                         break;
2999                 }
3000
3001                 case LFUN_DIALOG_DISCONNECT_INSET:
3002                         disconnectDialog(to_utf8(cmd.argument()));
3003                         break;
3004
3005                 case LFUN_DIALOG_HIDE: {
3006                         guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
3007                         break;
3008                 }
3009
3010                 case LFUN_DIALOG_SHOW: {
3011                         string const name = cmd.getArg(0);
3012                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
3013
3014                         if (name == "character") {
3015                                 data = freefont2string();
3016                                 if (!data.empty())
3017                                         showDialog("character", data);
3018                         } else if (name == "latexlog") {
3019                                 Buffer::LogType type; 
3020                                 string const logfile = doc_buffer->logName(&type);
3021                                 switch (type) {
3022                                 case Buffer::latexlog:
3023                                         data = "latex ";
3024                                         break;
3025                                 case Buffer::buildlog:
3026                                         data = "literate ";
3027                                         break;
3028                                 }
3029                                 data += Lexer::quoteString(logfile);
3030                                 showDialog("log", data);
3031                         } else if (name == "vclog") {
3032                                 string const data = "vc " +
3033                                         Lexer::quoteString(doc_buffer->lyxvc().getLogFile());
3034                                 showDialog("log", data);
3035                         } else if (name == "symbols") {
3036                                 data = bv->cursor().getEncoding()->name();
3037                                 if (!data.empty())
3038                                         showDialog("symbols", data);
3039                         // bug 5274
3040                         } else if (name == "prefs" && isFullScreen()) {
3041                                 lfunUiToggle("fullscreen");
3042                                 showDialog("prefs", data);
3043                         } else
3044                                 showDialog(name, data);
3045                         break;
3046                 }
3047
3048                 case LFUN_MESSAGE:
3049                         dr.setMessage(cmd.argument());
3050                         break;
3051
3052                 case LFUN_UI_TOGGLE: {
3053                         string arg = cmd.getArg(0);
3054                         if (!lfunUiToggle(arg)) {
3055                                 docstring const msg = "ui-toggle " + _("%1$s unknown command!");
3056                                 dr.setMessage(bformat(msg, from_utf8(arg)));
3057                         }
3058                         // Make sure the keyboard focus stays in the work area.
3059                         setFocus();
3060                         break;
3061                 }
3062
3063                 case LFUN_SPLIT_VIEW: {
3064                         LASSERT(doc_buffer, break);
3065                         string const orientation = cmd.getArg(0);
3066                         d.splitter_->setOrientation(orientation == "vertical"
3067                                 ? Qt::Vertical : Qt::Horizontal);
3068                         TabWorkArea * twa = addTabWorkArea();
3069                         GuiWorkArea * wa = twa->addWorkArea(*doc_buffer, *this);
3070                         setCurrentWorkArea(wa);
3071                         break;
3072                 }
3073                 case LFUN_CLOSE_TAB_GROUP:
3074                         if (TabWorkArea * twa = d.currentTabWorkArea()) {
3075                                 closeTabWorkArea(twa);
3076                                 d.current_work_area_ = 0;
3077                                 twa = d.currentTabWorkArea();
3078                                 // Switch to the next GuiWorkArea in the found TabWorkArea.
3079                                 if (twa) {
3080                                         // Make sure the work area is up to date.
3081                                         setCurrentWorkArea(twa->currentWorkArea());
3082                                 } else {
3083                                         setCurrentWorkArea(0);
3084                                 }
3085                         }
3086                         break;
3087                         
3088                 case LFUN_COMPLETION_INLINE:
3089                         if (d.current_work_area_)
3090                                 d.current_work_area_->completer().showInline();
3091                         break;
3092
3093                 case LFUN_COMPLETION_POPUP:
3094                         if (d.current_work_area_)
3095                                 d.current_work_area_->completer().showPopup();
3096                         break;
3097
3098
3099                 case LFUN_COMPLETION_COMPLETE:
3100                         if (d.current_work_area_)
3101                                 d.current_work_area_->completer().tab();
3102                         break;
3103
3104                 case LFUN_COMPLETION_CANCEL:
3105                         if (d.current_work_area_) {
3106                                 if (d.current_work_area_->completer().popupVisible())
3107                                         d.current_work_area_->completer().hidePopup();
3108                                 else
3109                                         d.current_work_area_->completer().hideInline();
3110                         }
3111                         break;
3112
3113                 case LFUN_COMPLETION_ACCEPT:
3114                         if (d.current_work_area_)
3115                                 d.current_work_area_->completer().activate();
3116                         break;
3117
3118                 case LFUN_BUFFER_ZOOM_IN:
3119                 case LFUN_BUFFER_ZOOM_OUT:
3120                         if (cmd.argument().empty()) {
3121                                 if (cmd.action == LFUN_BUFFER_ZOOM_IN)
3122                                         lyxrc.zoom += 20;
3123                                 else
3124                                         lyxrc.zoom -= 20;
3125                         } else
3126                                 lyxrc.zoom += convert<int>(cmd.argument());
3127
3128                         if (lyxrc.zoom < 10)
3129                                 lyxrc.zoom = 10;
3130                                 
3131                         // The global QPixmapCache is used in GuiPainter to cache text
3132                         // painting so we must reset it.
3133                         QPixmapCache::clear();
3134                         guiApp->fontLoader().update();
3135                         lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
3136                         break;
3137
3138                 case LFUN_VC_REGISTER:
3139                 case LFUN_VC_CHECK_IN:
3140                 case LFUN_VC_CHECK_OUT:
3141                 case LFUN_VC_REPO_UPDATE:
3142                 case LFUN_VC_LOCKING_TOGGLE:
3143                 case LFUN_VC_REVERT:
3144                 case LFUN_VC_UNDO_LAST:
3145                 case LFUN_VC_COMMAND:
3146                 case LFUN_VC_COMPARE:
3147                         dispatchVC(cmd);
3148                         break;
3149
3150                 case LFUN_SERVER_GOTO_FILE_ROW:
3151                         goToFileRow(to_utf8(cmd.argument()));
3152                         break;
3153
3154                 default:
3155                         dr.dispatched(false);
3156                         break;
3157         }
3158
3159         // Part of automatic menu appearance feature.
3160         if (isFullScreen()) {
3161                 if (menuBar()->isVisible() && lyxrc.full_screen_menubar)
3162                         menuBar()->hide();
3163                 if (statusBar()->isVisible())
3164                         statusBar()->hide();
3165         }
3166
3167         return;
3168 }
3169
3170
3171 bool GuiView::lfunUiToggle(string const & ui_component)
3172 {
3173         if (ui_component == "scrollbar") {
3174                 // hide() is of no help
3175                 if (d.current_work_area_->verticalScrollBarPolicy() ==
3176                         Qt::ScrollBarAlwaysOff)
3177
3178                         d.current_work_area_->setVerticalScrollBarPolicy(
3179                                 Qt::ScrollBarAsNeeded);
3180                 else
3181                         d.current_work_area_->setVerticalScrollBarPolicy(
3182                                 Qt::ScrollBarAlwaysOff);
3183         } else if (ui_component == "statusbar") {
3184                 statusBar()->setVisible(!statusBar()->isVisible());
3185         } else if (ui_component == "menubar") {
3186                 menuBar()->setVisible(!menuBar()->isVisible());
3187         } else
3188 #if QT_VERSION >= 0x040300
3189         if (ui_component == "frame") {
3190                 int l, t, r, b;
3191                 getContentsMargins(&l, &t, &r, &b);
3192                 //are the frames in default state?
3193                 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
3194                 if (l == 0) {
3195                         setContentsMargins(-2, -2, -2, -2);
3196                 } else {
3197                         setContentsMargins(0, 0, 0, 0);
3198                 }
3199         } else
3200 #endif
3201         if (ui_component == "fullscreen") {
3202                 toggleFullScreen();
3203         } else
3204                 return false;
3205         return true;
3206 }
3207
3208
3209 void GuiView::toggleFullScreen()
3210 {
3211         if (isFullScreen()) {
3212                 for (int i = 0; i != d.splitter_->count(); ++i)
3213                         d.tabWorkArea(i)->setFullScreen(false);
3214 #if QT_VERSION >= 0x040300
3215                 setContentsMargins(0, 0, 0, 0);
3216 #endif
3217                 setWindowState(windowState() ^ Qt::WindowFullScreen);
3218                 restoreLayout();
3219                 menuBar()->show();
3220                 statusBar()->show();
3221         } else {
3222                 // bug 5274
3223                 hideDialogs("prefs", 0);
3224                 for (int i = 0; i != d.splitter_->count(); ++i)
3225                         d.tabWorkArea(i)->setFullScreen(true);
3226 #if QT_VERSION >= 0x040300
3227                 setContentsMargins(-2, -2, -2, -2);
3228 #endif
3229                 saveLayout();
3230                 setWindowState(windowState() ^ Qt::WindowFullScreen);
3231                 statusBar()->hide();
3232                 if (lyxrc.full_screen_menubar)
3233                         menuBar()->hide();
3234                 if (lyxrc.full_screen_toolbars) {
3235                         ToolbarMap::iterator end = d.toolbars_.end();
3236                         for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
3237                                 it->second->hide();
3238                 }
3239         }
3240
3241         // give dialogs like the TOC a chance to adapt
3242         updateDialogs();
3243 }
3244
3245
3246 Buffer const * GuiView::updateInset(Inset const * inset)
3247 {
3248         if (!d.current_work_area_)
3249                 return 0;
3250
3251         if (inset)
3252                 d.current_work_area_->scheduleRedraw();
3253
3254         return &d.current_work_area_->bufferView().buffer();
3255 }
3256
3257
3258 void GuiView::restartCursor()
3259 {
3260         /* When we move around, or type, it's nice to be able to see
3261          * the cursor immediately after the keypress.
3262          */
3263         if (d.current_work_area_)
3264                 d.current_work_area_->startBlinkingCursor();
3265
3266         // Take this occasion to update the other GUI elements.
3267         updateDialogs();
3268         updateStatusBar();
3269 }
3270
3271
3272 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
3273 {
3274         if (d.current_work_area_)
3275                 d.current_work_area_->completer().updateVisibility(cur, start, keep);
3276 }
3277
3278 namespace {
3279
3280 // This list should be kept in sync with the list of insets in
3281 // src/insets/Inset.cpp.  I.e., if a dialog goes with an inset, the
3282 // dialog should have the same name as the inset.
3283 // Changes should be also recorded in LFUN_DIALOG_SHOW doxygen
3284 // docs in LyXAction.cpp.
3285
3286 char const * const dialognames[] = {
3287 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
3288 "citation", "compare", "document", "errorlist", "ert", "external", "file",
3289 "findreplace", "findreplaceadv", "float", "graphics", "href", "include",
3290 "index", "index_print", "info", "listings", "label", "log", "mathdelimiter",
3291 "mathmatrix", "mathspace", "nomenclature", "nomencl_print", "note",
3292 "paragraph", "phantom", "prefs", "print", "ref", "sendto", "space",
3293 "spellchecker", "symbols", "tabular", "tabularcreate", "thesaurus", "texinfo",
3294 "toc", "view-source", "vspace", "wrap", "progress"};
3295
3296 char const * const * const end_dialognames =
3297         dialognames + (sizeof(dialognames) / sizeof(char *));
3298
3299 class cmpCStr {
3300 public:
3301         cmpCStr(char const * name) : name_(name) {}
3302         bool operator()(char const * other) {
3303                 return strcmp(other, name_) == 0;
3304         }
3305 private:
3306         char const * name_;
3307 };
3308
3309
3310 bool isValidName(string const & name)
3311 {
3312         return find_if(dialognames, end_dialognames,
3313                             cmpCStr(name.c_str())) != end_dialognames;
3314 }
3315
3316 } // namespace anon
3317
3318
3319 void GuiView::resetDialogs()
3320 {
3321         // Make sure that no LFUN uses any GuiView.
3322         guiApp->setCurrentView(0);
3323         saveLayout();
3324         menuBar()->clear();
3325         constructToolbars();
3326         guiApp->menus().fillMenuBar(menuBar(), this, false);
3327         d.layout_->updateContents(true);
3328         // Now update controls with current buffer.
3329         guiApp->setCurrentView(this);
3330         restoreLayout();
3331         restartCursor();
3332 }
3333
3334
3335 Dialog * GuiView::findOrBuild(string const & name, bool hide_it)
3336 {
3337         if (!isValidName(name))
3338                 return 0;
3339
3340         map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
3341
3342         if (it != d.dialogs_.end()) {
3343                 if (hide_it)
3344                         it->second->hideView();
3345                 return it->second.get();
3346         }
3347
3348         Dialog * dialog = build(name);
3349         d.dialogs_[name].reset(dialog);
3350         if (lyxrc.allow_geometry_session)
3351                 dialog->restoreSession();
3352         if (hide_it)
3353                 dialog->hideView();
3354         return dialog;
3355 }
3356
3357
3358 void GuiView::showDialog(string const & name, string const & data,
3359         Inset * inset)
3360 {
3361         triggerShowDialog(toqstr(name), toqstr(data), inset);
3362 }
3363
3364
3365 void GuiView::doShowDialog(QString const & qname, QString const & qdata,
3366         Inset * inset)
3367 {
3368         if (d.in_show_)
3369                 return;
3370
3371         const string name = fromqstr(qname);
3372         const string data = fromqstr(qdata);
3373
3374         d.in_show_ = true;
3375         try {
3376                 Dialog * dialog = findOrBuild(name, false);
3377                 if (dialog) {
3378                         dialog->showData(data);
3379                         if (inset && currentBufferView())
3380                                 currentBufferView()->editInset(name, inset);
3381                 }
3382         }
3383         catch (ExceptionMessage const & ex) {
3384                 d.in_show_ = false;
3385                 throw ex;
3386         }
3387         d.in_show_ = false;
3388 }
3389
3390
3391 bool GuiView::isDialogVisible(string const & name) const
3392 {
3393         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
3394         if (it == d.dialogs_.end())
3395                 return false;
3396         return it->second.get()->isVisibleView() && !it->second.get()->isClosing();
3397 }
3398
3399
3400 void GuiView::hideDialog(string const & name, Inset * inset)
3401 {
3402         map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
3403         if (it == d.dialogs_.end())
3404                 return;
3405
3406         if (inset && currentBufferView()
3407                 && inset != currentBufferView()->editedInset(name))
3408                 return;
3409
3410         Dialog * const dialog = it->second.get();
3411         if (dialog->isVisibleView())
3412                 dialog->hideView();
3413         if (currentBufferView())
3414                 currentBufferView()->editInset(name, 0);
3415 }
3416
3417
3418 void GuiView::disconnectDialog(string const & name)
3419 {
3420         if (!isValidName(name))
3421                 return;
3422         if (currentBufferView())
3423                 currentBufferView()->editInset(name, 0);
3424 }
3425
3426
3427 void GuiView::hideAll() const
3428 {
3429         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
3430         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
3431
3432         for(; it != end; ++it)
3433                 it->second->hideView();
3434 }
3435
3436
3437 void GuiView::updateDialogs()
3438 {
3439         map<string, DialogPtr>::const_iterator it  = d.dialogs_.begin();
3440         map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
3441
3442         for(; it != end; ++it) {
3443                 Dialog * dialog = it->second.get();
3444                 if (dialog) {
3445                         if (dialog->isBufferDependent() && !documentBufferView())
3446                                 hideDialog(fromqstr(dialog->name()), 0);
3447                         else if (dialog->isVisibleView())
3448                                 dialog->checkStatus();
3449                 }
3450         }
3451         updateToolbars();
3452         updateLayoutList();
3453 }
3454
3455 Dialog * createDialog(GuiView & lv, string const & name);
3456
3457 // will be replaced by a proper factory...
3458 Dialog * createGuiAbout(GuiView & lv);
3459 Dialog * createGuiBibtex(GuiView & lv);
3460 Dialog * createGuiChanges(GuiView & lv);
3461 Dialog * createGuiCharacter(GuiView & lv);
3462 Dialog * createGuiCitation(GuiView & lv);
3463 Dialog * createGuiCompare(GuiView & lv);
3464 Dialog * createGuiDelimiter(GuiView & lv);
3465 Dialog * createGuiDocument(GuiView & lv);
3466 Dialog * createGuiErrorList(GuiView & lv);
3467 Dialog * createGuiExternal(GuiView & lv);
3468 Dialog * createGuiGraphics(GuiView & lv);
3469 Dialog * createGuiInclude(GuiView & lv);
3470 Dialog * createGuiIndex(GuiView & lv);
3471 Dialog * createGuiLabel(GuiView & lv);
3472 Dialog * createGuiListings(GuiView & lv);
3473 Dialog * createGuiLog(GuiView & lv);
3474 Dialog * createGuiMathMatrix(GuiView & lv);
3475 Dialog * createGuiNomenclature(GuiView & lv);
3476 Dialog * createGuiNote(GuiView & lv);
3477 Dialog * createGuiParagraph(GuiView & lv);
3478 Dialog * createGuiPhantom(GuiView & lv);
3479 Dialog * createGuiPreferences(GuiView & lv);
3480 Dialog * createGuiPrint(GuiView & lv);
3481 Dialog * createGuiPrintindex(GuiView & lv);
3482 Dialog * createGuiPrintNomencl(GuiView & lv);
3483 Dialog * createGuiRef(GuiView & lv);
3484 Dialog * createGuiSearch(GuiView & lv);
3485 Dialog * createGuiSearchAdv(GuiView & lv);
3486 Dialog * createGuiSendTo(GuiView & lv);
3487 Dialog * createGuiShowFile(GuiView & lv);
3488 Dialog * createGuiSpellchecker(GuiView & lv);
3489 Dialog * createGuiSymbols(GuiView & lv);
3490 Dialog * createGuiTabularCreate(GuiView & lv);
3491 Dialog * createGuiTexInfo(GuiView & lv);
3492 Dialog * createGuiToc(GuiView & lv);
3493 Dialog * createGuiThesaurus(GuiView & lv);
3494 Dialog * createGuiHyperlink(GuiView & lv);
3495 Dialog * createGuiViewSource(GuiView & lv);
3496 Dialog * createGuiWrap(GuiView & lv);
3497 Dialog * createGuiProgressView(GuiView & lv);
3498
3499
3500
3501 Dialog * GuiView::build(string const & name)
3502 {
3503         LASSERT(isValidName(name), return 0);
3504
3505         Dialog * dialog = createDialog(*this, name);
3506         if (dialog)
3507                 return dialog;
3508
3509         if (name == "aboutlyx")
3510                 return createGuiAbout(*this);
3511         if (name == "bibtex")
3512                 return createGuiBibtex(*this);
3513         if (name == "changes")
3514                 return createGuiChanges(*this);
3515         if (name == "character")
3516                 return createGuiCharacter(*this);
3517         if (name == "citation")
3518                 return createGuiCitation(*this);
3519         if (name == "compare")
3520                 return createGuiCompare(*this);
3521         if (name == "document")
3522                 return createGuiDocument(*this);
3523         if (name == "errorlist")
3524                 return createGuiErrorList(*this);
3525         if (name == "external")
3526                 return createGuiExternal(*this);
3527         if (name == "file")
3528                 return createGuiShowFile(*this);
3529         if (name == "findreplace")
3530                 return createGuiSearch(*this);
3531         if (name == "findreplaceadv")
3532                 return createGuiSearchAdv(*this);
3533         if (name == "graphics")
3534                 return createGuiGraphics(*this);
3535         if (name == "href")
3536                 return createGuiHyperlink(*this);
3537         if (name == "include")
3538                 return createGuiInclude(*this);
3539         if (name == "index")
3540                 return createGuiIndex(*this);
3541         if (name == "index_print")
3542                 return createGuiPrintindex(*this);
3543         if (name == "label")
3544                 return createGuiLabel(*this);
3545         if (name == "listings")
3546                 return createGuiListings(*this);
3547         if (name == "log")
3548                 return createGuiLog(*this);
3549         if (name == "mathdelimiter")
3550                 return createGuiDelimiter(*this);
3551         if (name == "mathmatrix")
3552                 return createGuiMathMatrix(*this);
3553         if (name == "nomenclature")
3554                 return createGuiNomenclature(*this);
3555         if (name == "nomencl_print")
3556                 return createGuiPrintNomencl(*this);
3557         if (name == "note")
3558                 return createGuiNote(*this);
3559         if (name == "paragraph")
3560                 return createGuiParagraph(*this);
3561         if (name == "phantom")
3562                 return createGuiPhantom(*this);
3563         if (name == "prefs")
3564                 return createGuiPreferences(*this);
3565         if (name == "print")
3566                 return createGuiPrint(*this);
3567         if (name == "ref")
3568                 return createGuiRef(*this);
3569         if (name == "sendto")
3570                 return createGuiSendTo(*this);
3571         if (name == "spellchecker")
3572                 return createGuiSpellchecker(*this);
3573         if (name == "symbols")
3574                 return createGuiSymbols(*this);
3575         if (name == "tabularcreate")
3576                 return createGuiTabularCreate(*this);
3577         if (name == "texinfo")
3578                 return createGuiTexInfo(*this);
3579         if (name == "thesaurus")
3580                 return createGuiThesaurus(*this);
3581         if (name == "toc")
3582                 return createGuiToc(*this);
3583         if (name == "view-source")
3584                 return createGuiViewSource(*this);
3585         if (name == "wrap")
3586                 return createGuiWrap(*this);
3587         if (name == "progress")
3588                 return createGuiProgressView(*this);
3589
3590         return 0;
3591 }
3592
3593
3594 } // namespace frontend
3595 } // namespace lyx
3596
3597 #include "moc_GuiView.cpp"