3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiCompleter.h"
22 #include "GuiWorkArea.h"
23 #include "GuiKeySymbol.h"
24 #include "GuiToolbar.h"
25 #include "GuiToolbars.h"
28 #include "qt_helpers.h"
30 #include "frontends/alert.h"
32 #include "buffer_funcs.h"
34 #include "BufferList.h"
35 #include "BufferParams.h"
36 #include "BufferView.h"
37 #include "Converter.h"
40 #include "ErrorList.h"
42 #include "FuncStatus.h"
43 #include "FuncRequest.h"
51 #include "Paragraph.h"
52 #include "TextClass.h"
54 #include "ToolbarBackend.h"
57 #include "support/assert.h"
58 #include "support/debug.h"
59 #include "support/FileName.h"
60 #include "support/filetools.h"
61 #include "support/gettext.h"
62 #include "support/ForkedCalls.h"
63 #include "support/lstrings.h"
64 #include "support/os.h"
65 #include "support/Package.h"
66 #include "support/Timeout.h"
69 #include <QApplication>
70 #include <QCloseEvent>
72 #include <QDesktopWidget>
73 #include <QDragEnterEvent>
81 #include <QPushButton>
85 #include <QStackedWidget>
92 #include <boost/bind.hpp>
94 #ifdef HAVE_SYS_TIME_H
95 # include <sys/time.h>
102 using namespace lyx::support;
109 class BackgroundWidget : public QWidget
114 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
115 /// The text to be written on top of the pixmap
116 QString const text = lyx_version ?
117 qt_("version ") + lyx_version : qt_("unknown version");
118 splash_ = QPixmap(":/images/banner.png");
120 QPainter pain(&splash_);
121 pain.setPen(QColor(0, 0, 0));
123 // The font used to display the version info
124 font.setStyleHint(QFont::SansSerif);
125 font.setWeight(QFont::Bold);
126 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
128 pain.drawText(190, 225, text);
131 void paintEvent(QPaintEvent *)
133 int x = (width() - splash_.width()) / 2;
134 int y = (height() - splash_.height()) / 2;
136 pain.drawPixmap(x, y, splash_);
146 typedef boost::shared_ptr<Dialog> DialogPtr;
148 struct GuiView::GuiViewPrivate
151 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
154 // hardcode here the platform specific icon size
155 smallIconSize = 14; // scaling problems
156 normalIconSize = 20; // ok, default
157 bigIconSize = 26; // better for some math icons
159 splitter_ = new QSplitter;
160 bg_widget_ = new BackgroundWidget;
161 stack_widget_ = new QStackedWidget;
162 stack_widget_->addWidget(bg_widget_);
163 stack_widget_->addWidget(splitter_);
171 delete stack_widget_;
175 QMenu * toolBarPopup(GuiView * parent)
177 // FIXME: translation
178 QMenu * menu = new QMenu(parent);
179 QActionGroup * iconSizeGroup = new QActionGroup(parent);
181 QAction * smallIcons = new QAction(iconSizeGroup);
182 smallIcons->setText(qt_("Small-sized icons"));
183 smallIcons->setCheckable(true);
184 QObject::connect(smallIcons, SIGNAL(triggered()),
185 parent, SLOT(smallSizedIcons()));
186 menu->addAction(smallIcons);
188 QAction * normalIcons = new QAction(iconSizeGroup);
189 normalIcons->setText(qt_("Normal-sized icons"));
190 normalIcons->setCheckable(true);
191 QObject::connect(normalIcons, SIGNAL(triggered()),
192 parent, SLOT(normalSizedIcons()));
193 menu->addAction(normalIcons);
195 QAction * bigIcons = new QAction(iconSizeGroup);
196 bigIcons->setText(qt_("Big-sized icons"));
197 bigIcons->setCheckable(true);
198 QObject::connect(bigIcons, SIGNAL(triggered()),
199 parent, SLOT(bigSizedIcons()));
200 menu->addAction(bigIcons);
202 unsigned int cur = parent->iconSize().width();
203 if ( cur == parent->d.smallIconSize)
204 smallIcons->setChecked(true);
205 else if (cur == parent->d.normalIconSize)
206 normalIcons->setChecked(true);
207 else if (cur == parent->d.bigIconSize)
208 bigIcons->setChecked(true);
215 stack_widget_->setCurrentWidget(bg_widget_);
216 bg_widget_->setUpdatesEnabled(true);
219 TabWorkArea * tabWorkArea(int i)
221 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
224 TabWorkArea * currentTabWorkArea()
226 if (splitter_->count() == 1)
227 // The first TabWorkArea is always the first one, if any.
228 return tabWorkArea(0);
230 for (int i = 0; i != splitter_->count(); ++i) {
231 TabWorkArea * twa = tabWorkArea(i);
232 if (current_work_area_ == twa->currentWorkArea())
236 // None has the focus so we just take the first one.
237 return tabWorkArea(0);
241 GuiWorkArea * current_work_area_;
242 QSplitter * splitter_;
243 QStackedWidget * stack_widget_;
244 BackgroundWidget * bg_widget_;
246 GuiToolbars * toolbars_;
247 /// The main layout box.
249 * \warning Don't Delete! The layout box is actually owned by
250 * whichever toolbar contains it. All the GuiView class needs is a
251 * means of accessing it.
253 * FIXME: replace that with a proper model so that we are not limited
254 * to only one dialog.
256 GuiLayoutBox * layout_;
259 map<string, Inset *> open_insets_;
262 map<string, DialogPtr> dialogs_;
264 unsigned int smallIconSize;
265 unsigned int normalIconSize;
266 unsigned int bigIconSize;
268 QTimer statusbar_timer_;
269 /// auto-saving of buffers
270 Timeout autosave_timeout_;
271 /// flag against a race condition due to multiclicks, see bug #1119
276 GuiView::GuiView(int id)
277 : d(*new GuiViewPrivate), id_(id)
279 // GuiToolbars *must* be initialised before the menu bar.
280 d.toolbars_ = new GuiToolbars(*this);
282 // set ourself as the current view. This is needed for the menu bar
283 // filling, at least for the static special menu item on Mac. Otherwise
284 // they are greyed out.
285 theLyXFunc().setLyXView(this);
287 // Fill up the menu bar.
288 guiApp->menus().fillMenuBar(menuBar(), this, true);
290 setCentralWidget(d.stack_widget_);
292 // Start autosave timer
293 if (lyxrc.autosave) {
294 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
295 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
296 d.autosave_timeout_.start();
298 connect(&d.statusbar_timer_, SIGNAL(timeout()),
299 this, SLOT(clearMessage()));
301 // We don't want to keep the window in memory if it is closed.
302 setAttribute(Qt::WA_DeleteOnClose, true);
304 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
305 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
306 // since the icon is provided in the application bundle.
307 setWindowIcon(QPixmap(":/images/lyx.png"));
311 setAcceptDrops(true);
313 statusBar()->setSizeGripEnabled(true);
315 // Forbid too small unresizable window because it can happen
316 // with some window manager under X11.
317 setMinimumSize(300, 200);
319 if (!lyxrc.allow_geometry_session)
320 // No session handling, default to a sane size.
321 setGeometry(50, 50, 690, 510);
323 // Now take care of session management.
325 QString const key = "view-" + QString::number(id_);
327 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
328 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
332 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
333 setGeometry(50, 50, 690, 510);
335 setIconSize(settings.value(key + "/icon_size").toSize());
341 if (guiApp->currentView() == this)
342 guiApp->setCurrentView(0);
343 theLyXFunc().setLyXView(0);
349 void GuiView::setFocus()
351 if (d.current_work_area_)
352 d.current_work_area_->setFocus();
358 QMenu * GuiView::createPopupMenu()
360 return d.toolBarPopup(this);
364 void GuiView::showEvent(QShowEvent * e)
366 LYXERR(Debug::GUI, "Passed Geometry "
367 << size().height() << "x" << size().width()
368 << "+" << pos().x() << "+" << pos().y());
370 if (d.splitter_->count() == 0)
371 // No work area, switch to the background widget.
374 QMainWindow::showEvent(e);
378 void GuiView::closeEvent(QCloseEvent * close_event)
380 // it can happen that this event arrives without selecting the view,
381 // e.g. when clicking the close button on a background window.
382 theLyXFunc().setLyXView(this);
384 while (Buffer * b = buffer()) {
386 // This is a child document, just close the tab after saving
387 // but keep the file loaded.
388 if (!saveBuffer(*b)) {
389 close_event->ignore();
392 removeWorkArea(d.current_work_area_);
396 std::vector<int> const & ids = guiApp->viewIds();
397 for (size_type i = 0; i != ids.size(); ++i) {
400 if (guiApp->view(ids[i]).workArea(*b)) {
401 // FIXME 1: should we put an alert box here that the buffer
402 // is viewed elsewhere?
403 // FIXME 2: should we try to save this buffer in any case?
406 // This buffer is also opened in another view, so
407 // but close the associated work area nevertheless.
408 removeWorkArea(d.current_work_area_);
409 // but don't close it.
414 if (b && !closeBuffer(*b, true)) {
415 close_event->ignore();
420 // Make sure that no LFUN use this close to be closed View.
421 theLyXFunc().setLyXView(0);
423 // Save toolbars configuration
424 if (isFullScreen()) {
425 d.toolbars_->toggleFullScreen(!isFullScreen());
429 // Make sure the timer time out will not trigger a statusbar update.
430 d.statusbar_timer_.stop();
432 // Saving fullscreen requires additional tweaks in the toolbar code.
433 // It wouldn't also work under linux natively.
434 if (lyxrc.allow_geometry_session && !isFullScreen()) {
436 QString const key = "view-" + QString::number(id_);
438 settings.setValue(key + "/pos", pos());
439 settings.setValue(key + "/size", size());
441 settings.setValue(key + "/geometry", saveGeometry());
443 settings.setValue(key + "/icon_size", iconSize());
444 d.toolbars_->saveToolbarInfo();
445 // Now take care of all other dialogs:
446 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
447 for (; it!= d.dialogs_.end(); ++it)
448 it->second->saveSession();
451 guiApp->unregisterView(id_);
452 close_event->accept();
456 void GuiView::dragEnterEvent(QDragEnterEvent * event)
458 if (event->mimeData()->hasUrls())
460 /// \todo Ask lyx-devel is this is enough:
461 /// if (event->mimeData()->hasFormat("text/plain"))
462 /// event->acceptProposedAction();
466 void GuiView::dropEvent(QDropEvent* event)
468 QList<QUrl> files = event->mimeData()->urls();
472 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
473 for (int i = 0; i != files.size(); ++i) {
474 string const file = os::internal_path(fromqstr(
475 files.at(i).toLocalFile()));
477 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
482 void GuiView::message(docstring const & str)
484 if (ForkedProcess::iAmAChild())
487 statusBar()->showMessage(toqstr(str));
488 d.statusbar_timer_.stop();
489 d.statusbar_timer_.start(3000);
493 void GuiView::smallSizedIcons()
495 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
499 void GuiView::normalSizedIcons()
501 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
505 void GuiView::bigSizedIcons()
507 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
511 void GuiView::clearMessage()
515 theLyXFunc().setLyXView(this);
516 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
517 d.statusbar_timer_.stop();
521 void GuiView::updateWindowTitle(GuiWorkArea * wa)
523 if (wa != d.current_work_area_)
525 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
526 setWindowIconText(wa->windowIconText());
530 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
533 disconnectBufferView();
534 connectBufferView(wa->bufferView());
535 connectBuffer(wa->bufferView().buffer());
536 d.current_work_area_ = wa;
537 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
538 this, SLOT(updateWindowTitle(GuiWorkArea *)));
539 updateWindowTitle(wa);
542 // Buffer-dependent dialogs should be updated or
543 // hidden. This should go here because some dialogs (eg ToC)
544 // require bv_->text.
545 updateBufferDependent(true);
552 void GuiView::on_lastWorkAreaRemoved()
555 // On Mac close the view if there is no Tab open anymore,
556 // but only if no splitter is visible
557 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
558 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
559 if (twa && twa->count() == 0) {
560 // close the view, as no tab is open anymore
561 QTimer::singleShot(0, this, SLOT(close()));
568 void GuiView::updateStatusBar()
570 // let the user see the explicit message
571 if (d.statusbar_timer_.isActive())
574 theLyXFunc().setLyXView(this);
575 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
579 bool GuiView::hasFocus() const
581 return qApp->activeWindow() == this;
585 bool GuiView::event(QEvent * e)
589 // Useful debug code:
590 //case QEvent::ActivationChange:
591 //case QEvent::WindowDeactivate:
592 //case QEvent::Paint:
593 //case QEvent::Enter:
594 //case QEvent::Leave:
595 //case QEvent::HoverEnter:
596 //case QEvent::HoverLeave:
597 //case QEvent::HoverMove:
598 //case QEvent::StatusTip:
599 //case QEvent::DragEnter:
600 //case QEvent::DragLeave:
604 case QEvent::WindowActivate: {
605 if (this == guiApp->currentView()) {
607 return QMainWindow::event(e);
609 guiApp->setCurrentView(this);
610 if (d.current_work_area_) {
611 BufferView & bv = d.current_work_area_->bufferView();
612 connectBufferView(bv);
613 connectBuffer(bv.buffer());
614 // The document structure, name and dialogs might have
615 // changed in another view.
616 updateBufferDependent(true);
621 setWindowTitle(qt_("LyX"));
622 setWindowIconText(qt_("LyX"));
625 return QMainWindow::event(e);
628 case QEvent::ShortcutOverride: {
629 if (d.current_work_area_)
630 // Nothing special to do.
631 return QMainWindow::event(e);
633 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
635 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
637 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
638 || ke->key() == Qt::Key_Backtab)
639 return QMainWindow::event(e);
641 // Allow processing of shortcuts that are allowed even when no Buffer
643 theLyXFunc().setLyXView(this);
645 setKeySymbol(&sym, ke);
646 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
652 return QMainWindow::event(e);
657 bool GuiView::focusNextPrevChild(bool /*next*/)
664 void GuiView::setBusy(bool busy)
666 if (d.current_work_area_) {
667 d.current_work_area_->setUpdatesEnabled(!busy);
669 d.current_work_area_->stopBlinkingCursor();
671 d.current_work_area_->startBlinkingCursor();
675 QApplication::setOverrideCursor(Qt::WaitCursor);
677 QApplication::restoreOverrideCursor();
681 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
683 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
685 if (tbinfo.flags & ToolbarInfo::TOP) {
687 addToolBarBreak(Qt::TopToolBarArea);
688 addToolBar(Qt::TopToolBarArea, toolBar);
691 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
692 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
693 #if (QT_VERSION >= 0x040202)
695 addToolBarBreak(Qt::BottomToolBarArea);
697 addToolBar(Qt::BottomToolBarArea, toolBar);
700 if (tbinfo.flags & ToolbarInfo::LEFT) {
701 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
702 #if (QT_VERSION >= 0x040202)
704 addToolBarBreak(Qt::LeftToolBarArea);
706 addToolBar(Qt::LeftToolBarArea, toolBar);
709 if (tbinfo.flags & ToolbarInfo::RIGHT) {
710 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
711 #if (QT_VERSION >= 0x040202)
713 addToolBarBreak(Qt::RightToolBarArea);
715 addToolBar(Qt::RightToolBarArea, toolBar);
718 // The following does not work so I cannot restore to exact toolbar location
720 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
721 toolBar->move(tbinfo.posx, tbinfo.posy);
728 GuiWorkArea * GuiView::workArea(Buffer & buffer)
730 if (TabWorkArea * twa = d.currentTabWorkArea())
731 return twa->workArea(buffer);
736 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
738 // Automatically create a TabWorkArea if there are none yet.
739 TabWorkArea * tab_widget = d.splitter_->count()
740 ? d.currentTabWorkArea() : addTabWorkArea();
741 return tab_widget->addWorkArea(buffer, *this);
745 TabWorkArea * GuiView::addTabWorkArea()
747 TabWorkArea * twa = new TabWorkArea;
748 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
749 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
750 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
751 this, SLOT(on_lastWorkAreaRemoved()));
753 d.splitter_->addWidget(twa);
754 d.stack_widget_->setCurrentWidget(d.splitter_);
759 GuiWorkArea const * GuiView::currentWorkArea() const
761 return d.current_work_area_;
765 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
769 // Changing work area can result from opening a file so
770 // update the toc in any case.
773 d.current_work_area_ = wa;
774 for (int i = 0; i != d.splitter_->count(); ++i) {
775 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
781 void GuiView::removeWorkArea(GuiWorkArea * wa)
784 if (wa == d.current_work_area_) {
786 disconnectBufferView();
787 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(support::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 = support::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::updateBufferDependent(bool switched) 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->isVisibleView())
2159 if (switched && dialog->isBufferDependent()) {
2160 if (dialog->initialiseParams(""))
2161 dialog->updateView();
2165 // A bit clunky, but the dialog will request
2166 // that the kernel provides it with the necessary
2168 dialog->updateDialog();
2174 void GuiView::checkStatus()
2176 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2177 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2179 for(; it != end; ++it) {
2180 Dialog * const dialog = it->second.get();
2181 if (dialog && dialog->isVisibleView())
2182 dialog->checkStatus();
2188 // will be replaced by a proper factory...
2189 Dialog * createGuiAbout(GuiView & lv);
2190 Dialog * createGuiBibitem(GuiView & lv);
2191 Dialog * createGuiBibtex(GuiView & lv);
2192 Dialog * createGuiBox(GuiView & lv);
2193 Dialog * createGuiBranch(GuiView & lv);
2194 Dialog * createGuiChanges(GuiView & lv);
2195 Dialog * createGuiCharacter(GuiView & lv);
2196 Dialog * createGuiCitation(GuiView & lv);
2197 Dialog * createGuiDelimiter(GuiView & lv);
2198 Dialog * createGuiDocument(GuiView & lv);
2199 Dialog * createGuiErrorList(GuiView & lv);
2200 Dialog * createGuiERT(GuiView & lv);
2201 Dialog * createGuiExternal(GuiView & lv);
2202 Dialog * createGuiFloat(GuiView & lv);
2203 Dialog * createGuiGraphics(GuiView & lv);
2204 Dialog * createGuiHSpace(GuiView & lv);
2205 Dialog * createGuiInclude(GuiView & lv);
2206 Dialog * createGuiLabel(GuiView & lv);
2207 Dialog * createGuiListings(GuiView & lv);
2208 Dialog * createGuiLog(GuiView & lv);
2209 Dialog * createGuiMathMatrix(GuiView & lv);
2210 Dialog * createGuiNomenclature(GuiView & lv);
2211 Dialog * createGuiNote(GuiView & lv);
2212 Dialog * createGuiParagraph(GuiView & lv);
2213 Dialog * createGuiPreferences(GuiView & lv);
2214 Dialog * createGuiPrint(GuiView & lv);
2215 Dialog * createGuiRef(GuiView & lv);
2216 Dialog * createGuiSearch(GuiView & lv);
2217 Dialog * createGuiSendTo(GuiView & lv);
2218 Dialog * createGuiShowFile(GuiView & lv);
2219 Dialog * createGuiSpellchecker(GuiView & lv);
2220 Dialog * createGuiSymbols(GuiView & lv);
2221 Dialog * createGuiTabularCreate(GuiView & lv);
2222 Dialog * createGuiTabular(GuiView & lv);
2223 Dialog * createGuiTexInfo(GuiView & lv);
2224 Dialog * createGuiToc(GuiView & lv);
2225 Dialog * createGuiThesaurus(GuiView & lv);
2226 Dialog * createGuiHyperlink(GuiView & lv);
2227 Dialog * createGuiVSpace(GuiView & lv);
2228 Dialog * createGuiViewSource(GuiView & lv);
2229 Dialog * createGuiWrap(GuiView & lv);
2232 Dialog * GuiView::build(string const & name)
2234 LASSERT(isValidName(name), /**/);
2236 if (name == "aboutlyx")
2237 return createGuiAbout(*this);
2238 if (name == "bibitem")
2239 return createGuiBibitem(*this);
2240 if (name == "bibtex")
2241 return createGuiBibtex(*this);
2243 return createGuiBox(*this);
2244 if (name == "branch")
2245 return createGuiBranch(*this);
2246 if (name == "changes")
2247 return createGuiChanges(*this);
2248 if (name == "character")
2249 return createGuiCharacter(*this);
2250 if (name == "citation")
2251 return createGuiCitation(*this);
2252 if (name == "document")
2253 return createGuiDocument(*this);
2254 if (name == "errorlist")
2255 return createGuiErrorList(*this);
2257 return createGuiERT(*this);
2258 if (name == "external")
2259 return createGuiExternal(*this);
2261 return createGuiShowFile(*this);
2262 if (name == "findreplace")
2263 return createGuiSearch(*this);
2264 if (name == "float")
2265 return createGuiFloat(*this);
2266 if (name == "graphics")
2267 return createGuiGraphics(*this);
2268 if (name == "include")
2269 return createGuiInclude(*this);
2270 if (name == "nomenclature")
2271 return createGuiNomenclature(*this);
2272 if (name == "label")
2273 return createGuiLabel(*this);
2275 return createGuiLog(*this);
2276 if (name == "view-source")
2277 return createGuiViewSource(*this);
2278 if (name == "mathdelimiter")
2279 return createGuiDelimiter(*this);
2280 if (name == "mathmatrix")
2281 return createGuiMathMatrix(*this);
2283 return createGuiNote(*this);
2284 if (name == "paragraph")
2285 return createGuiParagraph(*this);
2286 if (name == "prefs")
2287 return createGuiPreferences(*this);
2288 if (name == "print")
2289 return createGuiPrint(*this);
2291 return createGuiRef(*this);
2292 if (name == "sendto")
2293 return createGuiSendTo(*this);
2294 if (name == "space")
2295 return createGuiHSpace(*this);
2296 if (name == "spellchecker")
2297 return createGuiSpellchecker(*this);
2298 if (name == "symbols")
2299 return createGuiSymbols(*this);
2300 if (name == "tabular")
2301 return createGuiTabular(*this);
2302 if (name == "tabularcreate")
2303 return createGuiTabularCreate(*this);
2304 if (name == "texinfo")
2305 return createGuiTexInfo(*this);
2306 #ifdef HAVE_LIBAIKSAURUS
2307 if (name == "thesaurus")
2308 return createGuiThesaurus(*this);
2311 return createGuiToc(*this);
2313 return createGuiHyperlink(*this);
2314 if (name == "vspace")
2315 return createGuiVSpace(*this);
2317 return createGuiWrap(*this);
2318 if (name == "listings")
2319 return createGuiListings(*this);
2325 } // namespace frontend
2328 #include "GuiView_moc.cpp"