3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiWorkArea.h"
22 #include "GuiKeySymbol.h"
23 #include "GuiToolbar.h"
24 #include "GuiToolbars.h"
27 #include "qt_helpers.h"
29 #include "frontends/alert.h"
31 #include "buffer_funcs.h"
33 #include "BufferList.h"
34 #include "BufferParams.h"
35 #include "BufferView.h"
36 #include "Converter.h"
38 #include "ErrorList.h"
40 #include "FuncStatus.h"
41 #include "FuncRequest.h"
42 #include "support/gettext.h"
50 #include "Paragraph.h"
51 #include "TextClass.h"
53 #include "ToolbarBackend.h"
56 #include "support/debug.h"
57 #include "support/FileFilterList.h"
58 #include "support/FileName.h"
59 #include "support/filetools.h"
60 #include "support/ForkedCalls.h"
61 #include "support/lstrings.h"
62 #include "support/os.h"
63 #include "support/Package.h"
64 #include "support/Timeout.h"
67 #include <QApplication>
68 #include <QCloseEvent>
70 #include <QDesktopWidget>
71 #include <QDragEnterEvent>
79 #include <QPushButton>
83 #include <QStackedWidget>
90 #include <boost/assert.hpp>
91 #include <boost/bind.hpp>
93 #ifdef HAVE_SYS_TIME_H
94 # include <sys/time.h>
101 using namespace lyx::support;
108 class BackgroundWidget : public QWidget
113 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
114 /// The text to be written on top of the pixmap
115 QString const text = lyx_version ? lyx_version : qt_("unknown version");
116 splash_ = QPixmap(":/images/banner.png");
118 QPainter pain(&splash_);
119 pain.setPen(QColor(255, 255, 0));
121 // The font used to display the version info
122 font.setStyleHint(QFont::SansSerif);
123 font.setWeight(QFont::Bold);
124 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
126 pain.drawText(260, 270, text);
129 void paintEvent(QPaintEvent *)
131 int x = (width() - splash_.width()) / 2;
132 int y = (height() - splash_.height()) / 2;
134 pain.drawPixmap(x, y, splash_);
144 typedef boost::shared_ptr<Dialog> DialogPtr;
146 struct GuiView::GuiViewPrivate
149 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
152 // hardcode here the platform specific icon size
153 smallIconSize = 14; // scaling problems
154 normalIconSize = 20; // ok, default
155 bigIconSize = 26; // better for some math icons
157 splitter_ = new QSplitter;
158 bg_widget_ = new BackgroundWidget;
159 stack_widget_ = new QStackedWidget;
160 stack_widget_->addWidget(bg_widget_);
161 stack_widget_->addWidget(splitter_);
169 delete stack_widget_;
173 QMenu * toolBarPopup(GuiView * parent)
175 // FIXME: translation
176 QMenu * menu = new QMenu(parent);
177 QActionGroup * iconSizeGroup = new QActionGroup(parent);
179 QAction * smallIcons = new QAction(iconSizeGroup);
180 smallIcons->setText(qt_("Small-sized icons"));
181 smallIcons->setCheckable(true);
182 QObject::connect(smallIcons, SIGNAL(triggered()),
183 parent, SLOT(smallSizedIcons()));
184 menu->addAction(smallIcons);
186 QAction * normalIcons = new QAction(iconSizeGroup);
187 normalIcons->setText(qt_("Normal-sized icons"));
188 normalIcons->setCheckable(true);
189 QObject::connect(normalIcons, SIGNAL(triggered()),
190 parent, SLOT(normalSizedIcons()));
191 menu->addAction(normalIcons);
193 QAction * bigIcons = new QAction(iconSizeGroup);
194 bigIcons->setText(qt_("Big-sized icons"));
195 bigIcons->setCheckable(true);
196 QObject::connect(bigIcons, SIGNAL(triggered()),
197 parent, SLOT(bigSizedIcons()));
198 menu->addAction(bigIcons);
200 unsigned int cur = parent->iconSize().width();
201 if ( cur == parent->d.smallIconSize)
202 smallIcons->setChecked(true);
203 else if (cur == parent->d.normalIconSize)
204 normalIcons->setChecked(true);
205 else if (cur == parent->d.bigIconSize)
206 bigIcons->setChecked(true);
213 stack_widget_->setCurrentWidget(bg_widget_);
214 bg_widget_->setUpdatesEnabled(true);
217 TabWorkArea * tabWorkArea(int i)
219 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
222 TabWorkArea * currentTabWorkArea()
224 if (splitter_->count() == 1)
225 // The first TabWorkArea is always the first one, if any.
226 return tabWorkArea(0);
228 for (int i = 0; i != splitter_->count(); ++i) {
229 TabWorkArea * twa = tabWorkArea(i);
230 if (current_work_area_ == twa->currentWorkArea())
234 // None has the focus so we just take the first one.
235 return tabWorkArea(0);
239 GuiWorkArea * current_work_area_;
240 QSplitter * splitter_;
241 QStackedWidget * stack_widget_;
242 BackgroundWidget * bg_widget_;
244 GuiToolbars * toolbars_;
245 /// The main layout box.
247 * \warning Don't Delete! The layout box is actually owned by
248 * whichever toolbar contains it. All the GuiView class needs is a
249 * means of accessing it.
251 * FIXME: replace that with a proper model so that we are not limited
252 * to only one dialog.
254 GuiLayoutBox * layout_;
257 map<string, Inset *> open_insets_;
260 map<string, DialogPtr> dialogs_;
262 unsigned int smallIconSize;
263 unsigned int normalIconSize;
264 unsigned int bigIconSize;
266 QTimer statusbar_timer_;
267 /// auto-saving of buffers
268 Timeout autosave_timeout_;
269 /// flag against a race condition due to multiclicks, see bug #1119
274 GuiView::GuiView(int id)
275 : d(*new GuiViewPrivate), id_(id)
277 // GuiToolbars *must* be initialised before the menu bar.
278 d.toolbars_ = new GuiToolbars(*this);
280 // set ourself as the current view. This is needed for the menu bar
281 // filling, at least for the static special menu item on Mac. Otherwise
282 // they are greyed out.
283 theLyXFunc().setLyXView(this);
285 // Fill up the menu bar.
286 guiApp->menus().fillMenuBar(menuBar(), this);
288 setCentralWidget(d.stack_widget_);
290 // Start autosave timer
291 if (lyxrc.autosave) {
292 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
293 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
294 d.autosave_timeout_.start();
296 connect(&d.statusbar_timer_, SIGNAL(timeout()),
297 this, SLOT(clearMessage()));
299 // We don't want to keep the window in memory if it is closed.
300 setAttribute(Qt::WA_DeleteOnClose, true);
303 // assign an icon to main form. We do not do it under Qt/Mac,
304 // since the icon is provided in the application bundle.
305 setWindowIcon(QPixmap(":/images/lyx.png"));
309 setAcceptDrops(true);
311 statusBar()->setSizeGripEnabled(true);
313 // Forbid too small unresizable window because it can happen
314 // with some window manager under X11.
315 setMinimumSize(300, 200);
317 if (!lyxrc.allow_geometry_session)
318 // No session handling, default to a sane size.
319 setGeometry(50, 50, 690, 510);
321 // Now take care of session management.
323 QString const key = "view-" + QString::number(id_);
325 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
326 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
330 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
331 setGeometry(50, 50, 690, 510);
333 setIconSize(settings.value(key + "/icon_size").toSize());
339 if (guiApp->currentView() == this)
340 guiApp->setCurrentView(0);
341 theLyXFunc().setLyXView(0);
347 void GuiView::setFocus()
349 if (d.current_work_area_)
350 d.current_work_area_->setFocus();
356 QMenu * GuiView::createPopupMenu()
358 return d.toolBarPopup(this);
362 void GuiView::showEvent(QShowEvent * e)
364 LYXERR(Debug::GUI, "Passed Geometry "
365 << size().height() << "x" << size().width()
366 << "+" << pos().x() << "+" << pos().y());
368 if (d.splitter_->count() == 0)
369 // No work area, switch to the background widget.
372 QMainWindow::showEvent(e);
376 void GuiView::closeEvent(QCloseEvent * close_event)
378 // it can happen that this event arrives without selecting the view,
379 // e.g. when clicking the close button on a background window.
380 theLyXFunc().setLyXView(this);
382 while (Buffer * b = buffer()) {
384 // This is a child document, just close the tab after saving
385 // but keep the file loaded.
386 if (!saveBuffer(*b)) {
387 close_event->ignore();
390 removeWorkArea(d.current_work_area_);
394 std::vector<int> const & ids = guiApp->viewIds();
395 for (size_type i = 0; i != ids.size(); ++i) {
398 if (guiApp->view(ids[i]).workArea(*b)) {
399 // FIXME 1: should we put an alert box here that the buffer
400 // is viewed elsewhere?
401 // FIXME 2: should we try to save this buffer in any case?
404 // This buffer is also opened in another view, so
405 // but close the associated work area nevertheless.
406 removeWorkArea(d.current_work_area_);
407 // but don't close it.
412 if (b && !closeBuffer(*b)) {
413 close_event->ignore();
418 // Make sure that no LFUN use this close to be closed View.
419 theLyXFunc().setLyXView(0);
421 // Save toolbars configuration
422 if (isFullScreen()) {
423 d.toolbars_->toggleFullScreen(!isFullScreen());
427 // Make sure the timer time out will not trigger a statusbar update.
428 d.statusbar_timer_.stop();
430 // Saving fullscreen requires additional tweaks in the toolbar code.
431 // It wouldn't also work under linux natively.
432 if (lyxrc.allow_geometry_session && !isFullScreen()) {
434 QString const key = "view-" + QString::number(id_);
436 settings.setValue(key + "/pos", pos());
437 settings.setValue(key + "/size", size());
439 settings.setValue(key + "/geometry", saveGeometry());
441 settings.setValue(key + "/icon_size", iconSize());
442 d.toolbars_->saveToolbarInfo();
443 // Now take care of all other dialogs:
444 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
445 for (; it!= d.dialogs_.end(); ++it)
446 it->second->saveSession();
449 guiApp->unregisterView(id_);
450 close_event->accept();
454 void GuiView::dragEnterEvent(QDragEnterEvent * event)
456 if (event->mimeData()->hasUrls())
458 /// \todo Ask lyx-devel is this is enough:
459 /// if (event->mimeData()->hasFormat("text/plain"))
460 /// event->acceptProposedAction();
464 void GuiView::dropEvent(QDropEvent* event)
466 QList<QUrl> files = event->mimeData()->urls();
470 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
471 for (int i = 0; i != files.size(); ++i) {
472 string const file = os::internal_path(fromqstr(
473 files.at(i).toLocalFile()));
475 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
480 void GuiView::message(docstring const & str)
482 if (ForkedProcess::iAmAChild())
485 statusBar()->showMessage(toqstr(str));
486 d.statusbar_timer_.stop();
487 d.statusbar_timer_.start(3000);
491 void GuiView::smallSizedIcons()
493 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
497 void GuiView::normalSizedIcons()
499 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
503 void GuiView::bigSizedIcons()
505 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
509 void GuiView::clearMessage()
513 theLyXFunc().setLyXView(this);
514 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
515 d.statusbar_timer_.stop();
519 void GuiView::updateWindowTitle(GuiWorkArea * wa)
521 if (wa != d.current_work_area_)
523 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
524 setWindowIconText(wa->windowIconText());
528 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
531 disconnectBufferView();
532 connectBufferView(wa->bufferView());
533 connectBuffer(wa->bufferView().buffer());
534 d.current_work_area_ = wa;
535 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
536 this, SLOT(updateWindowTitle(GuiWorkArea *)));
537 updateWindowTitle(wa);
540 // Buffer-dependent dialogs should be updated or
541 // hidden. This should go here because some dialogs (eg ToC)
542 // require bv_->text.
543 updateBufferDependent(true);
550 void GuiView::on_lastWorkAreaRemoved()
553 // On Mac close the view if there is no Tab open anymore,
554 // but only if no splitter is visible
555 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
556 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
557 if (twa && twa->count() == 0) {
558 // close the view, as no tab is open anymore
559 QTimer::singleShot(0, this, SLOT(close()));
566 void GuiView::updateStatusBar()
568 // let the user see the explicit message
569 if (d.statusbar_timer_.isActive())
572 theLyXFunc().setLyXView(this);
573 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
577 bool GuiView::hasFocus() const
579 return qApp->activeWindow() == this;
583 bool GuiView::event(QEvent * e)
587 // Useful debug code:
588 //case QEvent::ActivationChange:
589 //case QEvent::WindowDeactivate:
590 //case QEvent::Paint:
591 //case QEvent::Enter:
592 //case QEvent::Leave:
593 //case QEvent::HoverEnter:
594 //case QEvent::HoverLeave:
595 //case QEvent::HoverMove:
596 //case QEvent::StatusTip:
597 //case QEvent::DragEnter:
598 //case QEvent::DragLeave:
602 case QEvent::WindowActivate: {
603 if (this == guiApp->currentView()) {
605 return QMainWindow::event(e);
607 guiApp->setCurrentView(this);
608 if (d.current_work_area_) {
609 BufferView & bv = d.current_work_area_->bufferView();
610 connectBufferView(bv);
611 connectBuffer(bv.buffer());
612 // The document structure, name and dialogs might have
613 // changed in another view.
614 updateBufferDependent(true);
619 setWindowTitle(qt_("LyX"));
620 setWindowIconText(qt_("LyX"));
623 return QMainWindow::event(e);
626 case QEvent::ShortcutOverride: {
627 if (d.current_work_area_)
628 // Nothing special to do.
629 return QMainWindow::event(e);
631 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
633 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
635 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
636 || ke->key() == Qt::Key_Backtab)
637 return QMainWindow::event(e);
639 // Allow processing of shortcuts that are allowed even when no Buffer
641 theLyXFunc().setLyXView(this);
643 setKeySymbol(&sym, ke);
644 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
650 return QMainWindow::event(e);
655 bool GuiView::focusNextPrevChild(bool /*next*/)
662 void GuiView::setBusy(bool busy)
664 if (d.current_work_area_) {
665 d.current_work_area_->setUpdatesEnabled(!busy);
667 d.current_work_area_->stopBlinkingCursor();
669 d.current_work_area_->startBlinkingCursor();
673 QApplication::setOverrideCursor(Qt::WaitCursor);
675 QApplication::restoreOverrideCursor();
679 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
681 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
683 if (tbinfo.flags & ToolbarInfo::TOP) {
685 addToolBarBreak(Qt::TopToolBarArea);
686 addToolBar(Qt::TopToolBarArea, toolBar);
689 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
690 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
691 #if (QT_VERSION >= 0x040202)
693 addToolBarBreak(Qt::BottomToolBarArea);
695 addToolBar(Qt::BottomToolBarArea, toolBar);
698 if (tbinfo.flags & ToolbarInfo::LEFT) {
699 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
700 #if (QT_VERSION >= 0x040202)
702 addToolBarBreak(Qt::LeftToolBarArea);
704 addToolBar(Qt::LeftToolBarArea, toolBar);
707 if (tbinfo.flags & ToolbarInfo::RIGHT) {
708 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
709 #if (QT_VERSION >= 0x040202)
711 addToolBarBreak(Qt::RightToolBarArea);
713 addToolBar(Qt::RightToolBarArea, toolBar);
716 // The following does not work so I cannot restore to exact toolbar location
718 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
719 toolBar->move(tbinfo.posx, tbinfo.posy);
726 GuiWorkArea * GuiView::workArea(Buffer & buffer)
728 if (TabWorkArea * twa = d.currentTabWorkArea())
729 return twa->workArea(buffer);
734 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
736 // Automatically create a TabWorkArea if there are none yet.
737 TabWorkArea * tab_widget = d.splitter_->count()
738 ? d.currentTabWorkArea() : addTabWorkArea();
739 return tab_widget->addWorkArea(buffer, *this);
743 TabWorkArea * GuiView::addTabWorkArea()
745 TabWorkArea * twa = new TabWorkArea;
746 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
747 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
748 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
749 this, SLOT(on_lastWorkAreaRemoved()));
751 d.splitter_->addWidget(twa);
752 d.stack_widget_->setCurrentWidget(d.splitter_);
757 GuiWorkArea const * GuiView::currentWorkArea() const
759 return d.current_work_area_;
763 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
767 // Changing work area can result from opening a file so
768 // update the toc in any case.
771 d.current_work_area_ = wa;
772 for (int i = 0; i != d.splitter_->count(); ++i) {
773 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
779 void GuiView::removeWorkArea(GuiWorkArea * wa)
782 if (wa == d.current_work_area_) {
784 disconnectBufferView();
785 hideBufferDependent();
786 d.current_work_area_ = 0;
789 for (int i = 0; i != d.splitter_->count(); ++i) {
790 TabWorkArea * twa = d.tabWorkArea(i);
791 if (!twa->removeWorkArea(wa))
792 // Not found in this tab group.
795 // We found and removed the GuiWorkArea.
797 // No more WorkAreas in this tab group, so delete it.
802 if (d.current_work_area_)
803 // This means that we are not closing the current GuiWorkArea;
806 // Switch to the next GuiWorkArea in the found TabWorkArea.
807 d.current_work_area_ = twa->currentWorkArea();
811 if (d.splitter_->count() == 0)
812 // No more work area, switch to the background widget.
817 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
823 void GuiView::updateLayoutList()
826 d.layout_->updateContents(false);
830 void GuiView::updateToolbars()
832 if (d.current_work_area_) {
834 d.current_work_area_->bufferView().cursor().inMathed();
836 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
838 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
839 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
840 bool const mathmacrotemplate =
841 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
843 d.toolbars_->update(math, table, review, mathmacrotemplate);
845 d.toolbars_->update(false, false, false, false);
847 // update read-only status of open dialogs.
852 Buffer * GuiView::buffer()
854 if (d.current_work_area_)
855 return &d.current_work_area_->bufferView().buffer();
860 Buffer const * GuiView::buffer() const
862 if (d.current_work_area_)
863 return &d.current_work_area_->bufferView().buffer();
868 void GuiView::setBuffer(Buffer * newBuffer)
870 BOOST_ASSERT(newBuffer);
873 GuiWorkArea * wa = workArea(*newBuffer);
875 updateLabels(*newBuffer->masterBuffer());
876 wa = addWorkArea(*newBuffer);
878 //Disconnect the old buffer...there's no new one.
881 connectBuffer(*newBuffer);
882 connectBufferView(wa->bufferView());
883 setCurrentWorkArea(wa);
889 void GuiView::connectBuffer(Buffer & buf)
891 buf.setGuiDelegate(this);
895 void GuiView::disconnectBuffer()
897 if (d.current_work_area_)
898 d.current_work_area_->bufferView().setGuiDelegate(0);
902 void GuiView::connectBufferView(BufferView & bv)
904 bv.setGuiDelegate(this);
908 void GuiView::disconnectBufferView()
910 if (d.current_work_area_)
911 d.current_work_area_->bufferView().setGuiDelegate(0);
915 void GuiView::errors(string const & error_type)
917 ErrorList & el = buffer()->errorList(error_type);
919 showDialog("errorlist", error_type);
923 void GuiView::updateDialog(string const & name, string const & data)
925 if (!isDialogVisible(name))
928 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
929 if (it == d.dialogs_.end())
932 Dialog * const dialog = it->second.get();
933 if (dialog->isVisibleView())
934 dialog->updateData(data);
938 BufferView * GuiView::view()
940 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
944 void GuiView::updateToc()
946 updateDialog("toc", "");
950 void GuiView::updateEmbeddedFiles()
952 updateDialog("embedding", "");
956 void GuiView::autoSave()
958 LYXERR(Debug::INFO, "Running autoSave()");
961 view()->buffer().autoSave();
965 void GuiView::resetAutosaveTimers()
968 d.autosave_timeout_.restart();
972 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
976 Buffer * buf = buffer();
978 /* In LyX/Mac, when a dialog is open, the menus of the
979 application can still be accessed without giving focus to
980 the main window. In this case, we want to disable the menu
981 entries that are buffer-related.
983 Note that this code is not perfect, as bug 1941 attests:
984 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
986 if (cmd.origin == FuncRequest::MENU && !hasFocus())
990 case LFUN_BUFFER_WRITE:
991 enable = buf && (buf->isUnnamed() || !buf->isClean());
994 case LFUN_BUFFER_WRITE_AS:
998 case LFUN_SPLIT_VIEW:
1002 case LFUN_CLOSE_TAB_GROUP:
1003 enable = d.currentTabWorkArea();
1006 case LFUN_TOOLBAR_TOGGLE:
1007 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1010 case LFUN_DIALOG_TOGGLE:
1011 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1012 // fall through to set "enable"
1013 case LFUN_DIALOG_SHOW: {
1014 string const name = cmd.getArg(0);
1016 enable = name == "aboutlyx"
1017 || name == "file" //FIXME: should be removed.
1019 || name == "texinfo";
1020 else if (name == "print")
1021 enable = buf->isExportable("dvi")
1022 && lyxrc.print_command != "none";
1023 else if (name == "character") {
1027 InsetCode ic = view()->cursor().inset().lyxCode();
1028 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1031 else if (name == "symbols") {
1032 if (!view() || view()->cursor().inMathed())
1035 InsetCode ic = view()->cursor().inset().lyxCode();
1036 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1039 else if (name == "latexlog")
1040 enable = FileName(buf->logName()).isReadableFile();
1041 else if (name == "spellchecker")
1042 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1043 enable = !buf->isReadonly();
1047 else if (name == "vclog")
1048 enable = buf->lyxvc().inUse();
1052 case LFUN_DIALOG_UPDATE: {
1053 string const name = cmd.getArg(0);
1055 enable = name == "prefs";
1059 case LFUN_INSET_APPLY: {
1064 string const name = cmd.getArg(0);
1065 Inset * inset = getOpenInset(name);
1067 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1069 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1070 // Every inset is supposed to handle this
1071 BOOST_ASSERT(false);
1075 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1076 flag |= getStatus(fr);
1078 enable = flag.enabled();
1082 case LFUN_COMPLETION_INLINE:
1083 if (!d.current_work_area_
1084 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1088 case LFUN_COMPLETION_POPUP:
1089 if (!d.current_work_area_
1090 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1094 case LFUN_COMPLETION_COMPLETE:
1095 if (!d.current_work_area_
1096 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1108 flag.enabled(false);
1114 static FileName selectTemplateFile()
1116 FileDialog dlg(qt_("Select template file"));
1117 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1118 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1120 FileDialog::Result result =
1121 dlg.open(toqstr(lyxrc.template_path),
1122 FileFilterList(_("LyX Documents (*.lyx)")));
1124 if (result.first == FileDialog::Later)
1126 if (result.second.isEmpty())
1128 return FileName(fromqstr(result.second));
1132 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1136 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1139 message(_("Document not loaded."));
1144 setBuffer(newBuffer);
1146 // scroll to the position when the file was last closed
1147 if (lyxrc.use_lastfilepos) {
1148 LastFilePosSection::FilePos filepos =
1149 LyX::ref().session().lastFilePos().load(filename);
1150 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1154 LyX::ref().session().lastFiles().add(filename);
1161 void GuiView::openDocument(string const & fname)
1163 string initpath = lyxrc.document_path;
1166 string const trypath = buffer()->filePath();
1167 // If directory is writeable, use this as default.
1168 if (FileName(trypath).isDirWritable())
1174 if (fname.empty()) {
1175 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1176 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1177 dlg.setButton2(qt_("Examples|#E#e"),
1178 toqstr(addPath(package().system_support().absFilename(), "examples")));
1180 FileDialog::Result result =
1181 dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1183 if (result.first == FileDialog::Later)
1186 filename = fromqstr(result.second);
1188 // check selected filename
1189 if (filename.empty()) {
1190 message(_("Canceled."));
1196 // get absolute path of file and add ".lyx" to the filename if
1198 FileName const fullname =
1199 fileSearch(string(), filename, "lyx", support::may_not_exist);
1200 if (!fullname.empty())
1201 filename = fullname.absFilename();
1203 // if the file doesn't exist, let the user create one
1204 if (!fullname.exists()) {
1205 // the user specifically chose this name. Believe him.
1206 Buffer * const b = newFile(filename, string(), true);
1212 docstring const disp_fn = makeDisplayPath(filename);
1213 message(bformat(_("Opening document %1$s..."), disp_fn));
1216 Buffer * buf = loadDocument(fullname);
1221 buf->errors("Parse");
1222 str2 = bformat(_("Document %1$s opened."), disp_fn);
1224 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1229 // FIXME: clean that
1230 static bool import(GuiView * lv, FileName const & filename,
1231 string const & format, ErrorList & errorList)
1233 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1235 string loader_format;
1236 vector<string> loaders = theConverters().loaders();
1237 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1238 for (vector<string>::const_iterator it = loaders.begin();
1239 it != loaders.end(); ++it) {
1240 if (!theConverters().isReachable(format, *it))
1243 string const tofile =
1244 support::changeExtension(filename.absFilename(),
1245 formats.extension(*it));
1246 if (!theConverters().convert(0, filename, FileName(tofile),
1247 filename, format, *it, errorList))
1249 loader_format = *it;
1252 if (loader_format.empty()) {
1253 frontend::Alert::error(_("Couldn't import file"),
1254 bformat(_("No information for importing the format %1$s."),
1255 formats.prettyName(format)));
1259 loader_format = format;
1261 if (loader_format == "lyx") {
1262 Buffer * buf = lv->loadDocument(lyxfile);
1267 buf->errors("Parse");
1269 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1273 bool as_paragraphs = loader_format == "textparagraph";
1274 string filename2 = (loader_format == format) ? filename.absFilename()
1275 : support::changeExtension(filename.absFilename(),
1276 formats.extension(loader_format));
1277 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1278 theLyXFunc().setLyXView(lv);
1279 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1286 void GuiView::importDocument(string const & argument)
1289 string filename = split(argument, format, ' ');
1291 LYXERR(Debug::INFO, format << " file: " << filename);
1293 // need user interaction
1294 if (filename.empty()) {
1295 string initpath = lyxrc.document_path;
1297 Buffer const * buf = buffer();
1299 string const trypath = buf->filePath();
1300 // If directory is writeable, use this as default.
1301 if (FileName(trypath).isDirWritable())
1305 docstring const text = bformat(_("Select %1$s file to import"),
1306 formats.prettyName(format));
1308 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1309 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1310 dlg.setButton2(qt_("Examples|#E#e"),
1311 toqstr(addPath(package().system_support().absFilename(), "examples")));
1313 docstring filter = formats.prettyName(format);
1316 filter += from_utf8(formats.extension(format));
1319 FileDialog::Result result =
1320 dlg.open(toqstr(initpath), FileFilterList(filter));
1322 if (result.first == FileDialog::Later)
1325 filename = fromqstr(result.second);
1327 // check selected filename
1328 if (filename.empty())
1329 message(_("Canceled."));
1332 if (filename.empty())
1335 // get absolute path of file
1336 FileName const fullname(makeAbsPath(filename));
1338 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1340 // Check if the document already is open
1341 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1344 if (!closeBuffer()) {
1345 message(_("Canceled."));
1350 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1352 // if the file exists already, and we didn't do
1353 // -i lyx thefile.lyx, warn
1354 if (lyxfile.exists() && fullname != lyxfile) {
1356 docstring text = bformat(_("The document %1$s already exists.\n\n"
1357 "Do you want to overwrite that document?"), displaypath);
1358 int const ret = Alert::prompt(_("Overwrite document?"),
1359 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1362 message(_("Canceled."));
1367 message(bformat(_("Importing %1$s..."), displaypath));
1368 ErrorList errorList;
1369 if (import(this, fullname, format, errorList))
1370 message(_("imported."));
1372 message(_("file not imported!"));
1374 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1378 void GuiView::newDocument(string const & filename, bool from_template)
1380 FileName initpath(lyxrc.document_path);
1381 Buffer * buf = buffer();
1383 FileName const trypath(buf->filePath());
1384 // If directory is writeable, use this as default.
1385 if (trypath.isDirWritable())
1389 string templatefile = from_template ?
1390 selectTemplateFile().absFilename() : string();
1392 if (filename.empty())
1393 b = newUnnamedFile(templatefile, initpath);
1395 b = newFile(filename, templatefile, true);
1399 // Ensure the cursor is correctly positionned on screen.
1400 view()->showCursor();
1404 void GuiView::insertLyXFile(docstring const & fname)
1406 BufferView * bv = view();
1411 FileName filename(to_utf8(fname));
1413 if (!filename.empty()) {
1414 bv->insertLyXFile(filename);
1418 // Launch a file browser
1420 string initpath = lyxrc.document_path;
1421 string const trypath = bv->buffer().filePath();
1422 // If directory is writeable, use this as default.
1423 if (FileName(trypath).isDirWritable())
1427 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1428 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1429 dlg.setButton2(qt_("Examples|#E#e"),
1430 toqstr(addPath(package().system_support().absFilename(),
1433 FileDialog::Result result =
1434 dlg.open(toqstr(initpath),
1435 FileFilterList(_("LyX Documents (*.lyx)")));
1437 if (result.first == FileDialog::Later)
1441 filename.set(fromqstr(result.second));
1443 // check selected filename
1444 if (filename.empty()) {
1445 // emit message signal.
1446 message(_("Canceled."));
1450 bv->insertLyXFile(filename);
1454 void GuiView::insertPlaintextFile(docstring const & fname,
1457 BufferView * bv = view();
1462 FileName filename(to_utf8(fname));
1464 if (!filename.empty()) {
1465 bv->insertPlaintextFile(filename, asParagraph);
1469 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1470 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1472 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1475 if (result.first == FileDialog::Later)
1479 filename.set(fromqstr(result.second));
1481 // check selected filename
1482 if (filename.empty()) {
1483 // emit message signal.
1484 message(_("Canceled."));
1488 bv->insertPlaintextFile(filename, asParagraph);
1492 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1494 FileName fname = b.fileName();
1495 FileName const oldname = fname;
1497 if (!newname.empty()) {
1499 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1501 // Switch to this Buffer.
1504 /// No argument? Ask user through dialog.
1506 FileDialog dlg(qt_("Choose a filename to save document as"),
1507 LFUN_BUFFER_WRITE_AS);
1508 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1509 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1511 if (!isLyXFilename(fname.absFilename()))
1512 fname.changeExtension(".lyx");
1514 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1516 FileDialog::Result result =
1517 dlg.save(toqstr(fname.onlyPath().absFilename()),
1519 toqstr(fname.onlyFileName()));
1521 if (result.first == FileDialog::Later)
1524 fname.set(fromqstr(result.second));
1529 if (!isLyXFilename(fname.absFilename()))
1530 fname.changeExtension(".lyx");
1533 if (FileName(fname).exists()) {
1534 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1535 docstring text = bformat(_("The document %1$s already "
1536 "exists.\n\nDo you want to "
1537 "overwrite that document?"),
1539 int const ret = Alert::prompt(_("Overwrite document?"),
1540 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1543 case 1: return renameBuffer(b, docstring());
1544 case 2: return false;
1548 // Ok, change the name of the buffer
1549 b.setFileName(fname.absFilename());
1551 bool unnamed = b.isUnnamed();
1552 b.setUnnamed(false);
1553 b.saveCheckSum(fname);
1555 if (!saveBuffer(b)) {
1556 b.setFileName(oldname.absFilename());
1557 b.setUnnamed(unnamed);
1558 b.saveCheckSum(oldname);
1566 bool GuiView::saveBuffer(Buffer & b)
1569 return renameBuffer(b, docstring());
1572 LyX::ref().session().lastFiles().add(b.fileName());
1576 // Switch to this Buffer.
1579 // FIXME: we don't tell the user *WHY* the save failed !!
1580 docstring const file = makeDisplayPath(b.absFileName(), 30);
1581 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1582 "Do you want to rename the document and "
1583 "try again?"), file);
1584 int const ret = Alert::prompt(_("Rename and save?"),
1585 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1588 if (!renameBuffer(b, docstring()))
1597 return saveBuffer(b);
1601 bool GuiView::closeBuffer()
1603 Buffer * buf = buffer();
1604 return buf && closeBuffer(*buf);
1608 bool GuiView::closeBuffer(Buffer & buf)
1610 // goto bookmark to update bookmark pit.
1611 //FIXME: we should update only the bookmarks related to this buffer!
1612 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1613 theLyXFunc().gotoBookmark(i+1, false, false);
1615 if (buf.isClean() || buf.paragraphs().empty()) {
1616 if (buf.masterBuffer() == &buf)
1617 LyX::ref().session().lastOpened().add(buf.fileName());
1618 theBufferList().release(&buf);
1621 // Switch to this Buffer.
1626 if (buf.isUnnamed())
1627 file = from_utf8(buf.fileName().onlyFileName());
1629 file = buf.fileName().displayName(30);
1631 // Bring this window to top before asking questions.
1635 docstring const text = bformat(_("The document %1$s has unsaved changes."
1636 "\n\nDo you want to save the document or discard the changes?"), file);
1637 int const ret = Alert::prompt(_("Save changed document?"),
1638 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1642 if (!saveBuffer(buf))
1646 // if we crash after this we could
1647 // have no autosave file but I guess
1648 // this is really improbable (Jug)
1649 removeAutosaveFile(buf.absFileName());
1655 // save file names to .lyx/session
1656 // if master/slave are both open, do not save slave since it
1657 // will be automatically loaded when the master is loaded
1658 if (buf.masterBuffer() == &buf)
1659 LyX::ref().session().lastOpened().add(buf.fileName());
1661 theBufferList().release(&buf);
1666 bool GuiView::dispatch(FuncRequest const & cmd)
1668 BufferView * bv = view();
1669 // By default we won't need any update.
1671 bv->cursor().updateFlags(Update::None);
1673 switch(cmd.action) {
1674 case LFUN_BUFFER_IMPORT:
1675 importDocument(to_utf8(cmd.argument()));
1678 case LFUN_BUFFER_SWITCH:
1679 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1682 case LFUN_BUFFER_NEXT:
1683 setBuffer(theBufferList().next(buffer()));
1686 case LFUN_BUFFER_PREVIOUS:
1687 setBuffer(theBufferList().previous(buffer()));
1690 case LFUN_COMMAND_EXECUTE: {
1691 bool const show_it = cmd.argument() != "off";
1692 d.toolbars_->showCommandBuffer(show_it);
1695 case LFUN_DROP_LAYOUTS_CHOICE:
1697 d.layout_->showPopup();
1700 case LFUN_MENU_OPEN:
1701 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1702 menu->exec(QCursor::pos());
1705 case LFUN_FILE_INSERT:
1706 insertLyXFile(cmd.argument());
1708 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1709 insertPlaintextFile(cmd.argument(), true);
1712 case LFUN_FILE_INSERT_PLAINTEXT:
1713 insertPlaintextFile(cmd.argument(), false);
1716 case LFUN_BUFFER_WRITE:
1718 saveBuffer(bv->buffer());
1721 case LFUN_BUFFER_WRITE_AS:
1723 renameBuffer(bv->buffer(), cmd.argument());
1726 case LFUN_BUFFER_WRITE_ALL: {
1727 Buffer * first = theBufferList().first();
1730 message(_("Saving all documents..."));
1731 // We cannot use a for loop as the buffer list cycles.
1737 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1738 b = theBufferList().next(b);
1739 } while (b != first);
1740 message(_("All documents saved."));
1744 case LFUN_TOOLBAR_TOGGLE: {
1745 string const name = cmd.getArg(0);
1746 bool const allowauto = cmd.getArg(1) == "allowauto";
1747 // it is possible to get current toolbar status like this,...
1748 // but I decide to obey the order of ToolbarBackend::flags
1749 // and disregard real toolbar status.
1750 // toolbars_->saveToolbarInfo();
1752 // toggle state on/off/auto
1753 d.toolbars_->toggleToolbarState(name, allowauto);
1757 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1759 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1763 if (tbi->flags & ToolbarInfo::ON)
1765 else if (tbi->flags & ToolbarInfo::OFF)
1767 else if (tbi->flags & ToolbarInfo::AUTO)
1770 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1771 _(tbi->gui_name), state));
1775 case LFUN_DIALOG_UPDATE: {
1776 string const name = to_utf8(cmd.argument());
1777 // Can only update a dialog connected to an existing inset
1778 Inset * inset = getOpenInset(name);
1780 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1781 inset->dispatch(view()->cursor(), fr);
1782 } else if (name == "paragraph") {
1783 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1784 } else if (name == "prefs") {
1785 updateDialog(name, string());
1790 case LFUN_DIALOG_TOGGLE: {
1791 if (isDialogVisible(cmd.getArg(0)))
1792 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1794 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1798 case LFUN_DIALOG_DISCONNECT_INSET:
1799 disconnectDialog(to_utf8(cmd.argument()));
1802 case LFUN_DIALOG_HIDE: {
1803 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1807 case LFUN_DIALOG_SHOW: {
1808 string const name = cmd.getArg(0);
1809 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1811 if (name == "character") {
1812 data = freefont2string();
1814 showDialog("character", data);
1815 } else if (name == "latexlog") {
1816 Buffer::LogType type;
1817 string const logfile = buffer()->logName(&type);
1819 case Buffer::latexlog:
1822 case Buffer::buildlog:
1826 data += Lexer::quoteString(logfile);
1827 showDialog("log", data);
1828 } else if (name == "vclog") {
1829 string const data = "vc " +
1830 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1831 showDialog("log", data);
1832 } else if (name == "symbols") {
1833 data = bv->cursor().getEncoding()->name();
1835 showDialog("symbols", data);
1837 showDialog(name, data);
1841 case LFUN_INSET_APPLY: {
1842 string const name = cmd.getArg(0);
1843 Inset * inset = getOpenInset(name);
1845 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1846 inset->dispatch(view()->cursor(), fr);
1848 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1854 case LFUN_UI_TOGGLE:
1856 // Make sure the keyboard focus stays in the work area.
1860 case LFUN_COMPLETION_INLINE:
1861 if (d.current_work_area_)
1862 d.current_work_area_->completer().showInline();
1865 case LFUN_SPLIT_VIEW:
1866 if (Buffer * buf = buffer()) {
1867 string const orientation = cmd.getArg(0);
1868 d.splitter_->setOrientation(orientation == "vertical"
1869 ? Qt::Vertical : Qt::Horizontal);
1870 TabWorkArea * twa = addTabWorkArea();
1871 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1872 setCurrentWorkArea(wa);
1876 case LFUN_CLOSE_TAB_GROUP:
1877 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1879 twa = d.currentTabWorkArea();
1880 // Switch to the next GuiWorkArea in the found TabWorkArea.
1881 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1882 if (d.splitter_->count() == 0)
1883 // No more work area, switch to the background widget.
1888 case LFUN_COMPLETION_POPUP:
1889 if (d.current_work_area_)
1890 d.current_work_area_->completer().showPopup();
1894 case LFUN_COMPLETION_COMPLETE:
1895 if (d.current_work_area_)
1896 d.current_work_area_->completer().tab();
1907 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1909 string const arg = cmd.getArg(0);
1910 if (arg == "scrollbar") {
1911 // hide() is of no help
1912 if (d.current_work_area_->verticalScrollBarPolicy() ==
1913 Qt::ScrollBarAlwaysOff)
1915 d.current_work_area_->setVerticalScrollBarPolicy(
1916 Qt::ScrollBarAsNeeded);
1918 d.current_work_area_->setVerticalScrollBarPolicy(
1919 Qt::ScrollBarAlwaysOff);
1922 if (arg == "statusbar") {
1923 statusBar()->setVisible(!statusBar()->isVisible());
1926 if (arg == "menubar") {
1927 menuBar()->setVisible(!menuBar()->isVisible());
1930 #if QT_VERSION >= 0x040300
1931 if (arg == "frame") {
1933 getContentsMargins(&l, &t, &r, &b);
1934 //are the frames in default state?
1935 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1937 setContentsMargins(-2, -2, -2, -2);
1939 setContentsMargins(0, 0, 0, 0);
1944 if (arg != "fullscreen") {
1945 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1949 if (lyxrc.full_screen_toolbars)
1950 d.toolbars_->toggleFullScreen(!isFullScreen());
1952 if (isFullScreen()) {
1953 for (int i = 0; i != d.splitter_->count(); ++i)
1954 d.tabWorkArea(i)->setFullScreen(false);
1955 #if QT_VERSION >= 0x040300
1956 setContentsMargins(0, 0, 0, 0);
1960 statusBar()->show();
1962 for (int i = 0; i != d.splitter_->count(); ++i)
1963 d.tabWorkArea(i)->setFullScreen(true);
1964 #if QT_VERSION >= 0x040300
1965 setContentsMargins(-2, -2, -2, -2);
1968 statusBar()->hide();
1974 Buffer const * GuiView::updateInset(Inset const * inset)
1976 if (!d.current_work_area_)
1980 d.current_work_area_->scheduleRedraw();
1982 return &d.current_work_area_->bufferView().buffer();
1986 void GuiView::restartCursor()
1988 /* When we move around, or type, it's nice to be able to see
1989 * the cursor immediately after the keypress.
1991 if (d.current_work_area_)
1992 d.current_work_area_->startBlinkingCursor();
1994 // Take this occasion to update the other GUI elements.
2001 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2003 if (d.current_work_area_)
2004 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2009 // This list should be kept in sync with the list of insets in
2010 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2011 // dialog should have the same name as the inset.
2013 char const * const dialognames[] = {
2014 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2015 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
2016 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2017 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2018 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
2020 #ifdef HAVE_LIBAIKSAURUS
2024 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2026 char const * const * const end_dialognames =
2027 dialognames + (sizeof(dialognames) / sizeof(char *));
2031 cmpCStr(char const * name) : name_(name) {}
2032 bool operator()(char const * other) {
2033 return strcmp(other, name_) == 0;
2040 bool isValidName(string const & name)
2042 return find_if(dialognames, end_dialognames,
2043 cmpCStr(name.c_str())) != end_dialognames;
2049 void GuiView::resetDialogs()
2051 // Make sure that no LFUN uses any LyXView.
2052 theLyXFunc().setLyXView(0);
2053 // FIXME: the "math panels" toolbar takes an awful lot of time to
2054 // initialise so we don't do that for the time being.
2055 //d.toolbars_->init();
2056 guiApp->menus().fillMenuBar(menuBar(), this);
2058 d.layout_->updateContents(true);
2059 // Now update controls with current buffer.
2060 theLyXFunc().setLyXView(this);
2065 Dialog * GuiView::find_or_build(string const & name)
2067 if (!isValidName(name))
2070 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2072 if (it != d.dialogs_.end())
2073 return it->second.get();
2075 Dialog * dialog = build(name);
2076 d.dialogs_[name].reset(dialog);
2077 if (lyxrc.allow_geometry_session)
2078 dialog->restoreSession();
2083 void GuiView::showDialog(string const & name, string const & data,
2090 Dialog * dialog = find_or_build(name);
2092 dialog->showData(data);
2094 d.open_insets_[name] = inset;
2100 bool GuiView::isDialogVisible(string const & name) const
2102 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2103 if (it == d.dialogs_.end())
2105 return it->second.get()->isVisibleView();
2109 void GuiView::hideDialog(string const & name, Inset * inset)
2111 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2112 if (it == d.dialogs_.end())
2115 if (inset && inset != getOpenInset(name))
2118 Dialog * const dialog = it->second.get();
2119 if (dialog->isVisibleView())
2121 d.open_insets_[name] = 0;
2125 void GuiView::disconnectDialog(string const & name)
2127 if (!isValidName(name))
2130 if (d.open_insets_.find(name) != d.open_insets_.end())
2131 d.open_insets_[name] = 0;
2135 Inset * GuiView::getOpenInset(string const & name) const
2137 if (!isValidName(name))
2140 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2141 return it == d.open_insets_.end() ? 0 : it->second;
2145 void GuiView::hideAll() const
2147 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2148 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2150 for(; it != end; ++it)
2151 it->second->hideView();
2155 void GuiView::hideBufferDependent() const
2157 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2158 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2160 for(; it != end; ++it) {
2161 Dialog * dialog = it->second.get();
2162 if (dialog->isBufferDependent())
2168 void GuiView::updateBufferDependent(bool switched) const
2170 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2171 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2173 for(; it != end; ++it) {
2174 Dialog * dialog = it->second.get();
2175 if (!dialog->isVisibleView())
2177 if (switched && dialog->isBufferDependent()) {
2178 if (dialog->initialiseParams(""))
2179 dialog->updateView();
2183 // A bit clunky, but the dialog will request
2184 // that the kernel provides it with the necessary
2186 dialog->updateDialog();
2192 void GuiView::checkStatus()
2194 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2195 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2197 for(; it != end; ++it) {
2198 Dialog * const dialog = it->second.get();
2199 if (dialog && dialog->isVisibleView())
2200 dialog->checkStatus();
2206 // will be replaced by a proper factory...
2207 Dialog * createGuiAbout(GuiView & lv);
2208 Dialog * createGuiBibitem(GuiView & lv);
2209 Dialog * createGuiBibtex(GuiView & lv);
2210 Dialog * createGuiBox(GuiView & lv);
2211 Dialog * createGuiBranch(GuiView & lv);
2212 Dialog * createGuiChanges(GuiView & lv);
2213 Dialog * createGuiCharacter(GuiView & lv);
2214 Dialog * createGuiCitation(GuiView & lv);
2215 Dialog * createGuiDelimiter(GuiView & lv);
2216 Dialog * createGuiDocument(GuiView & lv);
2217 Dialog * createGuiErrorList(GuiView & lv);
2218 Dialog * createGuiERT(GuiView & lv);
2219 Dialog * createGuiExternal(GuiView & lv);
2220 Dialog * createGuiFloat(GuiView & lv);
2221 Dialog * createGuiGraphics(GuiView & lv);
2222 Dialog * createGuiInclude(GuiView & lv);
2223 Dialog * createGuiLabel(GuiView & lv);
2224 Dialog * createGuiListings(GuiView & lv);
2225 Dialog * createGuiLog(GuiView & lv);
2226 Dialog * createGuiMathMatrix(GuiView & lv);
2227 Dialog * createGuiNomenclature(GuiView & lv);
2228 Dialog * createGuiNote(GuiView & lv);
2229 Dialog * createGuiParagraph(GuiView & lv);
2230 Dialog * createGuiPreferences(GuiView & lv);
2231 Dialog * createGuiPrint(GuiView & lv);
2232 Dialog * createGuiRef(GuiView & lv);
2233 Dialog * createGuiSearch(GuiView & lv);
2234 Dialog * createGuiSendTo(GuiView & lv);
2235 Dialog * createGuiShowFile(GuiView & lv);
2236 Dialog * createGuiSpellchecker(GuiView & lv);
2237 Dialog * createGuiSymbols(GuiView & lv);
2238 Dialog * createGuiTabularCreate(GuiView & lv);
2239 Dialog * createGuiTabular(GuiView & lv);
2240 Dialog * createGuiTexInfo(GuiView & lv);
2241 Dialog * createGuiToc(GuiView & lv);
2242 Dialog * createGuiThesaurus(GuiView & lv);
2243 Dialog * createGuiHyperlink(GuiView & lv);
2244 Dialog * createGuiVSpace(GuiView & lv);
2245 Dialog * createGuiViewSource(GuiView & lv);
2246 Dialog * createGuiWrap(GuiView & lv);
2249 Dialog * GuiView::build(string const & name)
2251 BOOST_ASSERT(isValidName(name));
2253 if (name == "aboutlyx")
2254 return createGuiAbout(*this);
2255 if (name == "bibitem")
2256 return createGuiBibitem(*this);
2257 if (name == "bibtex")
2258 return createGuiBibtex(*this);
2260 return createGuiBox(*this);
2261 if (name == "branch")
2262 return createGuiBranch(*this);
2263 if (name == "changes")
2264 return createGuiChanges(*this);
2265 if (name == "character")
2266 return createGuiCharacter(*this);
2267 if (name == "citation")
2268 return createGuiCitation(*this);
2269 if (name == "document")
2270 return createGuiDocument(*this);
2271 if (name == "errorlist")
2272 return createGuiErrorList(*this);
2274 return createGuiERT(*this);
2275 if (name == "external")
2276 return createGuiExternal(*this);
2278 return createGuiShowFile(*this);
2279 if (name == "findreplace")
2280 return createGuiSearch(*this);
2281 if (name == "float")
2282 return createGuiFloat(*this);
2283 if (name == "graphics")
2284 return createGuiGraphics(*this);
2285 if (name == "include")
2286 return createGuiInclude(*this);
2287 if (name == "nomenclature")
2288 return createGuiNomenclature(*this);
2289 if (name == "label")
2290 return createGuiLabel(*this);
2292 return createGuiLog(*this);
2293 if (name == "view-source")
2294 return createGuiViewSource(*this);
2295 if (name == "mathdelimiter")
2296 return createGuiDelimiter(*this);
2297 if (name == "mathmatrix")
2298 return createGuiMathMatrix(*this);
2300 return createGuiNote(*this);
2301 if (name == "paragraph")
2302 return createGuiParagraph(*this);
2303 if (name == "prefs")
2304 return createGuiPreferences(*this);
2305 if (name == "print")
2306 return createGuiPrint(*this);
2308 return createGuiRef(*this);
2309 if (name == "sendto")
2310 return createGuiSendTo(*this);
2311 if (name == "spellchecker")
2312 return createGuiSpellchecker(*this);
2313 if (name == "symbols")
2314 return createGuiSymbols(*this);
2315 if (name == "tabular")
2316 return createGuiTabular(*this);
2317 if (name == "tabularcreate")
2318 return createGuiTabularCreate(*this);
2319 if (name == "texinfo")
2320 return createGuiTexInfo(*this);
2321 #ifdef HAVE_LIBAIKSAURUS
2322 if (name == "thesaurus")
2323 return createGuiThesaurus(*this);
2326 return createGuiToc(*this);
2328 return createGuiHyperlink(*this);
2329 if (name == "vspace")
2330 return createGuiVSpace(*this);
2332 return createGuiWrap(*this);
2333 if (name == "listings")
2334 return createGuiListings(*this);
2340 } // namespace frontend
2343 #include "GuiView_moc.cpp"