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 // removing a work area often results from closing a file so
735 // update the toc in any case.
738 for (int i = 0; i != d.splitter_->count(); ++i) {
739 TabWorkArea * twa = d.tabWorkArea(i);
740 if (!twa->removeWorkArea(wa))
741 // Not found in this tab group.
744 // We found and removed the GuiWorkArea.
746 // No more WorkAreas in this tab group, so delete it.
751 if (d.current_work_area_)
752 // This means that we are not closing the current GuiWorkArea;
755 // Switch to the next GuiWorkArea in the found TabWorkArea.
756 d.current_work_area_ = twa->currentWorkArea();
760 if (d.splitter_->count() == 0)
761 // No more work area, switch to the background widget.
766 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
772 void GuiView::updateLayoutList()
775 d.layout_->updateContents(false);
779 void GuiView::updateToolbars()
781 if (d.current_work_area_) {
783 d.current_work_area_->bufferView().cursor().inMathed();
785 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
787 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
788 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
790 d.toolbars_->update(math, table, review);
792 d.toolbars_->update(false, false, false);
794 // update read-only status of open dialogs.
799 Buffer * GuiView::buffer()
801 if (d.current_work_area_)
802 return &d.current_work_area_->bufferView().buffer();
807 Buffer const * GuiView::buffer() const
809 if (d.current_work_area_)
810 return &d.current_work_area_->bufferView().buffer();
815 void GuiView::setBuffer(Buffer * newBuffer)
817 BOOST_ASSERT(newBuffer);
820 GuiWorkArea * wa = workArea(*newBuffer);
822 updateLabels(*newBuffer->masterBuffer());
823 wa = addWorkArea(*newBuffer);
825 //Disconnect the old buffer...there's no new one.
828 connectBuffer(*newBuffer);
829 connectBufferView(wa->bufferView());
830 setCurrentWorkArea(wa);
836 void GuiView::connectBuffer(Buffer & buf)
838 buf.setGuiDelegate(this);
842 void GuiView::disconnectBuffer()
844 if (d.current_work_area_)
845 d.current_work_area_->bufferView().setGuiDelegate(0);
849 void GuiView::connectBufferView(BufferView & bv)
851 bv.setGuiDelegate(this);
855 void GuiView::disconnectBufferView()
857 if (d.current_work_area_)
858 d.current_work_area_->bufferView().setGuiDelegate(0);
862 void GuiView::errors(string const & error_type)
864 ErrorList & el = buffer()->errorList(error_type);
866 showDialog("errorlist", error_type);
870 void GuiView::updateDialog(string const & name, string const & data)
872 if (!isDialogVisible(name))
875 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
876 if (it == d.dialogs_.end())
879 Dialog * const dialog = it->second.get();
880 if (dialog->isVisibleView())
881 dialog->updateData(data);
885 BufferView * GuiView::view()
887 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
891 void GuiView::updateToc()
893 updateDialog("toc", "");
897 void GuiView::updateEmbeddedFiles()
899 updateDialog("embedding", "");
903 void GuiView::autoSave()
905 LYXERR(Debug::INFO, "Running autoSave()");
908 view()->buffer().autoSave();
912 void GuiView::resetAutosaveTimers()
915 d.autosave_timeout_.restart();
919 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
923 Buffer * buf = buffer();
925 /* In LyX/Mac, when a dialog is open, the menus of the
926 application can still be accessed without giving focus to
927 the main window. In this case, we want to disable the menu
928 entries that are buffer-related.
930 Note that this code is not perfect, as bug 1941 attests:
931 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
933 if (cmd.origin == FuncRequest::MENU && !hasFocus())
937 case LFUN_TOOLBAR_TOGGLE:
938 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
941 case LFUN_DIALOG_TOGGLE:
942 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
943 // fall through to set "enable"
944 case LFUN_DIALOG_SHOW: {
945 string const name = cmd.getArg(0);
947 enable = name == "aboutlyx"
948 || name == "file" //FIXME: should be removed.
950 || name == "texinfo";
951 else if (name == "print")
952 enable = buf->isExportable("dvi")
953 && lyxrc.print_command != "none";
954 else if (name == "character") {
958 InsetCode ic = view()->cursor().inset().lyxCode();
959 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
962 else if (name == "latexlog")
963 enable = FileName(buf->logName()).isReadableFile();
964 else if (name == "spellchecker")
965 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
966 enable = !buf->isReadonly();
970 else if (name == "vclog")
971 enable = buf->lyxvc().inUse();
975 case LFUN_DIALOG_UPDATE: {
976 string const name = cmd.getArg(0);
978 enable = name == "prefs";
982 case LFUN_INSET_APPLY: {
987 string const name = cmd.getArg(0);
988 Inset * inset = getOpenInset(name);
990 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
992 if (!inset->getStatus(view()->cursor(), fr, fs)) {
993 // Every inset is supposed to handle this
998 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
999 flag |= getStatus(fr);
1001 enable = flag.enabled();
1013 flag.enabled(false);
1019 bool GuiView::dispatch(FuncRequest const & cmd)
1021 BufferView * bv = view();
1022 // By default we won't need any update.
1024 bv->cursor().updateFlags(Update::None);
1026 switch(cmd.action) {
1027 case LFUN_BUFFER_SWITCH:
1028 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1031 case LFUN_BUFFER_NEXT:
1032 setBuffer(theBufferList().next(buffer()));
1035 case LFUN_BUFFER_PREVIOUS:
1036 setBuffer(theBufferList().previous(buffer()));
1039 case LFUN_COMMAND_EXECUTE: {
1040 bool const show_it = cmd.argument() != "off";
1041 d.toolbars_->showCommandBuffer(show_it);
1044 case LFUN_DROP_LAYOUTS_CHOICE:
1046 d.layout_->showPopup();
1049 case LFUN_MENU_OPEN:
1050 d.menubar_->openByName(toqstr(cmd.argument()));
1053 case LFUN_TOOLBAR_TOGGLE: {
1054 string const name = cmd.getArg(0);
1055 bool const allowauto = cmd.getArg(1) == "allowauto";
1056 // it is possible to get current toolbar status like this,...
1057 // but I decide to obey the order of ToolbarBackend::flags
1058 // and disregard real toolbar status.
1059 // toolbars_->saveToolbarInfo();
1061 // toggle state on/off/auto
1062 d.toolbars_->toggleToolbarState(name, allowauto);
1066 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1068 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1072 if (tbi->flags & ToolbarInfo::ON)
1074 else if (tbi->flags & ToolbarInfo::OFF)
1076 else if (tbi->flags & ToolbarInfo::AUTO)
1079 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1080 _(tbi->gui_name), state));
1084 case LFUN_DIALOG_UPDATE: {
1085 string const name = to_utf8(cmd.argument());
1086 // Can only update a dialog connected to an existing inset
1087 Inset * inset = getOpenInset(name);
1089 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1090 inset->dispatch(view()->cursor(), fr);
1091 } else if (name == "paragraph") {
1092 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1093 } else if (name == "prefs") {
1094 updateDialog(name, string());
1099 case LFUN_DIALOG_TOGGLE: {
1100 if (isDialogVisible(cmd.getArg(0)))
1101 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1103 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1107 case LFUN_DIALOG_DISCONNECT_INSET:
1108 disconnectDialog(to_utf8(cmd.argument()));
1111 case LFUN_DIALOG_HIDE: {
1114 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1118 case LFUN_DIALOG_SHOW: {
1119 string const name = cmd.getArg(0);
1120 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1122 if (name == "character") {
1123 data = freefont2string();
1125 showDialog("character", data);
1126 } else if (name == "latexlog") {
1127 Buffer::LogType type;
1128 string const logfile = buffer()->logName(&type);
1130 case Buffer::latexlog:
1133 case Buffer::buildlog:
1137 data += Lexer::quoteString(logfile);
1138 showDialog("log", data);
1139 } else if (name == "vclog") {
1140 string const data = "vc " +
1141 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1142 showDialog("log", data);
1144 showDialog(name, data);
1148 case LFUN_INSET_APPLY: {
1149 string const name = cmd.getArg(0);
1150 Inset * inset = getOpenInset(name);
1152 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1153 inset->dispatch(view()->cursor(), fr);
1155 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1169 Buffer const * GuiView::updateInset(Inset const * inset)
1171 if (!d.current_work_area_)
1175 d.current_work_area_->scheduleRedraw();
1177 return &d.current_work_area_->bufferView().buffer();
1181 void GuiView::restartCursor()
1183 /* When we move around, or type, it's nice to be able to see
1184 * the cursor immediately after the keypress.
1186 if (d.current_work_area_)
1187 d.current_work_area_->startBlinkingCursor();
1189 // Take this occasion to update the toobars and layout list.
1196 // This list should be kept in sync with the list of insets in
1197 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1198 // dialog should have the same name as the inset.
1200 char const * const dialognames[] = {
1201 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1202 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1203 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1204 "mathdelimiter", "mathmatrix", "note", "paragraph",
1205 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1207 #ifdef HAVE_LIBAIKSAURUS
1211 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1213 char const * const * const end_dialognames =
1214 dialognames + (sizeof(dialognames) / sizeof(char *));
1218 cmpCStr(char const * name) : name_(name) {}
1219 bool operator()(char const * other) {
1220 return strcmp(other, name_) == 0;
1227 bool isValidName(string const & name)
1229 return std::find_if(dialognames, end_dialognames,
1230 cmpCStr(name.c_str())) != end_dialognames;
1236 void GuiView::resetDialogs()
1238 // Make sure that no LFUN uses any LyXView.
1239 theLyXFunc().setLyXView(0);
1240 d.toolbars_->init();
1243 d.layout_->updateContents(true);
1244 // Now update controls with current buffer.
1245 theLyXFunc().setLyXView(this);
1250 Dialog * GuiView::find_or_build(string const & name)
1252 if (!isValidName(name))
1255 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1257 if (it != d.dialogs_.end())
1258 return it->second.get();
1260 d.dialogs_[name].reset(build(name));
1261 return d.dialogs_[name].get();
1265 void GuiView::showDialog(string const & name, string const & data,
1272 Dialog * dialog = find_or_build(name);
1274 dialog->showData(data);
1276 d.open_insets_[name] = inset;
1282 bool GuiView::isDialogVisible(string const & name) const
1284 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1285 if (it == d.dialogs_.end())
1287 return it->second.get()->isVisibleView();
1291 void GuiView::hideDialog(string const & name, Inset * inset)
1293 // Don't send the signal if we are quitting, because on MSVC it is
1294 // destructed before the cut stack in CutAndPaste.cpp, and this method
1295 // is called from some inset destructor if the cut stack is not empty
1300 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1301 if (it == d.dialogs_.end())
1304 if (inset && inset != getOpenInset(name))
1307 Dialog * const dialog = it->second.get();
1308 if (dialog->isVisibleView())
1310 d.open_insets_[name] = 0;
1314 void GuiView::disconnectDialog(string const & name)
1316 if (!isValidName(name))
1319 if (d.open_insets_.find(name) != d.open_insets_.end())
1320 d.open_insets_[name] = 0;
1324 Inset * GuiView::getOpenInset(string const & name) const
1326 if (!isValidName(name))
1329 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1330 return it == d.open_insets_.end() ? 0 : it->second;
1334 void GuiView::hideAll() const
1336 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1337 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1339 for(; it != end; ++it)
1344 void GuiView::hideBufferDependent() const
1346 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1347 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1349 for(; it != end; ++it) {
1350 Dialog * dialog = it->second.get();
1351 if (dialog->isBufferDependent())
1357 void GuiView::updateBufferDependent(bool switched) const
1359 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1360 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1362 for(; it != end; ++it) {
1363 Dialog * dialog = it->second.get();
1364 if (switched && dialog->isBufferDependent()) {
1365 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1366 dialog->updateView();
1370 // A bit clunky, but the dialog will request
1371 // that the kernel provides it with the necessary
1373 dialog->updateDialog();
1379 void GuiView::checkStatus()
1381 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1382 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1384 for(; it != end; ++it) {
1385 Dialog * const dialog = it->second.get();
1386 if (dialog && dialog->isVisibleView())
1387 dialog->checkStatus();
1393 // will be replaced by a proper factory...
1394 Dialog * createGuiAbout(GuiView & lv);
1395 Dialog * createGuiBibitem(GuiView & lv);
1396 Dialog * createGuiBibtex(GuiView & lv);
1397 Dialog * createGuiBox(GuiView & lv);
1398 Dialog * createGuiBranch(GuiView & lv);
1399 Dialog * createGuiChanges(GuiView & lv);
1400 Dialog * createGuiCharacter(GuiView & lv);
1401 Dialog * createGuiCitation(GuiView & lv);
1402 Dialog * createGuiDelimiter(GuiView & lv);
1403 Dialog * createGuiDocument(GuiView & lv);
1404 Dialog * createGuiErrorList(GuiView & lv);
1405 Dialog * createGuiERT(GuiView & lv);
1406 Dialog * createGuiExternal(GuiView & lv);
1407 Dialog * createGuiFloat(GuiView & lv);
1408 Dialog * createGuiGraphics(GuiView & lv);
1409 Dialog * createGuiInclude(GuiView & lv);
1410 Dialog * createGuiIndex(GuiView & lv);
1411 Dialog * createGuiLabel(GuiView & lv);
1412 Dialog * createGuiListings(GuiView & lv);
1413 Dialog * createGuiLog(GuiView & lv);
1414 Dialog * createGuiMathMatrix(GuiView & lv);
1415 Dialog * createGuiNomenclature(GuiView & lv);
1416 Dialog * createGuiNote(GuiView & lv);
1417 Dialog * createGuiParagraph(GuiView & lv);
1418 Dialog * createGuiPreferences(GuiView & lv);
1419 Dialog * createGuiPrint(GuiView & lv);
1420 Dialog * createGuiRef(GuiView & lv);
1421 Dialog * createGuiSearch(GuiView & lv);
1422 Dialog * createGuiSendTo(GuiView & lv);
1423 Dialog * createGuiShowFile(GuiView & lv);
1424 Dialog * createGuiSpellchecker(GuiView & lv);
1425 Dialog * createGuiTabularCreate(GuiView & lv);
1426 Dialog * createGuiTabular(GuiView & lv);
1427 Dialog * createGuiTexInfo(GuiView & lv);
1428 Dialog * createGuiToc(GuiView & lv);
1429 Dialog * createGuiThesaurus(GuiView & lv);
1430 Dialog * createGuiHyperlink(GuiView & lv);
1431 Dialog * createGuiVSpace(GuiView & lv);
1432 Dialog * createGuiViewSource(GuiView & lv);
1433 Dialog * createGuiWrap(GuiView & lv);
1436 Dialog * GuiView::build(string const & name)
1438 BOOST_ASSERT(isValidName(name));
1440 if (name == "aboutlyx")
1441 return createGuiAbout(*this);
1442 if (name == "bibitem")
1443 return createGuiBibitem(*this);
1444 if (name == "bibtex")
1445 return createGuiBibtex(*this);
1447 return createGuiBox(*this);
1448 if (name == "branch")
1449 return createGuiBranch(*this);
1450 if (name == "changes")
1451 return createGuiChanges(*this);
1452 if (name == "character")
1453 return createGuiCharacter(*this);
1454 if (name == "citation")
1455 return createGuiCitation(*this);
1456 if (name == "document")
1457 return createGuiDocument(*this);
1458 if (name == "errorlist")
1459 return createGuiErrorList(*this);
1461 return createGuiERT(*this);
1462 if (name == "external")
1463 return createGuiExternal(*this);
1465 return createGuiShowFile(*this);
1466 if (name == "findreplace")
1467 return createGuiSearch(*this);
1468 if (name == "float")
1469 return createGuiFloat(*this);
1470 if (name == "graphics")
1471 return createGuiGraphics(*this);
1472 if (name == "include")
1473 return createGuiInclude(*this);
1474 if (name == "index")
1475 return createGuiIndex(*this);
1476 if (name == "nomenclature")
1477 return createGuiNomenclature(*this);
1478 if (name == "label")
1479 return createGuiLabel(*this);
1481 return createGuiLog(*this);
1482 if (name == "view-source")
1483 return createGuiViewSource(*this);
1484 if (name == "mathdelimiter")
1485 return createGuiDelimiter(*this);
1486 if (name == "mathmatrix")
1487 return createGuiMathMatrix(*this);
1489 return createGuiNote(*this);
1490 if (name == "paragraph")
1491 return createGuiParagraph(*this);
1492 if (name == "prefs")
1493 return createGuiPreferences(*this);
1494 if (name == "print")
1495 return createGuiPrint(*this);
1497 return createGuiRef(*this);
1498 if (name == "sendto")
1499 return createGuiSendTo(*this);
1500 if (name == "spellchecker")
1501 return createGuiSpellchecker(*this);
1502 if (name == "tabular")
1503 return createGuiTabular(*this);
1504 if (name == "tabularcreate")
1505 return createGuiTabularCreate(*this);
1506 if (name == "texinfo")
1507 return createGuiTexInfo(*this);
1508 #ifdef HAVE_LIBAIKSAURUS
1509 if (name == "thesaurus")
1510 return createGuiThesaurus(*this);
1513 return createGuiToc(*this);
1515 return createGuiHyperlink(*this);
1516 if (name == "vspace")
1517 return createGuiVSpace(*this);
1519 return createGuiWrap(*this);
1520 if (name == "listings")
1521 return createGuiListings(*this);
1527 } // namespace frontend
1530 #include "GuiView_moc.cpp"