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 "FuncStatus.h"
41 #include "FuncRequest.h"
42 #include "support/gettext.h"
50 #include "Paragraph.h"
51 #include "TextClass.h"
53 #include "ToolbarBackend.h"
56 #include "support/debug.h"
57 #include "support/FileFilterList.h"
58 #include "support/FileName.h"
59 #include "support/filetools.h"
60 #include "support/ForkedCalls.h"
61 #include "support/lstrings.h"
62 #include "support/os.h"
63 #include "support/Package.h"
64 #include "support/Timeout.h"
67 #include <QApplication>
68 #include <QCloseEvent>
70 #include <QDesktopWidget>
71 #include <QDragEnterEvent>
79 #include <QPushButton>
83 #include <QStackedWidget>
90 #include <boost/assert.hpp>
91 #include <boost/bind.hpp>
93 #ifdef HAVE_SYS_TIME_H
94 # include <sys/time.h>
101 using namespace lyx::support;
108 class BackgroundWidget : public QWidget
113 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
114 /// The text to be written on top of the pixmap
115 QString const text = lyx_version ? lyx_version : qt_("unknown version");
116 splash_ = QPixmap(":/images/banner.png");
118 QPainter pain(&splash_);
119 pain.setPen(QColor(255, 255, 0));
121 // The font used to display the version info
122 font.setStyleHint(QFont::SansSerif);
123 font.setWeight(QFont::Bold);
124 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
126 pain.drawText(260, 270, text);
129 void paintEvent(QPaintEvent *)
131 int x = (width() - splash_.width()) / 2;
132 int y = (height() - splash_.height()) / 2;
134 pain.drawPixmap(x, y, splash_);
144 typedef boost::shared_ptr<Dialog> DialogPtr;
146 struct GuiView::GuiViewPrivate
149 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
152 // hardcode here the platform specific icon size
153 smallIconSize = 14; // scaling problems
154 normalIconSize = 20; // ok, default
155 bigIconSize = 26; // better for some math icons
157 splitter_ = new QSplitter;
158 bg_widget_ = new BackgroundWidget;
159 stack_widget_ = new QStackedWidget;
160 stack_widget_->addWidget(bg_widget_);
161 stack_widget_->addWidget(splitter_);
169 delete stack_widget_;
173 QMenu * toolBarPopup(GuiView * parent)
175 // FIXME: translation
176 QMenu * menu = new QMenu(parent);
177 QActionGroup * iconSizeGroup = new QActionGroup(parent);
179 QAction * smallIcons = new QAction(iconSizeGroup);
180 smallIcons->setText(qt_("Small-sized icons"));
181 smallIcons->setCheckable(true);
182 QObject::connect(smallIcons, SIGNAL(triggered()),
183 parent, SLOT(smallSizedIcons()));
184 menu->addAction(smallIcons);
186 QAction * normalIcons = new QAction(iconSizeGroup);
187 normalIcons->setText(qt_("Normal-sized icons"));
188 normalIcons->setCheckable(true);
189 QObject::connect(normalIcons, SIGNAL(triggered()),
190 parent, SLOT(normalSizedIcons()));
191 menu->addAction(normalIcons);
193 QAction * bigIcons = new QAction(iconSizeGroup);
194 bigIcons->setText(qt_("Big-sized icons"));
195 bigIcons->setCheckable(true);
196 QObject::connect(bigIcons, SIGNAL(triggered()),
197 parent, SLOT(bigSizedIcons()));
198 menu->addAction(bigIcons);
200 unsigned int cur = parent->iconSize().width();
201 if ( cur == parent->d.smallIconSize)
202 smallIcons->setChecked(true);
203 else if (cur == parent->d.normalIconSize)
204 normalIcons->setChecked(true);
205 else if (cur == parent->d.bigIconSize)
206 bigIcons->setChecked(true);
213 stack_widget_->setCurrentWidget(bg_widget_);
214 bg_widget_->setUpdatesEnabled(true);
217 TabWorkArea * tabWorkArea(int i)
219 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
222 TabWorkArea * currentTabWorkArea()
224 if (splitter_->count() == 1)
225 // The first TabWorkArea is always the first one, if any.
226 return tabWorkArea(0);
228 for (int i = 0; i != splitter_->count(); ++i) {
229 TabWorkArea * twa = tabWorkArea(i);
230 if (current_work_area_ == twa->currentWorkArea())
234 // None has the focus so we just take the first one.
235 return tabWorkArea(0);
239 GuiWorkArea * current_work_area_;
240 QSplitter * splitter_;
241 QStackedWidget * stack_widget_;
242 BackgroundWidget * bg_widget_;
244 GuiToolbars * toolbars_;
245 /// The main layout box.
247 * \warning Don't Delete! The layout box is actually owned by
248 * whichever toolbar contains it. All the GuiView class needs is a
249 * means of accessing it.
251 * FIXME: replace that with a proper model so that we are not limited
252 * to only one dialog.
254 GuiLayoutBox * layout_;
257 map<string, Inset *> open_insets_;
260 map<string, DialogPtr> dialogs_;
262 unsigned int smallIconSize;
263 unsigned int normalIconSize;
264 unsigned int bigIconSize;
266 QTimer statusbar_timer_;
267 /// auto-saving of buffers
268 Timeout autosave_timeout_;
269 /// flag against a race condition due to multiclicks, see bug #1119
274 GuiView::GuiView(int id)
275 : d(*new GuiViewPrivate), id_(id)
277 // GuiToolbars *must* be initialised before the menu bar.
278 d.toolbars_ = new GuiToolbars(*this);
280 // Fill up the menu bar.
281 guiApp->menus().fillMenuBar(this);
283 setCentralWidget(d.stack_widget_);
285 // Start autosave timer
286 if (lyxrc.autosave) {
287 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
288 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
289 d.autosave_timeout_.start();
291 connect(&d.statusbar_timer_, SIGNAL(timeout()),
292 this, SLOT(clearMessage()));
294 // We don't want to keep the window in memory if it is closed.
295 setAttribute(Qt::WA_DeleteOnClose, true);
298 // assign an icon to main form. We do not do it under Qt/Mac,
299 // since the icon is provided in the application bundle.
300 setWindowIcon(QPixmap(":/images/lyx.png"));
304 setAcceptDrops(true);
306 statusBar()->setSizeGripEnabled(true);
308 // Forbid too small unresizable window because it can happen
309 // with some window manager under X11.
310 setMinimumSize(300, 200);
312 if (!lyxrc.allow_geometry_session)
313 // No session handling, default to a sane size.
314 setGeometry(50, 50, 690, 510);
316 // Now take care of session management.
318 QString const key = "view-" + QString::number(id_);
320 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
321 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
325 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
326 setGeometry(50, 50, 690, 510);
328 setIconSize(settings.value(key + "/icon_size").toSize());
338 void GuiView::setFocus()
340 if (d.current_work_area_)
341 d.current_work_area_->setFocus();
347 QMenu * GuiView::createPopupMenu()
349 return d.toolBarPopup(this);
353 void GuiView::showEvent(QShowEvent * e)
355 LYXERR(Debug::GUI, "Passed Geometry "
356 << size().height() << "x" << size().width()
357 << "+" << pos().x() << "+" << pos().y());
359 if (d.splitter_->count() == 0)
360 // No work area, switch to the background widget.
363 QMainWindow::showEvent(e);
367 void GuiView::closeEvent(QCloseEvent * close_event)
369 while (Buffer * b = buffer()) {
371 // This is a child document, just close the tab after saving
372 // but keep the file loaded.
373 if (!saveBuffer(*b)) {
374 close_event->ignore();
377 removeWorkArea(d.current_work_area_);
381 std::vector<int> const & ids = guiApp->viewIds();
382 for (size_type i = 0; i != ids.size(); ++i) {
385 if (guiApp->view(ids[i]).workArea(*b)) {
386 // FIXME 1: should we put an alert box here that the buffer
387 // is viewed elsewhere?
388 // FIXME 2: should we try to save this buffer in any case?
391 // This buffer is also opened in another view, so
392 // but close the associated work area nevertheless.
393 removeWorkArea(d.current_work_area_);
394 // but don't close it.
399 if (b && !closeBuffer(*b)) {
400 close_event->ignore();
405 // Make sure that no LFUN use this close to be closed View.
406 theLyXFunc().setLyXView(0);
408 // Save toolbars configuration
409 if (isFullScreen()) {
410 d.toolbars_->toggleFullScreen(!isFullScreen());
414 // Make sure the timer time out will not trigger a statusbar update.
415 d.statusbar_timer_.stop();
417 // Saving fullscreen requires additional tweaks in the toolbar code.
418 // It wouldn't also work under linux natively.
419 if (lyxrc.allow_geometry_session && !isFullScreen()) {
421 QString const key = "view-" + QString::number(id_);
423 settings.setValue(key + "/pos", pos());
424 settings.setValue(key + "/size", size());
426 settings.setValue(key + "/geometry", saveGeometry());
428 settings.setValue(key + "/icon_size", iconSize());
429 d.toolbars_->saveToolbarInfo();
430 // Now take care of all other dialogs:
431 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
432 for (; it!= d.dialogs_.end(); ++it)
433 it->second->saveSession();
436 guiApp->unregisterView(id_);
437 close_event->accept();
441 void GuiView::dragEnterEvent(QDragEnterEvent * event)
443 if (event->mimeData()->hasUrls())
445 /// \todo Ask lyx-devel is this is enough:
446 /// if (event->mimeData()->hasFormat("text/plain"))
447 /// event->acceptProposedAction();
451 void GuiView::dropEvent(QDropEvent* event)
453 QList<QUrl> files = event->mimeData()->urls();
457 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
458 for (int i = 0; i != files.size(); ++i) {
459 string const file = os::internal_path(fromqstr(
460 files.at(i).toLocalFile()));
462 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
467 void GuiView::message(docstring const & str)
469 if (ForkedProcess::iAmAChild())
472 statusBar()->showMessage(toqstr(str));
473 d.statusbar_timer_.stop();
474 d.statusbar_timer_.start(3000);
478 void GuiView::smallSizedIcons()
480 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
484 void GuiView::normalSizedIcons()
486 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
490 void GuiView::bigSizedIcons()
492 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
496 void GuiView::clearMessage()
500 theLyXFunc().setLyXView(this);
501 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
502 d.statusbar_timer_.stop();
506 void GuiView::updateWindowTitle(GuiWorkArea * wa)
508 if (wa != d.current_work_area_)
510 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
511 setWindowIconText(wa->windowIconText());
515 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
518 disconnectBufferView();
519 connectBufferView(wa->bufferView());
520 connectBuffer(wa->bufferView().buffer());
521 d.current_work_area_ = wa;
522 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
523 this, SLOT(updateWindowTitle(GuiWorkArea *)));
524 updateWindowTitle(wa);
527 // Buffer-dependent dialogs should be updated or
528 // hidden. This should go here because some dialogs (eg ToC)
529 // require bv_->text.
530 updateBufferDependent(true);
537 void GuiView::updateStatusBar()
539 // let the user see the explicit message
540 if (d.statusbar_timer_.isActive())
543 theLyXFunc().setLyXView(this);
544 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
548 bool GuiView::hasFocus() const
550 return qApp->activeWindow() == this;
554 bool GuiView::event(QEvent * e)
558 // Useful debug code:
559 //case QEvent::ActivationChange:
560 //case QEvent::WindowDeactivate:
561 //case QEvent::Paint:
562 //case QEvent::Enter:
563 //case QEvent::Leave:
564 //case QEvent::HoverEnter:
565 //case QEvent::HoverLeave:
566 //case QEvent::HoverMove:
567 //case QEvent::StatusTip:
568 //case QEvent::DragEnter:
569 //case QEvent::DragLeave:
573 case QEvent::WindowActivate: {
574 if (this == guiApp->currentView()) {
576 return QMainWindow::event(e);
578 guiApp->setCurrentView(*this);
579 if (d.current_work_area_) {
580 BufferView & bv = d.current_work_area_->bufferView();
581 connectBufferView(bv);
582 connectBuffer(bv.buffer());
583 // The document structure, name and dialogs might have
584 // changed in another view.
585 updateBufferDependent(true);
590 setWindowTitle(qt_("LyX"));
591 setWindowIconText(qt_("LyX"));
594 return QMainWindow::event(e);
597 case QEvent::ShortcutOverride: {
598 if (d.current_work_area_)
599 // Nothing special to do.
600 return QMainWindow::event(e);
602 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
604 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
606 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
607 || ke->key() == Qt::Key_Backtab)
608 return QMainWindow::event(e);
610 // Allow processing of shortcuts that are allowed even when no Buffer
612 theLyXFunc().setLyXView(this);
614 setKeySymbol(&sym, ke);
615 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
621 return QMainWindow::event(e);
626 bool GuiView::focusNextPrevChild(bool /*next*/)
633 void GuiView::setBusy(bool busy)
635 if (d.current_work_area_) {
636 d.current_work_area_->setUpdatesEnabled(!busy);
638 d.current_work_area_->stopBlinkingCursor();
640 d.current_work_area_->startBlinkingCursor();
644 QApplication::setOverrideCursor(Qt::WaitCursor);
646 QApplication::restoreOverrideCursor();
650 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
652 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
654 if (tbinfo.flags & ToolbarInfo::TOP) {
656 addToolBarBreak(Qt::TopToolBarArea);
657 addToolBar(Qt::TopToolBarArea, toolBar);
660 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
661 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
662 #if (QT_VERSION >= 0x040202)
664 addToolBarBreak(Qt::BottomToolBarArea);
666 addToolBar(Qt::BottomToolBarArea, toolBar);
669 if (tbinfo.flags & ToolbarInfo::LEFT) {
670 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
671 #if (QT_VERSION >= 0x040202)
673 addToolBarBreak(Qt::LeftToolBarArea);
675 addToolBar(Qt::LeftToolBarArea, toolBar);
678 if (tbinfo.flags & ToolbarInfo::RIGHT) {
679 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
680 #if (QT_VERSION >= 0x040202)
682 addToolBarBreak(Qt::RightToolBarArea);
684 addToolBar(Qt::RightToolBarArea, toolBar);
687 // The following does not work so I cannot restore to exact toolbar location
689 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
690 toolBar->move(tbinfo.posx, tbinfo.posy);
697 GuiWorkArea * GuiView::workArea(Buffer & buffer)
699 if (TabWorkArea * twa = d.currentTabWorkArea())
700 return twa->workArea(buffer);
705 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
707 // Automatically create a TabWorkArea if there are none yet.
708 TabWorkArea * tab_widget = d.splitter_->count()
709 ? d.currentTabWorkArea() : addTabWorkArea();
710 return tab_widget->addWorkArea(buffer, *this);
714 TabWorkArea * GuiView::addTabWorkArea()
716 TabWorkArea * twa = new TabWorkArea;
717 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
718 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
719 d.splitter_->addWidget(twa);
720 d.stack_widget_->setCurrentWidget(d.splitter_);
725 GuiWorkArea const * GuiView::currentWorkArea() const
727 return d.current_work_area_;
731 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
735 // Changing work area can result from opening a file so
736 // update the toc in any case.
739 d.current_work_area_ = wa;
740 for (int i = 0; i != d.splitter_->count(); ++i) {
741 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
747 void GuiView::removeWorkArea(GuiWorkArea * wa)
750 if (wa == d.current_work_area_) {
752 disconnectBufferView();
753 hideBufferDependent();
754 d.current_work_area_ = 0;
757 for (int i = 0; i != d.splitter_->count(); ++i) {
758 TabWorkArea * twa = d.tabWorkArea(i);
759 if (!twa->removeWorkArea(wa))
760 // Not found in this tab group.
763 // We found and removed the GuiWorkArea.
765 // No more WorkAreas in this tab group, so delete it.
770 if (d.current_work_area_)
771 // This means that we are not closing the current GuiWorkArea;
774 // Switch to the next GuiWorkArea in the found TabWorkArea.
775 d.current_work_area_ = twa->currentWorkArea();
779 if (d.splitter_->count() == 0)
780 // No more work area, switch to the background widget.
785 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
791 void GuiView::updateLayoutList()
794 d.layout_->updateContents(false);
798 void GuiView::updateToolbars()
800 if (d.current_work_area_) {
802 d.current_work_area_->bufferView().cursor().inMathed();
804 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
806 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
807 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
808 bool const mathmacrotemplate =
809 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
811 d.toolbars_->update(math, table, review, mathmacrotemplate);
813 d.toolbars_->update(false, false, false, false);
815 // update read-only status of open dialogs.
820 Buffer * GuiView::buffer()
822 if (d.current_work_area_)
823 return &d.current_work_area_->bufferView().buffer();
828 Buffer const * GuiView::buffer() const
830 if (d.current_work_area_)
831 return &d.current_work_area_->bufferView().buffer();
836 void GuiView::setBuffer(Buffer * newBuffer)
838 BOOST_ASSERT(newBuffer);
841 GuiWorkArea * wa = workArea(*newBuffer);
843 updateLabels(*newBuffer->masterBuffer());
844 wa = addWorkArea(*newBuffer);
846 //Disconnect the old buffer...there's no new one.
849 connectBuffer(*newBuffer);
850 connectBufferView(wa->bufferView());
851 setCurrentWorkArea(wa);
857 void GuiView::connectBuffer(Buffer & buf)
859 buf.setGuiDelegate(this);
863 void GuiView::disconnectBuffer()
865 if (d.current_work_area_)
866 d.current_work_area_->bufferView().setGuiDelegate(0);
870 void GuiView::connectBufferView(BufferView & bv)
872 bv.setGuiDelegate(this);
876 void GuiView::disconnectBufferView()
878 if (d.current_work_area_)
879 d.current_work_area_->bufferView().setGuiDelegate(0);
883 void GuiView::errors(string const & error_type)
885 ErrorList & el = buffer()->errorList(error_type);
887 showDialog("errorlist", error_type);
891 void GuiView::updateDialog(string const & name, string const & data)
893 if (!isDialogVisible(name))
896 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
897 if (it == d.dialogs_.end())
900 Dialog * const dialog = it->second.get();
901 if (dialog->isVisibleView())
902 dialog->updateData(data);
906 BufferView * GuiView::view()
908 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
912 void GuiView::updateToc()
914 updateDialog("toc", "");
918 void GuiView::updateEmbeddedFiles()
920 updateDialog("embedding", "");
924 void GuiView::autoSave()
926 LYXERR(Debug::INFO, "Running autoSave()");
929 view()->buffer().autoSave();
933 void GuiView::resetAutosaveTimers()
936 d.autosave_timeout_.restart();
940 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
944 Buffer * buf = buffer();
946 /* In LyX/Mac, when a dialog is open, the menus of the
947 application can still be accessed without giving focus to
948 the main window. In this case, we want to disable the menu
949 entries that are buffer-related.
951 Note that this code is not perfect, as bug 1941 attests:
952 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
954 if (cmd.origin == FuncRequest::MENU && !hasFocus())
958 case LFUN_BUFFER_WRITE:
959 enable = buf && (buf->isUnnamed() || !buf->isClean());
962 case LFUN_BUFFER_WRITE_AS:
966 case LFUN_SPLIT_VIEW:
970 case LFUN_CLOSE_TAB_GROUP:
971 enable = d.currentTabWorkArea();
974 case LFUN_TOOLBAR_TOGGLE:
975 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
978 case LFUN_DIALOG_TOGGLE:
979 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
980 // fall through to set "enable"
981 case LFUN_DIALOG_SHOW: {
982 string const name = cmd.getArg(0);
984 enable = name == "aboutlyx"
985 || name == "file" //FIXME: should be removed.
987 || name == "texinfo";
988 else if (name == "print")
989 enable = buf->isExportable("dvi")
990 && lyxrc.print_command != "none";
991 else if (name == "character") {
995 InsetCode ic = view()->cursor().inset().lyxCode();
996 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
999 else if (name == "symbols") {
1000 if (!view() || view()->cursor().inMathed())
1003 InsetCode ic = view()->cursor().inset().lyxCode();
1004 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1007 else if (name == "latexlog")
1008 enable = FileName(buf->logName()).isReadableFile();
1009 else if (name == "spellchecker")
1010 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1011 enable = !buf->isReadonly();
1015 else if (name == "vclog")
1016 enable = buf->lyxvc().inUse();
1020 case LFUN_DIALOG_UPDATE: {
1021 string const name = cmd.getArg(0);
1023 enable = name == "prefs";
1027 case LFUN_INSET_APPLY: {
1032 string const name = cmd.getArg(0);
1033 Inset * inset = getOpenInset(name);
1035 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1037 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1038 // Every inset is supposed to handle this
1039 BOOST_ASSERT(false);
1043 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1044 flag |= getStatus(fr);
1046 enable = flag.enabled();
1050 case LFUN_COMPLETION_INLINE:
1051 if (!d.current_work_area_
1052 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1056 case LFUN_COMPLETION_POPUP:
1057 if (!d.current_work_area_
1058 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1062 case LFUN_COMPLETION_COMPLETE:
1063 if (!d.current_work_area_
1064 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1076 flag.enabled(false);
1082 static FileName selectTemplateFile()
1084 FileDialog dlg(qt_("Select template file"));
1085 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1086 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1088 FileDialog::Result result =
1089 dlg.open(toqstr(lyxrc.template_path),
1090 FileFilterList(_("LyX Documents (*.lyx)")));
1092 if (result.first == FileDialog::Later)
1094 if (result.second.isEmpty())
1096 return FileName(fromqstr(result.second));
1100 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1104 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1107 message(_("Document not loaded."));
1112 setBuffer(newBuffer);
1114 // scroll to the position when the file was last closed
1115 if (lyxrc.use_lastfilepos) {
1116 LastFilePosSection::FilePos filepos =
1117 LyX::ref().session().lastFilePos().load(filename);
1118 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1122 LyX::ref().session().lastFiles().add(filename);
1129 void GuiView::openDocument(string const & fname)
1131 string initpath = lyxrc.document_path;
1134 string const trypath = buffer()->filePath();
1135 // If directory is writeable, use this as default.
1136 if (FileName(trypath).isDirWritable())
1142 if (fname.empty()) {
1143 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1144 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1145 dlg.setButton2(qt_("Examples|#E#e"),
1146 toqstr(addPath(package().system_support().absFilename(), "examples")));
1148 FileDialog::Result result =
1149 dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1151 if (result.first == FileDialog::Later)
1154 filename = fromqstr(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(support::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 support::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 : support::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(toqstr(text), LFUN_BUFFER_IMPORT);
1276 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1277 dlg.setButton2(qt_("Examples|#E#e"),
1278 toqstr(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(toqstr(initpath), FileFilterList(filter));
1289 if (result.first == FileDialog::Later)
1292 filename = fromqstr(result.second);
1294 // check selected filename
1295 if (filename.empty())
1296 message(_("Canceled."));
1299 if (filename.empty())
1302 // get absolute path of file
1303 FileName const fullname(makeAbsPath(filename));
1305 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1307 // Check if the document already is open
1308 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1311 if (!closeBuffer()) {
1312 message(_("Canceled."));
1317 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1319 // if the file exists already, and we didn't do
1320 // -i lyx thefile.lyx, warn
1321 if (lyxfile.exists() && fullname != lyxfile) {
1323 docstring text = bformat(_("The document %1$s already exists.\n\n"
1324 "Do you want to overwrite that document?"), displaypath);
1325 int const ret = Alert::prompt(_("Overwrite document?"),
1326 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1329 message(_("Canceled."));
1334 message(bformat(_("Importing %1$s..."), displaypath));
1335 ErrorList errorList;
1336 if (import(this, fullname, format, errorList))
1337 message(_("imported."));
1339 message(_("file not imported!"));
1341 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1345 void GuiView::newDocument(string const & filename, bool from_template)
1347 FileName initpath(lyxrc.document_path);
1348 Buffer * buf = buffer();
1350 FileName const trypath(buf->filePath());
1351 // If directory is writeable, use this as default.
1352 if (trypath.isDirWritable())
1356 string templatefile = from_template ?
1357 selectTemplateFile().absFilename() : string();
1359 if (filename.empty())
1360 b = newUnnamedFile(templatefile, initpath);
1362 b = newFile(filename, templatefile, true);
1366 // Ensure the cursor is correctly positionned on screen.
1367 view()->showCursor();
1371 void GuiView::insertLyXFile(docstring const & fname)
1373 BufferView * bv = view();
1378 FileName filename(to_utf8(fname));
1380 if (!filename.empty()) {
1381 bv->insertLyXFile(filename);
1385 // Launch a file browser
1387 string initpath = lyxrc.document_path;
1388 string const trypath = bv->buffer().filePath();
1389 // If directory is writeable, use this as default.
1390 if (FileName(trypath).isDirWritable())
1394 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1395 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1396 dlg.setButton2(qt_("Examples|#E#e"),
1397 toqstr(addPath(package().system_support().absFilename(),
1400 FileDialog::Result result =
1401 dlg.open(toqstr(initpath),
1402 FileFilterList(_("LyX Documents (*.lyx)")));
1404 if (result.first == FileDialog::Later)
1408 filename.set(fromqstr(result.second));
1410 // check selected filename
1411 if (filename.empty()) {
1412 // emit message signal.
1413 message(_("Canceled."));
1417 bv->insertLyXFile(filename);
1421 void GuiView::insertPlaintextFile(docstring const & fname,
1424 BufferView * bv = view();
1429 FileName filename(to_utf8(fname));
1431 if (!filename.empty()) {
1432 bv->insertPlaintextFile(filename, asParagraph);
1436 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1437 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1439 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1442 if (result.first == FileDialog::Later)
1446 filename.set(fromqstr(result.second));
1448 // check selected filename
1449 if (filename.empty()) {
1450 // emit message signal.
1451 message(_("Canceled."));
1455 bv->insertPlaintextFile(filename, asParagraph);
1459 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1461 FileName fname = b.fileName();
1462 FileName const oldname = fname;
1464 if (!newname.empty()) {
1466 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1468 // Switch to this Buffer.
1471 /// No argument? Ask user through dialog.
1473 FileDialog dlg(qt_("Choose a filename to save document as"),
1474 LFUN_BUFFER_WRITE_AS);
1475 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1476 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1478 if (!isLyXFilename(fname.absFilename()))
1479 fname.changeExtension(".lyx");
1481 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1483 FileDialog::Result result =
1484 dlg.save(toqstr(fname.onlyPath().absFilename()),
1486 toqstr(fname.onlyFileName()));
1488 if (result.first == FileDialog::Later)
1491 fname.set(fromqstr(result.second));
1496 if (!isLyXFilename(fname.absFilename()))
1497 fname.changeExtension(".lyx");
1500 if (FileName(fname).exists()) {
1501 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1502 docstring text = bformat(_("The document %1$s already "
1503 "exists.\n\nDo you want to "
1504 "overwrite that document?"),
1506 int const ret = Alert::prompt(_("Overwrite document?"),
1507 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1510 case 1: return renameBuffer(b, docstring());
1511 case 2: return false;
1515 // Ok, change the name of the buffer
1516 b.setFileName(fname.absFilename());
1518 bool unnamed = b.isUnnamed();
1519 b.setUnnamed(false);
1520 b.saveCheckSum(fname);
1522 if (!saveBuffer(b)) {
1523 b.setFileName(oldname.absFilename());
1524 b.setUnnamed(unnamed);
1525 b.saveCheckSum(oldname);
1533 bool GuiView::saveBuffer(Buffer & b)
1536 return renameBuffer(b, docstring());
1539 LyX::ref().session().lastFiles().add(b.fileName());
1543 // Switch to this Buffer.
1546 // FIXME: we don't tell the user *WHY* the save failed !!
1547 docstring const file = makeDisplayPath(b.absFileName(), 30);
1548 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1549 "Do you want to rename the document and "
1550 "try again?"), file);
1551 int const ret = Alert::prompt(_("Rename and save?"),
1552 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1555 if (!renameBuffer(b, docstring()))
1564 return saveBuffer(b);
1568 bool GuiView::closeBuffer()
1570 Buffer * buf = buffer();
1571 return buf && closeBuffer(*buf);
1575 bool GuiView::closeBuffer(Buffer & buf)
1577 // goto bookmark to update bookmark pit.
1578 //FIXME: we should update only the bookmarks related to this buffer!
1579 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1580 theLyXFunc().gotoBookmark(i+1, false, false);
1582 if (buf.isClean() || buf.paragraphs().empty()) {
1583 theBufferList().release(&buf);
1586 // Switch to this Buffer.
1591 if (buf.isUnnamed())
1592 file = from_utf8(buf.fileName().onlyFileName());
1594 file = buf.fileName().displayName(30);
1596 // Bring this window to top before asking questions.
1600 docstring const text = bformat(_("The document %1$s has unsaved changes."
1601 "\n\nDo you want to save the document or discard the changes?"), file);
1602 int const ret = Alert::prompt(_("Save changed document?"),
1603 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1607 if (!saveBuffer(buf))
1611 // if we crash after this we could
1612 // have no autosave file but I guess
1613 // this is really improbable (Jug)
1614 removeAutosaveFile(buf.absFileName());
1620 // save file names to .lyx/session
1621 // if master/slave are both open, do not save slave since it
1622 // will be automatically loaded when the master is loaded
1623 if (buf.masterBuffer() == &buf)
1624 LyX::ref().session().lastOpened().add(buf.fileName());
1626 theBufferList().release(&buf);
1631 bool GuiView::dispatch(FuncRequest const & cmd)
1633 BufferView * bv = view();
1634 // By default we won't need any update.
1636 bv->cursor().updateFlags(Update::None);
1638 switch(cmd.action) {
1639 case LFUN_FILE_OPEN:
1640 openDocument(to_utf8(cmd.argument()));
1643 case LFUN_BUFFER_IMPORT:
1644 importDocument(to_utf8(cmd.argument()));
1647 case LFUN_BUFFER_SWITCH:
1648 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1651 case LFUN_BUFFER_NEXT:
1652 setBuffer(theBufferList().next(buffer()));
1655 case LFUN_BUFFER_PREVIOUS:
1656 setBuffer(theBufferList().previous(buffer()));
1659 case LFUN_COMMAND_EXECUTE: {
1660 bool const show_it = cmd.argument() != "off";
1661 d.toolbars_->showCommandBuffer(show_it);
1664 case LFUN_DROP_LAYOUTS_CHOICE:
1666 d.layout_->showPopup();
1669 case LFUN_MENU_OPEN:
1670 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1671 menu->exec(QCursor::pos());
1674 case LFUN_FILE_INSERT:
1675 insertLyXFile(cmd.argument());
1677 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1678 insertPlaintextFile(cmd.argument(), true);
1681 case LFUN_FILE_INSERT_PLAINTEXT:
1682 insertPlaintextFile(cmd.argument(), false);
1685 case LFUN_BUFFER_WRITE:
1687 saveBuffer(bv->buffer());
1690 case LFUN_BUFFER_WRITE_AS:
1692 renameBuffer(bv->buffer(), cmd.argument());
1695 case LFUN_BUFFER_WRITE_ALL: {
1696 Buffer * first = theBufferList().first();
1699 message(_("Saving all documents..."));
1700 // We cannot use a for loop as the buffer list cycles.
1706 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1707 b = theBufferList().next(b);
1708 } while (b != first);
1709 message(_("All documents saved."));
1713 case LFUN_TOOLBAR_TOGGLE: {
1714 string const name = cmd.getArg(0);
1715 bool const allowauto = cmd.getArg(1) == "allowauto";
1716 // it is possible to get current toolbar status like this,...
1717 // but I decide to obey the order of ToolbarBackend::flags
1718 // and disregard real toolbar status.
1719 // toolbars_->saveToolbarInfo();
1721 // toggle state on/off/auto
1722 d.toolbars_->toggleToolbarState(name, allowauto);
1726 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1728 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1732 if (tbi->flags & ToolbarInfo::ON)
1734 else if (tbi->flags & ToolbarInfo::OFF)
1736 else if (tbi->flags & ToolbarInfo::AUTO)
1739 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1740 _(tbi->gui_name), state));
1744 case LFUN_DIALOG_UPDATE: {
1745 string const name = to_utf8(cmd.argument());
1746 // Can only update a dialog connected to an existing inset
1747 Inset * inset = getOpenInset(name);
1749 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1750 inset->dispatch(view()->cursor(), fr);
1751 } else if (name == "paragraph") {
1752 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1753 } else if (name == "prefs") {
1754 updateDialog(name, string());
1759 case LFUN_DIALOG_TOGGLE: {
1760 if (isDialogVisible(cmd.getArg(0)))
1761 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1763 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1767 case LFUN_DIALOG_DISCONNECT_INSET:
1768 disconnectDialog(to_utf8(cmd.argument()));
1771 case LFUN_DIALOG_HIDE: {
1772 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1776 case LFUN_DIALOG_SHOW: {
1777 string const name = cmd.getArg(0);
1778 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1780 if (name == "character") {
1781 data = freefont2string();
1783 showDialog("character", data);
1784 } else if (name == "latexlog") {
1785 Buffer::LogType type;
1786 string const logfile = buffer()->logName(&type);
1788 case Buffer::latexlog:
1791 case Buffer::buildlog:
1795 data += Lexer::quoteString(logfile);
1796 showDialog("log", data);
1797 } else if (name == "vclog") {
1798 string const data = "vc " +
1799 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1800 showDialog("log", data);
1801 } else if (name == "symbols") {
1802 data = bv->cursor().getEncoding()->name();
1804 showDialog("symbols", data);
1806 showDialog(name, data);
1810 case LFUN_INSET_APPLY: {
1811 string const name = cmd.getArg(0);
1812 Inset * inset = getOpenInset(name);
1814 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1815 inset->dispatch(view()->cursor(), fr);
1817 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1823 case LFUN_UI_TOGGLE:
1825 // Make sure the keyboard focus stays in the work area.
1829 case LFUN_COMPLETION_INLINE:
1830 if (d.current_work_area_)
1831 d.current_work_area_->completer().showInline();
1834 case LFUN_SPLIT_VIEW:
1835 if (Buffer * buf = buffer()) {
1836 string const orientation = cmd.getArg(0);
1837 d.splitter_->setOrientation(orientation == "vertical"
1838 ? Qt::Vertical : Qt::Horizontal);
1839 TabWorkArea * twa = addTabWorkArea();
1840 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1841 setCurrentWorkArea(wa);
1845 case LFUN_CLOSE_TAB_GROUP:
1846 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1848 twa = d.currentTabWorkArea();
1849 // Switch to the next GuiWorkArea in the found TabWorkArea.
1850 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1851 if (d.splitter_->count() == 0)
1852 // No more work area, switch to the background widget.
1857 case LFUN_COMPLETION_POPUP:
1858 if (d.current_work_area_)
1859 d.current_work_area_->completer().showPopup();
1863 case LFUN_COMPLETION_COMPLETE:
1864 if (d.current_work_area_)
1865 d.current_work_area_->completer().tab();
1876 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1878 string const arg = cmd.getArg(0);
1879 if (arg == "scrollbar") {
1880 // hide() is of no help
1881 if (d.current_work_area_->verticalScrollBarPolicy() ==
1882 Qt::ScrollBarAlwaysOff)
1884 d.current_work_area_->setVerticalScrollBarPolicy(
1885 Qt::ScrollBarAsNeeded);
1887 d.current_work_area_->setVerticalScrollBarPolicy(
1888 Qt::ScrollBarAlwaysOff);
1891 if (arg == "statusbar") {
1892 statusBar()->setVisible(!statusBar()->isVisible());
1895 if (arg == "menubar") {
1896 menuBar()->setVisible(!menuBar()->isVisible());
1899 #if QT_VERSION >= 0x040300
1900 if (arg == "frame") {
1902 getContentsMargins(&l, &t, &r, &b);
1903 //are the frames in default state?
1904 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1906 setContentsMargins(-2, -2, -2, -2);
1908 setContentsMargins(0, 0, 0, 0);
1913 if (arg != "fullscreen") {
1914 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1918 if (lyxrc.full_screen_toolbars)
1919 d.toolbars_->toggleFullScreen(!isFullScreen());
1921 if (isFullScreen()) {
1922 for (int i = 0; i != d.splitter_->count(); ++i)
1923 d.tabWorkArea(i)->setFullScreen(false);
1924 #if QT_VERSION >= 0x040300
1925 setContentsMargins(0, 0, 0, 0);
1929 statusBar()->show();
1931 for (int i = 0; i != d.splitter_->count(); ++i)
1932 d.tabWorkArea(i)->setFullScreen(true);
1933 #if QT_VERSION >= 0x040300
1934 setContentsMargins(-2, -2, -2, -2);
1937 statusBar()->hide();
1943 Buffer const * GuiView::updateInset(Inset const * inset)
1945 if (!d.current_work_area_)
1949 d.current_work_area_->scheduleRedraw();
1951 return &d.current_work_area_->bufferView().buffer();
1955 void GuiView::restartCursor()
1957 /* When we move around, or type, it's nice to be able to see
1958 * the cursor immediately after the keypress.
1960 if (d.current_work_area_)
1961 d.current_work_area_->startBlinkingCursor();
1963 // Take this occasion to update the other GUI elements.
1970 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1972 if (d.current_work_area_)
1973 d.current_work_area_->completer().updateVisibility(cur, start, keep);
1978 // This list should be kept in sync with the list of insets in
1979 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1980 // dialog should have the same name as the inset.
1982 char const * const dialognames[] = {
1983 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1984 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1985 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1986 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
1987 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1989 #ifdef HAVE_LIBAIKSAURUS
1993 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1995 char const * const * const end_dialognames =
1996 dialognames + (sizeof(dialognames) / sizeof(char *));
2000 cmpCStr(char const * name) : name_(name) {}
2001 bool operator()(char const * other) {
2002 return strcmp(other, name_) == 0;
2009 bool isValidName(string const & name)
2011 return find_if(dialognames, end_dialognames,
2012 cmpCStr(name.c_str())) != end_dialognames;
2018 void GuiView::resetDialogs()
2020 // Make sure that no LFUN uses any LyXView.
2021 theLyXFunc().setLyXView(0);
2022 // FIXME: the "math panels" toolbar takes an awful lot of time to
2023 // initialise so we don't do that for the time being.
2024 //d.toolbars_->init();
2025 guiApp->menus().fillMenuBar(this);
2027 d.layout_->updateContents(true);
2028 // Now update controls with current buffer.
2029 theLyXFunc().setLyXView(this);
2034 Dialog * GuiView::find_or_build(string const & name)
2036 if (!isValidName(name))
2039 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2041 if (it != d.dialogs_.end())
2042 return it->second.get();
2044 Dialog * dialog = build(name);
2045 d.dialogs_[name].reset(dialog);
2046 if (lyxrc.allow_geometry_session)
2047 dialog->restoreSession();
2052 void GuiView::showDialog(string const & name, string const & data,
2059 Dialog * dialog = find_or_build(name);
2061 dialog->showData(data);
2063 d.open_insets_[name] = inset;
2069 bool GuiView::isDialogVisible(string const & name) const
2071 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2072 if (it == d.dialogs_.end())
2074 return it->second.get()->isVisibleView();
2078 void GuiView::hideDialog(string const & name, Inset * inset)
2080 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2081 if (it == d.dialogs_.end())
2084 if (inset && inset != getOpenInset(name))
2087 Dialog * const dialog = it->second.get();
2088 if (dialog->isVisibleView())
2090 d.open_insets_[name] = 0;
2094 void GuiView::disconnectDialog(string const & name)
2096 if (!isValidName(name))
2099 if (d.open_insets_.find(name) != d.open_insets_.end())
2100 d.open_insets_[name] = 0;
2104 Inset * GuiView::getOpenInset(string const & name) const
2106 if (!isValidName(name))
2109 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2110 return it == d.open_insets_.end() ? 0 : it->second;
2114 void GuiView::hideAll() const
2116 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2117 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2119 for(; it != end; ++it)
2120 it->second->hideView();
2124 void GuiView::hideBufferDependent() const
2126 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2127 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2129 for(; it != end; ++it) {
2130 Dialog * dialog = it->second.get();
2131 if (dialog->isBufferDependent())
2137 void GuiView::updateBufferDependent(bool switched) const
2139 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2140 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2142 for(; it != end; ++it) {
2143 Dialog * dialog = it->second.get();
2144 if (!dialog->isVisibleView())
2146 if (switched && dialog->isBufferDependent()) {
2147 if (dialog->initialiseParams(""))
2148 dialog->updateView();
2152 // A bit clunky, but the dialog will request
2153 // that the kernel provides it with the necessary
2155 dialog->updateDialog();
2161 void GuiView::checkStatus()
2163 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2164 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2166 for(; it != end; ++it) {
2167 Dialog * const dialog = it->second.get();
2168 if (dialog && dialog->isVisibleView())
2169 dialog->checkStatus();
2175 // will be replaced by a proper factory...
2176 Dialog * createGuiAbout(GuiView & lv);
2177 Dialog * createGuiBibitem(GuiView & lv);
2178 Dialog * createGuiBibtex(GuiView & lv);
2179 Dialog * createGuiBox(GuiView & lv);
2180 Dialog * createGuiBranch(GuiView & lv);
2181 Dialog * createGuiChanges(GuiView & lv);
2182 Dialog * createGuiCharacter(GuiView & lv);
2183 Dialog * createGuiCitation(GuiView & lv);
2184 Dialog * createGuiDelimiter(GuiView & lv);
2185 Dialog * createGuiDocument(GuiView & lv);
2186 Dialog * createGuiErrorList(GuiView & lv);
2187 Dialog * createGuiERT(GuiView & lv);
2188 Dialog * createGuiExternal(GuiView & lv);
2189 Dialog * createGuiFloat(GuiView & lv);
2190 Dialog * createGuiGraphics(GuiView & lv);
2191 Dialog * createGuiInclude(GuiView & lv);
2192 Dialog * createGuiLabel(GuiView & lv);
2193 Dialog * createGuiListings(GuiView & lv);
2194 Dialog * createGuiLog(GuiView & lv);
2195 Dialog * createGuiMathMatrix(GuiView & lv);
2196 Dialog * createGuiNomenclature(GuiView & lv);
2197 Dialog * createGuiNote(GuiView & lv);
2198 Dialog * createGuiParagraph(GuiView & lv);
2199 Dialog * createGuiPreferences(GuiView & lv);
2200 Dialog * createGuiPrint(GuiView & lv);
2201 Dialog * createGuiRef(GuiView & lv);
2202 Dialog * createGuiSearch(GuiView & lv);
2203 Dialog * createGuiSendTo(GuiView & lv);
2204 Dialog * createGuiShowFile(GuiView & lv);
2205 Dialog * createGuiSpellchecker(GuiView & lv);
2206 Dialog * createGuiSymbols(GuiView & lv);
2207 Dialog * createGuiTabularCreate(GuiView & lv);
2208 Dialog * createGuiTabular(GuiView & lv);
2209 Dialog * createGuiTexInfo(GuiView & lv);
2210 Dialog * createGuiToc(GuiView & lv);
2211 Dialog * createGuiThesaurus(GuiView & lv);
2212 Dialog * createGuiHyperlink(GuiView & lv);
2213 Dialog * createGuiVSpace(GuiView & lv);
2214 Dialog * createGuiViewSource(GuiView & lv);
2215 Dialog * createGuiWrap(GuiView & lv);
2218 Dialog * GuiView::build(string const & name)
2220 BOOST_ASSERT(isValidName(name));
2222 if (name == "aboutlyx")
2223 return createGuiAbout(*this);
2224 if (name == "bibitem")
2225 return createGuiBibitem(*this);
2226 if (name == "bibtex")
2227 return createGuiBibtex(*this);
2229 return createGuiBox(*this);
2230 if (name == "branch")
2231 return createGuiBranch(*this);
2232 if (name == "changes")
2233 return createGuiChanges(*this);
2234 if (name == "character")
2235 return createGuiCharacter(*this);
2236 if (name == "citation")
2237 return createGuiCitation(*this);
2238 if (name == "document")
2239 return createGuiDocument(*this);
2240 if (name == "errorlist")
2241 return createGuiErrorList(*this);
2243 return createGuiERT(*this);
2244 if (name == "external")
2245 return createGuiExternal(*this);
2247 return createGuiShowFile(*this);
2248 if (name == "findreplace")
2249 return createGuiSearch(*this);
2250 if (name == "float")
2251 return createGuiFloat(*this);
2252 if (name == "graphics")
2253 return createGuiGraphics(*this);
2254 if (name == "include")
2255 return createGuiInclude(*this);
2256 if (name == "nomenclature")
2257 return createGuiNomenclature(*this);
2258 if (name == "label")
2259 return createGuiLabel(*this);
2261 return createGuiLog(*this);
2262 if (name == "view-source")
2263 return createGuiViewSource(*this);
2264 if (name == "mathdelimiter")
2265 return createGuiDelimiter(*this);
2266 if (name == "mathmatrix")
2267 return createGuiMathMatrix(*this);
2269 return createGuiNote(*this);
2270 if (name == "paragraph")
2271 return createGuiParagraph(*this);
2272 if (name == "prefs")
2273 return createGuiPreferences(*this);
2274 if (name == "print")
2275 return createGuiPrint(*this);
2277 return createGuiRef(*this);
2278 if (name == "sendto")
2279 return createGuiSendTo(*this);
2280 if (name == "spellchecker")
2281 return createGuiSpellchecker(*this);
2282 if (name == "symbols")
2283 return createGuiSymbols(*this);
2284 if (name == "tabular")
2285 return createGuiTabular(*this);
2286 if (name == "tabularcreate")
2287 return createGuiTabularCreate(*this);
2288 if (name == "texinfo")
2289 return createGuiTexInfo(*this);
2290 #ifdef HAVE_LIBAIKSAURUS
2291 if (name == "thesaurus")
2292 return createGuiThesaurus(*this);
2295 return createGuiToc(*this);
2297 return createGuiHyperlink(*this);
2298 if (name == "vspace")
2299 return createGuiVSpace(*this);
2301 return createGuiWrap(*this);
2302 if (name == "listings")
2303 return createGuiListings(*this);
2309 } // namespace frontend
2312 #include "GuiView_moc.cpp"