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 "GuiApplication.h"
20 #include "GuiWorkArea.h"
21 #include "GuiKeySymbol.h"
22 #include "GuiMenubar.h"
23 #include "GuiToolbar.h"
24 #include "GuiToolbars.h"
26 #include "qt_helpers.h"
28 #include "buffer_funcs.h"
30 #include "BufferList.h"
31 #include "BufferParams.h"
32 #include "BufferView.h"
35 #include "ErrorList.h"
36 #include "FuncRequest.h"
45 #include "MenuBackend.h"
46 #include "Paragraph.h"
47 #include "TextClass.h"
49 #include "ToolbarBackend.h"
52 #include "support/FileName.h"
53 #include "support/lstrings.h"
54 #include "support/os.h"
55 #include "support/Timeout.h"
58 #include <QApplication>
59 #include <QCloseEvent>
61 #include <QDesktopWidget>
62 #include <QDragEnterEvent>
69 #include <QPushButton>
73 #include <QStackedWidget>
79 #include <boost/assert.hpp>
80 #include <boost/bind.hpp>
82 #ifdef HAVE_SYS_TIME_H
83 # include <sys/time.h>
99 using support::bformat;
100 using support::FileName;
105 class BackgroundWidget : public QWidget
110 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
111 /// The text to be written on top of the pixmap
112 QString const text = lyx_version ? lyx_version : qt_("unknown version");
113 splash_ = QPixmap(":/images/banner.png");
115 QPainter pain(&splash_);
116 pain.setPen(QColor(255, 255, 0));
118 // The font used to display the version info
119 font.setStyleHint(QFont::SansSerif);
120 font.setWeight(QFont::Bold);
121 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
123 pain.drawText(260, 270, text);
126 void paintEvent(QPaintEvent *)
128 int x = (width() - splash_.width()) / 2;
129 int y = (height() - splash_.height()) / 2;
131 pain.drawPixmap(x, y, splash_);
141 typedef boost::shared_ptr<Dialog> DialogPtr;
143 struct GuiView::GuiViewPrivate
146 : current_work_area_(0), layout_(0),
147 quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false)
149 // hardcode here the platform specific icon size
150 smallIconSize = 14; // scaling problems
151 normalIconSize = 20; // ok, default
152 bigIconSize = 26; // better for some math icons
154 splitter_ = new QSplitter;
155 bg_widget_ = new BackgroundWidget;
156 stack_widget_ = new QStackedWidget;
157 stack_widget_->addWidget(bg_widget_);
158 stack_widget_->addWidget(splitter_);
166 delete stack_widget_;
171 QMenu * toolBarPopup(GuiView * parent)
173 // FIXME: translation
174 QMenu * menu = new QMenu(parent);
175 QActionGroup * iconSizeGroup = new QActionGroup(parent);
177 QAction * smallIcons = new QAction(iconSizeGroup);
178 smallIcons->setText(qt_("Small-sized icons"));
179 smallIcons->setCheckable(true);
180 QObject::connect(smallIcons, SIGNAL(triggered()),
181 parent, SLOT(smallSizedIcons()));
182 menu->addAction(smallIcons);
184 QAction * normalIcons = new QAction(iconSizeGroup);
185 normalIcons->setText(qt_("Normal-sized icons"));
186 normalIcons->setCheckable(true);
187 QObject::connect(normalIcons, SIGNAL(triggered()),
188 parent, SLOT(normalSizedIcons()));
189 menu->addAction(normalIcons);
191 QAction * bigIcons = new QAction(iconSizeGroup);
192 bigIcons->setText(qt_("Big-sized icons"));
193 bigIcons->setCheckable(true);
194 QObject::connect(bigIcons, SIGNAL(triggered()),
195 parent, SLOT(bigSizedIcons()));
196 menu->addAction(bigIcons);
198 unsigned int cur = parent->iconSize().width();
199 if ( cur == parent->d.smallIconSize)
200 smallIcons->setChecked(true);
201 else if (cur == parent->d.normalIconSize)
202 normalIcons->setChecked(true);
203 else if (cur == parent->d.bigIconSize)
204 bigIcons->setChecked(true);
211 stack_widget_->setCurrentWidget(bg_widget_);
212 bg_widget_->setUpdatesEnabled(true);
215 TabWorkArea * tabWorkArea(int i)
217 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
220 TabWorkArea * currentTabWorkArea()
222 if (splitter_->count() == 1)
223 // The first TabWorkArea is always the first one, if any.
224 return tabWorkArea(0);
226 TabWorkArea * tab_widget = 0;
227 for (int i = 0; i != splitter_->count(); ++i) {
228 QWidget * w = splitter_->widget(i);
231 tab_widget = dynamic_cast<TabWorkArea *>(w);
240 GuiWorkArea * current_work_area_;
241 QSplitter * splitter_;
242 QStackedWidget * stack_widget_;
243 BackgroundWidget * bg_widget_;
245 GuiMenubar * menubar_;
247 GuiToolbars * toolbars_;
248 /// The main layout box.
250 * \warning Don't Delete! The layout box is actually owned by
251 * whichever toolbar contains it. All the GuiView class needs is a
252 * means of accessing it.
254 * FIXME: replace that with a proper model so that we are not limited
255 * to only one dialog.
257 GuiLayoutBox * layout_;
260 std::map<std::string, Inset *> open_insets_;
263 std::map<std::string, DialogPtr> dialogs_;
265 unsigned int smallIconSize;
266 unsigned int normalIconSize;
267 unsigned int bigIconSize;
269 QTimer statusbar_timer_;
270 /// are we quitting by the menu?
271 bool quitting_by_menu_;
272 /// auto-saving of buffers
273 Timeout autosave_timeout_;
274 /// flag against a race condition due to multiclicks, see bug #1119
279 GuiView::GuiView(int id)
280 : d(*new GuiViewPrivate), id_(id)
282 // GuiToolbars *must* be initialised before GuiMenubar.
283 d.toolbars_ = new GuiToolbars(*this);
284 d.menubar_ = new GuiMenubar(this, menubackend);
286 setCentralWidget(d.stack_widget_);
288 // Start autosave timer
289 if (lyxrc.autosave) {
290 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
291 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
292 d.autosave_timeout_.start();
294 connect(&d.statusbar_timer_, SIGNAL(timeout()),
295 this, SLOT(clearMessage()));
297 // Qt bug? signal lastWindowClosed does not work
298 setAttribute(Qt::WA_QuitOnClose, false);
299 setAttribute(Qt::WA_DeleteOnClose, true);
301 // assign an icon to main form. We do not do it under Qt/Mac,
302 // since the icon is provided in the application bundle.
303 setWindowIcon(QPixmap(":/images/lyx.png"));
307 setAcceptDrops(true);
309 statusBar()->setSizeGripEnabled(true);
311 // Forbid too small unresizable window because it can happen
312 // with some window manager under X11.
313 setMinimumSize(300, 200);
315 if (!lyxrc.allow_geometry_session)
316 // No session handling, default to a sane size.
317 setGeometry(50, 50, 690, 510);
319 // Now take care of session management.
321 QString const key = "view-" + QString::number(id_);
323 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
324 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
328 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
329 setGeometry(50, 50, 690, 510);
331 setIconSize(settings.value(key + "/icon_size").toSize());
341 void GuiView::close()
343 d.quitting_by_menu_ = true;
344 d.current_work_area_ = 0;
345 for (int i = 0; i != d.splitter_->count(); ++i) {
346 TabWorkArea * twa = d.tabWorkArea(i);
350 QMainWindow::close();
351 d.quitting_by_menu_ = false;
355 void GuiView::setFocus()
357 if (d.current_work_area_)
358 d.current_work_area_->setFocus();
364 QMenu * GuiView::createPopupMenu()
366 return d.toolBarPopup(this);
370 void GuiView::showEvent(QShowEvent * e)
372 LYXERR(Debug::GUI, "Passed Geometry "
373 << size().height() << "x" << size().width()
374 << "+" << pos().x() << "+" << pos().y());
376 if (d.splitter_->count() == 0)
377 // No work area, switch to the background widget.
380 QMainWindow::showEvent(e);
384 void GuiView::closeEvent(QCloseEvent * close_event)
386 // we may have been called through the close window button
387 // which bypasses the LFUN machinery.
388 if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
389 if (!theBufferList().quitWriteAll()) {
390 close_event->ignore();
395 // Make sure that no LFUN use this close to be closed View.
396 theLyXFunc().setLyXView(0);
397 // Make sure the timer time out will not trigger a statusbar update.
398 d.statusbar_timer_.stop();
400 if (lyxrc.allow_geometry_session) {
402 QString const key = "view-" + QString::number(id_);
404 settings.setValue(key + "/pos", pos());
405 settings.setValue(key + "/size", size());
407 settings.setValue(key + "/geometry", saveGeometry());
409 settings.setValue(key + "/icon_size", iconSize());
410 d.toolbars_->saveToolbarInfo();
413 guiApp->unregisterView(id_);
414 if (guiApp->viewCount() > 0) {
415 // Just close the window and do nothing else if this is not the
417 close_event->accept();
423 // this is the place where we leave the frontend.
424 // it is the only point at which we start quitting.
425 close_event->accept();
426 // quit the event loop
431 void GuiView::dragEnterEvent(QDragEnterEvent * event)
433 if (event->mimeData()->hasUrls())
435 /// \todo Ask lyx-devel is this is enough:
436 /// if (event->mimeData()->hasFormat("text/plain"))
437 /// event->acceptProposedAction();
441 void GuiView::dropEvent(QDropEvent* event)
443 QList<QUrl> files = event->mimeData()->urls();
447 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
448 for (int i = 0; i != files.size(); ++i) {
449 string const file = support::os::internal_path(fromqstr(
450 files.at(i).toLocalFile()));
452 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
457 void GuiView::message(docstring const & str)
459 statusBar()->showMessage(toqstr(str));
460 d.statusbar_timer_.stop();
461 d.statusbar_timer_.start(3000);
465 void GuiView::smallSizedIcons()
467 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
471 void GuiView::normalSizedIcons()
473 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
477 void GuiView::bigSizedIcons()
479 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
483 void GuiView::clearMessage()
487 theLyXFunc().setLyXView(this);
488 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
489 d.statusbar_timer_.stop();
493 void GuiView::updateWindowTitle(GuiWorkArea * wa)
495 if (wa != d.current_work_area_)
497 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
498 setWindowIconText(wa->windowIconText());
502 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
505 disconnectBufferView();
506 connectBufferView(wa->bufferView());
507 connectBuffer(wa->bufferView().buffer());
508 d.current_work_area_ = wa;
509 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
510 this, SLOT(updateWindowTitle(GuiWorkArea *)));
511 updateWindowTitle(wa);
514 // Buffer-dependent dialogs should be updated or
515 // hidden. This should go here because some dialogs (eg ToC)
516 // require bv_->text.
517 updateBufferDependent(true);
524 void GuiView::updateStatusBar()
526 // let the user see the explicit message
527 if (d.statusbar_timer_.isActive())
530 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
534 bool GuiView::hasFocus() const
536 return qApp->activeWindow() == this;
540 bool GuiView::event(QEvent * e)
544 // Useful debug code:
545 //case QEvent::ActivationChange:
546 //case QEvent::WindowDeactivate:
547 //case QEvent::Paint:
548 //case QEvent::Enter:
549 //case QEvent::Leave:
550 //case QEvent::HoverEnter:
551 //case QEvent::HoverLeave:
552 //case QEvent::HoverMove:
553 //case QEvent::StatusTip:
554 //case QEvent::DragEnter:
555 //case QEvent::DragLeave:
559 case QEvent::WindowActivate: {
560 guiApp->setCurrentView(*this);
561 if (d.current_work_area_) {
562 BufferView & bv = d.current_work_area_->bufferView();
563 connectBufferView(bv);
564 connectBuffer(bv.buffer());
565 // The document structure, name and dialogs might have
566 // changed in another view.
567 updateBufferDependent(true);
569 setWindowTitle(qt_("LyX"));
570 setWindowIconText(qt_("LyX"));
572 return QMainWindow::event(e);
574 case QEvent::ShortcutOverride: {
575 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
576 if (!d.current_work_area_) {
577 theLyXFunc().setLyXView(this);
579 setKeySymbol(&sym, ke);
580 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
584 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
586 setKeySymbol(&sym, ke);
587 d.current_work_area_->processKeySym(sym, NoModifier);
593 return QMainWindow::event(e);
598 bool GuiView::focusNextPrevChild(bool /*next*/)
605 void GuiView::setBusy(bool yes)
607 if (d.current_work_area_) {
608 d.current_work_area_->setUpdatesEnabled(!yes);
610 d.current_work_area_->stopBlinkingCursor();
612 d.current_work_area_->startBlinkingCursor();
616 QApplication::setOverrideCursor(Qt::WaitCursor);
618 QApplication::restoreOverrideCursor();
622 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
624 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
626 if (tbinfo.flags & ToolbarInfo::TOP) {
628 addToolBarBreak(Qt::TopToolBarArea);
629 addToolBar(Qt::TopToolBarArea, toolBar);
632 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
633 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
634 #if (QT_VERSION >= 0x040202)
636 addToolBarBreak(Qt::BottomToolBarArea);
638 addToolBar(Qt::BottomToolBarArea, toolBar);
641 if (tbinfo.flags & ToolbarInfo::LEFT) {
642 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
643 #if (QT_VERSION >= 0x040202)
645 addToolBarBreak(Qt::LeftToolBarArea);
647 addToolBar(Qt::LeftToolBarArea, toolBar);
650 if (tbinfo.flags & ToolbarInfo::RIGHT) {
651 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
652 #if (QT_VERSION >= 0x040202)
654 addToolBarBreak(Qt::RightToolBarArea);
656 addToolBar(Qt::RightToolBarArea, toolBar);
659 // The following does not work so I cannot restore to exact toolbar location
661 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
662 toolBar->move(tbinfo.posx, tbinfo.posy);
669 GuiWorkArea * GuiView::workArea(Buffer & buffer)
671 for (int i = 0; i != d.splitter_->count(); ++i) {
672 GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
680 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
683 // Automatically create a TabWorkArea if there are none yet.
684 if (!d.splitter_->count())
687 TabWorkArea * tab_widget = d.currentTabWorkArea();
688 return tab_widget->addWorkArea(buffer, *this);
692 void GuiView::addTabWorkArea()
694 TabWorkArea * twa = new TabWorkArea;
695 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
696 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
697 d.splitter_->addWidget(twa);
698 d.stack_widget_->setCurrentWidget(d.splitter_);
702 GuiWorkArea const * GuiView::currentWorkArea() const
704 return d.current_work_area_;
708 void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
710 BOOST_ASSERT(work_area);
712 // Changing work area can result from opening a file so
713 // update the toc in any case.
716 GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
717 d.current_work_area_ = wa;
718 for (int i = 0; i != d.splitter_->count(); ++i) {
719 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
725 void GuiView::removeWorkArea(GuiWorkArea * work_area)
727 BOOST_ASSERT(work_area);
728 GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
729 if (gwa == d.current_work_area_) {
731 disconnectBufferView();
732 hideBufferDependent();
733 d.current_work_area_ = 0;
736 // removing a work area often results from closing a file so
737 // update the toc in any case.
740 for (int i = 0; i != d.splitter_->count(); ++i) {
741 TabWorkArea * twa = d.tabWorkArea(i);
742 if (!twa->removeWorkArea(gwa))
743 // Not found in this tab group.
746 // We found and removed the GuiWorkArea.
748 // No more WorkAreas in this tab group, so delete it.
753 if (d.current_work_area_)
754 // This means that we are not closing the current GuiWorkArea;
757 // Switch to the next GuiWorkArea in the found TabWorkArea.
758 d.current_work_area_ = twa->currentWorkArea();
762 if (d.splitter_->count() == 0)
763 // No more work area, switch to the background widget.
768 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
774 void GuiView::updateLayoutList()
777 d.layout_->updateContents(false);
781 void GuiView::updateToolbars()
783 if (d.current_work_area_) {
785 d.current_work_area_->bufferView().cursor().inMathed();
787 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
789 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
790 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
792 d.toolbars_->update(math, table, review);
794 d.toolbars_->update(false, false, false);
796 // update read-only status of open dialogs.
801 Buffer * GuiView::buffer()
803 if (d.current_work_area_)
804 return &d.current_work_area_->bufferView().buffer();
809 Buffer const * GuiView::buffer() const
811 if (d.current_work_area_)
812 return &d.current_work_area_->bufferView().buffer();
817 void GuiView::setBuffer(Buffer * newBuffer)
819 BOOST_ASSERT(newBuffer);
822 GuiWorkArea * wa = workArea(*newBuffer);
824 updateLabels(*newBuffer->masterBuffer());
825 wa = addWorkArea(*newBuffer);
827 //Disconnect the old buffer...there's no new one.
830 connectBuffer(*newBuffer);
831 connectBufferView(wa->bufferView());
832 setCurrentWorkArea(wa);
838 void GuiView::connectBuffer(Buffer & buf)
840 buf.setGuiDelegate(this);
844 void GuiView::disconnectBuffer()
846 if (d.current_work_area_)
847 d.current_work_area_->bufferView().setGuiDelegate(0);
851 void GuiView::connectBufferView(BufferView & bv)
853 bv.setGuiDelegate(this);
857 void GuiView::disconnectBufferView()
859 if (d.current_work_area_)
860 d.current_work_area_->bufferView().setGuiDelegate(0);
864 void GuiView::errors(string const & error_type)
866 ErrorList & el = buffer()->errorList(error_type);
868 showDialog("errorlist", error_type);
872 void GuiView::updateDialog(string const & name, string const & data)
874 if (!isDialogVisible(name))
877 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
878 if (it == d.dialogs_.end())
881 Dialog * const dialog = it->second.get();
882 if (dialog->isVisibleView())
883 dialog->updateData(data);
887 BufferView * GuiView::view()
889 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
893 void GuiView::updateToc()
895 updateDialog("toc", "");
899 void GuiView::updateEmbeddedFiles()
901 updateDialog("embedding", "");
905 void GuiView::autoSave()
907 LYXERR(Debug::INFO, "Running autoSave()");
910 view()->buffer().autoSave();
914 void GuiView::resetAutosaveTimers()
917 d.autosave_timeout_.restart();
921 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
925 Buffer * buf = buffer();
927 /* In LyX/Mac, when a dialog is open, the menus of the
928 application can still be accessed without giving focus to
929 the main window. In this case, we want to disable the menu
930 entries that are buffer-related.
932 Note that this code is not perfect, as bug 1941 attests:
933 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
935 if (cmd.origin == FuncRequest::MENU && !hasFocus())
939 case LFUN_TOOLBAR_TOGGLE:
940 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
943 case LFUN_DIALOG_TOGGLE:
944 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
945 // fall through to set "enable"
946 case LFUN_DIALOG_SHOW: {
947 string const name = cmd.getArg(0);
949 enable = name == "aboutlyx"
950 || name == "file" //FIXME: should be removed.
952 || name == "texinfo";
953 else if (name == "print")
954 enable = buf->isExportable("dvi")
955 && lyxrc.print_command != "none";
956 else if (name == "character") {
960 InsetCode ic = view()->cursor().inset().lyxCode();
961 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
964 else if (name == "latexlog")
965 enable = FileName(buf->logName()).isFileReadable();
966 else if (name == "spellchecker")
967 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
968 enable = !buf->isReadonly();
972 else if (name == "vclog")
973 enable = buf->lyxvc().inUse();
977 case LFUN_DIALOG_UPDATE: {
978 string const name = cmd.getArg(0);
980 enable = name == "prefs";
984 case LFUN_INSET_APPLY: {
989 string const name = cmd.getArg(0);
990 Inset * inset = getOpenInset(name);
992 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
994 if (!inset->getStatus(view()->cursor(), fr, fs)) {
995 // Every inset is supposed to handle this
1000 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1001 flag |= getStatus(fr);
1003 enable = flag.enabled();
1015 flag.enabled(false);
1021 void GuiView::dispatch(FuncRequest const & cmd)
1023 BufferView * bv = view();
1024 // By default we won't need any update.
1026 bv->cursor().updateFlags(Update::None);
1028 switch(cmd.action) {
1029 case LFUN_BUFFER_SWITCH:
1030 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1033 case LFUN_BUFFER_NEXT:
1034 setBuffer(theBufferList().next(buffer()));
1037 case LFUN_BUFFER_PREVIOUS:
1038 setBuffer(theBufferList().previous(buffer()));
1041 case LFUN_COMMAND_EXECUTE: {
1042 bool const show_it = cmd.argument() != "off";
1043 d.toolbars_->showCommandBuffer(show_it);
1046 case LFUN_DROP_LAYOUTS_CHOICE:
1048 d.layout_->showPopup();
1051 case LFUN_MENU_OPEN:
1052 d.menubar_->openByName(toqstr(cmd.argument()));
1055 case LFUN_TOOLBAR_TOGGLE: {
1056 string const name = cmd.getArg(0);
1057 bool const allowauto = cmd.getArg(1) == "allowauto";
1058 // it is possible to get current toolbar status like this,...
1059 // but I decide to obey the order of ToolbarBackend::flags
1060 // and disregard real toolbar status.
1061 // toolbars_->saveToolbarInfo();
1063 // toggle state on/off/auto
1064 d.toolbars_->toggleToolbarState(name, allowauto);
1068 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1070 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1074 if (tbi->flags & ToolbarInfo::ON)
1076 else if (tbi->flags & ToolbarInfo::OFF)
1078 else if (tbi->flags & ToolbarInfo::AUTO)
1081 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1082 _(tbi->gui_name), state));
1086 case LFUN_DIALOG_UPDATE: {
1087 string const name = to_utf8(cmd.argument());
1088 // Can only update a dialog connected to an existing inset
1089 Inset * inset = getOpenInset(name);
1091 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1092 inset->dispatch(view()->cursor(), fr);
1093 } else if (name == "paragraph") {
1094 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1095 } else if (name == "prefs") {
1096 updateDialog(name, string());
1101 case LFUN_DIALOG_TOGGLE: {
1102 if (isDialogVisible(cmd.getArg(0)))
1103 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1105 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1109 case LFUN_DIALOG_DISCONNECT_INSET:
1110 disconnectDialog(to_utf8(cmd.argument()));
1113 case LFUN_DIALOG_HIDE: {
1116 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1120 case LFUN_DIALOG_SHOW: {
1121 string const name = cmd.getArg(0);
1122 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1124 if (name == "character") {
1125 data = freefont2string();
1127 showDialog("character", data);
1128 } else if (name == "latexlog") {
1129 Buffer::LogType type;
1130 string const logfile = buffer()->logName(&type);
1132 case Buffer::latexlog:
1135 case Buffer::buildlog:
1139 data += Lexer::quoteString(logfile);
1140 showDialog("log", data);
1141 } else if (name == "vclog") {
1142 string const data = "vc " +
1143 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1144 showDialog("log", data);
1146 showDialog(name, data);
1150 case LFUN_INSET_APPLY: {
1151 string const name = cmd.getArg(0);
1152 Inset * inset = getOpenInset(name);
1154 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1155 inset->dispatch(view()->cursor(), fr);
1157 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1164 theLyXFunc().setLyXView(this);
1171 bv->processUpdateFlags(bv->cursor().result().update());
1172 // We won't need any new update.
1173 bv->cursor().updateFlags(Update::None);
1177 Buffer const * GuiView::updateInset(Inset const * inset)
1179 if (!d.current_work_area_)
1183 d.current_work_area_->scheduleRedraw();
1185 return &d.current_work_area_->bufferView().buffer();
1189 void GuiView::restartCursor()
1191 /* When we move around, or type, it's nice to be able to see
1192 * the cursor immediately after the keypress.
1194 if (d.current_work_area_)
1195 d.current_work_area_->startBlinkingCursor();
1197 // Take this occasion to update the toobars and layout list.
1204 // This list should be kept in sync with the list of insets in
1205 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1206 // dialog should have the same name as the inset.
1208 char const * const dialognames[] = {
1209 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1210 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1211 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1212 "mathdelimiter", "mathmatrix", "note", "paragraph",
1213 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1215 #ifdef HAVE_LIBAIKSAURUS
1219 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1221 char const * const * const end_dialognames =
1222 dialognames + (sizeof(dialognames) / sizeof(char *));
1226 cmpCStr(char const * name) : name_(name) {}
1227 bool operator()(char const * other) {
1228 return strcmp(other, name_) == 0;
1235 bool isValidName(string const & name)
1237 return std::find_if(dialognames, end_dialognames,
1238 cmpCStr(name.c_str())) != end_dialognames;
1244 void GuiView::resetDialogs()
1246 // Make sure that no LFUN uses any LyXView.
1247 theLyXFunc().setLyXView(0);
1248 d.toolbars_->init();
1251 d.layout_->updateContents(true);
1252 // Now update controls with current buffer.
1253 theLyXFunc().setLyXView(this);
1258 Dialog * GuiView::find_or_build(string const & name)
1260 if (!isValidName(name))
1263 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1265 if (it != d.dialogs_.end())
1266 return it->second.get();
1268 d.dialogs_[name].reset(build(name));
1269 return d.dialogs_[name].get();
1273 void GuiView::showDialog(string const & name, string const & data,
1280 Dialog * dialog = find_or_build(name);
1282 dialog->showData(data);
1284 d.open_insets_[name] = inset;
1290 bool GuiView::isDialogVisible(string const & name) const
1292 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1293 if (it == d.dialogs_.end())
1295 return it->second.get()->isVisibleView();
1299 void GuiView::hideDialog(string const & name, Inset * inset)
1301 // Don't send the signal if we are quitting, because on MSVC it is
1302 // destructed before the cut stack in CutAndPaste.cpp, and this method
1303 // is called from some inset destructor if the cut stack is not empty
1308 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1309 if (it == d.dialogs_.end())
1312 if (inset && inset != getOpenInset(name))
1315 Dialog * const dialog = it->second.get();
1316 if (dialog->isVisibleView())
1318 d.open_insets_[name] = 0;
1322 void GuiView::disconnectDialog(string const & name)
1324 if (!isValidName(name))
1327 if (d.open_insets_.find(name) != d.open_insets_.end())
1328 d.open_insets_[name] = 0;
1332 Inset * GuiView::getOpenInset(string const & name) const
1334 if (!isValidName(name))
1337 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1338 return it == d.open_insets_.end() ? 0 : it->second;
1342 void GuiView::hideAll() const
1344 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1345 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1347 for(; it != end; ++it)
1352 void GuiView::hideBufferDependent() const
1354 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1355 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1357 for(; it != end; ++it) {
1358 Dialog * dialog = it->second.get();
1359 if (dialog->isBufferDependent())
1365 void GuiView::updateBufferDependent(bool switched) const
1367 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1368 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1370 for(; it != end; ++it) {
1371 Dialog * dialog = it->second.get();
1372 if (switched && dialog->isBufferDependent()) {
1373 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1374 dialog->updateView();
1378 // A bit clunky, but the dialog will request
1379 // that the kernel provides it with the necessary
1381 dialog->updateDialog();
1387 void GuiView::checkStatus()
1389 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1390 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1392 for(; it != end; ++it) {
1393 Dialog * const dialog = it->second.get();
1394 if (dialog && dialog->isVisibleView())
1395 dialog->checkStatus();
1401 // will be replaced by a proper factory...
1402 Dialog * createGuiAbout(GuiView & lv);
1403 Dialog * createGuiBibitem(GuiView & lv);
1404 Dialog * createGuiBibtex(GuiView & lv);
1405 Dialog * createGuiBox(GuiView & lv);
1406 Dialog * createGuiBranch(GuiView & lv);
1407 Dialog * createGuiChanges(GuiView & lv);
1408 Dialog * createGuiCharacter(GuiView & lv);
1409 Dialog * createGuiCitation(GuiView & lv);
1410 Dialog * createGuiDelimiter(GuiView & lv);
1411 Dialog * createGuiDocument(GuiView & lv);
1412 Dialog * createGuiErrorList(GuiView & lv);
1413 Dialog * createGuiERT(GuiView & lv);
1414 Dialog * createGuiExternal(GuiView & lv);
1415 Dialog * createGuiFloat(GuiView & lv);
1416 Dialog * createGuiGraphics(GuiView & lv);
1417 Dialog * createGuiInclude(GuiView & lv);
1418 Dialog * createGuiIndex(GuiView & lv);
1419 Dialog * createGuiLabel(GuiView & lv);
1420 Dialog * createGuiListings(GuiView & lv);
1421 Dialog * createGuiLog(GuiView & lv);
1422 Dialog * createGuiMathMatrix(GuiView & lv);
1423 Dialog * createGuiNomenclature(GuiView & lv);
1424 Dialog * createGuiNote(GuiView & lv);
1425 Dialog * createGuiParagraph(GuiView & lv);
1426 Dialog * createGuiPreferences(GuiView & lv);
1427 Dialog * createGuiPrint(GuiView & lv);
1428 Dialog * createGuiRef(GuiView & lv);
1429 Dialog * createGuiSearch(GuiView & lv);
1430 Dialog * createGuiSendTo(GuiView & lv);
1431 Dialog * createGuiShowFile(GuiView & lv);
1432 Dialog * createGuiSpellchecker(GuiView & lv);
1433 Dialog * createGuiTabularCreate(GuiView & lv);
1434 Dialog * createGuiTabular(GuiView & lv);
1435 Dialog * createGuiTexInfo(GuiView & lv);
1436 Dialog * createGuiToc(GuiView & lv);
1437 Dialog * createGuiThesaurus(GuiView & lv);
1438 Dialog * createGuiHyperlink(GuiView & lv);
1439 Dialog * createGuiVSpace(GuiView & lv);
1440 Dialog * createGuiViewSource(GuiView & lv);
1441 Dialog * createGuiWrap(GuiView & lv);
1444 Dialog * GuiView::build(string const & name)
1446 BOOST_ASSERT(isValidName(name));
1448 if (name == "aboutlyx")
1449 return createGuiAbout(*this);
1450 if (name == "bibitem")
1451 return createGuiBibitem(*this);
1452 if (name == "bibtex")
1453 return createGuiBibtex(*this);
1455 return createGuiBox(*this);
1456 if (name == "branch")
1457 return createGuiBranch(*this);
1458 if (name == "changes")
1459 return createGuiChanges(*this);
1460 if (name == "character")
1461 return createGuiCharacter(*this);
1462 if (name == "citation")
1463 return createGuiCitation(*this);
1464 if (name == "document")
1465 return createGuiDocument(*this);
1466 if (name == "errorlist")
1467 return createGuiErrorList(*this);
1469 return createGuiERT(*this);
1470 if (name == "external")
1471 return createGuiExternal(*this);
1473 return createGuiShowFile(*this);
1474 if (name == "findreplace")
1475 return createGuiSearch(*this);
1476 if (name == "float")
1477 return createGuiFloat(*this);
1478 if (name == "graphics")
1479 return createGuiGraphics(*this);
1480 if (name == "include")
1481 return createGuiInclude(*this);
1482 if (name == "index")
1483 return createGuiIndex(*this);
1484 if (name == "nomenclature")
1485 return createGuiNomenclature(*this);
1486 if (name == "label")
1487 return createGuiLabel(*this);
1489 return createGuiLog(*this);
1490 if (name == "view-source")
1491 return createGuiViewSource(*this);
1492 if (name == "mathdelimiter")
1493 return createGuiDelimiter(*this);
1494 if (name == "mathmatrix")
1495 return createGuiMathMatrix(*this);
1497 return createGuiNote(*this);
1498 if (name == "paragraph")
1499 return createGuiParagraph(*this);
1500 if (name == "prefs")
1501 return createGuiPreferences(*this);
1502 if (name == "print")
1503 return createGuiPrint(*this);
1505 return createGuiRef(*this);
1506 if (name == "sendto")
1507 return createGuiSendTo(*this);
1508 if (name == "spellchecker")
1509 return createGuiSpellchecker(*this);
1510 if (name == "tabular")
1511 return createGuiTabular(*this);
1512 if (name == "tabularcreate")
1513 return createGuiTabularCreate(*this);
1514 if (name == "texinfo")
1515 return createGuiTexInfo(*this);
1516 #ifdef HAVE_LIBAIKSAURUS
1517 if (name == "thesaurus")
1518 return createGuiThesaurus(*this);
1521 return createGuiToc(*this);
1523 return createGuiHyperlink(*this);
1524 if (name == "vspace")
1525 return createGuiVSpace(*this);
1527 return createGuiWrap(*this);
1528 if (name == "listings")
1529 return createGuiListings(*this);
1535 } // namespace frontend
1538 #include "GuiView_moc.cpp"