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 "frontends/FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiWorkArea.h"
22 #include "GuiKeySymbol.h"
23 #include "GuiMenubar.h"
24 #include "GuiToolbar.h"
25 #include "GuiToolbars.h"
27 #include "qt_helpers.h"
29 #include "buffer_funcs.h"
31 #include "BufferList.h"
32 #include "BufferParams.h"
33 #include "BufferView.h"
35 #include "support/debug.h"
36 #include "ErrorList.h"
37 #include "FuncRequest.h"
38 #include "support/gettext.h"
46 #include "MenuBackend.h"
47 #include "Paragraph.h"
48 #include "TextClass.h"
50 #include "ToolbarBackend.h"
53 #include "support/FileFilterList.h"
54 #include "support/FileName.h"
55 #include "support/filetools.h"
56 #include "support/lstrings.h"
57 #include "support/os.h"
58 #include "support/Package.h"
59 #include "support/Timeout.h"
62 #include <QApplication>
63 #include <QCloseEvent>
65 #include <QDesktopWidget>
66 #include <QDragEnterEvent>
73 #include <QPushButton>
77 #include <QStackedWidget>
83 #include <boost/assert.hpp>
84 #include <boost/bind.hpp>
86 #ifdef HAVE_SYS_TIME_H
87 # include <sys/time.h>
103 using support::addPath;
104 using support::bformat;
105 using support::FileFilterList;
106 using support::FileName;
107 using support::package;
112 class BackgroundWidget : public QWidget
117 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
118 /// The text to be written on top of the pixmap
119 QString const text = lyx_version ? lyx_version : qt_("unknown version");
120 splash_ = QPixmap(":/images/banner.png");
122 QPainter pain(&splash_);
123 pain.setPen(QColor(255, 255, 0));
125 // The font used to display the version info
126 font.setStyleHint(QFont::SansSerif);
127 font.setWeight(QFont::Bold);
128 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
130 pain.drawText(260, 270, text);
133 void paintEvent(QPaintEvent *)
135 int x = (width() - splash_.width()) / 2;
136 int y = (height() - splash_.height()) / 2;
138 pain.drawPixmap(x, y, splash_);
148 typedef boost::shared_ptr<Dialog> DialogPtr;
150 struct GuiView::GuiViewPrivate
153 : current_work_area_(0), layout_(0),
154 quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false)
156 // hardcode here the platform specific icon size
157 smallIconSize = 14; // scaling problems
158 normalIconSize = 20; // ok, default
159 bigIconSize = 26; // better for some math icons
161 splitter_ = new QSplitter;
162 bg_widget_ = new BackgroundWidget;
163 stack_widget_ = new QStackedWidget;
164 stack_widget_->addWidget(bg_widget_);
165 stack_widget_->addWidget(splitter_);
173 delete stack_widget_;
178 QMenu * toolBarPopup(GuiView * parent)
180 // FIXME: translation
181 QMenu * menu = new QMenu(parent);
182 QActionGroup * iconSizeGroup = new QActionGroup(parent);
184 QAction * smallIcons = new QAction(iconSizeGroup);
185 smallIcons->setText(qt_("Small-sized icons"));
186 smallIcons->setCheckable(true);
187 QObject::connect(smallIcons, SIGNAL(triggered()),
188 parent, SLOT(smallSizedIcons()));
189 menu->addAction(smallIcons);
191 QAction * normalIcons = new QAction(iconSizeGroup);
192 normalIcons->setText(qt_("Normal-sized icons"));
193 normalIcons->setCheckable(true);
194 QObject::connect(normalIcons, SIGNAL(triggered()),
195 parent, SLOT(normalSizedIcons()));
196 menu->addAction(normalIcons);
198 QAction * bigIcons = new QAction(iconSizeGroup);
199 bigIcons->setText(qt_("Big-sized icons"));
200 bigIcons->setCheckable(true);
201 QObject::connect(bigIcons, SIGNAL(triggered()),
202 parent, SLOT(bigSizedIcons()));
203 menu->addAction(bigIcons);
205 unsigned int cur = parent->iconSize().width();
206 if ( cur == parent->d.smallIconSize)
207 smallIcons->setChecked(true);
208 else if (cur == parent->d.normalIconSize)
209 normalIcons->setChecked(true);
210 else if (cur == parent->d.bigIconSize)
211 bigIcons->setChecked(true);
218 stack_widget_->setCurrentWidget(bg_widget_);
219 bg_widget_->setUpdatesEnabled(true);
222 TabWorkArea * tabWorkArea(int i)
224 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
227 TabWorkArea * currentTabWorkArea()
229 if (splitter_->count() == 1)
230 // The first TabWorkArea is always the first one, if any.
231 return tabWorkArea(0);
233 TabWorkArea * tab_widget = 0;
234 for (int i = 0; i != splitter_->count(); ++i) {
235 QWidget * w = splitter_->widget(i);
238 tab_widget = dynamic_cast<TabWorkArea *>(w);
247 GuiWorkArea * current_work_area_;
248 QSplitter * splitter_;
249 QStackedWidget * stack_widget_;
250 BackgroundWidget * bg_widget_;
252 GuiMenubar * menubar_;
254 GuiToolbars * toolbars_;
255 /// The main layout box.
257 * \warning Don't Delete! The layout box is actually owned by
258 * whichever toolbar contains it. All the GuiView class needs is a
259 * means of accessing it.
261 * FIXME: replace that with a proper model so that we are not limited
262 * to only one dialog.
264 GuiLayoutBox * layout_;
267 std::map<std::string, Inset *> open_insets_;
270 std::map<std::string, DialogPtr> dialogs_;
272 unsigned int smallIconSize;
273 unsigned int normalIconSize;
274 unsigned int bigIconSize;
276 QTimer statusbar_timer_;
277 /// are we quitting by the menu?
278 bool quitting_by_menu_;
279 /// auto-saving of buffers
280 Timeout autosave_timeout_;
281 /// flag against a race condition due to multiclicks, see bug #1119
286 GuiView::GuiView(int id)
287 : d(*new GuiViewPrivate), id_(id)
289 // GuiToolbars *must* be initialised before GuiMenubar.
290 d.toolbars_ = new GuiToolbars(*this);
291 d.menubar_ = new GuiMenubar(this, menubackend);
293 setCentralWidget(d.stack_widget_);
295 // Start autosave timer
296 if (lyxrc.autosave) {
297 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
298 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
299 d.autosave_timeout_.start();
301 connect(&d.statusbar_timer_, SIGNAL(timeout()),
302 this, SLOT(clearMessage()));
304 // Qt bug? signal lastWindowClosed does not work
305 setAttribute(Qt::WA_QuitOnClose, false);
306 setAttribute(Qt::WA_DeleteOnClose, true);
308 // assign an icon to main form. We do not do it under Qt/Mac,
309 // since the icon is provided in the application bundle.
310 setWindowIcon(QPixmap(":/images/lyx.png"));
314 setAcceptDrops(true);
316 statusBar()->setSizeGripEnabled(true);
318 // Forbid too small unresizable window because it can happen
319 // with some window manager under X11.
320 setMinimumSize(300, 200);
322 if (!lyxrc.allow_geometry_session)
323 // No session handling, default to a sane size.
324 setGeometry(50, 50, 690, 510);
326 // Now take care of session management.
328 QString const key = "view-" + QString::number(id_);
330 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
331 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
335 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
336 setGeometry(50, 50, 690, 510);
338 setIconSize(settings.value(key + "/icon_size").toSize());
348 void GuiView::close()
350 d.quitting_by_menu_ = true;
351 d.current_work_area_ = 0;
352 for (int i = 0; i != d.splitter_->count(); ++i) {
353 TabWorkArea * twa = d.tabWorkArea(i);
357 QMainWindow::close();
358 d.quitting_by_menu_ = false;
362 void GuiView::setFocus()
364 if (d.current_work_area_)
365 d.current_work_area_->setFocus();
371 QMenu * GuiView::createPopupMenu()
373 return d.toolBarPopup(this);
377 void GuiView::showEvent(QShowEvent * e)
379 LYXERR(Debug::GUI, "Passed Geometry "
380 << size().height() << "x" << size().width()
381 << "+" << pos().x() << "+" << pos().y());
383 if (d.splitter_->count() == 0)
384 // No work area, switch to the background widget.
387 QMainWindow::showEvent(e);
391 void GuiView::closeEvent(QCloseEvent * close_event)
393 // we may have been called through the close window button
394 // which bypasses the LFUN machinery.
395 if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
396 if (!theBufferList().quitWriteAll()) {
397 close_event->ignore();
402 // Make sure that no LFUN use this close to be closed View.
403 theLyXFunc().setLyXView(0);
404 // Make sure the timer time out will not trigger a statusbar update.
405 d.statusbar_timer_.stop();
407 if (lyxrc.allow_geometry_session) {
409 QString const key = "view-" + QString::number(id_);
411 settings.setValue(key + "/pos", pos());
412 settings.setValue(key + "/size", size());
414 settings.setValue(key + "/geometry", saveGeometry());
416 settings.setValue(key + "/icon_size", iconSize());
417 d.toolbars_->saveToolbarInfo();
420 guiApp->unregisterView(id_);
421 if (guiApp->viewCount() > 0) {
422 // Just close the window and do nothing else if this is not the
424 close_event->accept();
430 // this is the place where we leave the frontend.
431 // it is the only point at which we start quitting.
432 close_event->accept();
433 // quit the event loop
438 void GuiView::dragEnterEvent(QDragEnterEvent * event)
440 if (event->mimeData()->hasUrls())
442 /// \todo Ask lyx-devel is this is enough:
443 /// if (event->mimeData()->hasFormat("text/plain"))
444 /// event->acceptProposedAction();
448 void GuiView::dropEvent(QDropEvent* event)
450 QList<QUrl> files = event->mimeData()->urls();
454 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
455 for (int i = 0; i != files.size(); ++i) {
456 string const file = support::os::internal_path(fromqstr(
457 files.at(i).toLocalFile()));
459 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
464 void GuiView::message(docstring const & str)
466 statusBar()->showMessage(toqstr(str));
467 d.statusbar_timer_.stop();
468 d.statusbar_timer_.start(3000);
472 void GuiView::smallSizedIcons()
474 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
478 void GuiView::normalSizedIcons()
480 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
484 void GuiView::bigSizedIcons()
486 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
490 void GuiView::clearMessage()
494 theLyXFunc().setLyXView(this);
495 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
496 d.statusbar_timer_.stop();
500 void GuiView::updateWindowTitle(GuiWorkArea * wa)
502 if (wa != d.current_work_area_)
504 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
505 setWindowIconText(wa->windowIconText());
509 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
512 disconnectBufferView();
513 connectBufferView(wa->bufferView());
514 connectBuffer(wa->bufferView().buffer());
515 d.current_work_area_ = wa;
516 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
517 this, SLOT(updateWindowTitle(GuiWorkArea *)));
518 updateWindowTitle(wa);
521 // Buffer-dependent dialogs should be updated or
522 // hidden. This should go here because some dialogs (eg ToC)
523 // require bv_->text.
524 updateBufferDependent(true);
531 void GuiView::updateStatusBar()
533 // let the user see the explicit message
534 if (d.statusbar_timer_.isActive())
537 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
541 bool GuiView::hasFocus() const
543 return qApp->activeWindow() == this;
547 bool GuiView::event(QEvent * e)
551 // Useful debug code:
552 //case QEvent::ActivationChange:
553 //case QEvent::WindowDeactivate:
554 //case QEvent::Paint:
555 //case QEvent::Enter:
556 //case QEvent::Leave:
557 //case QEvent::HoverEnter:
558 //case QEvent::HoverLeave:
559 //case QEvent::HoverMove:
560 //case QEvent::StatusTip:
561 //case QEvent::DragEnter:
562 //case QEvent::DragLeave:
566 case QEvent::WindowActivate: {
567 guiApp->setCurrentView(*this);
568 if (d.current_work_area_) {
569 BufferView & bv = d.current_work_area_->bufferView();
570 connectBufferView(bv);
571 connectBuffer(bv.buffer());
572 // The document structure, name and dialogs might have
573 // changed in another view.
574 updateBufferDependent(true);
576 setWindowTitle(qt_("LyX"));
577 setWindowIconText(qt_("LyX"));
579 return QMainWindow::event(e);
581 case QEvent::ShortcutOverride: {
582 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
583 if (!d.current_work_area_) {
584 theLyXFunc().setLyXView(this);
586 setKeySymbol(&sym, ke);
587 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
591 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
593 setKeySymbol(&sym, ke);
594 d.current_work_area_->processKeySym(sym, NoModifier);
600 return QMainWindow::event(e);
605 bool GuiView::focusNextPrevChild(bool /*next*/)
612 void GuiView::setBusy(bool yes)
614 if (d.current_work_area_) {
615 d.current_work_area_->setUpdatesEnabled(!yes);
617 d.current_work_area_->stopBlinkingCursor();
619 d.current_work_area_->startBlinkingCursor();
623 QApplication::setOverrideCursor(Qt::WaitCursor);
625 QApplication::restoreOverrideCursor();
629 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
631 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
633 if (tbinfo.flags & ToolbarInfo::TOP) {
635 addToolBarBreak(Qt::TopToolBarArea);
636 addToolBar(Qt::TopToolBarArea, toolBar);
639 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
640 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
641 #if (QT_VERSION >= 0x040202)
643 addToolBarBreak(Qt::BottomToolBarArea);
645 addToolBar(Qt::BottomToolBarArea, toolBar);
648 if (tbinfo.flags & ToolbarInfo::LEFT) {
649 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
650 #if (QT_VERSION >= 0x040202)
652 addToolBarBreak(Qt::LeftToolBarArea);
654 addToolBar(Qt::LeftToolBarArea, toolBar);
657 if (tbinfo.flags & ToolbarInfo::RIGHT) {
658 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
659 #if (QT_VERSION >= 0x040202)
661 addToolBarBreak(Qt::RightToolBarArea);
663 addToolBar(Qt::RightToolBarArea, toolBar);
666 // The following does not work so I cannot restore to exact toolbar location
668 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
669 toolBar->move(tbinfo.posx, tbinfo.posy);
676 GuiWorkArea * GuiView::workArea(Buffer & buffer)
678 for (int i = 0; i != d.splitter_->count(); ++i) {
679 GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
687 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
690 // Automatically create a TabWorkArea if there are none yet.
691 if (!d.splitter_->count())
694 TabWorkArea * tab_widget = d.currentTabWorkArea();
695 return tab_widget->addWorkArea(buffer, *this);
699 void GuiView::addTabWorkArea()
701 TabWorkArea * twa = new TabWorkArea;
702 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
703 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
704 d.splitter_->addWidget(twa);
705 d.stack_widget_->setCurrentWidget(d.splitter_);
709 GuiWorkArea const * GuiView::currentWorkArea() const
711 return d.current_work_area_;
715 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
719 // Changing work area can result from opening a file so
720 // update the toc in any case.
723 d.current_work_area_ = wa;
724 for (int i = 0; i != d.splitter_->count(); ++i) {
725 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
731 void GuiView::removeWorkArea(GuiWorkArea * wa)
734 if (wa == d.current_work_area_) {
736 disconnectBufferView();
737 hideBufferDependent();
738 d.current_work_area_ = 0;
741 for (int i = 0; i != d.splitter_->count(); ++i) {
742 TabWorkArea * twa = d.tabWorkArea(i);
743 if (!twa->removeWorkArea(wa))
744 // Not found in this tab group.
747 // We found and removed the GuiWorkArea.
749 // No more WorkAreas in this tab group, so delete it.
754 if (d.current_work_area_)
755 // This means that we are not closing the current GuiWorkArea;
758 // Switch to the next GuiWorkArea in the found TabWorkArea.
759 d.current_work_area_ = twa->currentWorkArea();
763 if (d.splitter_->count() == 0)
764 // No more work area, switch to the background widget.
769 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
775 void GuiView::updateLayoutList()
778 d.layout_->updateContents(false);
782 void GuiView::updateToolbars()
784 if (d.current_work_area_) {
786 d.current_work_area_->bufferView().cursor().inMathed();
788 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
790 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
791 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
793 d.toolbars_->update(math, table, review);
795 d.toolbars_->update(false, false, false);
797 // update read-only status of open dialogs.
802 Buffer * GuiView::buffer()
804 if (d.current_work_area_)
805 return &d.current_work_area_->bufferView().buffer();
810 Buffer const * GuiView::buffer() const
812 if (d.current_work_area_)
813 return &d.current_work_area_->bufferView().buffer();
818 void GuiView::setBuffer(Buffer * newBuffer)
820 BOOST_ASSERT(newBuffer);
823 GuiWorkArea * wa = workArea(*newBuffer);
825 updateLabels(*newBuffer->masterBuffer());
826 wa = addWorkArea(*newBuffer);
828 //Disconnect the old buffer...there's no new one.
831 connectBuffer(*newBuffer);
832 connectBufferView(wa->bufferView());
833 setCurrentWorkArea(wa);
839 void GuiView::connectBuffer(Buffer & buf)
841 buf.setGuiDelegate(this);
845 void GuiView::disconnectBuffer()
847 if (d.current_work_area_)
848 d.current_work_area_->bufferView().setGuiDelegate(0);
852 void GuiView::connectBufferView(BufferView & bv)
854 bv.setGuiDelegate(this);
858 void GuiView::disconnectBufferView()
860 if (d.current_work_area_)
861 d.current_work_area_->bufferView().setGuiDelegate(0);
865 void GuiView::errors(string const & error_type)
867 ErrorList & el = buffer()->errorList(error_type);
869 showDialog("errorlist", error_type);
873 void GuiView::updateDialog(string const & name, string const & data)
875 if (!isDialogVisible(name))
878 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
879 if (it == d.dialogs_.end())
882 Dialog * const dialog = it->second.get();
883 if (dialog->isVisibleView())
884 dialog->updateData(data);
888 BufferView * GuiView::view()
890 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
894 void GuiView::updateToc()
896 updateDialog("toc", "");
900 void GuiView::updateEmbeddedFiles()
902 updateDialog("embedding", "");
906 void GuiView::autoSave()
908 LYXERR(Debug::INFO, "Running autoSave()");
911 view()->buffer().autoSave();
915 void GuiView::resetAutosaveTimers()
918 d.autosave_timeout_.restart();
922 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
926 Buffer * buf = buffer();
928 /* In LyX/Mac, when a dialog is open, the menus of the
929 application can still be accessed without giving focus to
930 the main window. In this case, we want to disable the menu
931 entries that are buffer-related.
933 Note that this code is not perfect, as bug 1941 attests:
934 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
936 if (cmd.origin == FuncRequest::MENU && !hasFocus())
940 case LFUN_TOOLBAR_TOGGLE:
941 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
944 case LFUN_DIALOG_TOGGLE:
945 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
946 // fall through to set "enable"
947 case LFUN_DIALOG_SHOW: {
948 string const name = cmd.getArg(0);
950 enable = name == "aboutlyx"
951 || name == "file" //FIXME: should be removed.
953 || name == "texinfo";
954 else if (name == "print")
955 enable = buf->isExportable("dvi")
956 && lyxrc.print_command != "none";
957 else if (name == "character") {
961 InsetCode ic = view()->cursor().inset().lyxCode();
962 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
965 else if (name == "latexlog")
966 enable = FileName(buf->logName()).isReadableFile();
967 else if (name == "spellchecker")
968 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
969 enable = !buf->isReadonly();
973 else if (name == "vclog")
974 enable = buf->lyxvc().inUse();
978 case LFUN_DIALOG_UPDATE: {
979 string const name = cmd.getArg(0);
981 enable = name == "prefs";
985 case LFUN_INSET_APPLY: {
990 string const name = cmd.getArg(0);
991 Inset * inset = getOpenInset(name);
993 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
995 if (!inset->getStatus(view()->cursor(), fr, fs)) {
996 // Every inset is supposed to handle this
1001 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1002 flag |= getStatus(fr);
1004 enable = flag.enabled();
1016 flag.enabled(false);
1022 void GuiView::insertLyXFile(docstring const & fname)
1024 BufferView * bv = view();
1029 FileName filename(to_utf8(fname));
1031 if (!filename.empty()) {
1032 bv->insertLyXFile(filename);
1036 // Launch a file browser
1038 string initpath = lyxrc.document_path;
1039 string const trypath = bv->buffer().filePath();
1040 // If directory is writeable, use this as default.
1041 if (FileName(trypath).isDirWritable())
1045 FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT);
1046 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
1047 dlg.setButton2(_("Examples|#E#e"),
1048 from_utf8(addPath(package().system_support().absFilename(),
1051 FileDialog::Result result =
1052 dlg.open(from_utf8(initpath),
1053 FileFilterList(_("LyX Documents (*.lyx)")),
1056 if (result.first == FileDialog::Later)
1060 filename.set(to_utf8(result.second));
1062 // check selected filename
1063 if (filename.empty()) {
1064 // emit message signal.
1065 message(_("Canceled."));
1069 bv->insertLyXFile(filename);
1073 bool GuiView::dispatch(FuncRequest const & cmd)
1075 BufferView * bv = view();
1076 // By default we won't need any update.
1078 bv->cursor().updateFlags(Update::None);
1080 switch(cmd.action) {
1081 case LFUN_BUFFER_SWITCH:
1082 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1085 case LFUN_BUFFER_NEXT:
1086 setBuffer(theBufferList().next(buffer()));
1089 case LFUN_BUFFER_PREVIOUS:
1090 setBuffer(theBufferList().previous(buffer()));
1093 case LFUN_COMMAND_EXECUTE: {
1094 bool const show_it = cmd.argument() != "off";
1095 d.toolbars_->showCommandBuffer(show_it);
1098 case LFUN_DROP_LAYOUTS_CHOICE:
1100 d.layout_->showPopup();
1103 case LFUN_MENU_OPEN:
1104 d.menubar_->openByName(toqstr(cmd.argument()));
1107 case LFUN_FILE_INSERT:
1108 insertLyXFile(cmd.argument());
1111 case LFUN_TOOLBAR_TOGGLE: {
1112 string const name = cmd.getArg(0);
1113 bool const allowauto = cmd.getArg(1) == "allowauto";
1114 // it is possible to get current toolbar status like this,...
1115 // but I decide to obey the order of ToolbarBackend::flags
1116 // and disregard real toolbar status.
1117 // toolbars_->saveToolbarInfo();
1119 // toggle state on/off/auto
1120 d.toolbars_->toggleToolbarState(name, allowauto);
1124 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1126 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1130 if (tbi->flags & ToolbarInfo::ON)
1132 else if (tbi->flags & ToolbarInfo::OFF)
1134 else if (tbi->flags & ToolbarInfo::AUTO)
1137 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1138 _(tbi->gui_name), state));
1142 case LFUN_DIALOG_UPDATE: {
1143 string const name = to_utf8(cmd.argument());
1144 // Can only update a dialog connected to an existing inset
1145 Inset * inset = getOpenInset(name);
1147 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1148 inset->dispatch(view()->cursor(), fr);
1149 } else if (name == "paragraph") {
1150 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1151 } else if (name == "prefs") {
1152 updateDialog(name, string());
1157 case LFUN_DIALOG_TOGGLE: {
1158 if (isDialogVisible(cmd.getArg(0)))
1159 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1161 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1165 case LFUN_DIALOG_DISCONNECT_INSET:
1166 disconnectDialog(to_utf8(cmd.argument()));
1169 case LFUN_DIALOG_HIDE: {
1172 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1176 case LFUN_DIALOG_SHOW: {
1177 string const name = cmd.getArg(0);
1178 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1180 if (name == "character") {
1181 data = freefont2string();
1183 showDialog("character", data);
1184 } else if (name == "latexlog") {
1185 Buffer::LogType type;
1186 string const logfile = buffer()->logName(&type);
1188 case Buffer::latexlog:
1191 case Buffer::buildlog:
1195 data += Lexer::quoteString(logfile);
1196 showDialog("log", data);
1197 } else if (name == "vclog") {
1198 string const data = "vc " +
1199 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1200 showDialog("log", data);
1202 showDialog(name, data);
1206 case LFUN_INSET_APPLY: {
1207 string const name = cmd.getArg(0);
1208 Inset * inset = getOpenInset(name);
1210 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1211 inset->dispatch(view()->cursor(), fr);
1213 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1227 Buffer const * GuiView::updateInset(Inset const * inset)
1229 if (!d.current_work_area_)
1233 d.current_work_area_->scheduleRedraw();
1235 return &d.current_work_area_->bufferView().buffer();
1239 void GuiView::restartCursor()
1241 /* When we move around, or type, it's nice to be able to see
1242 * the cursor immediately after the keypress.
1244 if (d.current_work_area_)
1245 d.current_work_area_->startBlinkingCursor();
1247 // Take this occasion to update the toobars and layout list.
1254 // This list should be kept in sync with the list of insets in
1255 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1256 // dialog should have the same name as the inset.
1258 char const * const dialognames[] = {
1259 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1260 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1261 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1262 "mathdelimiter", "mathmatrix", "note", "paragraph",
1263 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1265 #ifdef HAVE_LIBAIKSAURUS
1269 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1271 char const * const * const end_dialognames =
1272 dialognames + (sizeof(dialognames) / sizeof(char *));
1276 cmpCStr(char const * name) : name_(name) {}
1277 bool operator()(char const * other) {
1278 return strcmp(other, name_) == 0;
1285 bool isValidName(string const & name)
1287 return std::find_if(dialognames, end_dialognames,
1288 cmpCStr(name.c_str())) != end_dialognames;
1294 void GuiView::resetDialogs()
1296 // Make sure that no LFUN uses any LyXView.
1297 theLyXFunc().setLyXView(0);
1298 d.toolbars_->init();
1301 d.layout_->updateContents(true);
1302 // Now update controls with current buffer.
1303 theLyXFunc().setLyXView(this);
1308 Dialog * GuiView::find_or_build(string const & name)
1310 if (!isValidName(name))
1313 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1315 if (it != d.dialogs_.end())
1316 return it->second.get();
1318 d.dialogs_[name].reset(build(name));
1319 return d.dialogs_[name].get();
1323 void GuiView::showDialog(string const & name, string const & data,
1330 Dialog * dialog = find_or_build(name);
1332 dialog->showData(data);
1334 d.open_insets_[name] = inset;
1340 bool GuiView::isDialogVisible(string const & name) const
1342 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1343 if (it == d.dialogs_.end())
1345 return it->second.get()->isVisibleView();
1349 void GuiView::hideDialog(string const & name, Inset * inset)
1351 // Don't send the signal if we are quitting, because on MSVC it is
1352 // destructed before the cut stack in CutAndPaste.cpp, and this method
1353 // is called from some inset destructor if the cut stack is not empty
1358 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1359 if (it == d.dialogs_.end())
1362 if (inset && inset != getOpenInset(name))
1365 Dialog * const dialog = it->second.get();
1366 if (dialog->isVisibleView())
1368 d.open_insets_[name] = 0;
1372 void GuiView::disconnectDialog(string const & name)
1374 if (!isValidName(name))
1377 if (d.open_insets_.find(name) != d.open_insets_.end())
1378 d.open_insets_[name] = 0;
1382 Inset * GuiView::getOpenInset(string const & name) const
1384 if (!isValidName(name))
1387 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1388 return it == d.open_insets_.end() ? 0 : it->second;
1392 void GuiView::hideAll() const
1394 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1395 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1397 for(; it != end; ++it)
1402 void GuiView::hideBufferDependent() const
1404 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1405 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1407 for(; it != end; ++it) {
1408 Dialog * dialog = it->second.get();
1409 if (dialog->isBufferDependent())
1415 void GuiView::updateBufferDependent(bool switched) const
1417 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1418 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1420 for(; it != end; ++it) {
1421 Dialog * dialog = it->second.get();
1422 if (switched && dialog->isBufferDependent()) {
1423 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1424 dialog->updateView();
1428 // A bit clunky, but the dialog will request
1429 // that the kernel provides it with the necessary
1431 dialog->updateDialog();
1437 void GuiView::checkStatus()
1439 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1440 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1442 for(; it != end; ++it) {
1443 Dialog * const dialog = it->second.get();
1444 if (dialog && dialog->isVisibleView())
1445 dialog->checkStatus();
1451 // will be replaced by a proper factory...
1452 Dialog * createGuiAbout(GuiView & lv);
1453 Dialog * createGuiBibitem(GuiView & lv);
1454 Dialog * createGuiBibtex(GuiView & lv);
1455 Dialog * createGuiBox(GuiView & lv);
1456 Dialog * createGuiBranch(GuiView & lv);
1457 Dialog * createGuiChanges(GuiView & lv);
1458 Dialog * createGuiCharacter(GuiView & lv);
1459 Dialog * createGuiCitation(GuiView & lv);
1460 Dialog * createGuiDelimiter(GuiView & lv);
1461 Dialog * createGuiDocument(GuiView & lv);
1462 Dialog * createGuiErrorList(GuiView & lv);
1463 Dialog * createGuiERT(GuiView & lv);
1464 Dialog * createGuiExternal(GuiView & lv);
1465 Dialog * createGuiFloat(GuiView & lv);
1466 Dialog * createGuiGraphics(GuiView & lv);
1467 Dialog * createGuiInclude(GuiView & lv);
1468 Dialog * createGuiIndex(GuiView & lv);
1469 Dialog * createGuiLabel(GuiView & lv);
1470 Dialog * createGuiListings(GuiView & lv);
1471 Dialog * createGuiLog(GuiView & lv);
1472 Dialog * createGuiMathMatrix(GuiView & lv);
1473 Dialog * createGuiNomenclature(GuiView & lv);
1474 Dialog * createGuiNote(GuiView & lv);
1475 Dialog * createGuiParagraph(GuiView & lv);
1476 Dialog * createGuiPreferences(GuiView & lv);
1477 Dialog * createGuiPrint(GuiView & lv);
1478 Dialog * createGuiRef(GuiView & lv);
1479 Dialog * createGuiSearch(GuiView & lv);
1480 Dialog * createGuiSendTo(GuiView & lv);
1481 Dialog * createGuiShowFile(GuiView & lv);
1482 Dialog * createGuiSpellchecker(GuiView & lv);
1483 Dialog * createGuiTabularCreate(GuiView & lv);
1484 Dialog * createGuiTabular(GuiView & lv);
1485 Dialog * createGuiTexInfo(GuiView & lv);
1486 Dialog * createGuiToc(GuiView & lv);
1487 Dialog * createGuiThesaurus(GuiView & lv);
1488 Dialog * createGuiHyperlink(GuiView & lv);
1489 Dialog * createGuiVSpace(GuiView & lv);
1490 Dialog * createGuiViewSource(GuiView & lv);
1491 Dialog * createGuiWrap(GuiView & lv);
1494 Dialog * GuiView::build(string const & name)
1496 BOOST_ASSERT(isValidName(name));
1498 if (name == "aboutlyx")
1499 return createGuiAbout(*this);
1500 if (name == "bibitem")
1501 return createGuiBibitem(*this);
1502 if (name == "bibtex")
1503 return createGuiBibtex(*this);
1505 return createGuiBox(*this);
1506 if (name == "branch")
1507 return createGuiBranch(*this);
1508 if (name == "changes")
1509 return createGuiChanges(*this);
1510 if (name == "character")
1511 return createGuiCharacter(*this);
1512 if (name == "citation")
1513 return createGuiCitation(*this);
1514 if (name == "document")
1515 return createGuiDocument(*this);
1516 if (name == "errorlist")
1517 return createGuiErrorList(*this);
1519 return createGuiERT(*this);
1520 if (name == "external")
1521 return createGuiExternal(*this);
1523 return createGuiShowFile(*this);
1524 if (name == "findreplace")
1525 return createGuiSearch(*this);
1526 if (name == "float")
1527 return createGuiFloat(*this);
1528 if (name == "graphics")
1529 return createGuiGraphics(*this);
1530 if (name == "include")
1531 return createGuiInclude(*this);
1532 if (name == "index")
1533 return createGuiIndex(*this);
1534 if (name == "nomenclature")
1535 return createGuiNomenclature(*this);
1536 if (name == "label")
1537 return createGuiLabel(*this);
1539 return createGuiLog(*this);
1540 if (name == "view-source")
1541 return createGuiViewSource(*this);
1542 if (name == "mathdelimiter")
1543 return createGuiDelimiter(*this);
1544 if (name == "mathmatrix")
1545 return createGuiMathMatrix(*this);
1547 return createGuiNote(*this);
1548 if (name == "paragraph")
1549 return createGuiParagraph(*this);
1550 if (name == "prefs")
1551 return createGuiPreferences(*this);
1552 if (name == "print")
1553 return createGuiPrint(*this);
1555 return createGuiRef(*this);
1556 if (name == "sendto")
1557 return createGuiSendTo(*this);
1558 if (name == "spellchecker")
1559 return createGuiSpellchecker(*this);
1560 if (name == "tabular")
1561 return createGuiTabular(*this);
1562 if (name == "tabularcreate")
1563 return createGuiTabularCreate(*this);
1564 if (name == "texinfo")
1565 return createGuiTexInfo(*this);
1566 #ifdef HAVE_LIBAIKSAURUS
1567 if (name == "thesaurus")
1568 return createGuiThesaurus(*this);
1571 return createGuiToc(*this);
1573 return createGuiHyperlink(*this);
1574 if (name == "vspace")
1575 return createGuiVSpace(*this);
1577 return createGuiWrap(*this);
1578 if (name == "listings")
1579 return createGuiListings(*this);
1585 } // namespace frontend
1588 #include "GuiView_moc.cpp"