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>
60 #include <QDesktopWidget>
61 #include <QDragEnterEvent>
68 #include <QPushButton>
72 #include <QStackedWidget>
78 #include <boost/assert.hpp>
79 #include <boost/bind.hpp>
81 #ifdef HAVE_SYS_TIME_H
82 # include <sys/time.h>
98 using support::bformat;
99 using support::FileName;
104 class BackgroundWidget : public QWidget
107 BackgroundWidget(QString const & file, QString const & text)
110 QPainter pain(&splash_);
111 pain.setPen(QColor(255, 255, 0));
113 // The font used to display the version info
114 font.setStyleHint(QFont::SansSerif);
115 font.setWeight(QFont::Bold);
116 font.setPointSize(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toInt());
118 pain.drawText(260, 270, text);
121 void paintEvent(QPaintEvent *)
123 int x = (width() - splash_.width()) / 2;
124 int y = (height() - splash_.height()) / 2;
126 pain.drawPixmap(x, y, splash_);
136 typedef boost::shared_ptr<Dialog> DialogPtr;
138 struct GuiView::GuiViewPrivate
141 : current_work_area_(0), layout_(0),
142 quitting_by_menu_(false), autosave_timeout_(5000), in_show_(false)
144 // hardcode here the platform specific icon size
145 smallIconSize = 14; // scaling problems
146 normalIconSize = 20; // ok, default
147 bigIconSize = 26; // better for some math icons
149 splitter_ = new QSplitter;
151 stack_widget_ = new QStackedWidget;
152 stack_widget_->addWidget(bg_widget_);
153 stack_widget_->addWidget(splitter_);
161 delete stack_widget_;
166 QMenu * toolBarPopup(GuiView * parent)
168 // FIXME: translation
169 QMenu * menu = new QMenu(parent);
170 QActionGroup * iconSizeGroup = new QActionGroup(parent);
172 QAction * smallIcons = new QAction(iconSizeGroup);
173 smallIcons->setText(qt_("Small-sized icons"));
174 smallIcons->setCheckable(true);
175 QObject::connect(smallIcons, SIGNAL(triggered()),
176 parent, SLOT(smallSizedIcons()));
177 menu->addAction(smallIcons);
179 QAction * normalIcons = new QAction(iconSizeGroup);
180 normalIcons->setText(qt_("Normal-sized icons"));
181 normalIcons->setCheckable(true);
182 QObject::connect(normalIcons, SIGNAL(triggered()),
183 parent, SLOT(normalSizedIcons()));
184 menu->addAction(normalIcons);
186 QAction * bigIcons = new QAction(iconSizeGroup);
187 bigIcons->setText(qt_("Big-sized icons"));
188 bigIcons->setCheckable(true);
189 QObject::connect(bigIcons, SIGNAL(triggered()),
190 parent, SLOT(bigSizedIcons()));
191 menu->addAction(bigIcons);
193 unsigned int cur = parent->iconSize().width();
194 if ( cur == parent->d.smallIconSize)
195 smallIcons->setChecked(true);
196 else if (cur == parent->d.normalIconSize)
197 normalIcons->setChecked(true);
198 else if (cur == parent->d.bigIconSize)
199 bigIcons->setChecked(true);
204 void initBackground()
206 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
207 /// The text to be written on top of the pixmap
208 QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
209 bg_widget_ = new BackgroundWidget(":/images/banner.png", text);
214 stack_widget_->setCurrentWidget(bg_widget_);
215 bg_widget_->setUpdatesEnabled(true);
218 TabWorkArea * tabWorkArea(int i)
220 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
223 TabWorkArea * currentTabWorkArea()
225 if (splitter_->count() == 1)
226 // The first TabWorkArea is always the first one, if any.
227 return tabWorkArea(0);
229 TabWorkArea * tab_widget = 0;
230 for (int i = 0; i != splitter_->count(); ++i) {
231 QWidget * w = splitter_->widget(i);
234 tab_widget = dynamic_cast<TabWorkArea *>(w);
246 GuiWorkArea * current_work_area_;
247 QSplitter * splitter_;
248 QStackedWidget * stack_widget_;
249 BackgroundWidget * bg_widget_;
251 GuiMenubar * menubar_;
253 GuiToolbars * toolbars_;
254 /// The main layout box.
256 * \warning Don't Delete! The layout box is actually owned by
257 * whichever toolbar contains it. All the GuiView class needs is a
258 * means of accessing it.
260 * FIXME: replace that with a proper model so that we are not limited
261 * to only one dialog.
263 GuiLayoutBox * layout_;
266 std::map<std::string, Inset *> open_insets_;
269 std::map<std::string, DialogPtr> dialogs_;
271 unsigned int smallIconSize;
272 unsigned int normalIconSize;
273 unsigned int bigIconSize;
275 QTimer statusbar_timer_;
276 /// are we quitting by the menu?
277 bool quitting_by_menu_;
278 /// auto-saving of buffers
279 Timeout autosave_timeout_;
281 /// flag against a race condition due to multiclicks in Qt frontend,
287 GuiView::GuiView(int id)
288 : d(*new GuiViewPrivate), id_(id)
290 // GuiToolbars *must* be initialised before GuiMenubar.
291 d.toolbars_ = new GuiToolbars(*this);
292 d.menubar_ = new GuiMenubar(this, menubackend);
294 setCentralWidget(d.stack_widget_);
296 // Start autosave timer
297 if (lyxrc.autosave) {
298 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
299 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
300 d.autosave_timeout_.start();
302 connect(&d.statusbar_timer_, SIGNAL(timeout()),
303 this, SLOT(clearMessage()));
305 // Qt bug? signal lastWindowClosed does not work
306 setAttribute(Qt::WA_QuitOnClose, false);
307 setAttribute(Qt::WA_DeleteOnClose, true);
309 // assign an icon to main form. We do not do it under Qt/Mac,
310 // since the icon is provided in the application bundle.
311 setWindowIcon(QPixmap(":/images/lyx.png"));
315 setAcceptDrops(true);
317 statusBar()->setSizeGripEnabled(true);
319 // Forbid too small unresizable window because it can happen
320 // with some window manager under X11.
321 setMinimumSize(300, 200);
323 if (!lyxrc.allow_geometry_session)
324 // No session handling, default to a sane size.
325 setGeometry(50, 50, 690, 510);
327 // Now take care of session management.
329 QString const key = "view-" + QString::number(id_);
331 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
332 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
336 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
337 setGeometry(50, 50, 690, 510);
339 setIconSize(settings.value(key + "/icon_size").toSize());
349 void GuiView::close()
351 d.quitting_by_menu_ = true;
352 d.current_work_area_ = 0;
353 for (int i = 0; i != d.splitter_->count(); ++i) {
354 TabWorkArea * twa = d.tabWorkArea(i);
358 QMainWindow::close();
359 d.quitting_by_menu_ = false;
363 void GuiView::setFocus()
365 if (d.current_work_area_)
366 d.current_work_area_->setFocus();
372 QMenu* GuiView::createPopupMenu()
374 return d.toolBarPopup(this);
378 void GuiView::showEvent(QShowEvent * e)
380 LYXERR(Debug::GUI, "Passed Geometry "
381 << size().height() << "x" << size().width()
382 << "+" << pos().x() << "+" << pos().y());
384 if (d.splitter_->count() == 0)
385 // No work area, switch to the background widget.
388 QMainWindow::showEvent(e);
392 void GuiView::closeEvent(QCloseEvent * close_event)
394 // we may have been called through the close window button
395 // which bypasses the LFUN machinery.
396 if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
397 if (!theBufferList().quitWriteAll()) {
398 close_event->ignore();
403 // Make sure that no LFUN use this close to be closed View.
404 theLyXFunc().setLyXView(0);
405 // Make sure the timer time out will not trigger a statusbar update.
406 d.statusbar_timer_.stop();
408 if (lyxrc.allow_geometry_session) {
410 QString const key = "view-" + QString::number(id_);
412 settings.setValue(key + "/pos", pos());
413 settings.setValue(key + "/size", size());
415 settings.setValue(key + "/geometry", saveGeometry());
417 settings.setValue(key + "/icon_size", iconSize());
418 d.toolbars_->saveToolbarInfo();
421 guiApp->unregisterView(id_);
422 if (guiApp->viewCount() > 0) {
423 // Just close the window and do nothing else if this is not the
425 close_event->accept();
431 // this is the place where we leave the frontend.
432 // it is the only point at which we start quitting.
433 close_event->accept();
434 // quit the event loop
439 void GuiView::dragEnterEvent(QDragEnterEvent * event)
441 if (event->mimeData()->hasUrls())
443 /// \todo Ask lyx-devel is this is enough:
444 /// if (event->mimeData()->hasFormat("text/plain"))
445 /// event->acceptProposedAction();
449 void GuiView::dropEvent(QDropEvent* event)
451 QList<QUrl> files = event->mimeData()->urls();
455 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
456 for (int i = 0; i != files.size(); ++i) {
457 string const file = support::os::internal_path(fromqstr(
458 files.at(i).toLocalFile()));
460 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
465 void GuiView::message(docstring const & str)
467 statusBar()->showMessage(toqstr(str));
468 d.statusbar_timer_.stop();
469 d.statusbar_timer_.start(3000);
473 void GuiView::smallSizedIcons()
475 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
479 void GuiView::normalSizedIcons()
481 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
485 void GuiView::bigSizedIcons()
487 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
491 void GuiView::clearMessage()
495 theLyXFunc().setLyXView(this);
496 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
497 d.statusbar_timer_.stop();
501 void GuiView::updateWindowTitle(GuiWorkArea * wa)
503 if (wa != d.current_work_area_)
505 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
506 setWindowIconText(wa->windowIconText());
510 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
513 disconnectBufferView();
514 connectBufferView(wa->bufferView());
515 connectBuffer(wa->bufferView().buffer());
516 d.current_work_area_ = wa;
517 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
518 this, SLOT(updateWindowTitle(GuiWorkArea *)));
519 updateWindowTitle(wa);
522 // Buffer-dependent dialogs should be updated or
523 // hidden. This should go here because some dialogs (eg ToC)
524 // require bv_->text.
525 updateBufferDependent(true);
532 void GuiView::updateStatusBar()
534 // let the user see the explicit message
535 if (d.statusbar_timer_.isActive())
538 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
542 bool GuiView::hasFocus() const
544 return qApp->activeWindow() == this;
548 bool GuiView::event(QEvent * e)
552 // Useful debug code:
553 //case QEvent::ActivationChange:
554 //case QEvent::WindowDeactivate:
555 //case QEvent::Paint:
556 //case QEvent::Enter:
557 //case QEvent::Leave:
558 //case QEvent::HoverEnter:
559 //case QEvent::HoverLeave:
560 //case QEvent::HoverMove:
561 //case QEvent::StatusTip:
562 //case QEvent::DragEnter:
563 //case QEvent::DragLeave:
567 case QEvent::WindowActivate: {
568 guiApp->setCurrentView(*this);
569 if (d.current_work_area_) {
570 BufferView & bv = d.current_work_area_->bufferView();
571 connectBufferView(bv);
572 connectBuffer(bv.buffer());
573 // The document structure, name and dialogs might have
574 // changed in another view.
575 updateBufferDependent(true);
577 setWindowTitle(qt_("LyX"));
578 setWindowIconText(qt_("LyX"));
580 return QMainWindow::event(e);
582 case QEvent::ShortcutOverride: {
583 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
584 if (!d.current_work_area_) {
585 theLyXFunc().setLyXView(this);
587 setKeySymbol(&sym, ke);
588 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
592 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
594 setKeySymbol(&sym, ke);
595 d.current_work_area_->processKeySym(sym, NoModifier);
601 return QMainWindow::event(e);
606 bool GuiView::focusNextPrevChild(bool /*next*/)
613 void GuiView::setBusy(bool yes)
615 if (d.current_work_area_) {
616 d.current_work_area_->setUpdatesEnabled(!yes);
618 d.current_work_area_->stopBlinkingCursor();
620 d.current_work_area_->startBlinkingCursor();
624 QApplication::setOverrideCursor(Qt::WaitCursor);
626 QApplication::restoreOverrideCursor();
630 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
632 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
634 if (tbinfo.flags & ToolbarInfo::TOP) {
636 addToolBarBreak(Qt::TopToolBarArea);
637 addToolBar(Qt::TopToolBarArea, toolBar);
640 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
641 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
642 #if (QT_VERSION >= 0x040202)
644 addToolBarBreak(Qt::BottomToolBarArea);
646 addToolBar(Qt::BottomToolBarArea, toolBar);
649 if (tbinfo.flags & ToolbarInfo::LEFT) {
650 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
651 #if (QT_VERSION >= 0x040202)
653 addToolBarBreak(Qt::LeftToolBarArea);
655 addToolBar(Qt::LeftToolBarArea, toolBar);
658 if (tbinfo.flags & ToolbarInfo::RIGHT) {
659 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
660 #if (QT_VERSION >= 0x040202)
662 addToolBarBreak(Qt::RightToolBarArea);
664 addToolBar(Qt::RightToolBarArea, toolBar);
667 // The following does not work so I cannot restore to exact toolbar location
669 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
670 toolBar->move(tbinfo.posx, tbinfo.posy);
677 GuiWorkArea * GuiView::workArea(Buffer & buffer)
679 for (int i = 0; i != d.splitter_->count(); ++i) {
680 GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
688 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
691 // Automatically create a TabWorkArea if there are none yet.
692 if (!d.splitter_->count())
695 TabWorkArea * tab_widget = d.currentTabWorkArea();
696 return tab_widget->addWorkArea(buffer, *this);
700 void GuiView::addTabWorkArea()
702 TabWorkArea * twa = new TabWorkArea;
703 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
704 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
705 d.splitter_->addWidget(twa);
706 d.stack_widget_->setCurrentWidget(d.splitter_);
710 GuiWorkArea const * GuiView::currentWorkArea() const
712 return d.current_work_area_;
716 void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
718 BOOST_ASSERT(work_area);
720 // Changing work area can result from opening a file so
721 // update the toc in any case.
724 GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
725 d.current_work_area_ = wa;
726 for (int i = 0; i != d.splitter_->count(); ++i) {
727 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
733 void GuiView::removeWorkArea(GuiWorkArea * work_area)
735 BOOST_ASSERT(work_area);
736 GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
737 if (gwa == d.current_work_area_) {
739 disconnectBufferView();
740 hideBufferDependent();
741 d.current_work_area_ = 0;
744 // removing a work area often results from closing a file so
745 // update the toc in any case.
748 for (int i = 0; i != d.splitter_->count(); ++i) {
749 TabWorkArea * twa = d.tabWorkArea(i);
750 if (!twa->removeWorkArea(gwa))
751 // Not found in this tab group.
754 // We found and removed the GuiWorkArea.
756 // No more WorkAreas in this tab group, so delete it.
761 if (d.current_work_area_)
762 // This means that we are not closing the current GuiWorkArea;
765 // Switch to the next GuiWorkArea in the found TabWorkArea.
766 d.current_work_area_ = twa->currentWorkArea();
770 if (d.splitter_->count() == 0)
771 // No more work area, switch to the background widget.
776 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
782 void GuiView::updateLayoutList()
785 d.layout_->updateContents(false);
789 void GuiView::updateToolbars()
791 if (d.current_work_area_) {
793 d.current_work_area_->bufferView().cursor().inMathed();
795 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
797 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
798 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
800 d.toolbars_->update(math, table, review);
802 d.toolbars_->update(false, false, false);
804 // update read-only status of open dialogs.
809 Buffer * GuiView::buffer()
811 if (d.current_work_area_)
812 return &d.current_work_area_->bufferView().buffer();
817 Buffer const * GuiView::buffer() const
819 if (d.current_work_area_)
820 return &d.current_work_area_->bufferView().buffer();
825 void GuiView::setBuffer(Buffer * newBuffer)
827 BOOST_ASSERT(newBuffer);
830 GuiWorkArea * wa = workArea(*newBuffer);
832 updateLabels(*newBuffer->masterBuffer());
833 wa = addWorkArea(*newBuffer);
835 //Disconnect the old buffer...there's no new one.
838 connectBuffer(*newBuffer);
839 connectBufferView(wa->bufferView());
840 setCurrentWorkArea(wa);
846 void GuiView::connectBuffer(Buffer & buf)
848 buf.setGuiDelegate(this);
852 void GuiView::disconnectBuffer()
854 if (d.current_work_area_)
855 d.current_work_area_->bufferView().setGuiDelegate(0);
859 void GuiView::connectBufferView(BufferView & bv)
861 bv.setGuiDelegate(this);
865 void GuiView::disconnectBufferView()
867 if (d.current_work_area_)
868 d.current_work_area_->bufferView().setGuiDelegate(0);
872 void GuiView::errors(string const & error_type)
874 ErrorList & el = buffer()->errorList(error_type);
876 showDialog("errorlist", error_type);
880 void GuiView::updateDialog(string const & name, string const & data)
882 if (!isDialogVisible(name))
885 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
886 if (it == d.dialogs_.end())
889 Dialog * const dialog = it->second.get();
890 if (dialog->isVisibleView())
891 dialog->updateData(data);
895 BufferView * GuiView::view()
897 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
901 void GuiView::updateToc()
903 updateDialog("toc", "");
907 void GuiView::updateEmbeddedFiles()
909 updateDialog("embedding", "");
913 void GuiView::autoSave()
915 LYXERR(Debug::INFO, "Running autoSave()");
918 view()->buffer().autoSave();
922 void GuiView::resetAutosaveTimers()
925 d.autosave_timeout_.restart();
929 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
933 Buffer * buf = buffer();
935 /* In LyX/Mac, when a dialog is open, the menus of the
936 application can still be accessed without giving focus to
937 the main window. In this case, we want to disable the menu
938 entries that are buffer-related.
940 Note that this code is not perfect, as bug 1941 attests:
941 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
943 if (cmd.origin == FuncRequest::MENU && !hasFocus())
947 case LFUN_TOOLBAR_TOGGLE:
948 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
951 case LFUN_DIALOG_TOGGLE:
952 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
953 // fall through to set "enable"
954 case LFUN_DIALOG_SHOW: {
955 string const name = cmd.getArg(0);
957 enable = name == "aboutlyx"
958 || name == "file" //FIXME: should be removed.
960 || name == "texinfo";
961 else if (name == "print")
962 enable = buf->isExportable("dvi")
963 && lyxrc.print_command != "none";
964 else if (name == "character") {
968 InsetCode ic = view()->cursor().inset().lyxCode();
969 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
972 else if (name == "latexlog")
973 enable = FileName(buf->logName()).isFileReadable();
974 else if (name == "spellchecker")
975 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
976 enable = !buf->isReadonly();
980 else if (name == "vclog")
981 enable = buf->lyxvc().inUse();
985 case LFUN_DIALOG_UPDATE: {
986 string const name = cmd.getArg(0);
988 enable = name == "prefs";
1000 flag.enabled(false);
1006 void GuiView::dispatch(FuncRequest const & cmd)
1008 Buffer * buf = buffer();
1009 switch(cmd.action) {
1010 case LFUN_BUFFER_SWITCH:
1011 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1014 case LFUN_COMMAND_EXECUTE: {
1015 bool const show_it = cmd.argument() != "off";
1016 d.toolbars_->showCommandBuffer(show_it);
1019 case LFUN_DROP_LAYOUTS_CHOICE:
1021 d.layout_->showPopup();
1024 case LFUN_MENU_OPEN:
1025 d.menubar_->openByName(toqstr(cmd.argument()));
1028 case LFUN_TOOLBAR_TOGGLE: {
1029 string const name = cmd.getArg(0);
1030 bool const allowauto = cmd.getArg(1) == "allowauto";
1031 // it is possible to get current toolbar status like this,...
1032 // but I decide to obey the order of ToolbarBackend::flags
1033 // and disregard real toolbar status.
1034 // toolbars_->saveToolbarInfo();
1036 // toggle state on/off/auto
1037 d.toolbars_->toggleToolbarState(name, allowauto);
1041 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1043 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1047 if (tbi->flags & ToolbarInfo::ON)
1049 else if (tbi->flags & ToolbarInfo::OFF)
1051 else if (tbi->flags & ToolbarInfo::AUTO)
1054 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1055 _(tbi->gui_name), state));
1059 case LFUN_DIALOG_UPDATE: {
1060 string const name = to_utf8(cmd.argument());
1061 // Can only update a dialog connected to an existing inset
1062 Inset * inset = getOpenInset(name);
1064 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1065 inset->dispatch(view()->cursor(), fr);
1066 } else if (name == "paragraph") {
1067 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1068 } else if (name == "prefs") {
1069 updateDialog(name, string());
1074 case LFUN_DIALOG_TOGGLE: {
1075 if (isDialogVisible(cmd.getArg(0)))
1076 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1078 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1082 case LFUN_DIALOG_DISCONNECT_INSET:
1083 disconnectDialog(to_utf8(cmd.argument()));
1086 case LFUN_DIALOG_HIDE: {
1089 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1093 case LFUN_DIALOG_SHOW: {
1094 string const name = cmd.getArg(0);
1095 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1097 if (name == "character") {
1098 data = freefont2string();
1100 showDialog("character", data);
1101 } else if (name == "latexlog") {
1102 Buffer::LogType type;
1103 string const logfile = buf->logName(&type);
1105 case Buffer::latexlog:
1108 case Buffer::buildlog:
1112 data += Lexer::quoteString(logfile);
1113 showDialog("log", data);
1114 } else if (name == "vclog") {
1115 string const data = "vc " +
1116 Lexer::quoteString(buf->lyxvc().getLogFile());
1117 showDialog("log", data);
1119 showDialog(name, data);
1124 theLyXFunc().setLyXView(this);
1130 Buffer const * GuiView::updateInset(Inset const * inset)
1132 if (!d.current_work_area_)
1136 d.current_work_area_->scheduleRedraw();
1138 return &d.current_work_area_->bufferView().buffer();
1142 void GuiView::restartCursor()
1144 /* When we move around, or type, it's nice to be able to see
1145 * the cursor immediately after the keypress.
1147 if (d.current_work_area_)
1148 d.current_work_area_->startBlinkingCursor();
1150 // Take this occasion to update the toobars and layout list.
1157 // This list should be kept in sync with the list of insets in
1158 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1159 // dialog should have the same name as the inset.
1161 char const * const dialognames[] = {
1162 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
1163 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
1164 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
1165 "mathdelimiter", "mathmatrix", "note", "paragraph",
1166 "prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
1168 #ifdef HAVE_LIBAIKSAURUS
1172 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
1174 char const * const * const end_dialognames =
1175 dialognames + (sizeof(dialognames) / sizeof(char *));
1179 cmpCStr(char const * name) : name_(name) {}
1180 bool operator()(char const * other) {
1181 return strcmp(other, name_) == 0;
1188 bool isValidName(string const & name)
1190 return std::find_if(dialognames, end_dialognames,
1191 cmpCStr(name.c_str())) != end_dialognames;
1197 void GuiView::resetDialogs()
1199 // Make sure that no LFUN uses any LyXView.
1200 theLyXFunc().setLyXView(0);
1201 d.toolbars_->init();
1204 d.layout_->updateContents(true);
1205 // Now update controls with current buffer.
1206 theLyXFunc().setLyXView(this);
1211 Dialog * GuiView::find_or_build(string const & name)
1213 if (!isValidName(name))
1216 std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
1218 if (it != d.dialogs_.end())
1219 return it->second.get();
1221 d.dialogs_[name].reset(build(name));
1222 return d.dialogs_[name].get();
1226 void GuiView::showDialog(string const & name, string const & data,
1233 Dialog * dialog = find_or_build(name);
1235 dialog->showData(data);
1237 d.open_insets_[name] = inset;
1243 bool GuiView::isDialogVisible(string const & name) const
1245 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1246 if (it == d.dialogs_.end())
1248 return it->second.get()->isVisibleView();
1252 void GuiView::hideDialog(string const & name, Inset * inset)
1254 // Don't send the signal if we are quitting, because on MSVC it is
1255 // destructed before the cut stack in CutAndPaste.cpp, and this method
1256 // is called from some inset destructor if the cut stack is not empty
1261 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1262 if (it == d.dialogs_.end())
1265 if (inset && inset != getOpenInset(name))
1268 Dialog * const dialog = it->second.get();
1269 if (dialog->isVisibleView())
1271 d.open_insets_[name] = 0;
1275 void GuiView::disconnectDialog(string const & name)
1277 if (!isValidName(name))
1280 if (d.open_insets_.find(name) != d.open_insets_.end())
1281 d.open_insets_[name] = 0;
1285 Inset * GuiView::getOpenInset(string const & name) const
1287 if (!isValidName(name))
1290 std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
1291 return it == d.open_insets_.end() ? 0 : it->second;
1295 void GuiView::hideAll() const
1297 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1298 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1300 for(; it != end; ++it)
1305 void GuiView::hideBufferDependent() const
1307 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1308 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1310 for(; it != end; ++it) {
1311 Dialog * dialog = it->second.get();
1312 if (dialog->isBufferDependent())
1318 void GuiView::updateBufferDependent(bool switched) const
1320 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1321 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1323 for(; it != end; ++it) {
1324 Dialog * dialog = it->second.get();
1325 if (switched && dialog->isBufferDependent()) {
1326 if (dialog->isVisibleView() && dialog->initialiseParams(""))
1327 dialog->updateView();
1331 // A bit clunky, but the dialog will request
1332 // that the kernel provides it with the necessary
1334 dialog->updateDialog(dialog->name());
1340 void GuiView::checkStatus()
1342 std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
1343 std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
1345 for(; it != end; ++it) {
1346 Dialog * const dialog = it->second.get();
1347 if (dialog && dialog->isVisibleView())
1348 dialog->checkStatus();
1354 // will be replaced by a proper factory...
1355 Dialog * createGuiAbout(LyXView & lv);
1356 Dialog * createGuiBibitem(LyXView & lv);
1357 Dialog * createGuiBibtex(LyXView & lv);
1358 Dialog * createGuiBox(LyXView & lv);
1359 Dialog * createGuiBranch(LyXView & lv);
1360 Dialog * createGuiChanges(LyXView & lv);
1361 Dialog * createGuiCharacter(LyXView & lv);
1362 Dialog * createGuiCitation(LyXView & lv);
1363 Dialog * createGuiDelimiter(LyXView & lv);
1364 Dialog * createGuiDocument(LyXView & lv);
1365 Dialog * createGuiErrorList(LyXView & lv);
1366 Dialog * createGuiERT(LyXView & lv);
1367 Dialog * createGuiExternal(LyXView & lv);
1368 Dialog * createGuiFloat(LyXView & lv);
1369 Dialog * createGuiGraphics(LyXView & lv);
1370 Dialog * createGuiInclude(LyXView & lv);
1371 Dialog * createGuiIndex(LyXView & lv);
1372 Dialog * createGuiLabel(LyXView & lv);
1373 Dialog * createGuiListings(LyXView & lv);
1374 Dialog * createGuiLog(LyXView & lv);
1375 Dialog * createGuiMathMatrix(LyXView & lv);
1376 Dialog * createGuiNomenclature(LyXView & lv);
1377 Dialog * createGuiNote(LyXView & lv);
1378 Dialog * createGuiParagraph(LyXView & lv);
1379 Dialog * createGuiPreferences(LyXView & lv);
1380 Dialog * createGuiPrint(LyXView & lv);
1381 Dialog * createGuiRef(LyXView & lv);
1382 Dialog * createGuiSearch(LyXView & lv);
1383 Dialog * createGuiSendTo(LyXView & lv);
1384 Dialog * createGuiShowFile(LyXView & lv);
1385 Dialog * createGuiSpellchecker(LyXView & lv);
1386 Dialog * createGuiTabularCreate(LyXView & lv);
1387 Dialog * createGuiTabular(LyXView & lv);
1388 Dialog * createGuiTexInfo(LyXView & lv);
1389 Dialog * createGuiToc(LyXView & lv);
1390 Dialog * createGuiThesaurus(LyXView & lv);
1391 Dialog * createGuiHyperlink(LyXView & lv);
1392 Dialog * createGuiVSpace(LyXView & lv);
1393 Dialog * createGuiViewSource(LyXView & lv);
1394 Dialog * createGuiWrap(LyXView & lv);
1397 Dialog * GuiView::build(string const & name)
1399 BOOST_ASSERT(isValidName(name));
1401 if (name == "aboutlyx")
1402 return createGuiAbout(*this);
1403 if (name == "bibitem")
1404 return createGuiBibitem(*this);
1405 if (name == "bibtex")
1406 return createGuiBibtex(*this);
1408 return createGuiBox(*this);
1409 if (name == "branch")
1410 return createGuiBranch(*this);
1411 if (name == "changes")
1412 return createGuiChanges(*this);
1413 if (name == "character")
1414 return createGuiCharacter(*this);
1415 if (name == "citation")
1416 return createGuiCitation(*this);
1417 if (name == "document")
1418 return createGuiDocument(*this);
1419 if (name == "errorlist")
1420 return createGuiErrorList(*this);
1422 return createGuiERT(*this);
1423 if (name == "external")
1424 return createGuiExternal(*this);
1426 return createGuiShowFile(*this);
1427 if (name == "findreplace")
1428 return createGuiSearch(*this);
1429 if (name == "float")
1430 return createGuiFloat(*this);
1431 if (name == "graphics")
1432 return createGuiGraphics(*this);
1433 if (name == "include")
1434 return createGuiInclude(*this);
1435 if (name == "index")
1436 return createGuiIndex(*this);
1437 if (name == "nomenclature")
1438 return createGuiNomenclature(*this);
1439 if (name == "label")
1440 return createGuiLabel(*this);
1442 return createGuiLog(*this);
1443 if (name == "view-source")
1444 return createGuiViewSource(*this);
1445 if (name == "mathdelimiter")
1446 return createGuiDelimiter(*this);
1447 if (name == "mathmatrix")
1448 return createGuiMathMatrix(*this);
1450 return createGuiNote(*this);
1451 if (name == "paragraph")
1452 return createGuiParagraph(*this);
1453 if (name == "prefs")
1454 return createGuiPreferences(*this);
1455 if (name == "print")
1456 return createGuiPrint(*this);
1458 return createGuiRef(*this);
1459 if (name == "sendto")
1460 return createGuiSendTo(*this);
1461 if (name == "spellchecker")
1462 return createGuiSpellchecker(*this);
1463 if (name == "tabular")
1464 return createGuiTabular(*this);
1465 if (name == "tabularcreate")
1466 return createGuiTabularCreate(*this);
1467 if (name == "texinfo")
1468 return createGuiTexInfo(*this);
1469 #ifdef HAVE_LIBAIKSAURUS
1470 if (name == "thesaurus")
1471 return createGuiThesaurus(*this);
1474 return createGuiToc(*this);
1476 return createGuiHyperlink(*this);
1477 if (name == "vspace")
1478 return createGuiVSpace(*this);
1480 return createGuiWrap(*this);
1481 if (name == "listings")
1482 return createGuiListings(*this);
1488 } // namespace frontend
1491 #include "GuiView_moc.cpp"