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();
1172 // This list should be kept in sync with the list of insets in
1173 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1174 // dialog should have the same name as the inset.
1176 char const * const dialognames[] = {
1177 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1178 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1179 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1180 "mathdelimiter", "mathmatrix", "note", "paragraph",
1181 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1183 #ifdef HAVE_LIBAIKSAURUS
1187 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1189 char const * const * const end_dialognames =
1190 dialognames + (sizeof(dialognames) / sizeof(char *));
1194 cmpCStr(char const * name) : name_(name) {}
1195 bool operator()(char const * other) {
1196 return strcmp(other, name_) == 0;
1203 bool isValidName(string const & name)
1205 return std::find_if(dialognames, end_dialognames,
1206 cmpCStr(name.c_str())) != end_dialognames;
1212 Dialog * GuiView::find_or_build(string const & name)
1214 if (!isValidName(name))
1217 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1219 if (it != d.dialogs_.end())
1220 return it->second.get();
1222 d.dialogs_[name].reset(build(name));
1223 return d.dialogs_[name].get();
1227 void GuiView::showDialog(string const & name, string const & data,
1234 Dialog * dialog = find_or_build(name);
1236 dialog->showData(data);
1238 d.open_insets_[name] = inset;
1244 bool GuiView::isDialogVisible(string const & name) const
1246 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1247 if (it == d.dialogs_.end())
1249 return it->second.get()->isVisibleView();
1253 void GuiView::hideDialog(string const & name, Inset * inset)
1255 // Don't send the signal if we are quitting, because on MSVC it is
1256 // destructed before the cut stack in CutAndPaste.cpp, and this method
1257 // is called from some inset destructor if the cut stack is not empty
1262 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1263 if (it == d.dialogs_.end())
1266 if (inset && inset != getOpenInset(name))
1269 Dialog * const dialog = it->second.get();
1270 if (dialog->isVisibleView())
1272 d.open_insets_[name] = 0;
1276 void GuiView::disconnectDialog(string const & name)
1278 if (!isValidName(name))
1281 if (d.open_insets_.find(name) != d.open_insets_.end())
1282 d.open_insets_[name] = 0;
1286 Inset * GuiView::getOpenInset(string const & name) const
1288 if (!isValidName(name))
1291 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1292 return it == d.open_insets_.end() ? 0 : it->second;
1296 void GuiView::hideAll() const
1298 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1299 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1301 for(; it != end; ++it)
1306 void GuiView::hideBufferDependent() const
1308 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1309 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1311 for(; it != end; ++it) {
1312 Dialog * dialog = it->second.get();
1313 if (dialog->isBufferDependent())
1319 void GuiView::updateBufferDependent(bool switched) const
1321 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1322 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1324 for(; it != end; ++it) {
1325 Dialog * dialog = it->second.get();
1326 if (switched && dialog->isBufferDependent()) {
1327 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1328 dialog->updateView();
1332 // A bit clunky, but the dialog will request
1333 // that the kernel provides it with the necessary
1335 dialog->slotRestore();
1341 void GuiView::checkStatus()
1343 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1344 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1346 for(; it != end; ++it) {
1347 Dialog * const dialog = it->second.get();
1348 if (dialog && dialog->isVisibleView())
1349 dialog->checkStatus();
1355 // will be replaced by a proper factory...
1356 Dialog * createGuiAbout(LyXView & lv);
1357 Dialog * createGuiBibitem(LyXView & lv);
1358 Dialog * createGuiBibtex(LyXView & lv);
1359 Dialog * createGuiBox(LyXView & lv);
1360 Dialog * createGuiBranch(LyXView & lv);
1361 Dialog * createGuiChanges(LyXView & lv);
1362 Dialog * createGuiCharacter(LyXView & lv);
1363 Dialog * createGuiCitation(LyXView & lv);
1364 Dialog * createGuiDelimiter(LyXView & lv);
1365 Dialog * createGuiDocument(LyXView & lv);
1366 Dialog * createGuiErrorList(LyXView & lv);
1367 Dialog * createGuiERT(LyXView & lv);
1368 Dialog * createGuiExternal(LyXView & lv);
1369 Dialog * createGuiFloat(LyXView & lv);
1370 Dialog * createGuiGraphics(LyXView & lv);
1371 Dialog * createGuiInclude(LyXView & lv);
1372 Dialog * createGuiIndex(LyXView & lv);
1373 Dialog * createGuiLabel(LyXView & lv);
1374 Dialog * createGuiListings(LyXView & lv);
1375 Dialog * createGuiLog(LyXView & lv);
1376 Dialog * createGuiMathMatrix(LyXView & lv);
1377 Dialog * createGuiNomenclature(LyXView & lv);
1378 Dialog * createGuiNote(LyXView & lv);
1379 Dialog * createGuiParagraph(LyXView & lv);
1380 Dialog * createGuiPreferences(LyXView & lv);
1381 Dialog * createGuiPrint(LyXView & lv);
1382 Dialog * createGuiRef(LyXView & lv);
1383 Dialog * createGuiSearch(LyXView & lv);
1384 Dialog * createGuiSendTo(LyXView & lv);
1385 Dialog * createGuiShowFile(LyXView & lv);
1386 Dialog * createGuiSpellchecker(LyXView & lv);
1387 Dialog * createGuiTabularCreate(LyXView & lv);
1388 Dialog * createGuiTabular(LyXView & lv);
1389 Dialog * createGuiTexInfo(LyXView & lv);
1390 Dialog * createGuiToc(LyXView & lv);
1391 Dialog * createGuiThesaurus(LyXView & lv);
1392 Dialog * createGuiHyperlink(LyXView & lv);
1393 Dialog * createGuiVSpace(LyXView & lv);
1394 Dialog * createGuiViewSource(LyXView & lv);
1395 Dialog * createGuiWrap(LyXView & lv);
1398 Dialog * GuiView::build(string const & name)
1400 BOOST_ASSERT(isValidName(name));
1402 if (name == "aboutlyx")
1403 return createGuiAbout(*this);
1404 if (name == "bibitem")
1405 return createGuiBibitem(*this);
1406 if (name == "bibtex")
1407 return createGuiBibtex(*this);
1409 return createGuiBox(*this);
1410 if (name == "branch")
1411 return createGuiBranch(*this);
1412 if (name == "changes")
1413 return createGuiChanges(*this);
1414 if (name == "character")
1415 return createGuiCharacter(*this);
1416 if (name == "citation")
1417 return createGuiCitation(*this);
1418 if (name == "document")
1419 return createGuiDocument(*this);
1420 if (name == "errorlist")
1421 return createGuiErrorList(*this);
1423 return createGuiERT(*this);
1424 if (name == "external")
1425 return createGuiExternal(*this);
1427 return createGuiShowFile(*this);
1428 if (name == "findreplace")
1429 return createGuiSearch(*this);
1430 if (name == "float")
1431 return createGuiFloat(*this);
1432 if (name == "graphics")
1433 return createGuiGraphics(*this);
1434 if (name == "include")
1435 return createGuiInclude(*this);
1436 if (name == "index")
1437 return createGuiIndex(*this);
1438 if (name == "nomenclature")
1439 return createGuiNomenclature(*this);
1440 if (name == "label")
1441 return createGuiLabel(*this);
1443 return createGuiLog(*this);
1444 if (name == "view-source")
1445 return createGuiViewSource(*this);
1446 if (name == "mathdelimiter")
1447 return createGuiDelimiter(*this);
1448 if (name == "mathmatrix")
1449 return createGuiMathMatrix(*this);
1451 return createGuiNote(*this);
1452 if (name == "paragraph")
1453 return createGuiParagraph(*this);
1454 if (name == "prefs")
1455 return createGuiPreferences(*this);
1456 if (name == "print")
1457 return createGuiPrint(*this);
1459 return createGuiRef(*this);
1460 if (name == "sendto")
1461 return createGuiSendTo(*this);
1462 if (name == "spellchecker")
1463 return createGuiSpellchecker(*this);
1464 if (name == "tabular")
1465 return createGuiTabular(*this);
1466 if (name == "tabularcreate")
1467 return createGuiTabularCreate(*this);
1468 if (name == "texinfo")
1469 return createGuiTexInfo(*this);
1470 #ifdef HAVE_LIBAIKSAURUS
1471 if (name == "thesaurus")
1472 return createGuiThesaurus(*this);
1475 return createGuiToc(*this);
1477 return createGuiHyperlink(*this);
1478 if (name == "vspace")
1479 return createGuiVSpace(*this);
1481 return createGuiWrap(*this);
1482 if (name == "listings")
1483 return createGuiListings(*this);
1489 } // namespace frontend
1492 #include "GuiView_moc.cpp"