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);
1189 buf->errors("Parse");
1190 str2 = bformat(_("Document %1$s opened."), disp_fn);
1192 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1197 // FIXME: clean that
1198 static bool import(GuiView * lv, FileName const & filename,
1199 string const & format, ErrorList & errorList)
1201 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1203 string loader_format;
1204 vector<string> loaders = theConverters().loaders();
1205 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1206 for (vector<string>::const_iterator it = loaders.begin();
1207 it != loaders.end(); ++it) {
1208 if (!theConverters().isReachable(format, *it))
1211 string const tofile =
1212 support::changeExtension(filename.absFilename(),
1213 formats.extension(*it));
1214 if (!theConverters().convert(0, filename, FileName(tofile),
1215 filename, format, *it, errorList))
1217 loader_format = *it;
1220 if (loader_format.empty()) {
1221 frontend::Alert::error(_("Couldn't import file"),
1222 bformat(_("No information for importing the format %1$s."),
1223 formats.prettyName(format)));
1227 loader_format = format;
1229 if (loader_format == "lyx") {
1230 Buffer * buf = lv->loadDocument(lyxfile);
1235 buf->errors("Parse");
1237 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1241 bool as_paragraphs = loader_format == "textparagraph";
1242 string filename2 = (loader_format == format) ? filename.absFilename()
1243 : support::changeExtension(filename.absFilename(),
1244 formats.extension(loader_format));
1245 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1246 theLyXFunc().setLyXView(lv);
1247 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1254 void GuiView::importDocument(string const & argument)
1257 string filename = split(argument, format, ' ');
1259 LYXERR(Debug::INFO, format << " file: " << filename);
1261 // need user interaction
1262 if (filename.empty()) {
1263 string initpath = lyxrc.document_path;
1265 Buffer const * buf = buffer();
1267 string const trypath = buf->filePath();
1268 // If directory is writeable, use this as default.
1269 if (FileName(trypath).isDirWritable())
1273 docstring const text = bformat(_("Select %1$s file to import"),
1274 formats.prettyName(format));
1276 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1277 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1278 dlg.setButton2(qt_("Examples|#E#e"),
1279 toqstr(addPath(package().system_support().absFilename(), "examples")));
1281 docstring filter = formats.prettyName(format);
1284 filter += from_utf8(formats.extension(format));
1287 FileDialog::Result result =
1288 dlg.open(toqstr(initpath), FileFilterList(filter));
1290 if (result.first == FileDialog::Later)
1293 filename = fromqstr(result.second);
1295 // check selected filename
1296 if (filename.empty())
1297 message(_("Canceled."));
1300 if (filename.empty())
1303 // get absolute path of file
1304 FileName const fullname(makeAbsPath(filename));
1306 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1308 // Check if the document already is open
1309 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1312 if (!closeBuffer()) {
1313 message(_("Canceled."));
1318 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1320 // if the file exists already, and we didn't do
1321 // -i lyx thefile.lyx, warn
1322 if (lyxfile.exists() && fullname != lyxfile) {
1324 docstring text = bformat(_("The document %1$s already exists.\n\n"
1325 "Do you want to overwrite that document?"), displaypath);
1326 int const ret = Alert::prompt(_("Overwrite document?"),
1327 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1330 message(_("Canceled."));
1335 message(bformat(_("Importing %1$s..."), displaypath));
1336 ErrorList errorList;
1337 if (import(this, fullname, format, errorList))
1338 message(_("imported."));
1340 message(_("file not imported!"));
1342 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1346 void GuiView::newDocument(string const & filename, bool from_template)
1348 FileName initpath(lyxrc.document_path);
1349 Buffer * buf = buffer();
1351 FileName const trypath(buf->filePath());
1352 // If directory is writeable, use this as default.
1353 if (trypath.isDirWritable())
1357 string templatefile = from_template ?
1358 selectTemplateFile().absFilename() : string();
1360 if (filename.empty())
1361 b = newUnnamedFile(templatefile, initpath);
1363 b = newFile(filename, templatefile, true);
1367 // Ensure the cursor is correctly positionned on screen.
1368 view()->showCursor();
1372 void GuiView::insertLyXFile(docstring const & fname)
1374 BufferView * bv = view();
1379 FileName filename(to_utf8(fname));
1381 if (!filename.empty()) {
1382 bv->insertLyXFile(filename);
1386 // Launch a file browser
1388 string initpath = lyxrc.document_path;
1389 string const trypath = bv->buffer().filePath();
1390 // If directory is writeable, use this as default.
1391 if (FileName(trypath).isDirWritable())
1395 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1396 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1397 dlg.setButton2(qt_("Examples|#E#e"),
1398 toqstr(addPath(package().system_support().absFilename(),
1401 FileDialog::Result result =
1402 dlg.open(toqstr(initpath),
1403 FileFilterList(_("LyX Documents (*.lyx)")));
1405 if (result.first == FileDialog::Later)
1409 filename.set(fromqstr(result.second));
1411 // check selected filename
1412 if (filename.empty()) {
1413 // emit message signal.
1414 message(_("Canceled."));
1418 bv->insertLyXFile(filename);
1422 void GuiView::insertPlaintextFile(docstring const & fname,
1425 BufferView * bv = view();
1430 FileName filename(to_utf8(fname));
1432 if (!filename.empty()) {
1433 bv->insertPlaintextFile(filename, asParagraph);
1437 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1438 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1440 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1443 if (result.first == FileDialog::Later)
1447 filename.set(fromqstr(result.second));
1449 // check selected filename
1450 if (filename.empty()) {
1451 // emit message signal.
1452 message(_("Canceled."));
1456 bv->insertPlaintextFile(filename, asParagraph);
1460 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1462 FileName fname = b.fileName();
1463 FileName const oldname = fname;
1465 if (!newname.empty()) {
1467 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1469 // Switch to this Buffer.
1472 /// No argument? Ask user through dialog.
1474 FileDialog dlg(qt_("Choose a filename to save document as"),
1475 LFUN_BUFFER_WRITE_AS);
1476 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1477 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1479 if (!isLyXFilename(fname.absFilename()))
1480 fname.changeExtension(".lyx");
1482 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1484 FileDialog::Result result =
1485 dlg.save(toqstr(fname.onlyPath().absFilename()),
1487 toqstr(fname.onlyFileName()));
1489 if (result.first == FileDialog::Later)
1492 fname.set(fromqstr(result.second));
1497 if (!isLyXFilename(fname.absFilename()))
1498 fname.changeExtension(".lyx");
1501 if (FileName(fname).exists()) {
1502 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1503 docstring text = bformat(_("The document %1$s already "
1504 "exists.\n\nDo you want to "
1505 "overwrite that document?"),
1507 int const ret = Alert::prompt(_("Overwrite document?"),
1508 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1511 case 1: return renameBuffer(b, docstring());
1512 case 2: return false;
1516 // Ok, change the name of the buffer
1517 b.setFileName(fname.absFilename());
1519 bool unnamed = b.isUnnamed();
1520 b.setUnnamed(false);
1521 b.saveCheckSum(fname);
1523 if (!saveBuffer(b)) {
1524 b.setFileName(oldname.absFilename());
1525 b.setUnnamed(unnamed);
1526 b.saveCheckSum(oldname);
1534 bool GuiView::saveBuffer(Buffer & b)
1537 return renameBuffer(b, docstring());
1540 LyX::ref().session().lastFiles().add(b.fileName());
1544 // Switch to this Buffer.
1547 // FIXME: we don't tell the user *WHY* the save failed !!
1548 docstring const file = makeDisplayPath(b.absFileName(), 30);
1549 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1550 "Do you want to rename the document and "
1551 "try again?"), file);
1552 int const ret = Alert::prompt(_("Rename and save?"),
1553 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1556 if (!renameBuffer(b, docstring()))
1565 return saveBuffer(b);
1569 bool GuiView::closeBuffer()
1571 Buffer * buf = buffer();
1572 return buf && closeBuffer(*buf);
1576 bool GuiView::closeBuffer(Buffer & buf)
1578 // goto bookmark to update bookmark pit.
1579 //FIXME: we should update only the bookmarks related to this buffer!
1580 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1581 theLyXFunc().gotoBookmark(i+1, false, false);
1583 if (buf.isClean() || buf.paragraphs().empty()) {
1584 if (buf.masterBuffer() == &buf)
1585 LyX::ref().session().lastOpened().add(buf.fileName());
1586 theBufferList().release(&buf);
1589 // Switch to this Buffer.
1594 if (buf.isUnnamed())
1595 file = from_utf8(buf.fileName().onlyFileName());
1597 file = buf.fileName().displayName(30);
1599 // Bring this window to top before asking questions.
1603 docstring const text = bformat(_("The document %1$s has unsaved changes."
1604 "\n\nDo you want to save the document or discard the changes?"), file);
1605 int const ret = Alert::prompt(_("Save changed document?"),
1606 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1610 if (!saveBuffer(buf))
1614 // if we crash after this we could
1615 // have no autosave file but I guess
1616 // this is really improbable (Jug)
1617 removeAutosaveFile(buf.absFileName());
1623 // save file names to .lyx/session
1624 // if master/slave are both open, do not save slave since it
1625 // will be automatically loaded when the master is loaded
1626 if (buf.masterBuffer() == &buf)
1627 LyX::ref().session().lastOpened().add(buf.fileName());
1629 theBufferList().release(&buf);
1634 bool GuiView::dispatch(FuncRequest const & cmd)
1636 BufferView * bv = view();
1637 // By default we won't need any update.
1639 bv->cursor().updateFlags(Update::None);
1641 switch(cmd.action) {
1642 case LFUN_FILE_OPEN:
1643 openDocument(to_utf8(cmd.argument()));
1646 case LFUN_BUFFER_IMPORT:
1647 importDocument(to_utf8(cmd.argument()));
1650 case LFUN_BUFFER_SWITCH:
1651 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1654 case LFUN_BUFFER_NEXT:
1655 setBuffer(theBufferList().next(buffer()));
1658 case LFUN_BUFFER_PREVIOUS:
1659 setBuffer(theBufferList().previous(buffer()));
1662 case LFUN_COMMAND_EXECUTE: {
1663 bool const show_it = cmd.argument() != "off";
1664 d.toolbars_->showCommandBuffer(show_it);
1667 case LFUN_DROP_LAYOUTS_CHOICE:
1669 d.layout_->showPopup();
1672 case LFUN_MENU_OPEN:
1673 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1674 menu->exec(QCursor::pos());
1677 case LFUN_FILE_INSERT:
1678 insertLyXFile(cmd.argument());
1680 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1681 insertPlaintextFile(cmd.argument(), true);
1684 case LFUN_FILE_INSERT_PLAINTEXT:
1685 insertPlaintextFile(cmd.argument(), false);
1688 case LFUN_BUFFER_WRITE:
1690 saveBuffer(bv->buffer());
1693 case LFUN_BUFFER_WRITE_AS:
1695 renameBuffer(bv->buffer(), cmd.argument());
1698 case LFUN_BUFFER_WRITE_ALL: {
1699 Buffer * first = theBufferList().first();
1702 message(_("Saving all documents..."));
1703 // We cannot use a for loop as the buffer list cycles.
1709 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1710 b = theBufferList().next(b);
1711 } while (b != first);
1712 message(_("All documents saved."));
1716 case LFUN_TOOLBAR_TOGGLE: {
1717 string const name = cmd.getArg(0);
1718 bool const allowauto = cmd.getArg(1) == "allowauto";
1719 // it is possible to get current toolbar status like this,...
1720 // but I decide to obey the order of ToolbarBackend::flags
1721 // and disregard real toolbar status.
1722 // toolbars_->saveToolbarInfo();
1724 // toggle state on/off/auto
1725 d.toolbars_->toggleToolbarState(name, allowauto);
1729 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1731 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1735 if (tbi->flags & ToolbarInfo::ON)
1737 else if (tbi->flags & ToolbarInfo::OFF)
1739 else if (tbi->flags & ToolbarInfo::AUTO)
1742 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1743 _(tbi->gui_name), state));
1747 case LFUN_DIALOG_UPDATE: {
1748 string const name = to_utf8(cmd.argument());
1749 // Can only update a dialog connected to an existing inset
1750 Inset * inset = getOpenInset(name);
1752 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1753 inset->dispatch(view()->cursor(), fr);
1754 } else if (name == "paragraph") {
1755 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1756 } else if (name == "prefs") {
1757 updateDialog(name, string());
1762 case LFUN_DIALOG_TOGGLE: {
1763 if (isDialogVisible(cmd.getArg(0)))
1764 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1766 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1770 case LFUN_DIALOG_DISCONNECT_INSET:
1771 disconnectDialog(to_utf8(cmd.argument()));
1774 case LFUN_DIALOG_HIDE: {
1775 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1779 case LFUN_DIALOG_SHOW: {
1780 string const name = cmd.getArg(0);
1781 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1783 if (name == "character") {
1784 data = freefont2string();
1786 showDialog("character", data);
1787 } else if (name == "latexlog") {
1788 Buffer::LogType type;
1789 string const logfile = buffer()->logName(&type);
1791 case Buffer::latexlog:
1794 case Buffer::buildlog:
1798 data += Lexer::quoteString(logfile);
1799 showDialog("log", data);
1800 } else if (name == "vclog") {
1801 string const data = "vc " +
1802 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1803 showDialog("log", data);
1804 } else if (name == "symbols") {
1805 data = bv->cursor().getEncoding()->name();
1807 showDialog("symbols", data);
1809 showDialog(name, data);
1813 case LFUN_INSET_APPLY: {
1814 string const name = cmd.getArg(0);
1815 Inset * inset = getOpenInset(name);
1817 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1818 inset->dispatch(view()->cursor(), fr);
1820 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1826 case LFUN_UI_TOGGLE:
1828 // Make sure the keyboard focus stays in the work area.
1832 case LFUN_COMPLETION_INLINE:
1833 if (d.current_work_area_)
1834 d.current_work_area_->completer().showInline();
1837 case LFUN_SPLIT_VIEW:
1838 if (Buffer * buf = buffer()) {
1839 string const orientation = cmd.getArg(0);
1840 d.splitter_->setOrientation(orientation == "vertical"
1841 ? Qt::Vertical : Qt::Horizontal);
1842 TabWorkArea * twa = addTabWorkArea();
1843 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1844 setCurrentWorkArea(wa);
1848 case LFUN_CLOSE_TAB_GROUP:
1849 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1851 twa = d.currentTabWorkArea();
1852 // Switch to the next GuiWorkArea in the found TabWorkArea.
1853 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1854 if (d.splitter_->count() == 0)
1855 // No more work area, switch to the background widget.
1860 case LFUN_COMPLETION_POPUP:
1861 if (d.current_work_area_)
1862 d.current_work_area_->completer().showPopup();
1866 case LFUN_COMPLETION_COMPLETE:
1867 if (d.current_work_area_)
1868 d.current_work_area_->completer().tab();
1879 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1881 string const arg = cmd.getArg(0);
1882 if (arg == "scrollbar") {
1883 // hide() is of no help
1884 if (d.current_work_area_->verticalScrollBarPolicy() ==
1885 Qt::ScrollBarAlwaysOff)
1887 d.current_work_area_->setVerticalScrollBarPolicy(
1888 Qt::ScrollBarAsNeeded);
1890 d.current_work_area_->setVerticalScrollBarPolicy(
1891 Qt::ScrollBarAlwaysOff);
1894 if (arg == "statusbar") {
1895 statusBar()->setVisible(!statusBar()->isVisible());
1898 if (arg == "menubar") {
1899 menuBar()->setVisible(!menuBar()->isVisible());
1902 #if QT_VERSION >= 0x040300
1903 if (arg == "frame") {
1905 getContentsMargins(&l, &t, &r, &b);
1906 //are the frames in default state?
1907 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1909 setContentsMargins(-2, -2, -2, -2);
1911 setContentsMargins(0, 0, 0, 0);
1916 if (arg != "fullscreen") {
1917 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1921 if (lyxrc.full_screen_toolbars)
1922 d.toolbars_->toggleFullScreen(!isFullScreen());
1924 if (isFullScreen()) {
1925 for (int i = 0; i != d.splitter_->count(); ++i)
1926 d.tabWorkArea(i)->setFullScreen(false);
1927 #if QT_VERSION >= 0x040300
1928 setContentsMargins(0, 0, 0, 0);
1932 statusBar()->show();
1934 for (int i = 0; i != d.splitter_->count(); ++i)
1935 d.tabWorkArea(i)->setFullScreen(true);
1936 #if QT_VERSION >= 0x040300
1937 setContentsMargins(-2, -2, -2, -2);
1940 statusBar()->hide();
1946 Buffer const * GuiView::updateInset(Inset const * inset)
1948 if (!d.current_work_area_)
1952 d.current_work_area_->scheduleRedraw();
1954 return &d.current_work_area_->bufferView().buffer();
1958 void GuiView::restartCursor()
1960 /* When we move around, or type, it's nice to be able to see
1961 * the cursor immediately after the keypress.
1963 if (d.current_work_area_)
1964 d.current_work_area_->startBlinkingCursor();
1966 // Take this occasion to update the other GUI elements.
1973 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1975 if (d.current_work_area_)
1976 d.current_work_area_->completer().updateVisibility(cur, start, keep);
1981 // This list should be kept in sync with the list of insets in
1982 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1983 // dialog should have the same name as the inset.
1985 char const * const dialognames[] = {
1986 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1987 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1988 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1989 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
1990 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
1992 #ifdef HAVE_LIBAIKSAURUS
1996 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1998 char const * const * const end_dialognames =
1999 dialognames + (sizeof(dialognames) / sizeof(char *));
2003 cmpCStr(char const * name) : name_(name) {}
2004 bool operator()(char const * other) {
2005 return strcmp(other, name_) == 0;
2012 bool isValidName(string const & name)
2014 return find_if(dialognames, end_dialognames,
2015 cmpCStr(name.c_str())) != end_dialognames;
2021 void GuiView::resetDialogs()
2023 // Make sure that no LFUN uses any LyXView.
2024 theLyXFunc().setLyXView(0);
2025 // FIXME: the "math panels" toolbar takes an awful lot of time to
2026 // initialise so we don't do that for the time being.
2027 //d.toolbars_->init();
2028 guiApp->menus().fillMenuBar(menuBar(), this);
2030 d.layout_->updateContents(true);
2031 // Now update controls with current buffer.
2032 theLyXFunc().setLyXView(this);
2037 Dialog * GuiView::find_or_build(string const & name)
2039 if (!isValidName(name))
2042 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2044 if (it != d.dialogs_.end())
2045 return it->second.get();
2047 Dialog * dialog = build(name);
2048 d.dialogs_[name].reset(dialog);
2049 if (lyxrc.allow_geometry_session)
2050 dialog->restoreSession();
2055 void GuiView::showDialog(string const & name, string const & data,
2062 Dialog * dialog = find_or_build(name);
2064 dialog->showData(data);
2066 d.open_insets_[name] = inset;
2072 bool GuiView::isDialogVisible(string const & name) const
2074 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2075 if (it == d.dialogs_.end())
2077 return it->second.get()->isVisibleView();
2081 void GuiView::hideDialog(string const & name, Inset * inset)
2083 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2084 if (it == d.dialogs_.end())
2087 if (inset && inset != getOpenInset(name))
2090 Dialog * const dialog = it->second.get();
2091 if (dialog->isVisibleView())
2093 d.open_insets_[name] = 0;
2097 void GuiView::disconnectDialog(string const & name)
2099 if (!isValidName(name))
2102 if (d.open_insets_.find(name) != d.open_insets_.end())
2103 d.open_insets_[name] = 0;
2107 Inset * GuiView::getOpenInset(string const & name) const
2109 if (!isValidName(name))
2112 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2113 return it == d.open_insets_.end() ? 0 : it->second;
2117 void GuiView::hideAll() const
2119 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2120 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2122 for(; it != end; ++it)
2123 it->second->hideView();
2127 void GuiView::hideBufferDependent() const
2129 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2130 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2132 for(; it != end; ++it) {
2133 Dialog * dialog = it->second.get();
2134 if (dialog->isBufferDependent())
2140 void GuiView::updateBufferDependent(bool switched) const
2142 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2143 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2145 for(; it != end; ++it) {
2146 Dialog * dialog = it->second.get();
2147 if (!dialog->isVisibleView())
2149 if (switched && dialog->isBufferDependent()) {
2150 if (dialog->initialiseParams(""))
2151 dialog->updateView();
2155 // A bit clunky, but the dialog will request
2156 // that the kernel provides it with the necessary
2158 dialog->updateDialog();
2164 void GuiView::checkStatus()
2166 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2167 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2169 for(; it != end; ++it) {
2170 Dialog * const dialog = it->second.get();
2171 if (dialog && dialog->isVisibleView())
2172 dialog->checkStatus();
2178 // will be replaced by a proper factory...
2179 Dialog * createGuiAbout(GuiView & lv);
2180 Dialog * createGuiBibitem(GuiView & lv);
2181 Dialog * createGuiBibtex(GuiView & lv);
2182 Dialog * createGuiBox(GuiView & lv);
2183 Dialog * createGuiBranch(GuiView & lv);
2184 Dialog * createGuiChanges(GuiView & lv);
2185 Dialog * createGuiCharacter(GuiView & lv);
2186 Dialog * createGuiCitation(GuiView & lv);
2187 Dialog * createGuiDelimiter(GuiView & lv);
2188 Dialog * createGuiDocument(GuiView & lv);
2189 Dialog * createGuiErrorList(GuiView & lv);
2190 Dialog * createGuiERT(GuiView & lv);
2191 Dialog * createGuiExternal(GuiView & lv);
2192 Dialog * createGuiFloat(GuiView & lv);
2193 Dialog * createGuiGraphics(GuiView & lv);
2194 Dialog * createGuiInclude(GuiView & lv);
2195 Dialog * createGuiLabel(GuiView & lv);
2196 Dialog * createGuiListings(GuiView & lv);
2197 Dialog * createGuiLog(GuiView & lv);
2198 Dialog * createGuiMathMatrix(GuiView & lv);
2199 Dialog * createGuiNomenclature(GuiView & lv);
2200 Dialog * createGuiNote(GuiView & lv);
2201 Dialog * createGuiParagraph(GuiView & lv);
2202 Dialog * createGuiPreferences(GuiView & lv);
2203 Dialog * createGuiPrint(GuiView & lv);
2204 Dialog * createGuiRef(GuiView & lv);
2205 Dialog * createGuiSearch(GuiView & lv);
2206 Dialog * createGuiSendTo(GuiView & lv);
2207 Dialog * createGuiShowFile(GuiView & lv);
2208 Dialog * createGuiSpellchecker(GuiView & lv);
2209 Dialog * createGuiSymbols(GuiView & lv);
2210 Dialog * createGuiTabularCreate(GuiView & lv);
2211 Dialog * createGuiTabular(GuiView & lv);
2212 Dialog * createGuiTexInfo(GuiView & lv);
2213 Dialog * createGuiToc(GuiView & lv);
2214 Dialog * createGuiThesaurus(GuiView & lv);
2215 Dialog * createGuiHyperlink(GuiView & lv);
2216 Dialog * createGuiVSpace(GuiView & lv);
2217 Dialog * createGuiViewSource(GuiView & lv);
2218 Dialog * createGuiWrap(GuiView & lv);
2221 Dialog * GuiView::build(string const & name)
2223 BOOST_ASSERT(isValidName(name));
2225 if (name == "aboutlyx")
2226 return createGuiAbout(*this);
2227 if (name == "bibitem")
2228 return createGuiBibitem(*this);
2229 if (name == "bibtex")
2230 return createGuiBibtex(*this);
2232 return createGuiBox(*this);
2233 if (name == "branch")
2234 return createGuiBranch(*this);
2235 if (name == "changes")
2236 return createGuiChanges(*this);
2237 if (name == "character")
2238 return createGuiCharacter(*this);
2239 if (name == "citation")
2240 return createGuiCitation(*this);
2241 if (name == "document")
2242 return createGuiDocument(*this);
2243 if (name == "errorlist")
2244 return createGuiErrorList(*this);
2246 return createGuiERT(*this);
2247 if (name == "external")
2248 return createGuiExternal(*this);
2250 return createGuiShowFile(*this);
2251 if (name == "findreplace")
2252 return createGuiSearch(*this);
2253 if (name == "float")
2254 return createGuiFloat(*this);
2255 if (name == "graphics")
2256 return createGuiGraphics(*this);
2257 if (name == "include")
2258 return createGuiInclude(*this);
2259 if (name == "nomenclature")
2260 return createGuiNomenclature(*this);
2261 if (name == "label")
2262 return createGuiLabel(*this);
2264 return createGuiLog(*this);
2265 if (name == "view-source")
2266 return createGuiViewSource(*this);
2267 if (name == "mathdelimiter")
2268 return createGuiDelimiter(*this);
2269 if (name == "mathmatrix")
2270 return createGuiMathMatrix(*this);
2272 return createGuiNote(*this);
2273 if (name == "paragraph")
2274 return createGuiParagraph(*this);
2275 if (name == "prefs")
2276 return createGuiPreferences(*this);
2277 if (name == "print")
2278 return createGuiPrint(*this);
2280 return createGuiRef(*this);
2281 if (name == "sendto")
2282 return createGuiSendTo(*this);
2283 if (name == "spellchecker")
2284 return createGuiSpellchecker(*this);
2285 if (name == "symbols")
2286 return createGuiSymbols(*this);
2287 if (name == "tabular")
2288 return createGuiTabular(*this);
2289 if (name == "tabularcreate")
2290 return createGuiTabularCreate(*this);
2291 if (name == "texinfo")
2292 return createGuiTexInfo(*this);
2293 #ifdef HAVE_LIBAIKSAURUS
2294 if (name == "thesaurus")
2295 return createGuiThesaurus(*this);
2298 return createGuiToc(*this);
2300 return createGuiHyperlink(*this);
2301 if (name == "vspace")
2302 return createGuiVSpace(*this);
2304 return createGuiWrap(*this);
2305 if (name == "listings")
2306 return createGuiListings(*this);
2312 } // namespace frontend
2315 #include "GuiView_moc.cpp"