3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiWorkArea.h"
22 #include "GuiKeySymbol.h"
23 #include "GuiToolbar.h"
24 #include "GuiToolbars.h"
27 #include "qt_helpers.h"
29 #include "frontends/alert.h"
31 #include "buffer_funcs.h"
33 #include "BufferList.h"
34 #include "BufferParams.h"
35 #include "BufferView.h"
36 #include "Converter.h"
38 #include "ErrorList.h"
40 #include "FuncRequest.h"
41 #include "support/gettext.h"
49 #include "Paragraph.h"
50 #include "TextClass.h"
52 #include "ToolbarBackend.h"
55 #include "support/debug.h"
56 #include "support/FileFilterList.h"
57 #include "support/FileName.h"
58 #include "support/filetools.h"
59 #include "support/ForkedCalls.h"
60 #include "support/lstrings.h"
61 #include "support/os.h"
62 #include "support/Package.h"
63 #include "support/Timeout.h"
66 #include <QApplication>
67 #include <QCloseEvent>
69 #include <QDesktopWidget>
70 #include <QDragEnterEvent>
78 #include <QPushButton>
82 #include <QStackedWidget>
89 #include <boost/assert.hpp>
90 #include <boost/bind.hpp>
92 #ifdef HAVE_SYS_TIME_H
93 # include <sys/time.h>
100 using namespace lyx::support;
107 class BackgroundWidget : public QWidget
112 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
113 /// The text to be written on top of the pixmap
114 QString const text = lyx_version ? lyx_version : qt_("unknown version");
115 splash_ = QPixmap(":/images/banner.png");
117 QPainter pain(&splash_);
118 pain.setPen(QColor(255, 255, 0));
120 // The font used to display the version info
121 font.setStyleHint(QFont::SansSerif);
122 font.setWeight(QFont::Bold);
123 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
125 pain.drawText(260, 270, text);
128 void paintEvent(QPaintEvent *)
130 int x = (width() - splash_.width()) / 2;
131 int y = (height() - splash_.height()) / 2;
133 pain.drawPixmap(x, y, splash_);
143 typedef boost::shared_ptr<Dialog> DialogPtr;
145 struct GuiView::GuiViewPrivate
148 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
151 // hardcode here the platform specific icon size
152 smallIconSize = 14; // scaling problems
153 normalIconSize = 20; // ok, default
154 bigIconSize = 26; // better for some math icons
156 splitter_ = new QSplitter;
157 bg_widget_ = new BackgroundWidget;
158 stack_widget_ = new QStackedWidget;
159 stack_widget_->addWidget(bg_widget_);
160 stack_widget_->addWidget(splitter_);
168 delete stack_widget_;
172 QMenu * toolBarPopup(GuiView * parent)
174 // FIXME: translation
175 QMenu * menu = new QMenu(parent);
176 QActionGroup * iconSizeGroup = new QActionGroup(parent);
178 QAction * smallIcons = new QAction(iconSizeGroup);
179 smallIcons->setText(qt_("Small-sized icons"));
180 smallIcons->setCheckable(true);
181 QObject::connect(smallIcons, SIGNAL(triggered()),
182 parent, SLOT(smallSizedIcons()));
183 menu->addAction(smallIcons);
185 QAction * normalIcons = new QAction(iconSizeGroup);
186 normalIcons->setText(qt_("Normal-sized icons"));
187 normalIcons->setCheckable(true);
188 QObject::connect(normalIcons, SIGNAL(triggered()),
189 parent, SLOT(normalSizedIcons()));
190 menu->addAction(normalIcons);
192 QAction * bigIcons = new QAction(iconSizeGroup);
193 bigIcons->setText(qt_("Big-sized icons"));
194 bigIcons->setCheckable(true);
195 QObject::connect(bigIcons, SIGNAL(triggered()),
196 parent, SLOT(bigSizedIcons()));
197 menu->addAction(bigIcons);
199 unsigned int cur = parent->iconSize().width();
200 if ( cur == parent->d.smallIconSize)
201 smallIcons->setChecked(true);
202 else if (cur == parent->d.normalIconSize)
203 normalIcons->setChecked(true);
204 else if (cur == parent->d.bigIconSize)
205 bigIcons->setChecked(true);
212 stack_widget_->setCurrentWidget(bg_widget_);
213 bg_widget_->setUpdatesEnabled(true);
216 TabWorkArea * tabWorkArea(int i)
218 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
221 TabWorkArea * currentTabWorkArea()
223 if (splitter_->count() == 1)
224 // The first TabWorkArea is always the first one, if any.
225 return tabWorkArea(0);
227 for (int i = 0; i != splitter_->count(); ++i) {
228 TabWorkArea * twa = tabWorkArea(i);
229 if (current_work_area_ == twa->currentWorkArea())
233 // None has the focus so we just take the first one.
234 return tabWorkArea(0);
238 GuiWorkArea * current_work_area_;
239 QSplitter * splitter_;
240 QStackedWidget * stack_widget_;
241 BackgroundWidget * bg_widget_;
243 GuiToolbars * toolbars_;
244 /// The main layout box.
246 * \warning Don't Delete! The layout box is actually owned by
247 * whichever toolbar contains it. All the GuiView class needs is a
248 * means of accessing it.
250 * FIXME: replace that with a proper model so that we are not limited
251 * to only one dialog.
253 GuiLayoutBox * layout_;
256 map<string, Inset *> open_insets_;
259 map<string, DialogPtr> dialogs_;
261 unsigned int smallIconSize;
262 unsigned int normalIconSize;
263 unsigned int bigIconSize;
265 QTimer statusbar_timer_;
266 /// auto-saving of buffers
267 Timeout autosave_timeout_;
268 /// flag against a race condition due to multiclicks, see bug #1119
273 GuiView::GuiView(int id)
274 : d(*new GuiViewPrivate), id_(id)
276 // GuiToolbars *must* be initialised before the menu bar.
277 d.toolbars_ = new GuiToolbars(*this);
279 // Fill up the menu bar.
280 guiApp->menus().fillMenuBar(this);
282 setCentralWidget(d.stack_widget_);
284 // Start autosave timer
285 if (lyxrc.autosave) {
286 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
287 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
288 d.autosave_timeout_.start();
290 connect(&d.statusbar_timer_, SIGNAL(timeout()),
291 this, SLOT(clearMessage()));
293 // Qt bug? signal lastWindowClosed does not work
294 setAttribute(Qt::WA_QuitOnClose, false);
295 setAttribute(Qt::WA_DeleteOnClose, true);
297 // assign an icon to main form. We do not do it under Qt/Mac,
298 // since the icon is provided in the application bundle.
299 setWindowIcon(QPixmap(":/images/lyx.png"));
303 setAcceptDrops(true);
305 statusBar()->setSizeGripEnabled(true);
307 // Forbid too small unresizable window because it can happen
308 // with some window manager under X11.
309 setMinimumSize(300, 200);
311 if (!lyxrc.allow_geometry_session)
312 // No session handling, default to a sane size.
313 setGeometry(50, 50, 690, 510);
315 // Now take care of session management.
317 QString const key = "view-" + QString::number(id_);
319 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
320 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
324 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
325 setGeometry(50, 50, 690, 510);
327 setIconSize(settings.value(key + "/icon_size").toSize());
337 void GuiView::setFocus()
339 if (d.current_work_area_)
340 d.current_work_area_->setFocus();
346 QMenu * GuiView::createPopupMenu()
348 return d.toolBarPopup(this);
352 void GuiView::showEvent(QShowEvent * e)
354 LYXERR(Debug::GUI, "Passed Geometry "
355 << size().height() << "x" << size().width()
356 << "+" << pos().x() << "+" << pos().y());
358 if (d.splitter_->count() == 0)
359 // No work area, switch to the background widget.
362 QMainWindow::showEvent(e);
366 void GuiView::closeEvent(QCloseEvent * close_event)
368 while (Buffer * b = buffer()) {
370 // This is a child document, just close the tab after saving
371 // but keep the file loaded.
372 if (!saveBuffer(*b)) {
373 close_event->ignore();
376 removeWorkArea(d.current_work_area_);
380 std::vector<int> const & ids = guiApp->viewIds();
381 for (int i = 0; i != ids.size(); ++i) {
384 if (guiApp->view(ids[i]).workArea(*b)) {
385 // FIXME 1: should we put an alert box here that the buffer
386 // is viewed elsewhere?
387 // FIXME 2: should we try to save this buffer in any case?
390 // This buffer is also opened in another view, so
391 // but close the associated work area nevertheless.
392 removeWorkArea(d.current_work_area_);
393 // but don't close it.
398 if (b && !closeBuffer(*b)) {
399 close_event->ignore();
404 // Make sure that no LFUN use this close to be closed View.
405 theLyXFunc().setLyXView(0);
407 // Save toolbars configuration
408 if (isFullScreen()) {
409 d.toolbars_->toggleFullScreen(!isFullScreen());
413 // Make sure the timer time out will not trigger a statusbar update.
414 d.statusbar_timer_.stop();
416 // Saving fullscreen requires additional tweaks in the toolbar code.
417 // It wouldn't also work under linux natively.
418 if (lyxrc.allow_geometry_session && !isFullScreen()) {
420 QString const key = "view-" + QString::number(id_);
422 settings.setValue(key + "/pos", pos());
423 settings.setValue(key + "/size", size());
425 settings.setValue(key + "/geometry", saveGeometry());
427 settings.setValue(key + "/icon_size", iconSize());
428 d.toolbars_->saveToolbarInfo();
429 // Now take care of all other dialogs:
430 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
431 for (; it!= d.dialogs_.end(); ++it)
432 it->second->saveSession();
435 guiApp->unregisterView(id_);
436 if (guiApp->viewCount() > 0) {
437 // Just close the window and do nothing else if this is not the
439 close_event->accept();
445 // this is the place where we leave the frontend.
446 // it is the only point at which we start quitting.
447 close_event->accept();
448 // quit the event loop
453 void GuiView::dragEnterEvent(QDragEnterEvent * event)
455 if (event->mimeData()->hasUrls())
457 /// \todo Ask lyx-devel is this is enough:
458 /// if (event->mimeData()->hasFormat("text/plain"))
459 /// event->acceptProposedAction();
463 void GuiView::dropEvent(QDropEvent* event)
465 QList<QUrl> files = event->mimeData()->urls();
469 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
470 for (int i = 0; i != files.size(); ++i) {
471 string const file = os::internal_path(fromqstr(
472 files.at(i).toLocalFile()));
474 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
479 void GuiView::message(docstring const & str)
481 if (ForkedProcess::iAmAChild())
484 statusBar()->showMessage(toqstr(str));
485 d.statusbar_timer_.stop();
486 d.statusbar_timer_.start(3000);
490 void GuiView::smallSizedIcons()
492 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
496 void GuiView::normalSizedIcons()
498 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
502 void GuiView::bigSizedIcons()
504 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
508 void GuiView::clearMessage()
512 theLyXFunc().setLyXView(this);
513 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
514 d.statusbar_timer_.stop();
518 void GuiView::updateWindowTitle(GuiWorkArea * wa)
520 if (wa != d.current_work_area_)
522 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
523 setWindowIconText(wa->windowIconText());
527 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
530 disconnectBufferView();
531 connectBufferView(wa->bufferView());
532 connectBuffer(wa->bufferView().buffer());
533 d.current_work_area_ = wa;
534 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
535 this, SLOT(updateWindowTitle(GuiWorkArea *)));
536 updateWindowTitle(wa);
539 // Buffer-dependent dialogs should be updated or
540 // hidden. This should go here because some dialogs (eg ToC)
541 // require bv_->text.
542 updateBufferDependent(true);
549 void GuiView::updateStatusBar()
551 // let the user see the explicit message
552 if (d.statusbar_timer_.isActive())
555 theLyXFunc().setLyXView(this);
556 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
560 bool GuiView::hasFocus() const
562 return qApp->activeWindow() == this;
566 bool GuiView::event(QEvent * e)
570 // Useful debug code:
571 //case QEvent::ActivationChange:
572 //case QEvent::WindowDeactivate:
573 //case QEvent::Paint:
574 //case QEvent::Enter:
575 //case QEvent::Leave:
576 //case QEvent::HoverEnter:
577 //case QEvent::HoverLeave:
578 //case QEvent::HoverMove:
579 //case QEvent::StatusTip:
580 //case QEvent::DragEnter:
581 //case QEvent::DragLeave:
585 case QEvent::WindowActivate: {
586 guiApp->setCurrentView(*this);
587 if (d.current_work_area_) {
588 BufferView & bv = d.current_work_area_->bufferView();
589 connectBufferView(bv);
590 connectBuffer(bv.buffer());
591 // The document structure, name and dialogs might have
592 // changed in another view.
593 updateBufferDependent(true);
598 setWindowTitle(qt_("LyX"));
599 setWindowIconText(qt_("LyX"));
602 return QMainWindow::event(e);
605 case QEvent::ShortcutOverride: {
606 if (d.current_work_area_)
607 // Nothing special to do.
608 return QMainWindow::event(e);
610 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
612 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
614 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
615 || ke->key() == Qt::Key_Backtab)
616 return QMainWindow::event(e);
618 // Allow processing of shortcuts that are allowed even when no Buffer
620 theLyXFunc().setLyXView(this);
622 setKeySymbol(&sym, ke);
623 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
629 return QMainWindow::event(e);
634 bool GuiView::focusNextPrevChild(bool /*next*/)
641 void GuiView::setBusy(bool busy)
643 if (d.current_work_area_) {
644 d.current_work_area_->setUpdatesEnabled(!busy);
646 d.current_work_area_->stopBlinkingCursor();
648 d.current_work_area_->startBlinkingCursor();
652 QApplication::setOverrideCursor(Qt::WaitCursor);
654 QApplication::restoreOverrideCursor();
658 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
660 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
662 if (tbinfo.flags & ToolbarInfo::TOP) {
664 addToolBarBreak(Qt::TopToolBarArea);
665 addToolBar(Qt::TopToolBarArea, toolBar);
668 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
669 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
670 #if (QT_VERSION >= 0x040202)
672 addToolBarBreak(Qt::BottomToolBarArea);
674 addToolBar(Qt::BottomToolBarArea, toolBar);
677 if (tbinfo.flags & ToolbarInfo::LEFT) {
678 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
679 #if (QT_VERSION >= 0x040202)
681 addToolBarBreak(Qt::LeftToolBarArea);
683 addToolBar(Qt::LeftToolBarArea, toolBar);
686 if (tbinfo.flags & ToolbarInfo::RIGHT) {
687 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
688 #if (QT_VERSION >= 0x040202)
690 addToolBarBreak(Qt::RightToolBarArea);
692 addToolBar(Qt::RightToolBarArea, toolBar);
695 // The following does not work so I cannot restore to exact toolbar location
697 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
698 toolBar->move(tbinfo.posx, tbinfo.posy);
705 GuiWorkArea * GuiView::workArea(Buffer & buffer)
707 if (TabWorkArea * twa = d.currentTabWorkArea())
708 return twa->workArea(buffer);
713 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
715 // Automatically create a TabWorkArea if there are none yet.
716 TabWorkArea * tab_widget = d.splitter_->count()
717 ? d.currentTabWorkArea() : addTabWorkArea();
718 return tab_widget->addWorkArea(buffer, *this);
722 TabWorkArea * GuiView::addTabWorkArea()
724 TabWorkArea * twa = new TabWorkArea;
725 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
726 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
727 d.splitter_->addWidget(twa);
728 d.stack_widget_->setCurrentWidget(d.splitter_);
733 GuiWorkArea const * GuiView::currentWorkArea() const
735 return d.current_work_area_;
739 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
743 // Changing work area can result from opening a file so
744 // update the toc in any case.
747 d.current_work_area_ = wa;
748 for (int i = 0; i != d.splitter_->count(); ++i) {
749 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
755 void GuiView::removeWorkArea(GuiWorkArea * wa)
758 if (wa == d.current_work_area_) {
760 disconnectBufferView();
761 hideBufferDependent();
762 d.current_work_area_ = 0;
765 for (int i = 0; i != d.splitter_->count(); ++i) {
766 TabWorkArea * twa = d.tabWorkArea(i);
767 if (!twa->removeWorkArea(wa))
768 // Not found in this tab group.
771 // We found and removed the GuiWorkArea.
773 // No more WorkAreas in this tab group, so delete it.
778 if (d.current_work_area_)
779 // This means that we are not closing the current GuiWorkArea;
782 // Switch to the next GuiWorkArea in the found TabWorkArea.
783 d.current_work_area_ = twa->currentWorkArea();
787 if (d.splitter_->count() == 0)
788 // No more work area, switch to the background widget.
793 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
799 void GuiView::updateLayoutList()
802 d.layout_->updateContents(false);
806 void GuiView::updateToolbars()
808 if (d.current_work_area_) {
810 d.current_work_area_->bufferView().cursor().inMathed();
812 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
814 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
815 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
816 bool const mathmacrotemplate =
817 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
819 d.toolbars_->update(math, table, review, mathmacrotemplate);
821 d.toolbars_->update(false, false, false, false);
823 // update read-only status of open dialogs.
828 Buffer * GuiView::buffer()
830 if (d.current_work_area_)
831 return &d.current_work_area_->bufferView().buffer();
836 Buffer const * GuiView::buffer() const
838 if (d.current_work_area_)
839 return &d.current_work_area_->bufferView().buffer();
844 void GuiView::setBuffer(Buffer * newBuffer)
846 BOOST_ASSERT(newBuffer);
849 GuiWorkArea * wa = workArea(*newBuffer);
851 updateLabels(*newBuffer->masterBuffer());
852 wa = addWorkArea(*newBuffer);
854 //Disconnect the old buffer...there's no new one.
857 connectBuffer(*newBuffer);
858 connectBufferView(wa->bufferView());
859 setCurrentWorkArea(wa);
865 void GuiView::connectBuffer(Buffer & buf)
867 buf.setGuiDelegate(this);
871 void GuiView::disconnectBuffer()
873 if (d.current_work_area_)
874 d.current_work_area_->bufferView().setGuiDelegate(0);
878 void GuiView::connectBufferView(BufferView & bv)
880 bv.setGuiDelegate(this);
884 void GuiView::disconnectBufferView()
886 if (d.current_work_area_)
887 d.current_work_area_->bufferView().setGuiDelegate(0);
891 void GuiView::errors(string const & error_type)
893 ErrorList & el = buffer()->errorList(error_type);
895 showDialog("errorlist", error_type);
899 void GuiView::updateDialog(string const & name, string const & data)
901 if (!isDialogVisible(name))
904 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
905 if (it == d.dialogs_.end())
908 Dialog * const dialog = it->second.get();
909 if (dialog->isVisibleView())
910 dialog->updateData(data);
914 BufferView * GuiView::view()
916 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
920 void GuiView::updateToc()
922 updateDialog("toc", "");
926 void GuiView::updateEmbeddedFiles()
928 updateDialog("embedding", "");
932 void GuiView::autoSave()
934 LYXERR(Debug::INFO, "Running autoSave()");
937 view()->buffer().autoSave();
941 void GuiView::resetAutosaveTimers()
944 d.autosave_timeout_.restart();
948 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
952 Buffer * buf = buffer();
954 /* In LyX/Mac, when a dialog is open, the menus of the
955 application can still be accessed without giving focus to
956 the main window. In this case, we want to disable the menu
957 entries that are buffer-related.
959 Note that this code is not perfect, as bug 1941 attests:
960 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
962 if (cmd.origin == FuncRequest::MENU && !hasFocus())
966 case LFUN_BUFFER_WRITE:
967 enable = buf && (buf->isUnnamed() || !buf->isClean());
970 case LFUN_BUFFER_WRITE_AS:
974 case LFUN_SPLIT_VIEW:
978 case LFUN_CLOSE_TAB_GROUP:
979 enable = d.currentTabWorkArea();
982 case LFUN_TOOLBAR_TOGGLE:
983 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
986 case LFUN_DIALOG_TOGGLE:
987 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
988 // fall through to set "enable"
989 case LFUN_DIALOG_SHOW: {
990 string const name = cmd.getArg(0);
992 enable = name == "aboutlyx"
993 || name == "file" //FIXME: should be removed.
995 || name == "texinfo";
996 else if (name == "print")
997 enable = buf->isExportable("dvi")
998 && lyxrc.print_command != "none";
999 else if (name == "character") {
1003 InsetCode ic = view()->cursor().inset().lyxCode();
1004 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1007 else if (name == "symbols") {
1008 if (!view() || view()->cursor().inMathed())
1011 InsetCode ic = view()->cursor().inset().lyxCode();
1012 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1015 else if (name == "latexlog")
1016 enable = FileName(buf->logName()).isReadableFile();
1017 else if (name == "spellchecker")
1018 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1019 enable = !buf->isReadonly();
1023 else if (name == "vclog")
1024 enable = buf->lyxvc().inUse();
1028 case LFUN_DIALOG_UPDATE: {
1029 string const name = cmd.getArg(0);
1031 enable = name == "prefs";
1035 case LFUN_INSET_APPLY: {
1040 string const name = cmd.getArg(0);
1041 Inset * inset = getOpenInset(name);
1043 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1045 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1046 // Every inset is supposed to handle this
1047 BOOST_ASSERT(false);
1051 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1052 flag |= getStatus(fr);
1054 enable = flag.enabled();
1058 case LFUN_COMPLETION_INLINE:
1059 if (!d.current_work_area_
1060 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1064 case LFUN_COMPLETION_POPUP:
1065 if (!d.current_work_area_
1066 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1070 case LFUN_COMPLETION_COMPLETE:
1071 if (!d.current_work_area_
1072 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1084 flag.enabled(false);
1090 static FileName selectTemplateFile()
1092 FileDialog dlg(_("Select template file"));
1093 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1094 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1096 FileDialog::Result result =
1097 dlg.open(from_utf8(lyxrc.template_path),
1098 FileFilterList(_("LyX Documents (*.lyx)")),
1101 if (result.first == FileDialog::Later)
1103 if (result.second.empty())
1105 return FileName(to_utf8(result.second));
1109 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1113 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1116 message(_("Document not loaded."));
1121 setBuffer(newBuffer);
1123 // scroll to the position when the file was last closed
1124 if (lyxrc.use_lastfilepos) {
1125 LastFilePosSection::FilePos filepos =
1126 LyX::ref().session().lastFilePos().load(filename);
1127 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1131 LyX::ref().session().lastFiles().add(filename);
1138 void GuiView::openDocument(string const & fname)
1140 string initpath = lyxrc.document_path;
1143 string const trypath = buffer()->filePath();
1144 // If directory is writeable, use this as default.
1145 if (FileName(trypath).isDirWritable())
1151 if (fname.empty()) {
1152 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
1153 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1154 dlg.setButton2(_("Examples|#E#e"),
1155 from_utf8(addPath(package().system_support().absFilename(), "examples")));
1157 FileDialog::Result result =
1158 dlg.open(from_utf8(initpath),
1159 FileFilterList(_("LyX Documents (*.lyx)")),
1162 if (result.first == FileDialog::Later)
1165 filename = to_utf8(result.second);
1167 // check selected filename
1168 if (filename.empty()) {
1169 message(_("Canceled."));
1175 // get absolute path of file and add ".lyx" to the filename if
1177 FileName const fullname =
1178 fileSearch(string(), filename, "lyx", support::may_not_exist);
1179 if (!fullname.empty())
1180 filename = fullname.absFilename();
1182 // if the file doesn't exist, let the user create one
1183 if (!fullname.exists()) {
1184 // the user specifically chose this name. Believe him.
1185 Buffer * const b = newFile(filename, string(), true);
1191 docstring const disp_fn = makeDisplayPath(filename);
1192 message(bformat(_("Opening document %1$s..."), disp_fn));
1195 Buffer * buf = loadDocument(fullname);
1199 buf->errors("Parse");
1200 str2 = bformat(_("Document %1$s opened."), disp_fn);
1202 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1207 // FIXME: clean that
1208 static bool import(GuiView * lv, FileName const & filename,
1209 string const & format, ErrorList & errorList)
1211 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
1213 string loader_format;
1214 vector<string> loaders = theConverters().loaders();
1215 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1216 for (vector<string>::const_iterator it = loaders.begin();
1217 it != loaders.end(); ++it) {
1218 if (!theConverters().isReachable(format, *it))
1221 string const tofile =
1222 changeExtension(filename.absFilename(),
1223 formats.extension(*it));
1224 if (!theConverters().convert(0, filename, FileName(tofile),
1225 filename, format, *it, errorList))
1227 loader_format = *it;
1230 if (loader_format.empty()) {
1231 frontend::Alert::error(_("Couldn't import file"),
1232 bformat(_("No information for importing the format %1$s."),
1233 formats.prettyName(format)));
1237 loader_format = format;
1239 if (loader_format == "lyx") {
1240 Buffer * buf = lv->loadDocument(lyxfile);
1245 buf->errors("Parse");
1247 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1251 bool as_paragraphs = loader_format == "textparagraph";
1252 string filename2 = (loader_format == format) ? filename.absFilename()
1253 : changeExtension(filename.absFilename(),
1254 formats.extension(loader_format));
1255 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1256 theLyXFunc().setLyXView(lv);
1257 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1264 void GuiView::importDocument(string const & argument)
1267 string filename = split(argument, format, ' ');
1269 LYXERR(Debug::INFO, format << " file: " << filename);
1271 // need user interaction
1272 if (filename.empty()) {
1273 string initpath = lyxrc.document_path;
1275 Buffer const * buf = buffer();
1277 string const trypath = buf->filePath();
1278 // If directory is writeable, use this as default.
1279 if (FileName(trypath).isDirWritable())
1283 docstring const text = bformat(_("Select %1$s file to import"),
1284 formats.prettyName(format));
1286 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
1287 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1288 dlg.setButton2(_("Examples|#E#e"),
1289 from_utf8(addPath(package().system_support().absFilename(), "examples")));
1291 docstring filter = formats.prettyName(format);
1294 filter += from_utf8(formats.extension(format));
1297 FileDialog::Result result =
1298 dlg.open(from_utf8(initpath),
1299 FileFilterList(filter),
1302 if (result.first == FileDialog::Later)
1305 filename = to_utf8(result.second);
1307 // check selected filename
1308 if (filename.empty())
1309 message(_("Canceled."));
1312 if (filename.empty())
1315 // get absolute path of file
1316 FileName const fullname(makeAbsPath(filename));
1318 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
1320 // Check if the document already is open
1321 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1324 if (!closeBuffer()) {
1325 message(_("Canceled."));
1330 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1332 // if the file exists already, and we didn't do
1333 // -i lyx thefile.lyx, warn
1334 if (lyxfile.exists() && fullname != lyxfile) {
1336 docstring text = bformat(_("The document %1$s already exists.\n\n"
1337 "Do you want to overwrite that document?"), displaypath);
1338 int const ret = Alert::prompt(_("Overwrite document?"),
1339 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1342 message(_("Canceled."));
1347 message(bformat(_("Importing %1$s..."), displaypath));
1348 ErrorList errorList;
1349 if (import(this, fullname, format, errorList))
1350 message(_("imported."));
1352 message(_("file not imported!"));
1354 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1358 void GuiView::newDocument(string const & filename, bool from_template)
1360 FileName initpath(lyxrc.document_path);
1361 Buffer * buf = buffer();
1363 FileName const trypath(buf->filePath());
1364 // If directory is writeable, use this as default.
1365 if (trypath.isDirWritable())
1369 string templatefile = from_template ?
1370 selectTemplateFile().absFilename() : string();
1372 if (filename.empty())
1373 b = newUnnamedFile(templatefile, initpath);
1375 b = newFile(filename, templatefile, true);
1379 // Ensure the cursor is correctly positionned on screen.
1380 view()->showCursor();
1384 void GuiView::insertLyXFile(docstring const & fname)
1386 BufferView * bv = view();
1391 FileName filename(to_utf8(fname));
1393 if (!filename.empty()) {
1394 bv->insertLyXFile(filename);
1398 // Launch a file browser
1400 string initpath = lyxrc.document_path;
1401 string const trypath = bv->buffer().filePath();
1402 // If directory is writeable, use this as default.
1403 if (FileName(trypath).isDirWritable())
1407 FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT);
1408 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1409 dlg.setButton2(_("Examples|#E#e"),
1410 from_utf8(addPath(package().system_support().absFilename(),
1413 FileDialog::Result result =
1414 dlg.open(from_utf8(initpath),
1415 FileFilterList(_("LyX Documents (*.lyx)")),
1418 if (result.first == FileDialog::Later)
1422 filename.set(to_utf8(result.second));
1424 // check selected filename
1425 if (filename.empty()) {
1426 // emit message signal.
1427 message(_("Canceled."));
1431 bv->insertLyXFile(filename);
1435 void GuiView::insertPlaintextFile(docstring const & fname,
1438 BufferView * bv = view();
1443 FileName filename(to_utf8(fname));
1445 if (!filename.empty()) {
1446 bv->insertPlaintextFile(filename, asParagraph);
1450 FileDialog dlg(_("Select file to insert"), (asParagraph ?
1451 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1453 FileDialog::Result result = dlg.open(from_utf8(bv->buffer().filePath()),
1454 FileFilterList(), docstring());
1456 if (result.first == FileDialog::Later)
1460 filename.set(to_utf8(result.second));
1462 // check selected filename
1463 if (filename.empty()) {
1464 // emit message signal.
1465 message(_("Canceled."));
1469 bv->insertPlaintextFile(filename, asParagraph);
1473 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1475 FileName fname = b.fileName();
1476 FileName const oldname = fname;
1478 if (!newname.empty()) {
1480 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1482 // Switch to this Buffer.
1485 /// No argument? Ask user through dialog.
1487 FileDialog dlg(_("Choose a filename to save document as"),
1488 LFUN_BUFFER_WRITE_AS);
1489 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1490 dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1492 if (!isLyXFilename(fname.absFilename()))
1493 fname.changeExtension(".lyx");
1495 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1497 FileDialog::Result result =
1498 dlg.save(from_utf8(fname.onlyPath().absFilename()),
1500 from_utf8(fname.onlyFileName()));
1502 if (result.first == FileDialog::Later)
1505 fname.set(to_utf8(result.second));
1510 if (!isLyXFilename(fname.absFilename()))
1511 fname.changeExtension(".lyx");
1514 if (FileName(fname).exists()) {
1515 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1516 docstring text = bformat(_("The document %1$s already "
1517 "exists.\n\nDo you want to "
1518 "overwrite that document?"),
1520 int const ret = Alert::prompt(_("Overwrite document?"),
1521 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1524 case 1: return renameBuffer(b, docstring());
1525 case 2: return false;
1529 // Ok, change the name of the buffer
1530 b.setFileName(fname.absFilename());
1532 bool unnamed = b.isUnnamed();
1533 b.setUnnamed(false);
1534 b.saveCheckSum(fname);
1536 if (!saveBuffer(b)) {
1537 b.setFileName(oldname.absFilename());
1538 b.setUnnamed(unnamed);
1539 b.saveCheckSum(oldname);
1547 bool GuiView::saveBuffer(Buffer & b)
1550 return renameBuffer(b, docstring());
1553 LyX::ref().session().lastFiles().add(b.fileName());
1557 // Switch to this Buffer.
1560 // FIXME: we don't tell the user *WHY* the save failed !!
1561 docstring const file = makeDisplayPath(b.absFileName(), 30);
1562 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1563 "Do you want to rename the document and "
1564 "try again?"), file);
1565 int const ret = Alert::prompt(_("Rename and save?"),
1566 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1569 if (!renameBuffer(b, docstring()))
1578 return saveBuffer(b);
1582 bool GuiView::closeBuffer()
1584 Buffer * buf = buffer();
1585 return buf && closeBuffer(*buf);
1589 bool GuiView::closeBuffer(Buffer & buf)
1591 // goto bookmark to update bookmark pit.
1592 //FIXME: we should update only the bookmarks related to this buffer!
1593 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1594 theLyXFunc().gotoBookmark(i+1, false, false);
1596 if (buf.isClean() || buf.paragraphs().empty()) {
1597 theBufferList().release(&buf);
1600 // Switch to this Buffer.
1605 if (buf.isUnnamed())
1606 file = from_utf8(buf.fileName().onlyFileName());
1608 file = buf.fileName().displayName(30);
1610 // Bring this window to top before asking questions.
1614 docstring const text = bformat(_("The document %1$s has unsaved changes."
1615 "\n\nDo you want to save the document or discard the changes?"), file);
1616 int const ret = Alert::prompt(_("Save changed document?"),
1617 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1621 if (!saveBuffer(buf))
1625 // if we crash after this we could
1626 // have no autosave file but I guess
1627 // this is really improbable (Jug)
1628 removeAutosaveFile(buf.absFileName());
1634 // save file names to .lyx/session
1635 // if master/slave are both open, do not save slave since it
1636 // will be automatically loaded when the master is loaded
1637 if (buf.masterBuffer() == &buf)
1638 LyX::ref().session().lastOpened().add(buf.fileName());
1640 theBufferList().release(&buf);
1645 bool GuiView::dispatch(FuncRequest const & cmd)
1647 BufferView * bv = view();
1648 // By default we won't need any update.
1650 bv->cursor().updateFlags(Update::None);
1652 switch(cmd.action) {
1653 case LFUN_FILE_OPEN:
1654 openDocument(to_utf8(cmd.argument()));
1657 case LFUN_BUFFER_IMPORT:
1658 importDocument(to_utf8(cmd.argument()));
1661 case LFUN_BUFFER_SWITCH:
1662 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1665 case LFUN_BUFFER_NEXT:
1666 setBuffer(theBufferList().next(buffer()));
1669 case LFUN_BUFFER_PREVIOUS:
1670 setBuffer(theBufferList().previous(buffer()));
1673 case LFUN_COMMAND_EXECUTE: {
1674 bool const show_it = cmd.argument() != "off";
1675 d.toolbars_->showCommandBuffer(show_it);
1678 case LFUN_DROP_LAYOUTS_CHOICE:
1680 d.layout_->showPopup();
1683 case LFUN_MENU_OPEN:
1684 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument())))
1685 menu->exec(QCursor::pos());
1688 case LFUN_FILE_INSERT:
1689 insertLyXFile(cmd.argument());
1691 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1692 insertPlaintextFile(cmd.argument(), true);
1695 case LFUN_FILE_INSERT_PLAINTEXT:
1696 insertPlaintextFile(cmd.argument(), false);
1699 case LFUN_BUFFER_WRITE:
1701 saveBuffer(bv->buffer());
1704 case LFUN_BUFFER_WRITE_AS:
1706 renameBuffer(bv->buffer(), cmd.argument());
1709 case LFUN_BUFFER_WRITE_ALL: {
1710 Buffer * first = theBufferList().first();
1713 message(_("Saving all documents..."));
1714 // We cannot use a for loop as the buffer list cycles.
1720 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1721 b = theBufferList().next(b);
1722 } while (b != first);
1723 message(_("All documents saved."));
1727 case LFUN_TOOLBAR_TOGGLE: {
1728 string const name = cmd.getArg(0);
1729 bool const allowauto = cmd.getArg(1) == "allowauto";
1730 // it is possible to get current toolbar status like this,...
1731 // but I decide to obey the order of ToolbarBackend::flags
1732 // and disregard real toolbar status.
1733 // toolbars_->saveToolbarInfo();
1735 // toggle state on/off/auto
1736 d.toolbars_->toggleToolbarState(name, allowauto);
1740 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1742 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1746 if (tbi->flags & ToolbarInfo::ON)
1748 else if (tbi->flags & ToolbarInfo::OFF)
1750 else if (tbi->flags & ToolbarInfo::AUTO)
1753 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1754 _(tbi->gui_name), state));
1758 case LFUN_DIALOG_UPDATE: {
1759 string const name = to_utf8(cmd.argument());
1760 // Can only update a dialog connected to an existing inset
1761 Inset * inset = getOpenInset(name);
1763 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1764 inset->dispatch(view()->cursor(), fr);
1765 } else if (name == "paragraph") {
1766 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1767 } else if (name == "prefs") {
1768 updateDialog(name, string());
1773 case LFUN_DIALOG_TOGGLE: {
1774 if (isDialogVisible(cmd.getArg(0)))
1775 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1777 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1781 case LFUN_DIALOG_DISCONNECT_INSET:
1782 disconnectDialog(to_utf8(cmd.argument()));
1785 case LFUN_DIALOG_HIDE: {
1788 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1792 case LFUN_DIALOG_SHOW: {
1793 string const name = cmd.getArg(0);
1794 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1796 if (name == "character") {
1797 data = freefont2string();
1799 showDialog("character", data);
1800 } else if (name == "latexlog") {
1801 Buffer::LogType type;
1802 string const logfile = buffer()->logName(&type);
1804 case Buffer::latexlog:
1807 case Buffer::buildlog:
1811 data += Lexer::quoteString(logfile);
1812 showDialog("log", data);
1813 } else if (name == "vclog") {
1814 string const data = "vc " +
1815 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1816 showDialog("log", data);
1817 } else if (name == "symbols") {
1818 data = bv->cursor().getEncoding()->name();
1820 showDialog("symbols", data);
1822 showDialog(name, data);
1826 case LFUN_INSET_APPLY: {
1827 string const name = cmd.getArg(0);
1828 Inset * inset = getOpenInset(name);
1830 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1831 inset->dispatch(view()->cursor(), fr);
1833 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1839 case LFUN_UI_TOGGLE:
1841 // Make sure the keyboard focus stays in the work area.
1845 case LFUN_COMPLETION_INLINE:
1846 if (d.current_work_area_)
1847 d.current_work_area_->completer().showInline();
1850 case LFUN_SPLIT_VIEW:
1851 if (Buffer * buf = buffer()) {
1852 string const orientation = cmd.getArg(0);
1853 d.splitter_->setOrientation(orientation == "vertical"
1854 ? Qt::Vertical : Qt::Horizontal);
1855 TabWorkArea * twa = addTabWorkArea();
1856 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1857 setCurrentWorkArea(wa);
1861 case LFUN_CLOSE_TAB_GROUP:
1862 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1864 twa = d.currentTabWorkArea();
1865 // Switch to the next GuiWorkArea in the found TabWorkArea.
1866 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1867 if (d.splitter_->count() == 0)
1868 // No more work area, switch to the background widget.
1873 case LFUN_COMPLETION_POPUP:
1874 if (d.current_work_area_)
1875 d.current_work_area_->completer().showPopup();
1879 case LFUN_COMPLETION_COMPLETE:
1880 if (d.current_work_area_)
1881 d.current_work_area_->completer().tab();
1892 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1894 string const arg = cmd.getArg(0);
1895 if (arg == "scrollbar") {
1896 // hide() is of no help
1897 if (d.current_work_area_->verticalScrollBarPolicy() ==
1898 Qt::ScrollBarAlwaysOff)
1900 d.current_work_area_->setVerticalScrollBarPolicy(
1901 Qt::ScrollBarAsNeeded);
1903 d.current_work_area_->setVerticalScrollBarPolicy(
1904 Qt::ScrollBarAlwaysOff);
1907 if (arg == "statusbar") {
1908 statusBar()->setVisible(!statusBar()->isVisible());
1911 if (arg == "menubar") {
1912 menuBar()->setVisible(!menuBar()->isVisible());
1915 #if QT_VERSION >= 0x040300
1916 if (arg == "frame") {
1918 getContentsMargins(&l, &t, &r, &b);
1919 //are the frames in default state?
1921 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1922 setContentsMargins(-2, -2, -2, -2);
1924 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1925 setContentsMargins(0, 0, 0, 0);
1930 if (arg != "fullscreen") {
1931 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1935 if (lyxrc.full_screen_toolbars)
1936 d.toolbars_->toggleFullScreen(!isFullScreen());
1938 if (isFullScreen()) {
1939 for (int i = 0; i != d.splitter_->count(); ++i)
1940 d.tabWorkArea(i)->setFullScreen(false);
1941 #if QT_VERSION >= 0x040300
1942 setContentsMargins(0, 0, 0, 0);
1946 statusBar()->show();
1948 for (int i = 0; i != d.splitter_->count(); ++i)
1949 d.tabWorkArea(i)->setFullScreen(true);
1950 #if QT_VERSION >= 0x040300
1951 setContentsMargins(-2, -2, -2, -2);
1954 statusBar()->hide();
1960 Buffer const * GuiView::updateInset(Inset const * inset)
1962 if (!d.current_work_area_)
1966 d.current_work_area_->scheduleRedraw();
1968 return &d.current_work_area_->bufferView().buffer();
1972 void GuiView::restartCursor()
1974 /* When we move around, or type, it's nice to be able to see
1975 * the cursor immediately after the keypress.
1977 if (d.current_work_area_)
1978 d.current_work_area_->startBlinkingCursor();
1980 // Take this occasion to update the other GUI elements.
1987 void GuiView::updateCompletion(bool start, bool keep)
1989 if (d.current_work_area_)
1990 d.current_work_area_->completer().updateVisibility(start, keep);
1995 // This list should be kept in sync with the list of insets in
1996 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1997 // dialog should have the same name as the inset.
1999 char const * const dialognames[] = {
2000 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2001 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
2002 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2003 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2004 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
2006 #ifdef HAVE_LIBAIKSAURUS
2010 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2012 char const * const * const end_dialognames =
2013 dialognames + (sizeof(dialognames) / sizeof(char *));
2017 cmpCStr(char const * name) : name_(name) {}
2018 bool operator()(char const * other) {
2019 return strcmp(other, name_) == 0;
2026 bool isValidName(string const & name)
2028 return find_if(dialognames, end_dialognames,
2029 cmpCStr(name.c_str())) != end_dialognames;
2035 void GuiView::resetDialogs()
2037 // Make sure that no LFUN uses any LyXView.
2038 theLyXFunc().setLyXView(0);
2039 // FIXME: the "math panels" toolbar takes an awful lot of time to
2040 // initialise so we don't do that for the time being.
2041 //d.toolbars_->init();
2042 guiApp->menus().fillMenuBar(this);
2044 d.layout_->updateContents(true);
2045 // Now update controls with current buffer.
2046 theLyXFunc().setLyXView(this);
2051 Dialog * GuiView::find_or_build(string const & name)
2053 if (!isValidName(name))
2056 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2058 if (it != d.dialogs_.end())
2059 return it->second.get();
2061 Dialog * dialog = build(name);
2062 d.dialogs_[name].reset(dialog);
2063 if (lyxrc.allow_geometry_session)
2064 dialog->restoreSession();
2069 void GuiView::showDialog(string const & name, string const & data,
2076 Dialog * dialog = find_or_build(name);
2078 dialog->showData(data);
2080 d.open_insets_[name] = inset;
2086 bool GuiView::isDialogVisible(string const & name) const
2088 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2089 if (it == d.dialogs_.end())
2091 return it->second.get()->isVisibleView();
2095 void GuiView::hideDialog(string const & name, Inset * inset)
2097 // Don't send the signal if we are quitting, because on MSVC it is
2098 // destructed before the cut stack in CutAndPaste.cpp, and this method
2099 // is called from some inset destructor if the cut stack is not empty
2104 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2105 if (it == d.dialogs_.end())
2108 if (inset && inset != getOpenInset(name))
2111 Dialog * const dialog = it->second.get();
2112 if (dialog->isVisibleView())
2114 d.open_insets_[name] = 0;
2118 void GuiView::disconnectDialog(string const & name)
2120 if (!isValidName(name))
2123 if (d.open_insets_.find(name) != d.open_insets_.end())
2124 d.open_insets_[name] = 0;
2128 Inset * GuiView::getOpenInset(string const & name) const
2130 if (!isValidName(name))
2133 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2134 return it == d.open_insets_.end() ? 0 : it->second;
2138 void GuiView::hideAll() const
2140 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2141 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2143 for(; it != end; ++it)
2144 it->second->hideView();
2148 void GuiView::hideBufferDependent() const
2150 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2151 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2153 for(; it != end; ++it) {
2154 Dialog * dialog = it->second.get();
2155 if (dialog->isBufferDependent())
2161 void GuiView::updateBufferDependent(bool switched) const
2163 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2164 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2166 for(; it != end; ++it) {
2167 Dialog * dialog = it->second.get();
2168 if (!dialog->isVisibleView())
2170 if (switched && dialog->isBufferDependent()) {
2171 if (dialog->initialiseParams(""))
2172 dialog->updateView();
2176 // A bit clunky, but the dialog will request
2177 // that the kernel provides it with the necessary
2179 dialog->updateDialog();
2185 void GuiView::checkStatus()
2187 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2188 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2190 for(; it != end; ++it) {
2191 Dialog * const dialog = it->second.get();
2192 if (dialog && dialog->isVisibleView())
2193 dialog->checkStatus();
2199 // will be replaced by a proper factory...
2200 Dialog * createGuiAbout(GuiView & lv);
2201 Dialog * createGuiBibitem(GuiView & lv);
2202 Dialog * createGuiBibtex(GuiView & lv);
2203 Dialog * createGuiBox(GuiView & lv);
2204 Dialog * createGuiBranch(GuiView & lv);
2205 Dialog * createGuiChanges(GuiView & lv);
2206 Dialog * createGuiCharacter(GuiView & lv);
2207 Dialog * createGuiCitation(GuiView & lv);
2208 Dialog * createGuiDelimiter(GuiView & lv);
2209 Dialog * createGuiDocument(GuiView & lv);
2210 Dialog * createGuiErrorList(GuiView & lv);
2211 Dialog * createGuiERT(GuiView & lv);
2212 Dialog * createGuiExternal(GuiView & lv);
2213 Dialog * createGuiFloat(GuiView & lv);
2214 Dialog * createGuiGraphics(GuiView & lv);
2215 Dialog * createGuiInclude(GuiView & lv);
2216 Dialog * createGuiLabel(GuiView & lv);
2217 Dialog * createGuiListings(GuiView & lv);
2218 Dialog * createGuiLog(GuiView & lv);
2219 Dialog * createGuiMathMatrix(GuiView & lv);
2220 Dialog * createGuiNomenclature(GuiView & lv);
2221 Dialog * createGuiNote(GuiView & lv);
2222 Dialog * createGuiParagraph(GuiView & lv);
2223 Dialog * createGuiPreferences(GuiView & lv);
2224 Dialog * createGuiPrint(GuiView & lv);
2225 Dialog * createGuiRef(GuiView & lv);
2226 Dialog * createGuiSearch(GuiView & lv);
2227 Dialog * createGuiSendTo(GuiView & lv);
2228 Dialog * createGuiShowFile(GuiView & lv);
2229 Dialog * createGuiSpellchecker(GuiView & lv);
2230 Dialog * createGuiSymbols(GuiView & lv);
2231 Dialog * createGuiTabularCreate(GuiView & lv);
2232 Dialog * createGuiTabular(GuiView & lv);
2233 Dialog * createGuiTexInfo(GuiView & lv);
2234 Dialog * createGuiToc(GuiView & lv);
2235 Dialog * createGuiThesaurus(GuiView & lv);
2236 Dialog * createGuiHyperlink(GuiView & lv);
2237 Dialog * createGuiVSpace(GuiView & lv);
2238 Dialog * createGuiViewSource(GuiView & lv);
2239 Dialog * createGuiWrap(GuiView & lv);
2242 Dialog * GuiView::build(string const & name)
2244 BOOST_ASSERT(isValidName(name));
2246 if (name == "aboutlyx")
2247 return createGuiAbout(*this);
2248 if (name == "bibitem")
2249 return createGuiBibitem(*this);
2250 if (name == "bibtex")
2251 return createGuiBibtex(*this);
2253 return createGuiBox(*this);
2254 if (name == "branch")
2255 return createGuiBranch(*this);
2256 if (name == "changes")
2257 return createGuiChanges(*this);
2258 if (name == "character")
2259 return createGuiCharacter(*this);
2260 if (name == "citation")
2261 return createGuiCitation(*this);
2262 if (name == "document")
2263 return createGuiDocument(*this);
2264 if (name == "errorlist")
2265 return createGuiErrorList(*this);
2267 return createGuiERT(*this);
2268 if (name == "external")
2269 return createGuiExternal(*this);
2271 return createGuiShowFile(*this);
2272 if (name == "findreplace")
2273 return createGuiSearch(*this);
2274 if (name == "float")
2275 return createGuiFloat(*this);
2276 if (name == "graphics")
2277 return createGuiGraphics(*this);
2278 if (name == "include")
2279 return createGuiInclude(*this);
2280 if (name == "nomenclature")
2281 return createGuiNomenclature(*this);
2282 if (name == "label")
2283 return createGuiLabel(*this);
2285 return createGuiLog(*this);
2286 if (name == "view-source")
2287 return createGuiViewSource(*this);
2288 if (name == "mathdelimiter")
2289 return createGuiDelimiter(*this);
2290 if (name == "mathmatrix")
2291 return createGuiMathMatrix(*this);
2293 return createGuiNote(*this);
2294 if (name == "paragraph")
2295 return createGuiParagraph(*this);
2296 if (name == "prefs")
2297 return createGuiPreferences(*this);
2298 if (name == "print")
2299 return createGuiPrint(*this);
2301 return createGuiRef(*this);
2302 if (name == "sendto")
2303 return createGuiSendTo(*this);
2304 if (name == "spellchecker")
2305 return createGuiSpellchecker(*this);
2306 if (name == "symbols")
2307 return createGuiSymbols(*this);
2308 if (name == "tabular")
2309 return createGuiTabular(*this);
2310 if (name == "tabularcreate")
2311 return createGuiTabularCreate(*this);
2312 if (name == "texinfo")
2313 return createGuiTexInfo(*this);
2314 #ifdef HAVE_LIBAIKSAURUS
2315 if (name == "thesaurus")
2316 return createGuiThesaurus(*this);
2319 return createGuiToc(*this);
2321 return createGuiHyperlink(*this);
2322 if (name == "vspace")
2323 return createGuiVSpace(*this);
2325 return createGuiWrap(*this);
2326 if (name == "listings")
2327 return createGuiListings(*this);
2333 } // namespace frontend
2336 #include "GuiView_moc.cpp"