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_);
165 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 // By default we won't need any new update.
1024 Update::flags update_flags = Update::None;
1026 switch(cmd.action) {
1027 case LFUN_BUFFER_SWITCH:
1028 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1031 case LFUN_COMMAND_EXECUTE: {
1032 bool const show_it = cmd.argument() != "off";
1033 d.toolbars_->showCommandBuffer(show_it);
1036 case LFUN_DROP_LAYOUTS_CHOICE:
1038 d.layout_->showPopup();
1041 case LFUN_MENU_OPEN:
1042 d.menubar_->openByName(toqstr(cmd.argument()));
1045 case LFUN_TOOLBAR_TOGGLE: {
1046 string const name = cmd.getArg(0);
1047 bool const allowauto = cmd.getArg(1) == "allowauto";
1048 // it is possible to get current toolbar status like this,...
1049 // but I decide to obey the order of ToolbarBackend::flags
1050 // and disregard real toolbar status.
1051 // toolbars_->saveToolbarInfo();
1053 // toggle state on/off/auto
1054 d.toolbars_->toggleToolbarState(name, allowauto);
1058 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1060 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1064 if (tbi->flags & ToolbarInfo::ON)
1066 else if (tbi->flags & ToolbarInfo::OFF)
1068 else if (tbi->flags & ToolbarInfo::AUTO)
1071 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1072 _(tbi->gui_name), state));
1076 case LFUN_DIALOG_UPDATE: {
1077 string const name = to_utf8(cmd.argument());
1078 // Can only update a dialog connected to an existing inset
1079 Inset * inset = getOpenInset(name);
1081 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1082 inset->dispatch(view()->cursor(), fr);
1083 } else if (name == "paragraph") {
1084 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1085 } else if (name == "prefs") {
1086 updateDialog(name, string());
1091 case LFUN_DIALOG_TOGGLE: {
1092 if (isDialogVisible(cmd.getArg(0)))
1093 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1095 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1099 case LFUN_DIALOG_DISCONNECT_INSET:
1100 disconnectDialog(to_utf8(cmd.argument()));
1103 case LFUN_DIALOG_HIDE: {
1106 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1110 case LFUN_DIALOG_SHOW: {
1111 string const name = cmd.getArg(0);
1112 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1114 if (name == "character") {
1115 data = freefont2string();
1117 showDialog("character", data);
1118 } else if (name == "latexlog") {
1119 Buffer::LogType type;
1120 string const logfile = buffer()->logName(&type);
1122 case Buffer::latexlog:
1125 case Buffer::buildlog:
1129 data += Lexer::quoteString(logfile);
1130 showDialog("log", data);
1131 } else if (name == "vclog") {
1132 string const data = "vc " +
1133 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1134 showDialog("log", data);
1136 showDialog(name, data);
1140 case LFUN_INSET_APPLY: {
1141 string const name = cmd.getArg(0);
1142 Inset * inset = getOpenInset(name);
1144 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1145 inset->dispatch(view()->cursor(), fr);
1146 // ideally, the update flag should be set by the insets,
1147 // but this is not possible currently
1148 update_flags = Update::Force | Update::FitCursor;
1150 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1157 theLyXFunc().setLyXView(this);
1162 view()->cursor().updateFlags(update_flags);
1166 Buffer const * GuiView::updateInset(Inset const * inset)
1168 if (!d.current_work_area_)
1172 d.current_work_area_->scheduleRedraw();
1174 return &d.current_work_area_->bufferView().buffer();
1178 void GuiView::restartCursor()
1180 /* When we move around, or type, it's nice to be able to see
1181 * the cursor immediately after the keypress.
1183 if (d.current_work_area_)
1184 d.current_work_area_->startBlinkingCursor();
1186 // Take this occasion to update the toobars and layout list.
1193 // This list should be kept in sync with the list of insets in
1194 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1195 // dialog should have the same name as the inset.
1197 char const * const dialognames[] = {
1198 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1199 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1200 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1201 "mathdelimiter", "mathmatrix", "note", "paragraph",
1202 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1204 #ifdef HAVE_LIBAIKSAURUS
1208 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1210 char const * const * const end_dialognames =
1211 dialognames + (sizeof(dialognames) / sizeof(char *));
1215 cmpCStr(char const * name) : name_(name) {}
1216 bool operator()(char const * other) {
1217 return strcmp(other, name_) == 0;
1224 bool isValidName(string const & name)
1226 return std::find_if(dialognames, end_dialognames,
1227 cmpCStr(name.c_str())) != end_dialognames;
1233 void GuiView::resetDialogs()
1235 // Make sure that no LFUN uses any LyXView.
1236 theLyXFunc().setLyXView(0);
1237 d.toolbars_->init();
1240 d.layout_->updateContents(true);
1241 // Now update controls with current buffer.
1242 theLyXFunc().setLyXView(this);
1247 Dialog * GuiView::find_or_build(string const & name)
1249 if (!isValidName(name))
1252 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1254 if (it != d.dialogs_.end())
1255 return it->second.get();
1257 d.dialogs_[name].reset(build(name));
1258 return d.dialogs_[name].get();
1262 void GuiView::showDialog(string const & name, string const & data,
1269 Dialog * dialog = find_or_build(name);
1271 dialog->showData(data);
1273 d.open_insets_[name] = inset;
1279 bool GuiView::isDialogVisible(string const & name) const
1281 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1282 if (it == d.dialogs_.end())
1284 return it->second.get()->isVisibleView();
1288 void GuiView::hideDialog(string const & name, Inset * inset)
1290 // Don't send the signal if we are quitting, because on MSVC it is
1291 // destructed before the cut stack in CutAndPaste.cpp, and this method
1292 // is called from some inset destructor if the cut stack is not empty
1297 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1298 if (it == d.dialogs_.end())
1301 if (inset && inset != getOpenInset(name))
1304 Dialog * const dialog = it->second.get();
1305 if (dialog->isVisibleView())
1307 d.open_insets_[name] = 0;
1311 void GuiView::disconnectDialog(string const & name)
1313 if (!isValidName(name))
1316 if (d.open_insets_.find(name) != d.open_insets_.end())
1317 d.open_insets_[name] = 0;
1321 Inset * GuiView::getOpenInset(string const & name) const
1323 if (!isValidName(name))
1326 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1327 return it == d.open_insets_.end() ? 0 : it->second;
1331 void GuiView::hideAll() const
1333 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1334 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1336 for(; it != end; ++it)
1341 void GuiView::hideBufferDependent() const
1343 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1344 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1346 for(; it != end; ++it) {
1347 Dialog * dialog = it->second.get();
1348 if (dialog->isBufferDependent())
1354 void GuiView::updateBufferDependent(bool switched) const
1356 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1357 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1359 for(; it != end; ++it) {
1360 Dialog * dialog = it->second.get();
1361 if (switched && dialog->isBufferDependent()) {
1362 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1363 dialog->updateView();
1367 // A bit clunky, but the dialog will request
1368 // that the kernel provides it with the necessary
1370 dialog->updateDialog(dialog->name());
1376 void GuiView::checkStatus()
1378 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1379 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1381 for(; it != end; ++it) {
1382 Dialog * const dialog = it->second.get();
1383 if (dialog && dialog->isVisibleView())
1384 dialog->checkStatus();
1390 // will be replaced by a proper factory...
1391 Dialog * createGuiAbout(GuiView & lv);
1392 Dialog * createGuiBibitem(GuiView & lv);
1393 Dialog * createGuiBibtex(GuiView & lv);
1394 Dialog * createGuiBox(GuiView & lv);
1395 Dialog * createGuiBranch(GuiView & lv);
1396 Dialog * createGuiChanges(GuiView & lv);
1397 Dialog * createGuiCharacter(GuiView & lv);
1398 Dialog * createGuiCitation(GuiView & lv);
1399 Dialog * createGuiDelimiter(GuiView & lv);
1400 Dialog * createGuiDocument(GuiView & lv);
1401 Dialog * createGuiErrorList(GuiView & lv);
1402 Dialog * createGuiERT(GuiView & lv);
1403 Dialog * createGuiExternal(GuiView & lv);
1404 Dialog * createGuiFloat(GuiView & lv);
1405 Dialog * createGuiGraphics(GuiView & lv);
1406 Dialog * createGuiInclude(GuiView & lv);
1407 Dialog * createGuiIndex(GuiView & lv);
1408 Dialog * createGuiLabel(GuiView & lv);
1409 Dialog * createGuiListings(GuiView & lv);
1410 Dialog * createGuiLog(GuiView & lv);
1411 Dialog * createGuiMathMatrix(GuiView & lv);
1412 Dialog * createGuiNomenclature(GuiView & lv);
1413 Dialog * createGuiNote(GuiView & lv);
1414 Dialog * createGuiParagraph(GuiView & lv);
1415 Dialog * createGuiPreferences(GuiView & lv);
1416 Dialog * createGuiPrint(GuiView & lv);
1417 Dialog * createGuiRef(GuiView & lv);
1418 Dialog * createGuiSearch(GuiView & lv);
1419 Dialog * createGuiSendTo(GuiView & lv);
1420 Dialog * createGuiShowFile(GuiView & lv);
1421 Dialog * createGuiSpellchecker(GuiView & lv);
1422 Dialog * createGuiTabularCreate(GuiView & lv);
1423 Dialog * createGuiTabular(GuiView & lv);
1424 Dialog * createGuiTexInfo(GuiView & lv);
1425 Dialog * createGuiToc(GuiView & lv);
1426 Dialog * createGuiThesaurus(GuiView & lv);
1427 Dialog * createGuiHyperlink(GuiView & lv);
1428 Dialog * createGuiVSpace(GuiView & lv);
1429 Dialog * createGuiViewSource(GuiView & lv);
1430 Dialog * createGuiWrap(GuiView & lv);
1433 Dialog * GuiView::build(string const & name)
1435 BOOST_ASSERT(isValidName(name));
1437 if (name == "aboutlyx")
1438 return createGuiAbout(*this);
1439 if (name == "bibitem")
1440 return createGuiBibitem(*this);
1441 if (name == "bibtex")
1442 return createGuiBibtex(*this);
1444 return createGuiBox(*this);
1445 if (name == "branch")
1446 return createGuiBranch(*this);
1447 if (name == "changes")
1448 return createGuiChanges(*this);
1449 if (name == "character")
1450 return createGuiCharacter(*this);
1451 if (name == "citation")
1452 return createGuiCitation(*this);
1453 if (name == "document")
1454 return createGuiDocument(*this);
1455 if (name == "errorlist")
1456 return createGuiErrorList(*this);
1458 return createGuiERT(*this);
1459 if (name == "external")
1460 return createGuiExternal(*this);
1462 return createGuiShowFile(*this);
1463 if (name == "findreplace")
1464 return createGuiSearch(*this);
1465 if (name == "float")
1466 return createGuiFloat(*this);
1467 if (name == "graphics")
1468 return createGuiGraphics(*this);
1469 if (name == "include")
1470 return createGuiInclude(*this);
1471 if (name == "index")
1472 return createGuiIndex(*this);
1473 if (name == "nomenclature")
1474 return createGuiNomenclature(*this);
1475 if (name == "label")
1476 return createGuiLabel(*this);
1478 return createGuiLog(*this);
1479 if (name == "view-source")
1480 return createGuiViewSource(*this);
1481 if (name == "mathdelimiter")
1482 return createGuiDelimiter(*this);
1483 if (name == "mathmatrix")
1484 return createGuiMathMatrix(*this);
1486 return createGuiNote(*this);
1487 if (name == "paragraph")
1488 return createGuiParagraph(*this);
1489 if (name == "prefs")
1490 return createGuiPreferences(*this);
1491 if (name == "print")
1492 return createGuiPrint(*this);
1494 return createGuiRef(*this);
1495 if (name == "sendto")
1496 return createGuiSendTo(*this);
1497 if (name == "spellchecker")
1498 return createGuiSpellchecker(*this);
1499 if (name == "tabular")
1500 return createGuiTabular(*this);
1501 if (name == "tabularcreate")
1502 return createGuiTabularCreate(*this);
1503 if (name == "texinfo")
1504 return createGuiTexInfo(*this);
1505 #ifdef HAVE_LIBAIKSAURUS
1506 if (name == "thesaurus")
1507 return createGuiThesaurus(*this);
1510 return createGuiToc(*this);
1512 return createGuiHyperlink(*this);
1513 if (name == "vspace")
1514 return createGuiVSpace(*this);
1516 return createGuiWrap(*this);
1517 if (name == "listings")
1518 return createGuiListings(*this);
1524 } // namespace frontend
1527 #include "GuiView_moc.cpp"