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 int const statusbar_timer_value = 3000;
113 class BackgroundWidget : public QWidget
116 BackgroundWidget(QString const & file, QString const & text)
118 splash_ = new QPixmap(file);
120 lyxerr << "could not load splash screen: '" << fromqstr(file) << "'" << endl;
124 QPainter pain(splash_);
125 pain.setPen(QColor(255, 255, 0));
127 // The font used to display the version info
128 font.setStyleHint(QFont::SansSerif);
129 font.setWeight(QFont::Bold);
130 font.setPointSize(convert<int>(lyxrc.font_sizes[FONT_SIZE_LARGE]));
132 pain.drawText(260, 270, text);
135 void paintEvent(QPaintEvent *)
140 int x = (width() - splash_->width()) / 2;
141 int y = (height() - splash_->height()) / 2;
143 pain.drawPixmap(x, y, *splash_);
153 typedef boost::shared_ptr<Dialog> DialogPtr;
155 struct GuiView::GuiViewPrivate
158 : current_work_area_(0), posx_offset(0), posy_offset(0),
159 autosave_timeout_(new Timeout(5000)), quitting_by_menu_(false),
162 // hardcode here the platform specific icon size
163 smallIconSize = 14; // scaling problems
164 normalIconSize = 20; // ok, default
165 bigIconSize = 26; // better for some math icons
167 splitter_ = new QSplitter;
169 stack_widget_ = new QStackedWidget;
170 stack_widget_->addWidget(bg_widget_);
171 stack_widget_->addWidget(splitter_);
179 delete stack_widget_;
182 delete autosave_timeout_;
185 QMenu * toolBarPopup(GuiView * parent)
187 // FIXME: translation
188 QMenu * menu = new QMenu(parent);
189 QActionGroup * iconSizeGroup = new QActionGroup(parent);
191 QAction * smallIcons = new QAction(iconSizeGroup);
192 smallIcons->setText(qt_("Small-sized icons"));
193 smallIcons->setCheckable(true);
194 QObject::connect(smallIcons, SIGNAL(triggered()),
195 parent, SLOT(smallSizedIcons()));
196 menu->addAction(smallIcons);
198 QAction * normalIcons = new QAction(iconSizeGroup);
199 normalIcons->setText(qt_("Normal-sized icons"));
200 normalIcons->setCheckable(true);
201 QObject::connect(normalIcons, SIGNAL(triggered()),
202 parent, SLOT(normalSizedIcons()));
203 menu->addAction(normalIcons);
205 QAction * bigIcons = new QAction(iconSizeGroup);
206 bigIcons->setText(qt_("Big-sized icons"));
207 bigIcons->setCheckable(true);
208 QObject::connect(bigIcons, SIGNAL(triggered()),
209 parent, SLOT(bigSizedIcons()));
210 menu->addAction(bigIcons);
212 unsigned int cur = parent->iconSize().width();
213 if ( cur == parent->d.smallIconSize)
214 smallIcons->setChecked(true);
215 else if (cur == parent->d.normalIconSize)
216 normalIcons->setChecked(true);
217 else if (cur == parent->d.bigIconSize)
218 bigIcons->setChecked(true);
223 void initBackground()
225 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
226 /// The text to be written on top of the pixmap
227 QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
228 bg_widget_ = new BackgroundWidget(":/images/banner.png", text);
233 stack_widget_->setCurrentWidget(bg_widget_);
234 bg_widget_->setUpdatesEnabled(true);
237 TabWorkArea * tabWorkArea(int i)
239 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
242 TabWorkArea * currentTabWorkArea()
244 if (splitter_->count() == 1)
245 // The first TabWorkArea is always the first one, if any.
246 return tabWorkArea(0);
248 TabWorkArea * tab_widget = 0;
249 for (int i = 0; i != splitter_->count(); ++i) {
250 QWidget * w = splitter_->widget(i);
253 tab_widget = dynamic_cast<TabWorkArea *>(w);
265 GuiWorkArea * current_work_area_;
269 QSplitter * splitter_;
270 QStackedWidget * stack_widget_;
271 BackgroundWidget * bg_widget_;
273 GuiMenubar * menubar_;
275 GuiToolbars * toolbars_;
277 docstring current_layout;
280 std::map<std::string, Inset *> open_insets_;
283 std::map<std::string, DialogPtr> dialogs_;
285 unsigned int smallIconSize;
286 unsigned int normalIconSize;
287 unsigned int bigIconSize;
289 QTimer statusbar_timer_;
290 /// are we quitting by the menu?
291 bool quitting_by_menu_;
292 /// auto-saving of buffers
293 Timeout * const autosave_timeout_;
295 /// flag against a race condition due to multiclicks in Qt frontend,
301 GuiView::GuiView(int id)
302 : d(*new GuiViewPrivate), id_(id)
304 // GuiToolbars *must* be initialised before GuiMenubar.
305 d.toolbars_ = new GuiToolbars(*this);
306 d.menubar_ = new GuiMenubar(this, menubackend);
308 setCentralWidget(d.stack_widget_);
310 // Start autosave timer
311 if (lyxrc.autosave) {
312 d.autosave_timeout_->timeout.connect(boost::bind(&GuiView::autoSave, this));
313 d.autosave_timeout_->setTimeout(lyxrc.autosave * 1000);
314 d.autosave_timeout_->start();
316 QObject::connect(&d.statusbar_timer_, SIGNAL(timeout()),
317 this, SLOT(clearMessage()));
319 // Qt bug? signal lastWindowClosed does not work
320 setAttribute(Qt::WA_QuitOnClose, false);
321 setAttribute(Qt::WA_DeleteOnClose, true);
323 // assign an icon to main form. We do not do it under Qt/Mac,
324 // since the icon is provided in the application bundle.
325 setWindowIcon(QPixmap(":/images/lyx.png"));
329 setAcceptDrops(true);
331 statusBar()->setSizeGripEnabled(true);
333 // Forbid too small unresizable window because it can happen
334 // with some window manager under X11.
335 setMinimumSize(300, 200);
337 if (!lyxrc.allow_geometry_session)
338 // No session handling, default to a sane size.
339 setGeometry(50, 50, 690, 510);
341 // Now take care of session management.
343 QString const key = "view-" + QString::number(id_);
345 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
346 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
350 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
351 setGeometry(50, 50, 690, 510);
353 setIconSize(settings.value(key + "/icon_size").toSize());
363 void GuiView::close()
365 d.quitting_by_menu_ = true;
366 d.current_work_area_ = 0;
367 for (int i = 0; i != d.splitter_->count(); ++i) {
368 TabWorkArea * twa = d.tabWorkArea(i);
372 QMainWindow::close();
373 d.quitting_by_menu_ = false;
377 void GuiView::setFocus()
379 if (d.current_work_area_)
380 d.current_work_area_->setFocus();
386 QMenu* GuiView::createPopupMenu()
388 return d.toolBarPopup(this);
392 void GuiView::showEvent(QShowEvent * e)
394 LYXERR(Debug::GUI, "Passed Geometry "
395 << size().height() << "x" << size().width()
396 << "+" << pos().x() << "+" << pos().y());
398 if (d.splitter_->count() == 0)
399 // No work area, switch to the background widget.
402 QMainWindow::showEvent(e);
406 void GuiView::closeEvent(QCloseEvent * close_event)
408 // we may have been called through the close window button
409 // which bypasses the LFUN machinery.
410 if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
411 if (!theBufferList().quitWriteAll()) {
412 close_event->ignore();
417 // Make sure that no LFUN use this close to be closed View.
418 theLyXFunc().setLyXView(0);
419 // Make sure the timer time out will not trigger a statusbar update.
420 d.statusbar_timer_.stop();
422 if (lyxrc.allow_geometry_session) {
424 QString const key = "view-" + QString::number(id_);
426 settings.setValue(key + "/pos", pos());
427 settings.setValue(key + "/size", size());
429 settings.setValue(key + "/geometry", saveGeometry());
431 settings.setValue(key + "/icon_size", iconSize());
432 d.toolbars_->saveToolbarInfo();
435 guiApp->unregisterView(id_);
436 if (guiApp->viewCount() > 0) {
437 // Just close the window and do nothing else if this is not the
439 close_event->accept();
445 // this is the place where we leave the frontend.
446 // it is the only point at which we start quitting.
447 close_event->accept();
448 // quit the event loop
453 void GuiView::dragEnterEvent(QDragEnterEvent * event)
455 if (event->mimeData()->hasUrls())
457 /// \todo Ask lyx-devel is this is enough:
458 /// if (event->mimeData()->hasFormat("text/plain"))
459 /// event->acceptProposedAction();
463 void GuiView::dropEvent(QDropEvent* event)
465 QList<QUrl> files = event->mimeData()->urls();
469 LYXERR(Debug::GUI, BOOST_CURRENT_FUNCTION << " got URLs!");
470 for (int i = 0; i != files.size(); ++i) {
471 string const file = support::os::internal_path(fromqstr(
472 files.at(i).toLocalFile()));
474 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
479 void GuiView::message(docstring const & str)
481 statusBar()->showMessage(toqstr(str));
482 d.statusbar_timer_.stop();
483 d.statusbar_timer_.start(statusbar_timer_value);
487 void GuiView::smallSizedIcons()
489 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
493 void GuiView::normalSizedIcons()
495 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
499 void GuiView::bigSizedIcons()
501 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
505 void GuiView::clearMessage()
509 theLyXFunc().setLyXView(this);
510 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
511 d.statusbar_timer_.stop();
515 void GuiView::updateWindowTitle(GuiWorkArea * wa)
517 if (wa != d.current_work_area_)
519 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
520 setWindowIconText(wa->windowIconText());
524 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
527 disconnectBufferView();
528 connectBufferView(wa->bufferView());
529 connectBuffer(wa->bufferView().buffer());
530 d.current_work_area_ = wa;
531 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
532 this, SLOT(updateWindowTitle(GuiWorkArea *)));
533 updateWindowTitle(wa);
536 // Buffer-dependent dialogs should be updated or
537 // hidden. This should go here because some dialogs (eg ToC)
538 // require bv_->text.
539 updateBufferDependent(true);
541 updateLayoutChoice(false);
546 void GuiView::updateStatusBar()
548 // let the user see the explicit message
549 if (d.statusbar_timer_.isActive())
552 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
556 bool GuiView::hasFocus() const
558 return qApp->activeWindow() == this;
562 bool GuiView::event(QEvent * e)
566 // Useful debug code:
567 //case QEvent::ActivationChange:
568 //case QEvent::WindowDeactivate:
569 //case QEvent::Paint:
570 //case QEvent::Enter:
571 //case QEvent::Leave:
572 //case QEvent::HoverEnter:
573 //case QEvent::HoverLeave:
574 //case QEvent::HoverMove:
575 //case QEvent::StatusTip:
576 //case QEvent::DragEnter:
577 //case QEvent::DragLeave:
581 case QEvent::WindowActivate: {
582 guiApp->setCurrentView(*this);
583 if (d.current_work_area_) {
584 BufferView & bv = d.current_work_area_->bufferView();
585 connectBufferView(bv);
586 connectBuffer(bv.buffer());
587 // The document structure, name and dialogs might have
588 // changed in another view.
589 updateBufferDependent(true);
591 setWindowTitle(qt_("LyX"));
592 setWindowIconText(qt_("LyX"));
594 return QMainWindow::event(e);
596 case QEvent::ShortcutOverride: {
597 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
598 if (!d.current_work_area_) {
599 theLyXFunc().setLyXView(this);
601 setKeySymbol(&sym, ke);
602 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
606 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
608 setKeySymbol(&sym, ke);
609 d.current_work_area_->processKeySym(sym, NoModifier);
615 return QMainWindow::event(e);
620 bool GuiView::focusNextPrevChild(bool /*next*/)
627 void GuiView::setBusy(bool yes)
629 if (d.current_work_area_) {
630 d.current_work_area_->setUpdatesEnabled(!yes);
632 d.current_work_area_->stopBlinkingCursor();
634 d.current_work_area_->startBlinkingCursor();
638 QApplication::setOverrideCursor(Qt::WaitCursor);
640 QApplication::restoreOverrideCursor();
644 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
646 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
648 if (tbinfo.flags & ToolbarInfo::TOP) {
650 addToolBarBreak(Qt::TopToolBarArea);
651 addToolBar(Qt::TopToolBarArea, toolBar);
654 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
655 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
656 #if (QT_VERSION >= 0x040202)
658 addToolBarBreak(Qt::BottomToolBarArea);
660 addToolBar(Qt::BottomToolBarArea, toolBar);
663 if (tbinfo.flags & ToolbarInfo::LEFT) {
664 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
665 #if (QT_VERSION >= 0x040202)
667 addToolBarBreak(Qt::LeftToolBarArea);
669 addToolBar(Qt::LeftToolBarArea, toolBar);
672 if (tbinfo.flags & ToolbarInfo::RIGHT) {
673 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
674 #if (QT_VERSION >= 0x040202)
676 addToolBarBreak(Qt::RightToolBarArea);
678 addToolBar(Qt::RightToolBarArea, toolBar);
681 // The following does not work so I cannot restore to exact toolbar location
683 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
684 toolBar->move(tbinfo.posx, tbinfo.posy);
691 GuiWorkArea * GuiView::workArea(Buffer & buffer)
693 for (int i = 0; i != d.splitter_->count(); ++i) {
694 GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
702 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
705 // Automatically create a TabWorkArea if there are none yet.
706 if (!d.splitter_->count())
709 TabWorkArea * tab_widget = d.currentTabWorkArea();
710 return tab_widget->addWorkArea(buffer, *this);
714 void GuiView::addTabWorkArea()
716 TabWorkArea * twa = new TabWorkArea;
717 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
718 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
719 d.splitter_->addWidget(twa);
720 d.stack_widget_->setCurrentWidget(d.splitter_);
724 GuiWorkArea const * GuiView::currentWorkArea() const
726 return d.current_work_area_;
730 void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
732 BOOST_ASSERT(work_area);
734 // Changing work area can result from opening a file so
735 // update the toc in any case.
738 GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
739 d.current_work_area_ = wa;
740 for (int i = 0; i != d.splitter_->count(); ++i) {
741 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
747 void GuiView::removeWorkArea(GuiWorkArea * work_area)
749 BOOST_ASSERT(work_area);
750 GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
751 if (gwa == d.current_work_area_) {
753 disconnectBufferView();
754 hideBufferDependent();
755 d.current_work_area_ = 0;
758 // removing a work area often results from closing a file so
759 // update the toc in any case.
762 for (int i = 0; i != d.splitter_->count(); ++i) {
763 TabWorkArea * twa = d.tabWorkArea(i);
764 if (!twa->removeWorkArea(gwa))
765 // Not found in this tab group.
768 // We found and removed the GuiWorkArea.
770 // No more WorkAreas in this tab group, so delete it.
775 if (d.current_work_area_)
776 // This means that we are not closing the current GuiWorkArea;
779 // Switch to the next GuiWorkArea in the found TabWorkArea.
780 d.current_work_area_ = twa->currentWorkArea();
784 if (d.splitter_->count() == 0)
785 // No more work area, switch to the background widget.
790 void GuiView::updateLayoutChoice(bool force)
792 // Don't show any layouts without a buffer
794 d.toolbars_->clearLayoutList();
798 // Update the layout display
799 if (d.toolbars_->updateLayoutList(buffer()->params().getTextClassPtr(), force)) {
800 d.current_layout = buffer()->params().getTextClass().defaultLayoutName();
803 docstring const & layout = d.current_work_area_->bufferView().cursor().
804 innerParagraph().layout()->name();
806 if (layout != d.current_layout) {
807 d.toolbars_->setLayout(layout);
808 d.current_layout = layout;
813 void GuiView::updateToolbars()
815 if (d.current_work_area_) {
817 d.current_work_area_->bufferView().cursor().inMathed();
819 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
821 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
822 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
824 d.toolbars_->update(math, table, review);
826 d.toolbars_->update(false, false, false);
828 // update read-only status of open dialogs.
833 Buffer * GuiView::buffer()
835 if (d.current_work_area_)
836 return &d.current_work_area_->bufferView().buffer();
841 Buffer const * GuiView::buffer() const
843 if (d.current_work_area_)
844 return &d.current_work_area_->bufferView().buffer();
849 void GuiView::setBuffer(Buffer * newBuffer)
851 BOOST_ASSERT(newBuffer);
854 GuiWorkArea * wa = workArea(*newBuffer);
856 updateLabels(*newBuffer->masterBuffer());
857 wa = addWorkArea(*newBuffer);
859 //Disconnect the old buffer...there's no new one.
862 connectBuffer(*newBuffer);
863 connectBufferView(wa->bufferView());
864 setCurrentWorkArea(wa);
870 void GuiView::connectBuffer(Buffer & buf)
872 buf.setGuiDelegate(this);
876 void GuiView::disconnectBuffer()
878 if (d.current_work_area_)
879 d.current_work_area_->bufferView().setGuiDelegate(0);
883 void GuiView::connectBufferView(BufferView & bv)
885 bv.setGuiDelegate(this);
889 void GuiView::disconnectBufferView()
891 if (d.current_work_area_)
892 d.current_work_area_->bufferView().setGuiDelegate(0);
896 void GuiView::errors(string const & error_type)
898 ErrorList & el = buffer()->errorList(error_type);
900 showDialog("errorlist", error_type);
904 void GuiView::updateDialog(string const & name, string const & data)
906 if (!isDialogVisible(name))
909 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
910 if (it == d.dialogs_.end())
913 Dialog * const dialog = it->second.get();
914 if (dialog->isVisibleView())
915 dialog->updateData(data);
919 BufferView * GuiView::view()
921 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
925 void GuiView::updateToc()
927 updateDialog("toc", "");
931 void GuiView::updateEmbeddedFiles()
933 updateDialog("embedding", "");
937 void GuiView::autoSave()
939 LYXERR(Debug::INFO, "Running autoSave()");
942 view()->buffer().autoSave();
946 void GuiView::resetAutosaveTimers()
949 d.autosave_timeout_->restart();
953 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
957 Buffer * buf = buffer();
960 case LFUN_TOOLBAR_TOGGLE:
961 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
964 case LFUN_DIALOG_TOGGLE:
965 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
966 // fall through to set "enable"
967 case LFUN_DIALOG_SHOW: {
968 string const name = cmd.getArg(0);
970 enable = name == "aboutlyx"
971 || name == "file" //FIXME: should be removed.
973 || name == "texinfo";
974 else if (name == "print")
975 enable = buf->isExportable("dvi")
976 && lyxrc.print_command != "none";
977 else if (name == "character") {
981 InsetCode ic = view()->cursor().inset().lyxCode();
982 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
985 else if (name == "latexlog")
986 enable = FileName(buf->logName()).isFileReadable();
987 else if (name == "spellchecker")
988 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
989 enable = !buf->isReadonly();
993 else if (name == "vclog")
994 enable = buf->lyxvc().inUse();
998 case LFUN_DIALOG_UPDATE: {
999 string const name = cmd.getArg(0);
1001 enable = name == "prefs";
1013 flag.enabled(false);
1019 void GuiView::dispatch(FuncRequest const & cmd)
1021 Buffer * buf = buffer();
1022 switch(cmd.action) {
1023 case LFUN_BUFFER_SWITCH:
1024 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1027 case LFUN_COMMAND_EXECUTE: {
1028 bool const show_it = cmd.argument() != "off";
1029 d.toolbars_->showCommandBuffer(show_it);
1032 case LFUN_DROP_LAYOUTS_CHOICE:
1033 d.toolbars_->openLayoutList();
1036 case LFUN_MENU_OPEN:
1037 d.menubar_->openByName(toqstr(cmd.argument()));
1040 case LFUN_TOOLBAR_TOGGLE: {
1041 string const name = cmd.getArg(0);
1042 bool const allowauto = cmd.getArg(1) == "allowauto";
1043 // it is possible to get current toolbar status like this,...
1044 // but I decide to obey the order of ToolbarBackend::flags
1045 // and disregard real toolbar status.
1046 // toolbars_->saveToolbarInfo();
1048 // toggle state on/off/auto
1049 d.toolbars_->toggleToolbarState(name, allowauto);
1053 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1055 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1059 if (tbi->flags & ToolbarInfo::ON)
1061 else if (tbi->flags & ToolbarInfo::OFF)
1063 else if (tbi->flags & ToolbarInfo::AUTO)
1066 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1067 _(tbi->gui_name), state));
1071 case LFUN_DIALOG_UPDATE: {
1072 string const name = to_utf8(cmd.argument());
1073 // Can only update a dialog connected to an existing inset
1074 Inset * inset = getOpenInset(name);
1076 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1077 inset->dispatch(view()->cursor(), fr);
1078 } else if (name == "paragraph") {
1079 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1080 } else if (name == "prefs") {
1081 updateDialog(name, string());
1086 case LFUN_DIALOG_TOGGLE: {
1087 if (isDialogVisible(cmd.getArg(0)))
1088 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1090 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1094 case LFUN_DIALOG_DISCONNECT_INSET:
1095 disconnectDialog(to_utf8(cmd.argument()));
1098 case LFUN_DIALOG_HIDE: {
1101 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1105 case LFUN_DIALOG_SHOW: {
1106 string const name = cmd.getArg(0);
1107 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1109 if (name == "character") {
1110 data = freefont2string();
1112 showDialog("character", data);
1113 } else if (name == "latexlog") {
1114 Buffer::LogType type;
1115 string const logfile = buf->logName(&type);
1117 case Buffer::latexlog:
1120 case Buffer::buildlog:
1124 data += Lexer::quoteString(logfile);
1125 showDialog("log", data);
1126 } else if (name == "vclog") {
1127 string const data = "vc " +
1128 Lexer::quoteString(buf->lyxvc().getLogFile());
1129 showDialog("log", data);
1131 showDialog(name, data);
1136 theLyXFunc().setLyXView(this);
1142 Buffer const * GuiView::updateInset(Inset const * inset)
1144 if (!d.current_work_area_)
1148 d.current_work_area_->scheduleRedraw();
1150 return &d.current_work_area_->bufferView().buffer();
1154 void GuiView::restartCursor()
1156 /* When we move around, or type, it's nice to be able to see
1157 * the cursor immediately after the keypress.
1159 if (d.current_work_area_)
1160 d.current_work_area_->startBlinkingCursor();
1165 // This list should be kept in sync with the list of insets in
1166 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1167 // dialog should have the same name as the inset.
1169 char const * const dialognames[] = {
1170 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1171 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1172 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1173 "mathdelimiter", "mathmatrix", "note", "paragraph",
1174 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1176 #ifdef HAVE_LIBAIKSAURUS
1180 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1182 char const * const * const end_dialognames =
1183 dialognames + (sizeof(dialognames) / sizeof(char *));
1187 cmpCStr(char const * name) : name_(name) {}
1188 bool operator()(char const * other) {
1189 return strcmp(other, name_) == 0;
1196 bool isValidName(string const & name)
1198 return std::find_if(dialognames, end_dialognames,
1199 cmpCStr(name.c_str())) != end_dialognames;
1205 Dialog * GuiView::find_or_build(string const & name)
1207 if (!isValidName(name))
1210 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1212 if (it != d.dialogs_.end())
1213 return it->second.get();
1215 d.dialogs_[name].reset(build(name));
1216 return d.dialogs_[name].get();
1220 void GuiView::showDialog(string const & name, string const & data,
1227 Dialog * dialog = find_or_build(name);
1229 dialog->showData(data);
1231 d.open_insets_[name] = inset;
1237 bool GuiView::isDialogVisible(string const & name) const
1239 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1240 if (it == d.dialogs_.end())
1242 return it->second.get()->isVisibleView();
1246 void GuiView::hideDialog(string const & name, Inset * inset)
1248 // Don't send the signal if we are quitting, because on MSVC it is
1249 // destructed before the cut stack in CutAndPaste.cpp, and this method
1250 // is called from some inset destructor if the cut stack is not empty
1255 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1256 if (it == d.dialogs_.end())
1259 if (inset && inset != getOpenInset(name))
1262 Dialog * const dialog = it->second.get();
1263 if (dialog->isVisibleView())
1265 d.open_insets_[name] = 0;
1269 void GuiView::disconnectDialog(string const & name)
1271 if (!isValidName(name))
1274 if (d.open_insets_.find(name) != d.open_insets_.end())
1275 d.open_insets_[name] = 0;
1279 Inset * GuiView::getOpenInset(string const & name) const
1281 if (!isValidName(name))
1284 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1285 return it == d.open_insets_.end() ? 0 : it->second;
1289 void GuiView::hideAll() const
1291 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1292 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1294 for(; it != end; ++it)
1299 void GuiView::hideBufferDependent() const
1301 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1302 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1304 for(; it != end; ++it) {
1305 Dialog * dialog = it->second.get();
1306 if (dialog->isBufferDependent())
1312 void GuiView::updateBufferDependent(bool switched) 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 (switched && dialog->isBufferDependent()) {
1320 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1321 dialog->updateView();
1325 // A bit clunky, but the dialog will request
1326 // that the kernel provides it with the necessary
1328 dialog->slotRestore();
1334 void GuiView::checkStatus()
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) {
1340 Dialog * const dialog = it->second.get();
1341 if (dialog && dialog->isVisibleView())
1342 dialog->checkStatus();
1348 // will be replaced by a proper factory...
1349 Dialog * createGuiAbout(LyXView & lv);
1350 Dialog * createGuiBibitem(LyXView & lv);
1351 Dialog * createGuiBibtex(LyXView & lv);
1352 Dialog * createGuiBox(LyXView & lv);
1353 Dialog * createGuiBranch(LyXView & lv);
1354 Dialog * createGuiChanges(LyXView & lv);
1355 Dialog * createGuiCharacter(LyXView & lv);
1356 Dialog * createGuiCitation(LyXView & lv);
1357 Dialog * createGuiDelimiter(LyXView & lv);
1358 Dialog * createGuiDocument(LyXView & lv);
1359 Dialog * createGuiErrorList(LyXView & lv);
1360 Dialog * createGuiERT(LyXView & lv);
1361 Dialog * createGuiExternal(LyXView & lv);
1362 Dialog * createGuiFloat(LyXView & lv);
1363 Dialog * createGuiGraphics(LyXView & lv);
1364 Dialog * createGuiInclude(LyXView & lv);
1365 Dialog * createGuiIndex(LyXView & lv);
1366 Dialog * createGuiLabel(LyXView & lv);
1367 Dialog * createGuiListings(LyXView & lv);
1368 Dialog * createGuiLog(LyXView & lv);
1369 Dialog * createGuiMathMatrix(LyXView & lv);
1370 Dialog * createGuiNomenclature(LyXView & lv);
1371 Dialog * createGuiNote(LyXView & lv);
1372 Dialog * createGuiParagraph(LyXView & lv);
1373 Dialog * createGuiPreferences(LyXView & lv);
1374 Dialog * createGuiPrint(LyXView & lv);
1375 Dialog * createGuiRef(LyXView & lv);
1376 Dialog * createGuiSearch(LyXView & lv);
1377 Dialog * createGuiSendTo(LyXView & lv);
1378 Dialog * createGuiShowFile(LyXView & lv);
1379 Dialog * createGuiSpellchecker(LyXView & lv);
1380 Dialog * createGuiTabularCreate(LyXView & lv);
1381 Dialog * createGuiTabular(LyXView & lv);
1382 Dialog * createGuiTexInfo(LyXView & lv);
1383 Dialog * createGuiToc(LyXView & lv);
1384 Dialog * createGuiThesaurus(LyXView & lv);
1385 Dialog * createGuiHyperlink(LyXView & lv);
1386 Dialog * createGuiVSpace(LyXView & lv);
1387 Dialog * createGuiViewSource(LyXView & lv);
1388 Dialog * createGuiWrap(LyXView & lv);
1391 Dialog * GuiView::build(string const & name)
1393 BOOST_ASSERT(isValidName(name));
1395 if (name == "aboutlyx")
1396 return createGuiAbout(*this);
1397 if (name == "bibitem")
1398 return createGuiBibitem(*this);
1399 if (name == "bibtex")
1400 return createGuiBibtex(*this);
1402 return createGuiBox(*this);
1403 if (name == "branch")
1404 return createGuiBranch(*this);
1405 if (name == "changes")
1406 return createGuiChanges(*this);
1407 if (name == "character")
1408 return createGuiCharacter(*this);
1409 if (name == "citation")
1410 return createGuiCitation(*this);
1411 if (name == "document")
1412 return createGuiDocument(*this);
1413 if (name == "errorlist")
1414 return createGuiErrorList(*this);
1416 return createGuiERT(*this);
1417 if (name == "external")
1418 return createGuiExternal(*this);
1420 return createGuiShowFile(*this);
1421 if (name == "findreplace")
1422 return createGuiSearch(*this);
1423 if (name == "float")
1424 return createGuiFloat(*this);
1425 if (name == "graphics")
1426 return createGuiGraphics(*this);
1427 if (name == "include")
1428 return createGuiInclude(*this);
1429 if (name == "index")
1430 return createGuiIndex(*this);
1431 if (name == "nomenclature")
1432 return createGuiNomenclature(*this);
1433 if (name == "label")
1434 return createGuiLabel(*this);
1436 return createGuiLog(*this);
1437 if (name == "view-source")
1438 return createGuiViewSource(*this);
1439 if (name == "mathdelimiter")
1440 return createGuiDelimiter(*this);
1441 if (name == "mathmatrix")
1442 return createGuiMathMatrix(*this);
1444 return createGuiNote(*this);
1445 if (name == "paragraph")
1446 return createGuiParagraph(*this);
1447 if (name == "prefs")
1448 return createGuiPreferences(*this);
1449 if (name == "print")
1450 return createGuiPrint(*this);
1452 return createGuiRef(*this);
1453 if (name == "sendto")
1454 return createGuiSendTo(*this);
1455 if (name == "spellchecker")
1456 return createGuiSpellchecker(*this);
1457 if (name == "tabular")
1458 return createGuiTabular(*this);
1459 if (name == "tabularcreate")
1460 return createGuiTabularCreate(*this);
1461 if (name == "texinfo")
1462 return createGuiTexInfo(*this);
1463 #ifdef HAVE_LIBAIKSAURUS
1464 if (name == "thesaurus")
1465 return createGuiThesaurus(*this);
1468 return createGuiToc(*this);
1470 return createGuiHyperlink(*this);
1471 if (name == "vspace")
1472 return createGuiVSpace(*this);
1474 return createGuiWrap(*this);
1475 if (name == "listings")
1476 return createGuiListings(*this);
1482 } // namespace frontend
1485 #include "GuiView_moc.cpp"