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 "GuiWorkArea.h"
22 #include "GuiKeySymbol.h"
23 #include "GuiToolbar.h"
24 #include "GuiToolbars.h"
27 #include "qt_helpers.h"
29 #include "frontends/alert.h"
31 #include "buffer_funcs.h"
33 #include "BufferList.h"
34 #include "BufferParams.h"
35 #include "BufferView.h"
36 #include "Converter.h"
39 #include "ErrorList.h"
41 #include "FuncStatus.h"
42 #include "FuncRequest.h"
50 #include "Paragraph.h"
51 #include "TextClass.h"
53 #include "ToolbarBackend.h"
56 #include "support/assert.h"
57 #include "support/debug.h"
58 #include "support/FileFilterList.h"
59 #include "support/FileName.h"
60 #include "support/filetools.h"
61 #include "support/gettext.h"
62 #include "support/ForkedCalls.h"
63 #include "support/lstrings.h"
64 #include "support/os.h"
65 #include "support/Package.h"
66 #include "support/Timeout.h"
69 #include <QApplication>
70 #include <QCloseEvent>
72 #include <QDesktopWidget>
73 #include <QDragEnterEvent>
81 #include <QPushButton>
85 #include <QStackedWidget>
92 #include <boost/bind.hpp>
94 #ifdef HAVE_SYS_TIME_H
95 # include <sys/time.h>
102 using namespace lyx::support;
109 class BackgroundWidget : public QWidget
114 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
115 /// The text to be written on top of the pixmap
116 QString const text = lyx_version ?
117 qt_("version ") + lyx_version : qt_("unknown version");
118 splash_ = QPixmap(":/images/banner.png");
120 QPainter pain(&splash_);
121 pain.setPen(QColor(0, 0, 0));
123 // The font used to display the version info
124 font.setStyleHint(QFont::SansSerif);
125 font.setWeight(QFont::Bold);
126 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
128 pain.drawText(190, 225, text);
131 void paintEvent(QPaintEvent *)
133 int x = (width() - splash_.width()) / 2;
134 int y = (height() - splash_.height()) / 2;
136 pain.drawPixmap(x, y, splash_);
146 typedef boost::shared_ptr<Dialog> DialogPtr;
148 struct GuiView::GuiViewPrivate
151 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
154 // hardcode here the platform specific icon size
155 smallIconSize = 14; // scaling problems
156 normalIconSize = 20; // ok, default
157 bigIconSize = 26; // better for some math icons
159 splitter_ = new QSplitter;
160 bg_widget_ = new BackgroundWidget;
161 stack_widget_ = new QStackedWidget;
162 stack_widget_->addWidget(bg_widget_);
163 stack_widget_->addWidget(splitter_);
171 delete stack_widget_;
175 QMenu * toolBarPopup(GuiView * parent)
177 // FIXME: translation
178 QMenu * menu = new QMenu(parent);
179 QActionGroup * iconSizeGroup = new QActionGroup(parent);
181 QAction * smallIcons = new QAction(iconSizeGroup);
182 smallIcons->setText(qt_("Small-sized icons"));
183 smallIcons->setCheckable(true);
184 QObject::connect(smallIcons, SIGNAL(triggered()),
185 parent, SLOT(smallSizedIcons()));
186 menu->addAction(smallIcons);
188 QAction * normalIcons = new QAction(iconSizeGroup);
189 normalIcons->setText(qt_("Normal-sized icons"));
190 normalIcons->setCheckable(true);
191 QObject::connect(normalIcons, SIGNAL(triggered()),
192 parent, SLOT(normalSizedIcons()));
193 menu->addAction(normalIcons);
195 QAction * bigIcons = new QAction(iconSizeGroup);
196 bigIcons->setText(qt_("Big-sized icons"));
197 bigIcons->setCheckable(true);
198 QObject::connect(bigIcons, SIGNAL(triggered()),
199 parent, SLOT(bigSizedIcons()));
200 menu->addAction(bigIcons);
202 unsigned int cur = parent->iconSize().width();
203 if ( cur == parent->d.smallIconSize)
204 smallIcons->setChecked(true);
205 else if (cur == parent->d.normalIconSize)
206 normalIcons->setChecked(true);
207 else if (cur == parent->d.bigIconSize)
208 bigIcons->setChecked(true);
215 stack_widget_->setCurrentWidget(bg_widget_);
216 bg_widget_->setUpdatesEnabled(true);
219 TabWorkArea * tabWorkArea(int i)
221 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
224 TabWorkArea * currentTabWorkArea()
226 if (splitter_->count() == 1)
227 // The first TabWorkArea is always the first one, if any.
228 return tabWorkArea(0);
230 for (int i = 0; i != splitter_->count(); ++i) {
231 TabWorkArea * twa = tabWorkArea(i);
232 if (current_work_area_ == twa->currentWorkArea())
236 // None has the focus so we just take the first one.
237 return tabWorkArea(0);
241 GuiWorkArea * current_work_area_;
242 QSplitter * splitter_;
243 QStackedWidget * stack_widget_;
244 BackgroundWidget * bg_widget_;
246 GuiToolbars * toolbars_;
247 /// The main layout box.
249 * \warning Don't Delete! The layout box is actually owned by
250 * whichever toolbar contains it. All the GuiView class needs is a
251 * means of accessing it.
253 * FIXME: replace that with a proper model so that we are not limited
254 * to only one dialog.
256 GuiLayoutBox * layout_;
259 map<string, Inset *> open_insets_;
262 map<string, DialogPtr> dialogs_;
264 unsigned int smallIconSize;
265 unsigned int normalIconSize;
266 unsigned int bigIconSize;
268 QTimer statusbar_timer_;
269 /// auto-saving of buffers
270 Timeout autosave_timeout_;
271 /// flag against a race condition due to multiclicks, see bug #1119
276 GuiView::GuiView(int id)
277 : d(*new GuiViewPrivate), id_(id)
279 // GuiToolbars *must* be initialised before the menu bar.
280 d.toolbars_ = new GuiToolbars(*this);
282 // set ourself as the current view. This is needed for the menu bar
283 // filling, at least for the static special menu item on Mac. Otherwise
284 // they are greyed out.
285 theLyXFunc().setLyXView(this);
287 // Fill up the menu bar.
288 guiApp->menus().fillMenuBar(menuBar(), this, true);
290 setCentralWidget(d.stack_widget_);
292 // Start autosave timer
293 if (lyxrc.autosave) {
294 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
295 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
296 d.autosave_timeout_.start();
298 connect(&d.statusbar_timer_, SIGNAL(timeout()),
299 this, SLOT(clearMessage()));
301 // We don't want to keep the window in memory if it is closed.
302 setAttribute(Qt::WA_DeleteOnClose, true);
304 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
305 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
306 // since the icon is provided in the application bundle.
307 setWindowIcon(QPixmap(":/images/lyx.png"));
311 setAcceptDrops(true);
313 statusBar()->setSizeGripEnabled(true);
315 // Forbid too small unresizable window because it can happen
316 // with some window manager under X11.
317 setMinimumSize(300, 200);
319 if (!lyxrc.allow_geometry_session)
320 // No session handling, default to a sane size.
321 setGeometry(50, 50, 690, 510);
323 // Now take care of session management.
325 QString const key = "view-" + QString::number(id_);
327 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
328 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
332 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
333 setGeometry(50, 50, 690, 510);
335 setIconSize(settings.value(key + "/icon_size").toSize());
341 if (guiApp->currentView() == this)
342 guiApp->setCurrentView(0);
343 theLyXFunc().setLyXView(0);
349 void GuiView::setFocus()
351 if (d.current_work_area_)
352 d.current_work_area_->setFocus();
358 QMenu * GuiView::createPopupMenu()
360 return d.toolBarPopup(this);
364 void GuiView::showEvent(QShowEvent * e)
366 LYXERR(Debug::GUI, "Passed Geometry "
367 << size().height() << "x" << size().width()
368 << "+" << pos().x() << "+" << pos().y());
370 if (d.splitter_->count() == 0)
371 // No work area, switch to the background widget.
374 QMainWindow::showEvent(e);
378 void GuiView::closeEvent(QCloseEvent * close_event)
380 // it can happen that this event arrives without selecting the view,
381 // e.g. when clicking the close button on a background window.
382 theLyXFunc().setLyXView(this);
384 while (Buffer * b = buffer()) {
386 // This is a child document, just close the tab after saving
387 // but keep the file loaded.
388 if (!saveBuffer(*b)) {
389 close_event->ignore();
392 removeWorkArea(d.current_work_area_);
396 std::vector<int> const & ids = guiApp->viewIds();
397 for (size_type i = 0; i != ids.size(); ++i) {
400 if (guiApp->view(ids[i]).workArea(*b)) {
401 // FIXME 1: should we put an alert box here that the buffer
402 // is viewed elsewhere?
403 // FIXME 2: should we try to save this buffer in any case?
406 // This buffer is also opened in another view, so
407 // but close the associated work area nevertheless.
408 removeWorkArea(d.current_work_area_);
409 // but don't close it.
414 if (b && !closeBuffer(*b)) {
415 close_event->ignore();
420 // Make sure that no LFUN use this close to be closed View.
421 theLyXFunc().setLyXView(0);
423 // Save toolbars configuration
424 if (isFullScreen()) {
425 d.toolbars_->toggleFullScreen(!isFullScreen());
429 // Make sure the timer time out will not trigger a statusbar update.
430 d.statusbar_timer_.stop();
432 // Saving fullscreen requires additional tweaks in the toolbar code.
433 // It wouldn't also work under linux natively.
434 if (lyxrc.allow_geometry_session && !isFullScreen()) {
436 QString const key = "view-" + QString::number(id_);
438 settings.setValue(key + "/pos", pos());
439 settings.setValue(key + "/size", size());
441 settings.setValue(key + "/geometry", saveGeometry());
443 settings.setValue(key + "/icon_size", iconSize());
444 d.toolbars_->saveToolbarInfo();
445 // Now take care of all other dialogs:
446 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
447 for (; it!= d.dialogs_.end(); ++it)
448 it->second->saveSession();
451 guiApp->unregisterView(id_);
452 close_event->accept();
456 void GuiView::dragEnterEvent(QDragEnterEvent * event)
458 if (event->mimeData()->hasUrls())
460 /// \todo Ask lyx-devel is this is enough:
461 /// if (event->mimeData()->hasFormat("text/plain"))
462 /// event->acceptProposedAction();
466 void GuiView::dropEvent(QDropEvent* event)
468 QList<QUrl> files = event->mimeData()->urls();
472 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
473 for (int i = 0; i != files.size(); ++i) {
474 string const file = os::internal_path(fromqstr(
475 files.at(i).toLocalFile()));
477 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
482 void GuiView::message(docstring const & str)
484 if (ForkedProcess::iAmAChild())
487 statusBar()->showMessage(toqstr(str));
488 d.statusbar_timer_.stop();
489 d.statusbar_timer_.start(3000);
493 void GuiView::smallSizedIcons()
495 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
499 void GuiView::normalSizedIcons()
501 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
505 void GuiView::bigSizedIcons()
507 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
511 void GuiView::clearMessage()
515 theLyXFunc().setLyXView(this);
516 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
517 d.statusbar_timer_.stop();
521 void GuiView::updateWindowTitle(GuiWorkArea * wa)
523 if (wa != d.current_work_area_)
525 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
526 setWindowIconText(wa->windowIconText());
530 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
533 disconnectBufferView();
534 connectBufferView(wa->bufferView());
535 connectBuffer(wa->bufferView().buffer());
536 d.current_work_area_ = wa;
537 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
538 this, SLOT(updateWindowTitle(GuiWorkArea *)));
539 updateWindowTitle(wa);
542 // Buffer-dependent dialogs should be updated or
543 // hidden. This should go here because some dialogs (eg ToC)
544 // require bv_->text.
545 updateBufferDependent(true);
552 void GuiView::on_lastWorkAreaRemoved()
555 // On Mac close the view if there is no Tab open anymore,
556 // but only if no splitter is visible
557 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
558 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
559 if (twa && twa->count() == 0) {
560 // close the view, as no tab is open anymore
561 QTimer::singleShot(0, this, SLOT(close()));
568 void GuiView::updateStatusBar()
570 // let the user see the explicit message
571 if (d.statusbar_timer_.isActive())
574 theLyXFunc().setLyXView(this);
575 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
579 bool GuiView::hasFocus() const
581 return qApp->activeWindow() == this;
585 bool GuiView::event(QEvent * e)
589 // Useful debug code:
590 //case QEvent::ActivationChange:
591 //case QEvent::WindowDeactivate:
592 //case QEvent::Paint:
593 //case QEvent::Enter:
594 //case QEvent::Leave:
595 //case QEvent::HoverEnter:
596 //case QEvent::HoverLeave:
597 //case QEvent::HoverMove:
598 //case QEvent::StatusTip:
599 //case QEvent::DragEnter:
600 //case QEvent::DragLeave:
604 case QEvent::WindowActivate: {
605 if (this == guiApp->currentView()) {
607 return QMainWindow::event(e);
609 guiApp->setCurrentView(this);
610 if (d.current_work_area_) {
611 BufferView & bv = d.current_work_area_->bufferView();
612 connectBufferView(bv);
613 connectBuffer(bv.buffer());
614 // The document structure, name and dialogs might have
615 // changed in another view.
616 updateBufferDependent(true);
621 setWindowTitle(qt_("LyX"));
622 setWindowIconText(qt_("LyX"));
625 return QMainWindow::event(e);
628 case QEvent::ShortcutOverride: {
629 if (d.current_work_area_)
630 // Nothing special to do.
631 return QMainWindow::event(e);
633 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
635 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
637 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
638 || ke->key() == Qt::Key_Backtab)
639 return QMainWindow::event(e);
641 // Allow processing of shortcuts that are allowed even when no Buffer
643 theLyXFunc().setLyXView(this);
645 setKeySymbol(&sym, ke);
646 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
652 return QMainWindow::event(e);
657 bool GuiView::focusNextPrevChild(bool /*next*/)
664 void GuiView::setBusy(bool busy)
666 if (d.current_work_area_) {
667 d.current_work_area_->setUpdatesEnabled(!busy);
669 d.current_work_area_->stopBlinkingCursor();
671 d.current_work_area_->startBlinkingCursor();
675 QApplication::setOverrideCursor(Qt::WaitCursor);
677 QApplication::restoreOverrideCursor();
681 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
683 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
685 if (tbinfo.flags & ToolbarInfo::TOP) {
687 addToolBarBreak(Qt::TopToolBarArea);
688 addToolBar(Qt::TopToolBarArea, toolBar);
691 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
692 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
693 #if (QT_VERSION >= 0x040202)
695 addToolBarBreak(Qt::BottomToolBarArea);
697 addToolBar(Qt::BottomToolBarArea, toolBar);
700 if (tbinfo.flags & ToolbarInfo::LEFT) {
701 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
702 #if (QT_VERSION >= 0x040202)
704 addToolBarBreak(Qt::LeftToolBarArea);
706 addToolBar(Qt::LeftToolBarArea, toolBar);
709 if (tbinfo.flags & ToolbarInfo::RIGHT) {
710 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
711 #if (QT_VERSION >= 0x040202)
713 addToolBarBreak(Qt::RightToolBarArea);
715 addToolBar(Qt::RightToolBarArea, toolBar);
718 // The following does not work so I cannot restore to exact toolbar location
720 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
721 toolBar->move(tbinfo.posx, tbinfo.posy);
728 GuiWorkArea * GuiView::workArea(Buffer & buffer)
730 if (TabWorkArea * twa = d.currentTabWorkArea())
731 return twa->workArea(buffer);
736 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
738 // Automatically create a TabWorkArea if there are none yet.
739 TabWorkArea * tab_widget = d.splitter_->count()
740 ? d.currentTabWorkArea() : addTabWorkArea();
741 return tab_widget->addWorkArea(buffer, *this);
745 TabWorkArea * GuiView::addTabWorkArea()
747 TabWorkArea * twa = new TabWorkArea;
748 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
749 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
750 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
751 this, SLOT(on_lastWorkAreaRemoved()));
753 d.splitter_->addWidget(twa);
754 d.stack_widget_->setCurrentWidget(d.splitter_);
759 GuiWorkArea const * GuiView::currentWorkArea() const
761 return d.current_work_area_;
765 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
769 // Changing work area can result from opening a file so
770 // update the toc in any case.
773 d.current_work_area_ = wa;
774 for (int i = 0; i != d.splitter_->count(); ++i) {
775 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
781 void GuiView::removeWorkArea(GuiWorkArea * wa)
784 if (wa == d.current_work_area_) {
786 disconnectBufferView();
787 hideBufferDependent();
788 d.current_work_area_ = 0;
791 for (int i = 0; i != d.splitter_->count(); ++i) {
792 TabWorkArea * twa = d.tabWorkArea(i);
793 if (!twa->removeWorkArea(wa))
794 // Not found in this tab group.
797 // We found and removed the GuiWorkArea.
799 // No more WorkAreas in this tab group, so delete it.
804 if (d.current_work_area_)
805 // This means that we are not closing the current GuiWorkArea;
808 // Switch to the next GuiWorkArea in the found TabWorkArea.
809 d.current_work_area_ = twa->currentWorkArea();
813 if (d.splitter_->count() == 0)
814 // No more work area, switch to the background widget.
819 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
825 void GuiView::updateLayoutList()
828 d.layout_->updateContents(false);
832 void GuiView::updateToolbars()
834 if (d.current_work_area_) {
836 d.current_work_area_->bufferView().cursor().inMathed();
838 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
840 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
841 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
842 bool const mathmacrotemplate =
843 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
845 d.toolbars_->update(math, table, review, mathmacrotemplate);
847 d.toolbars_->update(false, false, false, false);
849 // update read-only status of open dialogs.
854 Buffer * GuiView::buffer()
856 if (d.current_work_area_)
857 return &d.current_work_area_->bufferView().buffer();
862 Buffer const * GuiView::buffer() const
864 if (d.current_work_area_)
865 return &d.current_work_area_->bufferView().buffer();
870 void GuiView::setBuffer(Buffer * newBuffer)
872 LASSERT(newBuffer, /**/);
875 GuiWorkArea * wa = workArea(*newBuffer);
877 updateLabels(*newBuffer->masterBuffer());
878 wa = addWorkArea(*newBuffer);
880 //Disconnect the old buffer...there's no new one.
883 connectBuffer(*newBuffer);
884 connectBufferView(wa->bufferView());
885 setCurrentWorkArea(wa);
891 void GuiView::connectBuffer(Buffer & buf)
893 buf.setGuiDelegate(this);
897 void GuiView::disconnectBuffer()
899 if (d.current_work_area_)
900 d.current_work_area_->bufferView().setGuiDelegate(0);
904 void GuiView::connectBufferView(BufferView & bv)
906 bv.setGuiDelegate(this);
910 void GuiView::disconnectBufferView()
912 if (d.current_work_area_)
913 d.current_work_area_->bufferView().setGuiDelegate(0);
917 void GuiView::errors(string const & error_type)
919 ErrorList & el = buffer()->errorList(error_type);
921 showDialog("errorlist", error_type);
925 void GuiView::updateDialog(string const & name, string const & data)
927 if (!isDialogVisible(name))
930 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
931 if (it == d.dialogs_.end())
934 Dialog * const dialog = it->second.get();
935 if (dialog->isVisibleView())
936 dialog->updateData(data);
940 BufferView * GuiView::view()
942 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
946 void GuiView::updateToc()
948 updateDialog("toc", "");
952 void GuiView::updateEmbeddedFiles()
954 updateDialog("embedding", "");
958 void GuiView::autoSave()
960 LYXERR(Debug::INFO, "Running autoSave()");
963 view()->buffer().autoSave();
967 void GuiView::resetAutosaveTimers()
970 d.autosave_timeout_.restart();
974 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
978 Buffer * buf = buffer();
980 /* In LyX/Mac, when a dialog is open, the menus of the
981 application can still be accessed without giving focus to
982 the main window. In this case, we want to disable the menu
983 entries that are buffer-related.
985 Note that this code is not perfect, as bug 1941 attests:
986 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
988 if (cmd.origin == FuncRequest::MENU && !hasFocus())
992 case LFUN_BUFFER_WRITE:
993 enable = buf && (buf->isUnnamed() || !buf->isClean());
996 case LFUN_BUFFER_WRITE_AS:
1000 case LFUN_SPLIT_VIEW:
1004 case LFUN_CLOSE_TAB_GROUP:
1005 enable = d.currentTabWorkArea();
1008 case LFUN_TOOLBAR_TOGGLE:
1009 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1012 case LFUN_UI_TOGGLE:
1013 flag.setOnOff(isFullScreen());
1016 case LFUN_DIALOG_TOGGLE:
1017 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1018 // fall through to set "enable"
1019 case LFUN_DIALOG_SHOW: {
1020 string const name = cmd.getArg(0);
1022 enable = name == "aboutlyx"
1023 || name == "file" //FIXME: should be removed.
1025 || name == "texinfo";
1026 else if (name == "print")
1027 enable = buf->isExportable("dvi")
1028 && lyxrc.print_command != "none";
1029 else if (name == "character") {
1033 InsetCode ic = view()->cursor().inset().lyxCode();
1034 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1037 else if (name == "symbols") {
1038 if (!view() || view()->cursor().inMathed())
1041 InsetCode ic = view()->cursor().inset().lyxCode();
1042 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1045 else if (name == "latexlog")
1046 enable = FileName(buf->logName()).isReadableFile();
1047 else if (name == "spellchecker")
1048 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1049 enable = !buf->isReadonly();
1053 else if (name == "vclog")
1054 enable = buf->lyxvc().inUse();
1058 case LFUN_DIALOG_UPDATE: {
1059 string const name = cmd.getArg(0);
1061 enable = name == "prefs";
1065 case LFUN_INSET_APPLY: {
1070 string const name = cmd.getArg(0);
1071 Inset * inset = getOpenInset(name);
1073 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1075 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1076 // Every inset is supposed to handle this
1077 LASSERT(false, /**/);
1081 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1082 flag |= getStatus(fr);
1084 enable = flag.enabled();
1088 case LFUN_COMPLETION_INLINE:
1089 if (!d.current_work_area_
1090 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1094 case LFUN_COMPLETION_POPUP:
1095 if (!d.current_work_area_
1096 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1100 case LFUN_COMPLETION_COMPLETE:
1101 if (!d.current_work_area_
1102 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1114 flag.enabled(false);
1120 static FileName selectTemplateFile()
1122 FileDialog dlg(qt_("Select template file"));
1123 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1124 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1126 FileDialog::Result result =
1127 dlg.open(toqstr(lyxrc.template_path),
1128 FileFilterList(_("LyX Documents (*.lyx)")));
1130 if (result.first == FileDialog::Later)
1132 if (result.second.isEmpty())
1134 return FileName(fromqstr(result.second));
1138 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1142 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1145 message(_("Document not loaded."));
1150 setBuffer(newBuffer);
1152 // scroll to the position when the file was last closed
1153 if (lyxrc.use_lastfilepos) {
1154 LastFilePosSection::FilePos filepos =
1155 LyX::ref().session().lastFilePos().load(filename);
1156 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1160 LyX::ref().session().lastFiles().add(filename);
1167 void GuiView::openDocument(string const & fname)
1169 string initpath = lyxrc.document_path;
1172 string const trypath = buffer()->filePath();
1173 // If directory is writeable, use this as default.
1174 if (FileName(trypath).isDirWritable())
1180 if (fname.empty()) {
1181 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1182 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1183 dlg.setButton2(qt_("Examples|#E#e"),
1184 toqstr(addPath(package().system_support().absFilename(), "examples")));
1186 FileDialog::Result result =
1187 dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1189 if (result.first == FileDialog::Later)
1192 filename = fromqstr(result.second);
1194 // check selected filename
1195 if (filename.empty()) {
1196 message(_("Canceled."));
1202 // get absolute path of file and add ".lyx" to the filename if
1204 FileName const fullname =
1205 fileSearch(string(), filename, "lyx", support::may_not_exist);
1206 if (!fullname.empty())
1207 filename = fullname.absFilename();
1209 // if the file doesn't exist, let the user create one
1210 if (!fullname.exists()) {
1211 // the user specifically chose this name. Believe him.
1212 Buffer * const b = newFile(filename, string(), true);
1218 docstring const disp_fn = makeDisplayPath(filename);
1219 message(bformat(_("Opening document %1$s..."), disp_fn));
1222 Buffer * buf = loadDocument(fullname);
1227 buf->errors("Parse");
1228 str2 = bformat(_("Document %1$s opened."), disp_fn);
1230 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1235 // FIXME: clean that
1236 static bool import(GuiView * lv, FileName const & filename,
1237 string const & format, ErrorList & errorList)
1239 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1241 string loader_format;
1242 vector<string> loaders = theConverters().loaders();
1243 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1244 for (vector<string>::const_iterator it = loaders.begin();
1245 it != loaders.end(); ++it) {
1246 if (!theConverters().isReachable(format, *it))
1249 string const tofile =
1250 support::changeExtension(filename.absFilename(),
1251 formats.extension(*it));
1252 if (!theConverters().convert(0, filename, FileName(tofile),
1253 filename, format, *it, errorList))
1255 loader_format = *it;
1258 if (loader_format.empty()) {
1259 frontend::Alert::error(_("Couldn't import file"),
1260 bformat(_("No information for importing the format %1$s."),
1261 formats.prettyName(format)));
1265 loader_format = format;
1267 if (loader_format == "lyx") {
1268 Buffer * buf = lv->loadDocument(lyxfile);
1273 buf->errors("Parse");
1275 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1279 bool as_paragraphs = loader_format == "textparagraph";
1280 string filename2 = (loader_format == format) ? filename.absFilename()
1281 : support::changeExtension(filename.absFilename(),
1282 formats.extension(loader_format));
1283 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1284 theLyXFunc().setLyXView(lv);
1285 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1292 void GuiView::importDocument(string const & argument)
1295 string filename = split(argument, format, ' ');
1297 LYXERR(Debug::INFO, format << " file: " << filename);
1299 // need user interaction
1300 if (filename.empty()) {
1301 string initpath = lyxrc.document_path;
1303 Buffer const * buf = buffer();
1305 string const trypath = buf->filePath();
1306 // If directory is writeable, use this as default.
1307 if (FileName(trypath).isDirWritable())
1311 docstring const text = bformat(_("Select %1$s file to import"),
1312 formats.prettyName(format));
1314 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1315 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1316 dlg.setButton2(qt_("Examples|#E#e"),
1317 toqstr(addPath(package().system_support().absFilename(), "examples")));
1319 docstring filter = formats.prettyName(format);
1322 filter += from_utf8(formats.extension(format));
1325 FileDialog::Result result =
1326 dlg.open(toqstr(initpath), FileFilterList(filter));
1328 if (result.first == FileDialog::Later)
1331 filename = fromqstr(result.second);
1333 // check selected filename
1334 if (filename.empty())
1335 message(_("Canceled."));
1338 if (filename.empty())
1341 // get absolute path of file
1342 FileName const fullname(makeAbsPath(filename));
1344 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1346 // Check if the document already is open
1347 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1350 if (!closeBuffer()) {
1351 message(_("Canceled."));
1356 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1358 // if the file exists already, and we didn't do
1359 // -i lyx thefile.lyx, warn
1360 if (lyxfile.exists() && fullname != lyxfile) {
1362 docstring text = bformat(_("The document %1$s already exists.\n\n"
1363 "Do you want to overwrite that document?"), displaypath);
1364 int const ret = Alert::prompt(_("Overwrite document?"),
1365 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1368 message(_("Canceled."));
1373 message(bformat(_("Importing %1$s..."), displaypath));
1374 ErrorList errorList;
1375 if (import(this, fullname, format, errorList))
1376 message(_("imported."));
1378 message(_("file not imported!"));
1380 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1384 void GuiView::newDocument(string const & filename, bool from_template)
1386 FileName initpath(lyxrc.document_path);
1387 Buffer * buf = buffer();
1389 FileName const trypath(buf->filePath());
1390 // If directory is writeable, use this as default.
1391 if (trypath.isDirWritable())
1395 string templatefile = from_template ?
1396 selectTemplateFile().absFilename() : string();
1398 if (filename.empty())
1399 b = newUnnamedFile(templatefile, initpath);
1401 b = newFile(filename, templatefile, true);
1405 // Ensure the cursor is correctly positionned on screen.
1406 view()->showCursor();
1410 void GuiView::insertLyXFile(docstring const & fname)
1412 BufferView * bv = view();
1417 FileName filename(to_utf8(fname));
1419 if (!filename.empty()) {
1420 bv->insertLyXFile(filename);
1424 // Launch a file browser
1426 string initpath = lyxrc.document_path;
1427 string const trypath = bv->buffer().filePath();
1428 // If directory is writeable, use this as default.
1429 if (FileName(trypath).isDirWritable())
1433 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1434 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1435 dlg.setButton2(qt_("Examples|#E#e"),
1436 toqstr(addPath(package().system_support().absFilename(),
1439 FileDialog::Result result =
1440 dlg.open(toqstr(initpath),
1441 FileFilterList(_("LyX Documents (*.lyx)")));
1443 if (result.first == FileDialog::Later)
1447 filename.set(fromqstr(result.second));
1449 // check selected filename
1450 if (filename.empty()) {
1451 // emit message signal.
1452 message(_("Canceled."));
1456 bv->insertLyXFile(filename);
1460 void GuiView::insertPlaintextFile(docstring const & fname,
1463 BufferView * bv = view();
1468 FileName filename(to_utf8(fname));
1470 if (!filename.empty()) {
1471 bv->insertPlaintextFile(filename, asParagraph);
1475 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1476 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1478 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1481 if (result.first == FileDialog::Later)
1485 filename.set(fromqstr(result.second));
1487 // check selected filename
1488 if (filename.empty()) {
1489 // emit message signal.
1490 message(_("Canceled."));
1494 bv->insertPlaintextFile(filename, asParagraph);
1498 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1500 FileName fname = b.fileName();
1501 FileName const oldname = fname;
1503 if (!newname.empty()) {
1505 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1507 // Switch to this Buffer.
1510 /// No argument? Ask user through dialog.
1512 FileDialog dlg(qt_("Choose a filename to save document as"),
1513 LFUN_BUFFER_WRITE_AS);
1514 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1515 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1517 if (!isLyXFilename(fname.absFilename()))
1518 fname.changeExtension(".lyx");
1520 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1522 FileDialog::Result result =
1523 dlg.save(toqstr(fname.onlyPath().absFilename()),
1525 toqstr(fname.onlyFileName()));
1527 if (result.first == FileDialog::Later)
1530 fname.set(fromqstr(result.second));
1535 if (!isLyXFilename(fname.absFilename()))
1536 fname.changeExtension(".lyx");
1539 if (FileName(fname).exists()) {
1540 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1541 docstring text = bformat(_("The document %1$s already "
1542 "exists.\n\nDo you want to "
1543 "overwrite that document?"),
1545 int const ret = Alert::prompt(_("Overwrite document?"),
1546 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1549 case 1: return renameBuffer(b, docstring());
1550 case 2: return false;
1554 // Ok, change the name of the buffer
1555 b.setFileName(fname.absFilename());
1557 bool unnamed = b.isUnnamed();
1558 b.setUnnamed(false);
1559 b.saveCheckSum(fname);
1561 if (!saveBuffer(b)) {
1562 b.setFileName(oldname.absFilename());
1563 b.setUnnamed(unnamed);
1564 b.saveCheckSum(oldname);
1572 bool GuiView::saveBuffer(Buffer & b)
1575 return renameBuffer(b, docstring());
1578 LyX::ref().session().lastFiles().add(b.fileName());
1582 // Switch to this Buffer.
1585 // FIXME: we don't tell the user *WHY* the save failed !!
1586 docstring const file = makeDisplayPath(b.absFileName(), 30);
1587 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1588 "Do you want to rename the document and "
1589 "try again?"), file);
1590 int const ret = Alert::prompt(_("Rename and save?"),
1591 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1594 if (!renameBuffer(b, docstring()))
1603 return saveBuffer(b);
1607 bool GuiView::closeBuffer()
1609 Buffer * buf = buffer();
1610 return buf && closeBuffer(*buf);
1614 bool GuiView::closeBuffer(Buffer & buf)
1616 // goto bookmark to update bookmark pit.
1617 //FIXME: we should update only the bookmarks related to this buffer!
1618 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1619 theLyXFunc().gotoBookmark(i+1, false, false);
1621 if (buf.isClean() || buf.paragraphs().empty()) {
1622 if (buf.masterBuffer() == &buf)
1623 LyX::ref().session().lastOpened().add(buf.fileName());
1624 theBufferList().release(&buf);
1627 // Switch to this Buffer.
1632 if (buf.isUnnamed())
1633 file = from_utf8(buf.fileName().onlyFileName());
1635 file = buf.fileName().displayName(30);
1637 // Bring this window to top before asking questions.
1641 docstring const text = bformat(_("The document %1$s has unsaved changes."
1642 "\n\nDo you want to save the document or discard the changes?"), file);
1643 int const ret = Alert::prompt(_("Save changed document?"),
1644 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1648 if (!saveBuffer(buf))
1652 // if we crash after this we could
1653 // have no autosave file but I guess
1654 // this is really improbable (Jug)
1655 removeAutosaveFile(buf.absFileName());
1661 // save file names to .lyx/session
1662 // if master/slave are both open, do not save slave since it
1663 // will be automatically loaded when the master is loaded
1664 if (buf.masterBuffer() == &buf)
1665 LyX::ref().session().lastOpened().add(buf.fileName());
1667 theBufferList().release(&buf);
1672 bool GuiView::dispatch(FuncRequest const & cmd)
1674 BufferView * bv = view();
1675 // By default we won't need any update.
1677 bv->cursor().updateFlags(Update::None);
1679 switch(cmd.action) {
1680 case LFUN_BUFFER_IMPORT:
1681 importDocument(to_utf8(cmd.argument()));
1684 case LFUN_BUFFER_SWITCH:
1685 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1688 case LFUN_BUFFER_NEXT:
1689 setBuffer(theBufferList().next(buffer()));
1692 case LFUN_BUFFER_PREVIOUS:
1693 setBuffer(theBufferList().previous(buffer()));
1696 case LFUN_COMMAND_EXECUTE: {
1697 bool const show_it = cmd.argument() != "off";
1698 d.toolbars_->showCommandBuffer(show_it);
1701 case LFUN_DROP_LAYOUTS_CHOICE:
1703 d.layout_->showPopup();
1706 case LFUN_MENU_OPEN:
1707 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1708 menu->exec(QCursor::pos());
1711 case LFUN_FILE_INSERT:
1712 insertLyXFile(cmd.argument());
1714 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1715 insertPlaintextFile(cmd.argument(), true);
1718 case LFUN_FILE_INSERT_PLAINTEXT:
1719 insertPlaintextFile(cmd.argument(), false);
1722 case LFUN_BUFFER_WRITE:
1724 saveBuffer(bv->buffer());
1727 case LFUN_BUFFER_WRITE_AS:
1729 renameBuffer(bv->buffer(), cmd.argument());
1732 case LFUN_BUFFER_WRITE_ALL: {
1733 Buffer * first = theBufferList().first();
1736 message(_("Saving all documents..."));
1737 // We cannot use a for loop as the buffer list cycles.
1740 if (!b->isClean()) {
1742 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1744 b = theBufferList().next(b);
1745 } while (b != first);
1746 message(_("All documents saved."));
1750 case LFUN_TOOLBAR_TOGGLE: {
1751 string const name = cmd.getArg(0);
1752 bool const allowauto = cmd.getArg(1) == "allowauto";
1753 // it is possible to get current toolbar status like this,...
1754 // but I decide to obey the order of ToolbarBackend::flags
1755 // and disregard real toolbar status.
1756 // toolbars_->saveToolbarInfo();
1758 // toggle state on/off/auto
1759 d.toolbars_->toggleToolbarState(name, allowauto);
1763 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1765 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1769 if (tbi->flags & ToolbarInfo::ON)
1771 else if (tbi->flags & ToolbarInfo::OFF)
1773 else if (tbi->flags & ToolbarInfo::AUTO)
1776 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1777 _(tbi->gui_name), state));
1781 case LFUN_DIALOG_UPDATE: {
1782 string const name = to_utf8(cmd.argument());
1783 // Can only update a dialog connected to an existing inset
1784 Inset * inset = getOpenInset(name);
1786 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1787 inset->dispatch(view()->cursor(), fr);
1788 } else if (name == "paragraph") {
1789 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1790 } else if (name == "prefs") {
1791 updateDialog(name, string());
1796 case LFUN_DIALOG_TOGGLE: {
1797 if (isDialogVisible(cmd.getArg(0)))
1798 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1800 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1804 case LFUN_DIALOG_DISCONNECT_INSET:
1805 disconnectDialog(to_utf8(cmd.argument()));
1808 case LFUN_DIALOG_HIDE: {
1809 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1813 case LFUN_DIALOG_SHOW: {
1814 string const name = cmd.getArg(0);
1815 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1817 if (name == "character") {
1818 data = freefont2string();
1820 showDialog("character", data);
1821 } else if (name == "latexlog") {
1822 Buffer::LogType type;
1823 string const logfile = buffer()->logName(&type);
1825 case Buffer::latexlog:
1828 case Buffer::buildlog:
1832 data += Lexer::quoteString(logfile);
1833 showDialog("log", data);
1834 } else if (name == "vclog") {
1835 string const data = "vc " +
1836 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1837 showDialog("log", data);
1838 } else if (name == "symbols") {
1839 data = bv->cursor().getEncoding()->name();
1841 showDialog("symbols", data);
1843 showDialog(name, data);
1847 case LFUN_INSET_APPLY: {
1848 string const name = cmd.getArg(0);
1849 Inset * inset = getOpenInset(name);
1851 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1852 inset->dispatch(view()->cursor(), fr);
1854 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1860 case LFUN_UI_TOGGLE:
1862 // Make sure the keyboard focus stays in the work area.
1866 case LFUN_COMPLETION_INLINE:
1867 if (d.current_work_area_)
1868 d.current_work_area_->completer().showInline();
1871 case LFUN_SPLIT_VIEW:
1872 if (Buffer * buf = buffer()) {
1873 string const orientation = cmd.getArg(0);
1874 d.splitter_->setOrientation(orientation == "vertical"
1875 ? Qt::Vertical : Qt::Horizontal);
1876 TabWorkArea * twa = addTabWorkArea();
1877 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1878 setCurrentWorkArea(wa);
1882 case LFUN_CLOSE_TAB_GROUP:
1883 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1885 twa = d.currentTabWorkArea();
1886 // Switch to the next GuiWorkArea in the found TabWorkArea.
1887 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1888 if (d.splitter_->count() == 0)
1889 // No more work area, switch to the background widget.
1894 case LFUN_COMPLETION_POPUP:
1895 if (d.current_work_area_)
1896 d.current_work_area_->completer().showPopup();
1900 case LFUN_COMPLETION_COMPLETE:
1901 if (d.current_work_area_)
1902 d.current_work_area_->completer().tab();
1913 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1915 string const arg = cmd.getArg(0);
1916 if (arg == "scrollbar") {
1917 // hide() is of no help
1918 if (d.current_work_area_->verticalScrollBarPolicy() ==
1919 Qt::ScrollBarAlwaysOff)
1921 d.current_work_area_->setVerticalScrollBarPolicy(
1922 Qt::ScrollBarAsNeeded);
1924 d.current_work_area_->setVerticalScrollBarPolicy(
1925 Qt::ScrollBarAlwaysOff);
1928 if (arg == "statusbar") {
1929 statusBar()->setVisible(!statusBar()->isVisible());
1932 if (arg == "menubar") {
1933 menuBar()->setVisible(!menuBar()->isVisible());
1936 #if QT_VERSION >= 0x040300
1937 if (arg == "frame") {
1939 getContentsMargins(&l, &t, &r, &b);
1940 //are the frames in default state?
1941 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1943 setContentsMargins(-2, -2, -2, -2);
1945 setContentsMargins(0, 0, 0, 0);
1950 if (arg != "fullscreen") {
1951 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1955 if (lyxrc.full_screen_toolbars)
1956 d.toolbars_->toggleFullScreen(!isFullScreen());
1958 if (isFullScreen()) {
1959 for (int i = 0; i != d.splitter_->count(); ++i)
1960 d.tabWorkArea(i)->setFullScreen(false);
1961 #if QT_VERSION >= 0x040300
1962 setContentsMargins(0, 0, 0, 0);
1964 setWindowState(windowState() ^ Qt::WindowFullScreen);
1966 statusBar()->show();
1968 for (int i = 0; i != d.splitter_->count(); ++i)
1969 d.tabWorkArea(i)->setFullScreen(true);
1970 #if QT_VERSION >= 0x040300
1971 setContentsMargins(-2, -2, -2, -2);
1973 setWindowState(windowState() ^ Qt::WindowFullScreen);
1974 statusBar()->hide();
1980 Buffer const * GuiView::updateInset(Inset const * inset)
1982 if (!d.current_work_area_)
1986 d.current_work_area_->scheduleRedraw();
1988 return &d.current_work_area_->bufferView().buffer();
1992 void GuiView::restartCursor()
1994 /* When we move around, or type, it's nice to be able to see
1995 * the cursor immediately after the keypress.
1997 if (d.current_work_area_)
1998 d.current_work_area_->startBlinkingCursor();
2000 // Take this occasion to update the other GUI elements.
2007 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2009 if (d.current_work_area_)
2010 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2015 // This list should be kept in sync with the list of insets in
2016 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2017 // dialog should have the same name as the inset.
2019 char const * const dialognames[] = {
2020 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2021 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
2022 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2023 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2024 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2026 #ifdef HAVE_LIBAIKSAURUS
2030 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2032 char const * const * const end_dialognames =
2033 dialognames + (sizeof(dialognames) / sizeof(char *));
2037 cmpCStr(char const * name) : name_(name) {}
2038 bool operator()(char const * other) {
2039 return strcmp(other, name_) == 0;
2046 bool isValidName(string const & name)
2048 return find_if(dialognames, end_dialognames,
2049 cmpCStr(name.c_str())) != end_dialognames;
2055 void GuiView::resetDialogs()
2057 // Make sure that no LFUN uses any LyXView.
2058 theLyXFunc().setLyXView(0);
2059 // FIXME: the "math panels" toolbar takes an awful lot of time to
2060 // initialise so we don't do that for the time being.
2061 //d.toolbars_->init();
2062 guiApp->menus().fillMenuBar(menuBar(), this);
2064 d.layout_->updateContents(true);
2065 // Now update controls with current buffer.
2066 theLyXFunc().setLyXView(this);
2071 Dialog * GuiView::find_or_build(string const & name)
2073 if (!isValidName(name))
2076 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2078 if (it != d.dialogs_.end())
2079 return it->second.get();
2081 Dialog * dialog = build(name);
2082 d.dialogs_[name].reset(dialog);
2083 if (lyxrc.allow_geometry_session)
2084 dialog->restoreSession();
2089 void GuiView::showDialog(string const & name, string const & data,
2096 Dialog * dialog = find_or_build(name);
2098 dialog->showData(data);
2100 d.open_insets_[name] = inset;
2106 bool GuiView::isDialogVisible(string const & name) const
2108 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2109 if (it == d.dialogs_.end())
2111 return it->second.get()->isVisibleView();
2115 void GuiView::hideDialog(string const & name, Inset * inset)
2117 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2118 if (it == d.dialogs_.end())
2121 if (inset && inset != getOpenInset(name))
2124 Dialog * const dialog = it->second.get();
2125 if (dialog->isVisibleView())
2127 d.open_insets_[name] = 0;
2131 void GuiView::disconnectDialog(string const & name)
2133 if (!isValidName(name))
2136 if (d.open_insets_.find(name) != d.open_insets_.end())
2137 d.open_insets_[name] = 0;
2141 Inset * GuiView::getOpenInset(string const & name) const
2143 if (!isValidName(name))
2146 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2147 return it == d.open_insets_.end() ? 0 : it->second;
2151 void GuiView::hideAll() const
2153 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2154 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2156 for(; it != end; ++it)
2157 it->second->hideView();
2161 void GuiView::hideBufferDependent() const
2163 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2164 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2166 for(; it != end; ++it) {
2167 Dialog * dialog = it->second.get();
2168 if (dialog->isBufferDependent())
2174 void GuiView::updateBufferDependent(bool switched) const
2176 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2177 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2179 for(; it != end; ++it) {
2180 Dialog * dialog = it->second.get();
2181 if (!dialog->isVisibleView())
2183 if (switched && dialog->isBufferDependent()) {
2184 if (dialog->initialiseParams(""))
2185 dialog->updateView();
2189 // A bit clunky, but the dialog will request
2190 // that the kernel provides it with the necessary
2192 dialog->updateDialog();
2198 void GuiView::checkStatus()
2200 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2201 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2203 for(; it != end; ++it) {
2204 Dialog * const dialog = it->second.get();
2205 if (dialog && dialog->isVisibleView())
2206 dialog->checkStatus();
2212 // will be replaced by a proper factory...
2213 Dialog * createGuiAbout(GuiView & lv);
2214 Dialog * createGuiBibitem(GuiView & lv);
2215 Dialog * createGuiBibtex(GuiView & lv);
2216 Dialog * createGuiBox(GuiView & lv);
2217 Dialog * createGuiBranch(GuiView & lv);
2218 Dialog * createGuiChanges(GuiView & lv);
2219 Dialog * createGuiCharacter(GuiView & lv);
2220 Dialog * createGuiCitation(GuiView & lv);
2221 Dialog * createGuiDelimiter(GuiView & lv);
2222 Dialog * createGuiDocument(GuiView & lv);
2223 Dialog * createGuiErrorList(GuiView & lv);
2224 Dialog * createGuiERT(GuiView & lv);
2225 Dialog * createGuiExternal(GuiView & lv);
2226 Dialog * createGuiFloat(GuiView & lv);
2227 Dialog * createGuiGraphics(GuiView & lv);
2228 Dialog * createGuiHSpace(GuiView & lv);
2229 Dialog * createGuiInclude(GuiView & lv);
2230 Dialog * createGuiLabel(GuiView & lv);
2231 Dialog * createGuiListings(GuiView & lv);
2232 Dialog * createGuiLog(GuiView & lv);
2233 Dialog * createGuiMathMatrix(GuiView & lv);
2234 Dialog * createGuiNomenclature(GuiView & lv);
2235 Dialog * createGuiNote(GuiView & lv);
2236 Dialog * createGuiParagraph(GuiView & lv);
2237 Dialog * createGuiPreferences(GuiView & lv);
2238 Dialog * createGuiPrint(GuiView & lv);
2239 Dialog * createGuiRef(GuiView & lv);
2240 Dialog * createGuiSearch(GuiView & lv);
2241 Dialog * createGuiSendTo(GuiView & lv);
2242 Dialog * createGuiShowFile(GuiView & lv);
2243 Dialog * createGuiSpellchecker(GuiView & lv);
2244 Dialog * createGuiSymbols(GuiView & lv);
2245 Dialog * createGuiTabularCreate(GuiView & lv);
2246 Dialog * createGuiTabular(GuiView & lv);
2247 Dialog * createGuiTexInfo(GuiView & lv);
2248 Dialog * createGuiToc(GuiView & lv);
2249 Dialog * createGuiThesaurus(GuiView & lv);
2250 Dialog * createGuiHyperlink(GuiView & lv);
2251 Dialog * createGuiVSpace(GuiView & lv);
2252 Dialog * createGuiViewSource(GuiView & lv);
2253 Dialog * createGuiWrap(GuiView & lv);
2256 Dialog * GuiView::build(string const & name)
2258 LASSERT(isValidName(name), /**/);
2260 if (name == "aboutlyx")
2261 return createGuiAbout(*this);
2262 if (name == "bibitem")
2263 return createGuiBibitem(*this);
2264 if (name == "bibtex")
2265 return createGuiBibtex(*this);
2267 return createGuiBox(*this);
2268 if (name == "branch")
2269 return createGuiBranch(*this);
2270 if (name == "changes")
2271 return createGuiChanges(*this);
2272 if (name == "character")
2273 return createGuiCharacter(*this);
2274 if (name == "citation")
2275 return createGuiCitation(*this);
2276 if (name == "document")
2277 return createGuiDocument(*this);
2278 if (name == "errorlist")
2279 return createGuiErrorList(*this);
2281 return createGuiERT(*this);
2282 if (name == "external")
2283 return createGuiExternal(*this);
2285 return createGuiShowFile(*this);
2286 if (name == "findreplace")
2287 return createGuiSearch(*this);
2288 if (name == "float")
2289 return createGuiFloat(*this);
2290 if (name == "graphics")
2291 return createGuiGraphics(*this);
2292 if (name == "include")
2293 return createGuiInclude(*this);
2294 if (name == "nomenclature")
2295 return createGuiNomenclature(*this);
2296 if (name == "label")
2297 return createGuiLabel(*this);
2299 return createGuiLog(*this);
2300 if (name == "view-source")
2301 return createGuiViewSource(*this);
2302 if (name == "mathdelimiter")
2303 return createGuiDelimiter(*this);
2304 if (name == "mathmatrix")
2305 return createGuiMathMatrix(*this);
2307 return createGuiNote(*this);
2308 if (name == "paragraph")
2309 return createGuiParagraph(*this);
2310 if (name == "prefs")
2311 return createGuiPreferences(*this);
2312 if (name == "print")
2313 return createGuiPrint(*this);
2315 return createGuiRef(*this);
2316 if (name == "sendto")
2317 return createGuiSendTo(*this);
2318 if (name == "space")
2319 return createGuiHSpace(*this);
2320 if (name == "spellchecker")
2321 return createGuiSpellchecker(*this);
2322 if (name == "symbols")
2323 return createGuiSymbols(*this);
2324 if (name == "tabular")
2325 return createGuiTabular(*this);
2326 if (name == "tabularcreate")
2327 return createGuiTabularCreate(*this);
2328 if (name == "texinfo")
2329 return createGuiTexInfo(*this);
2330 #ifdef HAVE_LIBAIKSAURUS
2331 if (name == "thesaurus")
2332 return createGuiThesaurus(*this);
2335 return createGuiToc(*this);
2337 return createGuiHyperlink(*this);
2338 if (name == "vspace")
2339 return createGuiVSpace(*this);
2341 return createGuiWrap(*this);
2342 if (name == "listings")
2343 return createGuiListings(*this);
2349 } // namespace frontend
2352 #include "GuiView_moc.cpp"