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 "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiCompleter.h"
22 #include "GuiWorkArea.h"
23 #include "GuiKeySymbol.h"
24 #include "GuiToolbar.h"
25 #include "GuiToolbars.h"
29 #include "qt_helpers.h"
31 #include "frontends/alert.h"
33 #include "buffer_funcs.h"
35 #include "BufferList.h"
36 #include "BufferParams.h"
37 #include "BufferView.h"
38 #include "Converter.h"
41 #include "ErrorList.h"
43 #include "FuncStatus.h"
44 #include "FuncRequest.h"
52 #include "Paragraph.h"
53 #include "TextClass.h"
55 #include "ToolbarBackend.h"
58 #include "support/lassert.h"
59 #include "support/debug.h"
60 #include "support/FileName.h"
61 #include "support/filetools.h"
62 #include "support/gettext.h"
63 #include "support/ForkedCalls.h"
64 #include "support/lstrings.h"
65 #include "support/os.h"
66 #include "support/Package.h"
67 #include "support/Timeout.h"
70 #include <QApplication>
71 #include <QCloseEvent>
73 #include <QDesktopWidget>
74 #include <QDragEnterEvent>
82 #include <QPushButton>
86 #include <QStackedWidget>
93 #include <boost/bind.hpp>
95 #ifdef HAVE_SYS_TIME_H
96 # include <sys/time.h>
103 using namespace lyx::support;
110 class BackgroundWidget : public QWidget
115 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
116 /// The text to be written on top of the pixmap
117 QString const text = lyx_version ?
118 qt_("version ") + lyx_version : qt_("unknown version");
119 splash_ = QPixmap(":/images/banner.png");
121 QPainter pain(&splash_);
122 pain.setPen(QColor(0, 0, 0));
124 // The font used to display the version info
125 font.setStyleHint(QFont::SansSerif);
126 font.setWeight(QFont::Bold);
127 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
129 pain.drawText(190, 225, text);
132 void paintEvent(QPaintEvent *)
134 int x = (width() - splash_.width()) / 2;
135 int y = (height() - splash_.height()) / 2;
137 pain.drawPixmap(x, y, splash_);
147 typedef boost::shared_ptr<Dialog> DialogPtr;
149 struct GuiView::GuiViewPrivate
152 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
155 // hardcode here the platform specific icon size
156 smallIconSize = 14; // scaling problems
157 normalIconSize = 20; // ok, default
158 bigIconSize = 26; // better for some math icons
160 splitter_ = new QSplitter;
161 bg_widget_ = new BackgroundWidget;
162 stack_widget_ = new QStackedWidget;
163 stack_widget_->addWidget(bg_widget_);
164 stack_widget_->addWidget(splitter_);
172 delete stack_widget_;
176 QMenu * toolBarPopup(GuiView * parent)
178 // FIXME: translation
179 QMenu * menu = new QMenu(parent);
180 QActionGroup * iconSizeGroup = new QActionGroup(parent);
182 QAction * smallIcons = new QAction(iconSizeGroup);
183 smallIcons->setText(qt_("Small-sized icons"));
184 smallIcons->setCheckable(true);
185 QObject::connect(smallIcons, SIGNAL(triggered()),
186 parent, SLOT(smallSizedIcons()));
187 menu->addAction(smallIcons);
189 QAction * normalIcons = new QAction(iconSizeGroup);
190 normalIcons->setText(qt_("Normal-sized icons"));
191 normalIcons->setCheckable(true);
192 QObject::connect(normalIcons, SIGNAL(triggered()),
193 parent, SLOT(normalSizedIcons()));
194 menu->addAction(normalIcons);
196 QAction * bigIcons = new QAction(iconSizeGroup);
197 bigIcons->setText(qt_("Big-sized icons"));
198 bigIcons->setCheckable(true);
199 QObject::connect(bigIcons, SIGNAL(triggered()),
200 parent, SLOT(bigSizedIcons()));
201 menu->addAction(bigIcons);
203 unsigned int cur = parent->iconSize().width();
204 if ( cur == parent->d.smallIconSize)
205 smallIcons->setChecked(true);
206 else if (cur == parent->d.normalIconSize)
207 normalIcons->setChecked(true);
208 else if (cur == parent->d.bigIconSize)
209 bigIcons->setChecked(true);
216 stack_widget_->setCurrentWidget(bg_widget_);
217 bg_widget_->setUpdatesEnabled(true);
220 TabWorkArea * tabWorkArea(int i)
222 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
225 TabWorkArea * currentTabWorkArea()
227 if (splitter_->count() == 1)
228 // The first TabWorkArea is always the first one, if any.
229 return tabWorkArea(0);
231 for (int i = 0; i != splitter_->count(); ++i) {
232 TabWorkArea * twa = tabWorkArea(i);
233 if (current_work_area_ == twa->currentWorkArea())
237 // None has the focus so we just take the first one.
238 return tabWorkArea(0);
242 GuiWorkArea * current_work_area_;
243 QSplitter * splitter_;
244 QStackedWidget * stack_widget_;
245 BackgroundWidget * bg_widget_;
247 GuiToolbars * toolbars_;
248 /// The main layout box.
250 * \warning Don't Delete! The layout box is actually owned by
251 * whichever toolbar contains it. All the GuiView class needs is a
252 * means of accessing it.
254 * FIXME: replace that with a proper model so that we are not limited
255 * to only one dialog.
257 GuiLayoutBox * layout_;
260 map<string, Inset *> open_insets_;
263 map<string, DialogPtr> dialogs_;
265 unsigned int smallIconSize;
266 unsigned int normalIconSize;
267 unsigned int bigIconSize;
269 QTimer statusbar_timer_;
270 /// auto-saving of buffers
271 Timeout autosave_timeout_;
272 /// flag against a race condition due to multiclicks, see bug #1119
276 TocModels toc_models_;
281 class MenuBar : public QMenuBar
285 MenuBar() : QMenuBar(0) {}
286 void keyPressEvent(QKeyEvent * e) { QMenuBar::keyPressEvent(e); }
291 GuiView::GuiView(int id)
292 : d(*new GuiViewPrivate), id_(id)
294 // GuiToolbars *must* be initialised before the menu bar.
295 d.toolbars_ = new GuiToolbars(*this);
297 // set ourself as the current view. This is needed for the menu bar
298 // filling, at least for the static special menu item on Mac. Otherwise
299 // they are greyed out.
300 theLyXFunc().setLyXView(this);
303 setMenuBar(new MenuBar());
306 // Fill up the menu bar.
307 guiApp->menus().fillMenuBar(menuBar(), this, true);
309 setCentralWidget(d.stack_widget_);
311 // Start autosave timer
312 if (lyxrc.autosave) {
313 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
314 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
315 d.autosave_timeout_.start();
317 connect(&d.statusbar_timer_, SIGNAL(timeout()),
318 this, SLOT(clearMessage()));
320 // We don't want to keep the window in memory if it is closed.
321 setAttribute(Qt::WA_DeleteOnClose, true);
323 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
324 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
325 // since the icon is provided in the application bundle.
326 setWindowIcon(QPixmap(":/images/lyx.png"));
330 setAcceptDrops(true);
332 statusBar()->setSizeGripEnabled(true);
334 // Forbid too small unresizable window because it can happen
335 // with some window manager under X11.
336 setMinimumSize(300, 200);
338 if (!lyxrc.allow_geometry_session)
339 // No session handling, default to a sane size.
340 setGeometry(50, 50, 690, 510);
342 // Now take care of session management.
344 QString const key = "view-" + QString::number(id_);
346 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
347 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
351 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
352 setGeometry(50, 50, 690, 510);
354 setIconSize(settings.value(key + "/icon_size").toSize());
360 if (guiApp->currentView() == this)
361 guiApp->setCurrentView(0);
362 theLyXFunc().setLyXView(0);
368 TocModels & GuiView::tocModels()
370 return d.toc_models_;
374 void GuiView::setFocus()
376 if (d.current_work_area_)
377 d.current_work_area_->setFocus();
383 QMenu * GuiView::createPopupMenu()
385 return d.toolBarPopup(this);
389 void GuiView::showEvent(QShowEvent * e)
391 LYXERR(Debug::GUI, "Passed Geometry "
392 << size().height() << "x" << size().width()
393 << "+" << pos().x() << "+" << pos().y());
395 if (d.splitter_->count() == 0)
396 // No work area, switch to the background widget.
399 QMainWindow::showEvent(e);
403 void GuiView::closeEvent(QCloseEvent * close_event)
405 // it can happen that this event arrives without selecting the view,
406 // e.g. when clicking the close button on a background window.
407 theLyXFunc().setLyXView(this);
409 while (Buffer * b = buffer()) {
411 // This is a child document, just close the tab after saving
412 // but keep the file loaded.
413 if (!saveBuffer(*b)) {
414 close_event->ignore();
417 removeWorkArea(d.current_work_area_);
421 std::vector<int> const & ids = guiApp->viewIds();
422 for (size_type i = 0; i != ids.size(); ++i) {
425 if (guiApp->view(ids[i]).workArea(*b)) {
426 // FIXME 1: should we put an alert box here that the buffer
427 // is viewed elsewhere?
428 // FIXME 2: should we try to save this buffer in any case?
431 // This buffer is also opened in another view, so
432 // but close the associated work area nevertheless.
433 removeWorkArea(d.current_work_area_);
434 // but don't close it.
439 if (b && !closeBuffer(*b, true)) {
440 close_event->ignore();
445 // Make sure that no LFUN use this close to be closed View.
446 theLyXFunc().setLyXView(0);
448 // Save toolbars configuration
449 if (isFullScreen()) {
450 d.toolbars_->toggleFullScreen(!isFullScreen());
454 // Make sure the timer time out will not trigger a statusbar update.
455 d.statusbar_timer_.stop();
457 // Saving fullscreen requires additional tweaks in the toolbar code.
458 // It wouldn't also work under linux natively.
459 if (lyxrc.allow_geometry_session && !isFullScreen()) {
461 QString const key = "view-" + QString::number(id_);
463 settings.setValue(key + "/pos", pos());
464 settings.setValue(key + "/size", size());
466 settings.setValue(key + "/geometry", saveGeometry());
468 settings.setValue(key + "/icon_size", iconSize());
469 d.toolbars_->saveToolbarInfo();
470 // Now take care of all other dialogs:
471 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
472 for (; it!= d.dialogs_.end(); ++it)
473 it->second->saveSession();
476 guiApp->unregisterView(id_);
477 close_event->accept();
481 void GuiView::dragEnterEvent(QDragEnterEvent * event)
483 if (event->mimeData()->hasUrls())
485 /// \todo Ask lyx-devel is this is enough:
486 /// if (event->mimeData()->hasFormat("text/plain"))
487 /// event->acceptProposedAction();
491 void GuiView::dropEvent(QDropEvent* event)
493 QList<QUrl> files = event->mimeData()->urls();
497 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
498 for (int i = 0; i != files.size(); ++i) {
499 string const file = os::internal_path(fromqstr(
500 files.at(i).toLocalFile()));
502 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
507 void GuiView::message(docstring const & str)
509 if (ForkedProcess::iAmAChild())
512 statusBar()->showMessage(toqstr(str));
513 d.statusbar_timer_.stop();
514 d.statusbar_timer_.start(3000);
518 void GuiView::smallSizedIcons()
520 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
524 void GuiView::normalSizedIcons()
526 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
530 void GuiView::bigSizedIcons()
532 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
536 void GuiView::clearMessage()
540 theLyXFunc().setLyXView(this);
541 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
542 d.statusbar_timer_.stop();
546 void GuiView::updateWindowTitle(GuiWorkArea * wa)
548 if (wa != d.current_work_area_)
550 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
551 setWindowIconText(wa->windowIconText());
555 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
558 disconnectBufferView();
559 connectBufferView(wa->bufferView());
560 connectBuffer(wa->bufferView().buffer());
561 d.current_work_area_ = wa;
562 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
563 this, SLOT(updateWindowTitle(GuiWorkArea *)));
564 updateWindowTitle(wa);
568 // The document settings needs to be reinitialised.
569 updateDialog("document", "");
571 // Buffer-dependent dialogs must be updated. This is done here because
572 // some dialogs require buffer()->text.
577 void GuiView::on_lastWorkAreaRemoved()
580 // On Mac close the view if there is no Tab open anymore,
581 // but only if no splitter is visible
582 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
583 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
584 if (twa && twa->count() == 0) {
585 // close the view, as no tab is open anymore
586 QTimer::singleShot(0, this, SLOT(close()));
591 // The document settings needs to be reinitialised.
592 updateDialog("document", "");
598 void GuiView::updateStatusBar()
600 // let the user see the explicit message
601 if (d.statusbar_timer_.isActive())
604 theLyXFunc().setLyXView(this);
605 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
609 bool GuiView::hasFocus() const
611 return qApp->activeWindow() == this;
615 bool GuiView::event(QEvent * e)
619 // Useful debug code:
620 //case QEvent::ActivationChange:
621 //case QEvent::WindowDeactivate:
622 //case QEvent::Paint:
623 //case QEvent::Enter:
624 //case QEvent::Leave:
625 //case QEvent::HoverEnter:
626 //case QEvent::HoverLeave:
627 //case QEvent::HoverMove:
628 //case QEvent::StatusTip:
629 //case QEvent::DragEnter:
630 //case QEvent::DragLeave:
634 case QEvent::WindowActivate: {
635 if (this == guiApp->currentView()) {
637 return QMainWindow::event(e);
639 guiApp->setCurrentView(this);
640 if (d.current_work_area_) {
641 BufferView & bv = d.current_work_area_->bufferView();
642 connectBufferView(bv);
643 connectBuffer(bv.buffer());
644 // The document structure, name and dialogs might have
645 // changed in another view.
647 // The document settings needs to be reinitialised.
648 updateDialog("document", "");
651 setWindowTitle(qt_("LyX"));
652 setWindowIconText(qt_("LyX"));
655 return QMainWindow::event(e);
658 case QEvent::ShortcutOverride: {
661 if (isFullScreen() && menuBar()->isHidden()) {
662 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
663 if (!(ke->modifiers() & Qt::AltModifier)
664 || ke->key() == Qt::Key_Alt)
665 return QMainWindow::event(e);
666 MenuBar * menu_bar = static_cast<MenuBar *>(menuBar());
667 menu_bar->keyPressEvent(ke);
669 if (ke->isAccepted())
671 // Showing and hiding the menubar has the potential to create a bad
672 // flickering due to the window resizing. On Windows Vista, this flicker
673 // is not visible at all.
675 // Otherwise continue with even.
676 return QMainWindow::event(e);
680 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
681 if (d.current_work_area_)
682 // Nothing special to do.
683 return QMainWindow::event(e);
685 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
687 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
688 || ke->key() == Qt::Key_Backtab)
689 return QMainWindow::event(e);
691 // Allow processing of shortcuts that are allowed even when no Buffer
693 theLyXFunc().setLyXView(this);
695 setKeySymbol(&sym, ke);
696 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
702 return QMainWindow::event(e);
707 bool GuiView::focusNextPrevChild(bool /*next*/)
714 void GuiView::setBusy(bool busy)
716 if (d.current_work_area_) {
717 d.current_work_area_->setUpdatesEnabled(!busy);
719 d.current_work_area_->stopBlinkingCursor();
721 d.current_work_area_->startBlinkingCursor();
725 QApplication::setOverrideCursor(Qt::WaitCursor);
727 QApplication::restoreOverrideCursor();
731 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
733 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
735 if (tbinfo.flags & ToolbarInfo::TOP) {
737 addToolBarBreak(Qt::TopToolBarArea);
738 addToolBar(Qt::TopToolBarArea, toolBar);
741 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
742 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
743 #if (QT_VERSION >= 0x040202)
745 addToolBarBreak(Qt::BottomToolBarArea);
747 addToolBar(Qt::BottomToolBarArea, toolBar);
750 if (tbinfo.flags & ToolbarInfo::LEFT) {
751 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
752 #if (QT_VERSION >= 0x040202)
754 addToolBarBreak(Qt::LeftToolBarArea);
756 addToolBar(Qt::LeftToolBarArea, toolBar);
759 if (tbinfo.flags & ToolbarInfo::RIGHT) {
760 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
761 #if (QT_VERSION >= 0x040202)
763 addToolBarBreak(Qt::RightToolBarArea);
765 addToolBar(Qt::RightToolBarArea, toolBar);
768 // The following does not work so I cannot restore to exact toolbar location
770 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
771 toolBar->move(tbinfo.posx, tbinfo.posy);
778 GuiWorkArea * GuiView::workArea(Buffer & buffer)
780 if (TabWorkArea * twa = d.currentTabWorkArea())
781 return twa->workArea(buffer);
786 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
788 // Automatically create a TabWorkArea if there are none yet.
789 TabWorkArea * tab_widget = d.splitter_->count()
790 ? d.currentTabWorkArea() : addTabWorkArea();
791 return tab_widget->addWorkArea(buffer, *this);
795 TabWorkArea * GuiView::addTabWorkArea()
797 TabWorkArea * twa = new TabWorkArea;
798 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
799 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
800 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
801 this, SLOT(on_lastWorkAreaRemoved()));
803 d.splitter_->addWidget(twa);
804 d.stack_widget_->setCurrentWidget(d.splitter_);
809 GuiWorkArea const * GuiView::currentWorkArea() const
811 return d.current_work_area_;
815 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
818 d.current_work_area_ = wa;
819 for (int i = 0; i != d.splitter_->count(); ++i) {
820 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
826 void GuiView::removeWorkArea(GuiWorkArea * wa)
829 if (wa == d.current_work_area_) {
831 disconnectBufferView();
832 d.current_work_area_ = 0;
835 for (int i = 0; i != d.splitter_->count(); ++i) {
836 TabWorkArea * twa = d.tabWorkArea(i);
837 if (!twa->removeWorkArea(wa))
838 // Not found in this tab group.
841 // We found and removed the GuiWorkArea.
843 // No more WorkAreas in this tab group, so delete it.
848 if (d.current_work_area_)
849 // This means that we are not closing the current GuiWorkArea;
852 // Switch to the next GuiWorkArea in the found TabWorkArea.
853 d.current_work_area_ = twa->currentWorkArea();
857 if (d.splitter_->count() == 0)
858 // No more work area, switch to the background widget.
863 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
869 void GuiView::updateLayoutList()
872 d.layout_->updateContents(false);
876 void GuiView::updateToolbars()
878 if (d.current_work_area_) {
880 d.current_work_area_->bufferView().cursor().inMathed();
882 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
884 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
885 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
886 bool const mathmacrotemplate =
887 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
889 d.toolbars_->update(math, table, review, mathmacrotemplate);
891 d.toolbars_->update(false, false, false, false);
895 Buffer * GuiView::buffer()
897 if (d.current_work_area_)
898 return &d.current_work_area_->bufferView().buffer();
903 Buffer const * GuiView::buffer() const
905 if (d.current_work_area_)
906 return &d.current_work_area_->bufferView().buffer();
911 void GuiView::setBuffer(Buffer * newBuffer)
913 LASSERT(newBuffer, /**/);
916 GuiWorkArea * wa = workArea(*newBuffer);
918 updateLabels(*newBuffer->masterBuffer());
919 wa = addWorkArea(*newBuffer);
921 //Disconnect the old buffer...there's no new one.
924 connectBuffer(*newBuffer);
925 connectBufferView(wa->bufferView());
926 setCurrentWorkArea(wa);
932 void GuiView::connectBuffer(Buffer & buf)
934 buf.setGuiDelegate(this);
938 void GuiView::disconnectBuffer()
940 if (d.current_work_area_)
941 d.current_work_area_->bufferView().setGuiDelegate(0);
945 void GuiView::connectBufferView(BufferView & bv)
947 bv.setGuiDelegate(this);
951 void GuiView::disconnectBufferView()
953 if (d.current_work_area_)
954 d.current_work_area_->bufferView().setGuiDelegate(0);
958 void GuiView::errors(string const & error_type)
960 ErrorList & el = buffer()->errorList(error_type);
962 showDialog("errorlist", error_type);
966 void GuiView::structureChanged()
968 d.toc_models_.reset(view());
969 // Navigator needs more than a simple update in this case. It needs to be
971 updateDialog("toc", "");
975 void GuiView::updateDialog(string const & name, string const & data)
977 if (!isDialogVisible(name))
980 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
981 if (it == d.dialogs_.end())
984 Dialog * const dialog = it->second.get();
985 if (dialog->isVisibleView())
986 dialog->initialiseParams(data);
990 BufferView * GuiView::view()
992 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
996 void GuiView::autoSave()
998 LYXERR(Debug::INFO, "Running autoSave()");
1001 view()->buffer().autoSave();
1005 void GuiView::resetAutosaveTimers()
1008 d.autosave_timeout_.restart();
1012 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
1016 Buffer * buf = buffer();
1018 /* In LyX/Mac, when a dialog is open, the menus of the
1019 application can still be accessed without giving focus to
1020 the main window. In this case, we want to disable the menu
1021 entries that are buffer-related.
1023 Note that this code is not perfect, as bug 1941 attests:
1024 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1026 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1029 switch(cmd.action) {
1030 case LFUN_BUFFER_WRITE:
1031 enable = buf && (buf->isUnnamed() || !buf->isClean());
1034 case LFUN_BUFFER_WRITE_AS:
1038 case LFUN_SPLIT_VIEW:
1042 case LFUN_CLOSE_TAB_GROUP:
1043 enable = d.currentTabWorkArea();
1046 case LFUN_TOOLBAR_TOGGLE:
1047 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1050 case LFUN_UI_TOGGLE:
1051 flag.setOnOff(isFullScreen());
1054 case LFUN_DIALOG_TOGGLE:
1055 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1056 // fall through to set "enable"
1057 case LFUN_DIALOG_SHOW: {
1058 string const name = cmd.getArg(0);
1060 enable = name == "aboutlyx"
1061 || name == "file" //FIXME: should be removed.
1063 || name == "texinfo";
1064 else if (name == "print")
1065 enable = buf->isExportable("dvi")
1066 && lyxrc.print_command != "none";
1067 else if (name == "character") {
1071 InsetCode ic = view()->cursor().inset().lyxCode();
1072 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1075 else if (name == "symbols") {
1076 if (!view() || view()->cursor().inMathed())
1079 InsetCode ic = view()->cursor().inset().lyxCode();
1080 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1083 else if (name == "latexlog")
1084 enable = FileName(buf->logName()).isReadableFile();
1085 else if (name == "spellchecker")
1086 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1087 enable = !buf->isReadonly();
1091 else if (name == "vclog")
1092 enable = buf->lyxvc().inUse();
1096 case LFUN_DIALOG_UPDATE: {
1097 string const name = cmd.getArg(0);
1099 enable = name == "prefs";
1103 case LFUN_INSET_APPLY: {
1108 string const name = cmd.getArg(0);
1109 Inset * inset = getOpenInset(name);
1111 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1113 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1114 // Every inset is supposed to handle this
1115 LASSERT(false, /**/);
1119 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1120 flag |= getStatus(fr);
1122 enable = flag.enabled();
1126 case LFUN_COMPLETION_INLINE:
1127 if (!d.current_work_area_
1128 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1132 case LFUN_COMPLETION_POPUP:
1133 if (!d.current_work_area_
1134 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1138 case LFUN_COMPLETION_COMPLETE:
1139 if (!d.current_work_area_
1140 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1152 flag.enabled(false);
1158 static FileName selectTemplateFile()
1160 FileDialog dlg(qt_("Select template file"));
1161 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1162 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1164 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1165 QStringList(qt_("LyX Documents (*.lyx)")));
1167 if (result.first == FileDialog::Later)
1169 if (result.second.isEmpty())
1171 return FileName(fromqstr(result.second));
1175 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1179 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1182 message(_("Document not loaded."));
1187 setBuffer(newBuffer);
1189 // scroll to the position when the file was last closed
1190 if (lyxrc.use_lastfilepos) {
1191 LastFilePosSection::FilePos filepos =
1192 LyX::ref().session().lastFilePos().load(filename);
1193 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1197 LyX::ref().session().lastFiles().add(filename);
1204 void GuiView::openDocument(string const & fname)
1206 string initpath = lyxrc.document_path;
1209 string const trypath = buffer()->filePath();
1210 // If directory is writeable, use this as default.
1211 if (FileName(trypath).isDirWritable())
1217 if (fname.empty()) {
1218 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1219 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1220 dlg.setButton2(qt_("Examples|#E#e"),
1221 toqstr(addPath(package().system_support().absFilename(), "examples")));
1223 FileDialog::Result result =
1224 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1226 if (result.first == FileDialog::Later)
1229 filename = fromqstr(result.second);
1231 // check selected filename
1232 if (filename.empty()) {
1233 message(_("Canceled."));
1239 // get absolute path of file and add ".lyx" to the filename if
1241 FileName const fullname =
1242 fileSearch(string(), filename, "lyx", support::may_not_exist);
1243 if (!fullname.empty())
1244 filename = fullname.absFilename();
1246 // if the file doesn't exist, let the user create one
1247 if (!fullname.exists()) {
1248 // the user specifically chose this name. Believe him.
1249 Buffer * const b = newFile(filename, string(), true);
1255 docstring const disp_fn = makeDisplayPath(filename);
1256 message(bformat(_("Opening document %1$s..."), disp_fn));
1259 Buffer * buf = loadDocument(fullname);
1264 buf->errors("Parse");
1265 str2 = bformat(_("Document %1$s opened."), disp_fn);
1267 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1272 // FIXME: clean that
1273 static bool import(GuiView * lv, FileName const & filename,
1274 string const & format, ErrorList & errorList)
1276 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1278 string loader_format;
1279 vector<string> loaders = theConverters().loaders();
1280 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1281 for (vector<string>::const_iterator it = loaders.begin();
1282 it != loaders.end(); ++it) {
1283 if (!theConverters().isReachable(format, *it))
1286 string const tofile =
1287 support::changeExtension(filename.absFilename(),
1288 formats.extension(*it));
1289 if (!theConverters().convert(0, filename, FileName(tofile),
1290 filename, format, *it, errorList))
1292 loader_format = *it;
1295 if (loader_format.empty()) {
1296 frontend::Alert::error(_("Couldn't import file"),
1297 bformat(_("No information for importing the format %1$s."),
1298 formats.prettyName(format)));
1302 loader_format = format;
1304 if (loader_format == "lyx") {
1305 Buffer * buf = lv->loadDocument(lyxfile);
1310 buf->errors("Parse");
1312 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1316 bool as_paragraphs = loader_format == "textparagraph";
1317 string filename2 = (loader_format == format) ? filename.absFilename()
1318 : support::changeExtension(filename.absFilename(),
1319 formats.extension(loader_format));
1320 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1321 theLyXFunc().setLyXView(lv);
1322 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1329 void GuiView::importDocument(string const & argument)
1332 string filename = split(argument, format, ' ');
1334 LYXERR(Debug::INFO, format << " file: " << filename);
1336 // need user interaction
1337 if (filename.empty()) {
1338 string initpath = lyxrc.document_path;
1340 Buffer const * buf = buffer();
1342 string const trypath = buf->filePath();
1343 // If directory is writeable, use this as default.
1344 if (FileName(trypath).isDirWritable())
1348 docstring const text = bformat(_("Select %1$s file to import"),
1349 formats.prettyName(format));
1351 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1352 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1353 dlg.setButton2(qt_("Examples|#E#e"),
1354 toqstr(addPath(package().system_support().absFilename(), "examples")));
1356 docstring filter = formats.prettyName(format);
1359 filter += from_utf8(formats.extension(format));
1362 FileDialog::Result result =
1363 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1365 if (result.first == FileDialog::Later)
1368 filename = fromqstr(result.second);
1370 // check selected filename
1371 if (filename.empty())
1372 message(_("Canceled."));
1375 if (filename.empty())
1378 // get absolute path of file
1379 FileName const fullname(support::makeAbsPath(filename));
1381 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1383 // Check if the document already is open
1384 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1387 if (!closeBuffer()) {
1388 message(_("Canceled."));
1393 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1395 // if the file exists already, and we didn't do
1396 // -i lyx thefile.lyx, warn
1397 if (lyxfile.exists() && fullname != lyxfile) {
1399 docstring text = bformat(_("The document %1$s already exists.\n\n"
1400 "Do you want to overwrite that document?"), displaypath);
1401 int const ret = Alert::prompt(_("Overwrite document?"),
1402 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1405 message(_("Canceled."));
1410 message(bformat(_("Importing %1$s..."), displaypath));
1411 ErrorList errorList;
1412 if (import(this, fullname, format, errorList))
1413 message(_("imported."));
1415 message(_("file not imported!"));
1417 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1421 void GuiView::newDocument(string const & filename, bool from_template)
1423 FileName initpath(lyxrc.document_path);
1424 Buffer * buf = buffer();
1426 FileName const trypath(buf->filePath());
1427 // If directory is writeable, use this as default.
1428 if (trypath.isDirWritable())
1432 string templatefile = from_template ?
1433 selectTemplateFile().absFilename() : string();
1435 if (filename.empty())
1436 b = newUnnamedFile(templatefile, initpath);
1438 b = newFile(filename, templatefile, true);
1442 // Ensure the cursor is correctly positionned on screen.
1443 view()->showCursor();
1447 void GuiView::insertLyXFile(docstring const & fname)
1449 BufferView * bv = view();
1454 FileName filename(to_utf8(fname));
1456 if (!filename.empty()) {
1457 bv->insertLyXFile(filename);
1461 // Launch a file browser
1463 string initpath = lyxrc.document_path;
1464 string const trypath = bv->buffer().filePath();
1465 // If directory is writeable, use this as default.
1466 if (FileName(trypath).isDirWritable())
1470 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1471 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1472 dlg.setButton2(qt_("Examples|#E#e"),
1473 toqstr(addPath(package().system_support().absFilename(),
1476 FileDialog::Result result = dlg.open(toqstr(initpath),
1477 QStringList(qt_("LyX Documents (*.lyx)")));
1479 if (result.first == FileDialog::Later)
1483 filename.set(fromqstr(result.second));
1485 // check selected filename
1486 if (filename.empty()) {
1487 // emit message signal.
1488 message(_("Canceled."));
1492 bv->insertLyXFile(filename);
1496 void GuiView::insertPlaintextFile(docstring const & fname,
1499 BufferView * bv = view();
1504 FileName filename(to_utf8(fname));
1506 if (!filename.empty()) {
1507 bv->insertPlaintextFile(filename, asParagraph);
1511 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1512 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1514 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1517 if (result.first == FileDialog::Later)
1521 filename.set(fromqstr(result.second));
1523 // check selected filename
1524 if (filename.empty()) {
1525 // emit message signal.
1526 message(_("Canceled."));
1530 bv->insertPlaintextFile(filename, asParagraph);
1534 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1536 FileName fname = b.fileName();
1537 FileName const oldname = fname;
1539 if (!newname.empty()) {
1541 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1543 // Switch to this Buffer.
1546 /// No argument? Ask user through dialog.
1548 FileDialog dlg(qt_("Choose a filename to save document as"),
1549 LFUN_BUFFER_WRITE_AS);
1550 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1551 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1553 if (!isLyXFilename(fname.absFilename()))
1554 fname.changeExtension(".lyx");
1556 FileDialog::Result result =
1557 dlg.save(toqstr(fname.onlyPath().absFilename()),
1558 QStringList(qt_("LyX Documents (*.lyx)")),
1559 toqstr(fname.onlyFileName()));
1561 if (result.first == FileDialog::Later)
1564 fname.set(fromqstr(result.second));
1569 if (!isLyXFilename(fname.absFilename()))
1570 fname.changeExtension(".lyx");
1573 if (FileName(fname).exists()) {
1574 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1575 docstring text = bformat(_("The document %1$s already "
1576 "exists.\n\nDo you want to "
1577 "overwrite that document?"),
1579 int const ret = Alert::prompt(_("Overwrite document?"),
1580 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1583 case 1: return renameBuffer(b, docstring());
1584 case 2: return false;
1588 // Ok, change the name of the buffer
1589 b.setFileName(fname.absFilename());
1591 bool unnamed = b.isUnnamed();
1592 b.setUnnamed(false);
1593 b.saveCheckSum(fname);
1595 if (!saveBuffer(b)) {
1596 b.setFileName(oldname.absFilename());
1597 b.setUnnamed(unnamed);
1598 b.saveCheckSum(oldname);
1606 bool GuiView::saveBuffer(Buffer & b)
1609 return renameBuffer(b, docstring());
1612 LyX::ref().session().lastFiles().add(b.fileName());
1616 // Switch to this Buffer.
1619 // FIXME: we don't tell the user *WHY* the save failed !!
1620 docstring const file = makeDisplayPath(b.absFileName(), 30);
1621 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1622 "Do you want to rename the document and "
1623 "try again?"), file);
1624 int const ret = Alert::prompt(_("Rename and save?"),
1625 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1628 if (!renameBuffer(b, docstring()))
1637 return saveBuffer(b);
1641 bool GuiView::closeBuffer()
1643 Buffer * buf = buffer();
1644 return buf && closeBuffer(*buf);
1648 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1650 // goto bookmark to update bookmark pit.
1651 //FIXME: we should update only the bookmarks related to this buffer!
1652 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1653 theLyXFunc().gotoBookmark(i+1, false, false);
1655 if (buf.isClean() || buf.paragraphs().empty()) {
1656 if (buf.masterBuffer() == &buf && tolastopened)
1657 LyX::ref().session().lastOpened().add(buf.fileName());
1658 theBufferList().release(&buf);
1661 // Switch to this Buffer.
1666 if (buf.isUnnamed())
1667 file = from_utf8(buf.fileName().onlyFileName());
1669 file = buf.fileName().displayName(30);
1671 // Bring this window to top before asking questions.
1675 docstring const text = bformat(_("The document %1$s has unsaved changes."
1676 "\n\nDo you want to save the document or discard the changes?"), file);
1677 int const ret = Alert::prompt(_("Save changed document?"),
1678 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1682 if (!saveBuffer(buf))
1686 // if we crash after this we could
1687 // have no autosave file but I guess
1688 // this is really improbable (Jug)
1689 removeAutosaveFile(buf.absFileName());
1695 // save file names to .lyx/session
1696 // if master/slave are both open, do not save slave since it
1697 // will be automatically loaded when the master is loaded
1698 if (buf.masterBuffer() == &buf && tolastopened)
1699 LyX::ref().session().lastOpened().add(buf.fileName());
1701 theBufferList().release(&buf);
1706 bool GuiView::dispatch(FuncRequest const & cmd)
1708 BufferView * bv = view();
1709 // By default we won't need any update.
1711 bv->cursor().updateFlags(Update::None);
1712 bool dispatched = true;
1714 switch(cmd.action) {
1715 case LFUN_BUFFER_IMPORT:
1716 importDocument(to_utf8(cmd.argument()));
1719 case LFUN_BUFFER_SWITCH:
1720 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1723 case LFUN_BUFFER_NEXT:
1724 setBuffer(theBufferList().next(buffer()));
1727 case LFUN_BUFFER_PREVIOUS:
1728 setBuffer(theBufferList().previous(buffer()));
1731 case LFUN_COMMAND_EXECUTE: {
1732 bool const show_it = cmd.argument() != "off";
1733 d.toolbars_->showCommandBuffer(show_it);
1736 case LFUN_DROP_LAYOUTS_CHOICE:
1738 d.layout_->showPopup();
1741 case LFUN_MENU_OPEN:
1742 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1743 menu->exec(QCursor::pos());
1746 case LFUN_FILE_INSERT:
1747 insertLyXFile(cmd.argument());
1749 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1750 insertPlaintextFile(cmd.argument(), true);
1753 case LFUN_FILE_INSERT_PLAINTEXT:
1754 insertPlaintextFile(cmd.argument(), false);
1757 case LFUN_BUFFER_WRITE:
1759 saveBuffer(bv->buffer());
1762 case LFUN_BUFFER_WRITE_AS:
1764 renameBuffer(bv->buffer(), cmd.argument());
1767 case LFUN_BUFFER_WRITE_ALL: {
1768 Buffer * first = theBufferList().first();
1771 message(_("Saving all documents..."));
1772 // We cannot use a for loop as the buffer list cycles.
1775 if (!b->isClean()) {
1777 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1779 b = theBufferList().next(b);
1780 } while (b != first);
1781 message(_("All documents saved."));
1785 case LFUN_TOOLBAR_TOGGLE: {
1786 string const name = cmd.getArg(0);
1787 bool const allowauto = cmd.getArg(1) == "allowauto";
1788 // it is possible to get current toolbar status like this,...
1789 // but I decide to obey the order of ToolbarBackend::flags
1790 // and disregard real toolbar status.
1791 // toolbars_->saveToolbarInfo();
1793 // toggle state on/off/auto
1794 d.toolbars_->toggleToolbarState(name, allowauto);
1798 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1800 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1804 if (tbi->flags & ToolbarInfo::ON)
1806 else if (tbi->flags & ToolbarInfo::OFF)
1808 else if (tbi->flags & ToolbarInfo::AUTO)
1811 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1812 _(tbi->gui_name), state));
1816 case LFUN_DIALOG_UPDATE: {
1817 string const name = to_utf8(cmd.argument());
1818 // Can only update a dialog connected to an existing inset
1819 Inset * inset = getOpenInset(name);
1821 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1822 inset->dispatch(view()->cursor(), fr);
1823 } else if (name == "paragraph") {
1824 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1825 } else if (name == "prefs") {
1826 updateDialog(name, string());
1831 case LFUN_DIALOG_TOGGLE: {
1832 if (isDialogVisible(cmd.getArg(0)))
1833 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1835 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1839 case LFUN_DIALOG_DISCONNECT_INSET:
1840 disconnectDialog(to_utf8(cmd.argument()));
1843 case LFUN_DIALOG_HIDE: {
1844 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1848 case LFUN_DIALOG_SHOW: {
1849 string const name = cmd.getArg(0);
1850 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1852 if (name == "character") {
1853 data = freefont2string();
1855 showDialog("character", data);
1856 } else if (name == "latexlog") {
1857 Buffer::LogType type;
1858 string const logfile = buffer()->logName(&type);
1860 case Buffer::latexlog:
1863 case Buffer::buildlog:
1867 data += Lexer::quoteString(logfile);
1868 showDialog("log", data);
1869 } else if (name == "vclog") {
1870 string const data = "vc " +
1871 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1872 showDialog("log", data);
1873 } else if (name == "symbols") {
1874 data = bv->cursor().getEncoding()->name();
1876 showDialog("symbols", data);
1878 showDialog(name, data);
1882 case LFUN_INSET_APPLY: {
1883 view()->cursor().recordUndoFullDocument();
1884 string const name = cmd.getArg(0);
1885 Inset * inset = getOpenInset(name);
1887 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1888 inset->dispatch(view()->cursor(), fr);
1890 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1896 case LFUN_UI_TOGGLE:
1898 // Make sure the keyboard focus stays in the work area.
1902 case LFUN_COMPLETION_INLINE:
1903 if (d.current_work_area_)
1904 d.current_work_area_->completer().showInline();
1907 case LFUN_SPLIT_VIEW:
1908 if (Buffer * buf = buffer()) {
1909 string const orientation = cmd.getArg(0);
1910 d.splitter_->setOrientation(orientation == "vertical"
1911 ? Qt::Vertical : Qt::Horizontal);
1912 TabWorkArea * twa = addTabWorkArea();
1913 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1914 setCurrentWorkArea(wa);
1918 case LFUN_CLOSE_TAB_GROUP:
1919 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1921 twa = d.currentTabWorkArea();
1922 // Switch to the next GuiWorkArea in the found TabWorkArea.
1923 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1924 if (d.splitter_->count() == 0)
1925 // No more work area, switch to the background widget.
1930 case LFUN_COMPLETION_POPUP:
1931 if (d.current_work_area_)
1932 d.current_work_area_->completer().showPopup();
1936 case LFUN_COMPLETION_COMPLETE:
1937 if (d.current_work_area_)
1938 d.current_work_area_->completer().tab();
1946 if (isFullScreen()) {
1947 if (menuBar()->isVisible())
1949 if (statusBar()->isVisible())
1950 statusBar()->hide();
1957 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1959 string const arg = cmd.getArg(0);
1960 if (arg == "scrollbar") {
1961 // hide() is of no help
1962 if (d.current_work_area_->verticalScrollBarPolicy() ==
1963 Qt::ScrollBarAlwaysOff)
1965 d.current_work_area_->setVerticalScrollBarPolicy(
1966 Qt::ScrollBarAsNeeded);
1968 d.current_work_area_->setVerticalScrollBarPolicy(
1969 Qt::ScrollBarAlwaysOff);
1972 if (arg == "statusbar") {
1973 statusBar()->setVisible(!statusBar()->isVisible());
1976 if (arg == "menubar") {
1977 menuBar()->setVisible(!menuBar()->isVisible());
1980 #if QT_VERSION >= 0x040300
1981 if (arg == "frame") {
1983 getContentsMargins(&l, &t, &r, &b);
1984 //are the frames in default state?
1985 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1987 setContentsMargins(-2, -2, -2, -2);
1989 setContentsMargins(0, 0, 0, 0);
1994 if (arg != "fullscreen") {
1995 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1999 if (lyxrc.full_screen_toolbars)
2000 d.toolbars_->toggleFullScreen(!isFullScreen());
2002 if (isFullScreen()) {
2003 for (int i = 0; i != d.splitter_->count(); ++i)
2004 d.tabWorkArea(i)->setFullScreen(false);
2005 #if QT_VERSION >= 0x040300
2006 setContentsMargins(0, 0, 0, 0);
2008 setWindowState(windowState() ^ Qt::WindowFullScreen);
2010 statusBar()->show();
2012 for (int i = 0; i != d.splitter_->count(); ++i)
2013 d.tabWorkArea(i)->setFullScreen(true);
2014 #if QT_VERSION >= 0x040300
2015 setContentsMargins(-2, -2, -2, -2);
2017 setWindowState(windowState() ^ Qt::WindowFullScreen);
2018 statusBar()->hide();
2024 Buffer const * GuiView::updateInset(Inset const * inset)
2026 if (!d.current_work_area_)
2030 d.current_work_area_->scheduleRedraw();
2032 return &d.current_work_area_->bufferView().buffer();
2036 void GuiView::restartCursor()
2038 /* When we move around, or type, it's nice to be able to see
2039 * the cursor immediately after the keypress.
2041 if (d.current_work_area_)
2042 d.current_work_area_->startBlinkingCursor();
2044 // Take this occasion to update the other GUI elements.
2049 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2051 if (d.current_work_area_)
2052 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2057 // This list should be kept in sync with the list of insets in
2058 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2059 // dialog should have the same name as the inset.
2061 char const * const dialognames[] = {
2062 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2063 "citation", "document", "errorlist", "ert", "external", "file",
2064 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2065 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2066 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2068 #ifdef HAVE_LIBAIKSAURUS
2072 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2074 char const * const * const end_dialognames =
2075 dialognames + (sizeof(dialognames) / sizeof(char *));
2079 cmpCStr(char const * name) : name_(name) {}
2080 bool operator()(char const * other) {
2081 return strcmp(other, name_) == 0;
2088 bool isValidName(string const & name)
2090 return find_if(dialognames, end_dialognames,
2091 cmpCStr(name.c_str())) != end_dialognames;
2097 void GuiView::resetDialogs()
2099 // Make sure that no LFUN uses any LyXView.
2100 theLyXFunc().setLyXView(0);
2101 // FIXME: the "math panels" toolbar takes an awful lot of time to
2102 // initialise so we don't do that for the time being.
2103 //d.toolbars_->init();
2104 guiApp->menus().fillMenuBar(menuBar(), this);
2106 d.layout_->updateContents(true);
2107 // Now update controls with current buffer.
2108 theLyXFunc().setLyXView(this);
2113 Dialog * GuiView::find_or_build(string const & name)
2115 if (!isValidName(name))
2118 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2120 if (it != d.dialogs_.end())
2121 return it->second.get();
2123 Dialog * dialog = build(name);
2124 d.dialogs_[name].reset(dialog);
2125 if (lyxrc.allow_geometry_session)
2126 dialog->restoreSession();
2131 void GuiView::showDialog(string const & name, string const & data,
2138 Dialog * dialog = find_or_build(name);
2140 dialog->showData(data);
2142 d.open_insets_[name] = inset;
2148 bool GuiView::isDialogVisible(string const & name) const
2150 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2151 if (it == d.dialogs_.end())
2153 return it->second.get()->isVisibleView();
2157 void GuiView::hideDialog(string const & name, Inset * inset)
2159 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2160 if (it == d.dialogs_.end())
2163 if (inset && inset != getOpenInset(name))
2166 Dialog * const dialog = it->second.get();
2167 if (dialog->isVisibleView())
2169 d.open_insets_[name] = 0;
2173 void GuiView::disconnectDialog(string const & name)
2175 if (!isValidName(name))
2178 if (d.open_insets_.find(name) != d.open_insets_.end())
2179 d.open_insets_[name] = 0;
2183 Inset * GuiView::getOpenInset(string const & name) const
2185 if (!isValidName(name))
2188 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2189 return it == d.open_insets_.end() ? 0 : it->second;
2193 void GuiView::hideAll() const
2195 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2196 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2198 for(; it != end; ++it)
2199 it->second->hideView();
2203 void GuiView::updateDialogs()
2205 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2206 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2208 for(; it != end; ++it) {
2209 Dialog * dialog = it->second.get();
2210 if (dialog && dialog->isVisibleView())
2211 dialog->checkStatus();
2219 // will be replaced by a proper factory...
2220 Dialog * createGuiAbout(GuiView & lv);
2221 Dialog * createGuiBibitem(GuiView & lv);
2222 Dialog * createGuiBibtex(GuiView & lv);
2223 Dialog * createGuiBox(GuiView & lv);
2224 Dialog * createGuiBranch(GuiView & lv);
2225 Dialog * createGuiChanges(GuiView & lv);
2226 Dialog * createGuiCharacter(GuiView & lv);
2227 Dialog * createGuiCitation(GuiView & lv);
2228 Dialog * createGuiDelimiter(GuiView & lv);
2229 Dialog * createGuiDocument(GuiView & lv);
2230 Dialog * createGuiErrorList(GuiView & lv);
2231 Dialog * createGuiERT(GuiView & lv);
2232 Dialog * createGuiExternal(GuiView & lv);
2233 Dialog * createGuiFloat(GuiView & lv);
2234 Dialog * createGuiGraphics(GuiView & lv);
2235 Dialog * createGuiHSpace(GuiView & lv);
2236 Dialog * createGuiInclude(GuiView & lv);
2237 Dialog * createGuiLabel(GuiView & lv);
2238 Dialog * createGuiListings(GuiView & lv);
2239 Dialog * createGuiLog(GuiView & lv);
2240 Dialog * createGuiMathMatrix(GuiView & lv);
2241 Dialog * createGuiNomenclature(GuiView & lv);
2242 Dialog * createGuiNote(GuiView & lv);
2243 Dialog * createGuiParagraph(GuiView & lv);
2244 Dialog * createGuiPreferences(GuiView & lv);
2245 Dialog * createGuiPrint(GuiView & lv);
2246 Dialog * createGuiRef(GuiView & lv);
2247 Dialog * createGuiSearch(GuiView & lv);
2248 Dialog * createGuiSendTo(GuiView & lv);
2249 Dialog * createGuiShowFile(GuiView & lv);
2250 Dialog * createGuiSpellchecker(GuiView & lv);
2251 Dialog * createGuiSymbols(GuiView & lv);
2252 Dialog * createGuiTabularCreate(GuiView & lv);
2253 Dialog * createGuiTabular(GuiView & lv);
2254 Dialog * createGuiTexInfo(GuiView & lv);
2255 Dialog * createGuiToc(GuiView & lv);
2256 Dialog * createGuiThesaurus(GuiView & lv);
2257 Dialog * createGuiHyperlink(GuiView & lv);
2258 Dialog * createGuiVSpace(GuiView & lv);
2259 Dialog * createGuiViewSource(GuiView & lv);
2260 Dialog * createGuiWrap(GuiView & lv);
2263 Dialog * GuiView::build(string const & name)
2265 LASSERT(isValidName(name), /**/);
2267 if (name == "aboutlyx")
2268 return createGuiAbout(*this);
2269 if (name == "bibitem")
2270 return createGuiBibitem(*this);
2271 if (name == "bibtex")
2272 return createGuiBibtex(*this);
2274 return createGuiBox(*this);
2275 if (name == "branch")
2276 return createGuiBranch(*this);
2277 if (name == "changes")
2278 return createGuiChanges(*this);
2279 if (name == "character")
2280 return createGuiCharacter(*this);
2281 if (name == "citation")
2282 return createGuiCitation(*this);
2283 if (name == "document")
2284 return createGuiDocument(*this);
2285 if (name == "errorlist")
2286 return createGuiErrorList(*this);
2288 return createGuiERT(*this);
2289 if (name == "external")
2290 return createGuiExternal(*this);
2292 return createGuiShowFile(*this);
2293 if (name == "findreplace")
2294 return createGuiSearch(*this);
2295 if (name == "float")
2296 return createGuiFloat(*this);
2297 if (name == "graphics")
2298 return createGuiGraphics(*this);
2299 if (name == "include")
2300 return createGuiInclude(*this);
2301 if (name == "nomenclature")
2302 return createGuiNomenclature(*this);
2303 if (name == "label")
2304 return createGuiLabel(*this);
2306 return createGuiLog(*this);
2307 if (name == "view-source")
2308 return createGuiViewSource(*this);
2309 if (name == "mathdelimiter")
2310 return createGuiDelimiter(*this);
2311 if (name == "mathmatrix")
2312 return createGuiMathMatrix(*this);
2314 return createGuiNote(*this);
2315 if (name == "paragraph")
2316 return createGuiParagraph(*this);
2317 if (name == "prefs")
2318 return createGuiPreferences(*this);
2319 if (name == "print")
2320 return createGuiPrint(*this);
2322 return createGuiRef(*this);
2323 if (name == "sendto")
2324 return createGuiSendTo(*this);
2325 if (name == "space")
2326 return createGuiHSpace(*this);
2327 if (name == "spellchecker")
2328 return createGuiSpellchecker(*this);
2329 if (name == "symbols")
2330 return createGuiSymbols(*this);
2331 if (name == "tabular")
2332 return createGuiTabular(*this);
2333 if (name == "tabularcreate")
2334 return createGuiTabularCreate(*this);
2335 if (name == "texinfo")
2336 return createGuiTexInfo(*this);
2337 #ifdef HAVE_LIBAIKSAURUS
2338 if (name == "thesaurus")
2339 return createGuiThesaurus(*this);
2342 return createGuiToc(*this);
2344 return createGuiHyperlink(*this);
2345 if (name == "vspace")
2346 return createGuiVSpace(*this);
2348 return createGuiWrap(*this);
2349 if (name == "listings")
2350 return createGuiListings(*this);
2356 } // namespace frontend
2359 #include "GuiView_moc.cpp"