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 "GuiCommandBuffer.h"
22 #include "GuiCompleter.h"
23 #include "GuiWorkArea.h"
24 #include "GuiKeySymbol.h"
25 #include "GuiToolbar.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"
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_);
144 /// Toolbar store providing access to individual toolbars by name.
145 typedef std::map<std::string, GuiToolbar *> ToolbarMap;
147 typedef boost::shared_ptr<Dialog> DialogPtr;
152 struct GuiView::GuiViewPrivate
155 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
158 // hardcode here the platform specific icon size
159 smallIconSize = 14; // scaling problems
160 normalIconSize = 20; // ok, default
161 bigIconSize = 26; // better for some math icons
163 splitter_ = new QSplitter;
164 bg_widget_ = new BackgroundWidget;
165 stack_widget_ = new QStackedWidget;
166 stack_widget_->addWidget(bg_widget_);
167 stack_widget_->addWidget(splitter_);
175 delete stack_widget_;
178 QMenu * toolBarPopup(GuiView * parent)
180 // FIXME: translation
181 QMenu * menu = new QMenu(parent);
182 QActionGroup * iconSizeGroup = new QActionGroup(parent);
184 QAction * smallIcons = new QAction(iconSizeGroup);
185 smallIcons->setText(qt_("Small-sized icons"));
186 smallIcons->setCheckable(true);
187 QObject::connect(smallIcons, SIGNAL(triggered()),
188 parent, SLOT(smallSizedIcons()));
189 menu->addAction(smallIcons);
191 QAction * normalIcons = new QAction(iconSizeGroup);
192 normalIcons->setText(qt_("Normal-sized icons"));
193 normalIcons->setCheckable(true);
194 QObject::connect(normalIcons, SIGNAL(triggered()),
195 parent, SLOT(normalSizedIcons()));
196 menu->addAction(normalIcons);
198 QAction * bigIcons = new QAction(iconSizeGroup);
199 bigIcons->setText(qt_("Big-sized icons"));
200 bigIcons->setCheckable(true);
201 QObject::connect(bigIcons, SIGNAL(triggered()),
202 parent, SLOT(bigSizedIcons()));
203 menu->addAction(bigIcons);
205 unsigned int cur = parent->iconSize().width();
206 if ( cur == parent->d.smallIconSize)
207 smallIcons->setChecked(true);
208 else if (cur == parent->d.normalIconSize)
209 normalIcons->setChecked(true);
210 else if (cur == parent->d.bigIconSize)
211 bigIcons->setChecked(true);
218 stack_widget_->setCurrentWidget(bg_widget_);
219 bg_widget_->setUpdatesEnabled(true);
222 TabWorkArea * tabWorkArea(int i)
224 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
227 TabWorkArea * currentTabWorkArea()
229 if (splitter_->count() == 1)
230 // The first TabWorkArea is always the first one, if any.
231 return tabWorkArea(0);
233 for (int i = 0; i != splitter_->count(); ++i) {
234 TabWorkArea * twa = tabWorkArea(i);
235 if (current_work_area_ == twa->currentWorkArea())
239 // None has the focus so we just take the first one.
240 return tabWorkArea(0);
244 GuiWorkArea * current_work_area_;
245 QSplitter * splitter_;
246 QStackedWidget * stack_widget_;
247 BackgroundWidget * bg_widget_;
249 ToolbarMap toolbars_;
250 /// The main layout box.
252 * \warning Don't Delete! The layout box is actually owned by
253 * whichever toolbar contains it. All the GuiView class needs is a
254 * means of accessing it.
256 * FIXME: replace that with a proper model so that we are not limited
257 * to only one dialog.
259 GuiLayoutBox * layout_;
262 map<string, Inset *> open_insets_;
265 map<string, DialogPtr> dialogs_;
267 unsigned int smallIconSize;
268 unsigned int normalIconSize;
269 unsigned int bigIconSize;
271 QTimer statusbar_timer_;
272 /// auto-saving of buffers
273 Timeout autosave_timeout_;
274 /// flag against a race condition due to multiclicks, see bug #1119
278 TocModels toc_models_;
282 GuiView::GuiView(int id)
283 : d(*new GuiViewPrivate), id_(id)
285 // GuiToolbars *must* be initialised before the menu bar.
288 // set ourself as the current view. This is needed for the menu bar
289 // filling, at least for the static special menu item on Mac. Otherwise
290 // they are greyed out.
291 theLyXFunc().setLyXView(this);
293 // Fill up the menu bar.
294 guiApp->menus().fillMenuBar(menuBar(), this, true);
296 setCentralWidget(d.stack_widget_);
298 // Start autosave timer
299 if (lyxrc.autosave) {
300 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
301 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
302 d.autosave_timeout_.start();
304 connect(&d.statusbar_timer_, SIGNAL(timeout()),
305 this, SLOT(clearMessage()));
307 // We don't want to keep the window in memory if it is closed.
308 setAttribute(Qt::WA_DeleteOnClose, true);
310 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
311 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
312 // since the icon is provided in the application bundle.
313 setWindowIcon(QPixmap(":/images/lyx.png"));
317 setAcceptDrops(true);
319 statusBar()->setSizeGripEnabled(true);
321 // Forbid too small unresizable window because it can happen
322 // with some window manager under X11.
323 setMinimumSize(300, 200);
325 if (lyxrc.allow_geometry_session) {
326 // Now take care of session management.
331 // No session handling, default to a sane size.
332 setGeometry(50, 50, 690, 510);
334 // This enables to clear session data if any.
346 void GuiView::saveLayout() const
349 QString const key = "view-" + QString::number(id_);
351 settings.setValue(key + "/pos", pos());
352 settings.setValue(key + "/size", size());
354 settings.setValue(key + "/geometry", saveGeometry());
356 settings.setValue(key + "/layout", saveState(0));
357 settings.setValue(key + "/icon_size", iconSize());
361 void GuiView::restoreLayout()
364 QString const key = "view-" + QString::number(id_);
365 setIconSize(settings.value(key + "/icon_size").toSize());
367 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
368 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
372 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
373 setGeometry(50, 50, 690, 510);
375 // Allow the toc and view-source dock widget to be restored if needed.
376 find_or_build("toc");
377 find_or_build("view-source");
378 if (!restoreState(settings.value(key + "/layout").toByteArray(), 0))
383 GuiToolbar * GuiView::toolbar(string const & name)
385 ToolbarMap::iterator it = d.toolbars_.find(name);
386 if (it != d.toolbars_.end())
389 LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
390 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
395 void GuiView::constructToolbars()
397 ToolbarMap::iterator it = d.toolbars_.begin();
398 for (; it != d.toolbars_.end(); ++it)
402 // extracts the toolbars from the backend
403 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
404 Toolbars::Infos::iterator end = guiApp->toolbars().end();
405 for (; cit != end; ++cit)
406 d.toolbars_[cit->name] = new GuiToolbar(*cit, *this);
410 void GuiView::initToolbars()
412 // extracts the toolbars from the backend
413 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
414 Toolbars::Infos::iterator end = guiApp->toolbars().end();
415 for (; cit != end; ++cit) {
416 GuiToolbar * tb = toolbar(cit->name);
419 int const visibility = guiApp->toolbars().defaultVisibility(cit->name);
421 tb->setVisible(false);
422 tb->setVisibility(visibility);
424 if (visibility & Toolbars::TOP) {
426 addToolBarBreak(Qt::TopToolBarArea);
427 addToolBar(Qt::TopToolBarArea, tb);
430 if (visibility & Toolbars::BOTTOM) {
431 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
432 #if (QT_VERSION >= 0x040202)
433 addToolBarBreak(Qt::BottomToolBarArea);
435 addToolBar(Qt::BottomToolBarArea, tb);
438 if (visibility & Toolbars::LEFT) {
439 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
440 #if (QT_VERSION >= 0x040202)
441 addToolBarBreak(Qt::LeftToolBarArea);
443 addToolBar(Qt::LeftToolBarArea, tb);
446 if (visibility & Toolbars::RIGHT) {
447 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
448 #if (QT_VERSION >= 0x040202)
449 addToolBarBreak(Qt::RightToolBarArea);
451 addToolBar(Qt::RightToolBarArea, tb);
454 if (visibility & Toolbars::ON)
455 tb->setVisible(true);
460 TocModels & GuiView::tocModels()
462 return d.toc_models_;
466 void GuiView::setFocus()
468 // Make sure LyXFunc points to the correct view.
469 theLyXFunc().setLyXView(this);
470 if (d.current_work_area_)
471 d.current_work_area_->setFocus();
477 QMenu * GuiView::createPopupMenu()
479 return d.toolBarPopup(this);
483 void GuiView::showEvent(QShowEvent * e)
485 LYXERR(Debug::GUI, "Passed Geometry "
486 << size().height() << "x" << size().width()
487 << "+" << pos().x() << "+" << pos().y());
489 if (d.splitter_->count() == 0)
490 // No work area, switch to the background widget.
493 QMainWindow::showEvent(e);
497 void GuiView::closeEvent(QCloseEvent * close_event)
499 // it can happen that this event arrives without selecting the view,
500 // e.g. when clicking the close button on a background window.
501 theLyXFunc().setLyXView(this);
503 while (Buffer * b = buffer()) {
505 // This is a child document, just close the tab after saving
506 // but keep the file loaded.
507 if (!saveBuffer(*b)) {
508 close_event->ignore();
511 removeWorkArea(d.current_work_area_);
515 QList<int> const ids = guiApp->viewIds();
516 for (int i = 0; i != ids.size(); ++i) {
519 if (guiApp->view(ids[i]).workArea(*b)) {
520 // FIXME 1: should we put an alert box here that the buffer
521 // is viewed elsewhere?
522 // FIXME 2: should we try to save this buffer in any case?
525 // This buffer is also opened in another view, so
526 // but close the associated work area nevertheless.
527 removeWorkArea(d.current_work_area_);
528 // but don't close it.
533 if (b && !closeBuffer(*b, true)) {
534 close_event->ignore();
539 // Make sure that nothing will use this close to be closed View.
540 guiApp->unregisterView(this);
542 if (isFullScreen()) {
543 // Switch off fullscreen before closing.
548 // Make sure the timer time out will not trigger a statusbar update.
549 d.statusbar_timer_.stop();
551 // Saving fullscreen requires additional tweaks in the toolbar code.
552 // It wouldn't also work under linux natively.
553 if (lyxrc.allow_geometry_session) {
554 // Save this window geometry and layout.
556 // Then the toolbar private states.
557 ToolbarMap::iterator end = d.toolbars_.end();
558 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
559 it->second->saveSession();
560 // Now take care of all other dialogs:
561 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
562 for (; it!= d.dialogs_.end(); ++it)
563 it->second->saveSession();
566 close_event->accept();
570 void GuiView::dragEnterEvent(QDragEnterEvent * event)
572 if (event->mimeData()->hasUrls())
574 /// \todo Ask lyx-devel is this is enough:
575 /// if (event->mimeData()->hasFormat("text/plain"))
576 /// event->acceptProposedAction();
580 void GuiView::dropEvent(QDropEvent* event)
582 QList<QUrl> files = event->mimeData()->urls();
586 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
587 for (int i = 0; i != files.size(); ++i) {
588 string const file = os::internal_path(fromqstr(
589 files.at(i).toLocalFile()));
591 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
596 void GuiView::message(docstring const & str)
598 if (ForkedProcess::iAmAChild())
601 statusBar()->showMessage(toqstr(str));
602 d.statusbar_timer_.stop();
603 d.statusbar_timer_.start(3000);
607 void GuiView::smallSizedIcons()
609 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
613 void GuiView::normalSizedIcons()
615 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
619 void GuiView::bigSizedIcons()
621 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
625 void GuiView::clearMessage()
629 theLyXFunc().setLyXView(this);
630 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
631 d.statusbar_timer_.stop();
635 void GuiView::updateWindowTitle(GuiWorkArea * wa)
637 if (wa != d.current_work_area_)
639 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
640 setWindowIconText(wa->windowIconText());
644 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
647 disconnectBufferView();
648 connectBufferView(wa->bufferView());
649 connectBuffer(wa->bufferView().buffer());
650 d.current_work_area_ = wa;
651 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
652 this, SLOT(updateWindowTitle(GuiWorkArea *)));
653 updateWindowTitle(wa);
657 // The document settings needs to be reinitialised.
658 updateDialog("document", "");
660 // Buffer-dependent dialogs must be updated. This is done here because
661 // some dialogs require buffer()->text.
666 void GuiView::on_lastWorkAreaRemoved()
669 // On Mac close the view if there is no Tab open anymore,
670 // but only if no splitter is visible
671 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
672 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
673 if (twa && twa->count() == 0) {
674 // close the view, as no tab is open anymore
675 QTimer::singleShot(0, this, SLOT(close()));
679 d.toc_models_.reset(0);
680 // The document settings needs to be reinitialised.
681 updateDialog("document", "");
687 void GuiView::updateStatusBar()
689 // let the user see the explicit message
690 if (d.statusbar_timer_.isActive())
693 theLyXFunc().setLyXView(this);
694 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
698 bool GuiView::hasFocus() const
700 return qApp->activeWindow() == this;
704 bool GuiView::event(QEvent * e)
708 // Useful debug code:
709 //case QEvent::ActivationChange:
710 //case QEvent::WindowDeactivate:
711 //case QEvent::Paint:
712 //case QEvent::Enter:
713 //case QEvent::Leave:
714 //case QEvent::HoverEnter:
715 //case QEvent::HoverLeave:
716 //case QEvent::HoverMove:
717 //case QEvent::StatusTip:
718 //case QEvent::DragEnter:
719 //case QEvent::DragLeave:
723 case QEvent::WindowActivate: {
724 if (this == guiApp->currentView()) {
726 return QMainWindow::event(e);
728 guiApp->setCurrentView(this);
729 if (d.current_work_area_) {
730 BufferView & bv = d.current_work_area_->bufferView();
731 connectBufferView(bv);
732 connectBuffer(bv.buffer());
733 // The document structure, name and dialogs might have
734 // changed in another view.
736 // The document settings needs to be reinitialised.
737 updateDialog("document", "");
740 setWindowTitle(qt_("LyX"));
741 setWindowIconText(qt_("LyX"));
744 return QMainWindow::event(e);
747 case QEvent::ShortcutOverride: {
749 if (isFullScreen() && menuBar()->isHidden()) {
750 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
751 // FIXME: we should also try to detect special LyX shortcut such as
752 // Alt-P and Alt-M. Right now there is a hack in
753 // GuiWorkArea::processKeySym() that hides again the menubar for
755 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt)
757 return QMainWindow::event(e);
760 if (d.current_work_area_)
761 // Nothing special to do.
762 return QMainWindow::event(e);
764 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
765 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
767 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
768 || ke->key() == Qt::Key_Backtab)
769 return QMainWindow::event(e);
771 // Allow processing of shortcuts that are allowed even when no Buffer
773 theLyXFunc().setLyXView(this);
775 setKeySymbol(&sym, ke);
776 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
782 return QMainWindow::event(e);
787 bool GuiView::focusNextPrevChild(bool /*next*/)
794 void GuiView::setBusy(bool busy)
796 if (d.current_work_area_) {
797 d.current_work_area_->setUpdatesEnabled(!busy);
799 d.current_work_area_->stopBlinkingCursor();
801 d.current_work_area_->startBlinkingCursor();
805 QApplication::setOverrideCursor(Qt::WaitCursor);
807 QApplication::restoreOverrideCursor();
811 GuiWorkArea * GuiView::workArea(Buffer & buffer)
813 if (TabWorkArea * twa = d.currentTabWorkArea())
814 return twa->workArea(buffer);
819 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
821 // Automatically create a TabWorkArea if there are none yet.
822 TabWorkArea * tab_widget = d.splitter_->count()
823 ? d.currentTabWorkArea() : addTabWorkArea();
824 return tab_widget->addWorkArea(buffer, *this);
828 TabWorkArea * GuiView::addTabWorkArea()
830 TabWorkArea * twa = new TabWorkArea;
831 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
832 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
833 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
834 this, SLOT(on_lastWorkAreaRemoved()));
836 d.splitter_->addWidget(twa);
837 d.stack_widget_->setCurrentWidget(d.splitter_);
842 GuiWorkArea const * GuiView::currentWorkArea() const
844 return d.current_work_area_;
848 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
851 d.current_work_area_ = wa;
852 for (int i = 0; i != d.splitter_->count(); ++i) {
853 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
859 void GuiView::removeWorkArea(GuiWorkArea * wa)
862 if (wa == d.current_work_area_) {
864 disconnectBufferView();
865 d.current_work_area_ = 0;
868 for (int i = 0; i != d.splitter_->count(); ++i) {
869 TabWorkArea * twa = d.tabWorkArea(i);
870 if (!twa->removeWorkArea(wa))
871 // Not found in this tab group.
874 // We found and removed the GuiWorkArea.
876 // No more WorkAreas in this tab group, so delete it.
881 if (d.current_work_area_)
882 // This means that we are not closing the current GuiWorkArea;
885 // Switch to the next GuiWorkArea in the found TabWorkArea.
886 d.current_work_area_ = twa->currentWorkArea();
890 if (d.splitter_->count() == 0)
891 // No more work area, switch to the background widget.
896 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
902 void GuiView::updateLayoutList()
905 d.layout_->updateContents(false);
909 void GuiView::updateToolbars()
911 ToolbarMap::iterator end = d.toolbars_.end();
912 if (d.current_work_area_) {
914 d.current_work_area_->bufferView().cursor().inMathed();
916 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
918 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
919 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
920 bool const mathmacrotemplate =
921 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
923 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
924 it->second->update(math, table, review, mathmacrotemplate);
926 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
927 it->second->update(false, false, false, false);
931 Buffer * GuiView::buffer()
933 if (d.current_work_area_)
934 return &d.current_work_area_->bufferView().buffer();
939 Buffer const * GuiView::buffer() const
941 if (d.current_work_area_)
942 return &d.current_work_area_->bufferView().buffer();
947 void GuiView::setBuffer(Buffer * newBuffer)
949 LASSERT(newBuffer, /**/);
952 GuiWorkArea * wa = workArea(*newBuffer);
954 updateLabels(*newBuffer->masterBuffer());
955 wa = addWorkArea(*newBuffer);
957 //Disconnect the old buffer...there's no new one.
960 connectBuffer(*newBuffer);
961 connectBufferView(wa->bufferView());
962 setCurrentWorkArea(wa);
968 void GuiView::connectBuffer(Buffer & buf)
970 buf.setGuiDelegate(this);
974 void GuiView::disconnectBuffer()
976 if (d.current_work_area_)
977 d.current_work_area_->bufferView().setGuiDelegate(0);
981 void GuiView::connectBufferView(BufferView & bv)
983 bv.setGuiDelegate(this);
987 void GuiView::disconnectBufferView()
989 if (d.current_work_area_)
990 d.current_work_area_->bufferView().setGuiDelegate(0);
994 void GuiView::errors(string const & error_type)
996 ErrorList & el = buffer()->errorList(error_type);
998 showDialog("errorlist", error_type);
1002 void GuiView::structureChanged()
1004 d.toc_models_.reset(view());
1005 // Navigator needs more than a simple update in this case. It needs to be
1007 updateDialog("toc", "");
1011 void GuiView::updateDialog(string const & name, string const & data)
1013 if (!isDialogVisible(name))
1016 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1017 if (it == d.dialogs_.end())
1020 Dialog * const dialog = it->second.get();
1021 if (dialog->isVisibleView())
1022 dialog->initialiseParams(data);
1026 BufferView * GuiView::view()
1028 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1032 void GuiView::autoSave()
1034 LYXERR(Debug::INFO, "Running autoSave()");
1037 view()->buffer().autoSave();
1041 void GuiView::resetAutosaveTimers()
1044 d.autosave_timeout_.restart();
1048 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1051 Buffer * buf = buffer();
1053 /* In LyX/Mac, when a dialog is open, the menus of the
1054 application can still be accessed without giving focus to
1055 the main window. In this case, we want to disable the menu
1056 entries that are buffer-related.
1058 Note that this code is not perfect, as bug 1941 attests:
1059 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1061 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1064 switch(cmd.action) {
1065 case LFUN_BUFFER_WRITE:
1066 enable = buf && (buf->isUnnamed() || !buf->isClean());
1069 case LFUN_BUFFER_WRITE_AS:
1073 case LFUN_SPLIT_VIEW:
1077 case LFUN_CLOSE_TAB_GROUP:
1078 enable = d.currentTabWorkArea();
1081 case LFUN_TOOLBAR_TOGGLE:
1082 if (GuiToolbar * t = toolbar(cmd.getArg(0)))
1083 flag.setOnOff(t->isVisible());
1086 case LFUN_UI_TOGGLE:
1087 flag.setOnOff(isFullScreen());
1090 case LFUN_DIALOG_TOGGLE:
1091 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1092 // fall through to set "enable"
1093 case LFUN_DIALOG_SHOW: {
1094 string const name = cmd.getArg(0);
1096 enable = name == "aboutlyx"
1097 || name == "file" //FIXME: should be removed.
1099 || name == "texinfo";
1100 else if (name == "print")
1101 enable = buf->isExportable("dvi")
1102 && lyxrc.print_command != "none";
1103 else if (name == "character") {
1107 InsetCode ic = view()->cursor().inset().lyxCode();
1108 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1111 else if (name == "symbols") {
1112 if (!view() || view()->cursor().inMathed())
1115 InsetCode ic = view()->cursor().inset().lyxCode();
1116 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1119 else if (name == "latexlog")
1120 enable = FileName(buf->logName()).isReadableFile();
1121 else if (name == "spellchecker")
1122 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1123 enable = !buf->isReadonly();
1127 else if (name == "vclog")
1128 enable = buf->lyxvc().inUse();
1132 case LFUN_DIALOG_UPDATE: {
1133 string const name = cmd.getArg(0);
1135 enable = name == "prefs";
1139 case LFUN_INSET_APPLY: {
1140 string const name = cmd.getArg(0);
1141 Inset * inset = getOpenInset(name);
1143 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1145 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1146 // Every inset is supposed to handle this
1147 LASSERT(false, /**/);
1151 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1152 flag |= lyx::getStatus(fr);
1154 enable = flag.enabled();
1158 case LFUN_COMPLETION_INLINE:
1159 if (!d.current_work_area_
1160 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1164 case LFUN_COMPLETION_POPUP:
1165 if (!d.current_work_area_
1166 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1170 case LFUN_COMPLETION_COMPLETE:
1171 if (!d.current_work_area_
1172 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1181 flag.setEnabled(false);
1187 static FileName selectTemplateFile()
1189 FileDialog dlg(qt_("Select template file"));
1190 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1191 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1193 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1194 QStringList(qt_("LyX Documents (*.lyx)")));
1196 if (result.first == FileDialog::Later)
1198 if (result.second.isEmpty())
1200 return FileName(fromqstr(result.second));
1204 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1208 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1211 message(_("Document not loaded."));
1216 setBuffer(newBuffer);
1218 // scroll to the position when the file was last closed
1219 if (lyxrc.use_lastfilepos) {
1220 LastFilePosSection::FilePos filepos =
1221 LyX::ref().session().lastFilePos().load(filename);
1222 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1226 LyX::ref().session().lastFiles().add(filename);
1233 void GuiView::openDocument(string const & fname)
1235 string initpath = lyxrc.document_path;
1238 string const trypath = buffer()->filePath();
1239 // If directory is writeable, use this as default.
1240 if (FileName(trypath).isDirWritable())
1246 if (fname.empty()) {
1247 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1248 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1249 dlg.setButton2(qt_("Examples|#E#e"),
1250 toqstr(addPath(package().system_support().absFilename(), "examples")));
1252 FileDialog::Result result =
1253 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1255 if (result.first == FileDialog::Later)
1258 filename = fromqstr(result.second);
1260 // check selected filename
1261 if (filename.empty()) {
1262 message(_("Canceled."));
1268 // get absolute path of file and add ".lyx" to the filename if
1270 FileName const fullname =
1271 fileSearch(string(), filename, "lyx", support::may_not_exist);
1272 if (!fullname.empty())
1273 filename = fullname.absFilename();
1275 // if the file doesn't exist, let the user create one
1276 if (!fullname.exists()) {
1277 // the user specifically chose this name. Believe him.
1278 Buffer * const b = newFile(filename, string(), true);
1284 docstring const disp_fn = makeDisplayPath(filename);
1285 message(bformat(_("Opening document %1$s..."), disp_fn));
1288 Buffer * buf = loadDocument(fullname);
1293 buf->errors("Parse");
1294 str2 = bformat(_("Document %1$s opened."), disp_fn);
1296 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1301 // FIXME: clean that
1302 static bool import(GuiView * lv, FileName const & filename,
1303 string const & format, ErrorList & errorList)
1305 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1307 string loader_format;
1308 vector<string> loaders = theConverters().loaders();
1309 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1310 for (vector<string>::const_iterator it = loaders.begin();
1311 it != loaders.end(); ++it) {
1312 if (!theConverters().isReachable(format, *it))
1315 string const tofile =
1316 support::changeExtension(filename.absFilename(),
1317 formats.extension(*it));
1318 if (!theConverters().convert(0, filename, FileName(tofile),
1319 filename, format, *it, errorList))
1321 loader_format = *it;
1324 if (loader_format.empty()) {
1325 frontend::Alert::error(_("Couldn't import file"),
1326 bformat(_("No information for importing the format %1$s."),
1327 formats.prettyName(format)));
1331 loader_format = format;
1333 if (loader_format == "lyx") {
1334 Buffer * buf = lv->loadDocument(lyxfile);
1339 buf->errors("Parse");
1341 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1345 bool as_paragraphs = loader_format == "textparagraph";
1346 string filename2 = (loader_format == format) ? filename.absFilename()
1347 : support::changeExtension(filename.absFilename(),
1348 formats.extension(loader_format));
1349 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1350 theLyXFunc().setLyXView(lv);
1351 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1358 void GuiView::importDocument(string const & argument)
1361 string filename = split(argument, format, ' ');
1363 LYXERR(Debug::INFO, format << " file: " << filename);
1365 // need user interaction
1366 if (filename.empty()) {
1367 string initpath = lyxrc.document_path;
1369 Buffer const * buf = buffer();
1371 string const trypath = buf->filePath();
1372 // If directory is writeable, use this as default.
1373 if (FileName(trypath).isDirWritable())
1377 docstring const text = bformat(_("Select %1$s file to import"),
1378 formats.prettyName(format));
1380 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1381 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1382 dlg.setButton2(qt_("Examples|#E#e"),
1383 toqstr(addPath(package().system_support().absFilename(), "examples")));
1385 docstring filter = formats.prettyName(format);
1388 filter += from_utf8(formats.extension(format));
1391 FileDialog::Result result =
1392 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1394 if (result.first == FileDialog::Later)
1397 filename = fromqstr(result.second);
1399 // check selected filename
1400 if (filename.empty())
1401 message(_("Canceled."));
1404 if (filename.empty())
1407 // get absolute path of file
1408 FileName const fullname(support::makeAbsPath(filename));
1410 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1412 // Check if the document already is open
1413 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1416 if (!closeBuffer()) {
1417 message(_("Canceled."));
1422 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1424 // if the file exists already, and we didn't do
1425 // -i lyx thefile.lyx, warn
1426 if (lyxfile.exists() && fullname != lyxfile) {
1428 docstring text = bformat(_("The document %1$s already exists.\n\n"
1429 "Do you want to overwrite that document?"), displaypath);
1430 int const ret = Alert::prompt(_("Overwrite document?"),
1431 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1434 message(_("Canceled."));
1439 message(bformat(_("Importing %1$s..."), displaypath));
1440 ErrorList errorList;
1441 if (import(this, fullname, format, errorList))
1442 message(_("imported."));
1444 message(_("file not imported!"));
1446 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1450 void GuiView::newDocument(string const & filename, bool from_template)
1452 FileName initpath(lyxrc.document_path);
1453 Buffer * buf = buffer();
1455 FileName const trypath(buf->filePath());
1456 // If directory is writeable, use this as default.
1457 if (trypath.isDirWritable())
1461 string templatefile = from_template ?
1462 selectTemplateFile().absFilename() : string();
1464 if (filename.empty())
1465 b = newUnnamedFile(templatefile, initpath);
1467 b = newFile(filename, templatefile, true);
1471 // Ensure the cursor is correctly positionned on screen.
1472 view()->showCursor();
1476 void GuiView::insertLyXFile(docstring const & fname)
1478 BufferView * bv = view();
1483 FileName filename(to_utf8(fname));
1485 if (!filename.empty()) {
1486 bv->insertLyXFile(filename);
1490 // Launch a file browser
1492 string initpath = lyxrc.document_path;
1493 string const trypath = bv->buffer().filePath();
1494 // If directory is writeable, use this as default.
1495 if (FileName(trypath).isDirWritable())
1499 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1500 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1501 dlg.setButton2(qt_("Examples|#E#e"),
1502 toqstr(addPath(package().system_support().absFilename(),
1505 FileDialog::Result result = dlg.open(toqstr(initpath),
1506 QStringList(qt_("LyX Documents (*.lyx)")));
1508 if (result.first == FileDialog::Later)
1512 filename.set(fromqstr(result.second));
1514 // check selected filename
1515 if (filename.empty()) {
1516 // emit message signal.
1517 message(_("Canceled."));
1521 bv->insertLyXFile(filename);
1525 void GuiView::insertPlaintextFile(docstring const & fname,
1528 BufferView * bv = view();
1533 FileName filename(to_utf8(fname));
1535 if (!filename.empty()) {
1536 bv->insertPlaintextFile(filename, asParagraph);
1540 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1541 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1543 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1546 if (result.first == FileDialog::Later)
1550 filename.set(fromqstr(result.second));
1552 // check selected filename
1553 if (filename.empty()) {
1554 // emit message signal.
1555 message(_("Canceled."));
1559 bv->insertPlaintextFile(filename, asParagraph);
1563 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1565 FileName fname = b.fileName();
1566 FileName const oldname = fname;
1568 if (!newname.empty()) {
1570 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1572 // Switch to this Buffer.
1575 /// No argument? Ask user through dialog.
1577 FileDialog dlg(qt_("Choose a filename to save document as"),
1578 LFUN_BUFFER_WRITE_AS);
1579 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1580 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1582 if (!isLyXFilename(fname.absFilename()))
1583 fname.changeExtension(".lyx");
1585 FileDialog::Result result =
1586 dlg.save(toqstr(fname.onlyPath().absFilename()),
1587 QStringList(qt_("LyX Documents (*.lyx)")),
1588 toqstr(fname.onlyFileName()));
1590 if (result.first == FileDialog::Later)
1593 fname.set(fromqstr(result.second));
1598 if (!isLyXFilename(fname.absFilename()))
1599 fname.changeExtension(".lyx");
1602 if (FileName(fname).exists()) {
1603 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1604 docstring text = bformat(_("The document %1$s already "
1605 "exists.\n\nDo you want to "
1606 "overwrite that document?"),
1608 int const ret = Alert::prompt(_("Overwrite document?"),
1609 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1612 case 1: return renameBuffer(b, docstring());
1613 case 2: return false;
1617 // Ok, change the name of the buffer
1618 b.setFileName(fname.absFilename());
1620 bool unnamed = b.isUnnamed();
1621 b.setUnnamed(false);
1622 b.saveCheckSum(fname);
1624 if (!saveBuffer(b)) {
1625 b.setFileName(oldname.absFilename());
1626 b.setUnnamed(unnamed);
1627 b.saveCheckSum(oldname);
1635 bool GuiView::saveBuffer(Buffer & b)
1638 return renameBuffer(b, docstring());
1641 LyX::ref().session().lastFiles().add(b.fileName());
1645 // Switch to this Buffer.
1648 // FIXME: we don't tell the user *WHY* the save failed !!
1649 docstring const file = makeDisplayPath(b.absFileName(), 30);
1650 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1651 "Do you want to rename the document and "
1652 "try again?"), file);
1653 int const ret = Alert::prompt(_("Rename and save?"),
1654 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1657 if (!renameBuffer(b, docstring()))
1666 return saveBuffer(b);
1670 bool GuiView::closeBuffer()
1672 Buffer * buf = buffer();
1673 return buf && closeBuffer(*buf);
1677 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1679 // goto bookmark to update bookmark pit.
1680 //FIXME: we should update only the bookmarks related to this buffer!
1681 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1682 theLyXFunc().gotoBookmark(i+1, false, false);
1684 if (buf.isClean() || buf.paragraphs().empty()) {
1685 if (buf.masterBuffer() == &buf && tolastopened)
1686 LyX::ref().session().lastOpened().add(buf.fileName());
1687 theBufferList().release(&buf);
1690 // Switch to this Buffer.
1695 if (buf.isUnnamed())
1696 file = from_utf8(buf.fileName().onlyFileName());
1698 file = buf.fileName().displayName(30);
1700 // Bring this window to top before asking questions.
1704 docstring const text = bformat(_("The document %1$s has unsaved changes."
1705 "\n\nDo you want to save the document or discard the changes?"), file);
1706 int const ret = Alert::prompt(_("Save changed document?"),
1707 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1711 if (!saveBuffer(buf))
1715 // if we crash after this we could
1716 // have no autosave file but I guess
1717 // this is really improbable (Jug)
1718 removeAutosaveFile(buf.absFileName());
1724 // save file names to .lyx/session
1725 // if master/slave are both open, do not save slave since it
1726 // will be automatically loaded when the master is loaded
1727 if (buf.masterBuffer() == &buf && tolastopened)
1728 LyX::ref().session().lastOpened().add(buf.fileName());
1730 theBufferList().release(&buf);
1735 bool GuiView::dispatch(FuncRequest const & cmd)
1737 BufferView * bv = view();
1738 // By default we won't need any update.
1740 bv->cursor().updateFlags(Update::None);
1741 bool dispatched = true;
1743 switch(cmd.action) {
1744 case LFUN_BUFFER_IMPORT:
1745 importDocument(to_utf8(cmd.argument()));
1748 case LFUN_BUFFER_SWITCH:
1749 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1752 case LFUN_BUFFER_NEXT:
1753 setBuffer(theBufferList().next(buffer()));
1756 case LFUN_BUFFER_PREVIOUS:
1757 setBuffer(theBufferList().previous(buffer()));
1760 case LFUN_COMMAND_EXECUTE: {
1761 bool const show_it = cmd.argument() != "off";
1762 // FIXME: this is a hack, "minibuffer" should not be
1764 if (GuiToolbar * t = toolbar("minibuffer")) {
1765 t->setVisible(show_it);
1766 if (show_it && t->commandBuffer())
1767 t->commandBuffer()->setFocus();
1771 case LFUN_DROP_LAYOUTS_CHOICE:
1773 d.layout_->showPopup();
1776 case LFUN_MENU_OPEN:
1777 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1778 menu->exec(QCursor::pos());
1781 case LFUN_FILE_INSERT:
1782 insertLyXFile(cmd.argument());
1784 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1785 insertPlaintextFile(cmd.argument(), true);
1788 case LFUN_FILE_INSERT_PLAINTEXT:
1789 insertPlaintextFile(cmd.argument(), false);
1792 case LFUN_BUFFER_WRITE:
1794 saveBuffer(bv->buffer());
1797 case LFUN_BUFFER_WRITE_AS:
1799 renameBuffer(bv->buffer(), cmd.argument());
1802 case LFUN_BUFFER_WRITE_ALL: {
1803 Buffer * first = theBufferList().first();
1806 message(_("Saving all documents..."));
1807 // We cannot use a for loop as the buffer list cycles.
1810 if (!b->isClean()) {
1812 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1814 b = theBufferList().next(b);
1815 } while (b != first);
1816 message(_("All documents saved."));
1820 case LFUN_TOOLBAR_TOGGLE: {
1821 string const name = cmd.getArg(0);
1822 if (GuiToolbar * t = toolbar(name))
1827 case LFUN_DIALOG_UPDATE: {
1828 string const name = to_utf8(cmd.argument());
1829 // Can only update a dialog connected to an existing inset
1830 Inset * inset = getOpenInset(name);
1832 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1833 inset->dispatch(view()->cursor(), fr);
1834 } else if (name == "paragraph") {
1835 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1836 } else if (name == "prefs") {
1837 updateDialog(name, string());
1842 case LFUN_DIALOG_TOGGLE: {
1843 if (isDialogVisible(cmd.getArg(0)))
1844 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1846 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1850 case LFUN_DIALOG_DISCONNECT_INSET:
1851 disconnectDialog(to_utf8(cmd.argument()));
1854 case LFUN_DIALOG_HIDE: {
1855 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1859 case LFUN_DIALOG_SHOW: {
1860 string const name = cmd.getArg(0);
1861 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1863 if (name == "character") {
1864 data = freefont2string();
1866 showDialog("character", data);
1867 } else if (name == "latexlog") {
1868 Buffer::LogType type;
1869 string const logfile = buffer()->logName(&type);
1871 case Buffer::latexlog:
1874 case Buffer::buildlog:
1878 data += Lexer::quoteString(logfile);
1879 showDialog("log", data);
1880 } else if (name == "vclog") {
1881 string const data = "vc " +
1882 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1883 showDialog("log", data);
1884 } else if (name == "symbols") {
1885 data = bv->cursor().getEncoding()->name();
1887 showDialog("symbols", data);
1889 showDialog(name, data);
1893 case LFUN_INSET_APPLY: {
1894 view()->cursor().recordUndoFullDocument();
1895 string const name = cmd.getArg(0);
1896 Inset * inset = getOpenInset(name);
1898 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1899 inset->dispatch(view()->cursor(), fr);
1901 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1907 case LFUN_UI_TOGGLE:
1909 // Make sure the keyboard focus stays in the work area.
1913 case LFUN_COMPLETION_INLINE:
1914 if (d.current_work_area_)
1915 d.current_work_area_->completer().showInline();
1918 case LFUN_SPLIT_VIEW:
1919 if (Buffer * buf = buffer()) {
1920 string const orientation = cmd.getArg(0);
1921 d.splitter_->setOrientation(orientation == "vertical"
1922 ? Qt::Vertical : Qt::Horizontal);
1923 TabWorkArea * twa = addTabWorkArea();
1924 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1925 setCurrentWorkArea(wa);
1929 case LFUN_CLOSE_TAB_GROUP:
1930 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1932 twa = d.currentTabWorkArea();
1933 // Switch to the next GuiWorkArea in the found TabWorkArea.
1934 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1935 if (d.splitter_->count() == 0)
1936 // No more work area, switch to the background widget.
1941 case LFUN_COMPLETION_POPUP:
1942 if (d.current_work_area_)
1943 d.current_work_area_->completer().showPopup();
1947 case LFUN_COMPLETION_COMPLETE:
1948 if (d.current_work_area_)
1949 d.current_work_area_->completer().tab();
1957 if (isFullScreen()) {
1958 if (menuBar()->isVisible())
1960 if (statusBar()->isVisible())
1961 statusBar()->hide();
1968 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1970 string const arg = cmd.getArg(0);
1971 if (arg == "scrollbar") {
1972 // hide() is of no help
1973 if (d.current_work_area_->verticalScrollBarPolicy() ==
1974 Qt::ScrollBarAlwaysOff)
1976 d.current_work_area_->setVerticalScrollBarPolicy(
1977 Qt::ScrollBarAsNeeded);
1979 d.current_work_area_->setVerticalScrollBarPolicy(
1980 Qt::ScrollBarAlwaysOff);
1983 if (arg == "statusbar") {
1984 statusBar()->setVisible(!statusBar()->isVisible());
1987 if (arg == "menubar") {
1988 menuBar()->setVisible(!menuBar()->isVisible());
1991 #if QT_VERSION >= 0x040300
1992 if (arg == "frame") {
1994 getContentsMargins(&l, &t, &r, &b);
1995 //are the frames in default state?
1996 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1998 setContentsMargins(-2, -2, -2, -2);
2000 setContentsMargins(0, 0, 0, 0);
2005 if (arg == "fullscreen") {
2010 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
2014 void GuiView::toggleFullScreen()
2016 if (isFullScreen()) {
2017 for (int i = 0; i != d.splitter_->count(); ++i)
2018 d.tabWorkArea(i)->setFullScreen(false);
2019 #if QT_VERSION >= 0x040300
2020 setContentsMargins(0, 0, 0, 0);
2022 setWindowState(windowState() ^ Qt::WindowFullScreen);
2025 statusBar()->show();
2027 for (int i = 0; i != d.splitter_->count(); ++i)
2028 d.tabWorkArea(i)->setFullScreen(true);
2029 #if QT_VERSION >= 0x040300
2030 setContentsMargins(-2, -2, -2, -2);
2033 setWindowState(windowState() ^ Qt::WindowFullScreen);
2034 statusBar()->hide();
2036 if (lyxrc.full_screen_toolbars) {
2037 ToolbarMap::iterator end = d.toolbars_.end();
2038 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
2045 Buffer const * GuiView::updateInset(Inset const * inset)
2047 if (!d.current_work_area_)
2051 d.current_work_area_->scheduleRedraw();
2053 return &d.current_work_area_->bufferView().buffer();
2057 void GuiView::restartCursor()
2059 /* When we move around, or type, it's nice to be able to see
2060 * the cursor immediately after the keypress.
2062 if (d.current_work_area_)
2063 d.current_work_area_->startBlinkingCursor();
2065 // Take this occasion to update the other GUI elements.
2070 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2072 if (d.current_work_area_)
2073 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2078 // This list should be kept in sync with the list of insets in
2079 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2080 // dialog should have the same name as the inset.
2082 char const * const dialognames[] = {
2083 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2084 "citation", "document", "errorlist", "ert", "external", "file",
2085 "findreplace", "float", "graphics", "include", "index", "info", "nomenclature", "label", "log",
2086 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2087 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2089 #ifdef HAVE_LIBAIKSAURUS
2093 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2095 char const * const * const end_dialognames =
2096 dialognames + (sizeof(dialognames) / sizeof(char *));
2100 cmpCStr(char const * name) : name_(name) {}
2101 bool operator()(char const * other) {
2102 return strcmp(other, name_) == 0;
2109 bool isValidName(string const & name)
2111 return find_if(dialognames, end_dialognames,
2112 cmpCStr(name.c_str())) != end_dialognames;
2118 void GuiView::resetDialogs()
2120 // Make sure that no LFUN uses any LyXView.
2121 theLyXFunc().setLyXView(0);
2122 // FIXME: the "math panels" toolbar takes an awful lot of time to
2123 // initialise so we don't do that for the time being.
2125 guiApp->menus().fillMenuBar(menuBar(), this);
2127 d.layout_->updateContents(true);
2128 // Now update controls with current buffer.
2129 theLyXFunc().setLyXView(this);
2134 Dialog * GuiView::find_or_build(string const & name)
2136 if (!isValidName(name))
2139 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2141 if (it != d.dialogs_.end())
2142 return it->second.get();
2144 Dialog * dialog = build(name);
2145 d.dialogs_[name].reset(dialog);
2146 if (lyxrc.allow_geometry_session)
2147 dialog->restoreSession();
2152 void GuiView::showDialog(string const & name, string const & data,
2159 Dialog * dialog = find_or_build(name);
2161 dialog->showData(data);
2163 d.open_insets_[name] = inset;
2169 bool GuiView::isDialogVisible(string const & name) const
2171 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2172 if (it == d.dialogs_.end())
2174 return it->second.get()->isVisibleView();
2178 void GuiView::hideDialog(string const & name, Inset * inset)
2180 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2181 if (it == d.dialogs_.end())
2184 if (inset && inset != getOpenInset(name))
2187 Dialog * const dialog = it->second.get();
2188 if (dialog->isVisibleView())
2190 d.open_insets_[name] = 0;
2194 void GuiView::disconnectDialog(string const & name)
2196 if (!isValidName(name))
2199 if (d.open_insets_.find(name) != d.open_insets_.end())
2200 d.open_insets_[name] = 0;
2204 Inset * GuiView::getOpenInset(string const & name) const
2206 if (!isValidName(name))
2209 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2210 return it == d.open_insets_.end() ? 0 : it->second;
2214 void GuiView::hideAll() const
2216 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2217 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2219 for(; it != end; ++it)
2220 it->second->hideView();
2224 void GuiView::updateDialogs()
2226 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2227 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2229 for(; it != end; ++it) {
2230 Dialog * dialog = it->second.get();
2231 if (dialog && dialog->isVisibleView())
2232 dialog->checkStatus();
2240 // will be replaced by a proper factory...
2241 Dialog * createGuiAbout(GuiView & lv);
2242 Dialog * createGuiBibitem(GuiView & lv);
2243 Dialog * createGuiBibtex(GuiView & lv);
2244 Dialog * createGuiBox(GuiView & lv);
2245 Dialog * createGuiBranch(GuiView & lv);
2246 Dialog * createGuiChanges(GuiView & lv);
2247 Dialog * createGuiCharacter(GuiView & lv);
2248 Dialog * createGuiCitation(GuiView & lv);
2249 Dialog * createGuiDelimiter(GuiView & lv);
2250 Dialog * createGuiDocument(GuiView & lv);
2251 Dialog * createGuiErrorList(GuiView & lv);
2252 Dialog * createGuiERT(GuiView & lv);
2253 Dialog * createGuiExternal(GuiView & lv);
2254 Dialog * createGuiFloat(GuiView & lv);
2255 Dialog * createGuiGraphics(GuiView & lv);
2256 Dialog * createGuiHSpace(GuiView & lv);
2257 Dialog * createGuiInclude(GuiView & lv);
2258 Dialog * createGuiInfo(GuiView & lv);
2259 Dialog * createGuiLabel(GuiView & lv);
2260 Dialog * createGuiListings(GuiView & lv);
2261 Dialog * createGuiLog(GuiView & lv);
2262 Dialog * createGuiMathMatrix(GuiView & lv);
2263 Dialog * createGuiNomenclature(GuiView & lv);
2264 Dialog * createGuiNote(GuiView & lv);
2265 Dialog * createGuiParagraph(GuiView & lv);
2266 Dialog * createGuiPreferences(GuiView & lv);
2267 Dialog * createGuiPrint(GuiView & lv);
2268 Dialog * createGuiRef(GuiView & lv);
2269 Dialog * createGuiSearch(GuiView & lv);
2270 Dialog * createGuiSendTo(GuiView & lv);
2271 Dialog * createGuiShowFile(GuiView & lv);
2272 Dialog * createGuiSpellchecker(GuiView & lv);
2273 Dialog * createGuiSymbols(GuiView & lv);
2274 Dialog * createGuiTabularCreate(GuiView & lv);
2275 Dialog * createGuiTabular(GuiView & lv);
2276 Dialog * createGuiTexInfo(GuiView & lv);
2277 Dialog * createGuiToc(GuiView & lv);
2278 Dialog * createGuiThesaurus(GuiView & lv);
2279 Dialog * createGuiHyperlink(GuiView & lv);
2280 Dialog * createGuiVSpace(GuiView & lv);
2281 Dialog * createGuiViewSource(GuiView & lv);
2282 Dialog * createGuiWrap(GuiView & lv);
2285 Dialog * GuiView::build(string const & name)
2287 LASSERT(isValidName(name), /**/);
2289 if (name == "aboutlyx")
2290 return createGuiAbout(*this);
2291 if (name == "bibitem")
2292 return createGuiBibitem(*this);
2293 if (name == "bibtex")
2294 return createGuiBibtex(*this);
2296 return createGuiBox(*this);
2297 if (name == "branch")
2298 return createGuiBranch(*this);
2299 if (name == "changes")
2300 return createGuiChanges(*this);
2301 if (name == "character")
2302 return createGuiCharacter(*this);
2303 if (name == "citation")
2304 return createGuiCitation(*this);
2305 if (name == "document")
2306 return createGuiDocument(*this);
2307 if (name == "errorlist")
2308 return createGuiErrorList(*this);
2310 return createGuiERT(*this);
2311 if (name == "external")
2312 return createGuiExternal(*this);
2314 return createGuiShowFile(*this);
2315 if (name == "findreplace")
2316 return createGuiSearch(*this);
2317 if (name == "float")
2318 return createGuiFloat(*this);
2319 if (name == "graphics")
2320 return createGuiGraphics(*this);
2321 if (name == "include")
2322 return createGuiInclude(*this);
2324 return createGuiInfo(*this);
2325 if (name == "nomenclature")
2326 return createGuiNomenclature(*this);
2327 if (name == "label")
2328 return createGuiLabel(*this);
2330 return createGuiLog(*this);
2331 if (name == "view-source")
2332 return createGuiViewSource(*this);
2333 if (name == "mathdelimiter")
2334 return createGuiDelimiter(*this);
2335 if (name == "mathmatrix")
2336 return createGuiMathMatrix(*this);
2338 return createGuiNote(*this);
2339 if (name == "paragraph")
2340 return createGuiParagraph(*this);
2341 if (name == "prefs")
2342 return createGuiPreferences(*this);
2343 if (name == "print")
2344 return createGuiPrint(*this);
2346 return createGuiRef(*this);
2347 if (name == "sendto")
2348 return createGuiSendTo(*this);
2349 if (name == "space")
2350 return createGuiHSpace(*this);
2351 if (name == "spellchecker")
2352 return createGuiSpellchecker(*this);
2353 if (name == "symbols")
2354 return createGuiSymbols(*this);
2355 if (name == "tabular")
2356 return createGuiTabular(*this);
2357 if (name == "tabularcreate")
2358 return createGuiTabularCreate(*this);
2359 if (name == "texinfo")
2360 return createGuiTexInfo(*this);
2361 #ifdef HAVE_LIBAIKSAURUS
2362 if (name == "thesaurus")
2363 return createGuiThesaurus(*this);
2366 return createGuiToc(*this);
2368 return createGuiHyperlink(*this);
2369 if (name == "vspace")
2370 return createGuiVSpace(*this);
2372 return createGuiWrap(*this);
2373 if (name == "listings")
2374 return createGuiListings(*this);
2380 } // namespace frontend
2383 #include "GuiView_moc.cpp"