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"
38 #include "ErrorList.h"
40 #include "FuncStatus.h"
41 #include "FuncRequest.h"
42 #include "support/gettext.h"
50 #include "Paragraph.h"
51 #include "TextClass.h"
53 #include "ToolbarBackend.h"
56 #include "support/debug.h"
57 #include "support/FileFilterList.h"
58 #include "support/FileName.h"
59 #include "support/filetools.h"
60 #include "support/ForkedCalls.h"
61 #include "support/lstrings.h"
62 #include "support/os.h"
63 #include "support/Package.h"
64 #include "support/Timeout.h"
67 #include <QApplication>
68 #include <QCloseEvent>
70 #include <QDesktopWidget>
71 #include <QDragEnterEvent>
79 #include <QPushButton>
83 #include <QStackedWidget>
90 #include <boost/assert.hpp>
91 #include <boost/bind.hpp>
93 #ifdef HAVE_SYS_TIME_H
94 # include <sys/time.h>
101 using namespace lyx::support;
108 class BackgroundWidget : public QWidget
113 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
114 /// The text to be written on top of the pixmap
115 QString const text = lyx_version ? lyx_version : qt_("unknown version");
116 splash_ = QPixmap(":/images/banner.png");
118 QPainter pain(&splash_);
119 pain.setPen(QColor(255, 255, 0));
121 // The font used to display the version info
122 font.setStyleHint(QFont::SansSerif);
123 font.setWeight(QFont::Bold);
124 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
126 pain.drawText(260, 270, text);
129 void paintEvent(QPaintEvent *)
131 int x = (width() - splash_.width()) / 2;
132 int y = (height() - splash_.height()) / 2;
134 pain.drawPixmap(x, y, splash_);
144 typedef boost::shared_ptr<Dialog> DialogPtr;
146 struct GuiView::GuiViewPrivate
149 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
152 // hardcode here the platform specific icon size
153 smallIconSize = 14; // scaling problems
154 normalIconSize = 20; // ok, default
155 bigIconSize = 26; // better for some math icons
157 splitter_ = new QSplitter;
158 bg_widget_ = new BackgroundWidget;
159 stack_widget_ = new QStackedWidget;
160 stack_widget_->addWidget(bg_widget_);
161 stack_widget_->addWidget(splitter_);
169 delete stack_widget_;
173 QMenu * toolBarPopup(GuiView * parent)
175 // FIXME: translation
176 QMenu * menu = new QMenu(parent);
177 QActionGroup * iconSizeGroup = new QActionGroup(parent);
179 QAction * smallIcons = new QAction(iconSizeGroup);
180 smallIcons->setText(qt_("Small-sized icons"));
181 smallIcons->setCheckable(true);
182 QObject::connect(smallIcons, SIGNAL(triggered()),
183 parent, SLOT(smallSizedIcons()));
184 menu->addAction(smallIcons);
186 QAction * normalIcons = new QAction(iconSizeGroup);
187 normalIcons->setText(qt_("Normal-sized icons"));
188 normalIcons->setCheckable(true);
189 QObject::connect(normalIcons, SIGNAL(triggered()),
190 parent, SLOT(normalSizedIcons()));
191 menu->addAction(normalIcons);
193 QAction * bigIcons = new QAction(iconSizeGroup);
194 bigIcons->setText(qt_("Big-sized icons"));
195 bigIcons->setCheckable(true);
196 QObject::connect(bigIcons, SIGNAL(triggered()),
197 parent, SLOT(bigSizedIcons()));
198 menu->addAction(bigIcons);
200 unsigned int cur = parent->iconSize().width();
201 if ( cur == parent->d.smallIconSize)
202 smallIcons->setChecked(true);
203 else if (cur == parent->d.normalIconSize)
204 normalIcons->setChecked(true);
205 else if (cur == parent->d.bigIconSize)
206 bigIcons->setChecked(true);
213 stack_widget_->setCurrentWidget(bg_widget_);
214 bg_widget_->setUpdatesEnabled(true);
217 TabWorkArea * tabWorkArea(int i)
219 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
222 TabWorkArea * currentTabWorkArea()
224 if (splitter_->count() == 1)
225 // The first TabWorkArea is always the first one, if any.
226 return tabWorkArea(0);
228 for (int i = 0; i != splitter_->count(); ++i) {
229 TabWorkArea * twa = tabWorkArea(i);
230 if (current_work_area_ == twa->currentWorkArea())
234 // None has the focus so we just take the first one.
235 return tabWorkArea(0);
239 GuiWorkArea * current_work_area_;
240 QSplitter * splitter_;
241 QStackedWidget * stack_widget_;
242 BackgroundWidget * bg_widget_;
244 GuiToolbars * toolbars_;
245 /// The main layout box.
247 * \warning Don't Delete! The layout box is actually owned by
248 * whichever toolbar contains it. All the GuiView class needs is a
249 * means of accessing it.
251 * FIXME: replace that with a proper model so that we are not limited
252 * to only one dialog.
254 GuiLayoutBox * layout_;
257 map<string, Inset *> open_insets_;
260 map<string, DialogPtr> dialogs_;
262 unsigned int smallIconSize;
263 unsigned int normalIconSize;
264 unsigned int bigIconSize;
266 QTimer statusbar_timer_;
267 /// auto-saving of buffers
268 Timeout autosave_timeout_;
269 /// flag against a race condition due to multiclicks, see bug #1119
274 GuiView::GuiView(int id)
275 : d(*new GuiViewPrivate), id_(id)
277 // GuiToolbars *must* be initialised before the menu bar.
278 d.toolbars_ = new GuiToolbars(*this);
280 // set ourself as the current view. This is needed for the menu bar
281 // filling, at least for the static special menu item on Mac. Otherwise
282 // they are greyed out.
283 theLyXFunc().setLyXView(this);
285 // Fill up the menu bar.
286 guiApp->menus().fillMenuBar(menuBar(), this, true);
288 setCentralWidget(d.stack_widget_);
290 // Start autosave timer
291 if (lyxrc.autosave) {
292 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
293 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
294 d.autosave_timeout_.start();
296 connect(&d.statusbar_timer_, SIGNAL(timeout()),
297 this, SLOT(clearMessage()));
299 // We don't want to keep the window in memory if it is closed.
300 setAttribute(Qt::WA_DeleteOnClose, true);
303 // assign an icon to main form. We do not do it under Qt/Mac,
304 // since the icon is provided in the application bundle.
305 setWindowIcon(QPixmap(":/images/lyx.png"));
309 setAcceptDrops(true);
311 statusBar()->setSizeGripEnabled(true);
313 // Forbid too small unresizable window because it can happen
314 // with some window manager under X11.
315 setMinimumSize(300, 200);
317 if (!lyxrc.allow_geometry_session)
318 // No session handling, default to a sane size.
319 setGeometry(50, 50, 690, 510);
321 // Now take care of session management.
323 QString const key = "view-" + QString::number(id_);
325 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
326 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
330 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
331 setGeometry(50, 50, 690, 510);
333 setIconSize(settings.value(key + "/icon_size").toSize());
339 if (guiApp->currentView() == this)
340 guiApp->setCurrentView(0);
341 theLyXFunc().setLyXView(0);
347 void GuiView::setFocus()
349 if (d.current_work_area_)
350 d.current_work_area_->setFocus();
356 QMenu * GuiView::createPopupMenu()
358 return d.toolBarPopup(this);
362 void GuiView::showEvent(QShowEvent * e)
364 LYXERR(Debug::GUI, "Passed Geometry "
365 << size().height() << "x" << size().width()
366 << "+" << pos().x() << "+" << pos().y());
368 if (d.splitter_->count() == 0)
369 // No work area, switch to the background widget.
372 QMainWindow::showEvent(e);
376 void GuiView::closeEvent(QCloseEvent * close_event)
378 // it can happen that this event arrives without selecting the view,
379 // e.g. when clicking the close button on a background window.
380 theLyXFunc().setLyXView(this);
382 while (Buffer * b = buffer()) {
384 // This is a child document, just close the tab after saving
385 // but keep the file loaded.
386 if (!saveBuffer(*b)) {
387 close_event->ignore();
390 removeWorkArea(d.current_work_area_);
394 std::vector<int> const & ids = guiApp->viewIds();
395 for (size_type i = 0; i != ids.size(); ++i) {
398 if (guiApp->view(ids[i]).workArea(*b)) {
399 // FIXME 1: should we put an alert box here that the buffer
400 // is viewed elsewhere?
401 // FIXME 2: should we try to save this buffer in any case?
404 // This buffer is also opened in another view, so
405 // but close the associated work area nevertheless.
406 removeWorkArea(d.current_work_area_);
407 // but don't close it.
412 if (b && !closeBuffer(*b)) {
413 close_event->ignore();
418 // Make sure that no LFUN use this close to be closed View.
419 theLyXFunc().setLyXView(0);
421 // Save toolbars configuration
422 if (isFullScreen()) {
423 d.toolbars_->toggleFullScreen(!isFullScreen());
427 // Make sure the timer time out will not trigger a statusbar update.
428 d.statusbar_timer_.stop();
430 // Saving fullscreen requires additional tweaks in the toolbar code.
431 // It wouldn't also work under linux natively.
432 if (lyxrc.allow_geometry_session && !isFullScreen()) {
434 QString const key = "view-" + QString::number(id_);
436 settings.setValue(key + "/pos", pos());
437 settings.setValue(key + "/size", size());
439 settings.setValue(key + "/geometry", saveGeometry());
441 settings.setValue(key + "/icon_size", iconSize());
442 d.toolbars_->saveToolbarInfo();
443 // Now take care of all other dialogs:
444 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
445 for (; it!= d.dialogs_.end(); ++it)
446 it->second->saveSession();
449 guiApp->unregisterView(id_);
450 close_event->accept();
454 void GuiView::dragEnterEvent(QDragEnterEvent * event)
456 if (event->mimeData()->hasUrls())
458 /// \todo Ask lyx-devel is this is enough:
459 /// if (event->mimeData()->hasFormat("text/plain"))
460 /// event->acceptProposedAction();
464 void GuiView::dropEvent(QDropEvent* event)
466 QList<QUrl> files = event->mimeData()->urls();
470 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
471 for (int i = 0; i != files.size(); ++i) {
472 string const file = os::internal_path(fromqstr(
473 files.at(i).toLocalFile()));
475 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
480 void GuiView::message(docstring const & str)
482 if (ForkedProcess::iAmAChild())
485 statusBar()->showMessage(toqstr(str));
486 d.statusbar_timer_.stop();
487 d.statusbar_timer_.start(3000);
491 void GuiView::smallSizedIcons()
493 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
497 void GuiView::normalSizedIcons()
499 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
503 void GuiView::bigSizedIcons()
505 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
509 void GuiView::clearMessage()
513 theLyXFunc().setLyXView(this);
514 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
515 d.statusbar_timer_.stop();
519 void GuiView::updateWindowTitle(GuiWorkArea * wa)
521 if (wa != d.current_work_area_)
523 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
524 setWindowIconText(wa->windowIconText());
528 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
531 disconnectBufferView();
532 connectBufferView(wa->bufferView());
533 connectBuffer(wa->bufferView().buffer());
534 d.current_work_area_ = wa;
535 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
536 this, SLOT(updateWindowTitle(GuiWorkArea *)));
537 updateWindowTitle(wa);
540 // Buffer-dependent dialogs should be updated or
541 // hidden. This should go here because some dialogs (eg ToC)
542 // require bv_->text.
543 updateBufferDependent(true);
550 void GuiView::on_lastWorkAreaRemoved()
553 // On Mac close the view if there is no Tab open anymore,
554 // but only if no splitter is visible
555 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
556 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
557 if (twa && twa->count() == 0) {
558 // close the view, as no tab is open anymore
559 QTimer::singleShot(0, this, SLOT(close()));
566 void GuiView::updateStatusBar()
568 // let the user see the explicit message
569 if (d.statusbar_timer_.isActive())
572 theLyXFunc().setLyXView(this);
573 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
577 bool GuiView::hasFocus() const
579 return qApp->activeWindow() == this;
583 bool GuiView::event(QEvent * e)
587 // Useful debug code:
588 //case QEvent::ActivationChange:
589 //case QEvent::WindowDeactivate:
590 //case QEvent::Paint:
591 //case QEvent::Enter:
592 //case QEvent::Leave:
593 //case QEvent::HoverEnter:
594 //case QEvent::HoverLeave:
595 //case QEvent::HoverMove:
596 //case QEvent::StatusTip:
597 //case QEvent::DragEnter:
598 //case QEvent::DragLeave:
602 case QEvent::WindowActivate: {
603 if (this == guiApp->currentView()) {
605 return QMainWindow::event(e);
607 guiApp->setCurrentView(this);
608 if (d.current_work_area_) {
609 BufferView & bv = d.current_work_area_->bufferView();
610 connectBufferView(bv);
611 connectBuffer(bv.buffer());
612 // The document structure, name and dialogs might have
613 // changed in another view.
614 updateBufferDependent(true);
619 setWindowTitle(qt_("LyX"));
620 setWindowIconText(qt_("LyX"));
623 return QMainWindow::event(e);
626 case QEvent::ShortcutOverride: {
627 if (d.current_work_area_)
628 // Nothing special to do.
629 return QMainWindow::event(e);
631 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
633 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
635 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
636 || ke->key() == Qt::Key_Backtab)
637 return QMainWindow::event(e);
639 // Allow processing of shortcuts that are allowed even when no Buffer
641 theLyXFunc().setLyXView(this);
643 setKeySymbol(&sym, ke);
644 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
650 return QMainWindow::event(e);
655 bool GuiView::focusNextPrevChild(bool /*next*/)
662 void GuiView::setBusy(bool busy)
664 if (d.current_work_area_) {
665 d.current_work_area_->setUpdatesEnabled(!busy);
667 d.current_work_area_->stopBlinkingCursor();
669 d.current_work_area_->startBlinkingCursor();
673 QApplication::setOverrideCursor(Qt::WaitCursor);
675 QApplication::restoreOverrideCursor();
679 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
681 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
683 if (tbinfo.flags & ToolbarInfo::TOP) {
685 addToolBarBreak(Qt::TopToolBarArea);
686 addToolBar(Qt::TopToolBarArea, toolBar);
689 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
690 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
691 #if (QT_VERSION >= 0x040202)
693 addToolBarBreak(Qt::BottomToolBarArea);
695 addToolBar(Qt::BottomToolBarArea, toolBar);
698 if (tbinfo.flags & ToolbarInfo::LEFT) {
699 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
700 #if (QT_VERSION >= 0x040202)
702 addToolBarBreak(Qt::LeftToolBarArea);
704 addToolBar(Qt::LeftToolBarArea, toolBar);
707 if (tbinfo.flags & ToolbarInfo::RIGHT) {
708 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
709 #if (QT_VERSION >= 0x040202)
711 addToolBarBreak(Qt::RightToolBarArea);
713 addToolBar(Qt::RightToolBarArea, toolBar);
716 // The following does not work so I cannot restore to exact toolbar location
718 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
719 toolBar->move(tbinfo.posx, tbinfo.posy);
726 GuiWorkArea * GuiView::workArea(Buffer & buffer)
728 if (TabWorkArea * twa = d.currentTabWorkArea())
729 return twa->workArea(buffer);
734 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
736 // Automatically create a TabWorkArea if there are none yet.
737 TabWorkArea * tab_widget = d.splitter_->count()
738 ? d.currentTabWorkArea() : addTabWorkArea();
739 return tab_widget->addWorkArea(buffer, *this);
743 TabWorkArea * GuiView::addTabWorkArea()
745 TabWorkArea * twa = new TabWorkArea;
746 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
747 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
748 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
749 this, SLOT(on_lastWorkAreaRemoved()));
751 d.splitter_->addWidget(twa);
752 d.stack_widget_->setCurrentWidget(d.splitter_);
757 GuiWorkArea const * GuiView::currentWorkArea() const
759 return d.current_work_area_;
763 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
767 // Changing work area can result from opening a file so
768 // update the toc in any case.
771 d.current_work_area_ = wa;
772 for (int i = 0; i != d.splitter_->count(); ++i) {
773 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
779 void GuiView::removeWorkArea(GuiWorkArea * wa)
782 if (wa == d.current_work_area_) {
784 disconnectBufferView();
785 hideBufferDependent();
786 d.current_work_area_ = 0;
789 for (int i = 0; i != d.splitter_->count(); ++i) {
790 TabWorkArea * twa = d.tabWorkArea(i);
791 if (!twa->removeWorkArea(wa))
792 // Not found in this tab group.
795 // We found and removed the GuiWorkArea.
797 // No more WorkAreas in this tab group, so delete it.
802 if (d.current_work_area_)
803 // This means that we are not closing the current GuiWorkArea;
806 // Switch to the next GuiWorkArea in the found TabWorkArea.
807 d.current_work_area_ = twa->currentWorkArea();
811 if (d.splitter_->count() == 0)
812 // No more work area, switch to the background widget.
817 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
823 void GuiView::updateLayoutList()
826 d.layout_->updateContents(false);
830 void GuiView::updateToolbars()
832 if (d.current_work_area_) {
834 d.current_work_area_->bufferView().cursor().inMathed();
836 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
838 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
839 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
840 bool const mathmacrotemplate =
841 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
843 d.toolbars_->update(math, table, review, mathmacrotemplate);
845 d.toolbars_->update(false, false, false, false);
847 // update read-only status of open dialogs.
852 Buffer * GuiView::buffer()
854 if (d.current_work_area_)
855 return &d.current_work_area_->bufferView().buffer();
860 Buffer const * GuiView::buffer() const
862 if (d.current_work_area_)
863 return &d.current_work_area_->bufferView().buffer();
868 void GuiView::setBuffer(Buffer * newBuffer)
870 BOOST_ASSERT(newBuffer);
873 GuiWorkArea * wa = workArea(*newBuffer);
875 updateLabels(*newBuffer->masterBuffer());
876 wa = addWorkArea(*newBuffer);
878 //Disconnect the old buffer...there's no new one.
881 connectBuffer(*newBuffer);
882 connectBufferView(wa->bufferView());
883 setCurrentWorkArea(wa);
889 void GuiView::connectBuffer(Buffer & buf)
891 buf.setGuiDelegate(this);
895 void GuiView::disconnectBuffer()
897 if (d.current_work_area_)
898 d.current_work_area_->bufferView().setGuiDelegate(0);
902 void GuiView::connectBufferView(BufferView & bv)
904 bv.setGuiDelegate(this);
908 void GuiView::disconnectBufferView()
910 if (d.current_work_area_)
911 d.current_work_area_->bufferView().setGuiDelegate(0);
915 void GuiView::errors(string const & error_type)
917 ErrorList & el = buffer()->errorList(error_type);
919 showDialog("errorlist", error_type);
923 void GuiView::updateDialog(string const & name, string const & data)
925 if (!isDialogVisible(name))
928 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
929 if (it == d.dialogs_.end())
932 Dialog * const dialog = it->second.get();
933 if (dialog->isVisibleView())
934 dialog->updateData(data);
938 BufferView * GuiView::view()
940 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
944 void GuiView::updateToc()
946 updateDialog("toc", "");
950 void GuiView::updateEmbeddedFiles()
952 updateDialog("embedding", "");
956 void GuiView::autoSave()
958 LYXERR(Debug::INFO, "Running autoSave()");
961 view()->buffer().autoSave();
965 void GuiView::resetAutosaveTimers()
968 d.autosave_timeout_.restart();
972 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
976 Buffer * buf = buffer();
978 /* In LyX/Mac, when a dialog is open, the menus of the
979 application can still be accessed without giving focus to
980 the main window. In this case, we want to disable the menu
981 entries that are buffer-related.
983 Note that this code is not perfect, as bug 1941 attests:
984 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
986 if (cmd.origin == FuncRequest::MENU && !hasFocus())
990 case LFUN_BUFFER_WRITE:
991 enable = buf && (buf->isUnnamed() || !buf->isClean());
994 case LFUN_BUFFER_WRITE_AS:
998 case LFUN_SPLIT_VIEW:
1002 case LFUN_CLOSE_TAB_GROUP:
1003 enable = d.currentTabWorkArea();
1006 case LFUN_TOOLBAR_TOGGLE:
1007 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1010 case LFUN_UI_TOGGLE:
1011 flag.setOnOff(isFullScreen());
1014 case LFUN_DIALOG_TOGGLE:
1015 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1016 // fall through to set "enable"
1017 case LFUN_DIALOG_SHOW: {
1018 string const name = cmd.getArg(0);
1020 enable = name == "aboutlyx"
1021 || name == "file" //FIXME: should be removed.
1023 || name == "texinfo";
1024 else if (name == "print")
1025 enable = buf->isExportable("dvi")
1026 && lyxrc.print_command != "none";
1027 else if (name == "character") {
1031 InsetCode ic = view()->cursor().inset().lyxCode();
1032 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1035 else if (name == "symbols") {
1036 if (!view() || view()->cursor().inMathed())
1039 InsetCode ic = view()->cursor().inset().lyxCode();
1040 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1043 else if (name == "latexlog")
1044 enable = FileName(buf->logName()).isReadableFile();
1045 else if (name == "spellchecker")
1046 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1047 enable = !buf->isReadonly();
1051 else if (name == "vclog")
1052 enable = buf->lyxvc().inUse();
1056 case LFUN_DIALOG_UPDATE: {
1057 string const name = cmd.getArg(0);
1059 enable = name == "prefs";
1063 case LFUN_INSET_APPLY: {
1068 string const name = cmd.getArg(0);
1069 Inset * inset = getOpenInset(name);
1071 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1073 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1074 // Every inset is supposed to handle this
1075 BOOST_ASSERT(false);
1079 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1080 flag |= getStatus(fr);
1082 enable = flag.enabled();
1086 case LFUN_COMPLETION_INLINE:
1087 if (!d.current_work_area_
1088 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1092 case LFUN_COMPLETION_POPUP:
1093 if (!d.current_work_area_
1094 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1098 case LFUN_COMPLETION_COMPLETE:
1099 if (!d.current_work_area_
1100 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1112 flag.enabled(false);
1118 static FileName selectTemplateFile()
1120 FileDialog dlg(qt_("Select template file"));
1121 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1122 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1124 FileDialog::Result result =
1125 dlg.open(toqstr(lyxrc.template_path),
1126 FileFilterList(_("LyX Documents (*.lyx)")));
1128 if (result.first == FileDialog::Later)
1130 if (result.second.isEmpty())
1132 return FileName(fromqstr(result.second));
1136 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1140 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1143 message(_("Document not loaded."));
1148 setBuffer(newBuffer);
1150 // scroll to the position when the file was last closed
1151 if (lyxrc.use_lastfilepos) {
1152 LastFilePosSection::FilePos filepos =
1153 LyX::ref().session().lastFilePos().load(filename);
1154 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1158 LyX::ref().session().lastFiles().add(filename);
1165 void GuiView::openDocument(string const & fname)
1167 string initpath = lyxrc.document_path;
1170 string const trypath = buffer()->filePath();
1171 // If directory is writeable, use this as default.
1172 if (FileName(trypath).isDirWritable())
1178 if (fname.empty()) {
1179 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1180 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1181 dlg.setButton2(qt_("Examples|#E#e"),
1182 toqstr(addPath(package().system_support().absFilename(), "examples")));
1184 FileDialog::Result result =
1185 dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1187 if (result.first == FileDialog::Later)
1190 filename = fromqstr(result.second);
1192 // check selected filename
1193 if (filename.empty()) {
1194 message(_("Canceled."));
1200 // get absolute path of file and add ".lyx" to the filename if
1202 FileName const fullname =
1203 fileSearch(string(), filename, "lyx", support::may_not_exist);
1204 if (!fullname.empty())
1205 filename = fullname.absFilename();
1207 // if the file doesn't exist, let the user create one
1208 if (!fullname.exists()) {
1209 // the user specifically chose this name. Believe him.
1210 Buffer * const b = newFile(filename, string(), true);
1216 docstring const disp_fn = makeDisplayPath(filename);
1217 message(bformat(_("Opening document %1$s..."), disp_fn));
1220 Buffer * buf = loadDocument(fullname);
1225 buf->errors("Parse");
1226 str2 = bformat(_("Document %1$s opened."), disp_fn);
1228 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1233 // FIXME: clean that
1234 static bool import(GuiView * lv, FileName const & filename,
1235 string const & format, ErrorList & errorList)
1237 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1239 string loader_format;
1240 vector<string> loaders = theConverters().loaders();
1241 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1242 for (vector<string>::const_iterator it = loaders.begin();
1243 it != loaders.end(); ++it) {
1244 if (!theConverters().isReachable(format, *it))
1247 string const tofile =
1248 support::changeExtension(filename.absFilename(),
1249 formats.extension(*it));
1250 if (!theConverters().convert(0, filename, FileName(tofile),
1251 filename, format, *it, errorList))
1253 loader_format = *it;
1256 if (loader_format.empty()) {
1257 frontend::Alert::error(_("Couldn't import file"),
1258 bformat(_("No information for importing the format %1$s."),
1259 formats.prettyName(format)));
1263 loader_format = format;
1265 if (loader_format == "lyx") {
1266 Buffer * buf = lv->loadDocument(lyxfile);
1271 buf->errors("Parse");
1273 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1277 bool as_paragraphs = loader_format == "textparagraph";
1278 string filename2 = (loader_format == format) ? filename.absFilename()
1279 : support::changeExtension(filename.absFilename(),
1280 formats.extension(loader_format));
1281 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1282 theLyXFunc().setLyXView(lv);
1283 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1290 void GuiView::importDocument(string const & argument)
1293 string filename = split(argument, format, ' ');
1295 LYXERR(Debug::INFO, format << " file: " << filename);
1297 // need user interaction
1298 if (filename.empty()) {
1299 string initpath = lyxrc.document_path;
1301 Buffer const * buf = buffer();
1303 string const trypath = buf->filePath();
1304 // If directory is writeable, use this as default.
1305 if (FileName(trypath).isDirWritable())
1309 docstring const text = bformat(_("Select %1$s file to import"),
1310 formats.prettyName(format));
1312 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1313 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1314 dlg.setButton2(qt_("Examples|#E#e"),
1315 toqstr(addPath(package().system_support().absFilename(), "examples")));
1317 docstring filter = formats.prettyName(format);
1320 filter += from_utf8(formats.extension(format));
1323 FileDialog::Result result =
1324 dlg.open(toqstr(initpath), FileFilterList(filter));
1326 if (result.first == FileDialog::Later)
1329 filename = fromqstr(result.second);
1331 // check selected filename
1332 if (filename.empty())
1333 message(_("Canceled."));
1336 if (filename.empty())
1339 // get absolute path of file
1340 FileName const fullname(makeAbsPath(filename));
1342 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1344 // Check if the document already is open
1345 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1348 if (!closeBuffer()) {
1349 message(_("Canceled."));
1354 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1356 // if the file exists already, and we didn't do
1357 // -i lyx thefile.lyx, warn
1358 if (lyxfile.exists() && fullname != lyxfile) {
1360 docstring text = bformat(_("The document %1$s already exists.\n\n"
1361 "Do you want to overwrite that document?"), displaypath);
1362 int const ret = Alert::prompt(_("Overwrite document?"),
1363 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1366 message(_("Canceled."));
1371 message(bformat(_("Importing %1$s..."), displaypath));
1372 ErrorList errorList;
1373 if (import(this, fullname, format, errorList))
1374 message(_("imported."));
1376 message(_("file not imported!"));
1378 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1382 void GuiView::newDocument(string const & filename, bool from_template)
1384 FileName initpath(lyxrc.document_path);
1385 Buffer * buf = buffer();
1387 FileName const trypath(buf->filePath());
1388 // If directory is writeable, use this as default.
1389 if (trypath.isDirWritable())
1393 string templatefile = from_template ?
1394 selectTemplateFile().absFilename() : string();
1396 if (filename.empty())
1397 b = newUnnamedFile(templatefile, initpath);
1399 b = newFile(filename, templatefile, true);
1403 // Ensure the cursor is correctly positionned on screen.
1404 view()->showCursor();
1408 void GuiView::insertLyXFile(docstring const & fname)
1410 BufferView * bv = view();
1415 FileName filename(to_utf8(fname));
1417 if (!filename.empty()) {
1418 bv->insertLyXFile(filename);
1422 // Launch a file browser
1424 string initpath = lyxrc.document_path;
1425 string const trypath = bv->buffer().filePath();
1426 // If directory is writeable, use this as default.
1427 if (FileName(trypath).isDirWritable())
1431 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1432 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1433 dlg.setButton2(qt_("Examples|#E#e"),
1434 toqstr(addPath(package().system_support().absFilename(),
1437 FileDialog::Result result =
1438 dlg.open(toqstr(initpath),
1439 FileFilterList(_("LyX Documents (*.lyx)")));
1441 if (result.first == FileDialog::Later)
1445 filename.set(fromqstr(result.second));
1447 // check selected filename
1448 if (filename.empty()) {
1449 // emit message signal.
1450 message(_("Canceled."));
1454 bv->insertLyXFile(filename);
1458 void GuiView::insertPlaintextFile(docstring const & fname,
1461 BufferView * bv = view();
1466 FileName filename(to_utf8(fname));
1468 if (!filename.empty()) {
1469 bv->insertPlaintextFile(filename, asParagraph);
1473 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1474 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1476 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
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->insertPlaintextFile(filename, asParagraph);
1496 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1498 FileName fname = b.fileName();
1499 FileName const oldname = fname;
1501 if (!newname.empty()) {
1503 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1505 // Switch to this Buffer.
1508 /// No argument? Ask user through dialog.
1510 FileDialog dlg(qt_("Choose a filename to save document as"),
1511 LFUN_BUFFER_WRITE_AS);
1512 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1513 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1515 if (!isLyXFilename(fname.absFilename()))
1516 fname.changeExtension(".lyx");
1518 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1520 FileDialog::Result result =
1521 dlg.save(toqstr(fname.onlyPath().absFilename()),
1523 toqstr(fname.onlyFileName()));
1525 if (result.first == FileDialog::Later)
1528 fname.set(fromqstr(result.second));
1533 if (!isLyXFilename(fname.absFilename()))
1534 fname.changeExtension(".lyx");
1537 if (FileName(fname).exists()) {
1538 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1539 docstring text = bformat(_("The document %1$s already "
1540 "exists.\n\nDo you want to "
1541 "overwrite that document?"),
1543 int const ret = Alert::prompt(_("Overwrite document?"),
1544 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1547 case 1: return renameBuffer(b, docstring());
1548 case 2: return false;
1552 // Ok, change the name of the buffer
1553 b.setFileName(fname.absFilename());
1555 bool unnamed = b.isUnnamed();
1556 b.setUnnamed(false);
1557 b.saveCheckSum(fname);
1559 if (!saveBuffer(b)) {
1560 b.setFileName(oldname.absFilename());
1561 b.setUnnamed(unnamed);
1562 b.saveCheckSum(oldname);
1570 bool GuiView::saveBuffer(Buffer & b)
1573 return renameBuffer(b, docstring());
1576 LyX::ref().session().lastFiles().add(b.fileName());
1580 // Switch to this Buffer.
1583 // FIXME: we don't tell the user *WHY* the save failed !!
1584 docstring const file = makeDisplayPath(b.absFileName(), 30);
1585 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1586 "Do you want to rename the document and "
1587 "try again?"), file);
1588 int const ret = Alert::prompt(_("Rename and save?"),
1589 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1592 if (!renameBuffer(b, docstring()))
1601 return saveBuffer(b);
1605 bool GuiView::closeBuffer()
1607 Buffer * buf = buffer();
1608 return buf && closeBuffer(*buf);
1612 bool GuiView::closeBuffer(Buffer & buf)
1614 // goto bookmark to update bookmark pit.
1615 //FIXME: we should update only the bookmarks related to this buffer!
1616 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1617 theLyXFunc().gotoBookmark(i+1, false, false);
1619 if (buf.isClean() || buf.paragraphs().empty()) {
1620 if (buf.masterBuffer() == &buf)
1621 LyX::ref().session().lastOpened().add(buf.fileName());
1622 theBufferList().release(&buf);
1625 // Switch to this Buffer.
1630 if (buf.isUnnamed())
1631 file = from_utf8(buf.fileName().onlyFileName());
1633 file = buf.fileName().displayName(30);
1635 // Bring this window to top before asking questions.
1639 docstring const text = bformat(_("The document %1$s has unsaved changes."
1640 "\n\nDo you want to save the document or discard the changes?"), file);
1641 int const ret = Alert::prompt(_("Save changed document?"),
1642 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1646 if (!saveBuffer(buf))
1650 // if we crash after this we could
1651 // have no autosave file but I guess
1652 // this is really improbable (Jug)
1653 removeAutosaveFile(buf.absFileName());
1659 // save file names to .lyx/session
1660 // if master/slave are both open, do not save slave since it
1661 // will be automatically loaded when the master is loaded
1662 if (buf.masterBuffer() == &buf)
1663 LyX::ref().session().lastOpened().add(buf.fileName());
1665 theBufferList().release(&buf);
1670 bool GuiView::dispatch(FuncRequest const & cmd)
1672 BufferView * bv = view();
1673 // By default we won't need any update.
1675 bv->cursor().updateFlags(Update::None);
1677 switch(cmd.action) {
1678 case LFUN_BUFFER_IMPORT:
1679 importDocument(to_utf8(cmd.argument()));
1682 case LFUN_BUFFER_SWITCH:
1683 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1686 case LFUN_BUFFER_NEXT:
1687 setBuffer(theBufferList().next(buffer()));
1690 case LFUN_BUFFER_PREVIOUS:
1691 setBuffer(theBufferList().previous(buffer()));
1694 case LFUN_COMMAND_EXECUTE: {
1695 bool const show_it = cmd.argument() != "off";
1696 d.toolbars_->showCommandBuffer(show_it);
1699 case LFUN_DROP_LAYOUTS_CHOICE:
1701 d.layout_->showPopup();
1704 case LFUN_MENU_OPEN:
1705 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1706 menu->exec(QCursor::pos());
1709 case LFUN_FILE_INSERT:
1710 insertLyXFile(cmd.argument());
1712 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1713 insertPlaintextFile(cmd.argument(), true);
1716 case LFUN_FILE_INSERT_PLAINTEXT:
1717 insertPlaintextFile(cmd.argument(), false);
1720 case LFUN_BUFFER_WRITE:
1722 saveBuffer(bv->buffer());
1725 case LFUN_BUFFER_WRITE_AS:
1727 renameBuffer(bv->buffer(), cmd.argument());
1730 case LFUN_BUFFER_WRITE_ALL: {
1731 Buffer * first = theBufferList().first();
1734 message(_("Saving all documents..."));
1735 // We cannot use a for loop as the buffer list cycles.
1741 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1742 b = theBufferList().next(b);
1743 } while (b != first);
1744 message(_("All documents saved."));
1748 case LFUN_TOOLBAR_TOGGLE: {
1749 string const name = cmd.getArg(0);
1750 bool const allowauto = cmd.getArg(1) == "allowauto";
1751 // it is possible to get current toolbar status like this,...
1752 // but I decide to obey the order of ToolbarBackend::flags
1753 // and disregard real toolbar status.
1754 // toolbars_->saveToolbarInfo();
1756 // toggle state on/off/auto
1757 d.toolbars_->toggleToolbarState(name, allowauto);
1761 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1763 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1767 if (tbi->flags & ToolbarInfo::ON)
1769 else if (tbi->flags & ToolbarInfo::OFF)
1771 else if (tbi->flags & ToolbarInfo::AUTO)
1774 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1775 _(tbi->gui_name), state));
1779 case LFUN_DIALOG_UPDATE: {
1780 string const name = to_utf8(cmd.argument());
1781 // Can only update a dialog connected to an existing inset
1782 Inset * inset = getOpenInset(name);
1784 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1785 inset->dispatch(view()->cursor(), fr);
1786 } else if (name == "paragraph") {
1787 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1788 } else if (name == "prefs") {
1789 updateDialog(name, string());
1794 case LFUN_DIALOG_TOGGLE: {
1795 if (isDialogVisible(cmd.getArg(0)))
1796 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1798 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1802 case LFUN_DIALOG_DISCONNECT_INSET:
1803 disconnectDialog(to_utf8(cmd.argument()));
1806 case LFUN_DIALOG_HIDE: {
1807 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1811 case LFUN_DIALOG_SHOW: {
1812 string const name = cmd.getArg(0);
1813 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1815 if (name == "character") {
1816 data = freefont2string();
1818 showDialog("character", data);
1819 } else if (name == "latexlog") {
1820 Buffer::LogType type;
1821 string const logfile = buffer()->logName(&type);
1823 case Buffer::latexlog:
1826 case Buffer::buildlog:
1830 data += Lexer::quoteString(logfile);
1831 showDialog("log", data);
1832 } else if (name == "vclog") {
1833 string const data = "vc " +
1834 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1835 showDialog("log", data);
1836 } else if (name == "symbols") {
1837 data = bv->cursor().getEncoding()->name();
1839 showDialog("symbols", data);
1841 showDialog(name, data);
1845 case LFUN_INSET_APPLY: {
1846 string const name = cmd.getArg(0);
1847 Inset * inset = getOpenInset(name);
1849 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1850 inset->dispatch(view()->cursor(), fr);
1852 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1858 case LFUN_UI_TOGGLE:
1860 // Make sure the keyboard focus stays in the work area.
1864 case LFUN_COMPLETION_INLINE:
1865 if (d.current_work_area_)
1866 d.current_work_area_->completer().showInline();
1869 case LFUN_SPLIT_VIEW:
1870 if (Buffer * buf = buffer()) {
1871 string const orientation = cmd.getArg(0);
1872 d.splitter_->setOrientation(orientation == "vertical"
1873 ? Qt::Vertical : Qt::Horizontal);
1874 TabWorkArea * twa = addTabWorkArea();
1875 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1876 setCurrentWorkArea(wa);
1880 case LFUN_CLOSE_TAB_GROUP:
1881 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1883 twa = d.currentTabWorkArea();
1884 // Switch to the next GuiWorkArea in the found TabWorkArea.
1885 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1886 if (d.splitter_->count() == 0)
1887 // No more work area, switch to the background widget.
1892 case LFUN_COMPLETION_POPUP:
1893 if (d.current_work_area_)
1894 d.current_work_area_->completer().showPopup();
1898 case LFUN_COMPLETION_COMPLETE:
1899 if (d.current_work_area_)
1900 d.current_work_area_->completer().tab();
1911 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1913 string const arg = cmd.getArg(0);
1914 if (arg == "scrollbar") {
1915 // hide() is of no help
1916 if (d.current_work_area_->verticalScrollBarPolicy() ==
1917 Qt::ScrollBarAlwaysOff)
1919 d.current_work_area_->setVerticalScrollBarPolicy(
1920 Qt::ScrollBarAsNeeded);
1922 d.current_work_area_->setVerticalScrollBarPolicy(
1923 Qt::ScrollBarAlwaysOff);
1926 if (arg == "statusbar") {
1927 statusBar()->setVisible(!statusBar()->isVisible());
1930 if (arg == "menubar") {
1931 menuBar()->setVisible(!menuBar()->isVisible());
1934 #if QT_VERSION >= 0x040300
1935 if (arg == "frame") {
1937 getContentsMargins(&l, &t, &r, &b);
1938 //are the frames in default state?
1939 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1941 setContentsMargins(-2, -2, -2, -2);
1943 setContentsMargins(0, 0, 0, 0);
1948 if (arg != "fullscreen") {
1949 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1953 if (lyxrc.full_screen_toolbars)
1954 d.toolbars_->toggleFullScreen(!isFullScreen());
1956 if (isFullScreen()) {
1957 for (int i = 0; i != d.splitter_->count(); ++i)
1958 d.tabWorkArea(i)->setFullScreen(false);
1959 #if QT_VERSION >= 0x040300
1960 setContentsMargins(0, 0, 0, 0);
1964 statusBar()->show();
1966 for (int i = 0; i != d.splitter_->count(); ++i)
1967 d.tabWorkArea(i)->setFullScreen(true);
1968 #if QT_VERSION >= 0x040300
1969 setContentsMargins(-2, -2, -2, -2);
1972 statusBar()->hide();
1978 Buffer const * GuiView::updateInset(Inset const * inset)
1980 if (!d.current_work_area_)
1984 d.current_work_area_->scheduleRedraw();
1986 return &d.current_work_area_->bufferView().buffer();
1990 void GuiView::restartCursor()
1992 /* When we move around, or type, it's nice to be able to see
1993 * the cursor immediately after the keypress.
1995 if (d.current_work_area_)
1996 d.current_work_area_->startBlinkingCursor();
1998 // Take this occasion to update the other GUI elements.
2005 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2007 if (d.current_work_area_)
2008 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2013 // This list should be kept in sync with the list of insets in
2014 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2015 // dialog should have the same name as the inset.
2017 char const * const dialognames[] = {
2018 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2019 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
2020 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2021 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2022 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2024 #ifdef HAVE_LIBAIKSAURUS
2028 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2030 char const * const * const end_dialognames =
2031 dialognames + (sizeof(dialognames) / sizeof(char *));
2035 cmpCStr(char const * name) : name_(name) {}
2036 bool operator()(char const * other) {
2037 return strcmp(other, name_) == 0;
2044 bool isValidName(string const & name)
2046 return find_if(dialognames, end_dialognames,
2047 cmpCStr(name.c_str())) != end_dialognames;
2053 void GuiView::resetDialogs()
2055 // Make sure that no LFUN uses any LyXView.
2056 theLyXFunc().setLyXView(0);
2057 // FIXME: the "math panels" toolbar takes an awful lot of time to
2058 // initialise so we don't do that for the time being.
2059 //d.toolbars_->init();
2060 guiApp->menus().fillMenuBar(menuBar(), this);
2062 d.layout_->updateContents(true);
2063 // Now update controls with current buffer.
2064 theLyXFunc().setLyXView(this);
2069 Dialog * GuiView::find_or_build(string const & name)
2071 if (!isValidName(name))
2074 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2076 if (it != d.dialogs_.end())
2077 return it->second.get();
2079 Dialog * dialog = build(name);
2080 d.dialogs_[name].reset(dialog);
2081 if (lyxrc.allow_geometry_session)
2082 dialog->restoreSession();
2087 void GuiView::showDialog(string const & name, string const & data,
2094 Dialog * dialog = find_or_build(name);
2096 dialog->showData(data);
2098 d.open_insets_[name] = inset;
2104 bool GuiView::isDialogVisible(string const & name) const
2106 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2107 if (it == d.dialogs_.end())
2109 return it->second.get()->isVisibleView();
2113 void GuiView::hideDialog(string const & name, Inset * inset)
2115 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2116 if (it == d.dialogs_.end())
2119 if (inset && inset != getOpenInset(name))
2122 Dialog * const dialog = it->second.get();
2123 if (dialog->isVisibleView())
2125 d.open_insets_[name] = 0;
2129 void GuiView::disconnectDialog(string const & name)
2131 if (!isValidName(name))
2134 if (d.open_insets_.find(name) != d.open_insets_.end())
2135 d.open_insets_[name] = 0;
2139 Inset * GuiView::getOpenInset(string const & name) const
2141 if (!isValidName(name))
2144 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2145 return it == d.open_insets_.end() ? 0 : it->second;
2149 void GuiView::hideAll() const
2151 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2152 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2154 for(; it != end; ++it)
2155 it->second->hideView();
2159 void GuiView::hideBufferDependent() const
2161 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2162 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2164 for(; it != end; ++it) {
2165 Dialog * dialog = it->second.get();
2166 if (dialog->isBufferDependent())
2172 void GuiView::updateBufferDependent(bool switched) const
2174 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2175 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2177 for(; it != end; ++it) {
2178 Dialog * dialog = it->second.get();
2179 if (!dialog->isVisibleView())
2181 if (switched && dialog->isBufferDependent()) {
2182 if (dialog->initialiseParams(""))
2183 dialog->updateView();
2187 // A bit clunky, but the dialog will request
2188 // that the kernel provides it with the necessary
2190 dialog->updateDialog();
2196 void GuiView::checkStatus()
2198 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2199 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2201 for(; it != end; ++it) {
2202 Dialog * const dialog = it->second.get();
2203 if (dialog && dialog->isVisibleView())
2204 dialog->checkStatus();
2210 // will be replaced by a proper factory...
2211 Dialog * createGuiAbout(GuiView & lv);
2212 Dialog * createGuiBibitem(GuiView & lv);
2213 Dialog * createGuiBibtex(GuiView & lv);
2214 Dialog * createGuiBox(GuiView & lv);
2215 Dialog * createGuiBranch(GuiView & lv);
2216 Dialog * createGuiChanges(GuiView & lv);
2217 Dialog * createGuiCharacter(GuiView & lv);
2218 Dialog * createGuiCitation(GuiView & lv);
2219 Dialog * createGuiDelimiter(GuiView & lv);
2220 Dialog * createGuiDocument(GuiView & lv);
2221 Dialog * createGuiErrorList(GuiView & lv);
2222 Dialog * createGuiERT(GuiView & lv);
2223 Dialog * createGuiExternal(GuiView & lv);
2224 Dialog * createGuiFloat(GuiView & lv);
2225 Dialog * createGuiGraphics(GuiView & lv);
2226 Dialog * createGuiHSpace(GuiView & lv);
2227 Dialog * createGuiInclude(GuiView & lv);
2228 Dialog * createGuiLabel(GuiView & lv);
2229 Dialog * createGuiListings(GuiView & lv);
2230 Dialog * createGuiLog(GuiView & lv);
2231 Dialog * createGuiMathMatrix(GuiView & lv);
2232 Dialog * createGuiNomenclature(GuiView & lv);
2233 Dialog * createGuiNote(GuiView & lv);
2234 Dialog * createGuiParagraph(GuiView & lv);
2235 Dialog * createGuiPreferences(GuiView & lv);
2236 Dialog * createGuiPrint(GuiView & lv);
2237 Dialog * createGuiRef(GuiView & lv);
2238 Dialog * createGuiSearch(GuiView & lv);
2239 Dialog * createGuiSendTo(GuiView & lv);
2240 Dialog * createGuiShowFile(GuiView & lv);
2241 Dialog * createGuiSpellchecker(GuiView & lv);
2242 Dialog * createGuiSymbols(GuiView & lv);
2243 Dialog * createGuiTabularCreate(GuiView & lv);
2244 Dialog * createGuiTabular(GuiView & lv);
2245 Dialog * createGuiTexInfo(GuiView & lv);
2246 Dialog * createGuiToc(GuiView & lv);
2247 Dialog * createGuiThesaurus(GuiView & lv);
2248 Dialog * createGuiHyperlink(GuiView & lv);
2249 Dialog * createGuiVSpace(GuiView & lv);
2250 Dialog * createGuiViewSource(GuiView & lv);
2251 Dialog * createGuiWrap(GuiView & lv);
2254 Dialog * GuiView::build(string const & name)
2256 BOOST_ASSERT(isValidName(name));
2258 if (name == "aboutlyx")
2259 return createGuiAbout(*this);
2260 if (name == "bibitem")
2261 return createGuiBibitem(*this);
2262 if (name == "bibtex")
2263 return createGuiBibtex(*this);
2265 return createGuiBox(*this);
2266 if (name == "branch")
2267 return createGuiBranch(*this);
2268 if (name == "changes")
2269 return createGuiChanges(*this);
2270 if (name == "character")
2271 return createGuiCharacter(*this);
2272 if (name == "citation")
2273 return createGuiCitation(*this);
2274 if (name == "document")
2275 return createGuiDocument(*this);
2276 if (name == "errorlist")
2277 return createGuiErrorList(*this);
2279 return createGuiERT(*this);
2280 if (name == "external")
2281 return createGuiExternal(*this);
2283 return createGuiShowFile(*this);
2284 if (name == "findreplace")
2285 return createGuiSearch(*this);
2286 if (name == "float")
2287 return createGuiFloat(*this);
2288 if (name == "graphics")
2289 return createGuiGraphics(*this);
2290 if (name == "include")
2291 return createGuiInclude(*this);
2292 if (name == "nomenclature")
2293 return createGuiNomenclature(*this);
2294 if (name == "label")
2295 return createGuiLabel(*this);
2297 return createGuiLog(*this);
2298 if (name == "view-source")
2299 return createGuiViewSource(*this);
2300 if (name == "mathdelimiter")
2301 return createGuiDelimiter(*this);
2302 if (name == "mathmatrix")
2303 return createGuiMathMatrix(*this);
2305 return createGuiNote(*this);
2306 if (name == "paragraph")
2307 return createGuiParagraph(*this);
2308 if (name == "prefs")
2309 return createGuiPreferences(*this);
2310 if (name == "print")
2311 return createGuiPrint(*this);
2313 return createGuiRef(*this);
2314 if (name == "sendto")
2315 return createGuiSendTo(*this);
2316 if (name == "space")
2317 return createGuiHSpace(*this);
2318 if (name == "spellchecker")
2319 return createGuiSpellchecker(*this);
2320 if (name == "symbols")
2321 return createGuiSymbols(*this);
2322 if (name == "tabular")
2323 return createGuiTabular(*this);
2324 if (name == "tabularcreate")
2325 return createGuiTabularCreate(*this);
2326 if (name == "texinfo")
2327 return createGuiTexInfo(*this);
2328 #ifdef HAVE_LIBAIKSAURUS
2329 if (name == "thesaurus")
2330 return createGuiThesaurus(*this);
2333 return createGuiToc(*this);
2335 return createGuiHyperlink(*this);
2336 if (name == "vspace")
2337 return createGuiVSpace(*this);
2339 return createGuiWrap(*this);
2340 if (name == "listings")
2341 return createGuiListings(*this);
2347 } // namespace frontend
2350 #include "GuiView_moc.cpp"