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)
650 || ke->key() == Qt::Key_Alt)
651 return QMainWindow::event(e);
653 // Continue with even.
654 return QMainWindow::event(e);
657 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
658 if (d.current_work_area_)
659 // Nothing special to do.
660 return QMainWindow::event(e);
662 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
664 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
665 || ke->key() == Qt::Key_Backtab)
666 return QMainWindow::event(e);
668 // Allow processing of shortcuts that are allowed even when no Buffer
670 theLyXFunc().setLyXView(this);
672 setKeySymbol(&sym, ke);
673 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
679 return QMainWindow::event(e);
684 bool GuiView::focusNextPrevChild(bool /*next*/)
691 void GuiView::setBusy(bool busy)
693 if (d.current_work_area_) {
694 d.current_work_area_->setUpdatesEnabled(!busy);
696 d.current_work_area_->stopBlinkingCursor();
698 d.current_work_area_->startBlinkingCursor();
702 QApplication::setOverrideCursor(Qt::WaitCursor);
704 QApplication::restoreOverrideCursor();
708 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
710 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
712 if (tbinfo.flags & ToolbarInfo::TOP) {
714 addToolBarBreak(Qt::TopToolBarArea);
715 addToolBar(Qt::TopToolBarArea, toolBar);
718 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
719 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
720 #if (QT_VERSION >= 0x040202)
722 addToolBarBreak(Qt::BottomToolBarArea);
724 addToolBar(Qt::BottomToolBarArea, toolBar);
727 if (tbinfo.flags & ToolbarInfo::LEFT) {
728 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
729 #if (QT_VERSION >= 0x040202)
731 addToolBarBreak(Qt::LeftToolBarArea);
733 addToolBar(Qt::LeftToolBarArea, toolBar);
736 if (tbinfo.flags & ToolbarInfo::RIGHT) {
737 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
738 #if (QT_VERSION >= 0x040202)
740 addToolBarBreak(Qt::RightToolBarArea);
742 addToolBar(Qt::RightToolBarArea, toolBar);
745 // The following does not work so I cannot restore to exact toolbar location
747 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
748 toolBar->move(tbinfo.posx, tbinfo.posy);
755 GuiWorkArea * GuiView::workArea(Buffer & buffer)
757 if (TabWorkArea * twa = d.currentTabWorkArea())
758 return twa->workArea(buffer);
763 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
765 // Automatically create a TabWorkArea if there are none yet.
766 TabWorkArea * tab_widget = d.splitter_->count()
767 ? d.currentTabWorkArea() : addTabWorkArea();
768 return tab_widget->addWorkArea(buffer, *this);
772 TabWorkArea * GuiView::addTabWorkArea()
774 TabWorkArea * twa = new TabWorkArea;
775 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
776 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
777 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
778 this, SLOT(on_lastWorkAreaRemoved()));
780 d.splitter_->addWidget(twa);
781 d.stack_widget_->setCurrentWidget(d.splitter_);
786 GuiWorkArea const * GuiView::currentWorkArea() const
788 return d.current_work_area_;
792 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
795 d.current_work_area_ = wa;
796 for (int i = 0; i != d.splitter_->count(); ++i) {
797 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
803 void GuiView::removeWorkArea(GuiWorkArea * wa)
806 if (wa == d.current_work_area_) {
808 disconnectBufferView();
809 d.current_work_area_ = 0;
812 for (int i = 0; i != d.splitter_->count(); ++i) {
813 TabWorkArea * twa = d.tabWorkArea(i);
814 if (!twa->removeWorkArea(wa))
815 // Not found in this tab group.
818 // We found and removed the GuiWorkArea.
820 // No more WorkAreas in this tab group, so delete it.
825 if (d.current_work_area_)
826 // This means that we are not closing the current GuiWorkArea;
829 // Switch to the next GuiWorkArea in the found TabWorkArea.
830 d.current_work_area_ = twa->currentWorkArea();
834 if (d.splitter_->count() == 0)
835 // No more work area, switch to the background widget.
840 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
846 void GuiView::updateLayoutList()
849 d.layout_->updateContents(false);
853 void GuiView::updateToolbars()
855 if (d.current_work_area_) {
857 d.current_work_area_->bufferView().cursor().inMathed();
859 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
861 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
862 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
863 bool const mathmacrotemplate =
864 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
866 d.toolbars_->update(math, table, review, mathmacrotemplate);
868 d.toolbars_->update(false, false, false, false);
872 Buffer * GuiView::buffer()
874 if (d.current_work_area_)
875 return &d.current_work_area_->bufferView().buffer();
880 Buffer const * GuiView::buffer() const
882 if (d.current_work_area_)
883 return &d.current_work_area_->bufferView().buffer();
888 void GuiView::setBuffer(Buffer * newBuffer)
890 LASSERT(newBuffer, /**/);
893 GuiWorkArea * wa = workArea(*newBuffer);
895 updateLabels(*newBuffer->masterBuffer());
896 wa = addWorkArea(*newBuffer);
898 //Disconnect the old buffer...there's no new one.
901 connectBuffer(*newBuffer);
902 connectBufferView(wa->bufferView());
903 setCurrentWorkArea(wa);
909 void GuiView::connectBuffer(Buffer & buf)
911 buf.setGuiDelegate(this);
915 void GuiView::disconnectBuffer()
917 if (d.current_work_area_)
918 d.current_work_area_->bufferView().setGuiDelegate(0);
922 void GuiView::connectBufferView(BufferView & bv)
924 bv.setGuiDelegate(this);
928 void GuiView::disconnectBufferView()
930 if (d.current_work_area_)
931 d.current_work_area_->bufferView().setGuiDelegate(0);
935 void GuiView::errors(string const & error_type)
937 ErrorList & el = buffer()->errorList(error_type);
939 showDialog("errorlist", error_type);
943 void GuiView::structureChanged()
945 d.toc_models_.reset(view());
946 // Navigator needs more than a simple update in this case. It needs to be
948 updateDialog("toc", "");
952 void GuiView::updateDialog(string const & name, string const & data)
954 if (!isDialogVisible(name))
957 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
958 if (it == d.dialogs_.end())
961 Dialog * const dialog = it->second.get();
962 if (dialog->isVisibleView())
963 dialog->initialiseParams(data);
967 BufferView * GuiView::view()
969 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
973 void GuiView::autoSave()
975 LYXERR(Debug::INFO, "Running autoSave()");
978 view()->buffer().autoSave();
982 void GuiView::resetAutosaveTimers()
985 d.autosave_timeout_.restart();
989 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
993 Buffer * buf = buffer();
995 /* In LyX/Mac, when a dialog is open, the menus of the
996 application can still be accessed without giving focus to
997 the main window. In this case, we want to disable the menu
998 entries that are buffer-related.
1000 Note that this code is not perfect, as bug 1941 attests:
1001 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1003 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1006 switch(cmd.action) {
1007 case LFUN_BUFFER_WRITE:
1008 enable = buf && (buf->isUnnamed() || !buf->isClean());
1011 case LFUN_BUFFER_WRITE_AS:
1015 case LFUN_SPLIT_VIEW:
1019 case LFUN_CLOSE_TAB_GROUP:
1020 enable = d.currentTabWorkArea();
1023 case LFUN_TOOLBAR_TOGGLE:
1024 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1027 case LFUN_UI_TOGGLE:
1028 flag.setOnOff(isFullScreen());
1031 case LFUN_DIALOG_TOGGLE:
1032 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1033 // fall through to set "enable"
1034 case LFUN_DIALOG_SHOW: {
1035 string const name = cmd.getArg(0);
1037 enable = name == "aboutlyx"
1038 || name == "file" //FIXME: should be removed.
1040 || name == "texinfo";
1041 else if (name == "print")
1042 enable = buf->isExportable("dvi")
1043 && lyxrc.print_command != "none";
1044 else if (name == "character") {
1048 InsetCode ic = view()->cursor().inset().lyxCode();
1049 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1052 else if (name == "symbols") {
1053 if (!view() || view()->cursor().inMathed())
1056 InsetCode ic = view()->cursor().inset().lyxCode();
1057 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1060 else if (name == "latexlog")
1061 enable = FileName(buf->logName()).isReadableFile();
1062 else if (name == "spellchecker")
1063 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1064 enable = !buf->isReadonly();
1068 else if (name == "vclog")
1069 enable = buf->lyxvc().inUse();
1073 case LFUN_DIALOG_UPDATE: {
1074 string const name = cmd.getArg(0);
1076 enable = name == "prefs";
1080 case LFUN_INSET_APPLY: {
1085 string const name = cmd.getArg(0);
1086 Inset * inset = getOpenInset(name);
1088 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1090 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1091 // Every inset is supposed to handle this
1092 LASSERT(false, /**/);
1096 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1097 flag |= getStatus(fr);
1099 enable = flag.enabled();
1103 case LFUN_COMPLETION_INLINE:
1104 if (!d.current_work_area_
1105 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1109 case LFUN_COMPLETION_POPUP:
1110 if (!d.current_work_area_
1111 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1115 case LFUN_COMPLETION_COMPLETE:
1116 if (!d.current_work_area_
1117 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1129 flag.enabled(false);
1135 static FileName selectTemplateFile()
1137 FileDialog dlg(qt_("Select template file"));
1138 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1139 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1141 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1142 QStringList(qt_("LyX Documents (*.lyx)")));
1144 if (result.first == FileDialog::Later)
1146 if (result.second.isEmpty())
1148 return FileName(fromqstr(result.second));
1152 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1156 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1159 message(_("Document not loaded."));
1164 setBuffer(newBuffer);
1166 // scroll to the position when the file was last closed
1167 if (lyxrc.use_lastfilepos) {
1168 LastFilePosSection::FilePos filepos =
1169 LyX::ref().session().lastFilePos().load(filename);
1170 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1174 LyX::ref().session().lastFiles().add(filename);
1181 void GuiView::openDocument(string const & fname)
1183 string initpath = lyxrc.document_path;
1186 string const trypath = buffer()->filePath();
1187 // If directory is writeable, use this as default.
1188 if (FileName(trypath).isDirWritable())
1194 if (fname.empty()) {
1195 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1196 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1197 dlg.setButton2(qt_("Examples|#E#e"),
1198 toqstr(addPath(package().system_support().absFilename(), "examples")));
1200 FileDialog::Result result =
1201 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1203 if (result.first == FileDialog::Later)
1206 filename = fromqstr(result.second);
1208 // check selected filename
1209 if (filename.empty()) {
1210 message(_("Canceled."));
1216 // get absolute path of file and add ".lyx" to the filename if
1218 FileName const fullname =
1219 fileSearch(string(), filename, "lyx", support::may_not_exist);
1220 if (!fullname.empty())
1221 filename = fullname.absFilename();
1223 // if the file doesn't exist, let the user create one
1224 if (!fullname.exists()) {
1225 // the user specifically chose this name. Believe him.
1226 Buffer * const b = newFile(filename, string(), true);
1232 docstring const disp_fn = makeDisplayPath(filename);
1233 message(bformat(_("Opening document %1$s..."), disp_fn));
1236 Buffer * buf = loadDocument(fullname);
1241 buf->errors("Parse");
1242 str2 = bformat(_("Document %1$s opened."), disp_fn);
1244 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1249 // FIXME: clean that
1250 static bool import(GuiView * lv, FileName const & filename,
1251 string const & format, ErrorList & errorList)
1253 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1255 string loader_format;
1256 vector<string> loaders = theConverters().loaders();
1257 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1258 for (vector<string>::const_iterator it = loaders.begin();
1259 it != loaders.end(); ++it) {
1260 if (!theConverters().isReachable(format, *it))
1263 string const tofile =
1264 support::changeExtension(filename.absFilename(),
1265 formats.extension(*it));
1266 if (!theConverters().convert(0, filename, FileName(tofile),
1267 filename, format, *it, errorList))
1269 loader_format = *it;
1272 if (loader_format.empty()) {
1273 frontend::Alert::error(_("Couldn't import file"),
1274 bformat(_("No information for importing the format %1$s."),
1275 formats.prettyName(format)));
1279 loader_format = format;
1281 if (loader_format == "lyx") {
1282 Buffer * buf = lv->loadDocument(lyxfile);
1287 buf->errors("Parse");
1289 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1293 bool as_paragraphs = loader_format == "textparagraph";
1294 string filename2 = (loader_format == format) ? filename.absFilename()
1295 : support::changeExtension(filename.absFilename(),
1296 formats.extension(loader_format));
1297 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1298 theLyXFunc().setLyXView(lv);
1299 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1306 void GuiView::importDocument(string const & argument)
1309 string filename = split(argument, format, ' ');
1311 LYXERR(Debug::INFO, format << " file: " << filename);
1313 // need user interaction
1314 if (filename.empty()) {
1315 string initpath = lyxrc.document_path;
1317 Buffer const * buf = buffer();
1319 string const trypath = buf->filePath();
1320 // If directory is writeable, use this as default.
1321 if (FileName(trypath).isDirWritable())
1325 docstring const text = bformat(_("Select %1$s file to import"),
1326 formats.prettyName(format));
1328 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1329 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1330 dlg.setButton2(qt_("Examples|#E#e"),
1331 toqstr(addPath(package().system_support().absFilename(), "examples")));
1333 docstring filter = formats.prettyName(format);
1336 filter += from_utf8(formats.extension(format));
1339 FileDialog::Result result =
1340 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1342 if (result.first == FileDialog::Later)
1345 filename = fromqstr(result.second);
1347 // check selected filename
1348 if (filename.empty())
1349 message(_("Canceled."));
1352 if (filename.empty())
1355 // get absolute path of file
1356 FileName const fullname(support::makeAbsPath(filename));
1358 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1360 // Check if the document already is open
1361 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1364 if (!closeBuffer()) {
1365 message(_("Canceled."));
1370 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1372 // if the file exists already, and we didn't do
1373 // -i lyx thefile.lyx, warn
1374 if (lyxfile.exists() && fullname != lyxfile) {
1376 docstring text = bformat(_("The document %1$s already exists.\n\n"
1377 "Do you want to overwrite that document?"), displaypath);
1378 int const ret = Alert::prompt(_("Overwrite document?"),
1379 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1382 message(_("Canceled."));
1387 message(bformat(_("Importing %1$s..."), displaypath));
1388 ErrorList errorList;
1389 if (import(this, fullname, format, errorList))
1390 message(_("imported."));
1392 message(_("file not imported!"));
1394 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1398 void GuiView::newDocument(string const & filename, bool from_template)
1400 FileName initpath(lyxrc.document_path);
1401 Buffer * buf = buffer();
1403 FileName const trypath(buf->filePath());
1404 // If directory is writeable, use this as default.
1405 if (trypath.isDirWritable())
1409 string templatefile = from_template ?
1410 selectTemplateFile().absFilename() : string();
1412 if (filename.empty())
1413 b = newUnnamedFile(templatefile, initpath);
1415 b = newFile(filename, templatefile, true);
1419 // Ensure the cursor is correctly positionned on screen.
1420 view()->showCursor();
1424 void GuiView::insertLyXFile(docstring const & fname)
1426 BufferView * bv = view();
1431 FileName filename(to_utf8(fname));
1433 if (!filename.empty()) {
1434 bv->insertLyXFile(filename);
1438 // Launch a file browser
1440 string initpath = lyxrc.document_path;
1441 string const trypath = bv->buffer().filePath();
1442 // If directory is writeable, use this as default.
1443 if (FileName(trypath).isDirWritable())
1447 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1448 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1449 dlg.setButton2(qt_("Examples|#E#e"),
1450 toqstr(addPath(package().system_support().absFilename(),
1453 FileDialog::Result result = dlg.open(toqstr(initpath),
1454 QStringList(qt_("LyX Documents (*.lyx)")));
1456 if (result.first == FileDialog::Later)
1460 filename.set(fromqstr(result.second));
1462 // check selected filename
1463 if (filename.empty()) {
1464 // emit message signal.
1465 message(_("Canceled."));
1469 bv->insertLyXFile(filename);
1473 void GuiView::insertPlaintextFile(docstring const & fname,
1476 BufferView * bv = view();
1481 FileName filename(to_utf8(fname));
1483 if (!filename.empty()) {
1484 bv->insertPlaintextFile(filename, asParagraph);
1488 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1489 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1491 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1494 if (result.first == FileDialog::Later)
1498 filename.set(fromqstr(result.second));
1500 // check selected filename
1501 if (filename.empty()) {
1502 // emit message signal.
1503 message(_("Canceled."));
1507 bv->insertPlaintextFile(filename, asParagraph);
1511 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1513 FileName fname = b.fileName();
1514 FileName const oldname = fname;
1516 if (!newname.empty()) {
1518 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1520 // Switch to this Buffer.
1523 /// No argument? Ask user through dialog.
1525 FileDialog dlg(qt_("Choose a filename to save document as"),
1526 LFUN_BUFFER_WRITE_AS);
1527 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1528 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1530 if (!isLyXFilename(fname.absFilename()))
1531 fname.changeExtension(".lyx");
1533 FileDialog::Result result =
1534 dlg.save(toqstr(fname.onlyPath().absFilename()),
1535 QStringList(qt_("LyX Documents (*.lyx)")),
1536 toqstr(fname.onlyFileName()));
1538 if (result.first == FileDialog::Later)
1541 fname.set(fromqstr(result.second));
1546 if (!isLyXFilename(fname.absFilename()))
1547 fname.changeExtension(".lyx");
1550 if (FileName(fname).exists()) {
1551 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1552 docstring text = bformat(_("The document %1$s already "
1553 "exists.\n\nDo you want to "
1554 "overwrite that document?"),
1556 int const ret = Alert::prompt(_("Overwrite document?"),
1557 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1560 case 1: return renameBuffer(b, docstring());
1561 case 2: return false;
1565 // Ok, change the name of the buffer
1566 b.setFileName(fname.absFilename());
1568 bool unnamed = b.isUnnamed();
1569 b.setUnnamed(false);
1570 b.saveCheckSum(fname);
1572 if (!saveBuffer(b)) {
1573 b.setFileName(oldname.absFilename());
1574 b.setUnnamed(unnamed);
1575 b.saveCheckSum(oldname);
1583 bool GuiView::saveBuffer(Buffer & b)
1586 return renameBuffer(b, docstring());
1589 LyX::ref().session().lastFiles().add(b.fileName());
1593 // Switch to this Buffer.
1596 // FIXME: we don't tell the user *WHY* the save failed !!
1597 docstring const file = makeDisplayPath(b.absFileName(), 30);
1598 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1599 "Do you want to rename the document and "
1600 "try again?"), file);
1601 int const ret = Alert::prompt(_("Rename and save?"),
1602 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1605 if (!renameBuffer(b, docstring()))
1614 return saveBuffer(b);
1618 bool GuiView::closeBuffer()
1620 Buffer * buf = buffer();
1621 return buf && closeBuffer(*buf);
1625 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1627 // goto bookmark to update bookmark pit.
1628 //FIXME: we should update only the bookmarks related to this buffer!
1629 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1630 theLyXFunc().gotoBookmark(i+1, false, false);
1632 if (buf.isClean() || buf.paragraphs().empty()) {
1633 if (buf.masterBuffer() == &buf && tolastopened)
1634 LyX::ref().session().lastOpened().add(buf.fileName());
1635 theBufferList().release(&buf);
1638 // Switch to this Buffer.
1643 if (buf.isUnnamed())
1644 file = from_utf8(buf.fileName().onlyFileName());
1646 file = buf.fileName().displayName(30);
1648 // Bring this window to top before asking questions.
1652 docstring const text = bformat(_("The document %1$s has unsaved changes."
1653 "\n\nDo you want to save the document or discard the changes?"), file);
1654 int const ret = Alert::prompt(_("Save changed document?"),
1655 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1659 if (!saveBuffer(buf))
1663 // if we crash after this we could
1664 // have no autosave file but I guess
1665 // this is really improbable (Jug)
1666 removeAutosaveFile(buf.absFileName());
1672 // save file names to .lyx/session
1673 // if master/slave are both open, do not save slave since it
1674 // will be automatically loaded when the master is loaded
1675 if (buf.masterBuffer() == &buf && tolastopened)
1676 LyX::ref().session().lastOpened().add(buf.fileName());
1678 theBufferList().release(&buf);
1683 bool GuiView::dispatch(FuncRequest const & cmd)
1685 BufferView * bv = view();
1686 // By default we won't need any update.
1688 bv->cursor().updateFlags(Update::None);
1689 bool dispatched = true;
1691 switch(cmd.action) {
1692 case LFUN_BUFFER_IMPORT:
1693 importDocument(to_utf8(cmd.argument()));
1696 case LFUN_BUFFER_SWITCH:
1697 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1700 case LFUN_BUFFER_NEXT:
1701 setBuffer(theBufferList().next(buffer()));
1704 case LFUN_BUFFER_PREVIOUS:
1705 setBuffer(theBufferList().previous(buffer()));
1708 case LFUN_COMMAND_EXECUTE: {
1709 bool const show_it = cmd.argument() != "off";
1710 d.toolbars_->showCommandBuffer(show_it);
1713 case LFUN_DROP_LAYOUTS_CHOICE:
1715 d.layout_->showPopup();
1718 case LFUN_MENU_OPEN:
1719 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1720 menu->exec(QCursor::pos());
1723 case LFUN_FILE_INSERT:
1724 insertLyXFile(cmd.argument());
1726 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1727 insertPlaintextFile(cmd.argument(), true);
1730 case LFUN_FILE_INSERT_PLAINTEXT:
1731 insertPlaintextFile(cmd.argument(), false);
1734 case LFUN_BUFFER_WRITE:
1736 saveBuffer(bv->buffer());
1739 case LFUN_BUFFER_WRITE_AS:
1741 renameBuffer(bv->buffer(), cmd.argument());
1744 case LFUN_BUFFER_WRITE_ALL: {
1745 Buffer * first = theBufferList().first();
1748 message(_("Saving all documents..."));
1749 // We cannot use a for loop as the buffer list cycles.
1752 if (!b->isClean()) {
1754 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1756 b = theBufferList().next(b);
1757 } while (b != first);
1758 message(_("All documents saved."));
1762 case LFUN_TOOLBAR_TOGGLE: {
1763 string const name = cmd.getArg(0);
1764 bool const allowauto = cmd.getArg(1) == "allowauto";
1765 // it is possible to get current toolbar status like this,...
1766 // but I decide to obey the order of ToolbarBackend::flags
1767 // and disregard real toolbar status.
1768 // toolbars_->saveToolbarInfo();
1770 // toggle state on/off/auto
1771 d.toolbars_->toggleToolbarState(name, allowauto);
1775 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1777 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1781 if (tbi->flags & ToolbarInfo::ON)
1783 else if (tbi->flags & ToolbarInfo::OFF)
1785 else if (tbi->flags & ToolbarInfo::AUTO)
1788 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1789 _(tbi->gui_name), state));
1793 case LFUN_DIALOG_UPDATE: {
1794 string const name = to_utf8(cmd.argument());
1795 // Can only update a dialog connected to an existing inset
1796 Inset * inset = getOpenInset(name);
1798 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1799 inset->dispatch(view()->cursor(), fr);
1800 } else if (name == "paragraph") {
1801 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1802 } else if (name == "prefs") {
1803 updateDialog(name, string());
1808 case LFUN_DIALOG_TOGGLE: {
1809 if (isDialogVisible(cmd.getArg(0)))
1810 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1812 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1816 case LFUN_DIALOG_DISCONNECT_INSET:
1817 disconnectDialog(to_utf8(cmd.argument()));
1820 case LFUN_DIALOG_HIDE: {
1821 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1825 case LFUN_DIALOG_SHOW: {
1826 string const name = cmd.getArg(0);
1827 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1829 if (name == "character") {
1830 data = freefont2string();
1832 showDialog("character", data);
1833 } else if (name == "latexlog") {
1834 Buffer::LogType type;
1835 string const logfile = buffer()->logName(&type);
1837 case Buffer::latexlog:
1840 case Buffer::buildlog:
1844 data += Lexer::quoteString(logfile);
1845 showDialog("log", data);
1846 } else if (name == "vclog") {
1847 string const data = "vc " +
1848 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1849 showDialog("log", data);
1850 } else if (name == "symbols") {
1851 data = bv->cursor().getEncoding()->name();
1853 showDialog("symbols", data);
1855 showDialog(name, data);
1859 case LFUN_INSET_APPLY: {
1860 view()->cursor().recordUndoFullDocument();
1861 string const name = cmd.getArg(0);
1862 Inset * inset = getOpenInset(name);
1864 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1865 inset->dispatch(view()->cursor(), fr);
1867 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1873 case LFUN_UI_TOGGLE:
1875 // Make sure the keyboard focus stays in the work area.
1879 case LFUN_COMPLETION_INLINE:
1880 if (d.current_work_area_)
1881 d.current_work_area_->completer().showInline();
1884 case LFUN_SPLIT_VIEW:
1885 if (Buffer * buf = buffer()) {
1886 string const orientation = cmd.getArg(0);
1887 d.splitter_->setOrientation(orientation == "vertical"
1888 ? Qt::Vertical : Qt::Horizontal);
1889 TabWorkArea * twa = addTabWorkArea();
1890 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1891 setCurrentWorkArea(wa);
1895 case LFUN_CLOSE_TAB_GROUP:
1896 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1898 twa = d.currentTabWorkArea();
1899 // Switch to the next GuiWorkArea in the found TabWorkArea.
1900 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1901 if (d.splitter_->count() == 0)
1902 // No more work area, switch to the background widget.
1907 case LFUN_COMPLETION_POPUP:
1908 if (d.current_work_area_)
1909 d.current_work_area_->completer().showPopup();
1913 case LFUN_COMPLETION_COMPLETE:
1914 if (d.current_work_area_)
1915 d.current_work_area_->completer().tab();
1923 if (isFullScreen()) {
1924 if (menuBar()->isVisible())
1926 if (statusBar()->isVisible())
1927 statusBar()->hide();
1934 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1936 string const arg = cmd.getArg(0);
1937 if (arg == "scrollbar") {
1938 // hide() is of no help
1939 if (d.current_work_area_->verticalScrollBarPolicy() ==
1940 Qt::ScrollBarAlwaysOff)
1942 d.current_work_area_->setVerticalScrollBarPolicy(
1943 Qt::ScrollBarAsNeeded);
1945 d.current_work_area_->setVerticalScrollBarPolicy(
1946 Qt::ScrollBarAlwaysOff);
1949 if (arg == "statusbar") {
1950 statusBar()->setVisible(!statusBar()->isVisible());
1953 if (arg == "menubar") {
1954 menuBar()->setVisible(!menuBar()->isVisible());
1957 #if QT_VERSION >= 0x040300
1958 if (arg == "frame") {
1960 getContentsMargins(&l, &t, &r, &b);
1961 //are the frames in default state?
1962 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1964 setContentsMargins(-2, -2, -2, -2);
1966 setContentsMargins(0, 0, 0, 0);
1971 if (arg != "fullscreen") {
1972 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1976 if (lyxrc.full_screen_toolbars)
1977 d.toolbars_->toggleFullScreen(!isFullScreen());
1979 if (isFullScreen()) {
1980 for (int i = 0; i != d.splitter_->count(); ++i)
1981 d.tabWorkArea(i)->setFullScreen(false);
1982 #if QT_VERSION >= 0x040300
1983 setContentsMargins(0, 0, 0, 0);
1985 setWindowState(windowState() ^ Qt::WindowFullScreen);
1987 statusBar()->show();
1989 for (int i = 0; i != d.splitter_->count(); ++i)
1990 d.tabWorkArea(i)->setFullScreen(true);
1991 #if QT_VERSION >= 0x040300
1992 setContentsMargins(-2, -2, -2, -2);
1994 setWindowState(windowState() ^ Qt::WindowFullScreen);
1995 statusBar()->hide();
2001 Buffer const * GuiView::updateInset(Inset const * inset)
2003 if (!d.current_work_area_)
2007 d.current_work_area_->scheduleRedraw();
2009 return &d.current_work_area_->bufferView().buffer();
2013 void GuiView::restartCursor()
2015 /* When we move around, or type, it's nice to be able to see
2016 * the cursor immediately after the keypress.
2018 if (d.current_work_area_)
2019 d.current_work_area_->startBlinkingCursor();
2021 // Take this occasion to update the other GUI elements.
2026 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2028 if (d.current_work_area_)
2029 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2034 // This list should be kept in sync with the list of insets in
2035 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2036 // dialog should have the same name as the inset.
2038 char const * const dialognames[] = {
2039 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2040 "citation", "document", "errorlist", "ert", "external", "file",
2041 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2042 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2043 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2045 #ifdef HAVE_LIBAIKSAURUS
2049 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2051 char const * const * const end_dialognames =
2052 dialognames + (sizeof(dialognames) / sizeof(char *));
2056 cmpCStr(char const * name) : name_(name) {}
2057 bool operator()(char const * other) {
2058 return strcmp(other, name_) == 0;
2065 bool isValidName(string const & name)
2067 return find_if(dialognames, end_dialognames,
2068 cmpCStr(name.c_str())) != end_dialognames;
2074 void GuiView::resetDialogs()
2076 // Make sure that no LFUN uses any LyXView.
2077 theLyXFunc().setLyXView(0);
2078 // FIXME: the "math panels" toolbar takes an awful lot of time to
2079 // initialise so we don't do that for the time being.
2080 //d.toolbars_->init();
2081 guiApp->menus().fillMenuBar(menuBar(), this);
2083 d.layout_->updateContents(true);
2084 // Now update controls with current buffer.
2085 theLyXFunc().setLyXView(this);
2090 Dialog * GuiView::find_or_build(string const & name)
2092 if (!isValidName(name))
2095 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2097 if (it != d.dialogs_.end())
2098 return it->second.get();
2100 Dialog * dialog = build(name);
2101 d.dialogs_[name].reset(dialog);
2102 if (lyxrc.allow_geometry_session)
2103 dialog->restoreSession();
2108 void GuiView::showDialog(string const & name, string const & data,
2115 Dialog * dialog = find_or_build(name);
2117 dialog->showData(data);
2119 d.open_insets_[name] = inset;
2125 bool GuiView::isDialogVisible(string const & name) const
2127 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2128 if (it == d.dialogs_.end())
2130 return it->second.get()->isVisibleView();
2134 void GuiView::hideDialog(string const & name, Inset * inset)
2136 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2137 if (it == d.dialogs_.end())
2140 if (inset && inset != getOpenInset(name))
2143 Dialog * const dialog = it->second.get();
2144 if (dialog->isVisibleView())
2146 d.open_insets_[name] = 0;
2150 void GuiView::disconnectDialog(string const & name)
2152 if (!isValidName(name))
2155 if (d.open_insets_.find(name) != d.open_insets_.end())
2156 d.open_insets_[name] = 0;
2160 Inset * GuiView::getOpenInset(string const & name) const
2162 if (!isValidName(name))
2165 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2166 return it == d.open_insets_.end() ? 0 : it->second;
2170 void GuiView::hideAll() const
2172 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2173 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2175 for(; it != end; ++it)
2176 it->second->hideView();
2180 void GuiView::updateDialogs()
2182 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2183 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2185 for(; it != end; ++it) {
2186 Dialog * dialog = it->second.get();
2187 if (dialog && dialog->isVisibleView())
2188 dialog->checkStatus();
2196 // will be replaced by a proper factory...
2197 Dialog * createGuiAbout(GuiView & lv);
2198 Dialog * createGuiBibitem(GuiView & lv);
2199 Dialog * createGuiBibtex(GuiView & lv);
2200 Dialog * createGuiBox(GuiView & lv);
2201 Dialog * createGuiBranch(GuiView & lv);
2202 Dialog * createGuiChanges(GuiView & lv);
2203 Dialog * createGuiCharacter(GuiView & lv);
2204 Dialog * createGuiCitation(GuiView & lv);
2205 Dialog * createGuiDelimiter(GuiView & lv);
2206 Dialog * createGuiDocument(GuiView & lv);
2207 Dialog * createGuiErrorList(GuiView & lv);
2208 Dialog * createGuiERT(GuiView & lv);
2209 Dialog * createGuiExternal(GuiView & lv);
2210 Dialog * createGuiFloat(GuiView & lv);
2211 Dialog * createGuiGraphics(GuiView & lv);
2212 Dialog * createGuiHSpace(GuiView & lv);
2213 Dialog * createGuiInclude(GuiView & lv);
2214 Dialog * createGuiLabel(GuiView & lv);
2215 Dialog * createGuiListings(GuiView & lv);
2216 Dialog * createGuiLog(GuiView & lv);
2217 Dialog * createGuiMathMatrix(GuiView & lv);
2218 Dialog * createGuiNomenclature(GuiView & lv);
2219 Dialog * createGuiNote(GuiView & lv);
2220 Dialog * createGuiParagraph(GuiView & lv);
2221 Dialog * createGuiPreferences(GuiView & lv);
2222 Dialog * createGuiPrint(GuiView & lv);
2223 Dialog * createGuiRef(GuiView & lv);
2224 Dialog * createGuiSearch(GuiView & lv);
2225 Dialog * createGuiSendTo(GuiView & lv);
2226 Dialog * createGuiShowFile(GuiView & lv);
2227 Dialog * createGuiSpellchecker(GuiView & lv);
2228 Dialog * createGuiSymbols(GuiView & lv);
2229 Dialog * createGuiTabularCreate(GuiView & lv);
2230 Dialog * createGuiTabular(GuiView & lv);
2231 Dialog * createGuiTexInfo(GuiView & lv);
2232 Dialog * createGuiToc(GuiView & lv);
2233 Dialog * createGuiThesaurus(GuiView & lv);
2234 Dialog * createGuiHyperlink(GuiView & lv);
2235 Dialog * createGuiVSpace(GuiView & lv);
2236 Dialog * createGuiViewSource(GuiView & lv);
2237 Dialog * createGuiWrap(GuiView & lv);
2240 Dialog * GuiView::build(string const & name)
2242 LASSERT(isValidName(name), /**/);
2244 if (name == "aboutlyx")
2245 return createGuiAbout(*this);
2246 if (name == "bibitem")
2247 return createGuiBibitem(*this);
2248 if (name == "bibtex")
2249 return createGuiBibtex(*this);
2251 return createGuiBox(*this);
2252 if (name == "branch")
2253 return createGuiBranch(*this);
2254 if (name == "changes")
2255 return createGuiChanges(*this);
2256 if (name == "character")
2257 return createGuiCharacter(*this);
2258 if (name == "citation")
2259 return createGuiCitation(*this);
2260 if (name == "document")
2261 return createGuiDocument(*this);
2262 if (name == "errorlist")
2263 return createGuiErrorList(*this);
2265 return createGuiERT(*this);
2266 if (name == "external")
2267 return createGuiExternal(*this);
2269 return createGuiShowFile(*this);
2270 if (name == "findreplace")
2271 return createGuiSearch(*this);
2272 if (name == "float")
2273 return createGuiFloat(*this);
2274 if (name == "graphics")
2275 return createGuiGraphics(*this);
2276 if (name == "include")
2277 return createGuiInclude(*this);
2278 if (name == "nomenclature")
2279 return createGuiNomenclature(*this);
2280 if (name == "label")
2281 return createGuiLabel(*this);
2283 return createGuiLog(*this);
2284 if (name == "view-source")
2285 return createGuiViewSource(*this);
2286 if (name == "mathdelimiter")
2287 return createGuiDelimiter(*this);
2288 if (name == "mathmatrix")
2289 return createGuiMathMatrix(*this);
2291 return createGuiNote(*this);
2292 if (name == "paragraph")
2293 return createGuiParagraph(*this);
2294 if (name == "prefs")
2295 return createGuiPreferences(*this);
2296 if (name == "print")
2297 return createGuiPrint(*this);
2299 return createGuiRef(*this);
2300 if (name == "sendto")
2301 return createGuiSendTo(*this);
2302 if (name == "space")
2303 return createGuiHSpace(*this);
2304 if (name == "spellchecker")
2305 return createGuiSpellchecker(*this);
2306 if (name == "symbols")
2307 return createGuiSymbols(*this);
2308 if (name == "tabular")
2309 return createGuiTabular(*this);
2310 if (name == "tabularcreate")
2311 return createGuiTabularCreate(*this);
2312 if (name == "texinfo")
2313 return createGuiTexInfo(*this);
2314 #ifdef HAVE_LIBAIKSAURUS
2315 if (name == "thesaurus")
2316 return createGuiThesaurus(*this);
2319 return createGuiToc(*this);
2321 return createGuiHyperlink(*this);
2322 if (name == "vspace")
2323 return createGuiVSpace(*this);
2325 return createGuiWrap(*this);
2326 if (name == "listings")
2327 return createGuiListings(*this);
2333 } // namespace frontend
2336 #include "GuiView_moc.cpp"