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 (size_type 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 if (this == guiApp->currentView()) {
575 return QMainWindow::event(e);
577 guiApp->setCurrentView(*this);
578 if (d.current_work_area_) {
579 BufferView & bv = d.current_work_area_->bufferView();
580 connectBufferView(bv);
581 connectBuffer(bv.buffer());
582 // The document structure, name and dialogs might have
583 // changed in another view.
584 updateBufferDependent(true);
589 setWindowTitle(qt_("LyX"));
590 setWindowIconText(qt_("LyX"));
593 return QMainWindow::event(e);
596 case QEvent::ShortcutOverride: {
597 if (d.current_work_area_)
598 // Nothing special to do.
599 return QMainWindow::event(e);
601 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
603 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
605 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
606 || ke->key() == Qt::Key_Backtab)
607 return QMainWindow::event(e);
609 // Allow processing of shortcuts that are allowed even when no Buffer
611 theLyXFunc().setLyXView(this);
613 setKeySymbol(&sym, ke);
614 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
620 return QMainWindow::event(e);
625 bool GuiView::focusNextPrevChild(bool /*next*/)
632 void GuiView::setBusy(bool busy)
634 if (d.current_work_area_) {
635 d.current_work_area_->setUpdatesEnabled(!busy);
637 d.current_work_area_->stopBlinkingCursor();
639 d.current_work_area_->startBlinkingCursor();
643 QApplication::setOverrideCursor(Qt::WaitCursor);
645 QApplication::restoreOverrideCursor();
649 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
651 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
653 if (tbinfo.flags & ToolbarInfo::TOP) {
655 addToolBarBreak(Qt::TopToolBarArea);
656 addToolBar(Qt::TopToolBarArea, toolBar);
659 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
660 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
661 #if (QT_VERSION >= 0x040202)
663 addToolBarBreak(Qt::BottomToolBarArea);
665 addToolBar(Qt::BottomToolBarArea, toolBar);
668 if (tbinfo.flags & ToolbarInfo::LEFT) {
669 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
670 #if (QT_VERSION >= 0x040202)
672 addToolBarBreak(Qt::LeftToolBarArea);
674 addToolBar(Qt::LeftToolBarArea, toolBar);
677 if (tbinfo.flags & ToolbarInfo::RIGHT) {
678 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
679 #if (QT_VERSION >= 0x040202)
681 addToolBarBreak(Qt::RightToolBarArea);
683 addToolBar(Qt::RightToolBarArea, toolBar);
686 // The following does not work so I cannot restore to exact toolbar location
688 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
689 toolBar->move(tbinfo.posx, tbinfo.posy);
696 GuiWorkArea * GuiView::workArea(Buffer & buffer)
698 if (TabWorkArea * twa = d.currentTabWorkArea())
699 return twa->workArea(buffer);
704 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
706 // Automatically create a TabWorkArea if there are none yet.
707 TabWorkArea * tab_widget = d.splitter_->count()
708 ? d.currentTabWorkArea() : addTabWorkArea();
709 return tab_widget->addWorkArea(buffer, *this);
713 TabWorkArea * GuiView::addTabWorkArea()
715 TabWorkArea * twa = new TabWorkArea;
716 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
717 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
718 d.splitter_->addWidget(twa);
719 d.stack_widget_->setCurrentWidget(d.splitter_);
724 GuiWorkArea const * GuiView::currentWorkArea() const
726 return d.current_work_area_;
730 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
734 // Changing work area can result from opening a file so
735 // update the toc in any case.
738 d.current_work_area_ = wa;
739 for (int i = 0; i != d.splitter_->count(); ++i) {
740 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
746 void GuiView::removeWorkArea(GuiWorkArea * wa)
749 if (wa == d.current_work_area_) {
751 disconnectBufferView();
752 hideBufferDependent();
753 d.current_work_area_ = 0;
756 for (int i = 0; i != d.splitter_->count(); ++i) {
757 TabWorkArea * twa = d.tabWorkArea(i);
758 if (!twa->removeWorkArea(wa))
759 // Not found in this tab group.
762 // We found and removed the GuiWorkArea.
764 // No more WorkAreas in this tab group, so delete it.
769 if (d.current_work_area_)
770 // This means that we are not closing the current GuiWorkArea;
773 // Switch to the next GuiWorkArea in the found TabWorkArea.
774 d.current_work_area_ = twa->currentWorkArea();
778 if (d.splitter_->count() == 0)
779 // No more work area, switch to the background widget.
784 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
790 void GuiView::updateLayoutList()
793 d.layout_->updateContents(false);
797 void GuiView::updateToolbars()
799 if (d.current_work_area_) {
801 d.current_work_area_->bufferView().cursor().inMathed();
803 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
805 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
806 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
807 bool const mathmacrotemplate =
808 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
810 d.toolbars_->update(math, table, review, mathmacrotemplate);
812 d.toolbars_->update(false, false, false, false);
814 // update read-only status of open dialogs.
819 Buffer * GuiView::buffer()
821 if (d.current_work_area_)
822 return &d.current_work_area_->bufferView().buffer();
827 Buffer const * GuiView::buffer() const
829 if (d.current_work_area_)
830 return &d.current_work_area_->bufferView().buffer();
835 void GuiView::setBuffer(Buffer * newBuffer)
837 BOOST_ASSERT(newBuffer);
840 GuiWorkArea * wa = workArea(*newBuffer);
842 updateLabels(*newBuffer->masterBuffer());
843 wa = addWorkArea(*newBuffer);
845 //Disconnect the old buffer...there's no new one.
848 connectBuffer(*newBuffer);
849 connectBufferView(wa->bufferView());
850 setCurrentWorkArea(wa);
856 void GuiView::connectBuffer(Buffer & buf)
858 buf.setGuiDelegate(this);
862 void GuiView::disconnectBuffer()
864 if (d.current_work_area_)
865 d.current_work_area_->bufferView().setGuiDelegate(0);
869 void GuiView::connectBufferView(BufferView & bv)
871 bv.setGuiDelegate(this);
875 void GuiView::disconnectBufferView()
877 if (d.current_work_area_)
878 d.current_work_area_->bufferView().setGuiDelegate(0);
882 void GuiView::errors(string const & error_type)
884 ErrorList & el = buffer()->errorList(error_type);
886 showDialog("errorlist", error_type);
890 void GuiView::updateDialog(string const & name, string const & data)
892 if (!isDialogVisible(name))
895 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
896 if (it == d.dialogs_.end())
899 Dialog * const dialog = it->second.get();
900 if (dialog->isVisibleView())
901 dialog->updateData(data);
905 BufferView * GuiView::view()
907 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
911 void GuiView::updateToc()
913 updateDialog("toc", "");
917 void GuiView::updateEmbeddedFiles()
919 updateDialog("embedding", "");
923 void GuiView::autoSave()
925 LYXERR(Debug::INFO, "Running autoSave()");
928 view()->buffer().autoSave();
932 void GuiView::resetAutosaveTimers()
935 d.autosave_timeout_.restart();
939 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
943 Buffer * buf = buffer();
945 /* In LyX/Mac, when a dialog is open, the menus of the
946 application can still be accessed without giving focus to
947 the main window. In this case, we want to disable the menu
948 entries that are buffer-related.
950 Note that this code is not perfect, as bug 1941 attests:
951 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
953 if (cmd.origin == FuncRequest::MENU && !hasFocus())
957 case LFUN_BUFFER_WRITE:
958 enable = buf && (buf->isUnnamed() || !buf->isClean());
961 case LFUN_BUFFER_WRITE_AS:
965 case LFUN_SPLIT_VIEW:
969 case LFUN_CLOSE_TAB_GROUP:
970 enable = d.currentTabWorkArea();
973 case LFUN_TOOLBAR_TOGGLE:
974 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
977 case LFUN_DIALOG_TOGGLE:
978 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
979 // fall through to set "enable"
980 case LFUN_DIALOG_SHOW: {
981 string const name = cmd.getArg(0);
983 enable = name == "aboutlyx"
984 || name == "file" //FIXME: should be removed.
986 || name == "texinfo";
987 else if (name == "print")
988 enable = buf->isExportable("dvi")
989 && lyxrc.print_command != "none";
990 else if (name == "character") {
994 InsetCode ic = view()->cursor().inset().lyxCode();
995 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
998 else if (name == "symbols") {
999 if (!view() || view()->cursor().inMathed())
1002 InsetCode ic = view()->cursor().inset().lyxCode();
1003 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1006 else if (name == "latexlog")
1007 enable = FileName(buf->logName()).isReadableFile();
1008 else if (name == "spellchecker")
1009 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1010 enable = !buf->isReadonly();
1014 else if (name == "vclog")
1015 enable = buf->lyxvc().inUse();
1019 case LFUN_DIALOG_UPDATE: {
1020 string const name = cmd.getArg(0);
1022 enable = name == "prefs";
1026 case LFUN_INSET_APPLY: {
1031 string const name = cmd.getArg(0);
1032 Inset * inset = getOpenInset(name);
1034 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1036 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1037 // Every inset is supposed to handle this
1038 BOOST_ASSERT(false);
1042 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1043 flag |= getStatus(fr);
1045 enable = flag.enabled();
1049 case LFUN_COMPLETION_INLINE:
1050 if (!d.current_work_area_
1051 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1055 case LFUN_COMPLETION_POPUP:
1056 if (!d.current_work_area_
1057 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1061 case LFUN_COMPLETION_COMPLETE:
1062 if (!d.current_work_area_
1063 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1075 flag.enabled(false);
1081 static FileName selectTemplateFile()
1083 FileDialog dlg(qt_("Select template file"));
1084 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1085 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1087 FileDialog::Result result =
1088 dlg.open(toqstr(lyxrc.template_path),
1089 FileFilterList(_("LyX Documents (*.lyx)")));
1091 if (result.first == FileDialog::Later)
1093 if (result.second.isEmpty())
1095 return FileName(fromqstr(result.second));
1099 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1103 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1106 message(_("Document not loaded."));
1111 setBuffer(newBuffer);
1113 // scroll to the position when the file was last closed
1114 if (lyxrc.use_lastfilepos) {
1115 LastFilePosSection::FilePos filepos =
1116 LyX::ref().session().lastFilePos().load(filename);
1117 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1121 LyX::ref().session().lastFiles().add(filename);
1128 void GuiView::openDocument(string const & fname)
1130 string initpath = lyxrc.document_path;
1133 string const trypath = buffer()->filePath();
1134 // If directory is writeable, use this as default.
1135 if (FileName(trypath).isDirWritable())
1141 if (fname.empty()) {
1142 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1143 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1144 dlg.setButton2(qt_("Examples|#E#e"),
1145 toqstr(addPath(package().system_support().absFilename(), "examples")));
1147 FileDialog::Result result =
1148 dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1150 if (result.first == FileDialog::Later)
1153 filename = fromqstr(result.second);
1155 // check selected filename
1156 if (filename.empty()) {
1157 message(_("Canceled."));
1163 // get absolute path of file and add ".lyx" to the filename if
1165 FileName const fullname =
1166 fileSearch(string(), filename, "lyx", support::may_not_exist);
1167 if (!fullname.empty())
1168 filename = fullname.absFilename();
1170 // if the file doesn't exist, let the user create one
1171 if (!fullname.exists()) {
1172 // the user specifically chose this name. Believe him.
1173 Buffer * const b = newFile(filename, string(), true);
1179 docstring const disp_fn = makeDisplayPath(filename);
1180 message(bformat(_("Opening document %1$s..."), disp_fn));
1183 Buffer * buf = loadDocument(fullname);
1187 buf->errors("Parse");
1188 str2 = bformat(_("Document %1$s opened."), disp_fn);
1190 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1195 // FIXME: clean that
1196 static bool import(GuiView * lv, FileName const & filename,
1197 string const & format, ErrorList & errorList)
1199 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
1201 string loader_format;
1202 vector<string> loaders = theConverters().loaders();
1203 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1204 for (vector<string>::const_iterator it = loaders.begin();
1205 it != loaders.end(); ++it) {
1206 if (!theConverters().isReachable(format, *it))
1209 string const tofile =
1210 changeExtension(filename.absFilename(),
1211 formats.extension(*it));
1212 if (!theConverters().convert(0, filename, FileName(tofile),
1213 filename, format, *it, errorList))
1215 loader_format = *it;
1218 if (loader_format.empty()) {
1219 frontend::Alert::error(_("Couldn't import file"),
1220 bformat(_("No information for importing the format %1$s."),
1221 formats.prettyName(format)));
1225 loader_format = format;
1227 if (loader_format == "lyx") {
1228 Buffer * buf = lv->loadDocument(lyxfile);
1233 buf->errors("Parse");
1235 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1239 bool as_paragraphs = loader_format == "textparagraph";
1240 string filename2 = (loader_format == format) ? filename.absFilename()
1241 : changeExtension(filename.absFilename(),
1242 formats.extension(loader_format));
1243 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1244 theLyXFunc().setLyXView(lv);
1245 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1252 void GuiView::importDocument(string const & argument)
1255 string filename = split(argument, format, ' ');
1257 LYXERR(Debug::INFO, format << " file: " << filename);
1259 // need user interaction
1260 if (filename.empty()) {
1261 string initpath = lyxrc.document_path;
1263 Buffer const * buf = buffer();
1265 string const trypath = buf->filePath();
1266 // If directory is writeable, use this as default.
1267 if (FileName(trypath).isDirWritable())
1271 docstring const text = bformat(_("Select %1$s file to import"),
1272 formats.prettyName(format));
1274 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1275 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1276 dlg.setButton2(qt_("Examples|#E#e"),
1277 toqstr(addPath(package().system_support().absFilename(), "examples")));
1279 docstring filter = formats.prettyName(format);
1282 filter += from_utf8(formats.extension(format));
1285 FileDialog::Result result =
1286 dlg.open(toqstr(initpath), FileFilterList(filter));
1288 if (result.first == FileDialog::Later)
1291 filename = fromqstr(result.second);
1293 // check selected filename
1294 if (filename.empty())
1295 message(_("Canceled."));
1298 if (filename.empty())
1301 // get absolute path of file
1302 FileName const fullname(makeAbsPath(filename));
1304 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
1306 // Check if the document already is open
1307 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1310 if (!closeBuffer()) {
1311 message(_("Canceled."));
1316 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1318 // if the file exists already, and we didn't do
1319 // -i lyx thefile.lyx, warn
1320 if (lyxfile.exists() && fullname != lyxfile) {
1322 docstring text = bformat(_("The document %1$s already exists.\n\n"
1323 "Do you want to overwrite that document?"), displaypath);
1324 int const ret = Alert::prompt(_("Overwrite document?"),
1325 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1328 message(_("Canceled."));
1333 message(bformat(_("Importing %1$s..."), displaypath));
1334 ErrorList errorList;
1335 if (import(this, fullname, format, errorList))
1336 message(_("imported."));
1338 message(_("file not imported!"));
1340 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1344 void GuiView::newDocument(string const & filename, bool from_template)
1346 FileName initpath(lyxrc.document_path);
1347 Buffer * buf = buffer();
1349 FileName const trypath(buf->filePath());
1350 // If directory is writeable, use this as default.
1351 if (trypath.isDirWritable())
1355 string templatefile = from_template ?
1356 selectTemplateFile().absFilename() : string();
1358 if (filename.empty())
1359 b = newUnnamedFile(templatefile, initpath);
1361 b = newFile(filename, templatefile, true);
1365 // Ensure the cursor is correctly positionned on screen.
1366 view()->showCursor();
1370 void GuiView::insertLyXFile(docstring const & fname)
1372 BufferView * bv = view();
1377 FileName filename(to_utf8(fname));
1379 if (!filename.empty()) {
1380 bv->insertLyXFile(filename);
1384 // Launch a file browser
1386 string initpath = lyxrc.document_path;
1387 string const trypath = bv->buffer().filePath();
1388 // If directory is writeable, use this as default.
1389 if (FileName(trypath).isDirWritable())
1393 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1394 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1395 dlg.setButton2(qt_("Examples|#E#e"),
1396 toqstr(addPath(package().system_support().absFilename(),
1399 FileDialog::Result result =
1400 dlg.open(toqstr(initpath),
1401 FileFilterList(_("LyX Documents (*.lyx)")));
1403 if (result.first == FileDialog::Later)
1407 filename.set(fromqstr(result.second));
1409 // check selected filename
1410 if (filename.empty()) {
1411 // emit message signal.
1412 message(_("Canceled."));
1416 bv->insertLyXFile(filename);
1420 void GuiView::insertPlaintextFile(docstring const & fname,
1423 BufferView * bv = view();
1428 FileName filename(to_utf8(fname));
1430 if (!filename.empty()) {
1431 bv->insertPlaintextFile(filename, asParagraph);
1435 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1436 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1438 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1441 if (result.first == FileDialog::Later)
1445 filename.set(fromqstr(result.second));
1447 // check selected filename
1448 if (filename.empty()) {
1449 // emit message signal.
1450 message(_("Canceled."));
1454 bv->insertPlaintextFile(filename, asParagraph);
1458 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1460 FileName fname = b.fileName();
1461 FileName const oldname = fname;
1463 if (!newname.empty()) {
1465 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1467 // Switch to this Buffer.
1470 /// No argument? Ask user through dialog.
1472 FileDialog dlg(qt_("Choose a filename to save document as"),
1473 LFUN_BUFFER_WRITE_AS);
1474 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1475 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1477 if (!isLyXFilename(fname.absFilename()))
1478 fname.changeExtension(".lyx");
1480 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1482 FileDialog::Result result =
1483 dlg.save(toqstr(fname.onlyPath().absFilename()),
1485 toqstr(fname.onlyFileName()));
1487 if (result.first == FileDialog::Later)
1490 fname.set(fromqstr(result.second));
1495 if (!isLyXFilename(fname.absFilename()))
1496 fname.changeExtension(".lyx");
1499 if (FileName(fname).exists()) {
1500 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1501 docstring text = bformat(_("The document %1$s already "
1502 "exists.\n\nDo you want to "
1503 "overwrite that document?"),
1505 int const ret = Alert::prompt(_("Overwrite document?"),
1506 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1509 case 1: return renameBuffer(b, docstring());
1510 case 2: return false;
1514 // Ok, change the name of the buffer
1515 b.setFileName(fname.absFilename());
1517 bool unnamed = b.isUnnamed();
1518 b.setUnnamed(false);
1519 b.saveCheckSum(fname);
1521 if (!saveBuffer(b)) {
1522 b.setFileName(oldname.absFilename());
1523 b.setUnnamed(unnamed);
1524 b.saveCheckSum(oldname);
1532 bool GuiView::saveBuffer(Buffer & b)
1535 return renameBuffer(b, docstring());
1538 LyX::ref().session().lastFiles().add(b.fileName());
1542 // Switch to this Buffer.
1545 // FIXME: we don't tell the user *WHY* the save failed !!
1546 docstring const file = makeDisplayPath(b.absFileName(), 30);
1547 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1548 "Do you want to rename the document and "
1549 "try again?"), file);
1550 int const ret = Alert::prompt(_("Rename and save?"),
1551 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1554 if (!renameBuffer(b, docstring()))
1563 return saveBuffer(b);
1567 bool GuiView::closeBuffer()
1569 Buffer * buf = buffer();
1570 return buf && closeBuffer(*buf);
1574 bool GuiView::closeBuffer(Buffer & buf)
1576 // goto bookmark to update bookmark pit.
1577 //FIXME: we should update only the bookmarks related to this buffer!
1578 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1579 theLyXFunc().gotoBookmark(i+1, false, false);
1581 if (buf.isClean() || buf.paragraphs().empty()) {
1582 theBufferList().release(&buf);
1585 // Switch to this Buffer.
1590 if (buf.isUnnamed())
1591 file = from_utf8(buf.fileName().onlyFileName());
1593 file = buf.fileName().displayName(30);
1595 // Bring this window to top before asking questions.
1599 docstring const text = bformat(_("The document %1$s has unsaved changes."
1600 "\n\nDo you want to save the document or discard the changes?"), file);
1601 int const ret = Alert::prompt(_("Save changed document?"),
1602 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1606 if (!saveBuffer(buf))
1610 // if we crash after this we could
1611 // have no autosave file but I guess
1612 // this is really improbable (Jug)
1613 removeAutosaveFile(buf.absFileName());
1619 // save file names to .lyx/session
1620 // if master/slave are both open, do not save slave since it
1621 // will be automatically loaded when the master is loaded
1622 if (buf.masterBuffer() == &buf)
1623 LyX::ref().session().lastOpened().add(buf.fileName());
1625 theBufferList().release(&buf);
1630 bool GuiView::dispatch(FuncRequest const & cmd)
1632 BufferView * bv = view();
1633 // By default we won't need any update.
1635 bv->cursor().updateFlags(Update::None);
1637 switch(cmd.action) {
1638 case LFUN_FILE_OPEN:
1639 openDocument(to_utf8(cmd.argument()));
1642 case LFUN_BUFFER_IMPORT:
1643 importDocument(to_utf8(cmd.argument()));
1646 case LFUN_BUFFER_SWITCH:
1647 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1650 case LFUN_BUFFER_NEXT:
1651 setBuffer(theBufferList().next(buffer()));
1654 case LFUN_BUFFER_PREVIOUS:
1655 setBuffer(theBufferList().previous(buffer()));
1658 case LFUN_COMMAND_EXECUTE: {
1659 bool const show_it = cmd.argument() != "off";
1660 d.toolbars_->showCommandBuffer(show_it);
1663 case LFUN_DROP_LAYOUTS_CHOICE:
1665 d.layout_->showPopup();
1668 case LFUN_MENU_OPEN:
1669 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument())))
1670 menu->exec(QCursor::pos());
1673 case LFUN_FILE_INSERT:
1674 insertLyXFile(cmd.argument());
1676 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1677 insertPlaintextFile(cmd.argument(), true);
1680 case LFUN_FILE_INSERT_PLAINTEXT:
1681 insertPlaintextFile(cmd.argument(), false);
1684 case LFUN_BUFFER_WRITE:
1686 saveBuffer(bv->buffer());
1689 case LFUN_BUFFER_WRITE_AS:
1691 renameBuffer(bv->buffer(), cmd.argument());
1694 case LFUN_BUFFER_WRITE_ALL: {
1695 Buffer * first = theBufferList().first();
1698 message(_("Saving all documents..."));
1699 // We cannot use a for loop as the buffer list cycles.
1705 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1706 b = theBufferList().next(b);
1707 } while (b != first);
1708 message(_("All documents saved."));
1712 case LFUN_TOOLBAR_TOGGLE: {
1713 string const name = cmd.getArg(0);
1714 bool const allowauto = cmd.getArg(1) == "allowauto";
1715 // it is possible to get current toolbar status like this,...
1716 // but I decide to obey the order of ToolbarBackend::flags
1717 // and disregard real toolbar status.
1718 // toolbars_->saveToolbarInfo();
1720 // toggle state on/off/auto
1721 d.toolbars_->toggleToolbarState(name, allowauto);
1725 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1727 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1731 if (tbi->flags & ToolbarInfo::ON)
1733 else if (tbi->flags & ToolbarInfo::OFF)
1735 else if (tbi->flags & ToolbarInfo::AUTO)
1738 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1739 _(tbi->gui_name), state));
1743 case LFUN_DIALOG_UPDATE: {
1744 string const name = to_utf8(cmd.argument());
1745 // Can only update a dialog connected to an existing inset
1746 Inset * inset = getOpenInset(name);
1748 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1749 inset->dispatch(view()->cursor(), fr);
1750 } else if (name == "paragraph") {
1751 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1752 } else if (name == "prefs") {
1753 updateDialog(name, string());
1758 case LFUN_DIALOG_TOGGLE: {
1759 if (isDialogVisible(cmd.getArg(0)))
1760 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1762 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1766 case LFUN_DIALOG_DISCONNECT_INSET:
1767 disconnectDialog(to_utf8(cmd.argument()));
1770 case LFUN_DIALOG_HIDE: {
1771 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1775 case LFUN_DIALOG_SHOW: {
1776 string const name = cmd.getArg(0);
1777 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1779 if (name == "character") {
1780 data = freefont2string();
1782 showDialog("character", data);
1783 } else if (name == "latexlog") {
1784 Buffer::LogType type;
1785 string const logfile = buffer()->logName(&type);
1787 case Buffer::latexlog:
1790 case Buffer::buildlog:
1794 data += Lexer::quoteString(logfile);
1795 showDialog("log", data);
1796 } else if (name == "vclog") {
1797 string const data = "vc " +
1798 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1799 showDialog("log", data);
1800 } else if (name == "symbols") {
1801 data = bv->cursor().getEncoding()->name();
1803 showDialog("symbols", data);
1805 showDialog(name, data);
1809 case LFUN_INSET_APPLY: {
1810 string const name = cmd.getArg(0);
1811 Inset * inset = getOpenInset(name);
1813 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1814 inset->dispatch(view()->cursor(), fr);
1816 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1822 case LFUN_UI_TOGGLE:
1824 // Make sure the keyboard focus stays in the work area.
1828 case LFUN_COMPLETION_INLINE:
1829 if (d.current_work_area_)
1830 d.current_work_area_->completer().showInline();
1833 case LFUN_SPLIT_VIEW:
1834 if (Buffer * buf = buffer()) {
1835 string const orientation = cmd.getArg(0);
1836 d.splitter_->setOrientation(orientation == "vertical"
1837 ? Qt::Vertical : Qt::Horizontal);
1838 TabWorkArea * twa = addTabWorkArea();
1839 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1840 setCurrentWorkArea(wa);
1844 case LFUN_CLOSE_TAB_GROUP:
1845 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1847 twa = d.currentTabWorkArea();
1848 // Switch to the next GuiWorkArea in the found TabWorkArea.
1849 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1850 if (d.splitter_->count() == 0)
1851 // No more work area, switch to the background widget.
1856 case LFUN_COMPLETION_POPUP:
1857 if (d.current_work_area_)
1858 d.current_work_area_->completer().showPopup();
1862 case LFUN_COMPLETION_COMPLETE:
1863 if (d.current_work_area_)
1864 d.current_work_area_->completer().tab();
1875 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1877 string const arg = cmd.getArg(0);
1878 if (arg == "scrollbar") {
1879 // hide() is of no help
1880 if (d.current_work_area_->verticalScrollBarPolicy() ==
1881 Qt::ScrollBarAlwaysOff)
1883 d.current_work_area_->setVerticalScrollBarPolicy(
1884 Qt::ScrollBarAsNeeded);
1886 d.current_work_area_->setVerticalScrollBarPolicy(
1887 Qt::ScrollBarAlwaysOff);
1890 if (arg == "statusbar") {
1891 statusBar()->setVisible(!statusBar()->isVisible());
1894 if (arg == "menubar") {
1895 menuBar()->setVisible(!menuBar()->isVisible());
1898 #if QT_VERSION >= 0x040300
1899 if (arg == "frame") {
1901 getContentsMargins(&l, &t, &r, &b);
1902 //are the frames in default state?
1903 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1905 setContentsMargins(-2, -2, -2, -2);
1907 setContentsMargins(0, 0, 0, 0);
1912 if (arg != "fullscreen") {
1913 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1917 if (lyxrc.full_screen_toolbars)
1918 d.toolbars_->toggleFullScreen(!isFullScreen());
1920 if (isFullScreen()) {
1921 for (int i = 0; i != d.splitter_->count(); ++i)
1922 d.tabWorkArea(i)->setFullScreen(false);
1923 #if QT_VERSION >= 0x040300
1924 setContentsMargins(0, 0, 0, 0);
1928 statusBar()->show();
1930 for (int i = 0; i != d.splitter_->count(); ++i)
1931 d.tabWorkArea(i)->setFullScreen(true);
1932 #if QT_VERSION >= 0x040300
1933 setContentsMargins(-2, -2, -2, -2);
1936 statusBar()->hide();
1942 Buffer const * GuiView::updateInset(Inset const * inset)
1944 if (!d.current_work_area_)
1948 d.current_work_area_->scheduleRedraw();
1950 return &d.current_work_area_->bufferView().buffer();
1954 void GuiView::restartCursor()
1956 /* When we move around, or type, it's nice to be able to see
1957 * the cursor immediately after the keypress.
1959 if (d.current_work_area_)
1960 d.current_work_area_->startBlinkingCursor();
1962 // Take this occasion to update the other GUI elements.
1969 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1971 if (d.current_work_area_)
1972 d.current_work_area_->completer().updateVisibility(cur, start, keep);
1977 // This list should be kept in sync with the list of insets in
1978 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1979 // dialog should have the same name as the inset.
1981 char const * const dialognames[] = {
1982 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1983 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1984 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1985 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
1986 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1988 #ifdef HAVE_LIBAIKSAURUS
1992 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1994 char const * const * const end_dialognames =
1995 dialognames + (sizeof(dialognames) / sizeof(char *));
1999 cmpCStr(char const * name) : name_(name) {}
2000 bool operator()(char const * other) {
2001 return strcmp(other, name_) == 0;
2008 bool isValidName(string const & name)
2010 return find_if(dialognames, end_dialognames,
2011 cmpCStr(name.c_str())) != end_dialognames;
2017 void GuiView::resetDialogs()
2019 // Make sure that no LFUN uses any LyXView.
2020 theLyXFunc().setLyXView(0);
2021 // FIXME: the "math panels" toolbar takes an awful lot of time to
2022 // initialise so we don't do that for the time being.
2023 //d.toolbars_->init();
2024 guiApp->menus().fillMenuBar(this);
2026 d.layout_->updateContents(true);
2027 // Now update controls with current buffer.
2028 theLyXFunc().setLyXView(this);
2033 Dialog * GuiView::find_or_build(string const & name)
2035 if (!isValidName(name))
2038 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2040 if (it != d.dialogs_.end())
2041 return it->second.get();
2043 Dialog * dialog = build(name);
2044 d.dialogs_[name].reset(dialog);
2045 if (lyxrc.allow_geometry_session)
2046 dialog->restoreSession();
2051 void GuiView::showDialog(string const & name, string const & data,
2058 Dialog * dialog = find_or_build(name);
2060 dialog->showData(data);
2062 d.open_insets_[name] = inset;
2068 bool GuiView::isDialogVisible(string const & name) const
2070 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2071 if (it == d.dialogs_.end())
2073 return it->second.get()->isVisibleView();
2077 void GuiView::hideDialog(string const & name, Inset * inset)
2079 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2080 if (it == d.dialogs_.end())
2083 if (inset && inset != getOpenInset(name))
2086 Dialog * const dialog = it->second.get();
2087 if (dialog->isVisibleView())
2089 d.open_insets_[name] = 0;
2093 void GuiView::disconnectDialog(string const & name)
2095 if (!isValidName(name))
2098 if (d.open_insets_.find(name) != d.open_insets_.end())
2099 d.open_insets_[name] = 0;
2103 Inset * GuiView::getOpenInset(string const & name) const
2105 if (!isValidName(name))
2108 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2109 return it == d.open_insets_.end() ? 0 : it->second;
2113 void GuiView::hideAll() const
2115 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2116 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2118 for(; it != end; ++it)
2119 it->second->hideView();
2123 void GuiView::hideBufferDependent() const
2125 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2126 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2128 for(; it != end; ++it) {
2129 Dialog * dialog = it->second.get();
2130 if (dialog->isBufferDependent())
2136 void GuiView::updateBufferDependent(bool switched) const
2138 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2139 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2141 for(; it != end; ++it) {
2142 Dialog * dialog = it->second.get();
2143 if (!dialog->isVisibleView())
2145 if (switched && dialog->isBufferDependent()) {
2146 if (dialog->initialiseParams(""))
2147 dialog->updateView();
2151 // A bit clunky, but the dialog will request
2152 // that the kernel provides it with the necessary
2154 dialog->updateDialog();
2160 void GuiView::checkStatus()
2162 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2163 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2165 for(; it != end; ++it) {
2166 Dialog * const dialog = it->second.get();
2167 if (dialog && dialog->isVisibleView())
2168 dialog->checkStatus();
2174 // will be replaced by a proper factory...
2175 Dialog * createGuiAbout(GuiView & lv);
2176 Dialog * createGuiBibitem(GuiView & lv);
2177 Dialog * createGuiBibtex(GuiView & lv);
2178 Dialog * createGuiBox(GuiView & lv);
2179 Dialog * createGuiBranch(GuiView & lv);
2180 Dialog * createGuiChanges(GuiView & lv);
2181 Dialog * createGuiCharacter(GuiView & lv);
2182 Dialog * createGuiCitation(GuiView & lv);
2183 Dialog * createGuiDelimiter(GuiView & lv);
2184 Dialog * createGuiDocument(GuiView & lv);
2185 Dialog * createGuiErrorList(GuiView & lv);
2186 Dialog * createGuiERT(GuiView & lv);
2187 Dialog * createGuiExternal(GuiView & lv);
2188 Dialog * createGuiFloat(GuiView & lv);
2189 Dialog * createGuiGraphics(GuiView & lv);
2190 Dialog * createGuiInclude(GuiView & lv);
2191 Dialog * createGuiLabel(GuiView & lv);
2192 Dialog * createGuiListings(GuiView & lv);
2193 Dialog * createGuiLog(GuiView & lv);
2194 Dialog * createGuiMathMatrix(GuiView & lv);
2195 Dialog * createGuiNomenclature(GuiView & lv);
2196 Dialog * createGuiNote(GuiView & lv);
2197 Dialog * createGuiParagraph(GuiView & lv);
2198 Dialog * createGuiPreferences(GuiView & lv);
2199 Dialog * createGuiPrint(GuiView & lv);
2200 Dialog * createGuiRef(GuiView & lv);
2201 Dialog * createGuiSearch(GuiView & lv);
2202 Dialog * createGuiSendTo(GuiView & lv);
2203 Dialog * createGuiShowFile(GuiView & lv);
2204 Dialog * createGuiSpellchecker(GuiView & lv);
2205 Dialog * createGuiSymbols(GuiView & lv);
2206 Dialog * createGuiTabularCreate(GuiView & lv);
2207 Dialog * createGuiTabular(GuiView & lv);
2208 Dialog * createGuiTexInfo(GuiView & lv);
2209 Dialog * createGuiToc(GuiView & lv);
2210 Dialog * createGuiThesaurus(GuiView & lv);
2211 Dialog * createGuiHyperlink(GuiView & lv);
2212 Dialog * createGuiVSpace(GuiView & lv);
2213 Dialog * createGuiViewSource(GuiView & lv);
2214 Dialog * createGuiWrap(GuiView & lv);
2217 Dialog * GuiView::build(string const & name)
2219 BOOST_ASSERT(isValidName(name));
2221 if (name == "aboutlyx")
2222 return createGuiAbout(*this);
2223 if (name == "bibitem")
2224 return createGuiBibitem(*this);
2225 if (name == "bibtex")
2226 return createGuiBibtex(*this);
2228 return createGuiBox(*this);
2229 if (name == "branch")
2230 return createGuiBranch(*this);
2231 if (name == "changes")
2232 return createGuiChanges(*this);
2233 if (name == "character")
2234 return createGuiCharacter(*this);
2235 if (name == "citation")
2236 return createGuiCitation(*this);
2237 if (name == "document")
2238 return createGuiDocument(*this);
2239 if (name == "errorlist")
2240 return createGuiErrorList(*this);
2242 return createGuiERT(*this);
2243 if (name == "external")
2244 return createGuiExternal(*this);
2246 return createGuiShowFile(*this);
2247 if (name == "findreplace")
2248 return createGuiSearch(*this);
2249 if (name == "float")
2250 return createGuiFloat(*this);
2251 if (name == "graphics")
2252 return createGuiGraphics(*this);
2253 if (name == "include")
2254 return createGuiInclude(*this);
2255 if (name == "nomenclature")
2256 return createGuiNomenclature(*this);
2257 if (name == "label")
2258 return createGuiLabel(*this);
2260 return createGuiLog(*this);
2261 if (name == "view-source")
2262 return createGuiViewSource(*this);
2263 if (name == "mathdelimiter")
2264 return createGuiDelimiter(*this);
2265 if (name == "mathmatrix")
2266 return createGuiMathMatrix(*this);
2268 return createGuiNote(*this);
2269 if (name == "paragraph")
2270 return createGuiParagraph(*this);
2271 if (name == "prefs")
2272 return createGuiPreferences(*this);
2273 if (name == "print")
2274 return createGuiPrint(*this);
2276 return createGuiRef(*this);
2277 if (name == "sendto")
2278 return createGuiSendTo(*this);
2279 if (name == "spellchecker")
2280 return createGuiSpellchecker(*this);
2281 if (name == "symbols")
2282 return createGuiSymbols(*this);
2283 if (name == "tabular")
2284 return createGuiTabular(*this);
2285 if (name == "tabularcreate")
2286 return createGuiTabularCreate(*this);
2287 if (name == "texinfo")
2288 return createGuiTexInfo(*this);
2289 #ifdef HAVE_LIBAIKSAURUS
2290 if (name == "thesaurus")
2291 return createGuiThesaurus(*this);
2294 return createGuiToc(*this);
2296 return createGuiHyperlink(*this);
2297 if (name == "vspace")
2298 return createGuiVSpace(*this);
2300 return createGuiWrap(*this);
2301 if (name == "listings")
2302 return createGuiListings(*this);
2308 } // namespace frontend
2311 #include "GuiView_moc.cpp"