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"
34 #include "support/debug.h"
35 #include "ErrorList.h"
36 #include "FuncRequest.h"
37 #include "support/gettext.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 * wa)
712 // Changing work area can result from opening a file so
713 // update the toc in any case.
716 d.current_work_area_ = wa;
717 for (int i = 0; i != d.splitter_->count(); ++i) {
718 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
724 void GuiView::removeWorkArea(GuiWorkArea * wa)
727 if (wa == d.current_work_area_) {
729 disconnectBufferView();
730 hideBufferDependent();
731 d.current_work_area_ = 0;
734 for (int i = 0; i != d.splitter_->count(); ++i) {
735 TabWorkArea * twa = d.tabWorkArea(i);
736 if (!twa->removeWorkArea(wa))
737 // Not found in this tab group.
740 // We found and removed the GuiWorkArea.
742 // No more WorkAreas in this tab group, so delete it.
747 if (d.current_work_area_)
748 // This means that we are not closing the current GuiWorkArea;
751 // Switch to the next GuiWorkArea in the found TabWorkArea.
752 d.current_work_area_ = twa->currentWorkArea();
756 if (d.splitter_->count() == 0)
757 // No more work area, switch to the background widget.
762 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
768 void GuiView::updateLayoutList()
771 d.layout_->updateContents(false);
775 void GuiView::updateToolbars()
777 if (d.current_work_area_) {
779 d.current_work_area_->bufferView().cursor().inMathed();
781 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
783 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
784 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
786 d.toolbars_->update(math, table, review);
788 d.toolbars_->update(false, false, false);
790 // update read-only status of open dialogs.
795 Buffer * GuiView::buffer()
797 if (d.current_work_area_)
798 return &d.current_work_area_->bufferView().buffer();
803 Buffer const * GuiView::buffer() const
805 if (d.current_work_area_)
806 return &d.current_work_area_->bufferView().buffer();
811 void GuiView::setBuffer(Buffer * newBuffer)
813 BOOST_ASSERT(newBuffer);
816 GuiWorkArea * wa = workArea(*newBuffer);
818 updateLabels(*newBuffer->masterBuffer());
819 wa = addWorkArea(*newBuffer);
821 //Disconnect the old buffer...there's no new one.
824 connectBuffer(*newBuffer);
825 connectBufferView(wa->bufferView());
826 setCurrentWorkArea(wa);
832 void GuiView::connectBuffer(Buffer & buf)
834 buf.setGuiDelegate(this);
838 void GuiView::disconnectBuffer()
840 if (d.current_work_area_)
841 d.current_work_area_->bufferView().setGuiDelegate(0);
845 void GuiView::connectBufferView(BufferView & bv)
847 bv.setGuiDelegate(this);
851 void GuiView::disconnectBufferView()
853 if (d.current_work_area_)
854 d.current_work_area_->bufferView().setGuiDelegate(0);
858 void GuiView::errors(string const & error_type)
860 ErrorList & el = buffer()->errorList(error_type);
862 showDialog("errorlist", error_type);
866 void GuiView::updateDialog(string const & name, string const & data)
868 if (!isDialogVisible(name))
871 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
872 if (it == d.dialogs_.end())
875 Dialog * const dialog = it->second.get();
876 if (dialog->isVisibleView())
877 dialog->updateData(data);
881 BufferView * GuiView::view()
883 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
887 void GuiView::updateToc()
889 updateDialog("toc", "");
893 void GuiView::updateEmbeddedFiles()
895 updateDialog("embedding", "");
899 void GuiView::autoSave()
901 LYXERR(Debug::INFO, "Running autoSave()");
904 view()->buffer().autoSave();
908 void GuiView::resetAutosaveTimers()
911 d.autosave_timeout_.restart();
915 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
919 Buffer * buf = buffer();
921 /* In LyX/Mac, when a dialog is open, the menus of the
922 application can still be accessed without giving focus to
923 the main window. In this case, we want to disable the menu
924 entries that are buffer-related.
926 Note that this code is not perfect, as bug 1941 attests:
927 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
929 if (cmd.origin == FuncRequest::MENU && !hasFocus())
933 case LFUN_TOOLBAR_TOGGLE:
934 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
937 case LFUN_DIALOG_TOGGLE:
938 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
939 // fall through to set "enable"
940 case LFUN_DIALOG_SHOW: {
941 string const name = cmd.getArg(0);
943 enable = name == "aboutlyx"
944 || name == "file" //FIXME: should be removed.
946 || name == "texinfo";
947 else if (name == "print")
948 enable = buf->isExportable("dvi")
949 && lyxrc.print_command != "none";
950 else if (name == "character") {
954 InsetCode ic = view()->cursor().inset().lyxCode();
955 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
958 else if (name == "latexlog")
959 enable = FileName(buf->logName()).isReadableFile();
960 else if (name == "spellchecker")
961 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
962 enable = !buf->isReadonly();
966 else if (name == "vclog")
967 enable = buf->lyxvc().inUse();
971 case LFUN_DIALOG_UPDATE: {
972 string const name = cmd.getArg(0);
974 enable = name == "prefs";
978 case LFUN_INSET_APPLY: {
983 string const name = cmd.getArg(0);
984 Inset * inset = getOpenInset(name);
986 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
988 if (!inset->getStatus(view()->cursor(), fr, fs)) {
989 // Every inset is supposed to handle this
994 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
995 flag |= getStatus(fr);
997 enable = flag.enabled();
1009 flag.enabled(false);
1015 bool GuiView::dispatch(FuncRequest const & cmd)
1017 BufferView * bv = view();
1018 // By default we won't need any update.
1020 bv->cursor().updateFlags(Update::None);
1022 switch(cmd.action) {
1023 case LFUN_BUFFER_SWITCH:
1024 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1027 case LFUN_BUFFER_NEXT:
1028 setBuffer(theBufferList().next(buffer()));
1031 case LFUN_BUFFER_PREVIOUS:
1032 setBuffer(theBufferList().previous(buffer()));
1035 case LFUN_COMMAND_EXECUTE: {
1036 bool const show_it = cmd.argument() != "off";
1037 d.toolbars_->showCommandBuffer(show_it);
1040 case LFUN_DROP_LAYOUTS_CHOICE:
1042 d.layout_->showPopup();
1045 case LFUN_MENU_OPEN:
1046 d.menubar_->openByName(toqstr(cmd.argument()));
1049 case LFUN_TOOLBAR_TOGGLE: {
1050 string const name = cmd.getArg(0);
1051 bool const allowauto = cmd.getArg(1) == "allowauto";
1052 // it is possible to get current toolbar status like this,...
1053 // but I decide to obey the order of ToolbarBackend::flags
1054 // and disregard real toolbar status.
1055 // toolbars_->saveToolbarInfo();
1057 // toggle state on/off/auto
1058 d.toolbars_->toggleToolbarState(name, allowauto);
1062 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1064 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1068 if (tbi->flags & ToolbarInfo::ON)
1070 else if (tbi->flags & ToolbarInfo::OFF)
1072 else if (tbi->flags & ToolbarInfo::AUTO)
1075 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1076 _(tbi->gui_name), state));
1080 case LFUN_DIALOG_UPDATE: {
1081 string const name = to_utf8(cmd.argument());
1082 // Can only update a dialog connected to an existing inset
1083 Inset * inset = getOpenInset(name);
1085 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1086 inset->dispatch(view()->cursor(), fr);
1087 } else if (name == "paragraph") {
1088 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1089 } else if (name == "prefs") {
1090 updateDialog(name, string());
1095 case LFUN_DIALOG_TOGGLE: {
1096 if (isDialogVisible(cmd.getArg(0)))
1097 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1099 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1103 case LFUN_DIALOG_DISCONNECT_INSET:
1104 disconnectDialog(to_utf8(cmd.argument()));
1107 case LFUN_DIALOG_HIDE: {
1110 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1114 case LFUN_DIALOG_SHOW: {
1115 string const name = cmd.getArg(0);
1116 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1118 if (name == "character") {
1119 data = freefont2string();
1121 showDialog("character", data);
1122 } else if (name == "latexlog") {
1123 Buffer::LogType type;
1124 string const logfile = buffer()->logName(&type);
1126 case Buffer::latexlog:
1129 case Buffer::buildlog:
1133 data += Lexer::quoteString(logfile);
1134 showDialog("log", data);
1135 } else if (name == "vclog") {
1136 string const data = "vc " +
1137 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1138 showDialog("log", data);
1140 showDialog(name, data);
1144 case LFUN_INSET_APPLY: {
1145 string const name = cmd.getArg(0);
1146 Inset * inset = getOpenInset(name);
1148 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1149 inset->dispatch(view()->cursor(), fr);
1151 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1165 Buffer const * GuiView::updateInset(Inset const * inset)
1167 if (!d.current_work_area_)
1171 d.current_work_area_->scheduleRedraw();
1173 return &d.current_work_area_->bufferView().buffer();
1177 void GuiView::restartCursor()
1179 /* When we move around, or type, it's nice to be able to see
1180 * the cursor immediately after the keypress.
1182 if (d.current_work_area_)
1183 d.current_work_area_->startBlinkingCursor();
1185 // Take this occasion to update the toobars and layout list.
1192 // This list should be kept in sync with the list of insets in
1193 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1194 // dialog should have the same name as the inset.
1196 char const * const dialognames[] = {
1197 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1198 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1199 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1200 "mathdelimiter", "mathmatrix", "note", "paragraph",
1201 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1203 #ifdef HAVE_LIBAIKSAURUS
1207 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1209 char const * const * const end_dialognames =
1210 dialognames + (sizeof(dialognames) / sizeof(char *));
1214 cmpCStr(char const * name) : name_(name) {}
1215 bool operator()(char const * other) {
1216 return strcmp(other, name_) == 0;
1223 bool isValidName(string const & name)
1225 return std::find_if(dialognames, end_dialognames,
1226 cmpCStr(name.c_str())) != end_dialognames;
1232 void GuiView::resetDialogs()
1234 // Make sure that no LFUN uses any LyXView.
1235 theLyXFunc().setLyXView(0);
1236 d.toolbars_->init();
1239 d.layout_->updateContents(true);
1240 // Now update controls with current buffer.
1241 theLyXFunc().setLyXView(this);
1246 Dialog * GuiView::find_or_build(string const & name)
1248 if (!isValidName(name))
1251 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1253 if (it != d.dialogs_.end())
1254 return it->second.get();
1256 d.dialogs_[name].reset(build(name));
1257 return d.dialogs_[name].get();
1261 void GuiView::showDialog(string const & name, string const & data,
1268 Dialog * dialog = find_or_build(name);
1270 dialog->showData(data);
1272 d.open_insets_[name] = inset;
1278 bool GuiView::isDialogVisible(string const & name) const
1280 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1281 if (it == d.dialogs_.end())
1283 return it->second.get()->isVisibleView();
1287 void GuiView::hideDialog(string const & name, Inset * inset)
1289 // Don't send the signal if we are quitting, because on MSVC it is
1290 // destructed before the cut stack in CutAndPaste.cpp, and this method
1291 // is called from some inset destructor if the cut stack is not empty
1296 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1297 if (it == d.dialogs_.end())
1300 if (inset && inset != getOpenInset(name))
1303 Dialog * const dialog = it->second.get();
1304 if (dialog->isVisibleView())
1306 d.open_insets_[name] = 0;
1310 void GuiView::disconnectDialog(string const & name)
1312 if (!isValidName(name))
1315 if (d.open_insets_.find(name) != d.open_insets_.end())
1316 d.open_insets_[name] = 0;
1320 Inset * GuiView::getOpenInset(string const & name) const
1322 if (!isValidName(name))
1325 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1326 return it == d.open_insets_.end() ? 0 : it->second;
1330 void GuiView::hideAll() const
1332 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1333 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1335 for(; it != end; ++it)
1340 void GuiView::hideBufferDependent() const
1342 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1343 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1345 for(; it != end; ++it) {
1346 Dialog * dialog = it->second.get();
1347 if (dialog->isBufferDependent())
1353 void GuiView::updateBufferDependent(bool switched) const
1355 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1356 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1358 for(; it != end; ++it) {
1359 Dialog * dialog = it->second.get();
1360 if (switched && dialog->isBufferDependent()) {
1361 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1362 dialog->updateView();
1366 // A bit clunky, but the dialog will request
1367 // that the kernel provides it with the necessary
1369 dialog->updateDialog();
1375 void GuiView::checkStatus()
1377 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1378 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1380 for(; it != end; ++it) {
1381 Dialog * const dialog = it->second.get();
1382 if (dialog && dialog->isVisibleView())
1383 dialog->checkStatus();
1389 // will be replaced by a proper factory...
1390 Dialog * createGuiAbout(GuiView & lv);
1391 Dialog * createGuiBibitem(GuiView & lv);
1392 Dialog * createGuiBibtex(GuiView & lv);
1393 Dialog * createGuiBox(GuiView & lv);
1394 Dialog * createGuiBranch(GuiView & lv);
1395 Dialog * createGuiChanges(GuiView & lv);
1396 Dialog * createGuiCharacter(GuiView & lv);
1397 Dialog * createGuiCitation(GuiView & lv);
1398 Dialog * createGuiDelimiter(GuiView & lv);
1399 Dialog * createGuiDocument(GuiView & lv);
1400 Dialog * createGuiErrorList(GuiView & lv);
1401 Dialog * createGuiERT(GuiView & lv);
1402 Dialog * createGuiExternal(GuiView & lv);
1403 Dialog * createGuiFloat(GuiView & lv);
1404 Dialog * createGuiGraphics(GuiView & lv);
1405 Dialog * createGuiInclude(GuiView & lv);
1406 Dialog * createGuiIndex(GuiView & lv);
1407 Dialog * createGuiLabel(GuiView & lv);
1408 Dialog * createGuiListings(GuiView & lv);
1409 Dialog * createGuiLog(GuiView & lv);
1410 Dialog * createGuiMathMatrix(GuiView & lv);
1411 Dialog * createGuiNomenclature(GuiView & lv);
1412 Dialog * createGuiNote(GuiView & lv);
1413 Dialog * createGuiParagraph(GuiView & lv);
1414 Dialog * createGuiPreferences(GuiView & lv);
1415 Dialog * createGuiPrint(GuiView & lv);
1416 Dialog * createGuiRef(GuiView & lv);
1417 Dialog * createGuiSearch(GuiView & lv);
1418 Dialog * createGuiSendTo(GuiView & lv);
1419 Dialog * createGuiShowFile(GuiView & lv);
1420 Dialog * createGuiSpellchecker(GuiView & lv);
1421 Dialog * createGuiTabularCreate(GuiView & lv);
1422 Dialog * createGuiTabular(GuiView & lv);
1423 Dialog * createGuiTexInfo(GuiView & lv);
1424 Dialog * createGuiToc(GuiView & lv);
1425 Dialog * createGuiThesaurus(GuiView & lv);
1426 Dialog * createGuiHyperlink(GuiView & lv);
1427 Dialog * createGuiVSpace(GuiView & lv);
1428 Dialog * createGuiViewSource(GuiView & lv);
1429 Dialog * createGuiWrap(GuiView & lv);
1432 Dialog * GuiView::build(string const & name)
1434 BOOST_ASSERT(isValidName(name));
1436 if (name == "aboutlyx")
1437 return createGuiAbout(*this);
1438 if (name == "bibitem")
1439 return createGuiBibitem(*this);
1440 if (name == "bibtex")
1441 return createGuiBibtex(*this);
1443 return createGuiBox(*this);
1444 if (name == "branch")
1445 return createGuiBranch(*this);
1446 if (name == "changes")
1447 return createGuiChanges(*this);
1448 if (name == "character")
1449 return createGuiCharacter(*this);
1450 if (name == "citation")
1451 return createGuiCitation(*this);
1452 if (name == "document")
1453 return createGuiDocument(*this);
1454 if (name == "errorlist")
1455 return createGuiErrorList(*this);
1457 return createGuiERT(*this);
1458 if (name == "external")
1459 return createGuiExternal(*this);
1461 return createGuiShowFile(*this);
1462 if (name == "findreplace")
1463 return createGuiSearch(*this);
1464 if (name == "float")
1465 return createGuiFloat(*this);
1466 if (name == "graphics")
1467 return createGuiGraphics(*this);
1468 if (name == "include")
1469 return createGuiInclude(*this);
1470 if (name == "index")
1471 return createGuiIndex(*this);
1472 if (name == "nomenclature")
1473 return createGuiNomenclature(*this);
1474 if (name == "label")
1475 return createGuiLabel(*this);
1477 return createGuiLog(*this);
1478 if (name == "view-source")
1479 return createGuiViewSource(*this);
1480 if (name == "mathdelimiter")
1481 return createGuiDelimiter(*this);
1482 if (name == "mathmatrix")
1483 return createGuiMathMatrix(*this);
1485 return createGuiNote(*this);
1486 if (name == "paragraph")
1487 return createGuiParagraph(*this);
1488 if (name == "prefs")
1489 return createGuiPreferences(*this);
1490 if (name == "print")
1491 return createGuiPrint(*this);
1493 return createGuiRef(*this);
1494 if (name == "sendto")
1495 return createGuiSendTo(*this);
1496 if (name == "spellchecker")
1497 return createGuiSpellchecker(*this);
1498 if (name == "tabular")
1499 return createGuiTabular(*this);
1500 if (name == "tabularcreate")
1501 return createGuiTabularCreate(*this);
1502 if (name == "texinfo")
1503 return createGuiTexInfo(*this);
1504 #ifdef HAVE_LIBAIKSAURUS
1505 if (name == "thesaurus")
1506 return createGuiThesaurus(*this);
1509 return createGuiToc(*this);
1511 return createGuiHyperlink(*this);
1512 if (name == "vspace")
1513 return createGuiVSpace(*this);
1515 return createGuiWrap(*this);
1516 if (name == "listings")
1517 return createGuiListings(*this);
1523 } // namespace frontend
1526 #include "GuiView_moc.cpp"