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"
29 #include "qt_helpers.h"
31 #include "frontends/alert.h"
33 #include "buffer_funcs.h"
35 #include "BufferList.h"
36 #include "BufferParams.h"
37 #include "BufferView.h"
38 #include "Converter.h"
41 #include "ErrorList.h"
43 #include "FuncStatus.h"
44 #include "FuncRequest.h"
52 #include "Paragraph.h"
53 #include "TextClass.h"
55 #include "ToolbarBackend.h"
58 #include "support/lassert.h"
59 #include "support/debug.h"
60 #include "support/FileName.h"
61 #include "support/filetools.h"
62 #include "support/gettext.h"
63 #include "support/ForkedCalls.h"
64 #include "support/lstrings.h"
65 #include "support/os.h"
66 #include "support/Package.h"
67 #include "support/Timeout.h"
70 #include <QApplication>
71 #include <QCloseEvent>
73 #include <QDesktopWidget>
74 #include <QDragEnterEvent>
82 #include <QPushButton>
86 #include <QStackedWidget>
93 #include <boost/bind.hpp>
95 #ifdef HAVE_SYS_TIME_H
96 # include <sys/time.h>
103 using namespace lyx::support;
110 class BackgroundWidget : public QWidget
115 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
116 /// The text to be written on top of the pixmap
117 QString const text = lyx_version ?
118 qt_("version ") + lyx_version : qt_("unknown version");
119 splash_ = QPixmap(":/images/banner.png");
121 QPainter pain(&splash_);
122 pain.setPen(QColor(0, 0, 0));
124 // The font used to display the version info
125 font.setStyleHint(QFont::SansSerif);
126 font.setWeight(QFont::Bold);
127 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
129 pain.drawText(190, 225, text);
132 void paintEvent(QPaintEvent *)
134 int x = (width() - splash_.width()) / 2;
135 int y = (height() - splash_.height()) / 2;
137 pain.drawPixmap(x, y, splash_);
147 typedef boost::shared_ptr<Dialog> DialogPtr;
149 struct GuiView::GuiViewPrivate
152 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
155 // hardcode here the platform specific icon size
156 smallIconSize = 14; // scaling problems
157 normalIconSize = 20; // ok, default
158 bigIconSize = 26; // better for some math icons
160 splitter_ = new QSplitter;
161 bg_widget_ = new BackgroundWidget;
162 stack_widget_ = new QStackedWidget;
163 stack_widget_->addWidget(bg_widget_);
164 stack_widget_->addWidget(splitter_);
172 delete stack_widget_;
176 QMenu * toolBarPopup(GuiView * parent)
178 // FIXME: translation
179 QMenu * menu = new QMenu(parent);
180 QActionGroup * iconSizeGroup = new QActionGroup(parent);
182 QAction * smallIcons = new QAction(iconSizeGroup);
183 smallIcons->setText(qt_("Small-sized icons"));
184 smallIcons->setCheckable(true);
185 QObject::connect(smallIcons, SIGNAL(triggered()),
186 parent, SLOT(smallSizedIcons()));
187 menu->addAction(smallIcons);
189 QAction * normalIcons = new QAction(iconSizeGroup);
190 normalIcons->setText(qt_("Normal-sized icons"));
191 normalIcons->setCheckable(true);
192 QObject::connect(normalIcons, SIGNAL(triggered()),
193 parent, SLOT(normalSizedIcons()));
194 menu->addAction(normalIcons);
196 QAction * bigIcons = new QAction(iconSizeGroup);
197 bigIcons->setText(qt_("Big-sized icons"));
198 bigIcons->setCheckable(true);
199 QObject::connect(bigIcons, SIGNAL(triggered()),
200 parent, SLOT(bigSizedIcons()));
201 menu->addAction(bigIcons);
203 unsigned int cur = parent->iconSize().width();
204 if ( cur == parent->d.smallIconSize)
205 smallIcons->setChecked(true);
206 else if (cur == parent->d.normalIconSize)
207 normalIcons->setChecked(true);
208 else if (cur == parent->d.bigIconSize)
209 bigIcons->setChecked(true);
216 stack_widget_->setCurrentWidget(bg_widget_);
217 bg_widget_->setUpdatesEnabled(true);
220 TabWorkArea * tabWorkArea(int i)
222 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
225 TabWorkArea * currentTabWorkArea()
227 if (splitter_->count() == 1)
228 // The first TabWorkArea is always the first one, if any.
229 return tabWorkArea(0);
231 for (int i = 0; i != splitter_->count(); ++i) {
232 TabWorkArea * twa = tabWorkArea(i);
233 if (current_work_area_ == twa->currentWorkArea())
237 // None has the focus so we just take the first one.
238 return tabWorkArea(0);
242 GuiWorkArea * current_work_area_;
243 QSplitter * splitter_;
244 QStackedWidget * stack_widget_;
245 BackgroundWidget * bg_widget_;
247 GuiToolbars * toolbars_;
248 /// The main layout box.
250 * \warning Don't Delete! The layout box is actually owned by
251 * whichever toolbar contains it. All the GuiView class needs is a
252 * means of accessing it.
254 * FIXME: replace that with a proper model so that we are not limited
255 * to only one dialog.
257 GuiLayoutBox * layout_;
260 map<string, Inset *> open_insets_;
263 map<string, DialogPtr> dialogs_;
265 unsigned int smallIconSize;
266 unsigned int normalIconSize;
267 unsigned int bigIconSize;
269 QTimer statusbar_timer_;
270 /// auto-saving of buffers
271 Timeout autosave_timeout_;
272 /// flag against a race condition due to multiclicks, see bug #1119
276 TocModels toc_models_;
280 GuiView::GuiView(int id)
281 : d(*new GuiViewPrivate), id_(id)
283 // GuiToolbars *must* be initialised before the menu bar.
284 d.toolbars_ = new GuiToolbars(*this);
286 // set ourself as the current view. This is needed for the menu bar
287 // filling, at least for the static special menu item on Mac. Otherwise
288 // they are greyed out.
289 theLyXFunc().setLyXView(this);
291 // Fill up the menu bar.
292 guiApp->menus().fillMenuBar(menuBar(), this, true);
294 setCentralWidget(d.stack_widget_);
296 // Start autosave timer
297 if (lyxrc.autosave) {
298 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
299 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
300 d.autosave_timeout_.start();
302 connect(&d.statusbar_timer_, SIGNAL(timeout()),
303 this, SLOT(clearMessage()));
305 // We don't want to keep the window in memory if it is closed.
306 setAttribute(Qt::WA_DeleteOnClose, true);
308 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
309 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
310 // since the icon is provided in the application bundle.
311 setWindowIcon(QPixmap(":/images/lyx.png"));
315 setAcceptDrops(true);
317 statusBar()->setSizeGripEnabled(true);
319 // Forbid too small unresizable window because it can happen
320 // with some window manager under X11.
321 setMinimumSize(300, 200);
323 if (!lyxrc.allow_geometry_session)
324 // No session handling, default to a sane size.
325 setGeometry(50, 50, 690, 510);
327 // Now take care of session management.
329 QString const key = "view-" + QString::number(id_);
331 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
332 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
336 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
337 setGeometry(50, 50, 690, 510);
339 setIconSize(settings.value(key + "/icon_size").toSize());
345 if (guiApp->currentView() == this)
346 guiApp->setCurrentView(0);
347 theLyXFunc().setLyXView(0);
353 TocModels & GuiView::tocModels()
355 return d.toc_models_;
359 void GuiView::setFocus()
361 if (d.current_work_area_)
362 d.current_work_area_->setFocus();
368 QMenu * GuiView::createPopupMenu()
370 return d.toolBarPopup(this);
374 void GuiView::showEvent(QShowEvent * e)
376 LYXERR(Debug::GUI, "Passed Geometry "
377 << size().height() << "x" << size().width()
378 << "+" << pos().x() << "+" << pos().y());
380 if (d.splitter_->count() == 0)
381 // No work area, switch to the background widget.
384 QMainWindow::showEvent(e);
388 void GuiView::closeEvent(QCloseEvent * close_event)
390 // it can happen that this event arrives without selecting the view,
391 // e.g. when clicking the close button on a background window.
392 theLyXFunc().setLyXView(this);
394 while (Buffer * b = buffer()) {
396 // This is a child document, just close the tab after saving
397 // but keep the file loaded.
398 if (!saveBuffer(*b)) {
399 close_event->ignore();
402 removeWorkArea(d.current_work_area_);
406 std::vector<int> const & ids = guiApp->viewIds();
407 for (size_type i = 0; i != ids.size(); ++i) {
410 if (guiApp->view(ids[i]).workArea(*b)) {
411 // FIXME 1: should we put an alert box here that the buffer
412 // is viewed elsewhere?
413 // FIXME 2: should we try to save this buffer in any case?
416 // This buffer is also opened in another view, so
417 // but close the associated work area nevertheless.
418 removeWorkArea(d.current_work_area_);
419 // but don't close it.
424 if (b && !closeBuffer(*b, true)) {
425 close_event->ignore();
430 // Make sure that no LFUN use this close to be closed View.
431 theLyXFunc().setLyXView(0);
433 // Save toolbars configuration
434 if (isFullScreen()) {
435 d.toolbars_->toggleFullScreen(!isFullScreen());
439 // Make sure the timer time out will not trigger a statusbar update.
440 d.statusbar_timer_.stop();
442 // Saving fullscreen requires additional tweaks in the toolbar code.
443 // It wouldn't also work under linux natively.
444 if (lyxrc.allow_geometry_session && !isFullScreen()) {
446 QString const key = "view-" + QString::number(id_);
448 settings.setValue(key + "/pos", pos());
449 settings.setValue(key + "/size", size());
451 settings.setValue(key + "/geometry", saveGeometry());
453 settings.setValue(key + "/icon_size", iconSize());
454 d.toolbars_->saveToolbarInfo();
455 // Now take care of all other dialogs:
456 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
457 for (; it!= d.dialogs_.end(); ++it)
458 it->second->saveSession();
461 guiApp->unregisterView(id_);
462 close_event->accept();
466 void GuiView::dragEnterEvent(QDragEnterEvent * event)
468 if (event->mimeData()->hasUrls())
470 /// \todo Ask lyx-devel is this is enough:
471 /// if (event->mimeData()->hasFormat("text/plain"))
472 /// event->acceptProposedAction();
476 void GuiView::dropEvent(QDropEvent* event)
478 QList<QUrl> files = event->mimeData()->urls();
482 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
483 for (int i = 0; i != files.size(); ++i) {
484 string const file = os::internal_path(fromqstr(
485 files.at(i).toLocalFile()));
487 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
492 void GuiView::message(docstring const & str)
494 if (ForkedProcess::iAmAChild())
497 statusBar()->showMessage(toqstr(str));
498 d.statusbar_timer_.stop();
499 d.statusbar_timer_.start(3000);
503 void GuiView::smallSizedIcons()
505 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
509 void GuiView::normalSizedIcons()
511 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
515 void GuiView::bigSizedIcons()
517 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
521 void GuiView::clearMessage()
525 theLyXFunc().setLyXView(this);
526 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
527 d.statusbar_timer_.stop();
531 void GuiView::updateWindowTitle(GuiWorkArea * wa)
533 if (wa != d.current_work_area_)
535 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
536 setWindowIconText(wa->windowIconText());
540 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
543 disconnectBufferView();
544 connectBufferView(wa->bufferView());
545 connectBuffer(wa->bufferView().buffer());
546 d.current_work_area_ = wa;
547 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
548 this, SLOT(updateWindowTitle(GuiWorkArea *)));
549 updateWindowTitle(wa);
553 // The document settings needs to be reinitialised.
554 updateDialog("document", "");
556 // Buffer-dependent dialogs must be updated. This is done here because
557 // some dialogs require buffer()->text.
562 void GuiView::on_lastWorkAreaRemoved()
565 // On Mac close the view if there is no Tab open anymore,
566 // but only if no splitter is visible
567 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
568 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
569 if (twa && twa->count() == 0) {
570 // close the view, as no tab is open anymore
571 QTimer::singleShot(0, this, SLOT(close()));
576 // The document settings needs to be reinitialised.
577 updateDialog("document", "");
583 void GuiView::updateStatusBar()
585 // let the user see the explicit message
586 if (d.statusbar_timer_.isActive())
589 theLyXFunc().setLyXView(this);
590 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
594 bool GuiView::hasFocus() const
596 return qApp->activeWindow() == this;
600 bool GuiView::event(QEvent * e)
604 // Useful debug code:
605 //case QEvent::ActivationChange:
606 //case QEvent::WindowDeactivate:
607 //case QEvent::Paint:
608 //case QEvent::Enter:
609 //case QEvent::Leave:
610 //case QEvent::HoverEnter:
611 //case QEvent::HoverLeave:
612 //case QEvent::HoverMove:
613 //case QEvent::StatusTip:
614 //case QEvent::DragEnter:
615 //case QEvent::DragLeave:
619 case QEvent::WindowActivate: {
620 if (this == guiApp->currentView()) {
622 return QMainWindow::event(e);
624 guiApp->setCurrentView(this);
625 if (d.current_work_area_) {
626 BufferView & bv = d.current_work_area_->bufferView();
627 connectBufferView(bv);
628 connectBuffer(bv.buffer());
629 // The document structure, name and dialogs might have
630 // changed in another view.
632 // The document settings needs to be reinitialised.
633 updateDialog("document", "");
636 setWindowTitle(qt_("LyX"));
637 setWindowIconText(qt_("LyX"));
640 return QMainWindow::event(e);
643 case QEvent::ShortcutOverride: {
645 if (isFullScreen() && menuBar()->isHidden()) {
646 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
647 // FIXME: we should also try to detect special LyX shortcut such as
649 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt)
651 return QMainWindow::event(e);
654 if (d.current_work_area_)
655 // Nothing special to do.
656 return QMainWindow::event(e);
658 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
659 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
661 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
662 || ke->key() == Qt::Key_Backtab)
663 return QMainWindow::event(e);
665 // Allow processing of shortcuts that are allowed even when no Buffer
667 theLyXFunc().setLyXView(this);
669 setKeySymbol(&sym, ke);
670 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
676 return QMainWindow::event(e);
681 bool GuiView::focusNextPrevChild(bool /*next*/)
688 void GuiView::setBusy(bool busy)
690 if (d.current_work_area_) {
691 d.current_work_area_->setUpdatesEnabled(!busy);
693 d.current_work_area_->stopBlinkingCursor();
695 d.current_work_area_->startBlinkingCursor();
699 QApplication::setOverrideCursor(Qt::WaitCursor);
701 QApplication::restoreOverrideCursor();
705 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
707 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
709 if (tbinfo.flags & ToolbarInfo::TOP) {
711 addToolBarBreak(Qt::TopToolBarArea);
712 addToolBar(Qt::TopToolBarArea, toolBar);
715 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
716 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
717 #if (QT_VERSION >= 0x040202)
719 addToolBarBreak(Qt::BottomToolBarArea);
721 addToolBar(Qt::BottomToolBarArea, toolBar);
724 if (tbinfo.flags & ToolbarInfo::LEFT) {
725 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
726 #if (QT_VERSION >= 0x040202)
728 addToolBarBreak(Qt::LeftToolBarArea);
730 addToolBar(Qt::LeftToolBarArea, toolBar);
733 if (tbinfo.flags & ToolbarInfo::RIGHT) {
734 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
735 #if (QT_VERSION >= 0x040202)
737 addToolBarBreak(Qt::RightToolBarArea);
739 addToolBar(Qt::RightToolBarArea, toolBar);
742 // The following does not work so I cannot restore to exact toolbar location
744 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
745 toolBar->move(tbinfo.posx, tbinfo.posy);
752 GuiWorkArea * GuiView::workArea(Buffer & buffer)
754 if (TabWorkArea * twa = d.currentTabWorkArea())
755 return twa->workArea(buffer);
760 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
762 // Automatically create a TabWorkArea if there are none yet.
763 TabWorkArea * tab_widget = d.splitter_->count()
764 ? d.currentTabWorkArea() : addTabWorkArea();
765 return tab_widget->addWorkArea(buffer, *this);
769 TabWorkArea * GuiView::addTabWorkArea()
771 TabWorkArea * twa = new TabWorkArea;
772 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
773 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
774 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
775 this, SLOT(on_lastWorkAreaRemoved()));
777 d.splitter_->addWidget(twa);
778 d.stack_widget_->setCurrentWidget(d.splitter_);
783 GuiWorkArea const * GuiView::currentWorkArea() const
785 return d.current_work_area_;
789 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
792 d.current_work_area_ = wa;
793 for (int i = 0; i != d.splitter_->count(); ++i) {
794 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
800 void GuiView::removeWorkArea(GuiWorkArea * wa)
803 if (wa == d.current_work_area_) {
805 disconnectBufferView();
806 d.current_work_area_ = 0;
809 for (int i = 0; i != d.splitter_->count(); ++i) {
810 TabWorkArea * twa = d.tabWorkArea(i);
811 if (!twa->removeWorkArea(wa))
812 // Not found in this tab group.
815 // We found and removed the GuiWorkArea.
817 // No more WorkAreas in this tab group, so delete it.
822 if (d.current_work_area_)
823 // This means that we are not closing the current GuiWorkArea;
826 // Switch to the next GuiWorkArea in the found TabWorkArea.
827 d.current_work_area_ = twa->currentWorkArea();
831 if (d.splitter_->count() == 0)
832 // No more work area, switch to the background widget.
837 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
843 void GuiView::updateLayoutList()
846 d.layout_->updateContents(false);
850 void GuiView::updateToolbars()
852 if (d.current_work_area_) {
854 d.current_work_area_->bufferView().cursor().inMathed();
856 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
858 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
859 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
860 bool const mathmacrotemplate =
861 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
863 d.toolbars_->update(math, table, review, mathmacrotemplate);
865 d.toolbars_->update(false, false, false, false);
869 Buffer * GuiView::buffer()
871 if (d.current_work_area_)
872 return &d.current_work_area_->bufferView().buffer();
877 Buffer const * GuiView::buffer() const
879 if (d.current_work_area_)
880 return &d.current_work_area_->bufferView().buffer();
885 void GuiView::setBuffer(Buffer * newBuffer)
887 LASSERT(newBuffer, /**/);
890 GuiWorkArea * wa = workArea(*newBuffer);
892 updateLabels(*newBuffer->masterBuffer());
893 wa = addWorkArea(*newBuffer);
895 //Disconnect the old buffer...there's no new one.
898 connectBuffer(*newBuffer);
899 connectBufferView(wa->bufferView());
900 setCurrentWorkArea(wa);
906 void GuiView::connectBuffer(Buffer & buf)
908 buf.setGuiDelegate(this);
912 void GuiView::disconnectBuffer()
914 if (d.current_work_area_)
915 d.current_work_area_->bufferView().setGuiDelegate(0);
919 void GuiView::connectBufferView(BufferView & bv)
921 bv.setGuiDelegate(this);
925 void GuiView::disconnectBufferView()
927 if (d.current_work_area_)
928 d.current_work_area_->bufferView().setGuiDelegate(0);
932 void GuiView::errors(string const & error_type)
934 ErrorList & el = buffer()->errorList(error_type);
936 showDialog("errorlist", error_type);
940 void GuiView::structureChanged()
942 d.toc_models_.reset(view());
943 // Navigator needs more than a simple update in this case. It needs to be
945 updateDialog("toc", "");
949 void GuiView::updateDialog(string const & name, string const & data)
951 if (!isDialogVisible(name))
954 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
955 if (it == d.dialogs_.end())
958 Dialog * const dialog = it->second.get();
959 if (dialog->isVisibleView())
960 dialog->initialiseParams(data);
964 BufferView * GuiView::view()
966 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
970 void GuiView::autoSave()
972 LYXERR(Debug::INFO, "Running autoSave()");
975 view()->buffer().autoSave();
979 void GuiView::resetAutosaveTimers()
982 d.autosave_timeout_.restart();
986 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
990 Buffer * buf = buffer();
992 /* In LyX/Mac, when a dialog is open, the menus of the
993 application can still be accessed without giving focus to
994 the main window. In this case, we want to disable the menu
995 entries that are buffer-related.
997 Note that this code is not perfect, as bug 1941 attests:
998 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1000 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1003 switch(cmd.action) {
1004 case LFUN_BUFFER_WRITE:
1005 enable = buf && (buf->isUnnamed() || !buf->isClean());
1008 case LFUN_BUFFER_WRITE_AS:
1012 case LFUN_SPLIT_VIEW:
1016 case LFUN_CLOSE_TAB_GROUP:
1017 enable = d.currentTabWorkArea();
1020 case LFUN_TOOLBAR_TOGGLE:
1021 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1024 case LFUN_UI_TOGGLE:
1025 flag.setOnOff(isFullScreen());
1028 case LFUN_DIALOG_TOGGLE:
1029 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1030 // fall through to set "enable"
1031 case LFUN_DIALOG_SHOW: {
1032 string const name = cmd.getArg(0);
1034 enable = name == "aboutlyx"
1035 || name == "file" //FIXME: should be removed.
1037 || name == "texinfo";
1038 else if (name == "print")
1039 enable = buf->isExportable("dvi")
1040 && lyxrc.print_command != "none";
1041 else if (name == "character") {
1045 InsetCode ic = view()->cursor().inset().lyxCode();
1046 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1049 else if (name == "symbols") {
1050 if (!view() || view()->cursor().inMathed())
1053 InsetCode ic = view()->cursor().inset().lyxCode();
1054 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1057 else if (name == "latexlog")
1058 enable = FileName(buf->logName()).isReadableFile();
1059 else if (name == "spellchecker")
1060 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1061 enable = !buf->isReadonly();
1065 else if (name == "vclog")
1066 enable = buf->lyxvc().inUse();
1070 case LFUN_DIALOG_UPDATE: {
1071 string const name = cmd.getArg(0);
1073 enable = name == "prefs";
1077 case LFUN_INSET_APPLY: {
1082 string const name = cmd.getArg(0);
1083 Inset * inset = getOpenInset(name);
1085 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1087 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1088 // Every inset is supposed to handle this
1089 LASSERT(false, /**/);
1093 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1094 flag |= getStatus(fr);
1096 enable = flag.enabled();
1100 case LFUN_COMPLETION_INLINE:
1101 if (!d.current_work_area_
1102 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1106 case LFUN_COMPLETION_POPUP:
1107 if (!d.current_work_area_
1108 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1112 case LFUN_COMPLETION_COMPLETE:
1113 if (!d.current_work_area_
1114 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1126 flag.enabled(false);
1132 static FileName selectTemplateFile()
1134 FileDialog dlg(qt_("Select template file"));
1135 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1136 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1138 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1139 QStringList(qt_("LyX Documents (*.lyx)")));
1141 if (result.first == FileDialog::Later)
1143 if (result.second.isEmpty())
1145 return FileName(fromqstr(result.second));
1149 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1153 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1156 message(_("Document not loaded."));
1161 setBuffer(newBuffer);
1163 // scroll to the position when the file was last closed
1164 if (lyxrc.use_lastfilepos) {
1165 LastFilePosSection::FilePos filepos =
1166 LyX::ref().session().lastFilePos().load(filename);
1167 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1171 LyX::ref().session().lastFiles().add(filename);
1178 void GuiView::openDocument(string const & fname)
1180 string initpath = lyxrc.document_path;
1183 string const trypath = buffer()->filePath();
1184 // If directory is writeable, use this as default.
1185 if (FileName(trypath).isDirWritable())
1191 if (fname.empty()) {
1192 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1193 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1194 dlg.setButton2(qt_("Examples|#E#e"),
1195 toqstr(addPath(package().system_support().absFilename(), "examples")));
1197 FileDialog::Result result =
1198 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1200 if (result.first == FileDialog::Later)
1203 filename = fromqstr(result.second);
1205 // check selected filename
1206 if (filename.empty()) {
1207 message(_("Canceled."));
1213 // get absolute path of file and add ".lyx" to the filename if
1215 FileName const fullname =
1216 fileSearch(string(), filename, "lyx", support::may_not_exist);
1217 if (!fullname.empty())
1218 filename = fullname.absFilename();
1220 // if the file doesn't exist, let the user create one
1221 if (!fullname.exists()) {
1222 // the user specifically chose this name. Believe him.
1223 Buffer * const b = newFile(filename, string(), true);
1229 docstring const disp_fn = makeDisplayPath(filename);
1230 message(bformat(_("Opening document %1$s..."), disp_fn));
1233 Buffer * buf = loadDocument(fullname);
1238 buf->errors("Parse");
1239 str2 = bformat(_("Document %1$s opened."), disp_fn);
1241 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1246 // FIXME: clean that
1247 static bool import(GuiView * lv, FileName const & filename,
1248 string const & format, ErrorList & errorList)
1250 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1252 string loader_format;
1253 vector<string> loaders = theConverters().loaders();
1254 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1255 for (vector<string>::const_iterator it = loaders.begin();
1256 it != loaders.end(); ++it) {
1257 if (!theConverters().isReachable(format, *it))
1260 string const tofile =
1261 support::changeExtension(filename.absFilename(),
1262 formats.extension(*it));
1263 if (!theConverters().convert(0, filename, FileName(tofile),
1264 filename, format, *it, errorList))
1266 loader_format = *it;
1269 if (loader_format.empty()) {
1270 frontend::Alert::error(_("Couldn't import file"),
1271 bformat(_("No information for importing the format %1$s."),
1272 formats.prettyName(format)));
1276 loader_format = format;
1278 if (loader_format == "lyx") {
1279 Buffer * buf = lv->loadDocument(lyxfile);
1284 buf->errors("Parse");
1286 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1290 bool as_paragraphs = loader_format == "textparagraph";
1291 string filename2 = (loader_format == format) ? filename.absFilename()
1292 : support::changeExtension(filename.absFilename(),
1293 formats.extension(loader_format));
1294 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1295 theLyXFunc().setLyXView(lv);
1296 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1303 void GuiView::importDocument(string const & argument)
1306 string filename = split(argument, format, ' ');
1308 LYXERR(Debug::INFO, format << " file: " << filename);
1310 // need user interaction
1311 if (filename.empty()) {
1312 string initpath = lyxrc.document_path;
1314 Buffer const * buf = buffer();
1316 string const trypath = buf->filePath();
1317 // If directory is writeable, use this as default.
1318 if (FileName(trypath).isDirWritable())
1322 docstring const text = bformat(_("Select %1$s file to import"),
1323 formats.prettyName(format));
1325 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1326 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1327 dlg.setButton2(qt_("Examples|#E#e"),
1328 toqstr(addPath(package().system_support().absFilename(), "examples")));
1330 docstring filter = formats.prettyName(format);
1333 filter += from_utf8(formats.extension(format));
1336 FileDialog::Result result =
1337 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1339 if (result.first == FileDialog::Later)
1342 filename = fromqstr(result.second);
1344 // check selected filename
1345 if (filename.empty())
1346 message(_("Canceled."));
1349 if (filename.empty())
1352 // get absolute path of file
1353 FileName const fullname(support::makeAbsPath(filename));
1355 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1357 // Check if the document already is open
1358 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1361 if (!closeBuffer()) {
1362 message(_("Canceled."));
1367 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1369 // if the file exists already, and we didn't do
1370 // -i lyx thefile.lyx, warn
1371 if (lyxfile.exists() && fullname != lyxfile) {
1373 docstring text = bformat(_("The document %1$s already exists.\n\n"
1374 "Do you want to overwrite that document?"), displaypath);
1375 int const ret = Alert::prompt(_("Overwrite document?"),
1376 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1379 message(_("Canceled."));
1384 message(bformat(_("Importing %1$s..."), displaypath));
1385 ErrorList errorList;
1386 if (import(this, fullname, format, errorList))
1387 message(_("imported."));
1389 message(_("file not imported!"));
1391 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1395 void GuiView::newDocument(string const & filename, bool from_template)
1397 FileName initpath(lyxrc.document_path);
1398 Buffer * buf = buffer();
1400 FileName const trypath(buf->filePath());
1401 // If directory is writeable, use this as default.
1402 if (trypath.isDirWritable())
1406 string templatefile = from_template ?
1407 selectTemplateFile().absFilename() : string();
1409 if (filename.empty())
1410 b = newUnnamedFile(templatefile, initpath);
1412 b = newFile(filename, templatefile, true);
1416 // Ensure the cursor is correctly positionned on screen.
1417 view()->showCursor();
1421 void GuiView::insertLyXFile(docstring const & fname)
1423 BufferView * bv = view();
1428 FileName filename(to_utf8(fname));
1430 if (!filename.empty()) {
1431 bv->insertLyXFile(filename);
1435 // Launch a file browser
1437 string initpath = lyxrc.document_path;
1438 string const trypath = bv->buffer().filePath();
1439 // If directory is writeable, use this as default.
1440 if (FileName(trypath).isDirWritable())
1444 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1445 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1446 dlg.setButton2(qt_("Examples|#E#e"),
1447 toqstr(addPath(package().system_support().absFilename(),
1450 FileDialog::Result result = dlg.open(toqstr(initpath),
1451 QStringList(qt_("LyX Documents (*.lyx)")));
1453 if (result.first == FileDialog::Later)
1457 filename.set(fromqstr(result.second));
1459 // check selected filename
1460 if (filename.empty()) {
1461 // emit message signal.
1462 message(_("Canceled."));
1466 bv->insertLyXFile(filename);
1470 void GuiView::insertPlaintextFile(docstring const & fname,
1473 BufferView * bv = view();
1478 FileName filename(to_utf8(fname));
1480 if (!filename.empty()) {
1481 bv->insertPlaintextFile(filename, asParagraph);
1485 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1486 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1488 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1491 if (result.first == FileDialog::Later)
1495 filename.set(fromqstr(result.second));
1497 // check selected filename
1498 if (filename.empty()) {
1499 // emit message signal.
1500 message(_("Canceled."));
1504 bv->insertPlaintextFile(filename, asParagraph);
1508 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1510 FileName fname = b.fileName();
1511 FileName const oldname = fname;
1513 if (!newname.empty()) {
1515 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1517 // Switch to this Buffer.
1520 /// No argument? Ask user through dialog.
1522 FileDialog dlg(qt_("Choose a filename to save document as"),
1523 LFUN_BUFFER_WRITE_AS);
1524 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1525 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1527 if (!isLyXFilename(fname.absFilename()))
1528 fname.changeExtension(".lyx");
1530 FileDialog::Result result =
1531 dlg.save(toqstr(fname.onlyPath().absFilename()),
1532 QStringList(qt_("LyX Documents (*.lyx)")),
1533 toqstr(fname.onlyFileName()));
1535 if (result.first == FileDialog::Later)
1538 fname.set(fromqstr(result.second));
1543 if (!isLyXFilename(fname.absFilename()))
1544 fname.changeExtension(".lyx");
1547 if (FileName(fname).exists()) {
1548 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1549 docstring text = bformat(_("The document %1$s already "
1550 "exists.\n\nDo you want to "
1551 "overwrite that document?"),
1553 int const ret = Alert::prompt(_("Overwrite document?"),
1554 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1557 case 1: return renameBuffer(b, docstring());
1558 case 2: return false;
1562 // Ok, change the name of the buffer
1563 b.setFileName(fname.absFilename());
1565 bool unnamed = b.isUnnamed();
1566 b.setUnnamed(false);
1567 b.saveCheckSum(fname);
1569 if (!saveBuffer(b)) {
1570 b.setFileName(oldname.absFilename());
1571 b.setUnnamed(unnamed);
1572 b.saveCheckSum(oldname);
1580 bool GuiView::saveBuffer(Buffer & b)
1583 return renameBuffer(b, docstring());
1586 LyX::ref().session().lastFiles().add(b.fileName());
1590 // Switch to this Buffer.
1593 // FIXME: we don't tell the user *WHY* the save failed !!
1594 docstring const file = makeDisplayPath(b.absFileName(), 30);
1595 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1596 "Do you want to rename the document and "
1597 "try again?"), file);
1598 int const ret = Alert::prompt(_("Rename and save?"),
1599 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1602 if (!renameBuffer(b, docstring()))
1611 return saveBuffer(b);
1615 bool GuiView::closeBuffer()
1617 Buffer * buf = buffer();
1618 return buf && closeBuffer(*buf);
1622 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1624 // goto bookmark to update bookmark pit.
1625 //FIXME: we should update only the bookmarks related to this buffer!
1626 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1627 theLyXFunc().gotoBookmark(i+1, false, false);
1629 if (buf.isClean() || buf.paragraphs().empty()) {
1630 if (buf.masterBuffer() == &buf && tolastopened)
1631 LyX::ref().session().lastOpened().add(buf.fileName());
1632 theBufferList().release(&buf);
1635 // Switch to this Buffer.
1640 if (buf.isUnnamed())
1641 file = from_utf8(buf.fileName().onlyFileName());
1643 file = buf.fileName().displayName(30);
1645 // Bring this window to top before asking questions.
1649 docstring const text = bformat(_("The document %1$s has unsaved changes."
1650 "\n\nDo you want to save the document or discard the changes?"), file);
1651 int const ret = Alert::prompt(_("Save changed document?"),
1652 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1656 if (!saveBuffer(buf))
1660 // if we crash after this we could
1661 // have no autosave file but I guess
1662 // this is really improbable (Jug)
1663 removeAutosaveFile(buf.absFileName());
1669 // save file names to .lyx/session
1670 // if master/slave are both open, do not save slave since it
1671 // will be automatically loaded when the master is loaded
1672 if (buf.masterBuffer() == &buf && tolastopened)
1673 LyX::ref().session().lastOpened().add(buf.fileName());
1675 theBufferList().release(&buf);
1680 bool GuiView::dispatch(FuncRequest const & cmd)
1682 BufferView * bv = view();
1683 // By default we won't need any update.
1685 bv->cursor().updateFlags(Update::None);
1686 bool dispatched = true;
1688 switch(cmd.action) {
1689 case LFUN_BUFFER_IMPORT:
1690 importDocument(to_utf8(cmd.argument()));
1693 case LFUN_BUFFER_SWITCH:
1694 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1697 case LFUN_BUFFER_NEXT:
1698 setBuffer(theBufferList().next(buffer()));
1701 case LFUN_BUFFER_PREVIOUS:
1702 setBuffer(theBufferList().previous(buffer()));
1705 case LFUN_COMMAND_EXECUTE: {
1706 bool const show_it = cmd.argument() != "off";
1707 d.toolbars_->showCommandBuffer(show_it);
1710 case LFUN_DROP_LAYOUTS_CHOICE:
1712 d.layout_->showPopup();
1715 case LFUN_MENU_OPEN:
1716 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1717 menu->exec(QCursor::pos());
1720 case LFUN_FILE_INSERT:
1721 insertLyXFile(cmd.argument());
1723 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1724 insertPlaintextFile(cmd.argument(), true);
1727 case LFUN_FILE_INSERT_PLAINTEXT:
1728 insertPlaintextFile(cmd.argument(), false);
1731 case LFUN_BUFFER_WRITE:
1733 saveBuffer(bv->buffer());
1736 case LFUN_BUFFER_WRITE_AS:
1738 renameBuffer(bv->buffer(), cmd.argument());
1741 case LFUN_BUFFER_WRITE_ALL: {
1742 Buffer * first = theBufferList().first();
1745 message(_("Saving all documents..."));
1746 // We cannot use a for loop as the buffer list cycles.
1749 if (!b->isClean()) {
1751 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1753 b = theBufferList().next(b);
1754 } while (b != first);
1755 message(_("All documents saved."));
1759 case LFUN_TOOLBAR_TOGGLE: {
1760 string const name = cmd.getArg(0);
1761 bool const allowauto = cmd.getArg(1) == "allowauto";
1762 // it is possible to get current toolbar status like this,...
1763 // but I decide to obey the order of ToolbarBackend::flags
1764 // and disregard real toolbar status.
1765 // toolbars_->saveToolbarInfo();
1767 // toggle state on/off/auto
1768 d.toolbars_->toggleToolbarState(name, allowauto);
1772 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1774 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1778 if (tbi->flags & ToolbarInfo::ON)
1780 else if (tbi->flags & ToolbarInfo::OFF)
1782 else if (tbi->flags & ToolbarInfo::AUTO)
1785 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1786 _(tbi->gui_name), state));
1790 case LFUN_DIALOG_UPDATE: {
1791 string const name = to_utf8(cmd.argument());
1792 // Can only update a dialog connected to an existing inset
1793 Inset * inset = getOpenInset(name);
1795 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1796 inset->dispatch(view()->cursor(), fr);
1797 } else if (name == "paragraph") {
1798 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1799 } else if (name == "prefs") {
1800 updateDialog(name, string());
1805 case LFUN_DIALOG_TOGGLE: {
1806 if (isDialogVisible(cmd.getArg(0)))
1807 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1809 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1813 case LFUN_DIALOG_DISCONNECT_INSET:
1814 disconnectDialog(to_utf8(cmd.argument()));
1817 case LFUN_DIALOG_HIDE: {
1818 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1822 case LFUN_DIALOG_SHOW: {
1823 string const name = cmd.getArg(0);
1824 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1826 if (name == "character") {
1827 data = freefont2string();
1829 showDialog("character", data);
1830 } else if (name == "latexlog") {
1831 Buffer::LogType type;
1832 string const logfile = buffer()->logName(&type);
1834 case Buffer::latexlog:
1837 case Buffer::buildlog:
1841 data += Lexer::quoteString(logfile);
1842 showDialog("log", data);
1843 } else if (name == "vclog") {
1844 string const data = "vc " +
1845 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1846 showDialog("log", data);
1847 } else if (name == "symbols") {
1848 data = bv->cursor().getEncoding()->name();
1850 showDialog("symbols", data);
1852 showDialog(name, data);
1856 case LFUN_INSET_APPLY: {
1857 view()->cursor().recordUndoFullDocument();
1858 string const name = cmd.getArg(0);
1859 Inset * inset = getOpenInset(name);
1861 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1862 inset->dispatch(view()->cursor(), fr);
1864 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1870 case LFUN_UI_TOGGLE:
1872 // Make sure the keyboard focus stays in the work area.
1876 case LFUN_COMPLETION_INLINE:
1877 if (d.current_work_area_)
1878 d.current_work_area_->completer().showInline();
1881 case LFUN_SPLIT_VIEW:
1882 if (Buffer * buf = buffer()) {
1883 string const orientation = cmd.getArg(0);
1884 d.splitter_->setOrientation(orientation == "vertical"
1885 ? Qt::Vertical : Qt::Horizontal);
1886 TabWorkArea * twa = addTabWorkArea();
1887 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1888 setCurrentWorkArea(wa);
1892 case LFUN_CLOSE_TAB_GROUP:
1893 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1895 twa = d.currentTabWorkArea();
1896 // Switch to the next GuiWorkArea in the found TabWorkArea.
1897 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1898 if (d.splitter_->count() == 0)
1899 // No more work area, switch to the background widget.
1904 case LFUN_COMPLETION_POPUP:
1905 if (d.current_work_area_)
1906 d.current_work_area_->completer().showPopup();
1910 case LFUN_COMPLETION_COMPLETE:
1911 if (d.current_work_area_)
1912 d.current_work_area_->completer().tab();
1920 if (isFullScreen()) {
1921 if (menuBar()->isVisible())
1923 if (statusBar()->isVisible())
1924 statusBar()->hide();
1931 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1933 string const arg = cmd.getArg(0);
1934 if (arg == "scrollbar") {
1935 // hide() is of no help
1936 if (d.current_work_area_->verticalScrollBarPolicy() ==
1937 Qt::ScrollBarAlwaysOff)
1939 d.current_work_area_->setVerticalScrollBarPolicy(
1940 Qt::ScrollBarAsNeeded);
1942 d.current_work_area_->setVerticalScrollBarPolicy(
1943 Qt::ScrollBarAlwaysOff);
1946 if (arg == "statusbar") {
1947 statusBar()->setVisible(!statusBar()->isVisible());
1950 if (arg == "menubar") {
1951 menuBar()->setVisible(!menuBar()->isVisible());
1954 #if QT_VERSION >= 0x040300
1955 if (arg == "frame") {
1957 getContentsMargins(&l, &t, &r, &b);
1958 //are the frames in default state?
1959 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1961 setContentsMargins(-2, -2, -2, -2);
1963 setContentsMargins(0, 0, 0, 0);
1968 if (arg != "fullscreen") {
1969 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1973 if (lyxrc.full_screen_toolbars)
1974 d.toolbars_->toggleFullScreen(!isFullScreen());
1976 if (isFullScreen()) {
1977 for (int i = 0; i != d.splitter_->count(); ++i)
1978 d.tabWorkArea(i)->setFullScreen(false);
1979 #if QT_VERSION >= 0x040300
1980 setContentsMargins(0, 0, 0, 0);
1982 setWindowState(windowState() ^ Qt::WindowFullScreen);
1984 statusBar()->show();
1986 for (int i = 0; i != d.splitter_->count(); ++i)
1987 d.tabWorkArea(i)->setFullScreen(true);
1988 #if QT_VERSION >= 0x040300
1989 setContentsMargins(-2, -2, -2, -2);
1991 setWindowState(windowState() ^ Qt::WindowFullScreen);
1992 statusBar()->hide();
1998 Buffer const * GuiView::updateInset(Inset const * inset)
2000 if (!d.current_work_area_)
2004 d.current_work_area_->scheduleRedraw();
2006 return &d.current_work_area_->bufferView().buffer();
2010 void GuiView::restartCursor()
2012 /* When we move around, or type, it's nice to be able to see
2013 * the cursor immediately after the keypress.
2015 if (d.current_work_area_)
2016 d.current_work_area_->startBlinkingCursor();
2018 // Take this occasion to update the other GUI elements.
2023 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2025 if (d.current_work_area_)
2026 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2031 // This list should be kept in sync with the list of insets in
2032 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2033 // dialog should have the same name as the inset.
2035 char const * const dialognames[] = {
2036 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2037 "citation", "document", "errorlist", "ert", "external", "file",
2038 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2039 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2040 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2042 #ifdef HAVE_LIBAIKSAURUS
2046 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2048 char const * const * const end_dialognames =
2049 dialognames + (sizeof(dialognames) / sizeof(char *));
2053 cmpCStr(char const * name) : name_(name) {}
2054 bool operator()(char const * other) {
2055 return strcmp(other, name_) == 0;
2062 bool isValidName(string const & name)
2064 return find_if(dialognames, end_dialognames,
2065 cmpCStr(name.c_str())) != end_dialognames;
2071 void GuiView::resetDialogs()
2073 // Make sure that no LFUN uses any LyXView.
2074 theLyXFunc().setLyXView(0);
2075 // FIXME: the "math panels" toolbar takes an awful lot of time to
2076 // initialise so we don't do that for the time being.
2077 //d.toolbars_->init();
2078 guiApp->menus().fillMenuBar(menuBar(), this);
2080 d.layout_->updateContents(true);
2081 // Now update controls with current buffer.
2082 theLyXFunc().setLyXView(this);
2087 Dialog * GuiView::find_or_build(string const & name)
2089 if (!isValidName(name))
2092 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2094 if (it != d.dialogs_.end())
2095 return it->second.get();
2097 Dialog * dialog = build(name);
2098 d.dialogs_[name].reset(dialog);
2099 if (lyxrc.allow_geometry_session)
2100 dialog->restoreSession();
2105 void GuiView::showDialog(string const & name, string const & data,
2112 Dialog * dialog = find_or_build(name);
2114 dialog->showData(data);
2116 d.open_insets_[name] = inset;
2122 bool GuiView::isDialogVisible(string const & name) const
2124 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2125 if (it == d.dialogs_.end())
2127 return it->second.get()->isVisibleView();
2131 void GuiView::hideDialog(string const & name, Inset * inset)
2133 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2134 if (it == d.dialogs_.end())
2137 if (inset && inset != getOpenInset(name))
2140 Dialog * const dialog = it->second.get();
2141 if (dialog->isVisibleView())
2143 d.open_insets_[name] = 0;
2147 void GuiView::disconnectDialog(string const & name)
2149 if (!isValidName(name))
2152 if (d.open_insets_.find(name) != d.open_insets_.end())
2153 d.open_insets_[name] = 0;
2157 Inset * GuiView::getOpenInset(string const & name) const
2159 if (!isValidName(name))
2162 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2163 return it == d.open_insets_.end() ? 0 : it->second;
2167 void GuiView::hideAll() const
2169 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2170 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2172 for(; it != end; ++it)
2173 it->second->hideView();
2177 void GuiView::updateDialogs()
2179 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2180 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2182 for(; it != end; ++it) {
2183 Dialog * dialog = it->second.get();
2184 if (dialog && dialog->isVisibleView())
2185 dialog->checkStatus();
2193 // will be replaced by a proper factory...
2194 Dialog * createGuiAbout(GuiView & lv);
2195 Dialog * createGuiBibitem(GuiView & lv);
2196 Dialog * createGuiBibtex(GuiView & lv);
2197 Dialog * createGuiBox(GuiView & lv);
2198 Dialog * createGuiBranch(GuiView & lv);
2199 Dialog * createGuiChanges(GuiView & lv);
2200 Dialog * createGuiCharacter(GuiView & lv);
2201 Dialog * createGuiCitation(GuiView & lv);
2202 Dialog * createGuiDelimiter(GuiView & lv);
2203 Dialog * createGuiDocument(GuiView & lv);
2204 Dialog * createGuiErrorList(GuiView & lv);
2205 Dialog * createGuiERT(GuiView & lv);
2206 Dialog * createGuiExternal(GuiView & lv);
2207 Dialog * createGuiFloat(GuiView & lv);
2208 Dialog * createGuiGraphics(GuiView & lv);
2209 Dialog * createGuiHSpace(GuiView & lv);
2210 Dialog * createGuiInclude(GuiView & lv);
2211 Dialog * createGuiLabel(GuiView & lv);
2212 Dialog * createGuiListings(GuiView & lv);
2213 Dialog * createGuiLog(GuiView & lv);
2214 Dialog * createGuiMathMatrix(GuiView & lv);
2215 Dialog * createGuiNomenclature(GuiView & lv);
2216 Dialog * createGuiNote(GuiView & lv);
2217 Dialog * createGuiParagraph(GuiView & lv);
2218 Dialog * createGuiPreferences(GuiView & lv);
2219 Dialog * createGuiPrint(GuiView & lv);
2220 Dialog * createGuiRef(GuiView & lv);
2221 Dialog * createGuiSearch(GuiView & lv);
2222 Dialog * createGuiSendTo(GuiView & lv);
2223 Dialog * createGuiShowFile(GuiView & lv);
2224 Dialog * createGuiSpellchecker(GuiView & lv);
2225 Dialog * createGuiSymbols(GuiView & lv);
2226 Dialog * createGuiTabularCreate(GuiView & lv);
2227 Dialog * createGuiTabular(GuiView & lv);
2228 Dialog * createGuiTexInfo(GuiView & lv);
2229 Dialog * createGuiToc(GuiView & lv);
2230 Dialog * createGuiThesaurus(GuiView & lv);
2231 Dialog * createGuiHyperlink(GuiView & lv);
2232 Dialog * createGuiVSpace(GuiView & lv);
2233 Dialog * createGuiViewSource(GuiView & lv);
2234 Dialog * createGuiWrap(GuiView & lv);
2237 Dialog * GuiView::build(string const & name)
2239 LASSERT(isValidName(name), /**/);
2241 if (name == "aboutlyx")
2242 return createGuiAbout(*this);
2243 if (name == "bibitem")
2244 return createGuiBibitem(*this);
2245 if (name == "bibtex")
2246 return createGuiBibtex(*this);
2248 return createGuiBox(*this);
2249 if (name == "branch")
2250 return createGuiBranch(*this);
2251 if (name == "changes")
2252 return createGuiChanges(*this);
2253 if (name == "character")
2254 return createGuiCharacter(*this);
2255 if (name == "citation")
2256 return createGuiCitation(*this);
2257 if (name == "document")
2258 return createGuiDocument(*this);
2259 if (name == "errorlist")
2260 return createGuiErrorList(*this);
2262 return createGuiERT(*this);
2263 if (name == "external")
2264 return createGuiExternal(*this);
2266 return createGuiShowFile(*this);
2267 if (name == "findreplace")
2268 return createGuiSearch(*this);
2269 if (name == "float")
2270 return createGuiFloat(*this);
2271 if (name == "graphics")
2272 return createGuiGraphics(*this);
2273 if (name == "include")
2274 return createGuiInclude(*this);
2275 if (name == "nomenclature")
2276 return createGuiNomenclature(*this);
2277 if (name == "label")
2278 return createGuiLabel(*this);
2280 return createGuiLog(*this);
2281 if (name == "view-source")
2282 return createGuiViewSource(*this);
2283 if (name == "mathdelimiter")
2284 return createGuiDelimiter(*this);
2285 if (name == "mathmatrix")
2286 return createGuiMathMatrix(*this);
2288 return createGuiNote(*this);
2289 if (name == "paragraph")
2290 return createGuiParagraph(*this);
2291 if (name == "prefs")
2292 return createGuiPreferences(*this);
2293 if (name == "print")
2294 return createGuiPrint(*this);
2296 return createGuiRef(*this);
2297 if (name == "sendto")
2298 return createGuiSendTo(*this);
2299 if (name == "space")
2300 return createGuiHSpace(*this);
2301 if (name == "spellchecker")
2302 return createGuiSpellchecker(*this);
2303 if (name == "symbols")
2304 return createGuiSymbols(*this);
2305 if (name == "tabular")
2306 return createGuiTabular(*this);
2307 if (name == "tabularcreate")
2308 return createGuiTabularCreate(*this);
2309 if (name == "texinfo")
2310 return createGuiTexInfo(*this);
2311 #ifdef HAVE_LIBAIKSAURUS
2312 if (name == "thesaurus")
2313 return createGuiThesaurus(*this);
2316 return createGuiToc(*this);
2318 return createGuiHyperlink(*this);
2319 if (name == "vspace")
2320 return createGuiVSpace(*this);
2322 return createGuiWrap(*this);
2323 if (name == "listings")
2324 return createGuiListings(*this);
2330 } // namespace frontend
2333 #include "GuiView_moc.cpp"