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), layout_(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_;
266 QSplitter * splitter_;
267 QStackedWidget * stack_widget_;
268 BackgroundWidget * bg_widget_;
270 GuiMenubar * menubar_;
272 GuiToolbars * toolbars_;
273 /// The main layout box.
275 * \warning Don't Delete! The layout box is actually owned by
276 * whichever toolbar contains it. All the GuiView class needs is a
277 * means of accessing it.
279 * FIXME: replace that with a proper model so that we are not limited
280 * to only one dialog.
282 GuiLayoutBox * layout_;
285 std::map<std::string, Inset *> open_insets_;
288 std::map<std::string, DialogPtr> dialogs_;
290 unsigned int smallIconSize;
291 unsigned int normalIconSize;
292 unsigned int bigIconSize;
294 QTimer statusbar_timer_;
295 /// are we quitting by the menu?
296 bool quitting_by_menu_;
297 /// auto-saving of buffers
298 Timeout * const autosave_timeout_;
300 /// flag against a race condition due to multiclicks in Qt frontend,
306 GuiView::GuiView(int id)
307 : d(*new GuiViewPrivate), id_(id)
309 // GuiToolbars *must* be initialised before GuiMenubar.
310 d.toolbars_ = new GuiToolbars(*this);
311 d.menubar_ = new GuiMenubar(this, menubackend);
313 setCentralWidget(d.stack_widget_);
315 // Start autosave timer
316 if (lyxrc.autosave) {
317 d.autosave_timeout_->timeout.connect(boost::bind(&GuiView::autoSave, this));
318 d.autosave_timeout_->setTimeout(lyxrc.autosave * 1000);
319 d.autosave_timeout_->start();
321 QObject::connect(&d.statusbar_timer_, SIGNAL(timeout()),
322 this, SLOT(clearMessage()));
324 // Qt bug? signal lastWindowClosed does not work
325 setAttribute(Qt::WA_QuitOnClose, false);
326 setAttribute(Qt::WA_DeleteOnClose, true);
328 // assign an icon to main form. We do not do it under Qt/Mac,
329 // since the icon is provided in the application bundle.
330 setWindowIcon(QPixmap(":/images/lyx.png"));
334 setAcceptDrops(true);
336 statusBar()->setSizeGripEnabled(true);
338 // Forbid too small unresizable window because it can happen
339 // with some window manager under X11.
340 setMinimumSize(300, 200);
342 if (!lyxrc.allow_geometry_session)
343 // No session handling, default to a sane size.
344 setGeometry(50, 50, 690, 510);
346 // Now take care of session management.
348 QString const key = "view-" + QString::number(id_);
350 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
351 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
355 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
356 setGeometry(50, 50, 690, 510);
358 setIconSize(settings.value(key + "/icon_size").toSize());
368 void GuiView::close()
370 d.quitting_by_menu_ = true;
371 d.current_work_area_ = 0;
372 for (int i = 0; i != d.splitter_->count(); ++i) {
373 TabWorkArea * twa = d.tabWorkArea(i);
377 QMainWindow::close();
378 d.quitting_by_menu_ = false;
382 void GuiView::setFocus()
384 if (d.current_work_area_)
385 d.current_work_area_->setFocus();
391 QMenu* GuiView::createPopupMenu()
393 return d.toolBarPopup(this);
397 void GuiView::showEvent(QShowEvent * e)
399 LYXERR(Debug::GUI, "Passed Geometry "
400 << size().height() << "x" << size().width()
401 << "+" << pos().x() << "+" << pos().y());
403 if (d.splitter_->count() == 0)
404 // No work area, switch to the background widget.
407 QMainWindow::showEvent(e);
411 void GuiView::closeEvent(QCloseEvent * close_event)
413 // we may have been called through the close window button
414 // which bypasses the LFUN machinery.
415 if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
416 if (!theBufferList().quitWriteAll()) {
417 close_event->ignore();
422 // Make sure that no LFUN use this close to be closed View.
423 theLyXFunc().setLyXView(0);
424 // Make sure the timer time out will not trigger a statusbar update.
425 d.statusbar_timer_.stop();
427 if (lyxrc.allow_geometry_session) {
429 QString const key = "view-" + QString::number(id_);
431 settings.setValue(key + "/pos", pos());
432 settings.setValue(key + "/size", size());
434 settings.setValue(key + "/geometry", saveGeometry());
436 settings.setValue(key + "/icon_size", iconSize());
437 d.toolbars_->saveToolbarInfo();
440 guiApp->unregisterView(id_);
441 if (guiApp->viewCount() > 0) {
442 // Just close the window and do nothing else if this is not the
444 close_event->accept();
450 // this is the place where we leave the frontend.
451 // it is the only point at which we start quitting.
452 close_event->accept();
453 // quit the event loop
458 void GuiView::dragEnterEvent(QDragEnterEvent * event)
460 if (event->mimeData()->hasUrls())
462 /// \todo Ask lyx-devel is this is enough:
463 /// if (event->mimeData()->hasFormat("text/plain"))
464 /// event->acceptProposedAction();
468 void GuiView::dropEvent(QDropEvent* event)
470 QList<QUrl> files = event->mimeData()->urls();
474 LYXERR(Debug::GUI, BOOST_CURRENT_FUNCTION << " got URLs!");
475 for (int i = 0; i != files.size(); ++i) {
476 string const file = support::os::internal_path(fromqstr(
477 files.at(i).toLocalFile()));
479 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
484 void GuiView::message(docstring const & str)
486 statusBar()->showMessage(toqstr(str));
487 d.statusbar_timer_.stop();
488 d.statusbar_timer_.start(statusbar_timer_value);
492 void GuiView::smallSizedIcons()
494 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
498 void GuiView::normalSizedIcons()
500 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
504 void GuiView::bigSizedIcons()
506 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
510 void GuiView::clearMessage()
514 theLyXFunc().setLyXView(this);
515 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
516 d.statusbar_timer_.stop();
520 void GuiView::updateWindowTitle(GuiWorkArea * wa)
522 if (wa != d.current_work_area_)
524 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
525 setWindowIconText(wa->windowIconText());
529 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
532 disconnectBufferView();
533 connectBufferView(wa->bufferView());
534 connectBuffer(wa->bufferView().buffer());
535 d.current_work_area_ = wa;
536 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
537 this, SLOT(updateWindowTitle(GuiWorkArea *)));
538 updateWindowTitle(wa);
541 // Buffer-dependent dialogs should be updated or
542 // hidden. This should go here because some dialogs (eg ToC)
543 // require bv_->text.
544 updateBufferDependent(true);
551 void GuiView::updateStatusBar()
553 // let the user see the explicit message
554 if (d.statusbar_timer_.isActive())
557 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
561 bool GuiView::hasFocus() const
563 return qApp->activeWindow() == this;
567 bool GuiView::event(QEvent * e)
571 // Useful debug code:
572 //case QEvent::ActivationChange:
573 //case QEvent::WindowDeactivate:
574 //case QEvent::Paint:
575 //case QEvent::Enter:
576 //case QEvent::Leave:
577 //case QEvent::HoverEnter:
578 //case QEvent::HoverLeave:
579 //case QEvent::HoverMove:
580 //case QEvent::StatusTip:
581 //case QEvent::DragEnter:
582 //case QEvent::DragLeave:
586 case QEvent::WindowActivate: {
587 guiApp->setCurrentView(*this);
588 if (d.current_work_area_) {
589 BufferView & bv = d.current_work_area_->bufferView();
590 connectBufferView(bv);
591 connectBuffer(bv.buffer());
592 // The document structure, name and dialogs might have
593 // changed in another view.
594 updateBufferDependent(true);
596 setWindowTitle(qt_("LyX"));
597 setWindowIconText(qt_("LyX"));
599 return QMainWindow::event(e);
601 case QEvent::ShortcutOverride: {
602 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
603 if (!d.current_work_area_) {
604 theLyXFunc().setLyXView(this);
606 setKeySymbol(&sym, ke);
607 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
611 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
613 setKeySymbol(&sym, ke);
614 d.current_work_area_->processKeySym(sym, NoModifier);
620 return QMainWindow::event(e);
625 bool GuiView::focusNextPrevChild(bool /*next*/)
632 void GuiView::setBusy(bool yes)
634 if (d.current_work_area_) {
635 d.current_work_area_->setUpdatesEnabled(!yes);
637 d.current_work_area_->stopBlinkingCursor();
639 d.current_work_area_->startBlinkingCursor();
643 QApplication::setOverrideCursor(Qt::WaitCursor);
645 QApplication::restoreOverrideCursor();
649 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
651 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
653 if (tbinfo.flags & ToolbarInfo::TOP) {
655 addToolBarBreak(Qt::TopToolBarArea);
656 addToolBar(Qt::TopToolBarArea, toolBar);
659 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
660 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
661 #if (QT_VERSION >= 0x040202)
663 addToolBarBreak(Qt::BottomToolBarArea);
665 addToolBar(Qt::BottomToolBarArea, toolBar);
668 if (tbinfo.flags & ToolbarInfo::LEFT) {
669 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
670 #if (QT_VERSION >= 0x040202)
672 addToolBarBreak(Qt::LeftToolBarArea);
674 addToolBar(Qt::LeftToolBarArea, toolBar);
677 if (tbinfo.flags & ToolbarInfo::RIGHT) {
678 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
679 #if (QT_VERSION >= 0x040202)
681 addToolBarBreak(Qt::RightToolBarArea);
683 addToolBar(Qt::RightToolBarArea, toolBar);
686 // The following does not work so I cannot restore to exact toolbar location
688 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
689 toolBar->move(tbinfo.posx, tbinfo.posy);
696 GuiWorkArea * GuiView::workArea(Buffer & buffer)
698 for (int i = 0; i != d.splitter_->count(); ++i) {
699 GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
707 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
710 // Automatically create a TabWorkArea if there are none yet.
711 if (!d.splitter_->count())
714 TabWorkArea * tab_widget = d.currentTabWorkArea();
715 return tab_widget->addWorkArea(buffer, *this);
719 void GuiView::addTabWorkArea()
721 TabWorkArea * twa = new TabWorkArea;
722 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
723 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
724 d.splitter_->addWidget(twa);
725 d.stack_widget_->setCurrentWidget(d.splitter_);
729 GuiWorkArea const * GuiView::currentWorkArea() const
731 return d.current_work_area_;
735 void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
737 BOOST_ASSERT(work_area);
739 // Changing work area can result from opening a file so
740 // update the toc in any case.
743 GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
744 d.current_work_area_ = wa;
745 for (int i = 0; i != d.splitter_->count(); ++i) {
746 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
752 void GuiView::removeWorkArea(GuiWorkArea * work_area)
754 BOOST_ASSERT(work_area);
755 GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
756 if (gwa == d.current_work_area_) {
758 disconnectBufferView();
759 hideBufferDependent();
760 d.current_work_area_ = 0;
763 // removing a work area often results from closing a file so
764 // update the toc in any case.
767 for (int i = 0; i != d.splitter_->count(); ++i) {
768 TabWorkArea * twa = d.tabWorkArea(i);
769 if (!twa->removeWorkArea(gwa))
770 // Not found in this tab group.
773 // We found and removed the GuiWorkArea.
775 // No more WorkAreas in this tab group, so delete it.
780 if (d.current_work_area_)
781 // This means that we are not closing the current GuiWorkArea;
784 // Switch to the next GuiWorkArea in the found TabWorkArea.
785 d.current_work_area_ = twa->currentWorkArea();
789 if (d.splitter_->count() == 0)
790 // No more work area, switch to the background widget.
795 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
801 void GuiView::updateLayoutList()
804 d.layout_->updateContents(false);
808 void GuiView::updateToolbars()
810 if (d.current_work_area_) {
812 d.current_work_area_->bufferView().cursor().inMathed();
814 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
816 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
817 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
819 d.toolbars_->update(math, table, review);
821 d.toolbars_->update(false, false, false);
823 // update read-only status of open dialogs.
828 Buffer * GuiView::buffer()
830 if (d.current_work_area_)
831 return &d.current_work_area_->bufferView().buffer();
836 Buffer const * GuiView::buffer() const
838 if (d.current_work_area_)
839 return &d.current_work_area_->bufferView().buffer();
844 void GuiView::setBuffer(Buffer * newBuffer)
846 BOOST_ASSERT(newBuffer);
849 GuiWorkArea * wa = workArea(*newBuffer);
851 updateLabels(*newBuffer->masterBuffer());
852 wa = addWorkArea(*newBuffer);
854 //Disconnect the old buffer...there's no new one.
857 connectBuffer(*newBuffer);
858 connectBufferView(wa->bufferView());
859 setCurrentWorkArea(wa);
865 void GuiView::connectBuffer(Buffer & buf)
867 buf.setGuiDelegate(this);
871 void GuiView::disconnectBuffer()
873 if (d.current_work_area_)
874 d.current_work_area_->bufferView().setGuiDelegate(0);
878 void GuiView::connectBufferView(BufferView & bv)
880 bv.setGuiDelegate(this);
884 void GuiView::disconnectBufferView()
886 if (d.current_work_area_)
887 d.current_work_area_->bufferView().setGuiDelegate(0);
891 void GuiView::errors(string const & error_type)
893 ErrorList & el = buffer()->errorList(error_type);
895 showDialog("errorlist", error_type);
899 void GuiView::updateDialog(string const & name, string const & data)
901 if (!isDialogVisible(name))
904 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
905 if (it == d.dialogs_.end())
908 Dialog * const dialog = it->second.get();
909 if (dialog->isVisibleView())
910 dialog->updateData(data);
914 BufferView * GuiView::view()
916 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
920 void GuiView::updateToc()
922 updateDialog("toc", "");
926 void GuiView::updateEmbeddedFiles()
928 updateDialog("embedding", "");
932 void GuiView::autoSave()
934 LYXERR(Debug::INFO, "Running autoSave()");
937 view()->buffer().autoSave();
941 void GuiView::resetAutosaveTimers()
944 d.autosave_timeout_->restart();
948 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
952 Buffer * buf = buffer();
954 /* In LyX/Mac, when a dialog is open, the menus of the
955 application can still be accessed without giving focus to
956 the main window. In this case, we want to disable the menu
957 entries that are buffer-related.
959 Note that this code is not perfect, as bug 1941 attests:
960 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
962 if (cmd.origin == FuncRequest::MENU && !hasFocus())
966 case LFUN_TOOLBAR_TOGGLE:
967 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
970 case LFUN_DIALOG_TOGGLE:
971 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
972 // fall through to set "enable"
973 case LFUN_DIALOG_SHOW: {
974 string const name = cmd.getArg(0);
976 enable = name == "aboutlyx"
977 || name == "file" //FIXME: should be removed.
979 || name == "texinfo";
980 else if (name == "print")
981 enable = buf->isExportable("dvi")
982 && lyxrc.print_command != "none";
983 else if (name == "character") {
987 InsetCode ic = view()->cursor().inset().lyxCode();
988 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
991 else if (name == "latexlog")
992 enable = FileName(buf->logName()).isFileReadable();
993 else if (name == "spellchecker")
994 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
995 enable = !buf->isReadonly();
999 else if (name == "vclog")
1000 enable = buf->lyxvc().inUse();
1004 case LFUN_DIALOG_UPDATE: {
1005 string const name = cmd.getArg(0);
1007 enable = name == "prefs";
1019 flag.enabled(false);
1025 void GuiView::dispatch(FuncRequest const & cmd)
1027 Buffer * buf = buffer();
1028 switch(cmd.action) {
1029 case LFUN_BUFFER_SWITCH:
1030 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1033 case LFUN_COMMAND_EXECUTE: {
1034 bool const show_it = cmd.argument() != "off";
1035 d.toolbars_->showCommandBuffer(show_it);
1038 case LFUN_DROP_LAYOUTS_CHOICE:
1040 d.layout_->showPopup();
1043 case LFUN_MENU_OPEN:
1044 d.menubar_->openByName(toqstr(cmd.argument()));
1047 case LFUN_TOOLBAR_TOGGLE: {
1048 string const name = cmd.getArg(0);
1049 bool const allowauto = cmd.getArg(1) == "allowauto";
1050 // it is possible to get current toolbar status like this,...
1051 // but I decide to obey the order of ToolbarBackend::flags
1052 // and disregard real toolbar status.
1053 // toolbars_->saveToolbarInfo();
1055 // toggle state on/off/auto
1056 d.toolbars_->toggleToolbarState(name, allowauto);
1060 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1062 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1066 if (tbi->flags & ToolbarInfo::ON)
1068 else if (tbi->flags & ToolbarInfo::OFF)
1070 else if (tbi->flags & ToolbarInfo::AUTO)
1073 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1074 _(tbi->gui_name), state));
1078 case LFUN_DIALOG_UPDATE: {
1079 string const name = to_utf8(cmd.argument());
1080 // Can only update a dialog connected to an existing inset
1081 Inset * inset = getOpenInset(name);
1083 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1084 inset->dispatch(view()->cursor(), fr);
1085 } else if (name == "paragraph") {
1086 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1087 } else if (name == "prefs") {
1088 updateDialog(name, string());
1093 case LFUN_DIALOG_TOGGLE: {
1094 if (isDialogVisible(cmd.getArg(0)))
1095 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1097 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1101 case LFUN_DIALOG_DISCONNECT_INSET:
1102 disconnectDialog(to_utf8(cmd.argument()));
1105 case LFUN_DIALOG_HIDE: {
1108 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1112 case LFUN_DIALOG_SHOW: {
1113 string const name = cmd.getArg(0);
1114 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1116 if (name == "character") {
1117 data = freefont2string();
1119 showDialog("character", data);
1120 } else if (name == "latexlog") {
1121 Buffer::LogType type;
1122 string const logfile = buf->logName(&type);
1124 case Buffer::latexlog:
1127 case Buffer::buildlog:
1131 data += Lexer::quoteString(logfile);
1132 showDialog("log", data);
1133 } else if (name == "vclog") {
1134 string const data = "vc " +
1135 Lexer::quoteString(buf->lyxvc().getLogFile());
1136 showDialog("log", data);
1138 showDialog(name, data);
1143 theLyXFunc().setLyXView(this);
1149 Buffer const * GuiView::updateInset(Inset const * inset)
1151 if (!d.current_work_area_)
1155 d.current_work_area_->scheduleRedraw();
1157 return &d.current_work_area_->bufferView().buffer();
1161 void GuiView::restartCursor()
1163 /* When we move around, or type, it's nice to be able to see
1164 * the cursor immediately after the keypress.
1166 if (d.current_work_area_)
1167 d.current_work_area_->startBlinkingCursor();
1169 // Take this occasion to update the toobars and layout list.
1176 // This list should be kept in sync with the list of insets in
1177 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1178 // dialog should have the same name as the inset.
1180 char const * const dialognames[] = {
1181 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1182 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1183 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1184 "mathdelimiter", "mathmatrix", "note", "paragraph",
1185 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1187 #ifdef HAVE_LIBAIKSAURUS
1191 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1193 char const * const * const end_dialognames =
1194 dialognames + (sizeof(dialognames) / sizeof(char *));
1198 cmpCStr(char const * name) : name_(name) {}
1199 bool operator()(char const * other) {
1200 return strcmp(other, name_) == 0;
1207 bool isValidName(string const & name)
1209 return std::find_if(dialognames, end_dialognames,
1210 cmpCStr(name.c_str())) != end_dialognames;
1216 void GuiView::resetDialogs()
1218 // Make sure that no LFUN uses any LyXView.
1219 theLyXFunc().setLyXView(0);
1220 d.toolbars_->init();
1223 d.layout_->updateContents(true);
1227 Dialog * GuiView::find_or_build(string const & name)
1229 if (!isValidName(name))
1232 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1234 if (it != d.dialogs_.end())
1235 return it->second.get();
1237 d.dialogs_[name].reset(build(name));
1238 return d.dialogs_[name].get();
1242 void GuiView::showDialog(string const & name, string const & data,
1249 Dialog * dialog = find_or_build(name);
1251 dialog->showData(data);
1253 d.open_insets_[name] = inset;
1259 bool GuiView::isDialogVisible(string const & name) const
1261 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1262 if (it == d.dialogs_.end())
1264 return it->second.get()->isVisibleView();
1268 void GuiView::hideDialog(string const & name, Inset * inset)
1270 // Don't send the signal if we are quitting, because on MSVC it is
1271 // destructed before the cut stack in CutAndPaste.cpp, and this method
1272 // is called from some inset destructor if the cut stack is not empty
1277 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1278 if (it == d.dialogs_.end())
1281 if (inset && inset != getOpenInset(name))
1284 Dialog * const dialog = it->second.get();
1285 if (dialog->isVisibleView())
1287 d.open_insets_[name] = 0;
1291 void GuiView::disconnectDialog(string const & name)
1293 if (!isValidName(name))
1296 if (d.open_insets_.find(name) != d.open_insets_.end())
1297 d.open_insets_[name] = 0;
1301 Inset * GuiView::getOpenInset(string const & name) const
1303 if (!isValidName(name))
1306 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1307 return it == d.open_insets_.end() ? 0 : it->second;
1311 void GuiView::hideAll() const
1313 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1314 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1316 for(; it != end; ++it)
1321 void GuiView::hideBufferDependent() const
1323 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1324 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1326 for(; it != end; ++it) {
1327 Dialog * dialog = it->second.get();
1328 if (dialog->isBufferDependent())
1334 void GuiView::updateBufferDependent(bool switched) const
1336 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1337 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1339 for(; it != end; ++it) {
1340 Dialog * dialog = it->second.get();
1341 if (switched && dialog->isBufferDependent()) {
1342 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1343 dialog->updateView();
1347 // A bit clunky, but the dialog will request
1348 // that the kernel provides it with the necessary
1350 dialog->slotRestore();
1356 void GuiView::checkStatus()
1358 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1359 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1361 for(; it != end; ++it) {
1362 Dialog * const dialog = it->second.get();
1363 if (dialog && dialog->isVisibleView())
1364 dialog->checkStatus();
1370 // will be replaced by a proper factory...
1371 Dialog * createGuiAbout(LyXView & lv);
1372 Dialog * createGuiBibitem(LyXView & lv);
1373 Dialog * createGuiBibtex(LyXView & lv);
1374 Dialog * createGuiBox(LyXView & lv);
1375 Dialog * createGuiBranch(LyXView & lv);
1376 Dialog * createGuiChanges(LyXView & lv);
1377 Dialog * createGuiCharacter(LyXView & lv);
1378 Dialog * createGuiCitation(LyXView & lv);
1379 Dialog * createGuiDelimiter(LyXView & lv);
1380 Dialog * createGuiDocument(LyXView & lv);
1381 Dialog * createGuiErrorList(LyXView & lv);
1382 Dialog * createGuiERT(LyXView & lv);
1383 Dialog * createGuiExternal(LyXView & lv);
1384 Dialog * createGuiFloat(LyXView & lv);
1385 Dialog * createGuiGraphics(LyXView & lv);
1386 Dialog * createGuiInclude(LyXView & lv);
1387 Dialog * createGuiIndex(LyXView & lv);
1388 Dialog * createGuiLabel(LyXView & lv);
1389 Dialog * createGuiListings(LyXView & lv);
1390 Dialog * createGuiLog(LyXView & lv);
1391 Dialog * createGuiMathMatrix(LyXView & lv);
1392 Dialog * createGuiNomenclature(LyXView & lv);
1393 Dialog * createGuiNote(LyXView & lv);
1394 Dialog * createGuiParagraph(LyXView & lv);
1395 Dialog * createGuiPreferences(LyXView & lv);
1396 Dialog * createGuiPrint(LyXView & lv);
1397 Dialog * createGuiRef(LyXView & lv);
1398 Dialog * createGuiSearch(LyXView & lv);
1399 Dialog * createGuiSendTo(LyXView & lv);
1400 Dialog * createGuiShowFile(LyXView & lv);
1401 Dialog * createGuiSpellchecker(LyXView & lv);
1402 Dialog * createGuiTabularCreate(LyXView & lv);
1403 Dialog * createGuiTabular(LyXView & lv);
1404 Dialog * createGuiTexInfo(LyXView & lv);
1405 Dialog * createGuiToc(LyXView & lv);
1406 Dialog * createGuiThesaurus(LyXView & lv);
1407 Dialog * createGuiHyperlink(LyXView & lv);
1408 Dialog * createGuiVSpace(LyXView & lv);
1409 Dialog * createGuiViewSource(LyXView & lv);
1410 Dialog * createGuiWrap(LyXView & lv);
1413 Dialog * GuiView::build(string const & name)
1415 BOOST_ASSERT(isValidName(name));
1417 if (name == "aboutlyx")
1418 return createGuiAbout(*this);
1419 if (name == "bibitem")
1420 return createGuiBibitem(*this);
1421 if (name == "bibtex")
1422 return createGuiBibtex(*this);
1424 return createGuiBox(*this);
1425 if (name == "branch")
1426 return createGuiBranch(*this);
1427 if (name == "changes")
1428 return createGuiChanges(*this);
1429 if (name == "character")
1430 return createGuiCharacter(*this);
1431 if (name == "citation")
1432 return createGuiCitation(*this);
1433 if (name == "document")
1434 return createGuiDocument(*this);
1435 if (name == "errorlist")
1436 return createGuiErrorList(*this);
1438 return createGuiERT(*this);
1439 if (name == "external")
1440 return createGuiExternal(*this);
1442 return createGuiShowFile(*this);
1443 if (name == "findreplace")
1444 return createGuiSearch(*this);
1445 if (name == "float")
1446 return createGuiFloat(*this);
1447 if (name == "graphics")
1448 return createGuiGraphics(*this);
1449 if (name == "include")
1450 return createGuiInclude(*this);
1451 if (name == "index")
1452 return createGuiIndex(*this);
1453 if (name == "nomenclature")
1454 return createGuiNomenclature(*this);
1455 if (name == "label")
1456 return createGuiLabel(*this);
1458 return createGuiLog(*this);
1459 if (name == "view-source")
1460 return createGuiViewSource(*this);
1461 if (name == "mathdelimiter")
1462 return createGuiDelimiter(*this);
1463 if (name == "mathmatrix")
1464 return createGuiMathMatrix(*this);
1466 return createGuiNote(*this);
1467 if (name == "paragraph")
1468 return createGuiParagraph(*this);
1469 if (name == "prefs")
1470 return createGuiPreferences(*this);
1471 if (name == "print")
1472 return createGuiPrint(*this);
1474 return createGuiRef(*this);
1475 if (name == "sendto")
1476 return createGuiSendTo(*this);
1477 if (name == "spellchecker")
1478 return createGuiSpellchecker(*this);
1479 if (name == "tabular")
1480 return createGuiTabular(*this);
1481 if (name == "tabularcreate")
1482 return createGuiTabularCreate(*this);
1483 if (name == "texinfo")
1484 return createGuiTexInfo(*this);
1485 #ifdef HAVE_LIBAIKSAURUS
1486 if (name == "thesaurus")
1487 return createGuiThesaurus(*this);
1490 return createGuiToc(*this);
1492 return createGuiHyperlink(*this);
1493 if (name == "vspace")
1494 return createGuiVSpace(*this);
1496 return createGuiWrap(*this);
1497 if (name == "listings")
1498 return createGuiListings(*this);
1504 } // namespace frontend
1507 #include "GuiView_moc.cpp"