3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "GuiApplication.h"
20 #include "GuiWorkArea.h"
21 #include "GuiKeySymbol.h"
22 #include "GuiMenubar.h"
23 #include "GuiToolbar.h"
24 #include "GuiToolbars.h"
26 #include "qt_helpers.h"
28 #include "buffer_funcs.h"
30 #include "BufferList.h"
31 #include "BufferParams.h"
32 #include "BufferView.h"
35 #include "ErrorList.h"
36 #include "FuncRequest.h"
45 #include "MenuBackend.h"
46 #include "Paragraph.h"
47 #include "TextClass.h"
49 #include "ToolbarBackend.h"
52 #include "support/FileName.h"
53 #include "support/lstrings.h"
54 #include "support/os.h"
55 #include "support/Timeout.h"
58 #include <QApplication>
59 #include <QCloseEvent>
61 #include <QDesktopWidget>
62 #include <QDragEnterEvent>
69 #include <QPushButton>
73 #include <QStackedWidget>
79 #include <boost/assert.hpp>
80 #include <boost/bind.hpp>
82 #ifdef HAVE_SYS_TIME_H
83 # include <sys/time.h>
99 using support::bformat;
100 using support::FileName;
105 class BackgroundWidget : public QWidget
110 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
111 /// The text to be written on top of the pixmap
112 QString const text = lyx_version ? lyx_version : qt_("unknown version");
113 splash_ = QPixmap(":/images/banner.png");
115 QPainter pain(&splash_);
116 pain.setPen(QColor(255, 255, 0));
118 // The font used to display the version info
119 font.setStyleHint(QFont::SansSerif);
120 font.setWeight(QFont::Bold);
121 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
123 pain.drawText(260, 270, text);
126 void paintEvent(QPaintEvent *)
128 int x = (width() - splash_.width()) / 2;
129 int y = (height() - splash_.height()) / 2;
131 pain.drawPixmap(x, y, splash_);
141 typedef boost::shared_ptr<Dialog> DialogPtr;
143 struct GuiView::GuiViewPrivate
146 : current_work_area_(0), layout_(0),
147 quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false)
149 // hardcode here the platform specific icon size
150 smallIconSize = 14; // scaling problems
151 normalIconSize = 20; // ok, default
152 bigIconSize = 26; // better for some math icons
154 splitter_ = new QSplitter;
155 bg_widget_ = new BackgroundWidget;
156 stack_widget_ = new QStackedWidget;
157 stack_widget_->addWidget(bg_widget_);
158 stack_widget_->addWidget(splitter_);
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 * work_area)
710 BOOST_ASSERT(work_area);
712 // Changing work area can result from opening a file so
713 // update the toc in any case.
716 GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
717 d.current_work_area_ = wa;
718 for (int i = 0; i != d.splitter_->count(); ++i) {
719 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
725 void GuiView::removeWorkArea(GuiWorkArea * work_area)
727 BOOST_ASSERT(work_area);
728 GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
729 if (gwa == d.current_work_area_) {
731 disconnectBufferView();
732 hideBufferDependent();
733 d.current_work_area_ = 0;
736 // removing a work area often results from closing a file so
737 // update the toc in any case.
740 for (int i = 0; i != d.splitter_->count(); ++i) {
741 TabWorkArea * twa = d.tabWorkArea(i);
742 if (!twa->removeWorkArea(gwa))
743 // Not found in this tab group.
746 // We found and removed the GuiWorkArea.
748 // No more WorkAreas in this tab group, so delete it.
753 if (d.current_work_area_)
754 // This means that we are not closing the current GuiWorkArea;
757 // Switch to the next GuiWorkArea in the found TabWorkArea.
758 d.current_work_area_ = twa->currentWorkArea();
762 if (d.splitter_->count() == 0)
763 // No more work area, switch to the background widget.
768 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
774 void GuiView::updateLayoutList()
777 d.layout_->updateContents(false);
781 void GuiView::updateToolbars()
783 if (d.current_work_area_) {
785 d.current_work_area_->bufferView().cursor().inMathed();
787 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
789 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
790 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
792 d.toolbars_->update(math, table, review);
794 d.toolbars_->update(false, false, false);
796 // update read-only status of open dialogs.
801 Buffer * GuiView::buffer()
803 if (d.current_work_area_)
804 return &d.current_work_area_->bufferView().buffer();
809 Buffer const * GuiView::buffer() const
811 if (d.current_work_area_)
812 return &d.current_work_area_->bufferView().buffer();
817 void GuiView::setBuffer(Buffer * newBuffer)
819 BOOST_ASSERT(newBuffer);
822 GuiWorkArea * wa = workArea(*newBuffer);
824 updateLabels(*newBuffer->masterBuffer());
825 wa = addWorkArea(*newBuffer);
827 //Disconnect the old buffer...there's no new one.
830 connectBuffer(*newBuffer);
831 connectBufferView(wa->bufferView());
832 setCurrentWorkArea(wa);
838 void GuiView::connectBuffer(Buffer & buf)
840 buf.setGuiDelegate(this);
844 void GuiView::disconnectBuffer()
846 if (d.current_work_area_)
847 d.current_work_area_->bufferView().setGuiDelegate(0);
851 void GuiView::connectBufferView(BufferView & bv)
853 bv.setGuiDelegate(this);
857 void GuiView::disconnectBufferView()
859 if (d.current_work_area_)
860 d.current_work_area_->bufferView().setGuiDelegate(0);
864 void GuiView::errors(string const & error_type)
866 ErrorList & el = buffer()->errorList(error_type);
868 showDialog("errorlist", error_type);
872 void GuiView::updateDialog(string const & name, string const & data)
874 if (!isDialogVisible(name))
877 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
878 if (it == d.dialogs_.end())
881 Dialog * const dialog = it->second.get();
882 if (dialog->isVisibleView())
883 dialog->updateData(data);
887 BufferView * GuiView::view()
889 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
893 void GuiView::updateToc()
895 updateDialog("toc", "");
899 void GuiView::updateEmbeddedFiles()
901 updateDialog("embedding", "");
905 void GuiView::autoSave()
907 LYXERR(Debug::INFO, "Running autoSave()");
910 view()->buffer().autoSave();
914 void GuiView::resetAutosaveTimers()
917 d.autosave_timeout_.restart();
921 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
925 Buffer * buf = buffer();
927 /* In LyX/Mac, when a dialog is open, the menus of the
928 application can still be accessed without giving focus to
929 the main window. In this case, we want to disable the menu
930 entries that are buffer-related.
932 Note that this code is not perfect, as bug 1941 attests:
933 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
935 if (cmd.origin == FuncRequest::MENU && !hasFocus())
939 case LFUN_TOOLBAR_TOGGLE:
940 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
943 case LFUN_DIALOG_TOGGLE:
944 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
945 // fall through to set "enable"
946 case LFUN_DIALOG_SHOW: {
947 string const name = cmd.getArg(0);
949 enable = name == "aboutlyx"
950 || name == "file" //FIXME: should be removed.
952 || name == "texinfo";
953 else if (name == "print")
954 enable = buf->isExportable("dvi")
955 && lyxrc.print_command != "none";
956 else if (name == "character") {
960 InsetCode ic = view()->cursor().inset().lyxCode();
961 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
964 else if (name == "latexlog")
965 enable = FileName(buf->logName()).isReadableFile();
966 else if (name == "spellchecker")
967 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
968 enable = !buf->isReadonly();
972 else if (name == "vclog")
973 enable = buf->lyxvc().inUse();
977 case LFUN_DIALOG_UPDATE: {
978 string const name = cmd.getArg(0);
980 enable = name == "prefs";
984 case LFUN_INSET_APPLY: {
989 string const name = cmd.getArg(0);
990 Inset * inset = getOpenInset(name);
992 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
994 if (!inset->getStatus(view()->cursor(), fr, fs)) {
995 // Every inset is supposed to handle this
1000 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1001 flag |= getStatus(fr);
1003 enable = flag.enabled();
1015 flag.enabled(false);
1021 bool GuiView::dispatch(FuncRequest const & cmd, bool propagate)
1023 BufferView * bv = view();
1024 // By default we won't need any update.
1026 bv->cursor().updateFlags(Update::None);
1028 switch(cmd.action) {
1029 case LFUN_BUFFER_SWITCH:
1030 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1033 case LFUN_BUFFER_NEXT:
1034 setBuffer(theBufferList().next(buffer()));
1037 case LFUN_BUFFER_PREVIOUS:
1038 setBuffer(theBufferList().previous(buffer()));
1041 case LFUN_COMMAND_EXECUTE: {
1042 bool const show_it = cmd.argument() != "off";
1043 d.toolbars_->showCommandBuffer(show_it);
1046 case LFUN_DROP_LAYOUTS_CHOICE:
1048 d.layout_->showPopup();
1051 case LFUN_MENU_OPEN:
1052 d.menubar_->openByName(toqstr(cmd.argument()));
1055 case LFUN_TOOLBAR_TOGGLE: {
1056 string const name = cmd.getArg(0);
1057 bool const allowauto = cmd.getArg(1) == "allowauto";
1058 // it is possible to get current toolbar status like this,...
1059 // but I decide to obey the order of ToolbarBackend::flags
1060 // and disregard real toolbar status.
1061 // toolbars_->saveToolbarInfo();
1063 // toggle state on/off/auto
1064 d.toolbars_->toggleToolbarState(name, allowauto);
1068 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1070 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1074 if (tbi->flags & ToolbarInfo::ON)
1076 else if (tbi->flags & ToolbarInfo::OFF)
1078 else if (tbi->flags & ToolbarInfo::AUTO)
1081 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1082 _(tbi->gui_name), state));
1086 case LFUN_DIALOG_UPDATE: {
1087 string const name = to_utf8(cmd.argument());
1088 // Can only update a dialog connected to an existing inset
1089 Inset * inset = getOpenInset(name);
1091 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1092 inset->dispatch(view()->cursor(), fr);
1093 } else if (name == "paragraph") {
1094 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1095 } else if (name == "prefs") {
1096 updateDialog(name, string());
1101 case LFUN_DIALOG_TOGGLE: {
1102 if (isDialogVisible(cmd.getArg(0)))
1103 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1105 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1109 case LFUN_DIALOG_DISCONNECT_INSET:
1110 disconnectDialog(to_utf8(cmd.argument()));
1113 case LFUN_DIALOG_HIDE: {
1116 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1120 case LFUN_DIALOG_SHOW: {
1121 string const name = cmd.getArg(0);
1122 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1124 if (name == "character") {
1125 data = freefont2string();
1127 showDialog("character", data);
1128 } else if (name == "latexlog") {
1129 Buffer::LogType type;
1130 string const logfile = buffer()->logName(&type);
1132 case Buffer::latexlog:
1135 case Buffer::buildlog:
1139 data += Lexer::quoteString(logfile);
1140 showDialog("log", data);
1141 } else if (name == "vclog") {
1142 string const data = "vc " +
1143 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1144 showDialog("log", data);
1146 showDialog(name, data);
1150 case LFUN_INSET_APPLY: {
1151 string const name = cmd.getArg(0);
1152 Inset * inset = getOpenInset(name);
1154 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1155 inset->dispatch(view()->cursor(), fr);
1157 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1165 theLyXFunc().setLyXView(this);
1172 bv->processUpdateFlags(bv->cursor().result().update());
1173 // We won't need any new update.
1174 bv->cursor().updateFlags(Update::None);
1180 Buffer const * GuiView::updateInset(Inset const * inset)
1182 if (!d.current_work_area_)
1186 d.current_work_area_->scheduleRedraw();
1188 return &d.current_work_area_->bufferView().buffer();
1192 void GuiView::restartCursor()
1194 /* When we move around, or type, it's nice to be able to see
1195 * the cursor immediately after the keypress.
1197 if (d.current_work_area_)
1198 d.current_work_area_->startBlinkingCursor();
1200 // Take this occasion to update the toobars and layout list.
1207 // This list should be kept in sync with the list of insets in
1208 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1209 // dialog should have the same name as the inset.
1211 char const * const dialognames[] = {
1212 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1213 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1214 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1215 "mathdelimiter", "mathmatrix", "note", "paragraph",
1216 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1218 #ifdef HAVE_LIBAIKSAURUS
1222 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1224 char const * const * const end_dialognames =
1225 dialognames + (sizeof(dialognames) / sizeof(char *));
1229 cmpCStr(char const * name) : name_(name) {}
1230 bool operator()(char const * other) {
1231 return strcmp(other, name_) == 0;
1238 bool isValidName(string const & name)
1240 return std::find_if(dialognames, end_dialognames,
1241 cmpCStr(name.c_str())) != end_dialognames;
1247 void GuiView::resetDialogs()
1249 // Make sure that no LFUN uses any LyXView.
1250 theLyXFunc().setLyXView(0);
1251 d.toolbars_->init();
1254 d.layout_->updateContents(true);
1255 // Now update controls with current buffer.
1256 theLyXFunc().setLyXView(this);
1261 Dialog * GuiView::find_or_build(string const & name)
1263 if (!isValidName(name))
1266 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1268 if (it != d.dialogs_.end())
1269 return it->second.get();
1271 d.dialogs_[name].reset(build(name));
1272 return d.dialogs_[name].get();
1276 void GuiView::showDialog(string const & name, string const & data,
1283 Dialog * dialog = find_or_build(name);
1285 dialog->showData(data);
1287 d.open_insets_[name] = inset;
1293 bool GuiView::isDialogVisible(string const & name) const
1295 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1296 if (it == d.dialogs_.end())
1298 return it->second.get()->isVisibleView();
1302 void GuiView::hideDialog(string const & name, Inset * inset)
1304 // Don't send the signal if we are quitting, because on MSVC it is
1305 // destructed before the cut stack in CutAndPaste.cpp, and this method
1306 // is called from some inset destructor if the cut stack is not empty
1311 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1312 if (it == d.dialogs_.end())
1315 if (inset && inset != getOpenInset(name))
1318 Dialog * const dialog = it->second.get();
1319 if (dialog->isVisibleView())
1321 d.open_insets_[name] = 0;
1325 void GuiView::disconnectDialog(string const & name)
1327 if (!isValidName(name))
1330 if (d.open_insets_.find(name) != d.open_insets_.end())
1331 d.open_insets_[name] = 0;
1335 Inset * GuiView::getOpenInset(string const & name) const
1337 if (!isValidName(name))
1340 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1341 return it == d.open_insets_.end() ? 0 : it->second;
1345 void GuiView::hideAll() const
1347 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1348 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1350 for(; it != end; ++it)
1355 void GuiView::hideBufferDependent() const
1357 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1358 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1360 for(; it != end; ++it) {
1361 Dialog * dialog = it->second.get();
1362 if (dialog->isBufferDependent())
1368 void GuiView::updateBufferDependent(bool switched) const
1370 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1371 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1373 for(; it != end; ++it) {
1374 Dialog * dialog = it->second.get();
1375 if (switched && dialog->isBufferDependent()) {
1376 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1377 dialog->updateView();
1381 // A bit clunky, but the dialog will request
1382 // that the kernel provides it with the necessary
1384 dialog->updateDialog();
1390 void GuiView::checkStatus()
1392 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1393 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1395 for(; it != end; ++it) {
1396 Dialog * const dialog = it->second.get();
1397 if (dialog && dialog->isVisibleView())
1398 dialog->checkStatus();
1404 // will be replaced by a proper factory...
1405 Dialog * createGuiAbout(GuiView & lv);
1406 Dialog * createGuiBibitem(GuiView & lv);
1407 Dialog * createGuiBibtex(GuiView & lv);
1408 Dialog * createGuiBox(GuiView & lv);
1409 Dialog * createGuiBranch(GuiView & lv);
1410 Dialog * createGuiChanges(GuiView & lv);
1411 Dialog * createGuiCharacter(GuiView & lv);
1412 Dialog * createGuiCitation(GuiView & lv);
1413 Dialog * createGuiDelimiter(GuiView & lv);
1414 Dialog * createGuiDocument(GuiView & lv);
1415 Dialog * createGuiErrorList(GuiView & lv);
1416 Dialog * createGuiERT(GuiView & lv);
1417 Dialog * createGuiExternal(GuiView & lv);
1418 Dialog * createGuiFloat(GuiView & lv);
1419 Dialog * createGuiGraphics(GuiView & lv);
1420 Dialog * createGuiInclude(GuiView & lv);
1421 Dialog * createGuiIndex(GuiView & lv);
1422 Dialog * createGuiLabel(GuiView & lv);
1423 Dialog * createGuiListings(GuiView & lv);
1424 Dialog * createGuiLog(GuiView & lv);
1425 Dialog * createGuiMathMatrix(GuiView & lv);
1426 Dialog * createGuiNomenclature(GuiView & lv);
1427 Dialog * createGuiNote(GuiView & lv);
1428 Dialog * createGuiParagraph(GuiView & lv);
1429 Dialog * createGuiPreferences(GuiView & lv);
1430 Dialog * createGuiPrint(GuiView & lv);
1431 Dialog * createGuiRef(GuiView & lv);
1432 Dialog * createGuiSearch(GuiView & lv);
1433 Dialog * createGuiSendTo(GuiView & lv);
1434 Dialog * createGuiShowFile(GuiView & lv);
1435 Dialog * createGuiSpellchecker(GuiView & lv);
1436 Dialog * createGuiTabularCreate(GuiView & lv);
1437 Dialog * createGuiTabular(GuiView & lv);
1438 Dialog * createGuiTexInfo(GuiView & lv);
1439 Dialog * createGuiToc(GuiView & lv);
1440 Dialog * createGuiThesaurus(GuiView & lv);
1441 Dialog * createGuiHyperlink(GuiView & lv);
1442 Dialog * createGuiVSpace(GuiView & lv);
1443 Dialog * createGuiViewSource(GuiView & lv);
1444 Dialog * createGuiWrap(GuiView & lv);
1447 Dialog * GuiView::build(string const & name)
1449 BOOST_ASSERT(isValidName(name));
1451 if (name == "aboutlyx")
1452 return createGuiAbout(*this);
1453 if (name == "bibitem")
1454 return createGuiBibitem(*this);
1455 if (name == "bibtex")
1456 return createGuiBibtex(*this);
1458 return createGuiBox(*this);
1459 if (name == "branch")
1460 return createGuiBranch(*this);
1461 if (name == "changes")
1462 return createGuiChanges(*this);
1463 if (name == "character")
1464 return createGuiCharacter(*this);
1465 if (name == "citation")
1466 return createGuiCitation(*this);
1467 if (name == "document")
1468 return createGuiDocument(*this);
1469 if (name == "errorlist")
1470 return createGuiErrorList(*this);
1472 return createGuiERT(*this);
1473 if (name == "external")
1474 return createGuiExternal(*this);
1476 return createGuiShowFile(*this);
1477 if (name == "findreplace")
1478 return createGuiSearch(*this);
1479 if (name == "float")
1480 return createGuiFloat(*this);
1481 if (name == "graphics")
1482 return createGuiGraphics(*this);
1483 if (name == "include")
1484 return createGuiInclude(*this);
1485 if (name == "index")
1486 return createGuiIndex(*this);
1487 if (name == "nomenclature")
1488 return createGuiNomenclature(*this);
1489 if (name == "label")
1490 return createGuiLabel(*this);
1492 return createGuiLog(*this);
1493 if (name == "view-source")
1494 return createGuiViewSource(*this);
1495 if (name == "mathdelimiter")
1496 return createGuiDelimiter(*this);
1497 if (name == "mathmatrix")
1498 return createGuiMathMatrix(*this);
1500 return createGuiNote(*this);
1501 if (name == "paragraph")
1502 return createGuiParagraph(*this);
1503 if (name == "prefs")
1504 return createGuiPreferences(*this);
1505 if (name == "print")
1506 return createGuiPrint(*this);
1508 return createGuiRef(*this);
1509 if (name == "sendto")
1510 return createGuiSendTo(*this);
1511 if (name == "spellchecker")
1512 return createGuiSpellchecker(*this);
1513 if (name == "tabular")
1514 return createGuiTabular(*this);
1515 if (name == "tabularcreate")
1516 return createGuiTabularCreate(*this);
1517 if (name == "texinfo")
1518 return createGuiTexInfo(*this);
1519 #ifdef HAVE_LIBAIKSAURUS
1520 if (name == "thesaurus")
1521 return createGuiThesaurus(*this);
1524 return createGuiToc(*this);
1526 return createGuiHyperlink(*this);
1527 if (name == "vspace")
1528 return createGuiVSpace(*this);
1530 return createGuiWrap(*this);
1531 if (name == "listings")
1532 return createGuiListings(*this);
1538 } // namespace frontend
1541 #include "GuiView_moc.cpp"