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 // We don't want to keep the window in memory if it is closed.
294 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 close_event->accept();
440 void GuiView::dragEnterEvent(QDragEnterEvent * event)
442 if (event->mimeData()->hasUrls())
444 /// \todo Ask lyx-devel is this is enough:
445 /// if (event->mimeData()->hasFormat("text/plain"))
446 /// event->acceptProposedAction();
450 void GuiView::dropEvent(QDropEvent* event)
452 QList<QUrl> files = event->mimeData()->urls();
456 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
457 for (int i = 0; i != files.size(); ++i) {
458 string const file = os::internal_path(fromqstr(
459 files.at(i).toLocalFile()));
461 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
466 void GuiView::message(docstring const & str)
468 if (ForkedProcess::iAmAChild())
471 statusBar()->showMessage(toqstr(str));
472 d.statusbar_timer_.stop();
473 d.statusbar_timer_.start(3000);
477 void GuiView::smallSizedIcons()
479 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
483 void GuiView::normalSizedIcons()
485 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
489 void GuiView::bigSizedIcons()
491 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
495 void GuiView::clearMessage()
499 theLyXFunc().setLyXView(this);
500 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
501 d.statusbar_timer_.stop();
505 void GuiView::updateWindowTitle(GuiWorkArea * wa)
507 if (wa != d.current_work_area_)
509 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
510 setWindowIconText(wa->windowIconText());
514 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
517 disconnectBufferView();
518 connectBufferView(wa->bufferView());
519 connectBuffer(wa->bufferView().buffer());
520 d.current_work_area_ = wa;
521 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
522 this, SLOT(updateWindowTitle(GuiWorkArea *)));
523 updateWindowTitle(wa);
526 // Buffer-dependent dialogs should be updated or
527 // hidden. This should go here because some dialogs (eg ToC)
528 // require bv_->text.
529 updateBufferDependent(true);
536 void GuiView::updateStatusBar()
538 // let the user see the explicit message
539 if (d.statusbar_timer_.isActive())
542 theLyXFunc().setLyXView(this);
543 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
547 bool GuiView::hasFocus() const
549 return qApp->activeWindow() == this;
553 bool GuiView::event(QEvent * e)
557 // Useful debug code:
558 //case QEvent::ActivationChange:
559 //case QEvent::WindowDeactivate:
560 //case QEvent::Paint:
561 //case QEvent::Enter:
562 //case QEvent::Leave:
563 //case QEvent::HoverEnter:
564 //case QEvent::HoverLeave:
565 //case QEvent::HoverMove:
566 //case QEvent::StatusTip:
567 //case QEvent::DragEnter:
568 //case QEvent::DragLeave:
572 case QEvent::WindowActivate: {
573 guiApp->setCurrentView(*this);
574 if (d.current_work_area_) {
575 BufferView & bv = d.current_work_area_->bufferView();
576 connectBufferView(bv);
577 connectBuffer(bv.buffer());
578 // The document structure, name and dialogs might have
579 // changed in another view.
580 updateBufferDependent(true);
585 setWindowTitle(qt_("LyX"));
586 setWindowIconText(qt_("LyX"));
589 return QMainWindow::event(e);
592 case QEvent::ShortcutOverride: {
593 if (d.current_work_area_)
594 // Nothing special to do.
595 return QMainWindow::event(e);
597 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
599 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
601 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
602 || ke->key() == Qt::Key_Backtab)
603 return QMainWindow::event(e);
605 // Allow processing of shortcuts that are allowed even when no Buffer
607 theLyXFunc().setLyXView(this);
609 setKeySymbol(&sym, ke);
610 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
616 return QMainWindow::event(e);
621 bool GuiView::focusNextPrevChild(bool /*next*/)
628 void GuiView::setBusy(bool busy)
630 if (d.current_work_area_) {
631 d.current_work_area_->setUpdatesEnabled(!busy);
633 d.current_work_area_->stopBlinkingCursor();
635 d.current_work_area_->startBlinkingCursor();
639 QApplication::setOverrideCursor(Qt::WaitCursor);
641 QApplication::restoreOverrideCursor();
645 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
647 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
649 if (tbinfo.flags & ToolbarInfo::TOP) {
651 addToolBarBreak(Qt::TopToolBarArea);
652 addToolBar(Qt::TopToolBarArea, toolBar);
655 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
656 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
657 #if (QT_VERSION >= 0x040202)
659 addToolBarBreak(Qt::BottomToolBarArea);
661 addToolBar(Qt::BottomToolBarArea, toolBar);
664 if (tbinfo.flags & ToolbarInfo::LEFT) {
665 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
666 #if (QT_VERSION >= 0x040202)
668 addToolBarBreak(Qt::LeftToolBarArea);
670 addToolBar(Qt::LeftToolBarArea, toolBar);
673 if (tbinfo.flags & ToolbarInfo::RIGHT) {
674 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
675 #if (QT_VERSION >= 0x040202)
677 addToolBarBreak(Qt::RightToolBarArea);
679 addToolBar(Qt::RightToolBarArea, toolBar);
682 // The following does not work so I cannot restore to exact toolbar location
684 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
685 toolBar->move(tbinfo.posx, tbinfo.posy);
692 GuiWorkArea * GuiView::workArea(Buffer & buffer)
694 if (TabWorkArea * twa = d.currentTabWorkArea())
695 return twa->workArea(buffer);
700 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
702 // Automatically create a TabWorkArea if there are none yet.
703 TabWorkArea * tab_widget = d.splitter_->count()
704 ? d.currentTabWorkArea() : addTabWorkArea();
705 return tab_widget->addWorkArea(buffer, *this);
709 TabWorkArea * GuiView::addTabWorkArea()
711 TabWorkArea * twa = new TabWorkArea;
712 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
713 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
714 d.splitter_->addWidget(twa);
715 d.stack_widget_->setCurrentWidget(d.splitter_);
720 GuiWorkArea const * GuiView::currentWorkArea() const
722 return d.current_work_area_;
726 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
730 // Changing work area can result from opening a file so
731 // update the toc in any case.
734 d.current_work_area_ = wa;
735 for (int i = 0; i != d.splitter_->count(); ++i) {
736 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
742 void GuiView::removeWorkArea(GuiWorkArea * wa)
745 if (wa == d.current_work_area_) {
747 disconnectBufferView();
748 hideBufferDependent();
749 d.current_work_area_ = 0;
752 for (int i = 0; i != d.splitter_->count(); ++i) {
753 TabWorkArea * twa = d.tabWorkArea(i);
754 if (!twa->removeWorkArea(wa))
755 // Not found in this tab group.
758 // We found and removed the GuiWorkArea.
760 // No more WorkAreas in this tab group, so delete it.
765 if (d.current_work_area_)
766 // This means that we are not closing the current GuiWorkArea;
769 // Switch to the next GuiWorkArea in the found TabWorkArea.
770 d.current_work_area_ = twa->currentWorkArea();
774 if (d.splitter_->count() == 0)
775 // No more work area, switch to the background widget.
780 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
786 void GuiView::updateLayoutList()
789 d.layout_->updateContents(false);
793 void GuiView::updateToolbars()
795 if (d.current_work_area_) {
797 d.current_work_area_->bufferView().cursor().inMathed();
799 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
801 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
802 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
803 bool const mathmacrotemplate =
804 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
806 d.toolbars_->update(math, table, review, mathmacrotemplate);
808 d.toolbars_->update(false, false, false, false);
810 // update read-only status of open dialogs.
815 Buffer * GuiView::buffer()
817 if (d.current_work_area_)
818 return &d.current_work_area_->bufferView().buffer();
823 Buffer const * GuiView::buffer() const
825 if (d.current_work_area_)
826 return &d.current_work_area_->bufferView().buffer();
831 void GuiView::setBuffer(Buffer * newBuffer)
833 BOOST_ASSERT(newBuffer);
836 GuiWorkArea * wa = workArea(*newBuffer);
838 updateLabels(*newBuffer->masterBuffer());
839 wa = addWorkArea(*newBuffer);
841 //Disconnect the old buffer...there's no new one.
844 connectBuffer(*newBuffer);
845 connectBufferView(wa->bufferView());
846 setCurrentWorkArea(wa);
852 void GuiView::connectBuffer(Buffer & buf)
854 buf.setGuiDelegate(this);
858 void GuiView::disconnectBuffer()
860 if (d.current_work_area_)
861 d.current_work_area_->bufferView().setGuiDelegate(0);
865 void GuiView::connectBufferView(BufferView & bv)
867 bv.setGuiDelegate(this);
871 void GuiView::disconnectBufferView()
873 if (d.current_work_area_)
874 d.current_work_area_->bufferView().setGuiDelegate(0);
878 void GuiView::errors(string const & error_type)
880 ErrorList & el = buffer()->errorList(error_type);
882 showDialog("errorlist", error_type);
886 void GuiView::updateDialog(string const & name, string const & data)
888 if (!isDialogVisible(name))
891 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
892 if (it == d.dialogs_.end())
895 Dialog * const dialog = it->second.get();
896 if (dialog->isVisibleView())
897 dialog->updateData(data);
901 BufferView * GuiView::view()
903 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
907 void GuiView::updateToc()
909 updateDialog("toc", "");
913 void GuiView::updateEmbeddedFiles()
915 updateDialog("embedding", "");
919 void GuiView::autoSave()
921 LYXERR(Debug::INFO, "Running autoSave()");
924 view()->buffer().autoSave();
928 void GuiView::resetAutosaveTimers()
931 d.autosave_timeout_.restart();
935 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
939 Buffer * buf = buffer();
941 /* In LyX/Mac, when a dialog is open, the menus of the
942 application can still be accessed without giving focus to
943 the main window. In this case, we want to disable the menu
944 entries that are buffer-related.
946 Note that this code is not perfect, as bug 1941 attests:
947 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
949 if (cmd.origin == FuncRequest::MENU && !hasFocus())
953 case LFUN_BUFFER_WRITE:
954 enable = buf && (buf->isUnnamed() || !buf->isClean());
957 case LFUN_BUFFER_WRITE_AS:
961 case LFUN_SPLIT_VIEW:
965 case LFUN_CLOSE_TAB_GROUP:
966 enable = d.currentTabWorkArea();
969 case LFUN_TOOLBAR_TOGGLE:
970 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
973 case LFUN_DIALOG_TOGGLE:
974 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
975 // fall through to set "enable"
976 case LFUN_DIALOG_SHOW: {
977 string const name = cmd.getArg(0);
979 enable = name == "aboutlyx"
980 || name == "file" //FIXME: should be removed.
982 || name == "texinfo";
983 else if (name == "print")
984 enable = buf->isExportable("dvi")
985 && lyxrc.print_command != "none";
986 else if (name == "character") {
990 InsetCode ic = view()->cursor().inset().lyxCode();
991 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
994 else if (name == "symbols") {
995 if (!view() || view()->cursor().inMathed())
998 InsetCode ic = view()->cursor().inset().lyxCode();
999 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1002 else if (name == "latexlog")
1003 enable = FileName(buf->logName()).isReadableFile();
1004 else if (name == "spellchecker")
1005 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1006 enable = !buf->isReadonly();
1010 else if (name == "vclog")
1011 enable = buf->lyxvc().inUse();
1015 case LFUN_DIALOG_UPDATE: {
1016 string const name = cmd.getArg(0);
1018 enable = name == "prefs";
1022 case LFUN_INSET_APPLY: {
1027 string const name = cmd.getArg(0);
1028 Inset * inset = getOpenInset(name);
1030 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1032 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1033 // Every inset is supposed to handle this
1034 BOOST_ASSERT(false);
1038 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1039 flag |= getStatus(fr);
1041 enable = flag.enabled();
1045 case LFUN_COMPLETION_INLINE:
1046 if (!d.current_work_area_
1047 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1051 case LFUN_COMPLETION_POPUP:
1052 if (!d.current_work_area_
1053 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1057 case LFUN_COMPLETION_COMPLETE:
1058 if (!d.current_work_area_
1059 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1071 flag.enabled(false);
1077 static FileName selectTemplateFile()
1079 FileDialog dlg(_("Select template file"));
1080 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1081 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1083 FileDialog::Result result =
1084 dlg.open(from_utf8(lyxrc.template_path),
1085 FileFilterList(_("LyX Documents (*.lyx)")),
1088 if (result.first == FileDialog::Later)
1090 if (result.second.empty())
1092 return FileName(to_utf8(result.second));
1096 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1100 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1103 message(_("Document not loaded."));
1108 setBuffer(newBuffer);
1110 // scroll to the position when the file was last closed
1111 if (lyxrc.use_lastfilepos) {
1112 LastFilePosSection::FilePos filepos =
1113 LyX::ref().session().lastFilePos().load(filename);
1114 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1118 LyX::ref().session().lastFiles().add(filename);
1125 void GuiView::openDocument(string const & fname)
1127 string initpath = lyxrc.document_path;
1130 string const trypath = buffer()->filePath();
1131 // If directory is writeable, use this as default.
1132 if (FileName(trypath).isDirWritable())
1138 if (fname.empty()) {
1139 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
1140 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1141 dlg.setButton2(_("Examples|#E#e"),
1142 from_utf8(addPath(package().system_support().absFilename(), "examples")));
1144 FileDialog::Result result =
1145 dlg.open(from_utf8(initpath),
1146 FileFilterList(_("LyX Documents (*.lyx)")),
1149 if (result.first == FileDialog::Later)
1152 filename = to_utf8(result.second);
1154 // check selected filename
1155 if (filename.empty()) {
1156 message(_("Canceled."));
1162 // get absolute path of file and add ".lyx" to the filename if
1164 FileName const fullname =
1165 fileSearch(string(), filename, "lyx", support::may_not_exist);
1166 if (!fullname.empty())
1167 filename = fullname.absFilename();
1169 // if the file doesn't exist, let the user create one
1170 if (!fullname.exists()) {
1171 // the user specifically chose this name. Believe him.
1172 Buffer * const b = newFile(filename, string(), true);
1178 docstring const disp_fn = makeDisplayPath(filename);
1179 message(bformat(_("Opening document %1$s..."), disp_fn));
1182 Buffer * buf = loadDocument(fullname);
1186 buf->errors("Parse");
1187 str2 = bformat(_("Document %1$s opened."), disp_fn);
1189 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1194 // FIXME: clean that
1195 static bool import(GuiView * lv, FileName const & filename,
1196 string const & format, ErrorList & errorList)
1198 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
1200 string loader_format;
1201 vector<string> loaders = theConverters().loaders();
1202 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1203 for (vector<string>::const_iterator it = loaders.begin();
1204 it != loaders.end(); ++it) {
1205 if (!theConverters().isReachable(format, *it))
1208 string const tofile =
1209 changeExtension(filename.absFilename(),
1210 formats.extension(*it));
1211 if (!theConverters().convert(0, filename, FileName(tofile),
1212 filename, format, *it, errorList))
1214 loader_format = *it;
1217 if (loader_format.empty()) {
1218 frontend::Alert::error(_("Couldn't import file"),
1219 bformat(_("No information for importing the format %1$s."),
1220 formats.prettyName(format)));
1224 loader_format = format;
1226 if (loader_format == "lyx") {
1227 Buffer * buf = lv->loadDocument(lyxfile);
1232 buf->errors("Parse");
1234 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1238 bool as_paragraphs = loader_format == "textparagraph";
1239 string filename2 = (loader_format == format) ? filename.absFilename()
1240 : changeExtension(filename.absFilename(),
1241 formats.extension(loader_format));
1242 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1243 theLyXFunc().setLyXView(lv);
1244 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1251 void GuiView::importDocument(string const & argument)
1254 string filename = split(argument, format, ' ');
1256 LYXERR(Debug::INFO, format << " file: " << filename);
1258 // need user interaction
1259 if (filename.empty()) {
1260 string initpath = lyxrc.document_path;
1262 Buffer const * buf = buffer();
1264 string const trypath = buf->filePath();
1265 // If directory is writeable, use this as default.
1266 if (FileName(trypath).isDirWritable())
1270 docstring const text = bformat(_("Select %1$s file to import"),
1271 formats.prettyName(format));
1273 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
1274 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1275 dlg.setButton2(_("Examples|#E#e"),
1276 from_utf8(addPath(package().system_support().absFilename(), "examples")));
1278 docstring filter = formats.prettyName(format);
1281 filter += from_utf8(formats.extension(format));
1284 FileDialog::Result result =
1285 dlg.open(from_utf8(initpath),
1286 FileFilterList(filter),
1289 if (result.first == FileDialog::Later)
1292 filename = to_utf8(result.second);
1294 // check selected filename
1295 if (filename.empty())
1296 message(_("Canceled."));
1299 if (filename.empty())
1302 // get absolute path of file
1303 FileName const fullname(makeAbsPath(filename));
1305 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
1307 // Check if the document already is open
1308 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1311 if (!closeBuffer()) {
1312 message(_("Canceled."));
1317 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1319 // if the file exists already, and we didn't do
1320 // -i lyx thefile.lyx, warn
1321 if (lyxfile.exists() && fullname != lyxfile) {
1323 docstring text = bformat(_("The document %1$s already exists.\n\n"
1324 "Do you want to overwrite that document?"), displaypath);
1325 int const ret = Alert::prompt(_("Overwrite document?"),
1326 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1329 message(_("Canceled."));
1334 message(bformat(_("Importing %1$s..."), displaypath));
1335 ErrorList errorList;
1336 if (import(this, fullname, format, errorList))
1337 message(_("imported."));
1339 message(_("file not imported!"));
1341 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1345 void GuiView::newDocument(string const & filename, bool from_template)
1347 FileName initpath(lyxrc.document_path);
1348 Buffer * buf = buffer();
1350 FileName const trypath(buf->filePath());
1351 // If directory is writeable, use this as default.
1352 if (trypath.isDirWritable())
1356 string templatefile = from_template ?
1357 selectTemplateFile().absFilename() : string();
1359 if (filename.empty())
1360 b = newUnnamedFile(templatefile, initpath);
1362 b = newFile(filename, templatefile, true);
1366 // Ensure the cursor is correctly positionned on screen.
1367 view()->showCursor();
1371 void GuiView::insertLyXFile(docstring const & fname)
1373 BufferView * bv = view();
1378 FileName filename(to_utf8(fname));
1380 if (!filename.empty()) {
1381 bv->insertLyXFile(filename);
1385 // Launch a file browser
1387 string initpath = lyxrc.document_path;
1388 string const trypath = bv->buffer().filePath();
1389 // If directory is writeable, use this as default.
1390 if (FileName(trypath).isDirWritable())
1394 FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT);
1395 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1396 dlg.setButton2(_("Examples|#E#e"),
1397 from_utf8(addPath(package().system_support().absFilename(),
1400 FileDialog::Result result =
1401 dlg.open(from_utf8(initpath),
1402 FileFilterList(_("LyX Documents (*.lyx)")),
1405 if (result.first == FileDialog::Later)
1409 filename.set(to_utf8(result.second));
1411 // check selected filename
1412 if (filename.empty()) {
1413 // emit message signal.
1414 message(_("Canceled."));
1418 bv->insertLyXFile(filename);
1422 void GuiView::insertPlaintextFile(docstring const & fname,
1425 BufferView * bv = view();
1430 FileName filename(to_utf8(fname));
1432 if (!filename.empty()) {
1433 bv->insertPlaintextFile(filename, asParagraph);
1437 FileDialog dlg(_("Select file to insert"), (asParagraph ?
1438 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1440 FileDialog::Result result = dlg.open(from_utf8(bv->buffer().filePath()),
1441 FileFilterList(), docstring());
1443 if (result.first == FileDialog::Later)
1447 filename.set(to_utf8(result.second));
1449 // check selected filename
1450 if (filename.empty()) {
1451 // emit message signal.
1452 message(_("Canceled."));
1456 bv->insertPlaintextFile(filename, asParagraph);
1460 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1462 FileName fname = b.fileName();
1463 FileName const oldname = fname;
1465 if (!newname.empty()) {
1467 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1469 // Switch to this Buffer.
1472 /// No argument? Ask user through dialog.
1474 FileDialog dlg(_("Choose a filename to save document as"),
1475 LFUN_BUFFER_WRITE_AS);
1476 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1477 dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1479 if (!isLyXFilename(fname.absFilename()))
1480 fname.changeExtension(".lyx");
1482 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1484 FileDialog::Result result =
1485 dlg.save(from_utf8(fname.onlyPath().absFilename()),
1487 from_utf8(fname.onlyFileName()));
1489 if (result.first == FileDialog::Later)
1492 fname.set(to_utf8(result.second));
1497 if (!isLyXFilename(fname.absFilename()))
1498 fname.changeExtension(".lyx");
1501 if (FileName(fname).exists()) {
1502 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1503 docstring text = bformat(_("The document %1$s already "
1504 "exists.\n\nDo you want to "
1505 "overwrite that document?"),
1507 int const ret = Alert::prompt(_("Overwrite document?"),
1508 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1511 case 1: return renameBuffer(b, docstring());
1512 case 2: return false;
1516 // Ok, change the name of the buffer
1517 b.setFileName(fname.absFilename());
1519 bool unnamed = b.isUnnamed();
1520 b.setUnnamed(false);
1521 b.saveCheckSum(fname);
1523 if (!saveBuffer(b)) {
1524 b.setFileName(oldname.absFilename());
1525 b.setUnnamed(unnamed);
1526 b.saveCheckSum(oldname);
1534 bool GuiView::saveBuffer(Buffer & b)
1537 return renameBuffer(b, docstring());
1540 LyX::ref().session().lastFiles().add(b.fileName());
1544 // Switch to this Buffer.
1547 // FIXME: we don't tell the user *WHY* the save failed !!
1548 docstring const file = makeDisplayPath(b.absFileName(), 30);
1549 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1550 "Do you want to rename the document and "
1551 "try again?"), file);
1552 int const ret = Alert::prompt(_("Rename and save?"),
1553 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1556 if (!renameBuffer(b, docstring()))
1565 return saveBuffer(b);
1569 bool GuiView::closeBuffer()
1571 Buffer * buf = buffer();
1572 return buf && closeBuffer(*buf);
1576 bool GuiView::closeBuffer(Buffer & buf)
1578 // goto bookmark to update bookmark pit.
1579 //FIXME: we should update only the bookmarks related to this buffer!
1580 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1581 theLyXFunc().gotoBookmark(i+1, false, false);
1583 if (buf.isClean() || buf.paragraphs().empty()) {
1584 theBufferList().release(&buf);
1587 // Switch to this Buffer.
1592 if (buf.isUnnamed())
1593 file = from_utf8(buf.fileName().onlyFileName());
1595 file = buf.fileName().displayName(30);
1597 // Bring this window to top before asking questions.
1601 docstring const text = bformat(_("The document %1$s has unsaved changes."
1602 "\n\nDo you want to save the document or discard the changes?"), file);
1603 int const ret = Alert::prompt(_("Save changed document?"),
1604 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1608 if (!saveBuffer(buf))
1612 // if we crash after this we could
1613 // have no autosave file but I guess
1614 // this is really improbable (Jug)
1615 removeAutosaveFile(buf.absFileName());
1621 // save file names to .lyx/session
1622 // if master/slave are both open, do not save slave since it
1623 // will be automatically loaded when the master is loaded
1624 if (buf.masterBuffer() == &buf)
1625 LyX::ref().session().lastOpened().add(buf.fileName());
1627 theBufferList().release(&buf);
1632 bool GuiView::dispatch(FuncRequest const & cmd)
1634 BufferView * bv = view();
1635 // By default we won't need any update.
1637 bv->cursor().updateFlags(Update::None);
1639 switch(cmd.action) {
1640 case LFUN_FILE_OPEN:
1641 openDocument(to_utf8(cmd.argument()));
1644 case LFUN_BUFFER_IMPORT:
1645 importDocument(to_utf8(cmd.argument()));
1648 case LFUN_BUFFER_SWITCH:
1649 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1652 case LFUN_BUFFER_NEXT:
1653 setBuffer(theBufferList().next(buffer()));
1656 case LFUN_BUFFER_PREVIOUS:
1657 setBuffer(theBufferList().previous(buffer()));
1660 case LFUN_COMMAND_EXECUTE: {
1661 bool const show_it = cmd.argument() != "off";
1662 d.toolbars_->showCommandBuffer(show_it);
1665 case LFUN_DROP_LAYOUTS_CHOICE:
1667 d.layout_->showPopup();
1670 case LFUN_MENU_OPEN:
1671 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument())))
1672 menu->exec(QCursor::pos());
1675 case LFUN_FILE_INSERT:
1676 insertLyXFile(cmd.argument());
1678 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1679 insertPlaintextFile(cmd.argument(), true);
1682 case LFUN_FILE_INSERT_PLAINTEXT:
1683 insertPlaintextFile(cmd.argument(), false);
1686 case LFUN_BUFFER_WRITE:
1688 saveBuffer(bv->buffer());
1691 case LFUN_BUFFER_WRITE_AS:
1693 renameBuffer(bv->buffer(), cmd.argument());
1696 case LFUN_BUFFER_WRITE_ALL: {
1697 Buffer * first = theBufferList().first();
1700 message(_("Saving all documents..."));
1701 // We cannot use a for loop as the buffer list cycles.
1707 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1708 b = theBufferList().next(b);
1709 } while (b != first);
1710 message(_("All documents saved."));
1714 case LFUN_TOOLBAR_TOGGLE: {
1715 string const name = cmd.getArg(0);
1716 bool const allowauto = cmd.getArg(1) == "allowauto";
1717 // it is possible to get current toolbar status like this,...
1718 // but I decide to obey the order of ToolbarBackend::flags
1719 // and disregard real toolbar status.
1720 // toolbars_->saveToolbarInfo();
1722 // toggle state on/off/auto
1723 d.toolbars_->toggleToolbarState(name, allowauto);
1727 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1729 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1733 if (tbi->flags & ToolbarInfo::ON)
1735 else if (tbi->flags & ToolbarInfo::OFF)
1737 else if (tbi->flags & ToolbarInfo::AUTO)
1740 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1741 _(tbi->gui_name), state));
1745 case LFUN_DIALOG_UPDATE: {
1746 string const name = to_utf8(cmd.argument());
1747 // Can only update a dialog connected to an existing inset
1748 Inset * inset = getOpenInset(name);
1750 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1751 inset->dispatch(view()->cursor(), fr);
1752 } else if (name == "paragraph") {
1753 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1754 } else if (name == "prefs") {
1755 updateDialog(name, string());
1760 case LFUN_DIALOG_TOGGLE: {
1761 if (isDialogVisible(cmd.getArg(0)))
1762 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1764 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1768 case LFUN_DIALOG_DISCONNECT_INSET:
1769 disconnectDialog(to_utf8(cmd.argument()));
1772 case LFUN_DIALOG_HIDE: {
1773 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1777 case LFUN_DIALOG_SHOW: {
1778 string const name = cmd.getArg(0);
1779 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1781 if (name == "character") {
1782 data = freefont2string();
1784 showDialog("character", data);
1785 } else if (name == "latexlog") {
1786 Buffer::LogType type;
1787 string const logfile = buffer()->logName(&type);
1789 case Buffer::latexlog:
1792 case Buffer::buildlog:
1796 data += Lexer::quoteString(logfile);
1797 showDialog("log", data);
1798 } else if (name == "vclog") {
1799 string const data = "vc " +
1800 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1801 showDialog("log", data);
1802 } else if (name == "symbols") {
1803 data = bv->cursor().getEncoding()->name();
1805 showDialog("symbols", data);
1807 showDialog(name, data);
1811 case LFUN_INSET_APPLY: {
1812 string const name = cmd.getArg(0);
1813 Inset * inset = getOpenInset(name);
1815 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1816 inset->dispatch(view()->cursor(), fr);
1818 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1824 case LFUN_UI_TOGGLE:
1826 // Make sure the keyboard focus stays in the work area.
1830 case LFUN_COMPLETION_INLINE:
1831 if (d.current_work_area_)
1832 d.current_work_area_->completer().showInline();
1835 case LFUN_SPLIT_VIEW:
1836 if (Buffer * buf = buffer()) {
1837 string const orientation = cmd.getArg(0);
1838 d.splitter_->setOrientation(orientation == "vertical"
1839 ? Qt::Vertical : Qt::Horizontal);
1840 TabWorkArea * twa = addTabWorkArea();
1841 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1842 setCurrentWorkArea(wa);
1846 case LFUN_CLOSE_TAB_GROUP:
1847 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1849 twa = d.currentTabWorkArea();
1850 // Switch to the next GuiWorkArea in the found TabWorkArea.
1851 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1852 if (d.splitter_->count() == 0)
1853 // No more work area, switch to the background widget.
1858 case LFUN_COMPLETION_POPUP:
1859 if (d.current_work_area_)
1860 d.current_work_area_->completer().showPopup();
1864 case LFUN_COMPLETION_COMPLETE:
1865 if (d.current_work_area_)
1866 d.current_work_area_->completer().tab();
1877 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1879 string const arg = cmd.getArg(0);
1880 if (arg == "scrollbar") {
1881 // hide() is of no help
1882 if (d.current_work_area_->verticalScrollBarPolicy() ==
1883 Qt::ScrollBarAlwaysOff)
1885 d.current_work_area_->setVerticalScrollBarPolicy(
1886 Qt::ScrollBarAsNeeded);
1888 d.current_work_area_->setVerticalScrollBarPolicy(
1889 Qt::ScrollBarAlwaysOff);
1892 if (arg == "statusbar") {
1893 statusBar()->setVisible(!statusBar()->isVisible());
1896 if (arg == "menubar") {
1897 menuBar()->setVisible(!menuBar()->isVisible());
1900 #if QT_VERSION >= 0x040300
1901 if (arg == "frame") {
1903 getContentsMargins(&l, &t, &r, &b);
1904 //are the frames in default state?
1906 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1907 setContentsMargins(-2, -2, -2, -2);
1909 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1910 setContentsMargins(0, 0, 0, 0);
1915 if (arg != "fullscreen") {
1916 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1920 if (lyxrc.full_screen_toolbars)
1921 d.toolbars_->toggleFullScreen(!isFullScreen());
1923 if (isFullScreen()) {
1924 for (int i = 0; i != d.splitter_->count(); ++i)
1925 d.tabWorkArea(i)->setFullScreen(false);
1926 #if QT_VERSION >= 0x040300
1927 setContentsMargins(0, 0, 0, 0);
1931 statusBar()->show();
1933 for (int i = 0; i != d.splitter_->count(); ++i)
1934 d.tabWorkArea(i)->setFullScreen(true);
1935 #if QT_VERSION >= 0x040300
1936 setContentsMargins(-2, -2, -2, -2);
1939 statusBar()->hide();
1945 Buffer const * GuiView::updateInset(Inset const * inset)
1947 if (!d.current_work_area_)
1951 d.current_work_area_->scheduleRedraw();
1953 return &d.current_work_area_->bufferView().buffer();
1957 void GuiView::restartCursor()
1959 /* When we move around, or type, it's nice to be able to see
1960 * the cursor immediately after the keypress.
1962 if (d.current_work_area_)
1963 d.current_work_area_->startBlinkingCursor();
1965 // Take this occasion to update the other GUI elements.
1972 void GuiView::updateCompletion(bool start, bool keep)
1974 if (d.current_work_area_)
1975 d.current_work_area_->completer().updateVisibility(start, keep);
1980 // This list should be kept in sync with the list of insets in
1981 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1982 // dialog should have the same name as the inset.
1984 char const * const dialognames[] = {
1985 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1986 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1987 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1988 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
1989 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1991 #ifdef HAVE_LIBAIKSAURUS
1995 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1997 char const * const * const end_dialognames =
1998 dialognames + (sizeof(dialognames) / sizeof(char *));
2002 cmpCStr(char const * name) : name_(name) {}
2003 bool operator()(char const * other) {
2004 return strcmp(other, name_) == 0;
2011 bool isValidName(string const & name)
2013 return find_if(dialognames, end_dialognames,
2014 cmpCStr(name.c_str())) != end_dialognames;
2020 void GuiView::resetDialogs()
2022 // Make sure that no LFUN uses any LyXView.
2023 theLyXFunc().setLyXView(0);
2024 // FIXME: the "math panels" toolbar takes an awful lot of time to
2025 // initialise so we don't do that for the time being.
2026 //d.toolbars_->init();
2027 guiApp->menus().fillMenuBar(this);
2029 d.layout_->updateContents(true);
2030 // Now update controls with current buffer.
2031 theLyXFunc().setLyXView(this);
2036 Dialog * GuiView::find_or_build(string const & name)
2038 if (!isValidName(name))
2041 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2043 if (it != d.dialogs_.end())
2044 return it->second.get();
2046 Dialog * dialog = build(name);
2047 d.dialogs_[name].reset(dialog);
2048 if (lyxrc.allow_geometry_session)
2049 dialog->restoreSession();
2054 void GuiView::showDialog(string const & name, string const & data,
2061 Dialog * dialog = find_or_build(name);
2063 dialog->showData(data);
2065 d.open_insets_[name] = inset;
2071 bool GuiView::isDialogVisible(string const & name) const
2073 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2074 if (it == d.dialogs_.end())
2076 return it->second.get()->isVisibleView();
2080 void GuiView::hideDialog(string const & name, Inset * inset)
2082 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2083 if (it == d.dialogs_.end())
2086 if (inset && inset != getOpenInset(name))
2089 Dialog * const dialog = it->second.get();
2090 if (dialog->isVisibleView())
2092 d.open_insets_[name] = 0;
2096 void GuiView::disconnectDialog(string const & name)
2098 if (!isValidName(name))
2101 if (d.open_insets_.find(name) != d.open_insets_.end())
2102 d.open_insets_[name] = 0;
2106 Inset * GuiView::getOpenInset(string const & name) const
2108 if (!isValidName(name))
2111 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2112 return it == d.open_insets_.end() ? 0 : it->second;
2116 void GuiView::hideAll() const
2118 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2119 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2121 for(; it != end; ++it)
2122 it->second->hideView();
2126 void GuiView::hideBufferDependent() const
2128 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2129 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2131 for(; it != end; ++it) {
2132 Dialog * dialog = it->second.get();
2133 if (dialog->isBufferDependent())
2139 void GuiView::updateBufferDependent(bool switched) const
2141 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2142 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2144 for(; it != end; ++it) {
2145 Dialog * dialog = it->second.get();
2146 if (!dialog->isVisibleView())
2148 if (switched && dialog->isBufferDependent()) {
2149 if (dialog->initialiseParams(""))
2150 dialog->updateView();
2154 // A bit clunky, but the dialog will request
2155 // that the kernel provides it with the necessary
2157 dialog->updateDialog();
2163 void GuiView::checkStatus()
2165 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2166 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2168 for(; it != end; ++it) {
2169 Dialog * const dialog = it->second.get();
2170 if (dialog && dialog->isVisibleView())
2171 dialog->checkStatus();
2177 // will be replaced by a proper factory...
2178 Dialog * createGuiAbout(GuiView & lv);
2179 Dialog * createGuiBibitem(GuiView & lv);
2180 Dialog * createGuiBibtex(GuiView & lv);
2181 Dialog * createGuiBox(GuiView & lv);
2182 Dialog * createGuiBranch(GuiView & lv);
2183 Dialog * createGuiChanges(GuiView & lv);
2184 Dialog * createGuiCharacter(GuiView & lv);
2185 Dialog * createGuiCitation(GuiView & lv);
2186 Dialog * createGuiDelimiter(GuiView & lv);
2187 Dialog * createGuiDocument(GuiView & lv);
2188 Dialog * createGuiErrorList(GuiView & lv);
2189 Dialog * createGuiERT(GuiView & lv);
2190 Dialog * createGuiExternal(GuiView & lv);
2191 Dialog * createGuiFloat(GuiView & lv);
2192 Dialog * createGuiGraphics(GuiView & lv);
2193 Dialog * createGuiInclude(GuiView & lv);
2194 Dialog * createGuiLabel(GuiView & lv);
2195 Dialog * createGuiListings(GuiView & lv);
2196 Dialog * createGuiLog(GuiView & lv);
2197 Dialog * createGuiMathMatrix(GuiView & lv);
2198 Dialog * createGuiNomenclature(GuiView & lv);
2199 Dialog * createGuiNote(GuiView & lv);
2200 Dialog * createGuiParagraph(GuiView & lv);
2201 Dialog * createGuiPreferences(GuiView & lv);
2202 Dialog * createGuiPrint(GuiView & lv);
2203 Dialog * createGuiRef(GuiView & lv);
2204 Dialog * createGuiSearch(GuiView & lv);
2205 Dialog * createGuiSendTo(GuiView & lv);
2206 Dialog * createGuiShowFile(GuiView & lv);
2207 Dialog * createGuiSpellchecker(GuiView & lv);
2208 Dialog * createGuiSymbols(GuiView & lv);
2209 Dialog * createGuiTabularCreate(GuiView & lv);
2210 Dialog * createGuiTabular(GuiView & lv);
2211 Dialog * createGuiTexInfo(GuiView & lv);
2212 Dialog * createGuiToc(GuiView & lv);
2213 Dialog * createGuiThesaurus(GuiView & lv);
2214 Dialog * createGuiHyperlink(GuiView & lv);
2215 Dialog * createGuiVSpace(GuiView & lv);
2216 Dialog * createGuiViewSource(GuiView & lv);
2217 Dialog * createGuiWrap(GuiView & lv);
2220 Dialog * GuiView::build(string const & name)
2222 BOOST_ASSERT(isValidName(name));
2224 if (name == "aboutlyx")
2225 return createGuiAbout(*this);
2226 if (name == "bibitem")
2227 return createGuiBibitem(*this);
2228 if (name == "bibtex")
2229 return createGuiBibtex(*this);
2231 return createGuiBox(*this);
2232 if (name == "branch")
2233 return createGuiBranch(*this);
2234 if (name == "changes")
2235 return createGuiChanges(*this);
2236 if (name == "character")
2237 return createGuiCharacter(*this);
2238 if (name == "citation")
2239 return createGuiCitation(*this);
2240 if (name == "document")
2241 return createGuiDocument(*this);
2242 if (name == "errorlist")
2243 return createGuiErrorList(*this);
2245 return createGuiERT(*this);
2246 if (name == "external")
2247 return createGuiExternal(*this);
2249 return createGuiShowFile(*this);
2250 if (name == "findreplace")
2251 return createGuiSearch(*this);
2252 if (name == "float")
2253 return createGuiFloat(*this);
2254 if (name == "graphics")
2255 return createGuiGraphics(*this);
2256 if (name == "include")
2257 return createGuiInclude(*this);
2258 if (name == "nomenclature")
2259 return createGuiNomenclature(*this);
2260 if (name == "label")
2261 return createGuiLabel(*this);
2263 return createGuiLog(*this);
2264 if (name == "view-source")
2265 return createGuiViewSource(*this);
2266 if (name == "mathdelimiter")
2267 return createGuiDelimiter(*this);
2268 if (name == "mathmatrix")
2269 return createGuiMathMatrix(*this);
2271 return createGuiNote(*this);
2272 if (name == "paragraph")
2273 return createGuiParagraph(*this);
2274 if (name == "prefs")
2275 return createGuiPreferences(*this);
2276 if (name == "print")
2277 return createGuiPrint(*this);
2279 return createGuiRef(*this);
2280 if (name == "sendto")
2281 return createGuiSendTo(*this);
2282 if (name == "spellchecker")
2283 return createGuiSpellchecker(*this);
2284 if (name == "symbols")
2285 return createGuiSymbols(*this);
2286 if (name == "tabular")
2287 return createGuiTabular(*this);
2288 if (name == "tabularcreate")
2289 return createGuiTabularCreate(*this);
2290 if (name == "texinfo")
2291 return createGuiTexInfo(*this);
2292 #ifdef HAVE_LIBAIKSAURUS
2293 if (name == "thesaurus")
2294 return createGuiThesaurus(*this);
2297 return createGuiToc(*this);
2299 return createGuiHyperlink(*this);
2300 if (name == "vspace")
2301 return createGuiVSpace(*this);
2303 return createGuiWrap(*this);
2304 if (name == "listings")
2305 return createGuiListings(*this);
2311 } // namespace frontend
2314 #include "GuiView_moc.cpp"