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