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 <boost/assert.hpp>
25 #include "GuiApplication.h"
26 #include "GuiWorkArea.h"
27 #include "GuiKeySymbol.h"
28 #include "GuiMenubar.h"
29 #include "GuiToolbar.h"
30 #include "GuiToolbars.h"
32 #include "qt_helpers.h"
34 #include "buffer_funcs.h"
36 #include "BufferList.h"
37 #include "BufferParams.h"
38 #include "BufferView.h"
41 #include "ErrorList.h"
42 #include "FuncRequest.h"
51 #include "MenuBackend.h"
52 #include "Paragraph.h"
53 #include "TextClass.h"
55 #include "ToolbarBackend.h"
58 #include "support/convert.h"
59 #include "support/FileName.h"
60 #include "support/lstrings.h"
61 #include "support/os.h"
62 #include "support/Timeout.h"
65 #include <QApplication>
66 #include <QCloseEvent>
67 #include <QDesktopWidget>
68 #include <QDragEnterEvent>
75 #include <QPushButton>
79 #include <QStackedWidget>
85 #include <boost/bind.hpp>
86 #include <boost/current_function.hpp>
88 #ifdef HAVE_SYS_TIME_H
89 # include <sys/time.h>
101 extern bool quitting;
105 using support::bformat;
106 using support::FileName;
111 class BackgroundWidget : public QWidget
114 BackgroundWidget(QString const & file, QString const & text)
117 QPainter pain(&splash_);
118 pain.setPen(QColor(255, 255, 0));
120 // The font used to display the version info
121 font.setStyleHint(QFont::SansSerif);
122 font.setWeight(QFont::Bold);
123 font.setPointSize(convert<int>(lyxrc.font_sizes[FONT_SIZE_LARGE]));
125 pain.drawText(260, 270, text);
128 void paintEvent(QPaintEvent *)
130 int x = (width() - splash_.width()) / 2;
131 int y = (height() - splash_.height()) / 2;
133 pain.drawPixmap(x, y, splash_);
143 typedef boost::shared_ptr<Dialog> DialogPtr;
145 struct GuiView::GuiViewPrivate
148 : current_work_area_(0), layout_(0),
149 quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false)
151 // hardcode here the platform specific icon size
152 smallIconSize = 14; // scaling problems
153 normalIconSize = 20; // ok, default
154 bigIconSize = 26; // better for some math icons
156 splitter_ = new QSplitter;
158 stack_widget_ = new QStackedWidget;
159 stack_widget_->addWidget(bg_widget_);
160 stack_widget_->addWidget(splitter_);
168 delete stack_widget_;
173 QMenu * toolBarPopup(GuiView * parent)
175 // FIXME: translation
176 QMenu * menu = new QMenu(parent);
177 QActionGroup * iconSizeGroup = new QActionGroup(parent);
179 QAction * smallIcons = new QAction(iconSizeGroup);
180 smallIcons->setText(qt_("Small-sized icons"));
181 smallIcons->setCheckable(true);
182 QObject::connect(smallIcons, SIGNAL(triggered()),
183 parent, SLOT(smallSizedIcons()));
184 menu->addAction(smallIcons);
186 QAction * normalIcons = new QAction(iconSizeGroup);
187 normalIcons->setText(qt_("Normal-sized icons"));
188 normalIcons->setCheckable(true);
189 QObject::connect(normalIcons, SIGNAL(triggered()),
190 parent, SLOT(normalSizedIcons()));
191 menu->addAction(normalIcons);
193 QAction * bigIcons = new QAction(iconSizeGroup);
194 bigIcons->setText(qt_("Big-sized icons"));
195 bigIcons->setCheckable(true);
196 QObject::connect(bigIcons, SIGNAL(triggered()),
197 parent, SLOT(bigSizedIcons()));
198 menu->addAction(bigIcons);
200 unsigned int cur = parent->iconSize().width();
201 if ( cur == parent->d.smallIconSize)
202 smallIcons->setChecked(true);
203 else if (cur == parent->d.normalIconSize)
204 normalIcons->setChecked(true);
205 else if (cur == parent->d.bigIconSize)
206 bigIcons->setChecked(true);
211 void initBackground()
213 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
214 /// The text to be written on top of the pixmap
215 QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
216 bg_widget_ = new BackgroundWidget(":/images/banner.png", text);
221 stack_widget_->setCurrentWidget(bg_widget_);
222 bg_widget_->setUpdatesEnabled(true);
225 TabWorkArea * tabWorkArea(int i)
227 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
230 TabWorkArea * currentTabWorkArea()
232 if (splitter_->count() == 1)
233 // The first TabWorkArea is always the first one, if any.
234 return tabWorkArea(0);
236 TabWorkArea * tab_widget = 0;
237 for (int i = 0; i != splitter_->count(); ++i) {
238 QWidget * w = splitter_->widget(i);
241 tab_widget = dynamic_cast<TabWorkArea *>(w);
253 GuiWorkArea * current_work_area_;
254 QSplitter * splitter_;
255 QStackedWidget * stack_widget_;
256 BackgroundWidget * bg_widget_;
258 GuiMenubar * menubar_;
260 GuiToolbars * toolbars_;
261 /// The main layout box.
263 * \warning Don't Delete! The layout box is actually owned by
264 * whichever toolbar contains it. All the GuiView class needs is a
265 * means of accessing it.
267 * FIXME: replace that with a proper model so that we are not limited
268 * to only one dialog.
270 GuiLayoutBox * layout_;
273 std::map<std::string, Inset *> open_insets_;
276 std::map<std::string, DialogPtr> dialogs_;
278 unsigned int smallIconSize;
279 unsigned int normalIconSize;
280 unsigned int bigIconSize;
282 QTimer statusbar_timer_;
283 /// are we quitting by the menu?
284 bool quitting_by_menu_;
285 /// auto-saving of buffers
286 Timeout autosave_timeout_;
288 /// flag against a race condition due to multiclicks in Qt frontend,
294 GuiView::GuiView(int id)
295 : d(*new GuiViewPrivate), id_(id)
297 // GuiToolbars *must* be initialised before GuiMenubar.
298 d.toolbars_ = new GuiToolbars(*this);
299 d.menubar_ = new GuiMenubar(this, menubackend);
301 setCentralWidget(d.stack_widget_);
303 // Start autosave timer
304 if (lyxrc.autosave) {
305 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
306 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
307 d.autosave_timeout_.start();
309 connect(&d.statusbar_timer_, SIGNAL(timeout()),
310 this, SLOT(clearMessage()));
312 // Qt bug? signal lastWindowClosed does not work
313 setAttribute(Qt::WA_QuitOnClose, false);
314 setAttribute(Qt::WA_DeleteOnClose, true);
316 // assign an icon to main form. We do not do it under Qt/Mac,
317 // since the icon is provided in the application bundle.
318 setWindowIcon(QPixmap(":/images/lyx.png"));
322 setAcceptDrops(true);
324 statusBar()->setSizeGripEnabled(true);
326 // Forbid too small unresizable window because it can happen
327 // with some window manager under X11.
328 setMinimumSize(300, 200);
330 if (!lyxrc.allow_geometry_session)
331 // No session handling, default to a sane size.
332 setGeometry(50, 50, 690, 510);
334 // Now take care of session management.
336 QString const key = "view-" + QString::number(id_);
338 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
339 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
343 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
344 setGeometry(50, 50, 690, 510);
346 setIconSize(settings.value(key + "/icon_size").toSize());
356 void GuiView::close()
358 d.quitting_by_menu_ = true;
359 d.current_work_area_ = 0;
360 for (int i = 0; i != d.splitter_->count(); ++i) {
361 TabWorkArea * twa = d.tabWorkArea(i);
365 QMainWindow::close();
366 d.quitting_by_menu_ = false;
370 void GuiView::setFocus()
372 if (d.current_work_area_)
373 d.current_work_area_->setFocus();
379 QMenu* GuiView::createPopupMenu()
381 return d.toolBarPopup(this);
385 void GuiView::showEvent(QShowEvent * e)
387 LYXERR(Debug::GUI, "Passed Geometry "
388 << size().height() << "x" << size().width()
389 << "+" << pos().x() << "+" << pos().y());
391 if (d.splitter_->count() == 0)
392 // No work area, switch to the background widget.
395 QMainWindow::showEvent(e);
399 void GuiView::closeEvent(QCloseEvent * close_event)
401 // we may have been called through the close window button
402 // which bypasses the LFUN machinery.
403 if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
404 if (!theBufferList().quitWriteAll()) {
405 close_event->ignore();
410 // Make sure that no LFUN use this close to be closed View.
411 theLyXFunc().setLyXView(0);
412 // Make sure the timer time out will not trigger a statusbar update.
413 d.statusbar_timer_.stop();
415 if (lyxrc.allow_geometry_session) {
417 QString const key = "view-" + QString::number(id_);
419 settings.setValue(key + "/pos", pos());
420 settings.setValue(key + "/size", size());
422 settings.setValue(key + "/geometry", saveGeometry());
424 settings.setValue(key + "/icon_size", iconSize());
425 d.toolbars_->saveToolbarInfo();
428 guiApp->unregisterView(id_);
429 if (guiApp->viewCount() > 0) {
430 // Just close the window and do nothing else if this is not the
432 close_event->accept();
438 // this is the place where we leave the frontend.
439 // it is the only point at which we start quitting.
440 close_event->accept();
441 // quit the event loop
446 void GuiView::dragEnterEvent(QDragEnterEvent * event)
448 if (event->mimeData()->hasUrls())
450 /// \todo Ask lyx-devel is this is enough:
451 /// if (event->mimeData()->hasFormat("text/plain"))
452 /// event->acceptProposedAction();
456 void GuiView::dropEvent(QDropEvent* event)
458 QList<QUrl> files = event->mimeData()->urls();
462 LYXERR(Debug::GUI, BOOST_CURRENT_FUNCTION << " got URLs!");
463 for (int i = 0; i != files.size(); ++i) {
464 string const file = support::os::internal_path(fromqstr(
465 files.at(i).toLocalFile()));
467 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
472 void GuiView::message(docstring const & str)
474 statusBar()->showMessage(toqstr(str));
475 d.statusbar_timer_.stop();
476 d.statusbar_timer_.start(3000);
480 void GuiView::smallSizedIcons()
482 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
486 void GuiView::normalSizedIcons()
488 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
492 void GuiView::bigSizedIcons()
494 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
498 void GuiView::clearMessage()
502 theLyXFunc().setLyXView(this);
503 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
504 d.statusbar_timer_.stop();
508 void GuiView::updateWindowTitle(GuiWorkArea * wa)
510 if (wa != d.current_work_area_)
512 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
513 setWindowIconText(wa->windowIconText());
517 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
520 disconnectBufferView();
521 connectBufferView(wa->bufferView());
522 connectBuffer(wa->bufferView().buffer());
523 d.current_work_area_ = wa;
524 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
525 this, SLOT(updateWindowTitle(GuiWorkArea *)));
526 updateWindowTitle(wa);
529 // Buffer-dependent dialogs should be updated or
530 // hidden. This should go here because some dialogs (eg ToC)
531 // require bv_->text.
532 updateBufferDependent(true);
539 void GuiView::updateStatusBar()
541 // let the user see the explicit message
542 if (d.statusbar_timer_.isActive())
545 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
549 bool GuiView::hasFocus() const
551 return qApp->activeWindow() == this;
555 bool GuiView::event(QEvent * e)
559 // Useful debug code:
560 //case QEvent::ActivationChange:
561 //case QEvent::WindowDeactivate:
562 //case QEvent::Paint:
563 //case QEvent::Enter:
564 //case QEvent::Leave:
565 //case QEvent::HoverEnter:
566 //case QEvent::HoverLeave:
567 //case QEvent::HoverMove:
568 //case QEvent::StatusTip:
569 //case QEvent::DragEnter:
570 //case QEvent::DragLeave:
574 case QEvent::WindowActivate: {
575 guiApp->setCurrentView(*this);
576 if (d.current_work_area_) {
577 BufferView & bv = d.current_work_area_->bufferView();
578 connectBufferView(bv);
579 connectBuffer(bv.buffer());
580 // The document structure, name and dialogs might have
581 // changed in another view.
582 updateBufferDependent(true);
584 setWindowTitle(qt_("LyX"));
585 setWindowIconText(qt_("LyX"));
587 return QMainWindow::event(e);
589 case QEvent::ShortcutOverride: {
590 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
591 if (!d.current_work_area_) {
592 theLyXFunc().setLyXView(this);
594 setKeySymbol(&sym, ke);
595 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
599 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
601 setKeySymbol(&sym, ke);
602 d.current_work_area_->processKeySym(sym, NoModifier);
608 return QMainWindow::event(e);
613 bool GuiView::focusNextPrevChild(bool /*next*/)
620 void GuiView::setBusy(bool yes)
622 if (d.current_work_area_) {
623 d.current_work_area_->setUpdatesEnabled(!yes);
625 d.current_work_area_->stopBlinkingCursor();
627 d.current_work_area_->startBlinkingCursor();
631 QApplication::setOverrideCursor(Qt::WaitCursor);
633 QApplication::restoreOverrideCursor();
637 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
639 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
641 if (tbinfo.flags & ToolbarInfo::TOP) {
643 addToolBarBreak(Qt::TopToolBarArea);
644 addToolBar(Qt::TopToolBarArea, toolBar);
647 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
648 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
649 #if (QT_VERSION >= 0x040202)
651 addToolBarBreak(Qt::BottomToolBarArea);
653 addToolBar(Qt::BottomToolBarArea, toolBar);
656 if (tbinfo.flags & ToolbarInfo::LEFT) {
657 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
658 #if (QT_VERSION >= 0x040202)
660 addToolBarBreak(Qt::LeftToolBarArea);
662 addToolBar(Qt::LeftToolBarArea, toolBar);
665 if (tbinfo.flags & ToolbarInfo::RIGHT) {
666 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
667 #if (QT_VERSION >= 0x040202)
669 addToolBarBreak(Qt::RightToolBarArea);
671 addToolBar(Qt::RightToolBarArea, toolBar);
674 // The following does not work so I cannot restore to exact toolbar location
676 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
677 toolBar->move(tbinfo.posx, tbinfo.posy);
684 GuiWorkArea * GuiView::workArea(Buffer & buffer)
686 for (int i = 0; i != d.splitter_->count(); ++i) {
687 GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
695 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
698 // Automatically create a TabWorkArea if there are none yet.
699 if (!d.splitter_->count())
702 TabWorkArea * tab_widget = d.currentTabWorkArea();
703 return tab_widget->addWorkArea(buffer, *this);
707 void GuiView::addTabWorkArea()
709 TabWorkArea * twa = new TabWorkArea;
710 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
711 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
712 d.splitter_->addWidget(twa);
713 d.stack_widget_->setCurrentWidget(d.splitter_);
717 GuiWorkArea const * GuiView::currentWorkArea() const
719 return d.current_work_area_;
723 void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
725 BOOST_ASSERT(work_area);
727 // Changing work area can result from opening a file so
728 // update the toc in any case.
731 GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
732 d.current_work_area_ = wa;
733 for (int i = 0; i != d.splitter_->count(); ++i) {
734 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
740 void GuiView::removeWorkArea(GuiWorkArea * work_area)
742 BOOST_ASSERT(work_area);
743 GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
744 if (gwa == d.current_work_area_) {
746 disconnectBufferView();
747 hideBufferDependent();
748 d.current_work_area_ = 0;
751 // removing a work area often results from closing a file so
752 // update the toc in any case.
755 for (int i = 0; i != d.splitter_->count(); ++i) {
756 TabWorkArea * twa = d.tabWorkArea(i);
757 if (!twa->removeWorkArea(gwa))
758 // Not found in this tab group.
761 // We found and removed the GuiWorkArea.
763 // No more WorkAreas in this tab group, so delete it.
768 if (d.current_work_area_)
769 // This means that we are not closing the current GuiWorkArea;
772 // Switch to the next GuiWorkArea in the found TabWorkArea.
773 d.current_work_area_ = twa->currentWorkArea();
777 if (d.splitter_->count() == 0)
778 // No more work area, switch to the background widget.
783 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
789 void GuiView::updateLayoutList()
792 d.layout_->updateContents(false);
796 void GuiView::updateToolbars()
798 if (d.current_work_area_) {
800 d.current_work_area_->bufferView().cursor().inMathed();
802 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
804 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
805 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
807 d.toolbars_->update(math, table, review);
809 d.toolbars_->update(false, false, false);
811 // update read-only status of open dialogs.
816 Buffer * GuiView::buffer()
818 if (d.current_work_area_)
819 return &d.current_work_area_->bufferView().buffer();
824 Buffer const * GuiView::buffer() const
826 if (d.current_work_area_)
827 return &d.current_work_area_->bufferView().buffer();
832 void GuiView::setBuffer(Buffer * newBuffer)
834 BOOST_ASSERT(newBuffer);
837 GuiWorkArea * wa = workArea(*newBuffer);
839 updateLabels(*newBuffer->masterBuffer());
840 wa = addWorkArea(*newBuffer);
842 //Disconnect the old buffer...there's no new one.
845 connectBuffer(*newBuffer);
846 connectBufferView(wa->bufferView());
847 setCurrentWorkArea(wa);
853 void GuiView::connectBuffer(Buffer & buf)
855 buf.setGuiDelegate(this);
859 void GuiView::disconnectBuffer()
861 if (d.current_work_area_)
862 d.current_work_area_->bufferView().setGuiDelegate(0);
866 void GuiView::connectBufferView(BufferView & bv)
868 bv.setGuiDelegate(this);
872 void GuiView::disconnectBufferView()
874 if (d.current_work_area_)
875 d.current_work_area_->bufferView().setGuiDelegate(0);
879 void GuiView::errors(string const & error_type)
881 ErrorList & el = buffer()->errorList(error_type);
883 showDialog("errorlist", error_type);
887 void GuiView::updateDialog(string const & name, string const & data)
889 if (!isDialogVisible(name))
892 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
893 if (it == d.dialogs_.end())
896 Dialog * const dialog = it->second.get();
897 if (dialog->isVisibleView())
898 dialog->updateData(data);
902 BufferView * GuiView::view()
904 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
908 void GuiView::updateToc()
910 updateDialog("toc", "");
914 void GuiView::updateEmbeddedFiles()
916 updateDialog("embedding", "");
920 void GuiView::autoSave()
922 LYXERR(Debug::INFO, "Running autoSave()");
925 view()->buffer().autoSave();
929 void GuiView::resetAutosaveTimers()
932 d.autosave_timeout_.restart();
936 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
940 Buffer * buf = buffer();
942 /* In LyX/Mac, when a dialog is open, the menus of the
943 application can still be accessed without giving focus to
944 the main window. In this case, we want to disable the menu
945 entries that are buffer-related.
947 Note that this code is not perfect, as bug 1941 attests:
948 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
950 if (cmd.origin == FuncRequest::MENU && !hasFocus())
954 case LFUN_TOOLBAR_TOGGLE:
955 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
958 case LFUN_DIALOG_TOGGLE:
959 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
960 // fall through to set "enable"
961 case LFUN_DIALOG_SHOW: {
962 string const name = cmd.getArg(0);
964 enable = name == "aboutlyx"
965 || name == "file" //FIXME: should be removed.
967 || name == "texinfo";
968 else if (name == "print")
969 enable = buf->isExportable("dvi")
970 && lyxrc.print_command != "none";
971 else if (name == "character") {
975 InsetCode ic = view()->cursor().inset().lyxCode();
976 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
979 else if (name == "latexlog")
980 enable = FileName(buf->logName()).isFileReadable();
981 else if (name == "spellchecker")
982 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
983 enable = !buf->isReadonly();
987 else if (name == "vclog")
988 enable = buf->lyxvc().inUse();
992 case LFUN_DIALOG_UPDATE: {
993 string const name = cmd.getArg(0);
995 enable = name == "prefs";
1007 flag.enabled(false);
1013 void GuiView::dispatch(FuncRequest const & cmd)
1015 Buffer * buf = buffer();
1016 switch(cmd.action) {
1017 case LFUN_BUFFER_SWITCH:
1018 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1021 case LFUN_COMMAND_EXECUTE: {
1022 bool const show_it = cmd.argument() != "off";
1023 d.toolbars_->showCommandBuffer(show_it);
1026 case LFUN_DROP_LAYOUTS_CHOICE:
1028 d.layout_->showPopup();
1031 case LFUN_MENU_OPEN:
1032 d.menubar_->openByName(toqstr(cmd.argument()));
1035 case LFUN_TOOLBAR_TOGGLE: {
1036 string const name = cmd.getArg(0);
1037 bool const allowauto = cmd.getArg(1) == "allowauto";
1038 // it is possible to get current toolbar status like this,...
1039 // but I decide to obey the order of ToolbarBackend::flags
1040 // and disregard real toolbar status.
1041 // toolbars_->saveToolbarInfo();
1043 // toggle state on/off/auto
1044 d.toolbars_->toggleToolbarState(name, allowauto);
1048 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1050 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1054 if (tbi->flags & ToolbarInfo::ON)
1056 else if (tbi->flags & ToolbarInfo::OFF)
1058 else if (tbi->flags & ToolbarInfo::AUTO)
1061 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1062 _(tbi->gui_name), state));
1066 case LFUN_DIALOG_UPDATE: {
1067 string const name = to_utf8(cmd.argument());
1068 // Can only update a dialog connected to an existing inset
1069 Inset * inset = getOpenInset(name);
1071 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1072 inset->dispatch(view()->cursor(), fr);
1073 } else if (name == "paragraph") {
1074 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1075 } else if (name == "prefs") {
1076 updateDialog(name, string());
1081 case LFUN_DIALOG_TOGGLE: {
1082 if (isDialogVisible(cmd.getArg(0)))
1083 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1085 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1089 case LFUN_DIALOG_DISCONNECT_INSET:
1090 disconnectDialog(to_utf8(cmd.argument()));
1093 case LFUN_DIALOG_HIDE: {
1096 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1100 case LFUN_DIALOG_SHOW: {
1101 string const name = cmd.getArg(0);
1102 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1104 if (name == "character") {
1105 data = freefont2string();
1107 showDialog("character", data);
1108 } else if (name == "latexlog") {
1109 Buffer::LogType type;
1110 string const logfile = buf->logName(&type);
1112 case Buffer::latexlog:
1115 case Buffer::buildlog:
1119 data += Lexer::quoteString(logfile);
1120 showDialog("log", data);
1121 } else if (name == "vclog") {
1122 string const data = "vc " +
1123 Lexer::quoteString(buf->lyxvc().getLogFile());
1124 showDialog("log", data);
1126 showDialog(name, data);
1131 theLyXFunc().setLyXView(this);
1137 Buffer const * GuiView::updateInset(Inset const * inset)
1139 if (!d.current_work_area_)
1143 d.current_work_area_->scheduleRedraw();
1145 return &d.current_work_area_->bufferView().buffer();
1149 void GuiView::restartCursor()
1151 /* When we move around, or type, it's nice to be able to see
1152 * the cursor immediately after the keypress.
1154 if (d.current_work_area_)
1155 d.current_work_area_->startBlinkingCursor();
1157 // Take this occasion to update the toobars and layout list.
1164 // This list should be kept in sync with the list of insets in
1165 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1166 // dialog should have the same name as the inset.
1168 char const * const dialognames[] = {
1169 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1170 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1171 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1172 "mathdelimiter", "mathmatrix", "note", "paragraph",
1173 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1175 #ifdef HAVE_LIBAIKSAURUS
1179 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1181 char const * const * const end_dialognames =
1182 dialognames + (sizeof(dialognames) / sizeof(char *));
1186 cmpCStr(char const * name) : name_(name) {}
1187 bool operator()(char const * other) {
1188 return strcmp(other, name_) == 0;
1195 bool isValidName(string const & name)
1197 return std::find_if(dialognames, end_dialognames,
1198 cmpCStr(name.c_str())) != end_dialognames;
1204 void GuiView::resetDialogs()
1206 // Make sure that no LFUN uses any LyXView.
1207 theLyXFunc().setLyXView(0);
1208 d.toolbars_->init();
1211 d.layout_->updateContents(true);
1212 // Now update controls with current buffer.
1213 theLyXFunc().setLyXView(this);
1218 Dialog * GuiView::find_or_build(string const & name)
1220 if (!isValidName(name))
1223 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1225 if (it != d.dialogs_.end())
1226 return it->second.get();
1228 d.dialogs_[name].reset(build(name));
1229 return d.dialogs_[name].get();
1233 void GuiView::showDialog(string const & name, string const & data,
1240 Dialog * dialog = find_or_build(name);
1242 dialog->showData(data);
1244 d.open_insets_[name] = inset;
1250 bool GuiView::isDialogVisible(string const & name) const
1252 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1253 if (it == d.dialogs_.end())
1255 return it->second.get()->isVisibleView();
1259 void GuiView::hideDialog(string const & name, Inset * inset)
1261 // Don't send the signal if we are quitting, because on MSVC it is
1262 // destructed before the cut stack in CutAndPaste.cpp, and this method
1263 // is called from some inset destructor if the cut stack is not empty
1268 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1269 if (it == d.dialogs_.end())
1272 if (inset && inset != getOpenInset(name))
1275 Dialog * const dialog = it->second.get();
1276 if (dialog->isVisibleView())
1278 d.open_insets_[name] = 0;
1282 void GuiView::disconnectDialog(string const & name)
1284 if (!isValidName(name))
1287 if (d.open_insets_.find(name) != d.open_insets_.end())
1288 d.open_insets_[name] = 0;
1292 Inset * GuiView::getOpenInset(string const & name) const
1294 if (!isValidName(name))
1297 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1298 return it == d.open_insets_.end() ? 0 : it->second;
1302 void GuiView::hideAll() const
1304 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1305 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1307 for(; it != end; ++it)
1312 void GuiView::hideBufferDependent() const
1314 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1315 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1317 for(; it != end; ++it) {
1318 Dialog * dialog = it->second.get();
1319 if (dialog->isBufferDependent())
1325 void GuiView::updateBufferDependent(bool switched) const
1327 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1328 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1330 for(; it != end; ++it) {
1331 Dialog * dialog = it->second.get();
1332 if (switched && dialog->isBufferDependent()) {
1333 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1334 dialog->updateView();
1338 // A bit clunky, but the dialog will request
1339 // that the kernel provides it with the necessary
1341 dialog->updateDialog(dialog->name());
1347 void GuiView::checkStatus()
1349 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1350 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1352 for(; it != end; ++it) {
1353 Dialog * const dialog = it->second.get();
1354 if (dialog && dialog->isVisibleView())
1355 dialog->checkStatus();
1361 // will be replaced by a proper factory...
1362 Dialog * createGuiAbout(LyXView & lv);
1363 Dialog * createGuiBibitem(LyXView & lv);
1364 Dialog * createGuiBibtex(LyXView & lv);
1365 Dialog * createGuiBox(LyXView & lv);
1366 Dialog * createGuiBranch(LyXView & lv);
1367 Dialog * createGuiChanges(LyXView & lv);
1368 Dialog * createGuiCharacter(LyXView & lv);
1369 Dialog * createGuiCitation(LyXView & lv);
1370 Dialog * createGuiDelimiter(LyXView & lv);
1371 Dialog * createGuiDocument(LyXView & lv);
1372 Dialog * createGuiErrorList(LyXView & lv);
1373 Dialog * createGuiERT(LyXView & lv);
1374 Dialog * createGuiExternal(LyXView & lv);
1375 Dialog * createGuiFloat(LyXView & lv);
1376 Dialog * createGuiGraphics(LyXView & lv);
1377 Dialog * createGuiInclude(LyXView & lv);
1378 Dialog * createGuiIndex(LyXView & lv);
1379 Dialog * createGuiLabel(LyXView & lv);
1380 Dialog * createGuiListings(LyXView & lv);
1381 Dialog * createGuiLog(LyXView & lv);
1382 Dialog * createGuiMathMatrix(LyXView & lv);
1383 Dialog * createGuiNomenclature(LyXView & lv);
1384 Dialog * createGuiNote(LyXView & lv);
1385 Dialog * createGuiParagraph(LyXView & lv);
1386 Dialog * createGuiPreferences(LyXView & lv);
1387 Dialog * createGuiPrint(LyXView & lv);
1388 Dialog * createGuiRef(LyXView & lv);
1389 Dialog * createGuiSearch(LyXView & lv);
1390 Dialog * createGuiSendTo(LyXView & lv);
1391 Dialog * createGuiShowFile(LyXView & lv);
1392 Dialog * createGuiSpellchecker(LyXView & lv);
1393 Dialog * createGuiTabularCreate(LyXView & lv);
1394 Dialog * createGuiTabular(LyXView & lv);
1395 Dialog * createGuiTexInfo(LyXView & lv);
1396 Dialog * createGuiToc(LyXView & lv);
1397 Dialog * createGuiThesaurus(LyXView & lv);
1398 Dialog * createGuiHyperlink(LyXView & lv);
1399 Dialog * createGuiVSpace(LyXView & lv);
1400 Dialog * createGuiViewSource(LyXView & lv);
1401 Dialog * createGuiWrap(LyXView & lv);
1404 Dialog * GuiView::build(string const & name)
1406 BOOST_ASSERT(isValidName(name));
1408 if (name == "aboutlyx")
1409 return createGuiAbout(*this);
1410 if (name == "bibitem")
1411 return createGuiBibitem(*this);
1412 if (name == "bibtex")
1413 return createGuiBibtex(*this);
1415 return createGuiBox(*this);
1416 if (name == "branch")
1417 return createGuiBranch(*this);
1418 if (name == "changes")
1419 return createGuiChanges(*this);
1420 if (name == "character")
1421 return createGuiCharacter(*this);
1422 if (name == "citation")
1423 return createGuiCitation(*this);
1424 if (name == "document")
1425 return createGuiDocument(*this);
1426 if (name == "errorlist")
1427 return createGuiErrorList(*this);
1429 return createGuiERT(*this);
1430 if (name == "external")
1431 return createGuiExternal(*this);
1433 return createGuiShowFile(*this);
1434 if (name == "findreplace")
1435 return createGuiSearch(*this);
1436 if (name == "float")
1437 return createGuiFloat(*this);
1438 if (name == "graphics")
1439 return createGuiGraphics(*this);
1440 if (name == "include")
1441 return createGuiInclude(*this);
1442 if (name == "index")
1443 return createGuiIndex(*this);
1444 if (name == "nomenclature")
1445 return createGuiNomenclature(*this);
1446 if (name == "label")
1447 return createGuiLabel(*this);
1449 return createGuiLog(*this);
1450 if (name == "view-source")
1451 return createGuiViewSource(*this);
1452 if (name == "mathdelimiter")
1453 return createGuiDelimiter(*this);
1454 if (name == "mathmatrix")
1455 return createGuiMathMatrix(*this);
1457 return createGuiNote(*this);
1458 if (name == "paragraph")
1459 return createGuiParagraph(*this);
1460 if (name == "prefs")
1461 return createGuiPreferences(*this);
1462 if (name == "print")
1463 return createGuiPrint(*this);
1465 return createGuiRef(*this);
1466 if (name == "sendto")
1467 return createGuiSendTo(*this);
1468 if (name == "spellchecker")
1469 return createGuiSpellchecker(*this);
1470 if (name == "tabular")
1471 return createGuiTabular(*this);
1472 if (name == "tabularcreate")
1473 return createGuiTabularCreate(*this);
1474 if (name == "texinfo")
1475 return createGuiTexInfo(*this);
1476 #ifdef HAVE_LIBAIKSAURUS
1477 if (name == "thesaurus")
1478 return createGuiThesaurus(*this);
1481 return createGuiToc(*this);
1483 return createGuiHyperlink(*this);
1484 if (name == "vspace")
1485 return createGuiVSpace(*this);
1487 return createGuiWrap(*this);
1488 if (name == "listings")
1489 return createGuiListings(*this);
1495 } // namespace frontend
1498 #include "GuiView_moc.cpp"