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(menuBar(), 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 if (buf.masterBuffer() == &buf)
1584 LyX::ref().session().lastOpened().add(buf.fileName());
1585 theBufferList().release(&buf);
1588 // Switch to this Buffer.
1593 if (buf.isUnnamed())
1594 file = from_utf8(buf.fileName().onlyFileName());
1596 file = buf.fileName().displayName(30);
1598 // Bring this window to top before asking questions.
1602 docstring const text = bformat(_("The document %1$s has unsaved changes."
1603 "\n\nDo you want to save the document or discard the changes?"), file);
1604 int const ret = Alert::prompt(_("Save changed document?"),
1605 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1609 if (!saveBuffer(buf))
1613 // if we crash after this we could
1614 // have no autosave file but I guess
1615 // this is really improbable (Jug)
1616 removeAutosaveFile(buf.absFileName());
1622 // save file names to .lyx/session
1623 // if master/slave are both open, do not save slave since it
1624 // will be automatically loaded when the master is loaded
1625 if (buf.masterBuffer() == &buf)
1626 LyX::ref().session().lastOpened().add(buf.fileName());
1628 theBufferList().release(&buf);
1633 bool GuiView::dispatch(FuncRequest const & cmd)
1635 BufferView * bv = view();
1636 // By default we won't need any update.
1638 bv->cursor().updateFlags(Update::None);
1640 switch(cmd.action) {
1641 case LFUN_FILE_OPEN:
1642 openDocument(to_utf8(cmd.argument()));
1645 case LFUN_BUFFER_IMPORT:
1646 importDocument(to_utf8(cmd.argument()));
1649 case LFUN_BUFFER_SWITCH:
1650 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1653 case LFUN_BUFFER_NEXT:
1654 setBuffer(theBufferList().next(buffer()));
1657 case LFUN_BUFFER_PREVIOUS:
1658 setBuffer(theBufferList().previous(buffer()));
1661 case LFUN_COMMAND_EXECUTE: {
1662 bool const show_it = cmd.argument() != "off";
1663 d.toolbars_->showCommandBuffer(show_it);
1666 case LFUN_DROP_LAYOUTS_CHOICE:
1668 d.layout_->showPopup();
1671 case LFUN_MENU_OPEN:
1672 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1673 menu->exec(QCursor::pos());
1676 case LFUN_FILE_INSERT:
1677 insertLyXFile(cmd.argument());
1679 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1680 insertPlaintextFile(cmd.argument(), true);
1683 case LFUN_FILE_INSERT_PLAINTEXT:
1684 insertPlaintextFile(cmd.argument(), false);
1687 case LFUN_BUFFER_WRITE:
1689 saveBuffer(bv->buffer());
1692 case LFUN_BUFFER_WRITE_AS:
1694 renameBuffer(bv->buffer(), cmd.argument());
1697 case LFUN_BUFFER_WRITE_ALL: {
1698 Buffer * first = theBufferList().first();
1701 message(_("Saving all documents..."));
1702 // We cannot use a for loop as the buffer list cycles.
1708 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1709 b = theBufferList().next(b);
1710 } while (b != first);
1711 message(_("All documents saved."));
1715 case LFUN_TOOLBAR_TOGGLE: {
1716 string const name = cmd.getArg(0);
1717 bool const allowauto = cmd.getArg(1) == "allowauto";
1718 // it is possible to get current toolbar status like this,...
1719 // but I decide to obey the order of ToolbarBackend::flags
1720 // and disregard real toolbar status.
1721 // toolbars_->saveToolbarInfo();
1723 // toggle state on/off/auto
1724 d.toolbars_->toggleToolbarState(name, allowauto);
1728 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1730 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1734 if (tbi->flags & ToolbarInfo::ON)
1736 else if (tbi->flags & ToolbarInfo::OFF)
1738 else if (tbi->flags & ToolbarInfo::AUTO)
1741 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1742 _(tbi->gui_name), state));
1746 case LFUN_DIALOG_UPDATE: {
1747 string const name = to_utf8(cmd.argument());
1748 // Can only update a dialog connected to an existing inset
1749 Inset * inset = getOpenInset(name);
1751 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1752 inset->dispatch(view()->cursor(), fr);
1753 } else if (name == "paragraph") {
1754 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1755 } else if (name == "prefs") {
1756 updateDialog(name, string());
1761 case LFUN_DIALOG_TOGGLE: {
1762 if (isDialogVisible(cmd.getArg(0)))
1763 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1765 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1769 case LFUN_DIALOG_DISCONNECT_INSET:
1770 disconnectDialog(to_utf8(cmd.argument()));
1773 case LFUN_DIALOG_HIDE: {
1774 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1778 case LFUN_DIALOG_SHOW: {
1779 string const name = cmd.getArg(0);
1780 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1782 if (name == "character") {
1783 data = freefont2string();
1785 showDialog("character", data);
1786 } else if (name == "latexlog") {
1787 Buffer::LogType type;
1788 string const logfile = buffer()->logName(&type);
1790 case Buffer::latexlog:
1793 case Buffer::buildlog:
1797 data += Lexer::quoteString(logfile);
1798 showDialog("log", data);
1799 } else if (name == "vclog") {
1800 string const data = "vc " +
1801 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1802 showDialog("log", data);
1803 } else if (name == "symbols") {
1804 data = bv->cursor().getEncoding()->name();
1806 showDialog("symbols", data);
1808 showDialog(name, data);
1812 case LFUN_INSET_APPLY: {
1813 string const name = cmd.getArg(0);
1814 Inset * inset = getOpenInset(name);
1816 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1817 inset->dispatch(view()->cursor(), fr);
1819 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1825 case LFUN_UI_TOGGLE:
1827 // Make sure the keyboard focus stays in the work area.
1831 case LFUN_COMPLETION_INLINE:
1832 if (d.current_work_area_)
1833 d.current_work_area_->completer().showInline();
1836 case LFUN_SPLIT_VIEW:
1837 if (Buffer * buf = buffer()) {
1838 string const orientation = cmd.getArg(0);
1839 d.splitter_->setOrientation(orientation == "vertical"
1840 ? Qt::Vertical : Qt::Horizontal);
1841 TabWorkArea * twa = addTabWorkArea();
1842 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1843 setCurrentWorkArea(wa);
1847 case LFUN_CLOSE_TAB_GROUP:
1848 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1850 twa = d.currentTabWorkArea();
1851 // Switch to the next GuiWorkArea in the found TabWorkArea.
1852 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1853 if (d.splitter_->count() == 0)
1854 // No more work area, switch to the background widget.
1859 case LFUN_COMPLETION_POPUP:
1860 if (d.current_work_area_)
1861 d.current_work_area_->completer().showPopup();
1865 case LFUN_COMPLETION_COMPLETE:
1866 if (d.current_work_area_)
1867 d.current_work_area_->completer().tab();
1878 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1880 string const arg = cmd.getArg(0);
1881 if (arg == "scrollbar") {
1882 // hide() is of no help
1883 if (d.current_work_area_->verticalScrollBarPolicy() ==
1884 Qt::ScrollBarAlwaysOff)
1886 d.current_work_area_->setVerticalScrollBarPolicy(
1887 Qt::ScrollBarAsNeeded);
1889 d.current_work_area_->setVerticalScrollBarPolicy(
1890 Qt::ScrollBarAlwaysOff);
1893 if (arg == "statusbar") {
1894 statusBar()->setVisible(!statusBar()->isVisible());
1897 if (arg == "menubar") {
1898 menuBar()->setVisible(!menuBar()->isVisible());
1901 #if QT_VERSION >= 0x040300
1902 if (arg == "frame") {
1904 getContentsMargins(&l, &t, &r, &b);
1905 //are the frames in default state?
1906 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1908 setContentsMargins(-2, -2, -2, -2);
1910 setContentsMargins(0, 0, 0, 0);
1915 if (arg != "fullscreen") {
1916 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1920 if (lyxrc.full_screen_toolbars)
1921 d.toolbars_->toggleFullScreen(!isFullScreen());
1923 if (isFullScreen()) {
1924 for (int i = 0; i != d.splitter_->count(); ++i)
1925 d.tabWorkArea(i)->setFullScreen(false);
1926 #if QT_VERSION >= 0x040300
1927 setContentsMargins(0, 0, 0, 0);
1931 statusBar()->show();
1933 for (int i = 0; i != d.splitter_->count(); ++i)
1934 d.tabWorkArea(i)->setFullScreen(true);
1935 #if QT_VERSION >= 0x040300
1936 setContentsMargins(-2, -2, -2, -2);
1939 statusBar()->hide();
1945 Buffer const * GuiView::updateInset(Inset const * inset)
1947 if (!d.current_work_area_)
1951 d.current_work_area_->scheduleRedraw();
1953 return &d.current_work_area_->bufferView().buffer();
1957 void GuiView::restartCursor()
1959 /* When we move around, or type, it's nice to be able to see
1960 * the cursor immediately after the keypress.
1962 if (d.current_work_area_)
1963 d.current_work_area_->startBlinkingCursor();
1965 // Take this occasion to update the other GUI elements.
1972 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1974 if (d.current_work_area_)
1975 d.current_work_area_->completer().updateVisibility(cur, start, keep);
1980 // This list should be kept in sync with the list of insets in
1981 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1982 // dialog should have the same name as the inset.
1984 char const * const dialognames[] = {
1985 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1986 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1987 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1988 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
1989 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1991 #ifdef HAVE_LIBAIKSAURUS
1995 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1997 char const * const * const end_dialognames =
1998 dialognames + (sizeof(dialognames) / sizeof(char *));
2002 cmpCStr(char const * name) : name_(name) {}
2003 bool operator()(char const * other) {
2004 return strcmp(other, name_) == 0;
2011 bool isValidName(string const & name)
2013 return find_if(dialognames, end_dialognames,
2014 cmpCStr(name.c_str())) != end_dialognames;
2020 void GuiView::resetDialogs()
2022 // Make sure that no LFUN uses any LyXView.
2023 theLyXFunc().setLyXView(0);
2024 // FIXME: the "math panels" toolbar takes an awful lot of time to
2025 // initialise so we don't do that for the time being.
2026 //d.toolbars_->init();
2027 guiApp->menus().fillMenuBar(menuBar(), this);
2029 d.layout_->updateContents(true);
2030 // Now update controls with current buffer.
2031 theLyXFunc().setLyXView(this);
2036 Dialog * GuiView::find_or_build(string const & name)
2038 if (!isValidName(name))
2041 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2043 if (it != d.dialogs_.end())
2044 return it->second.get();
2046 Dialog * dialog = build(name);
2047 d.dialogs_[name].reset(dialog);
2048 if (lyxrc.allow_geometry_session)
2049 dialog->restoreSession();
2054 void GuiView::showDialog(string const & name, string const & data,
2061 Dialog * dialog = find_or_build(name);
2063 dialog->showData(data);
2065 d.open_insets_[name] = inset;
2071 bool GuiView::isDialogVisible(string const & name) const
2073 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2074 if (it == d.dialogs_.end())
2076 return it->second.get()->isVisibleView();
2080 void GuiView::hideDialog(string const & name, Inset * inset)
2082 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2083 if (it == d.dialogs_.end())
2086 if (inset && inset != getOpenInset(name))
2089 Dialog * const dialog = it->second.get();
2090 if (dialog->isVisibleView())
2092 d.open_insets_[name] = 0;
2096 void GuiView::disconnectDialog(string const & name)
2098 if (!isValidName(name))
2101 if (d.open_insets_.find(name) != d.open_insets_.end())
2102 d.open_insets_[name] = 0;
2106 Inset * GuiView::getOpenInset(string const & name) const
2108 if (!isValidName(name))
2111 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2112 return it == d.open_insets_.end() ? 0 : it->second;
2116 void GuiView::hideAll() const
2118 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2119 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2121 for(; it != end; ++it)
2122 it->second->hideView();
2126 void GuiView::hideBufferDependent() const
2128 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2129 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2131 for(; it != end; ++it) {
2132 Dialog * dialog = it->second.get();
2133 if (dialog->isBufferDependent())
2139 void GuiView::updateBufferDependent(bool switched) const
2141 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2142 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2144 for(; it != end; ++it) {
2145 Dialog * dialog = it->second.get();
2146 if (!dialog->isVisibleView())
2148 if (switched && dialog->isBufferDependent()) {
2149 if (dialog->initialiseParams(""))
2150 dialog->updateView();
2154 // A bit clunky, but the dialog will request
2155 // that the kernel provides it with the necessary
2157 dialog->updateDialog();
2163 void GuiView::checkStatus()
2165 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2166 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2168 for(; it != end; ++it) {
2169 Dialog * const dialog = it->second.get();
2170 if (dialog && dialog->isVisibleView())
2171 dialog->checkStatus();
2177 // will be replaced by a proper factory...
2178 Dialog * createGuiAbout(GuiView & lv);
2179 Dialog * createGuiBibitem(GuiView & lv);
2180 Dialog * createGuiBibtex(GuiView & lv);
2181 Dialog * createGuiBox(GuiView & lv);
2182 Dialog * createGuiBranch(GuiView & lv);
2183 Dialog * createGuiChanges(GuiView & lv);
2184 Dialog * createGuiCharacter(GuiView & lv);
2185 Dialog * createGuiCitation(GuiView & lv);
2186 Dialog * createGuiDelimiter(GuiView & lv);
2187 Dialog * createGuiDocument(GuiView & lv);
2188 Dialog * createGuiErrorList(GuiView & lv);
2189 Dialog * createGuiERT(GuiView & lv);
2190 Dialog * createGuiExternal(GuiView & lv);
2191 Dialog * createGuiFloat(GuiView & lv);
2192 Dialog * createGuiGraphics(GuiView & lv);
2193 Dialog * createGuiInclude(GuiView & lv);
2194 Dialog * createGuiLabel(GuiView & lv);
2195 Dialog * createGuiListings(GuiView & lv);
2196 Dialog * createGuiLog(GuiView & lv);
2197 Dialog * createGuiMathMatrix(GuiView & lv);
2198 Dialog * createGuiNomenclature(GuiView & lv);
2199 Dialog * createGuiNote(GuiView & lv);
2200 Dialog * createGuiParagraph(GuiView & lv);
2201 Dialog * createGuiPreferences(GuiView & lv);
2202 Dialog * createGuiPrint(GuiView & lv);
2203 Dialog * createGuiRef(GuiView & lv);
2204 Dialog * createGuiSearch(GuiView & lv);
2205 Dialog * createGuiSendTo(GuiView & lv);
2206 Dialog * createGuiShowFile(GuiView & lv);
2207 Dialog * createGuiSpellchecker(GuiView & lv);
2208 Dialog * createGuiSymbols(GuiView & lv);
2209 Dialog * createGuiTabularCreate(GuiView & lv);
2210 Dialog * createGuiTabular(GuiView & lv);
2211 Dialog * createGuiTexInfo(GuiView & lv);
2212 Dialog * createGuiToc(GuiView & lv);
2213 Dialog * createGuiThesaurus(GuiView & lv);
2214 Dialog * createGuiHyperlink(GuiView & lv);
2215 Dialog * createGuiVSpace(GuiView & lv);
2216 Dialog * createGuiViewSource(GuiView & lv);
2217 Dialog * createGuiWrap(GuiView & lv);
2220 Dialog * GuiView::build(string const & name)
2222 BOOST_ASSERT(isValidName(name));
2224 if (name == "aboutlyx")
2225 return createGuiAbout(*this);
2226 if (name == "bibitem")
2227 return createGuiBibitem(*this);
2228 if (name == "bibtex")
2229 return createGuiBibtex(*this);
2231 return createGuiBox(*this);
2232 if (name == "branch")
2233 return createGuiBranch(*this);
2234 if (name == "changes")
2235 return createGuiChanges(*this);
2236 if (name == "character")
2237 return createGuiCharacter(*this);
2238 if (name == "citation")
2239 return createGuiCitation(*this);
2240 if (name == "document")
2241 return createGuiDocument(*this);
2242 if (name == "errorlist")
2243 return createGuiErrorList(*this);
2245 return createGuiERT(*this);
2246 if (name == "external")
2247 return createGuiExternal(*this);
2249 return createGuiShowFile(*this);
2250 if (name == "findreplace")
2251 return createGuiSearch(*this);
2252 if (name == "float")
2253 return createGuiFloat(*this);
2254 if (name == "graphics")
2255 return createGuiGraphics(*this);
2256 if (name == "include")
2257 return createGuiInclude(*this);
2258 if (name == "nomenclature")
2259 return createGuiNomenclature(*this);
2260 if (name == "label")
2261 return createGuiLabel(*this);
2263 return createGuiLog(*this);
2264 if (name == "view-source")
2265 return createGuiViewSource(*this);
2266 if (name == "mathdelimiter")
2267 return createGuiDelimiter(*this);
2268 if (name == "mathmatrix")
2269 return createGuiMathMatrix(*this);
2271 return createGuiNote(*this);
2272 if (name == "paragraph")
2273 return createGuiParagraph(*this);
2274 if (name == "prefs")
2275 return createGuiPreferences(*this);
2276 if (name == "print")
2277 return createGuiPrint(*this);
2279 return createGuiRef(*this);
2280 if (name == "sendto")
2281 return createGuiSendTo(*this);
2282 if (name == "spellchecker")
2283 return createGuiSpellchecker(*this);
2284 if (name == "symbols")
2285 return createGuiSymbols(*this);
2286 if (name == "tabular")
2287 return createGuiTabular(*this);
2288 if (name == "tabularcreate")
2289 return createGuiTabularCreate(*this);
2290 if (name == "texinfo")
2291 return createGuiTexInfo(*this);
2292 #ifdef HAVE_LIBAIKSAURUS
2293 if (name == "thesaurus")
2294 return createGuiThesaurus(*this);
2297 return createGuiToc(*this);
2299 return createGuiHyperlink(*this);
2300 if (name == "vspace")
2301 return createGuiVSpace(*this);
2303 return createGuiWrap(*this);
2304 if (name == "listings")
2305 return createGuiListings(*this);
2311 } // namespace frontend
2314 #include "GuiView_moc.cpp"