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),
149 quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false)
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 /// are we quitting by the menu?
267 bool quitting_by_menu_;
268 /// auto-saving of buffers
269 Timeout autosave_timeout_;
270 /// flag against a race condition due to multiclicks, see bug #1119
275 GuiView::GuiView(int id)
276 : d(*new GuiViewPrivate), id_(id)
278 // GuiToolbars *must* be initialised before the menu bar.
279 d.toolbars_ = new GuiToolbars(*this);
281 // Fill up the menu bar.
282 guiApp->menus().fillMenuBar(this);
284 setCentralWidget(d.stack_widget_);
286 // Start autosave timer
287 if (lyxrc.autosave) {
288 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
289 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
290 d.autosave_timeout_.start();
292 connect(&d.statusbar_timer_, SIGNAL(timeout()),
293 this, SLOT(clearMessage()));
295 // Qt bug? signal lastWindowClosed does not work
296 setAttribute(Qt::WA_QuitOnClose, false);
297 setAttribute(Qt::WA_DeleteOnClose, true);
299 // assign an icon to main form. We do not do it under Qt/Mac,
300 // since the icon is provided in the application bundle.
301 setWindowIcon(QPixmap(":/images/lyx.png"));
305 setAcceptDrops(true);
307 statusBar()->setSizeGripEnabled(true);
309 // Forbid too small unresizable window because it can happen
310 // with some window manager under X11.
311 setMinimumSize(300, 200);
313 if (!lyxrc.allow_geometry_session)
314 // No session handling, default to a sane size.
315 setGeometry(50, 50, 690, 510);
317 // Now take care of session management.
319 QString const key = "view-" + QString::number(id_);
321 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
322 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
326 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
327 setGeometry(50, 50, 690, 510);
329 setIconSize(settings.value(key + "/icon_size").toSize());
339 void GuiView::close()
341 d.quitting_by_menu_ = true;
342 d.current_work_area_ = 0;
343 for (int i = 0; i != d.splitter_->count(); ++i) {
344 TabWorkArea * twa = d.tabWorkArea(i);
348 QMainWindow::close();
349 d.quitting_by_menu_ = false;
353 void GuiView::setFocus()
355 if (d.current_work_area_)
356 d.current_work_area_->setFocus();
362 QMenu * GuiView::createPopupMenu()
364 return d.toolBarPopup(this);
368 void GuiView::showEvent(QShowEvent * e)
370 LYXERR(Debug::GUI, "Passed Geometry "
371 << size().height() << "x" << size().width()
372 << "+" << pos().x() << "+" << pos().y());
374 if (d.splitter_->count() == 0)
375 // No work area, switch to the background widget.
378 QMainWindow::showEvent(e);
382 void GuiView::closeEvent(QCloseEvent * close_event)
384 // we may have been called through the close window button
385 // which bypasses the LFUN machinery.
386 if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
387 if (!quitWriteAll()) {
388 close_event->ignore();
393 // Make sure that no LFUN use this close to be closed View.
394 theLyXFunc().setLyXView(0);
396 // Save toolbars configuration
397 if (isFullScreen()) {
398 d.toolbars_->toggleFullScreen(!isFullScreen());
402 // Make sure the timer time out will not trigger a statusbar update.
403 d.statusbar_timer_.stop();
405 // Saving fullscreen requires additional tweaks in the toolbar code.
406 // It wouldn't also work under linux natively.
407 if (lyxrc.allow_geometry_session && !isFullScreen()) {
409 QString const key = "view-" + QString::number(id_);
411 settings.setValue(key + "/pos", pos());
412 settings.setValue(key + "/size", size());
414 settings.setValue(key + "/geometry", saveGeometry());
416 settings.setValue(key + "/icon_size", iconSize());
417 d.toolbars_->saveToolbarInfo();
418 // Now take care of all other dialogs:
419 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
420 for (; it!= d.dialogs_.end(); ++it)
421 it->second->saveSession();
424 guiApp->unregisterView(id_);
425 if (guiApp->viewCount() > 0) {
426 // Just close the window and do nothing else if this is not the
428 close_event->accept();
434 // this is the place where we leave the frontend.
435 // it is the only point at which we start quitting.
436 close_event->accept();
437 // quit the event loop
442 void GuiView::dragEnterEvent(QDragEnterEvent * event)
444 if (event->mimeData()->hasUrls())
446 /// \todo Ask lyx-devel is this is enough:
447 /// if (event->mimeData()->hasFormat("text/plain"))
448 /// event->acceptProposedAction();
452 void GuiView::dropEvent(QDropEvent* event)
454 QList<QUrl> files = event->mimeData()->urls();
458 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
459 for (int i = 0; i != files.size(); ++i) {
460 string const file = os::internal_path(fromqstr(
461 files.at(i).toLocalFile()));
463 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
468 void GuiView::message(docstring const & str)
470 if (ForkedProcess::iAmAChild())
473 statusBar()->showMessage(toqstr(str));
474 d.statusbar_timer_.stop();
475 d.statusbar_timer_.start(3000);
479 void GuiView::smallSizedIcons()
481 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
485 void GuiView::normalSizedIcons()
487 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
491 void GuiView::bigSizedIcons()
493 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
497 void GuiView::clearMessage()
501 theLyXFunc().setLyXView(this);
502 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
503 d.statusbar_timer_.stop();
507 void GuiView::updateWindowTitle(GuiWorkArea * wa)
509 if (wa != d.current_work_area_)
511 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
512 setWindowIconText(wa->windowIconText());
516 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
519 disconnectBufferView();
520 connectBufferView(wa->bufferView());
521 connectBuffer(wa->bufferView().buffer());
522 d.current_work_area_ = wa;
523 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
524 this, SLOT(updateWindowTitle(GuiWorkArea *)));
525 updateWindowTitle(wa);
528 // Buffer-dependent dialogs should be updated or
529 // hidden. This should go here because some dialogs (eg ToC)
530 // require bv_->text.
531 updateBufferDependent(true);
538 void GuiView::updateStatusBar()
540 // let the user see the explicit message
541 if (d.statusbar_timer_.isActive())
544 theLyXFunc().setLyXView(this);
545 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
549 bool GuiView::hasFocus() const
551 return qApp->activeWindow() == this;
555 bool GuiView::event(QEvent * e)
559 // Useful debug code:
560 //case QEvent::ActivationChange:
561 //case QEvent::WindowDeactivate:
562 //case QEvent::Paint:
563 //case QEvent::Enter:
564 //case QEvent::Leave:
565 //case QEvent::HoverEnter:
566 //case QEvent::HoverLeave:
567 //case QEvent::HoverMove:
568 //case QEvent::StatusTip:
569 //case QEvent::DragEnter:
570 //case QEvent::DragLeave:
574 case QEvent::WindowActivate: {
575 guiApp->setCurrentView(*this);
576 if (d.current_work_area_) {
577 BufferView & bv = d.current_work_area_->bufferView();
578 connectBufferView(bv);
579 connectBuffer(bv.buffer());
580 // The document structure, name and dialogs might have
581 // changed in another view.
582 updateBufferDependent(true);
587 setWindowTitle(qt_("LyX"));
588 setWindowIconText(qt_("LyX"));
591 return QMainWindow::event(e);
594 case QEvent::ShortcutOverride: {
595 if (d.current_work_area_)
596 // Nothing special to do.
597 return QMainWindow::event(e);
599 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
601 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
603 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
604 || ke->key() == Qt::Key_Backtab)
605 return QMainWindow::event(e);
607 // Allow processing of shortcuts that are allowed even when no Buffer
609 theLyXFunc().setLyXView(this);
611 setKeySymbol(&sym, ke);
612 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
618 return QMainWindow::event(e);
623 bool GuiView::focusNextPrevChild(bool /*next*/)
630 void GuiView::setBusy(bool busy)
632 if (d.current_work_area_) {
633 d.current_work_area_->setUpdatesEnabled(!busy);
635 d.current_work_area_->stopBlinkingCursor();
637 d.current_work_area_->startBlinkingCursor();
641 QApplication::setOverrideCursor(Qt::WaitCursor);
643 QApplication::restoreOverrideCursor();
647 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
649 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
651 if (tbinfo.flags & ToolbarInfo::TOP) {
653 addToolBarBreak(Qt::TopToolBarArea);
654 addToolBar(Qt::TopToolBarArea, toolBar);
657 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
658 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
659 #if (QT_VERSION >= 0x040202)
661 addToolBarBreak(Qt::BottomToolBarArea);
663 addToolBar(Qt::BottomToolBarArea, toolBar);
666 if (tbinfo.flags & ToolbarInfo::LEFT) {
667 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
668 #if (QT_VERSION >= 0x040202)
670 addToolBarBreak(Qt::LeftToolBarArea);
672 addToolBar(Qt::LeftToolBarArea, toolBar);
675 if (tbinfo.flags & ToolbarInfo::RIGHT) {
676 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
677 #if (QT_VERSION >= 0x040202)
679 addToolBarBreak(Qt::RightToolBarArea);
681 addToolBar(Qt::RightToolBarArea, toolBar);
684 // The following does not work so I cannot restore to exact toolbar location
686 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
687 toolBar->move(tbinfo.posx, tbinfo.posy);
694 GuiWorkArea * GuiView::workArea(Buffer & buffer)
696 if (TabWorkArea * twa = d.currentTabWorkArea())
697 return twa->workArea(buffer);
702 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
704 // Automatically create a TabWorkArea if there are none yet.
705 TabWorkArea * tab_widget = d.splitter_->count()
706 ? d.currentTabWorkArea() : addTabWorkArea();
707 return tab_widget->addWorkArea(buffer, *this);
711 TabWorkArea * GuiView::addTabWorkArea()
713 TabWorkArea * twa = new TabWorkArea;
714 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
715 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
716 d.splitter_->addWidget(twa);
717 d.stack_widget_->setCurrentWidget(d.splitter_);
722 GuiWorkArea const * GuiView::currentWorkArea() const
724 return d.current_work_area_;
728 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
732 // Changing work area can result from opening a file so
733 // update the toc in any case.
736 d.current_work_area_ = wa;
737 for (int i = 0; i != d.splitter_->count(); ++i) {
738 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
744 void GuiView::removeWorkArea(GuiWorkArea * wa)
747 if (wa == d.current_work_area_) {
749 disconnectBufferView();
750 hideBufferDependent();
751 d.current_work_area_ = 0;
754 for (int i = 0; i != d.splitter_->count(); ++i) {
755 TabWorkArea * twa = d.tabWorkArea(i);
756 if (!twa->removeWorkArea(wa))
757 // Not found in this tab group.
760 // We found and removed the GuiWorkArea.
762 // No more WorkAreas in this tab group, so delete it.
767 if (d.current_work_area_)
768 // This means that we are not closing the current GuiWorkArea;
771 // Switch to the next GuiWorkArea in the found TabWorkArea.
772 d.current_work_area_ = twa->currentWorkArea();
776 if (d.splitter_->count() == 0)
777 // No more work area, switch to the background widget.
782 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
788 void GuiView::updateLayoutList()
791 d.layout_->updateContents(false);
795 void GuiView::updateToolbars()
797 if (d.current_work_area_) {
799 d.current_work_area_->bufferView().cursor().inMathed();
801 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
803 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
804 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
805 bool const mathmacrotemplate =
806 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
808 d.toolbars_->update(math, table, review, mathmacrotemplate);
810 d.toolbars_->update(false, false, false, false);
812 // update read-only status of open dialogs.
817 Buffer * GuiView::buffer()
819 if (d.current_work_area_)
820 return &d.current_work_area_->bufferView().buffer();
825 Buffer const * GuiView::buffer() const
827 if (d.current_work_area_)
828 return &d.current_work_area_->bufferView().buffer();
833 void GuiView::setBuffer(Buffer * newBuffer)
835 BOOST_ASSERT(newBuffer);
838 GuiWorkArea * wa = workArea(*newBuffer);
840 updateLabels(*newBuffer->masterBuffer());
841 wa = addWorkArea(*newBuffer);
843 //Disconnect the old buffer...there's no new one.
846 connectBuffer(*newBuffer);
847 connectBufferView(wa->bufferView());
848 setCurrentWorkArea(wa);
854 void GuiView::connectBuffer(Buffer & buf)
856 buf.setGuiDelegate(this);
860 void GuiView::disconnectBuffer()
862 if (d.current_work_area_)
863 d.current_work_area_->bufferView().setGuiDelegate(0);
867 void GuiView::connectBufferView(BufferView & bv)
869 bv.setGuiDelegate(this);
873 void GuiView::disconnectBufferView()
875 if (d.current_work_area_)
876 d.current_work_area_->bufferView().setGuiDelegate(0);
880 void GuiView::errors(string const & error_type)
882 ErrorList & el = buffer()->errorList(error_type);
884 showDialog("errorlist", error_type);
888 void GuiView::updateDialog(string const & name, string const & data)
890 if (!isDialogVisible(name))
893 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
894 if (it == d.dialogs_.end())
897 Dialog * const dialog = it->second.get();
898 if (dialog->isVisibleView())
899 dialog->updateData(data);
903 BufferView * GuiView::view()
905 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
909 void GuiView::updateToc()
911 updateDialog("toc", "");
915 void GuiView::updateEmbeddedFiles()
917 updateDialog("embedding", "");
921 void GuiView::autoSave()
923 LYXERR(Debug::INFO, "Running autoSave()");
926 view()->buffer().autoSave();
930 void GuiView::resetAutosaveTimers()
933 d.autosave_timeout_.restart();
937 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
941 Buffer * buf = buffer();
943 /* In LyX/Mac, when a dialog is open, the menus of the
944 application can still be accessed without giving focus to
945 the main window. In this case, we want to disable the menu
946 entries that are buffer-related.
948 Note that this code is not perfect, as bug 1941 attests:
949 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
951 if (cmd.origin == FuncRequest::MENU && !hasFocus())
955 case LFUN_BUFFER_WRITE:
956 enable = buf && (buf->isUnnamed() || !buf->isClean());
959 case LFUN_BUFFER_WRITE_AS:
963 case LFUN_SPLIT_VIEW:
967 case LFUN_CLOSE_TAB_GROUP:
968 enable = d.currentTabWorkArea();
971 case LFUN_TOOLBAR_TOGGLE:
972 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
975 case LFUN_DIALOG_TOGGLE:
976 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
977 // fall through to set "enable"
978 case LFUN_DIALOG_SHOW: {
979 string const name = cmd.getArg(0);
981 enable = name == "aboutlyx"
982 || name == "file" //FIXME: should be removed.
984 || name == "texinfo";
985 else if (name == "print")
986 enable = buf->isExportable("dvi")
987 && lyxrc.print_command != "none";
988 else if (name == "character") {
992 InsetCode ic = view()->cursor().inset().lyxCode();
993 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
996 else if (name == "symbols") {
997 if (!view() || view()->cursor().inMathed())
1000 InsetCode ic = view()->cursor().inset().lyxCode();
1001 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1004 else if (name == "latexlog")
1005 enable = FileName(buf->logName()).isReadableFile();
1006 else if (name == "spellchecker")
1007 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1008 enable = !buf->isReadonly();
1012 else if (name == "vclog")
1013 enable = buf->lyxvc().inUse();
1017 case LFUN_DIALOG_UPDATE: {
1018 string const name = cmd.getArg(0);
1020 enable = name == "prefs";
1024 case LFUN_INSET_APPLY: {
1029 string const name = cmd.getArg(0);
1030 Inset * inset = getOpenInset(name);
1032 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1034 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1035 // Every inset is supposed to handle this
1036 BOOST_ASSERT(false);
1040 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1041 flag |= getStatus(fr);
1043 enable = flag.enabled();
1047 case LFUN_COMPLETION_INLINE:
1048 if (!d.current_work_area_
1049 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1053 case LFUN_COMPLETION_POPUP:
1054 if (!d.current_work_area_
1055 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1059 case LFUN_COMPLETION_COMPLETE:
1060 if (!d.current_work_area_
1061 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1073 flag.enabled(false);
1079 static FileName selectTemplateFile()
1081 FileDialog dlg(_("Select template file"));
1082 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1083 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1085 FileDialog::Result result =
1086 dlg.open(from_utf8(lyxrc.template_path),
1087 FileFilterList(_("LyX Documents (*.lyx)")),
1090 if (result.first == FileDialog::Later)
1092 if (result.second.empty())
1094 return FileName(to_utf8(result.second));
1098 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1102 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1105 message(_("Document not loaded."));
1110 setBuffer(newBuffer);
1112 // scroll to the position when the file was last closed
1113 if (lyxrc.use_lastfilepos) {
1114 LastFilePosSection::FilePos filepos =
1115 LyX::ref().session().lastFilePos().load(filename);
1116 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1120 LyX::ref().session().lastFiles().add(filename);
1127 void GuiView::openDocument(string const & fname)
1129 string initpath = lyxrc.document_path;
1132 string const trypath = buffer()->filePath();
1133 // If directory is writeable, use this as default.
1134 if (FileName(trypath).isDirWritable())
1140 if (fname.empty()) {
1141 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
1142 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1143 dlg.setButton2(_("Examples|#E#e"),
1144 from_utf8(addPath(package().system_support().absFilename(), "examples")));
1146 FileDialog::Result result =
1147 dlg.open(from_utf8(initpath),
1148 FileFilterList(_("LyX Documents (*.lyx)")),
1151 if (result.first == FileDialog::Later)
1154 filename = to_utf8(result.second);
1156 // check selected filename
1157 if (filename.empty()) {
1158 message(_("Canceled."));
1164 // get absolute path of file and add ".lyx" to the filename if
1166 FileName const fullname =
1167 fileSearch(string(), filename, "lyx", support::may_not_exist);
1168 if (!fullname.empty())
1169 filename = fullname.absFilename();
1171 // if the file doesn't exist, let the user create one
1172 if (!fullname.exists()) {
1173 // the user specifically chose this name. Believe him.
1174 Buffer * const b = newFile(filename, string(), true);
1180 docstring const disp_fn = makeDisplayPath(filename);
1181 message(bformat(_("Opening document %1$s..."), disp_fn));
1184 Buffer * buf = loadDocument(fullname);
1188 buf->errors("Parse");
1189 str2 = bformat(_("Document %1$s opened."), disp_fn);
1191 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1196 // FIXME: clean that
1197 static bool import(GuiView * lv, FileName const & filename,
1198 string const & format, ErrorList & errorList)
1200 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
1202 string loader_format;
1203 vector<string> loaders = theConverters().loaders();
1204 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1205 for (vector<string>::const_iterator it = loaders.begin();
1206 it != loaders.end(); ++it) {
1207 if (!theConverters().isReachable(format, *it))
1210 string const tofile =
1211 changeExtension(filename.absFilename(),
1212 formats.extension(*it));
1213 if (!theConverters().convert(0, filename, FileName(tofile),
1214 filename, format, *it, errorList))
1216 loader_format = *it;
1219 if (loader_format.empty()) {
1220 frontend::Alert::error(_("Couldn't import file"),
1221 bformat(_("No information for importing the format %1$s."),
1222 formats.prettyName(format)));
1226 loader_format = format;
1228 if (loader_format == "lyx") {
1229 Buffer * buf = lv->loadDocument(lyxfile);
1234 buf->errors("Parse");
1236 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1240 bool as_paragraphs = loader_format == "textparagraph";
1241 string filename2 = (loader_format == format) ? filename.absFilename()
1242 : changeExtension(filename.absFilename(),
1243 formats.extension(loader_format));
1244 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1245 theLyXFunc().setLyXView(lv);
1246 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1253 void GuiView::importDocument(string const & argument)
1256 string filename = split(argument, format, ' ');
1258 LYXERR(Debug::INFO, format << " file: " << filename);
1260 // need user interaction
1261 if (filename.empty()) {
1262 string initpath = lyxrc.document_path;
1264 Buffer const * buf = buffer();
1266 string const trypath = buf->filePath();
1267 // If directory is writeable, use this as default.
1268 if (FileName(trypath).isDirWritable())
1272 docstring const text = bformat(_("Select %1$s file to import"),
1273 formats.prettyName(format));
1275 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
1276 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1277 dlg.setButton2(_("Examples|#E#e"),
1278 from_utf8(addPath(package().system_support().absFilename(), "examples")));
1280 docstring filter = formats.prettyName(format);
1283 filter += from_utf8(formats.extension(format));
1286 FileDialog::Result result =
1287 dlg.open(from_utf8(initpath),
1288 FileFilterList(filter),
1291 if (result.first == FileDialog::Later)
1294 filename = to_utf8(result.second);
1296 // check selected filename
1297 if (filename.empty())
1298 message(_("Canceled."));
1301 if (filename.empty())
1304 // get absolute path of file
1305 FileName const fullname(makeAbsPath(filename));
1307 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
1309 // Check if the document already is open
1310 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1313 if (!closeBuffer()) {
1314 message(_("Canceled."));
1319 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1321 // if the file exists already, and we didn't do
1322 // -i lyx thefile.lyx, warn
1323 if (lyxfile.exists() && fullname != lyxfile) {
1325 docstring text = bformat(_("The document %1$s already exists.\n\n"
1326 "Do you want to overwrite that document?"), displaypath);
1327 int const ret = Alert::prompt(_("Overwrite document?"),
1328 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1331 message(_("Canceled."));
1336 message(bformat(_("Importing %1$s..."), displaypath));
1337 ErrorList errorList;
1338 if (import(this, fullname, format, errorList))
1339 message(_("imported."));
1341 message(_("file not imported!"));
1343 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1347 void GuiView::newDocument(string const & filename, bool from_template)
1349 FileName initpath(lyxrc.document_path);
1350 Buffer * buf = buffer();
1352 FileName const trypath(buf->filePath());
1353 // If directory is writeable, use this as default.
1354 if (trypath.isDirWritable())
1358 string templatefile = from_template ?
1359 selectTemplateFile().absFilename() : string();
1361 if (filename.empty())
1362 b = newUnnamedFile(templatefile, initpath);
1364 b = newFile(filename, templatefile, true);
1368 // Ensure the cursor is correctly positionned on screen.
1369 view()->showCursor();
1373 void GuiView::insertLyXFile(docstring const & fname)
1375 BufferView * bv = view();
1380 FileName filename(to_utf8(fname));
1382 if (!filename.empty()) {
1383 bv->insertLyXFile(filename);
1387 // Launch a file browser
1389 string initpath = lyxrc.document_path;
1390 string const trypath = bv->buffer().filePath();
1391 // If directory is writeable, use this as default.
1392 if (FileName(trypath).isDirWritable())
1396 FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT);
1397 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1398 dlg.setButton2(_("Examples|#E#e"),
1399 from_utf8(addPath(package().system_support().absFilename(),
1402 FileDialog::Result result =
1403 dlg.open(from_utf8(initpath),
1404 FileFilterList(_("LyX Documents (*.lyx)")),
1407 if (result.first == FileDialog::Later)
1411 filename.set(to_utf8(result.second));
1413 // check selected filename
1414 if (filename.empty()) {
1415 // emit message signal.
1416 message(_("Canceled."));
1420 bv->insertLyXFile(filename);
1424 void GuiView::insertPlaintextFile(docstring const & fname,
1427 BufferView * bv = view();
1432 FileName filename(to_utf8(fname));
1434 if (!filename.empty()) {
1435 bv->insertPlaintextFile(filename, asParagraph);
1439 FileDialog dlg(_("Select file to insert"), (asParagraph ?
1440 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1442 FileDialog::Result result = dlg.open(from_utf8(bv->buffer().filePath()),
1443 FileFilterList(), docstring());
1445 if (result.first == FileDialog::Later)
1449 filename.set(to_utf8(result.second));
1451 // check selected filename
1452 if (filename.empty()) {
1453 // emit message signal.
1454 message(_("Canceled."));
1458 bv->insertPlaintextFile(filename, asParagraph);
1462 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1464 FileName fname = b.fileName();
1465 FileName const oldname = fname;
1467 if (!newname.empty()) {
1469 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1471 // Switch to this Buffer.
1474 /// No argument? Ask user through dialog.
1476 FileDialog dlg(_("Choose a filename to save document as"),
1477 LFUN_BUFFER_WRITE_AS);
1478 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1479 dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
1481 if (!isLyXFilename(fname.absFilename()))
1482 fname.changeExtension(".lyx");
1484 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1486 FileDialog::Result result =
1487 dlg.save(from_utf8(fname.onlyPath().absFilename()),
1489 from_utf8(fname.onlyFileName()));
1491 if (result.first == FileDialog::Later)
1494 fname.set(to_utf8(result.second));
1499 if (!isLyXFilename(fname.absFilename()))
1500 fname.changeExtension(".lyx");
1503 if (FileName(fname).exists()) {
1504 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1505 docstring text = bformat(_("The document %1$s already "
1506 "exists.\n\nDo you want to "
1507 "overwrite that document?"),
1509 int const ret = Alert::prompt(_("Overwrite document?"),
1510 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1513 case 1: return renameBuffer(b, docstring());
1514 case 2: return false;
1518 // Ok, change the name of the buffer
1519 b.setFileName(fname.absFilename());
1521 bool unnamed = b.isUnnamed();
1522 b.setUnnamed(false);
1523 b.saveCheckSum(fname);
1525 if (!saveBuffer(b)) {
1526 b.setFileName(oldname.absFilename());
1527 b.setUnnamed(unnamed);
1528 b.saveCheckSum(oldname);
1536 bool GuiView::saveBuffer(Buffer & b)
1539 return renameBuffer(b, docstring());
1542 LyX::ref().session().lastFiles().add(b.fileName());
1546 // Switch to this Buffer.
1549 // FIXME: we don't tell the user *WHY* the save failed !!
1550 docstring const file = makeDisplayPath(b.absFileName(), 30);
1551 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1552 "Do you want to rename the document and "
1553 "try again?"), file);
1554 int const ret = Alert::prompt(_("Rename and save?"),
1555 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1558 if (!renameBuffer(b, docstring()))
1567 return saveBuffer(b);
1571 bool GuiView::closeBuffer()
1573 Buffer * buf = buffer();
1574 return buf && closeBuffer(*buf);
1578 bool GuiView::closeBuffer(Buffer & buf)
1580 if (buf.isClean() || buf.paragraphs().empty()) {
1581 theBufferList().release(&buf);
1584 // Switch to this Buffer.
1589 if (buf.isUnnamed())
1590 file = from_utf8(buf.fileName().onlyFileName());
1592 file = buf.fileName().displayName(30);
1594 docstring const text = bformat(_("The document %1$s has unsaved changes."
1595 "\n\nDo you want to save the document or discard the changes?"), file);
1596 int const ret = Alert::prompt(_("Save changed document?"),
1597 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1601 if (!saveBuffer(buf))
1605 // if we crash after this we could
1606 // have no autosave file but I guess
1607 // this is really improbable (Jug)
1608 removeAutosaveFile(buf.absFileName());
1614 // save file names to .lyx/session
1615 // if master/slave are both open, do not save slave since it
1616 // will be automatically loaded when the master is loaded
1617 if (buf.masterBuffer() == &buf)
1618 LyX::ref().session().lastOpened().add(buf.fileName());
1620 theBufferList().release(&buf);
1625 bool GuiView::quitWriteAll()
1627 while (!theBufferList().empty()) {
1628 Buffer * b = theBufferList().first();
1629 if (!closeBuffer(*b))
1636 bool GuiView::dispatch(FuncRequest const & cmd)
1638 BufferView * bv = view();
1639 // By default we won't need any update.
1641 bv->cursor().updateFlags(Update::None);
1643 switch(cmd.action) {
1644 case LFUN_FILE_OPEN:
1645 openDocument(to_utf8(cmd.argument()));
1648 case LFUN_BUFFER_IMPORT:
1649 importDocument(to_utf8(cmd.argument()));
1652 case LFUN_BUFFER_SWITCH:
1653 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1656 case LFUN_BUFFER_NEXT:
1657 setBuffer(theBufferList().next(buffer()));
1660 case LFUN_BUFFER_PREVIOUS:
1661 setBuffer(theBufferList().previous(buffer()));
1664 case LFUN_COMMAND_EXECUTE: {
1665 bool const show_it = cmd.argument() != "off";
1666 d.toolbars_->showCommandBuffer(show_it);
1669 case LFUN_DROP_LAYOUTS_CHOICE:
1671 d.layout_->showPopup();
1674 case LFUN_MENU_OPEN:
1675 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument())))
1676 menu->exec(QCursor::pos());
1679 case LFUN_FILE_INSERT:
1680 insertLyXFile(cmd.argument());
1682 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1683 insertPlaintextFile(cmd.argument(), true);
1686 case LFUN_FILE_INSERT_PLAINTEXT:
1687 insertPlaintextFile(cmd.argument(), false);
1690 case LFUN_BUFFER_WRITE:
1692 saveBuffer(bv->buffer());
1695 case LFUN_BUFFER_WRITE_AS:
1697 renameBuffer(bv->buffer(), cmd.argument());
1700 case LFUN_BUFFER_WRITE_ALL: {
1701 Buffer * first = theBufferList().first();
1704 message(_("Saving all documents..."));
1705 // We cannot use a for loop as the buffer list cycles.
1711 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1712 b = theBufferList().next(b);
1713 } while (b != first);
1714 message(_("All documents saved."));
1718 case LFUN_TOOLBAR_TOGGLE: {
1719 string const name = cmd.getArg(0);
1720 bool const allowauto = cmd.getArg(1) == "allowauto";
1721 // it is possible to get current toolbar status like this,...
1722 // but I decide to obey the order of ToolbarBackend::flags
1723 // and disregard real toolbar status.
1724 // toolbars_->saveToolbarInfo();
1726 // toggle state on/off/auto
1727 d.toolbars_->toggleToolbarState(name, allowauto);
1731 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1733 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1737 if (tbi->flags & ToolbarInfo::ON)
1739 else if (tbi->flags & ToolbarInfo::OFF)
1741 else if (tbi->flags & ToolbarInfo::AUTO)
1744 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1745 _(tbi->gui_name), state));
1749 case LFUN_DIALOG_UPDATE: {
1750 string const name = to_utf8(cmd.argument());
1751 // Can only update a dialog connected to an existing inset
1752 Inset * inset = getOpenInset(name);
1754 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1755 inset->dispatch(view()->cursor(), fr);
1756 } else if (name == "paragraph") {
1757 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1758 } else if (name == "prefs") {
1759 updateDialog(name, string());
1764 case LFUN_DIALOG_TOGGLE: {
1765 if (isDialogVisible(cmd.getArg(0)))
1766 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1768 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1772 case LFUN_DIALOG_DISCONNECT_INSET:
1773 disconnectDialog(to_utf8(cmd.argument()));
1776 case LFUN_DIALOG_HIDE: {
1779 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1783 case LFUN_DIALOG_SHOW: {
1784 string const name = cmd.getArg(0);
1785 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1787 if (name == "character") {
1788 data = freefont2string();
1790 showDialog("character", data);
1791 } else if (name == "latexlog") {
1792 Buffer::LogType type;
1793 string const logfile = buffer()->logName(&type);
1795 case Buffer::latexlog:
1798 case Buffer::buildlog:
1802 data += Lexer::quoteString(logfile);
1803 showDialog("log", data);
1804 } else if (name == "vclog") {
1805 string const data = "vc " +
1806 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1807 showDialog("log", data);
1808 } else if (name == "symbols") {
1809 data = bv->cursor().getEncoding()->name();
1811 showDialog("symbols", data);
1813 showDialog(name, data);
1817 case LFUN_INSET_APPLY: {
1818 string const name = cmd.getArg(0);
1819 Inset * inset = getOpenInset(name);
1821 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1822 inset->dispatch(view()->cursor(), fr);
1824 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1830 case LFUN_UI_TOGGLE:
1832 // Make sure the keyboard focus stays in the work area.
1836 case LFUN_COMPLETION_INLINE:
1837 if (d.current_work_area_)
1838 d.current_work_area_->completer().showInline();
1841 case LFUN_SPLIT_VIEW:
1842 if (Buffer * buf = buffer()) {
1843 string const orientation = cmd.getArg(0);
1844 d.splitter_->setOrientation(orientation == "vertical"
1845 ? Qt::Vertical : Qt::Horizontal);
1846 TabWorkArea * twa = addTabWorkArea();
1847 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1848 setCurrentWorkArea(wa);
1852 case LFUN_CLOSE_TAB_GROUP:
1853 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1855 twa = d.currentTabWorkArea();
1856 // Switch to the next GuiWorkArea in the found TabWorkArea.
1857 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1858 if (d.splitter_->count() == 0)
1859 // No more work area, switch to the background widget.
1864 case LFUN_COMPLETION_POPUP:
1865 if (d.current_work_area_)
1866 d.current_work_area_->completer().showPopup();
1870 case LFUN_COMPLETION_COMPLETE:
1871 if (d.current_work_area_)
1872 d.current_work_area_->completer().tab();
1883 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1885 string const arg = cmd.getArg(0);
1886 if (arg == "scrollbar") {
1887 // hide() is of no help
1888 if (d.current_work_area_->verticalScrollBarPolicy() ==
1889 Qt::ScrollBarAlwaysOff)
1891 d.current_work_area_->setVerticalScrollBarPolicy(
1892 Qt::ScrollBarAsNeeded);
1894 d.current_work_area_->setVerticalScrollBarPolicy(
1895 Qt::ScrollBarAlwaysOff);
1898 if (arg == "statusbar") {
1899 statusBar()->setVisible(!statusBar()->isVisible());
1902 if (arg == "menubar") {
1903 menuBar()->setVisible(!menuBar()->isVisible());
1906 #if QT_VERSION >= 0x040300
1907 if (arg == "frame") {
1909 getContentsMargins(&l, &t, &r, &b);
1910 //are the frames in default state?
1912 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1913 setContentsMargins(-2, -2, -2, -2);
1915 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1916 setContentsMargins(0, 0, 0, 0);
1921 if (arg != "fullscreen") {
1922 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1926 if (lyxrc.full_screen_toolbars)
1927 d.toolbars_->toggleFullScreen(!isFullScreen());
1929 if (isFullScreen()) {
1930 for (int i = 0; i != d.splitter_->count(); ++i)
1931 d.tabWorkArea(i)->setFullScreen(false);
1932 #if QT_VERSION >= 0x040300
1933 setContentsMargins(0, 0, 0, 0);
1937 statusBar()->show();
1939 for (int i = 0; i != d.splitter_->count(); ++i)
1940 d.tabWorkArea(i)->setFullScreen(true);
1941 #if QT_VERSION >= 0x040300
1942 setContentsMargins(-2, -2, -2, -2);
1945 statusBar()->hide();
1951 Buffer const * GuiView::updateInset(Inset const * inset)
1953 if (!d.current_work_area_)
1957 d.current_work_area_->scheduleRedraw();
1959 return &d.current_work_area_->bufferView().buffer();
1963 void GuiView::restartCursor()
1965 /* When we move around, or type, it's nice to be able to see
1966 * the cursor immediately after the keypress.
1968 if (d.current_work_area_)
1969 d.current_work_area_->startBlinkingCursor();
1971 // Take this occasion to update the toobars and layout list.
1977 void GuiView::updateCompletion(bool start, bool keep)
1979 if (d.current_work_area_)
1980 d.current_work_area_->completer().updateVisibility(start, keep);
1985 // This list should be kept in sync with the list of insets in
1986 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1987 // dialog should have the same name as the inset.
1989 char const * const dialognames[] = {
1990 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1991 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1992 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1993 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
1994 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1996 #ifdef HAVE_LIBAIKSAURUS
2000 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2002 char const * const * const end_dialognames =
2003 dialognames + (sizeof(dialognames) / sizeof(char *));
2007 cmpCStr(char const * name) : name_(name) {}
2008 bool operator()(char const * other) {
2009 return strcmp(other, name_) == 0;
2016 bool isValidName(string const & name)
2018 return find_if(dialognames, end_dialognames,
2019 cmpCStr(name.c_str())) != end_dialognames;
2025 void GuiView::resetDialogs()
2027 // Make sure that no LFUN uses any LyXView.
2028 theLyXFunc().setLyXView(0);
2029 // FIXME: the "math panels" toolbar takes an awful lot of time to
2030 // initialise so we don't do that for the time being.
2031 //d.toolbars_->init();
2032 guiApp->menus().fillMenuBar(this);
2034 d.layout_->updateContents(true);
2035 // Now update controls with current buffer.
2036 theLyXFunc().setLyXView(this);
2041 Dialog * GuiView::find_or_build(string const & name)
2043 if (!isValidName(name))
2046 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2048 if (it != d.dialogs_.end())
2049 return it->second.get();
2051 Dialog * dialog = build(name);
2052 d.dialogs_[name].reset(dialog);
2053 if (lyxrc.allow_geometry_session)
2054 dialog->restoreSession();
2059 void GuiView::showDialog(string const & name, string const & data,
2066 Dialog * dialog = find_or_build(name);
2068 dialog->showData(data);
2070 d.open_insets_[name] = inset;
2076 bool GuiView::isDialogVisible(string const & name) const
2078 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2079 if (it == d.dialogs_.end())
2081 return it->second.get()->isVisibleView();
2085 void GuiView::hideDialog(string const & name, Inset * inset)
2087 // Don't send the signal if we are quitting, because on MSVC it is
2088 // destructed before the cut stack in CutAndPaste.cpp, and this method
2089 // is called from some inset destructor if the cut stack is not empty
2094 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2095 if (it == d.dialogs_.end())
2098 if (inset && inset != getOpenInset(name))
2101 Dialog * const dialog = it->second.get();
2102 if (dialog->isVisibleView())
2104 d.open_insets_[name] = 0;
2108 void GuiView::disconnectDialog(string const & name)
2110 if (!isValidName(name))
2113 if (d.open_insets_.find(name) != d.open_insets_.end())
2114 d.open_insets_[name] = 0;
2118 Inset * GuiView::getOpenInset(string const & name) const
2120 if (!isValidName(name))
2123 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2124 return it == d.open_insets_.end() ? 0 : it->second;
2128 void GuiView::hideAll() const
2130 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2131 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2133 for(; it != end; ++it)
2134 it->second->hideView();
2138 void GuiView::hideBufferDependent() const
2140 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2141 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2143 for(; it != end; ++it) {
2144 Dialog * dialog = it->second.get();
2145 if (dialog->isBufferDependent())
2151 void GuiView::updateBufferDependent(bool switched) const
2153 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2154 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2156 for(; it != end; ++it) {
2157 Dialog * dialog = it->second.get();
2158 if (!dialog->isVisibleView())
2160 if (switched && dialog->isBufferDependent()) {
2161 if (dialog->initialiseParams(""))
2162 dialog->updateView();
2166 // A bit clunky, but the dialog will request
2167 // that the kernel provides it with the necessary
2169 dialog->updateDialog();
2175 void GuiView::checkStatus()
2177 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2178 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2180 for(; it != end; ++it) {
2181 Dialog * const dialog = it->second.get();
2182 if (dialog && dialog->isVisibleView())
2183 dialog->checkStatus();
2189 // will be replaced by a proper factory...
2190 Dialog * createGuiAbout(GuiView & lv);
2191 Dialog * createGuiBibitem(GuiView & lv);
2192 Dialog * createGuiBibtex(GuiView & lv);
2193 Dialog * createGuiBox(GuiView & lv);
2194 Dialog * createGuiBranch(GuiView & lv);
2195 Dialog * createGuiChanges(GuiView & lv);
2196 Dialog * createGuiCharacter(GuiView & lv);
2197 Dialog * createGuiCitation(GuiView & lv);
2198 Dialog * createGuiDelimiter(GuiView & lv);
2199 Dialog * createGuiDocument(GuiView & lv);
2200 Dialog * createGuiErrorList(GuiView & lv);
2201 Dialog * createGuiERT(GuiView & lv);
2202 Dialog * createGuiExternal(GuiView & lv);
2203 Dialog * createGuiFloat(GuiView & lv);
2204 Dialog * createGuiGraphics(GuiView & lv);
2205 Dialog * createGuiInclude(GuiView & lv);
2206 Dialog * createGuiLabel(GuiView & lv);
2207 Dialog * createGuiListings(GuiView & lv);
2208 Dialog * createGuiLog(GuiView & lv);
2209 Dialog * createGuiMathMatrix(GuiView & lv);
2210 Dialog * createGuiNomenclature(GuiView & lv);
2211 Dialog * createGuiNote(GuiView & lv);
2212 Dialog * createGuiParagraph(GuiView & lv);
2213 Dialog * createGuiPreferences(GuiView & lv);
2214 Dialog * createGuiPrint(GuiView & lv);
2215 Dialog * createGuiRef(GuiView & lv);
2216 Dialog * createGuiSearch(GuiView & lv);
2217 Dialog * createGuiSendTo(GuiView & lv);
2218 Dialog * createGuiShowFile(GuiView & lv);
2219 Dialog * createGuiSpellchecker(GuiView & lv);
2220 Dialog * createGuiSymbols(GuiView & lv);
2221 Dialog * createGuiTabularCreate(GuiView & lv);
2222 Dialog * createGuiTabular(GuiView & lv);
2223 Dialog * createGuiTexInfo(GuiView & lv);
2224 Dialog * createGuiToc(GuiView & lv);
2225 Dialog * createGuiThesaurus(GuiView & lv);
2226 Dialog * createGuiHyperlink(GuiView & lv);
2227 Dialog * createGuiVSpace(GuiView & lv);
2228 Dialog * createGuiViewSource(GuiView & lv);
2229 Dialog * createGuiWrap(GuiView & lv);
2232 Dialog * GuiView::build(string const & name)
2234 BOOST_ASSERT(isValidName(name));
2236 if (name == "aboutlyx")
2237 return createGuiAbout(*this);
2238 if (name == "bibitem")
2239 return createGuiBibitem(*this);
2240 if (name == "bibtex")
2241 return createGuiBibtex(*this);
2243 return createGuiBox(*this);
2244 if (name == "branch")
2245 return createGuiBranch(*this);
2246 if (name == "changes")
2247 return createGuiChanges(*this);
2248 if (name == "character")
2249 return createGuiCharacter(*this);
2250 if (name == "citation")
2251 return createGuiCitation(*this);
2252 if (name == "document")
2253 return createGuiDocument(*this);
2254 if (name == "errorlist")
2255 return createGuiErrorList(*this);
2257 return createGuiERT(*this);
2258 if (name == "external")
2259 return createGuiExternal(*this);
2261 return createGuiShowFile(*this);
2262 if (name == "findreplace")
2263 return createGuiSearch(*this);
2264 if (name == "float")
2265 return createGuiFloat(*this);
2266 if (name == "graphics")
2267 return createGuiGraphics(*this);
2268 if (name == "include")
2269 return createGuiInclude(*this);
2270 if (name == "nomenclature")
2271 return createGuiNomenclature(*this);
2272 if (name == "label")
2273 return createGuiLabel(*this);
2275 return createGuiLog(*this);
2276 if (name == "view-source")
2277 return createGuiViewSource(*this);
2278 if (name == "mathdelimiter")
2279 return createGuiDelimiter(*this);
2280 if (name == "mathmatrix")
2281 return createGuiMathMatrix(*this);
2283 return createGuiNote(*this);
2284 if (name == "paragraph")
2285 return createGuiParagraph(*this);
2286 if (name == "prefs")
2287 return createGuiPreferences(*this);
2288 if (name == "print")
2289 return createGuiPrint(*this);
2291 return createGuiRef(*this);
2292 if (name == "sendto")
2293 return createGuiSendTo(*this);
2294 if (name == "spellchecker")
2295 return createGuiSpellchecker(*this);
2296 if (name == "symbols")
2297 return createGuiSymbols(*this);
2298 if (name == "tabular")
2299 return createGuiTabular(*this);
2300 if (name == "tabularcreate")
2301 return createGuiTabularCreate(*this);
2302 if (name == "texinfo")
2303 return createGuiTexInfo(*this);
2304 #ifdef HAVE_LIBAIKSAURUS
2305 if (name == "thesaurus")
2306 return createGuiThesaurus(*this);
2309 return createGuiToc(*this);
2311 return createGuiHyperlink(*this);
2312 if (name == "vspace")
2313 return createGuiVSpace(*this);
2315 return createGuiWrap(*this);
2316 if (name == "listings")
2317 return createGuiListings(*this);
2323 } // namespace frontend
2326 #include "GuiView_moc.cpp"