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/FileName.h"
59 #include "support/filetools.h"
60 #include "support/gettext.h"
61 #include "support/ForkedCalls.h"
62 #include "support/lstrings.h"
63 #include "support/os.h"
64 #include "support/Package.h"
65 #include "support/Timeout.h"
68 #include <QApplication>
69 #include <QCloseEvent>
71 #include <QDesktopWidget>
72 #include <QDragEnterEvent>
80 #include <QPushButton>
84 #include <QStackedWidget>
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 ?
116 qt_("version ") + lyx_version : qt_("unknown version");
117 splash_ = QPixmap(":/images/banner.png");
119 QPainter pain(&splash_);
120 pain.setPen(QColor(0, 0, 0));
122 // The font used to display the version info
123 font.setStyleHint(QFont::SansSerif);
124 font.setWeight(QFont::Bold);
125 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
127 pain.drawText(190, 225, text);
130 void paintEvent(QPaintEvent *)
132 int x = (width() - splash_.width()) / 2;
133 int y = (height() - splash_.height()) / 2;
135 pain.drawPixmap(x, y, splash_);
145 typedef boost::shared_ptr<Dialog> DialogPtr;
147 struct GuiView::GuiViewPrivate
150 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
153 // hardcode here the platform specific icon size
154 smallIconSize = 14; // scaling problems
155 normalIconSize = 20; // ok, default
156 bigIconSize = 26; // better for some math icons
158 splitter_ = new QSplitter;
159 bg_widget_ = new BackgroundWidget;
160 stack_widget_ = new QStackedWidget;
161 stack_widget_->addWidget(bg_widget_);
162 stack_widget_->addWidget(splitter_);
170 delete stack_widget_;
174 QMenu * toolBarPopup(GuiView * parent)
176 // FIXME: translation
177 QMenu * menu = new QMenu(parent);
178 QActionGroup * iconSizeGroup = new QActionGroup(parent);
180 QAction * smallIcons = new QAction(iconSizeGroup);
181 smallIcons->setText(qt_("Small-sized icons"));
182 smallIcons->setCheckable(true);
183 QObject::connect(smallIcons, SIGNAL(triggered()),
184 parent, SLOT(smallSizedIcons()));
185 menu->addAction(smallIcons);
187 QAction * normalIcons = new QAction(iconSizeGroup);
188 normalIcons->setText(qt_("Normal-sized icons"));
189 normalIcons->setCheckable(true);
190 QObject::connect(normalIcons, SIGNAL(triggered()),
191 parent, SLOT(normalSizedIcons()));
192 menu->addAction(normalIcons);
194 QAction * bigIcons = new QAction(iconSizeGroup);
195 bigIcons->setText(qt_("Big-sized icons"));
196 bigIcons->setCheckable(true);
197 QObject::connect(bigIcons, SIGNAL(triggered()),
198 parent, SLOT(bigSizedIcons()));
199 menu->addAction(bigIcons);
201 unsigned int cur = parent->iconSize().width();
202 if ( cur == parent->d.smallIconSize)
203 smallIcons->setChecked(true);
204 else if (cur == parent->d.normalIconSize)
205 normalIcons->setChecked(true);
206 else if (cur == parent->d.bigIconSize)
207 bigIcons->setChecked(true);
214 stack_widget_->setCurrentWidget(bg_widget_);
215 bg_widget_->setUpdatesEnabled(true);
218 TabWorkArea * tabWorkArea(int i)
220 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
223 TabWorkArea * currentTabWorkArea()
225 if (splitter_->count() == 1)
226 // The first TabWorkArea is always the first one, if any.
227 return tabWorkArea(0);
229 for (int i = 0; i != splitter_->count(); ++i) {
230 TabWorkArea * twa = tabWorkArea(i);
231 if (current_work_area_ == twa->currentWorkArea())
235 // None has the focus so we just take the first one.
236 return tabWorkArea(0);
240 GuiWorkArea * current_work_area_;
241 QSplitter * splitter_;
242 QStackedWidget * stack_widget_;
243 BackgroundWidget * bg_widget_;
245 GuiToolbars * toolbars_;
246 /// The main layout box.
248 * \warning Don't Delete! The layout box is actually owned by
249 * whichever toolbar contains it. All the GuiView class needs is a
250 * means of accessing it.
252 * FIXME: replace that with a proper model so that we are not limited
253 * to only one dialog.
255 GuiLayoutBox * layout_;
258 map<string, Inset *> open_insets_;
261 map<string, DialogPtr> dialogs_;
263 unsigned int smallIconSize;
264 unsigned int normalIconSize;
265 unsigned int bigIconSize;
267 QTimer statusbar_timer_;
268 /// auto-saving of buffers
269 Timeout autosave_timeout_;
270 /// flag against a race condition due to multiclicks, see bug #1119
275 GuiView::GuiView(int id)
276 : d(*new GuiViewPrivate), id_(id)
278 // GuiToolbars *must* be initialised before the menu bar.
279 d.toolbars_ = new GuiToolbars(*this);
281 // set ourself as the current view. This is needed for the menu bar
282 // filling, at least for the static special menu item on Mac. Otherwise
283 // they are greyed out.
284 theLyXFunc().setLyXView(this);
286 // Fill up the menu bar.
287 guiApp->menus().fillMenuBar(menuBar(), this, true);
289 setCentralWidget(d.stack_widget_);
291 // Start autosave timer
292 if (lyxrc.autosave) {
293 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
294 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
295 d.autosave_timeout_.start();
297 connect(&d.statusbar_timer_, SIGNAL(timeout()),
298 this, SLOT(clearMessage()));
300 // We don't want to keep the window in memory if it is closed.
301 setAttribute(Qt::WA_DeleteOnClose, true);
303 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
304 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
305 // since the icon is provided in the application bundle.
306 setWindowIcon(QPixmap(":/images/lyx.png"));
310 setAcceptDrops(true);
312 statusBar()->setSizeGripEnabled(true);
314 // Forbid too small unresizable window because it can happen
315 // with some window manager under X11.
316 setMinimumSize(300, 200);
318 if (!lyxrc.allow_geometry_session)
319 // No session handling, default to a sane size.
320 setGeometry(50, 50, 690, 510);
322 // Now take care of session management.
324 QString const key = "view-" + QString::number(id_);
326 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
327 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
331 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
332 setGeometry(50, 50, 690, 510);
334 setIconSize(settings.value(key + "/icon_size").toSize());
340 if (guiApp->currentView() == this)
341 guiApp->setCurrentView(0);
342 theLyXFunc().setLyXView(0);
348 void GuiView::setFocus()
350 if (d.current_work_area_)
351 d.current_work_area_->setFocus();
357 QMenu * GuiView::createPopupMenu()
359 return d.toolBarPopup(this);
363 void GuiView::showEvent(QShowEvent * e)
365 LYXERR(Debug::GUI, "Passed Geometry "
366 << size().height() << "x" << size().width()
367 << "+" << pos().x() << "+" << pos().y());
369 if (d.splitter_->count() == 0)
370 // No work area, switch to the background widget.
373 QMainWindow::showEvent(e);
377 void GuiView::closeEvent(QCloseEvent * close_event)
379 // it can happen that this event arrives without selecting the view,
380 // e.g. when clicking the close button on a background window.
381 theLyXFunc().setLyXView(this);
383 while (Buffer * b = buffer()) {
385 // This is a child document, just close the tab after saving
386 // but keep the file loaded.
387 if (!saveBuffer(*b)) {
388 close_event->ignore();
391 removeWorkArea(d.current_work_area_);
395 std::vector<int> const & ids = guiApp->viewIds();
396 for (size_type i = 0; i != ids.size(); ++i) {
399 if (guiApp->view(ids[i]).workArea(*b)) {
400 // FIXME 1: should we put an alert box here that the buffer
401 // is viewed elsewhere?
402 // FIXME 2: should we try to save this buffer in any case?
405 // This buffer is also opened in another view, so
406 // but close the associated work area nevertheless.
407 removeWorkArea(d.current_work_area_);
408 // but don't close it.
413 if (b && !closeBuffer(*b, true)) {
414 close_event->ignore();
419 // Make sure that no LFUN use this close to be closed View.
420 theLyXFunc().setLyXView(0);
422 // Save toolbars configuration
423 if (isFullScreen()) {
424 d.toolbars_->toggleFullScreen(!isFullScreen());
428 // Make sure the timer time out will not trigger a statusbar update.
429 d.statusbar_timer_.stop();
431 // Saving fullscreen requires additional tweaks in the toolbar code.
432 // It wouldn't also work under linux natively.
433 if (lyxrc.allow_geometry_session && !isFullScreen()) {
435 QString const key = "view-" + QString::number(id_);
437 settings.setValue(key + "/pos", pos());
438 settings.setValue(key + "/size", size());
440 settings.setValue(key + "/geometry", saveGeometry());
442 settings.setValue(key + "/icon_size", iconSize());
443 d.toolbars_->saveToolbarInfo();
444 // Now take care of all other dialogs:
445 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
446 for (; it!= d.dialogs_.end(); ++it)
447 it->second->saveSession();
450 guiApp->unregisterView(id_);
451 close_event->accept();
455 void GuiView::dragEnterEvent(QDragEnterEvent * event)
457 if (event->mimeData()->hasUrls())
459 /// \todo Ask lyx-devel is this is enough:
460 /// if (event->mimeData()->hasFormat("text/plain"))
461 /// event->acceptProposedAction();
465 void GuiView::dropEvent(QDropEvent* event)
467 QList<QUrl> files = event->mimeData()->urls();
471 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
472 for (int i = 0; i != files.size(); ++i) {
473 string const file = os::internal_path(fromqstr(
474 files.at(i).toLocalFile()));
476 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
481 void GuiView::message(docstring const & str)
483 if (ForkedProcess::iAmAChild())
486 statusBar()->showMessage(toqstr(str));
487 d.statusbar_timer_.stop();
488 d.statusbar_timer_.start(3000);
492 void GuiView::smallSizedIcons()
494 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
498 void GuiView::normalSizedIcons()
500 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
504 void GuiView::bigSizedIcons()
506 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
510 void GuiView::clearMessage()
514 theLyXFunc().setLyXView(this);
515 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
516 d.statusbar_timer_.stop();
520 void GuiView::updateWindowTitle(GuiWorkArea * wa)
522 if (wa != d.current_work_area_)
524 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
525 setWindowIconText(wa->windowIconText());
529 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
532 disconnectBufferView();
533 connectBufferView(wa->bufferView());
534 connectBuffer(wa->bufferView().buffer());
535 d.current_work_area_ = wa;
536 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
537 this, SLOT(updateWindowTitle(GuiWorkArea *)));
538 updateWindowTitle(wa);
541 // Buffer-dependent dialogs should be updated or
542 // hidden. This should go here because some dialogs (eg ToC)
543 // require bv_->text.
544 updateBufferDependent(true);
551 void GuiView::on_lastWorkAreaRemoved()
554 // On Mac close the view if there is no Tab open anymore,
555 // but only if no splitter is visible
556 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
557 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
558 if (twa && twa->count() == 0) {
559 // close the view, as no tab is open anymore
560 QTimer::singleShot(0, this, SLOT(close()));
567 void GuiView::updateStatusBar()
569 // let the user see the explicit message
570 if (d.statusbar_timer_.isActive())
573 theLyXFunc().setLyXView(this);
574 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
578 bool GuiView::hasFocus() const
580 return qApp->activeWindow() == this;
584 bool GuiView::event(QEvent * e)
588 // Useful debug code:
589 //case QEvent::ActivationChange:
590 //case QEvent::WindowDeactivate:
591 //case QEvent::Paint:
592 //case QEvent::Enter:
593 //case QEvent::Leave:
594 //case QEvent::HoverEnter:
595 //case QEvent::HoverLeave:
596 //case QEvent::HoverMove:
597 //case QEvent::StatusTip:
598 //case QEvent::DragEnter:
599 //case QEvent::DragLeave:
603 case QEvent::WindowActivate: {
604 if (this == guiApp->currentView()) {
606 return QMainWindow::event(e);
608 guiApp->setCurrentView(this);
609 if (d.current_work_area_) {
610 BufferView & bv = d.current_work_area_->bufferView();
611 connectBufferView(bv);
612 connectBuffer(bv.buffer());
613 // The document structure, name and dialogs might have
614 // changed in another view.
615 updateBufferDependent(true);
620 setWindowTitle(qt_("LyX"));
621 setWindowIconText(qt_("LyX"));
624 return QMainWindow::event(e);
627 case QEvent::ShortcutOverride: {
628 if (d.current_work_area_)
629 // Nothing special to do.
630 return QMainWindow::event(e);
632 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
634 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
636 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
637 || ke->key() == Qt::Key_Backtab)
638 return QMainWindow::event(e);
640 // Allow processing of shortcuts that are allowed even when no Buffer
642 theLyXFunc().setLyXView(this);
644 setKeySymbol(&sym, ke);
645 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
651 return QMainWindow::event(e);
656 bool GuiView::focusNextPrevChild(bool /*next*/)
663 void GuiView::setBusy(bool busy)
665 if (d.current_work_area_) {
666 d.current_work_area_->setUpdatesEnabled(!busy);
668 d.current_work_area_->stopBlinkingCursor();
670 d.current_work_area_->startBlinkingCursor();
674 QApplication::setOverrideCursor(Qt::WaitCursor);
676 QApplication::restoreOverrideCursor();
680 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
682 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
684 if (tbinfo.flags & ToolbarInfo::TOP) {
686 addToolBarBreak(Qt::TopToolBarArea);
687 addToolBar(Qt::TopToolBarArea, toolBar);
690 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
691 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
692 #if (QT_VERSION >= 0x040202)
694 addToolBarBreak(Qt::BottomToolBarArea);
696 addToolBar(Qt::BottomToolBarArea, toolBar);
699 if (tbinfo.flags & ToolbarInfo::LEFT) {
700 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
701 #if (QT_VERSION >= 0x040202)
703 addToolBarBreak(Qt::LeftToolBarArea);
705 addToolBar(Qt::LeftToolBarArea, toolBar);
708 if (tbinfo.flags & ToolbarInfo::RIGHT) {
709 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
710 #if (QT_VERSION >= 0x040202)
712 addToolBarBreak(Qt::RightToolBarArea);
714 addToolBar(Qt::RightToolBarArea, toolBar);
717 // The following does not work so I cannot restore to exact toolbar location
719 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
720 toolBar->move(tbinfo.posx, tbinfo.posy);
727 GuiWorkArea * GuiView::workArea(Buffer & buffer)
729 if (TabWorkArea * twa = d.currentTabWorkArea())
730 return twa->workArea(buffer);
735 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
737 // Automatically create a TabWorkArea if there are none yet.
738 TabWorkArea * tab_widget = d.splitter_->count()
739 ? d.currentTabWorkArea() : addTabWorkArea();
740 return tab_widget->addWorkArea(buffer, *this);
744 TabWorkArea * GuiView::addTabWorkArea()
746 TabWorkArea * twa = new TabWorkArea;
747 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
748 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
749 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
750 this, SLOT(on_lastWorkAreaRemoved()));
752 d.splitter_->addWidget(twa);
753 d.stack_widget_->setCurrentWidget(d.splitter_);
758 GuiWorkArea const * GuiView::currentWorkArea() const
760 return d.current_work_area_;
764 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
768 // Changing work area can result from opening a file so
769 // update the toc in any case.
772 d.current_work_area_ = wa;
773 for (int i = 0; i != d.splitter_->count(); ++i) {
774 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
780 void GuiView::removeWorkArea(GuiWorkArea * wa)
783 if (wa == d.current_work_area_) {
785 disconnectBufferView();
786 hideBufferDependent();
787 d.current_work_area_ = 0;
790 for (int i = 0; i != d.splitter_->count(); ++i) {
791 TabWorkArea * twa = d.tabWorkArea(i);
792 if (!twa->removeWorkArea(wa))
793 // Not found in this tab group.
796 // We found and removed the GuiWorkArea.
798 // No more WorkAreas in this tab group, so delete it.
803 if (d.current_work_area_)
804 // This means that we are not closing the current GuiWorkArea;
807 // Switch to the next GuiWorkArea in the found TabWorkArea.
808 d.current_work_area_ = twa->currentWorkArea();
812 if (d.splitter_->count() == 0)
813 // No more work area, switch to the background widget.
818 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
824 void GuiView::updateLayoutList()
827 d.layout_->updateContents(false);
831 void GuiView::updateToolbars()
833 if (d.current_work_area_) {
835 d.current_work_area_->bufferView().cursor().inMathed();
837 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
839 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
840 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
841 bool const mathmacrotemplate =
842 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
844 d.toolbars_->update(math, table, review, mathmacrotemplate);
846 d.toolbars_->update(false, false, false, false);
848 // update read-only status of open dialogs.
853 Buffer * GuiView::buffer()
855 if (d.current_work_area_)
856 return &d.current_work_area_->bufferView().buffer();
861 Buffer const * GuiView::buffer() const
863 if (d.current_work_area_)
864 return &d.current_work_area_->bufferView().buffer();
869 void GuiView::setBuffer(Buffer * newBuffer)
871 LASSERT(newBuffer, /**/);
874 GuiWorkArea * wa = workArea(*newBuffer);
876 updateLabels(*newBuffer->masterBuffer());
877 wa = addWorkArea(*newBuffer);
879 //Disconnect the old buffer...there's no new one.
882 connectBuffer(*newBuffer);
883 connectBufferView(wa->bufferView());
884 setCurrentWorkArea(wa);
890 void GuiView::connectBuffer(Buffer & buf)
892 buf.setGuiDelegate(this);
896 void GuiView::disconnectBuffer()
898 if (d.current_work_area_)
899 d.current_work_area_->bufferView().setGuiDelegate(0);
903 void GuiView::connectBufferView(BufferView & bv)
905 bv.setGuiDelegate(this);
909 void GuiView::disconnectBufferView()
911 if (d.current_work_area_)
912 d.current_work_area_->bufferView().setGuiDelegate(0);
916 void GuiView::errors(string const & error_type)
918 ErrorList & el = buffer()->errorList(error_type);
920 showDialog("errorlist", error_type);
924 void GuiView::updateDialog(string const & name, string const & data)
926 if (!isDialogVisible(name))
929 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
930 if (it == d.dialogs_.end())
933 Dialog * const dialog = it->second.get();
934 if (dialog->isVisibleView())
935 dialog->updateData(data);
939 BufferView * GuiView::view()
941 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
945 void GuiView::updateToc()
947 updateDialog("toc", "");
951 void GuiView::autoSave()
953 LYXERR(Debug::INFO, "Running autoSave()");
956 view()->buffer().autoSave();
960 void GuiView::resetAutosaveTimers()
963 d.autosave_timeout_.restart();
967 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
971 Buffer * buf = buffer();
973 /* In LyX/Mac, when a dialog is open, the menus of the
974 application can still be accessed without giving focus to
975 the main window. In this case, we want to disable the menu
976 entries that are buffer-related.
978 Note that this code is not perfect, as bug 1941 attests:
979 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
981 if (cmd.origin == FuncRequest::MENU && !hasFocus())
985 case LFUN_BUFFER_WRITE:
986 enable = buf && (buf->isUnnamed() || !buf->isClean());
989 case LFUN_BUFFER_WRITE_AS:
993 case LFUN_SPLIT_VIEW:
997 case LFUN_CLOSE_TAB_GROUP:
998 enable = d.currentTabWorkArea();
1001 case LFUN_TOOLBAR_TOGGLE:
1002 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1005 case LFUN_UI_TOGGLE:
1006 flag.setOnOff(isFullScreen());
1009 case LFUN_DIALOG_TOGGLE:
1010 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1011 // fall through to set "enable"
1012 case LFUN_DIALOG_SHOW: {
1013 string const name = cmd.getArg(0);
1015 enable = name == "aboutlyx"
1016 || name == "file" //FIXME: should be removed.
1018 || name == "texinfo";
1019 else if (name == "print")
1020 enable = buf->isExportable("dvi")
1021 && lyxrc.print_command != "none";
1022 else if (name == "character") {
1026 InsetCode ic = view()->cursor().inset().lyxCode();
1027 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1030 else if (name == "symbols") {
1031 if (!view() || view()->cursor().inMathed())
1034 InsetCode ic = view()->cursor().inset().lyxCode();
1035 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1038 else if (name == "latexlog")
1039 enable = FileName(buf->logName()).isReadableFile();
1040 else if (name == "spellchecker")
1041 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1042 enable = !buf->isReadonly();
1046 else if (name == "vclog")
1047 enable = buf->lyxvc().inUse();
1051 case LFUN_DIALOG_UPDATE: {
1052 string const name = cmd.getArg(0);
1054 enable = name == "prefs";
1058 case LFUN_INSET_APPLY: {
1063 string const name = cmd.getArg(0);
1064 Inset * inset = getOpenInset(name);
1066 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1068 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1069 // Every inset is supposed to handle this
1070 LASSERT(false, /**/);
1074 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1075 flag |= getStatus(fr);
1077 enable = flag.enabled();
1081 case LFUN_COMPLETION_INLINE:
1082 if (!d.current_work_area_
1083 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1087 case LFUN_COMPLETION_POPUP:
1088 if (!d.current_work_area_
1089 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1093 case LFUN_COMPLETION_COMPLETE:
1094 if (!d.current_work_area_
1095 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1107 flag.enabled(false);
1113 static FileName selectTemplateFile()
1115 FileDialog dlg(qt_("Select template file"));
1116 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1117 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1119 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1120 QStringList(qt_("LyX Documents (*.lyx)")));
1122 if (result.first == FileDialog::Later)
1124 if (result.second.isEmpty())
1126 return FileName(fromqstr(result.second));
1130 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1134 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1137 message(_("Document not loaded."));
1142 setBuffer(newBuffer);
1144 // scroll to the position when the file was last closed
1145 if (lyxrc.use_lastfilepos) {
1146 LastFilePosSection::FilePos filepos =
1147 LyX::ref().session().lastFilePos().load(filename);
1148 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1152 LyX::ref().session().lastFiles().add(filename);
1159 void GuiView::openDocument(string const & fname)
1161 string initpath = lyxrc.document_path;
1164 string const trypath = buffer()->filePath();
1165 // If directory is writeable, use this as default.
1166 if (FileName(trypath).isDirWritable())
1172 if (fname.empty()) {
1173 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1174 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1175 dlg.setButton2(qt_("Examples|#E#e"),
1176 toqstr(addPath(package().system_support().absFilename(), "examples")));
1178 FileDialog::Result result =
1179 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1181 if (result.first == FileDialog::Later)
1184 filename = fromqstr(result.second);
1186 // check selected filename
1187 if (filename.empty()) {
1188 message(_("Canceled."));
1194 // get absolute path of file and add ".lyx" to the filename if
1196 FileName const fullname =
1197 fileSearch(string(), filename, "lyx", support::may_not_exist);
1198 if (!fullname.empty())
1199 filename = fullname.absFilename();
1201 // if the file doesn't exist, let the user create one
1202 if (!fullname.exists()) {
1203 // the user specifically chose this name. Believe him.
1204 Buffer * const b = newFile(filename, string(), true);
1210 docstring const disp_fn = makeDisplayPath(filename);
1211 message(bformat(_("Opening document %1$s..."), disp_fn));
1214 Buffer * buf = loadDocument(fullname);
1219 buf->errors("Parse");
1220 str2 = bformat(_("Document %1$s opened."), disp_fn);
1222 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1227 // FIXME: clean that
1228 static bool import(GuiView * lv, FileName const & filename,
1229 string const & format, ErrorList & errorList)
1231 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1233 string loader_format;
1234 vector<string> loaders = theConverters().loaders();
1235 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1236 for (vector<string>::const_iterator it = loaders.begin();
1237 it != loaders.end(); ++it) {
1238 if (!theConverters().isReachable(format, *it))
1241 string const tofile =
1242 support::changeExtension(filename.absFilename(),
1243 formats.extension(*it));
1244 if (!theConverters().convert(0, filename, FileName(tofile),
1245 filename, format, *it, errorList))
1247 loader_format = *it;
1250 if (loader_format.empty()) {
1251 frontend::Alert::error(_("Couldn't import file"),
1252 bformat(_("No information for importing the format %1$s."),
1253 formats.prettyName(format)));
1257 loader_format = format;
1259 if (loader_format == "lyx") {
1260 Buffer * buf = lv->loadDocument(lyxfile);
1265 buf->errors("Parse");
1267 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1271 bool as_paragraphs = loader_format == "textparagraph";
1272 string filename2 = (loader_format == format) ? filename.absFilename()
1273 : support::changeExtension(filename.absFilename(),
1274 formats.extension(loader_format));
1275 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1276 theLyXFunc().setLyXView(lv);
1277 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1284 void GuiView::importDocument(string const & argument)
1287 string filename = split(argument, format, ' ');
1289 LYXERR(Debug::INFO, format << " file: " << filename);
1291 // need user interaction
1292 if (filename.empty()) {
1293 string initpath = lyxrc.document_path;
1295 Buffer const * buf = buffer();
1297 string const trypath = buf->filePath();
1298 // If directory is writeable, use this as default.
1299 if (FileName(trypath).isDirWritable())
1303 docstring const text = bformat(_("Select %1$s file to import"),
1304 formats.prettyName(format));
1306 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1307 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1308 dlg.setButton2(qt_("Examples|#E#e"),
1309 toqstr(addPath(package().system_support().absFilename(), "examples")));
1311 docstring filter = formats.prettyName(format);
1314 filter += from_utf8(formats.extension(format));
1317 FileDialog::Result result =
1318 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1320 if (result.first == FileDialog::Later)
1323 filename = fromqstr(result.second);
1325 // check selected filename
1326 if (filename.empty())
1327 message(_("Canceled."));
1330 if (filename.empty())
1333 // get absolute path of file
1334 FileName const fullname(makeAbsPath(filename));
1336 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1338 // Check if the document already is open
1339 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1342 if (!closeBuffer()) {
1343 message(_("Canceled."));
1348 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1350 // if the file exists already, and we didn't do
1351 // -i lyx thefile.lyx, warn
1352 if (lyxfile.exists() && fullname != lyxfile) {
1354 docstring text = bformat(_("The document %1$s already exists.\n\n"
1355 "Do you want to overwrite that document?"), displaypath);
1356 int const ret = Alert::prompt(_("Overwrite document?"),
1357 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1360 message(_("Canceled."));
1365 message(bformat(_("Importing %1$s..."), displaypath));
1366 ErrorList errorList;
1367 if (import(this, fullname, format, errorList))
1368 message(_("imported."));
1370 message(_("file not imported!"));
1372 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1376 void GuiView::newDocument(string const & filename, bool from_template)
1378 FileName initpath(lyxrc.document_path);
1379 Buffer * buf = buffer();
1381 FileName const trypath(buf->filePath());
1382 // If directory is writeable, use this as default.
1383 if (trypath.isDirWritable())
1387 string templatefile = from_template ?
1388 selectTemplateFile().absFilename() : string();
1390 if (filename.empty())
1391 b = newUnnamedFile(templatefile, initpath);
1393 b = newFile(filename, templatefile, true);
1397 // Ensure the cursor is correctly positionned on screen.
1398 view()->showCursor();
1402 void GuiView::insertLyXFile(docstring const & fname)
1404 BufferView * bv = view();
1409 FileName filename(to_utf8(fname));
1411 if (!filename.empty()) {
1412 bv->insertLyXFile(filename);
1416 // Launch a file browser
1418 string initpath = lyxrc.document_path;
1419 string const trypath = bv->buffer().filePath();
1420 // If directory is writeable, use this as default.
1421 if (FileName(trypath).isDirWritable())
1425 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1426 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1427 dlg.setButton2(qt_("Examples|#E#e"),
1428 toqstr(addPath(package().system_support().absFilename(),
1431 FileDialog::Result result = dlg.open(toqstr(initpath),
1432 QStringList(qt_("LyX Documents (*.lyx)")));
1434 if (result.first == FileDialog::Later)
1438 filename.set(fromqstr(result.second));
1440 // check selected filename
1441 if (filename.empty()) {
1442 // emit message signal.
1443 message(_("Canceled."));
1447 bv->insertLyXFile(filename);
1451 void GuiView::insertPlaintextFile(docstring const & fname,
1454 BufferView * bv = view();
1459 FileName filename(to_utf8(fname));
1461 if (!filename.empty()) {
1462 bv->insertPlaintextFile(filename, asParagraph);
1466 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1467 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1469 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1472 if (result.first == FileDialog::Later)
1476 filename.set(fromqstr(result.second));
1478 // check selected filename
1479 if (filename.empty()) {
1480 // emit message signal.
1481 message(_("Canceled."));
1485 bv->insertPlaintextFile(filename, asParagraph);
1489 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1491 FileName fname = b.fileName();
1492 FileName const oldname = fname;
1494 if (!newname.empty()) {
1496 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1498 // Switch to this Buffer.
1501 /// No argument? Ask user through dialog.
1503 FileDialog dlg(qt_("Choose a filename to save document as"),
1504 LFUN_BUFFER_WRITE_AS);
1505 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1506 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1508 if (!isLyXFilename(fname.absFilename()))
1509 fname.changeExtension(".lyx");
1511 FileDialog::Result result =
1512 dlg.save(toqstr(fname.onlyPath().absFilename()),
1513 QStringList(qt_("LyX Documents (*.lyx)")),
1514 toqstr(fname.onlyFileName()));
1516 if (result.first == FileDialog::Later)
1519 fname.set(fromqstr(result.second));
1524 if (!isLyXFilename(fname.absFilename()))
1525 fname.changeExtension(".lyx");
1528 if (FileName(fname).exists()) {
1529 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1530 docstring text = bformat(_("The document %1$s already "
1531 "exists.\n\nDo you want to "
1532 "overwrite that document?"),
1534 int const ret = Alert::prompt(_("Overwrite document?"),
1535 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1538 case 1: return renameBuffer(b, docstring());
1539 case 2: return false;
1543 // Ok, change the name of the buffer
1544 b.setFileName(fname.absFilename());
1546 bool unnamed = b.isUnnamed();
1547 b.setUnnamed(false);
1548 b.saveCheckSum(fname);
1550 if (!saveBuffer(b)) {
1551 b.setFileName(oldname.absFilename());
1552 b.setUnnamed(unnamed);
1553 b.saveCheckSum(oldname);
1561 bool GuiView::saveBuffer(Buffer & b)
1564 return renameBuffer(b, docstring());
1567 LyX::ref().session().lastFiles().add(b.fileName());
1571 // Switch to this Buffer.
1574 // FIXME: we don't tell the user *WHY* the save failed !!
1575 docstring const file = makeDisplayPath(b.absFileName(), 30);
1576 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1577 "Do you want to rename the document and "
1578 "try again?"), file);
1579 int const ret = Alert::prompt(_("Rename and save?"),
1580 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1583 if (!renameBuffer(b, docstring()))
1592 return saveBuffer(b);
1596 bool GuiView::closeBuffer()
1598 Buffer * buf = buffer();
1599 return buf && closeBuffer(*buf);
1603 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1605 // goto bookmark to update bookmark pit.
1606 //FIXME: we should update only the bookmarks related to this buffer!
1607 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1608 theLyXFunc().gotoBookmark(i+1, false, false);
1610 if (buf.isClean() || buf.paragraphs().empty()) {
1611 if (buf.masterBuffer() == &buf && tolastopened)
1612 LyX::ref().session().lastOpened().add(buf.fileName());
1613 theBufferList().release(&buf);
1616 // Switch to this Buffer.
1621 if (buf.isUnnamed())
1622 file = from_utf8(buf.fileName().onlyFileName());
1624 file = buf.fileName().displayName(30);
1626 // Bring this window to top before asking questions.
1630 docstring const text = bformat(_("The document %1$s has unsaved changes."
1631 "\n\nDo you want to save the document or discard the changes?"), file);
1632 int const ret = Alert::prompt(_("Save changed document?"),
1633 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1637 if (!saveBuffer(buf))
1641 // if we crash after this we could
1642 // have no autosave file but I guess
1643 // this is really improbable (Jug)
1644 removeAutosaveFile(buf.absFileName());
1650 // save file names to .lyx/session
1651 // if master/slave are both open, do not save slave since it
1652 // will be automatically loaded when the master is loaded
1653 if (buf.masterBuffer() == &buf && tolastopened)
1654 LyX::ref().session().lastOpened().add(buf.fileName());
1656 theBufferList().release(&buf);
1661 bool GuiView::dispatch(FuncRequest const & cmd)
1663 BufferView * bv = view();
1664 // By default we won't need any update.
1666 bv->cursor().updateFlags(Update::None);
1668 switch(cmd.action) {
1669 case LFUN_BUFFER_IMPORT:
1670 importDocument(to_utf8(cmd.argument()));
1673 case LFUN_BUFFER_SWITCH:
1674 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1677 case LFUN_BUFFER_NEXT:
1678 setBuffer(theBufferList().next(buffer()));
1681 case LFUN_BUFFER_PREVIOUS:
1682 setBuffer(theBufferList().previous(buffer()));
1685 case LFUN_COMMAND_EXECUTE: {
1686 bool const show_it = cmd.argument() != "off";
1687 d.toolbars_->showCommandBuffer(show_it);
1690 case LFUN_DROP_LAYOUTS_CHOICE:
1692 d.layout_->showPopup();
1695 case LFUN_MENU_OPEN:
1696 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1697 menu->exec(QCursor::pos());
1700 case LFUN_FILE_INSERT:
1701 insertLyXFile(cmd.argument());
1703 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1704 insertPlaintextFile(cmd.argument(), true);
1707 case LFUN_FILE_INSERT_PLAINTEXT:
1708 insertPlaintextFile(cmd.argument(), false);
1711 case LFUN_BUFFER_WRITE:
1713 saveBuffer(bv->buffer());
1716 case LFUN_BUFFER_WRITE_AS:
1718 renameBuffer(bv->buffer(), cmd.argument());
1721 case LFUN_BUFFER_WRITE_ALL: {
1722 Buffer * first = theBufferList().first();
1725 message(_("Saving all documents..."));
1726 // We cannot use a for loop as the buffer list cycles.
1729 if (!b->isClean()) {
1731 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1733 b = theBufferList().next(b);
1734 } while (b != first);
1735 message(_("All documents saved."));
1739 case LFUN_TOOLBAR_TOGGLE: {
1740 string const name = cmd.getArg(0);
1741 bool const allowauto = cmd.getArg(1) == "allowauto";
1742 // it is possible to get current toolbar status like this,...
1743 // but I decide to obey the order of ToolbarBackend::flags
1744 // and disregard real toolbar status.
1745 // toolbars_->saveToolbarInfo();
1747 // toggle state on/off/auto
1748 d.toolbars_->toggleToolbarState(name, allowauto);
1752 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1754 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1758 if (tbi->flags & ToolbarInfo::ON)
1760 else if (tbi->flags & ToolbarInfo::OFF)
1762 else if (tbi->flags & ToolbarInfo::AUTO)
1765 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1766 _(tbi->gui_name), state));
1770 case LFUN_DIALOG_UPDATE: {
1771 string const name = to_utf8(cmd.argument());
1772 // Can only update a dialog connected to an existing inset
1773 Inset * inset = getOpenInset(name);
1775 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1776 inset->dispatch(view()->cursor(), fr);
1777 } else if (name == "paragraph") {
1778 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1779 } else if (name == "prefs") {
1780 updateDialog(name, string());
1785 case LFUN_DIALOG_TOGGLE: {
1786 if (isDialogVisible(cmd.getArg(0)))
1787 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1789 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1793 case LFUN_DIALOG_DISCONNECT_INSET:
1794 disconnectDialog(to_utf8(cmd.argument()));
1797 case LFUN_DIALOG_HIDE: {
1798 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1802 case LFUN_DIALOG_SHOW: {
1803 string const name = cmd.getArg(0);
1804 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1806 if (name == "character") {
1807 data = freefont2string();
1809 showDialog("character", data);
1810 } else if (name == "latexlog") {
1811 Buffer::LogType type;
1812 string const logfile = buffer()->logName(&type);
1814 case Buffer::latexlog:
1817 case Buffer::buildlog:
1821 data += Lexer::quoteString(logfile);
1822 showDialog("log", data);
1823 } else if (name == "vclog") {
1824 string const data = "vc " +
1825 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1826 showDialog("log", data);
1827 } else if (name == "symbols") {
1828 data = bv->cursor().getEncoding()->name();
1830 showDialog("symbols", data);
1832 showDialog(name, data);
1836 case LFUN_INSET_APPLY: {
1837 string const name = cmd.getArg(0);
1838 Inset * inset = getOpenInset(name);
1840 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1841 inset->dispatch(view()->cursor(), fr);
1843 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1849 case LFUN_UI_TOGGLE:
1851 // Make sure the keyboard focus stays in the work area.
1855 case LFUN_COMPLETION_INLINE:
1856 if (d.current_work_area_)
1857 d.current_work_area_->completer().showInline();
1860 case LFUN_SPLIT_VIEW:
1861 if (Buffer * buf = buffer()) {
1862 string const orientation = cmd.getArg(0);
1863 d.splitter_->setOrientation(orientation == "vertical"
1864 ? Qt::Vertical : Qt::Horizontal);
1865 TabWorkArea * twa = addTabWorkArea();
1866 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1867 setCurrentWorkArea(wa);
1871 case LFUN_CLOSE_TAB_GROUP:
1872 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1874 twa = d.currentTabWorkArea();
1875 // Switch to the next GuiWorkArea in the found TabWorkArea.
1876 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1877 if (d.splitter_->count() == 0)
1878 // No more work area, switch to the background widget.
1883 case LFUN_COMPLETION_POPUP:
1884 if (d.current_work_area_)
1885 d.current_work_area_->completer().showPopup();
1889 case LFUN_COMPLETION_COMPLETE:
1890 if (d.current_work_area_)
1891 d.current_work_area_->completer().tab();
1902 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1904 string const arg = cmd.getArg(0);
1905 if (arg == "scrollbar") {
1906 // hide() is of no help
1907 if (d.current_work_area_->verticalScrollBarPolicy() ==
1908 Qt::ScrollBarAlwaysOff)
1910 d.current_work_area_->setVerticalScrollBarPolicy(
1911 Qt::ScrollBarAsNeeded);
1913 d.current_work_area_->setVerticalScrollBarPolicy(
1914 Qt::ScrollBarAlwaysOff);
1917 if (arg == "statusbar") {
1918 statusBar()->setVisible(!statusBar()->isVisible());
1921 if (arg == "menubar") {
1922 menuBar()->setVisible(!menuBar()->isVisible());
1925 #if QT_VERSION >= 0x040300
1926 if (arg == "frame") {
1928 getContentsMargins(&l, &t, &r, &b);
1929 //are the frames in default state?
1930 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1932 setContentsMargins(-2, -2, -2, -2);
1934 setContentsMargins(0, 0, 0, 0);
1939 if (arg != "fullscreen") {
1940 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1944 if (lyxrc.full_screen_toolbars)
1945 d.toolbars_->toggleFullScreen(!isFullScreen());
1947 if (isFullScreen()) {
1948 for (int i = 0; i != d.splitter_->count(); ++i)
1949 d.tabWorkArea(i)->setFullScreen(false);
1950 #if QT_VERSION >= 0x040300
1951 setContentsMargins(0, 0, 0, 0);
1953 setWindowState(windowState() ^ Qt::WindowFullScreen);
1955 statusBar()->show();
1957 for (int i = 0; i != d.splitter_->count(); ++i)
1958 d.tabWorkArea(i)->setFullScreen(true);
1959 #if QT_VERSION >= 0x040300
1960 setContentsMargins(-2, -2, -2, -2);
1962 setWindowState(windowState() ^ Qt::WindowFullScreen);
1963 statusBar()->hide();
1969 Buffer const * GuiView::updateInset(Inset const * inset)
1971 if (!d.current_work_area_)
1975 d.current_work_area_->scheduleRedraw();
1977 return &d.current_work_area_->bufferView().buffer();
1981 void GuiView::restartCursor()
1983 /* When we move around, or type, it's nice to be able to see
1984 * the cursor immediately after the keypress.
1986 if (d.current_work_area_)
1987 d.current_work_area_->startBlinkingCursor();
1989 // Take this occasion to update the other GUI elements.
1996 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1998 if (d.current_work_area_)
1999 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2004 // This list should be kept in sync with the list of insets in
2005 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2006 // dialog should have the same name as the inset.
2008 char const * const dialognames[] = {
2009 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2010 "citation", "document", "errorlist", "ert", "external", "file",
2011 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2012 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2013 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2015 #ifdef HAVE_LIBAIKSAURUS
2019 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2021 char const * const * const end_dialognames =
2022 dialognames + (sizeof(dialognames) / sizeof(char *));
2026 cmpCStr(char const * name) : name_(name) {}
2027 bool operator()(char const * other) {
2028 return strcmp(other, name_) == 0;
2035 bool isValidName(string const & name)
2037 return find_if(dialognames, end_dialognames,
2038 cmpCStr(name.c_str())) != end_dialognames;
2044 void GuiView::resetDialogs()
2046 // Make sure that no LFUN uses any LyXView.
2047 theLyXFunc().setLyXView(0);
2048 // FIXME: the "math panels" toolbar takes an awful lot of time to
2049 // initialise so we don't do that for the time being.
2050 //d.toolbars_->init();
2051 guiApp->menus().fillMenuBar(menuBar(), this);
2053 d.layout_->updateContents(true);
2054 // Now update controls with current buffer.
2055 theLyXFunc().setLyXView(this);
2060 Dialog * GuiView::find_or_build(string const & name)
2062 if (!isValidName(name))
2065 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2067 if (it != d.dialogs_.end())
2068 return it->second.get();
2070 Dialog * dialog = build(name);
2071 d.dialogs_[name].reset(dialog);
2072 if (lyxrc.allow_geometry_session)
2073 dialog->restoreSession();
2078 void GuiView::showDialog(string const & name, string const & data,
2085 Dialog * dialog = find_or_build(name);
2087 dialog->showData(data);
2089 d.open_insets_[name] = inset;
2095 bool GuiView::isDialogVisible(string const & name) const
2097 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2098 if (it == d.dialogs_.end())
2100 return it->second.get()->isVisibleView();
2104 void GuiView::hideDialog(string const & name, Inset * inset)
2106 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2107 if (it == d.dialogs_.end())
2110 if (inset && inset != getOpenInset(name))
2113 Dialog * const dialog = it->second.get();
2114 if (dialog->isVisibleView())
2116 d.open_insets_[name] = 0;
2120 void GuiView::disconnectDialog(string const & name)
2122 if (!isValidName(name))
2125 if (d.open_insets_.find(name) != d.open_insets_.end())
2126 d.open_insets_[name] = 0;
2130 Inset * GuiView::getOpenInset(string const & name) const
2132 if (!isValidName(name))
2135 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2136 return it == d.open_insets_.end() ? 0 : it->second;
2140 void GuiView::hideAll() const
2142 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2143 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2145 for(; it != end; ++it)
2146 it->second->hideView();
2150 void GuiView::hideBufferDependent() const
2152 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2153 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2155 for(; it != end; ++it) {
2156 Dialog * dialog = it->second.get();
2157 if (dialog->isBufferDependent())
2163 void GuiView::updateBufferDependent(bool switched) const
2165 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2166 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2168 for(; it != end; ++it) {
2169 Dialog * dialog = it->second.get();
2170 if (!dialog->isVisibleView())
2172 if (switched && dialog->isBufferDependent()) {
2173 if (dialog->initialiseParams(""))
2174 dialog->updateView();
2178 // A bit clunky, but the dialog will request
2179 // that the kernel provides it with the necessary
2181 dialog->updateDialog();
2187 void GuiView::checkStatus()
2189 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2190 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2192 for(; it != end; ++it) {
2193 Dialog * const dialog = it->second.get();
2194 if (dialog && dialog->isVisibleView())
2195 dialog->checkStatus();
2201 // will be replaced by a proper factory...
2202 Dialog * createGuiAbout(GuiView & lv);
2203 Dialog * createGuiBibitem(GuiView & lv);
2204 Dialog * createGuiBibtex(GuiView & lv);
2205 Dialog * createGuiBox(GuiView & lv);
2206 Dialog * createGuiBranch(GuiView & lv);
2207 Dialog * createGuiChanges(GuiView & lv);
2208 Dialog * createGuiCharacter(GuiView & lv);
2209 Dialog * createGuiCitation(GuiView & lv);
2210 Dialog * createGuiDelimiter(GuiView & lv);
2211 Dialog * createGuiDocument(GuiView & lv);
2212 Dialog * createGuiErrorList(GuiView & lv);
2213 Dialog * createGuiERT(GuiView & lv);
2214 Dialog * createGuiExternal(GuiView & lv);
2215 Dialog * createGuiFloat(GuiView & lv);
2216 Dialog * createGuiGraphics(GuiView & lv);
2217 Dialog * createGuiHSpace(GuiView & lv);
2218 Dialog * createGuiInclude(GuiView & lv);
2219 Dialog * createGuiLabel(GuiView & lv);
2220 Dialog * createGuiListings(GuiView & lv);
2221 Dialog * createGuiLog(GuiView & lv);
2222 Dialog * createGuiMathMatrix(GuiView & lv);
2223 Dialog * createGuiNomenclature(GuiView & lv);
2224 Dialog * createGuiNote(GuiView & lv);
2225 Dialog * createGuiParagraph(GuiView & lv);
2226 Dialog * createGuiPreferences(GuiView & lv);
2227 Dialog * createGuiPrint(GuiView & lv);
2228 Dialog * createGuiRef(GuiView & lv);
2229 Dialog * createGuiSearch(GuiView & lv);
2230 Dialog * createGuiSendTo(GuiView & lv);
2231 Dialog * createGuiShowFile(GuiView & lv);
2232 Dialog * createGuiSpellchecker(GuiView & lv);
2233 Dialog * createGuiSymbols(GuiView & lv);
2234 Dialog * createGuiTabularCreate(GuiView & lv);
2235 Dialog * createGuiTabular(GuiView & lv);
2236 Dialog * createGuiTexInfo(GuiView & lv);
2237 Dialog * createGuiToc(GuiView & lv);
2238 Dialog * createGuiThesaurus(GuiView & lv);
2239 Dialog * createGuiHyperlink(GuiView & lv);
2240 Dialog * createGuiVSpace(GuiView & lv);
2241 Dialog * createGuiViewSource(GuiView & lv);
2242 Dialog * createGuiWrap(GuiView & lv);
2245 Dialog * GuiView::build(string const & name)
2247 LASSERT(isValidName(name), /**/);
2249 if (name == "aboutlyx")
2250 return createGuiAbout(*this);
2251 if (name == "bibitem")
2252 return createGuiBibitem(*this);
2253 if (name == "bibtex")
2254 return createGuiBibtex(*this);
2256 return createGuiBox(*this);
2257 if (name == "branch")
2258 return createGuiBranch(*this);
2259 if (name == "changes")
2260 return createGuiChanges(*this);
2261 if (name == "character")
2262 return createGuiCharacter(*this);
2263 if (name == "citation")
2264 return createGuiCitation(*this);
2265 if (name == "document")
2266 return createGuiDocument(*this);
2267 if (name == "errorlist")
2268 return createGuiErrorList(*this);
2270 return createGuiERT(*this);
2271 if (name == "external")
2272 return createGuiExternal(*this);
2274 return createGuiShowFile(*this);
2275 if (name == "findreplace")
2276 return createGuiSearch(*this);
2277 if (name == "float")
2278 return createGuiFloat(*this);
2279 if (name == "graphics")
2280 return createGuiGraphics(*this);
2281 if (name == "include")
2282 return createGuiInclude(*this);
2283 if (name == "nomenclature")
2284 return createGuiNomenclature(*this);
2285 if (name == "label")
2286 return createGuiLabel(*this);
2288 return createGuiLog(*this);
2289 if (name == "view-source")
2290 return createGuiViewSource(*this);
2291 if (name == "mathdelimiter")
2292 return createGuiDelimiter(*this);
2293 if (name == "mathmatrix")
2294 return createGuiMathMatrix(*this);
2296 return createGuiNote(*this);
2297 if (name == "paragraph")
2298 return createGuiParagraph(*this);
2299 if (name == "prefs")
2300 return createGuiPreferences(*this);
2301 if (name == "print")
2302 return createGuiPrint(*this);
2304 return createGuiRef(*this);
2305 if (name == "sendto")
2306 return createGuiSendTo(*this);
2307 if (name == "space")
2308 return createGuiHSpace(*this);
2309 if (name == "spellchecker")
2310 return createGuiSpellchecker(*this);
2311 if (name == "symbols")
2312 return createGuiSymbols(*this);
2313 if (name == "tabular")
2314 return createGuiTabular(*this);
2315 if (name == "tabularcreate")
2316 return createGuiTabularCreate(*this);
2317 if (name == "texinfo")
2318 return createGuiTexInfo(*this);
2319 #ifdef HAVE_LIBAIKSAURUS
2320 if (name == "thesaurus")
2321 return createGuiThesaurus(*this);
2324 return createGuiToc(*this);
2326 return createGuiHyperlink(*this);
2327 if (name == "vspace")
2328 return createGuiVSpace(*this);
2330 return createGuiWrap(*this);
2331 if (name == "listings")
2332 return createGuiListings(*this);
2338 } // namespace frontend
2341 #include "GuiView_moc.cpp"