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());
349 TocModels & GuiView::tocModels()
351 return d.toc_models_;
355 void GuiView::setFocus()
357 if (d.current_work_area_)
358 d.current_work_area_->setFocus();
364 QMenu * GuiView::createPopupMenu()
366 return d.toolBarPopup(this);
370 void GuiView::showEvent(QShowEvent * e)
372 LYXERR(Debug::GUI, "Passed Geometry "
373 << size().height() << "x" << size().width()
374 << "+" << pos().x() << "+" << pos().y());
376 if (d.splitter_->count() == 0)
377 // No work area, switch to the background widget.
380 QMainWindow::showEvent(e);
384 void GuiView::closeEvent(QCloseEvent * close_event)
386 // it can happen that this event arrives without selecting the view,
387 // e.g. when clicking the close button on a background window.
388 theLyXFunc().setLyXView(this);
390 while (Buffer * b = buffer()) {
392 // This is a child document, just close the tab after saving
393 // but keep the file loaded.
394 if (!saveBuffer(*b)) {
395 close_event->ignore();
398 removeWorkArea(d.current_work_area_);
402 QList<int> const ids = guiApp->viewIds();
403 for (int i = 0; i != ids.size(); ++i) {
406 if (guiApp->view(ids[i]).workArea(*b)) {
407 // FIXME 1: should we put an alert box here that the buffer
408 // is viewed elsewhere?
409 // FIXME 2: should we try to save this buffer in any case?
412 // This buffer is also opened in another view, so
413 // but close the associated work area nevertheless.
414 removeWorkArea(d.current_work_area_);
415 // but don't close it.
420 if (b && !closeBuffer(*b, true)) {
421 close_event->ignore();
426 // Make sure that nothing will use this close to be closed View.
427 guiApp->unregisterView(this);
429 // Save toolbars configuration
430 if (isFullScreen()) {
431 d.toolbars_->toggleFullScreen(!isFullScreen());
435 // Make sure the timer time out will not trigger a statusbar update.
436 d.statusbar_timer_.stop();
438 // Saving fullscreen requires additional tweaks in the toolbar code.
439 // It wouldn't also work under linux natively.
440 if (lyxrc.allow_geometry_session && !isFullScreen()) {
442 QString const key = "view-" + QString::number(id_);
444 settings.setValue(key + "/pos", pos());
445 settings.setValue(key + "/size", size());
447 settings.setValue(key + "/geometry", saveGeometry());
449 settings.setValue(key + "/icon_size", iconSize());
450 d.toolbars_->saveToolbarInfo();
451 // Now take care of all other dialogs:
452 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
453 for (; it!= d.dialogs_.end(); ++it)
454 it->second->saveSession();
457 close_event->accept();
461 void GuiView::dragEnterEvent(QDragEnterEvent * event)
463 if (event->mimeData()->hasUrls())
465 /// \todo Ask lyx-devel is this is enough:
466 /// if (event->mimeData()->hasFormat("text/plain"))
467 /// event->acceptProposedAction();
471 void GuiView::dropEvent(QDropEvent* event)
473 QList<QUrl> files = event->mimeData()->urls();
477 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
478 for (int i = 0; i != files.size(); ++i) {
479 string const file = os::internal_path(fromqstr(
480 files.at(i).toLocalFile()));
482 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
487 void GuiView::message(docstring const & str)
489 if (ForkedProcess::iAmAChild())
492 statusBar()->showMessage(toqstr(str));
493 d.statusbar_timer_.stop();
494 d.statusbar_timer_.start(3000);
498 void GuiView::smallSizedIcons()
500 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
504 void GuiView::normalSizedIcons()
506 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
510 void GuiView::bigSizedIcons()
512 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
516 void GuiView::clearMessage()
520 theLyXFunc().setLyXView(this);
521 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
522 d.statusbar_timer_.stop();
526 void GuiView::updateWindowTitle(GuiWorkArea * wa)
528 if (wa != d.current_work_area_)
530 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
531 setWindowIconText(wa->windowIconText());
535 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
538 disconnectBufferView();
539 connectBufferView(wa->bufferView());
540 connectBuffer(wa->bufferView().buffer());
541 d.current_work_area_ = wa;
542 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
543 this, SLOT(updateWindowTitle(GuiWorkArea *)));
544 updateWindowTitle(wa);
548 // The document settings needs to be reinitialised.
549 updateDialog("document", "");
551 // Buffer-dependent dialogs must be updated. This is done here because
552 // some dialogs require buffer()->text.
557 void GuiView::on_lastWorkAreaRemoved()
560 // On Mac close the view if there is no Tab open anymore,
561 // but only if no splitter is visible
562 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
563 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
564 if (twa && twa->count() == 0) {
565 // close the view, as no tab is open anymore
566 QTimer::singleShot(0, this, SLOT(close()));
571 // The document settings needs to be reinitialised.
572 updateDialog("document", "");
578 void GuiView::updateStatusBar()
580 // let the user see the explicit message
581 if (d.statusbar_timer_.isActive())
584 theLyXFunc().setLyXView(this);
585 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
589 bool GuiView::hasFocus() const
591 return qApp->activeWindow() == this;
595 bool GuiView::event(QEvent * e)
599 // Useful debug code:
600 //case QEvent::ActivationChange:
601 //case QEvent::WindowDeactivate:
602 //case QEvent::Paint:
603 //case QEvent::Enter:
604 //case QEvent::Leave:
605 //case QEvent::HoverEnter:
606 //case QEvent::HoverLeave:
607 //case QEvent::HoverMove:
608 //case QEvent::StatusTip:
609 //case QEvent::DragEnter:
610 //case QEvent::DragLeave:
614 case QEvent::WindowActivate: {
615 if (this == guiApp->currentView()) {
617 return QMainWindow::event(e);
619 guiApp->setCurrentView(this);
620 if (d.current_work_area_) {
621 BufferView & bv = d.current_work_area_->bufferView();
622 connectBufferView(bv);
623 connectBuffer(bv.buffer());
624 // The document structure, name and dialogs might have
625 // changed in another view.
627 // The document settings needs to be reinitialised.
628 updateDialog("document", "");
631 setWindowTitle(qt_("LyX"));
632 setWindowIconText(qt_("LyX"));
635 return QMainWindow::event(e);
638 case QEvent::ShortcutOverride: {
640 if (isFullScreen() && menuBar()->isHidden()) {
641 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
642 // FIXME: we should also try to detect special LyX shortcut such as
643 // Alt-P and Alt-M. Right now there is a hack in
644 // GuiWorkArea::processKeySym() that hides again the menubar for
646 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt)
648 return QMainWindow::event(e);
651 if (d.current_work_area_)
652 // Nothing special to do.
653 return QMainWindow::event(e);
655 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
656 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
658 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
659 || ke->key() == Qt::Key_Backtab)
660 return QMainWindow::event(e);
662 // Allow processing of shortcuts that are allowed even when no Buffer
664 theLyXFunc().setLyXView(this);
666 setKeySymbol(&sym, ke);
667 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
673 return QMainWindow::event(e);
678 bool GuiView::focusNextPrevChild(bool /*next*/)
685 void GuiView::setBusy(bool busy)
687 if (d.current_work_area_) {
688 d.current_work_area_->setUpdatesEnabled(!busy);
690 d.current_work_area_->stopBlinkingCursor();
692 d.current_work_area_->startBlinkingCursor();
696 QApplication::setOverrideCursor(Qt::WaitCursor);
698 QApplication::restoreOverrideCursor();
702 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
704 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
706 if (tbinfo.flags & ToolbarInfo::TOP) {
708 addToolBarBreak(Qt::TopToolBarArea);
709 addToolBar(Qt::TopToolBarArea, toolBar);
712 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
713 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
714 #if (QT_VERSION >= 0x040202)
716 addToolBarBreak(Qt::BottomToolBarArea);
718 addToolBar(Qt::BottomToolBarArea, toolBar);
721 if (tbinfo.flags & ToolbarInfo::LEFT) {
722 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
723 #if (QT_VERSION >= 0x040202)
725 addToolBarBreak(Qt::LeftToolBarArea);
727 addToolBar(Qt::LeftToolBarArea, toolBar);
730 if (tbinfo.flags & ToolbarInfo::RIGHT) {
731 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
732 #if (QT_VERSION >= 0x040202)
734 addToolBarBreak(Qt::RightToolBarArea);
736 addToolBar(Qt::RightToolBarArea, toolBar);
739 // The following does not work so I cannot restore to exact toolbar location
741 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
742 toolBar->move(tbinfo.posx, tbinfo.posy);
749 GuiWorkArea * GuiView::workArea(Buffer & buffer)
751 if (TabWorkArea * twa = d.currentTabWorkArea())
752 return twa->workArea(buffer);
757 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
759 // Automatically create a TabWorkArea if there are none yet.
760 TabWorkArea * tab_widget = d.splitter_->count()
761 ? d.currentTabWorkArea() : addTabWorkArea();
762 return tab_widget->addWorkArea(buffer, *this);
766 TabWorkArea * GuiView::addTabWorkArea()
768 TabWorkArea * twa = new TabWorkArea;
769 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
770 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
771 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
772 this, SLOT(on_lastWorkAreaRemoved()));
774 d.splitter_->addWidget(twa);
775 d.stack_widget_->setCurrentWidget(d.splitter_);
780 GuiWorkArea const * GuiView::currentWorkArea() const
782 return d.current_work_area_;
786 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
789 d.current_work_area_ = wa;
790 for (int i = 0; i != d.splitter_->count(); ++i) {
791 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
797 void GuiView::removeWorkArea(GuiWorkArea * wa)
800 if (wa == d.current_work_area_) {
802 disconnectBufferView();
803 d.current_work_area_ = 0;
806 for (int i = 0; i != d.splitter_->count(); ++i) {
807 TabWorkArea * twa = d.tabWorkArea(i);
808 if (!twa->removeWorkArea(wa))
809 // Not found in this tab group.
812 // We found and removed the GuiWorkArea.
814 // No more WorkAreas in this tab group, so delete it.
819 if (d.current_work_area_)
820 // This means that we are not closing the current GuiWorkArea;
823 // Switch to the next GuiWorkArea in the found TabWorkArea.
824 d.current_work_area_ = twa->currentWorkArea();
828 if (d.splitter_->count() == 0)
829 // No more work area, switch to the background widget.
834 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
840 void GuiView::updateLayoutList()
843 d.layout_->updateContents(false);
847 void GuiView::updateToolbars()
849 if (d.current_work_area_) {
851 d.current_work_area_->bufferView().cursor().inMathed();
853 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
855 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
856 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
857 bool const mathmacrotemplate =
858 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
860 d.toolbars_->update(math, table, review, mathmacrotemplate);
862 d.toolbars_->update(false, false, false, false);
866 Buffer * GuiView::buffer()
868 if (d.current_work_area_)
869 return &d.current_work_area_->bufferView().buffer();
874 Buffer const * GuiView::buffer() const
876 if (d.current_work_area_)
877 return &d.current_work_area_->bufferView().buffer();
882 void GuiView::setBuffer(Buffer * newBuffer)
884 LASSERT(newBuffer, /**/);
887 GuiWorkArea * wa = workArea(*newBuffer);
889 updateLabels(*newBuffer->masterBuffer());
890 wa = addWorkArea(*newBuffer);
892 //Disconnect the old buffer...there's no new one.
895 connectBuffer(*newBuffer);
896 connectBufferView(wa->bufferView());
897 setCurrentWorkArea(wa);
903 void GuiView::connectBuffer(Buffer & buf)
905 buf.setGuiDelegate(this);
909 void GuiView::disconnectBuffer()
911 if (d.current_work_area_)
912 d.current_work_area_->bufferView().setGuiDelegate(0);
916 void GuiView::connectBufferView(BufferView & bv)
918 bv.setGuiDelegate(this);
922 void GuiView::disconnectBufferView()
924 if (d.current_work_area_)
925 d.current_work_area_->bufferView().setGuiDelegate(0);
929 void GuiView::errors(string const & error_type)
931 ErrorList & el = buffer()->errorList(error_type);
933 showDialog("errorlist", error_type);
937 void GuiView::structureChanged()
939 d.toc_models_.reset(view());
940 // Navigator needs more than a simple update in this case. It needs to be
942 updateDialog("toc", "");
946 void GuiView::updateDialog(string const & name, string const & data)
948 if (!isDialogVisible(name))
951 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
952 if (it == d.dialogs_.end())
955 Dialog * const dialog = it->second.get();
956 if (dialog->isVisibleView())
957 dialog->initialiseParams(data);
961 BufferView * GuiView::view()
963 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
967 void GuiView::autoSave()
969 LYXERR(Debug::INFO, "Running autoSave()");
972 view()->buffer().autoSave();
976 void GuiView::resetAutosaveTimers()
979 d.autosave_timeout_.restart();
983 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
986 Buffer * buf = buffer();
988 /* In LyX/Mac, when a dialog is open, the menus of the
989 application can still be accessed without giving focus to
990 the main window. In this case, we want to disable the menu
991 entries that are buffer-related.
993 Note that this code is not perfect, as bug 1941 attests:
994 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
996 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1000 case LFUN_BUFFER_WRITE:
1001 enable = buf && (buf->isUnnamed() || !buf->isClean());
1004 case LFUN_BUFFER_WRITE_AS:
1008 case LFUN_SPLIT_VIEW:
1012 case LFUN_CLOSE_TAB_GROUP:
1013 enable = d.currentTabWorkArea();
1016 case LFUN_TOOLBAR_TOGGLE:
1017 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1020 case LFUN_UI_TOGGLE:
1021 flag.setOnOff(isFullScreen());
1024 case LFUN_DIALOG_TOGGLE:
1025 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1026 // fall through to set "enable"
1027 case LFUN_DIALOG_SHOW: {
1028 string const name = cmd.getArg(0);
1030 enable = name == "aboutlyx"
1031 || name == "file" //FIXME: should be removed.
1033 || name == "texinfo";
1034 else if (name == "print")
1035 enable = buf->isExportable("dvi")
1036 && lyxrc.print_command != "none";
1037 else if (name == "character") {
1041 InsetCode ic = view()->cursor().inset().lyxCode();
1042 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1045 else if (name == "symbols") {
1046 if (!view() || view()->cursor().inMathed())
1049 InsetCode ic = view()->cursor().inset().lyxCode();
1050 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1053 else if (name == "latexlog")
1054 enable = FileName(buf->logName()).isReadableFile();
1055 else if (name == "spellchecker")
1056 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1057 enable = !buf->isReadonly();
1061 else if (name == "vclog")
1062 enable = buf->lyxvc().inUse();
1066 case LFUN_DIALOG_UPDATE: {
1067 string const name = cmd.getArg(0);
1069 enable = name == "prefs";
1073 case LFUN_INSET_APPLY: {
1074 string const name = cmd.getArg(0);
1075 Inset * inset = getOpenInset(name);
1077 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1079 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1080 // Every inset is supposed to handle this
1081 LASSERT(false, /**/);
1085 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1086 flag |= lyx::getStatus(fr);
1088 enable = flag.enabled();
1092 case LFUN_COMPLETION_INLINE:
1093 if (!d.current_work_area_
1094 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1098 case LFUN_COMPLETION_POPUP:
1099 if (!d.current_work_area_
1100 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1104 case LFUN_COMPLETION_COMPLETE:
1105 if (!d.current_work_area_
1106 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1115 flag.enabled(false);
1121 static FileName selectTemplateFile()
1123 FileDialog dlg(qt_("Select template file"));
1124 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1125 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1127 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1128 QStringList(qt_("LyX Documents (*.lyx)")));
1130 if (result.first == FileDialog::Later)
1132 if (result.second.isEmpty())
1134 return FileName(fromqstr(result.second));
1138 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1142 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1145 message(_("Document not loaded."));
1150 setBuffer(newBuffer);
1152 // scroll to the position when the file was last closed
1153 if (lyxrc.use_lastfilepos) {
1154 LastFilePosSection::FilePos filepos =
1155 LyX::ref().session().lastFilePos().load(filename);
1156 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1160 LyX::ref().session().lastFiles().add(filename);
1167 void GuiView::openDocument(string const & fname)
1169 string initpath = lyxrc.document_path;
1172 string const trypath = buffer()->filePath();
1173 // If directory is writeable, use this as default.
1174 if (FileName(trypath).isDirWritable())
1180 if (fname.empty()) {
1181 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1182 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1183 dlg.setButton2(qt_("Examples|#E#e"),
1184 toqstr(addPath(package().system_support().absFilename(), "examples")));
1186 FileDialog::Result result =
1187 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1189 if (result.first == FileDialog::Later)
1192 filename = fromqstr(result.second);
1194 // check selected filename
1195 if (filename.empty()) {
1196 message(_("Canceled."));
1202 // get absolute path of file and add ".lyx" to the filename if
1204 FileName const fullname =
1205 fileSearch(string(), filename, "lyx", support::may_not_exist);
1206 if (!fullname.empty())
1207 filename = fullname.absFilename();
1209 // if the file doesn't exist, let the user create one
1210 if (!fullname.exists()) {
1211 // the user specifically chose this name. Believe him.
1212 Buffer * const b = newFile(filename, string(), true);
1218 docstring const disp_fn = makeDisplayPath(filename);
1219 message(bformat(_("Opening document %1$s..."), disp_fn));
1222 Buffer * buf = loadDocument(fullname);
1227 buf->errors("Parse");
1228 str2 = bformat(_("Document %1$s opened."), disp_fn);
1230 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1235 // FIXME: clean that
1236 static bool import(GuiView * lv, FileName const & filename,
1237 string const & format, ErrorList & errorList)
1239 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1241 string loader_format;
1242 vector<string> loaders = theConverters().loaders();
1243 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1244 for (vector<string>::const_iterator it = loaders.begin();
1245 it != loaders.end(); ++it) {
1246 if (!theConverters().isReachable(format, *it))
1249 string const tofile =
1250 support::changeExtension(filename.absFilename(),
1251 formats.extension(*it));
1252 if (!theConverters().convert(0, filename, FileName(tofile),
1253 filename, format, *it, errorList))
1255 loader_format = *it;
1258 if (loader_format.empty()) {
1259 frontend::Alert::error(_("Couldn't import file"),
1260 bformat(_("No information for importing the format %1$s."),
1261 formats.prettyName(format)));
1265 loader_format = format;
1267 if (loader_format == "lyx") {
1268 Buffer * buf = lv->loadDocument(lyxfile);
1273 buf->errors("Parse");
1275 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1279 bool as_paragraphs = loader_format == "textparagraph";
1280 string filename2 = (loader_format == format) ? filename.absFilename()
1281 : support::changeExtension(filename.absFilename(),
1282 formats.extension(loader_format));
1283 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1284 theLyXFunc().setLyXView(lv);
1285 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1292 void GuiView::importDocument(string const & argument)
1295 string filename = split(argument, format, ' ');
1297 LYXERR(Debug::INFO, format << " file: " << filename);
1299 // need user interaction
1300 if (filename.empty()) {
1301 string initpath = lyxrc.document_path;
1303 Buffer const * buf = buffer();
1305 string const trypath = buf->filePath();
1306 // If directory is writeable, use this as default.
1307 if (FileName(trypath).isDirWritable())
1311 docstring const text = bformat(_("Select %1$s file to import"),
1312 formats.prettyName(format));
1314 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1315 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1316 dlg.setButton2(qt_("Examples|#E#e"),
1317 toqstr(addPath(package().system_support().absFilename(), "examples")));
1319 docstring filter = formats.prettyName(format);
1322 filter += from_utf8(formats.extension(format));
1325 FileDialog::Result result =
1326 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1328 if (result.first == FileDialog::Later)
1331 filename = fromqstr(result.second);
1333 // check selected filename
1334 if (filename.empty())
1335 message(_("Canceled."));
1338 if (filename.empty())
1341 // get absolute path of file
1342 FileName const fullname(support::makeAbsPath(filename));
1344 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1346 // Check if the document already is open
1347 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1350 if (!closeBuffer()) {
1351 message(_("Canceled."));
1356 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1358 // if the file exists already, and we didn't do
1359 // -i lyx thefile.lyx, warn
1360 if (lyxfile.exists() && fullname != lyxfile) {
1362 docstring text = bformat(_("The document %1$s already exists.\n\n"
1363 "Do you want to overwrite that document?"), displaypath);
1364 int const ret = Alert::prompt(_("Overwrite document?"),
1365 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1368 message(_("Canceled."));
1373 message(bformat(_("Importing %1$s..."), displaypath));
1374 ErrorList errorList;
1375 if (import(this, fullname, format, errorList))
1376 message(_("imported."));
1378 message(_("file not imported!"));
1380 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1384 void GuiView::newDocument(string const & filename, bool from_template)
1386 FileName initpath(lyxrc.document_path);
1387 Buffer * buf = buffer();
1389 FileName const trypath(buf->filePath());
1390 // If directory is writeable, use this as default.
1391 if (trypath.isDirWritable())
1395 string templatefile = from_template ?
1396 selectTemplateFile().absFilename() : string();
1398 if (filename.empty())
1399 b = newUnnamedFile(templatefile, initpath);
1401 b = newFile(filename, templatefile, true);
1405 // Ensure the cursor is correctly positionned on screen.
1406 view()->showCursor();
1410 void GuiView::insertLyXFile(docstring const & fname)
1412 BufferView * bv = view();
1417 FileName filename(to_utf8(fname));
1419 if (!filename.empty()) {
1420 bv->insertLyXFile(filename);
1424 // Launch a file browser
1426 string initpath = lyxrc.document_path;
1427 string const trypath = bv->buffer().filePath();
1428 // If directory is writeable, use this as default.
1429 if (FileName(trypath).isDirWritable())
1433 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1434 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1435 dlg.setButton2(qt_("Examples|#E#e"),
1436 toqstr(addPath(package().system_support().absFilename(),
1439 FileDialog::Result result = dlg.open(toqstr(initpath),
1440 QStringList(qt_("LyX Documents (*.lyx)")));
1442 if (result.first == FileDialog::Later)
1446 filename.set(fromqstr(result.second));
1448 // check selected filename
1449 if (filename.empty()) {
1450 // emit message signal.
1451 message(_("Canceled."));
1455 bv->insertLyXFile(filename);
1459 void GuiView::insertPlaintextFile(docstring const & fname,
1462 BufferView * bv = view();
1467 FileName filename(to_utf8(fname));
1469 if (!filename.empty()) {
1470 bv->insertPlaintextFile(filename, asParagraph);
1474 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1475 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1477 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1480 if (result.first == FileDialog::Later)
1484 filename.set(fromqstr(result.second));
1486 // check selected filename
1487 if (filename.empty()) {
1488 // emit message signal.
1489 message(_("Canceled."));
1493 bv->insertPlaintextFile(filename, asParagraph);
1497 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1499 FileName fname = b.fileName();
1500 FileName const oldname = fname;
1502 if (!newname.empty()) {
1504 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1506 // Switch to this Buffer.
1509 /// No argument? Ask user through dialog.
1511 FileDialog dlg(qt_("Choose a filename to save document as"),
1512 LFUN_BUFFER_WRITE_AS);
1513 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1514 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1516 if (!isLyXFilename(fname.absFilename()))
1517 fname.changeExtension(".lyx");
1519 FileDialog::Result result =
1520 dlg.save(toqstr(fname.onlyPath().absFilename()),
1521 QStringList(qt_("LyX Documents (*.lyx)")),
1522 toqstr(fname.onlyFileName()));
1524 if (result.first == FileDialog::Later)
1527 fname.set(fromqstr(result.second));
1532 if (!isLyXFilename(fname.absFilename()))
1533 fname.changeExtension(".lyx");
1536 if (FileName(fname).exists()) {
1537 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1538 docstring text = bformat(_("The document %1$s already "
1539 "exists.\n\nDo you want to "
1540 "overwrite that document?"),
1542 int const ret = Alert::prompt(_("Overwrite document?"),
1543 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1546 case 1: return renameBuffer(b, docstring());
1547 case 2: return false;
1551 // Ok, change the name of the buffer
1552 b.setFileName(fname.absFilename());
1554 bool unnamed = b.isUnnamed();
1555 b.setUnnamed(false);
1556 b.saveCheckSum(fname);
1558 if (!saveBuffer(b)) {
1559 b.setFileName(oldname.absFilename());
1560 b.setUnnamed(unnamed);
1561 b.saveCheckSum(oldname);
1569 bool GuiView::saveBuffer(Buffer & b)
1572 return renameBuffer(b, docstring());
1575 LyX::ref().session().lastFiles().add(b.fileName());
1579 // Switch to this Buffer.
1582 // FIXME: we don't tell the user *WHY* the save failed !!
1583 docstring const file = makeDisplayPath(b.absFileName(), 30);
1584 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1585 "Do you want to rename the document and "
1586 "try again?"), file);
1587 int const ret = Alert::prompt(_("Rename and save?"),
1588 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1591 if (!renameBuffer(b, docstring()))
1600 return saveBuffer(b);
1604 bool GuiView::closeBuffer()
1606 Buffer * buf = buffer();
1607 return buf && closeBuffer(*buf);
1611 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1613 // goto bookmark to update bookmark pit.
1614 //FIXME: we should update only the bookmarks related to this buffer!
1615 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1616 theLyXFunc().gotoBookmark(i+1, false, false);
1618 if (buf.isClean() || buf.paragraphs().empty()) {
1619 if (buf.masterBuffer() == &buf && tolastopened)
1620 LyX::ref().session().lastOpened().add(buf.fileName());
1621 theBufferList().release(&buf);
1624 // Switch to this Buffer.
1629 if (buf.isUnnamed())
1630 file = from_utf8(buf.fileName().onlyFileName());
1632 file = buf.fileName().displayName(30);
1634 // Bring this window to top before asking questions.
1638 docstring const text = bformat(_("The document %1$s has unsaved changes."
1639 "\n\nDo you want to save the document or discard the changes?"), file);
1640 int const ret = Alert::prompt(_("Save changed document?"),
1641 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1645 if (!saveBuffer(buf))
1649 // if we crash after this we could
1650 // have no autosave file but I guess
1651 // this is really improbable (Jug)
1652 removeAutosaveFile(buf.absFileName());
1658 // save file names to .lyx/session
1659 // if master/slave are both open, do not save slave since it
1660 // will be automatically loaded when the master is loaded
1661 if (buf.masterBuffer() == &buf && tolastopened)
1662 LyX::ref().session().lastOpened().add(buf.fileName());
1664 theBufferList().release(&buf);
1669 bool GuiView::dispatch(FuncRequest const & cmd)
1671 BufferView * bv = view();
1672 // By default we won't need any update.
1674 bv->cursor().updateFlags(Update::None);
1675 bool dispatched = true;
1677 switch(cmd.action) {
1678 case LFUN_BUFFER_IMPORT:
1679 importDocument(to_utf8(cmd.argument()));
1682 case LFUN_BUFFER_SWITCH:
1683 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1686 case LFUN_BUFFER_NEXT:
1687 setBuffer(theBufferList().next(buffer()));
1690 case LFUN_BUFFER_PREVIOUS:
1691 setBuffer(theBufferList().previous(buffer()));
1694 case LFUN_COMMAND_EXECUTE: {
1695 bool const show_it = cmd.argument() != "off";
1696 d.toolbars_->showCommandBuffer(show_it);
1699 case LFUN_DROP_LAYOUTS_CHOICE:
1701 d.layout_->showPopup();
1704 case LFUN_MENU_OPEN:
1705 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1706 menu->exec(QCursor::pos());
1709 case LFUN_FILE_INSERT:
1710 insertLyXFile(cmd.argument());
1712 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1713 insertPlaintextFile(cmd.argument(), true);
1716 case LFUN_FILE_INSERT_PLAINTEXT:
1717 insertPlaintextFile(cmd.argument(), false);
1720 case LFUN_BUFFER_WRITE:
1722 saveBuffer(bv->buffer());
1725 case LFUN_BUFFER_WRITE_AS:
1727 renameBuffer(bv->buffer(), cmd.argument());
1730 case LFUN_BUFFER_WRITE_ALL: {
1731 Buffer * first = theBufferList().first();
1734 message(_("Saving all documents..."));
1735 // We cannot use a for loop as the buffer list cycles.
1738 if (!b->isClean()) {
1740 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1742 b = theBufferList().next(b);
1743 } while (b != first);
1744 message(_("All documents saved."));
1748 case LFUN_TOOLBAR_TOGGLE: {
1749 string const name = cmd.getArg(0);
1750 bool const allowauto = cmd.getArg(1) == "allowauto";
1751 // it is possible to get current toolbar status like this,...
1752 // but I decide to obey the order of ToolbarBackend::flags
1753 // and disregard real toolbar status.
1754 // toolbars_->saveToolbarInfo();
1756 // toggle state on/off/auto
1757 d.toolbars_->toggleToolbarState(name, allowauto);
1761 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1763 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1767 if (tbi->flags & ToolbarInfo::ON)
1769 else if (tbi->flags & ToolbarInfo::OFF)
1771 else if (tbi->flags & ToolbarInfo::AUTO)
1774 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1775 _(tbi->gui_name), state));
1779 case LFUN_DIALOG_UPDATE: {
1780 string const name = to_utf8(cmd.argument());
1781 // Can only update a dialog connected to an existing inset
1782 Inset * inset = getOpenInset(name);
1784 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1785 inset->dispatch(view()->cursor(), fr);
1786 } else if (name == "paragraph") {
1787 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1788 } else if (name == "prefs") {
1789 updateDialog(name, string());
1794 case LFUN_DIALOG_TOGGLE: {
1795 if (isDialogVisible(cmd.getArg(0)))
1796 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1798 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1802 case LFUN_DIALOG_DISCONNECT_INSET:
1803 disconnectDialog(to_utf8(cmd.argument()));
1806 case LFUN_DIALOG_HIDE: {
1807 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1811 case LFUN_DIALOG_SHOW: {
1812 string const name = cmd.getArg(0);
1813 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1815 if (name == "character") {
1816 data = freefont2string();
1818 showDialog("character", data);
1819 } else if (name == "latexlog") {
1820 Buffer::LogType type;
1821 string const logfile = buffer()->logName(&type);
1823 case Buffer::latexlog:
1826 case Buffer::buildlog:
1830 data += Lexer::quoteString(logfile);
1831 showDialog("log", data);
1832 } else if (name == "vclog") {
1833 string const data = "vc " +
1834 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1835 showDialog("log", data);
1836 } else if (name == "symbols") {
1837 data = bv->cursor().getEncoding()->name();
1839 showDialog("symbols", data);
1841 showDialog(name, data);
1845 case LFUN_INSET_APPLY: {
1846 view()->cursor().recordUndoFullDocument();
1847 string const name = cmd.getArg(0);
1848 Inset * inset = getOpenInset(name);
1850 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1851 inset->dispatch(view()->cursor(), fr);
1853 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1859 case LFUN_UI_TOGGLE:
1861 // Make sure the keyboard focus stays in the work area.
1865 case LFUN_COMPLETION_INLINE:
1866 if (d.current_work_area_)
1867 d.current_work_area_->completer().showInline();
1870 case LFUN_SPLIT_VIEW:
1871 if (Buffer * buf = buffer()) {
1872 string const orientation = cmd.getArg(0);
1873 d.splitter_->setOrientation(orientation == "vertical"
1874 ? Qt::Vertical : Qt::Horizontal);
1875 TabWorkArea * twa = addTabWorkArea();
1876 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1877 setCurrentWorkArea(wa);
1881 case LFUN_CLOSE_TAB_GROUP:
1882 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1884 twa = d.currentTabWorkArea();
1885 // Switch to the next GuiWorkArea in the found TabWorkArea.
1886 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1887 if (d.splitter_->count() == 0)
1888 // No more work area, switch to the background widget.
1893 case LFUN_COMPLETION_POPUP:
1894 if (d.current_work_area_)
1895 d.current_work_area_->completer().showPopup();
1899 case LFUN_COMPLETION_COMPLETE:
1900 if (d.current_work_area_)
1901 d.current_work_area_->completer().tab();
1909 if (isFullScreen()) {
1910 if (menuBar()->isVisible())
1912 if (statusBar()->isVisible())
1913 statusBar()->hide();
1920 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1922 string const arg = cmd.getArg(0);
1923 if (arg == "scrollbar") {
1924 // hide() is of no help
1925 if (d.current_work_area_->verticalScrollBarPolicy() ==
1926 Qt::ScrollBarAlwaysOff)
1928 d.current_work_area_->setVerticalScrollBarPolicy(
1929 Qt::ScrollBarAsNeeded);
1931 d.current_work_area_->setVerticalScrollBarPolicy(
1932 Qt::ScrollBarAlwaysOff);
1935 if (arg == "statusbar") {
1936 statusBar()->setVisible(!statusBar()->isVisible());
1939 if (arg == "menubar") {
1940 menuBar()->setVisible(!menuBar()->isVisible());
1943 #if QT_VERSION >= 0x040300
1944 if (arg == "frame") {
1946 getContentsMargins(&l, &t, &r, &b);
1947 //are the frames in default state?
1948 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1950 setContentsMargins(-2, -2, -2, -2);
1952 setContentsMargins(0, 0, 0, 0);
1957 if (arg != "fullscreen") {
1958 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1962 if (lyxrc.full_screen_toolbars)
1963 d.toolbars_->toggleFullScreen(!isFullScreen());
1965 if (isFullScreen()) {
1966 for (int i = 0; i != d.splitter_->count(); ++i)
1967 d.tabWorkArea(i)->setFullScreen(false);
1968 #if QT_VERSION >= 0x040300
1969 setContentsMargins(0, 0, 0, 0);
1971 setWindowState(windowState() ^ Qt::WindowFullScreen);
1973 statusBar()->show();
1975 for (int i = 0; i != d.splitter_->count(); ++i)
1976 d.tabWorkArea(i)->setFullScreen(true);
1977 #if QT_VERSION >= 0x040300
1978 setContentsMargins(-2, -2, -2, -2);
1980 setWindowState(windowState() ^ Qt::WindowFullScreen);
1981 statusBar()->hide();
1987 Buffer const * GuiView::updateInset(Inset const * inset)
1989 if (!d.current_work_area_)
1993 d.current_work_area_->scheduleRedraw();
1995 return &d.current_work_area_->bufferView().buffer();
1999 void GuiView::restartCursor()
2001 /* When we move around, or type, it's nice to be able to see
2002 * the cursor immediately after the keypress.
2004 if (d.current_work_area_)
2005 d.current_work_area_->startBlinkingCursor();
2007 // Take this occasion to update the other GUI elements.
2012 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2014 if (d.current_work_area_)
2015 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2020 // This list should be kept in sync with the list of insets in
2021 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2022 // dialog should have the same name as the inset.
2024 char const * const dialognames[] = {
2025 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2026 "citation", "document", "errorlist", "ert", "external", "file",
2027 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2028 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2029 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2031 #ifdef HAVE_LIBAIKSAURUS
2035 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2037 char const * const * const end_dialognames =
2038 dialognames + (sizeof(dialognames) / sizeof(char *));
2042 cmpCStr(char const * name) : name_(name) {}
2043 bool operator()(char const * other) {
2044 return strcmp(other, name_) == 0;
2051 bool isValidName(string const & name)
2053 return find_if(dialognames, end_dialognames,
2054 cmpCStr(name.c_str())) != end_dialognames;
2060 void GuiView::resetDialogs()
2062 // Make sure that no LFUN uses any LyXView.
2063 theLyXFunc().setLyXView(0);
2064 // FIXME: the "math panels" toolbar takes an awful lot of time to
2065 // initialise so we don't do that for the time being.
2066 //d.toolbars_->init();
2067 guiApp->menus().fillMenuBar(menuBar(), this);
2069 d.layout_->updateContents(true);
2070 // Now update controls with current buffer.
2071 theLyXFunc().setLyXView(this);
2076 Dialog * GuiView::find_or_build(string const & name)
2078 if (!isValidName(name))
2081 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2083 if (it != d.dialogs_.end())
2084 return it->second.get();
2086 Dialog * dialog = build(name);
2087 d.dialogs_[name].reset(dialog);
2088 if (lyxrc.allow_geometry_session)
2089 dialog->restoreSession();
2094 void GuiView::showDialog(string const & name, string const & data,
2101 Dialog * dialog = find_or_build(name);
2103 dialog->showData(data);
2105 d.open_insets_[name] = inset;
2111 bool GuiView::isDialogVisible(string const & name) const
2113 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2114 if (it == d.dialogs_.end())
2116 return it->second.get()->isVisibleView();
2120 void GuiView::hideDialog(string const & name, Inset * inset)
2122 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2123 if (it == d.dialogs_.end())
2126 if (inset && inset != getOpenInset(name))
2129 Dialog * const dialog = it->second.get();
2130 if (dialog->isVisibleView())
2132 d.open_insets_[name] = 0;
2136 void GuiView::disconnectDialog(string const & name)
2138 if (!isValidName(name))
2141 if (d.open_insets_.find(name) != d.open_insets_.end())
2142 d.open_insets_[name] = 0;
2146 Inset * GuiView::getOpenInset(string const & name) const
2148 if (!isValidName(name))
2151 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2152 return it == d.open_insets_.end() ? 0 : it->second;
2156 void GuiView::hideAll() const
2158 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2159 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2161 for(; it != end; ++it)
2162 it->second->hideView();
2166 void GuiView::updateDialogs()
2168 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2169 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2171 for(; it != end; ++it) {
2172 Dialog * dialog = it->second.get();
2173 if (dialog && dialog->isVisibleView())
2174 dialog->checkStatus();
2182 // will be replaced by a proper factory...
2183 Dialog * createGuiAbout(GuiView & lv);
2184 Dialog * createGuiBibitem(GuiView & lv);
2185 Dialog * createGuiBibtex(GuiView & lv);
2186 Dialog * createGuiBox(GuiView & lv);
2187 Dialog * createGuiBranch(GuiView & lv);
2188 Dialog * createGuiChanges(GuiView & lv);
2189 Dialog * createGuiCharacter(GuiView & lv);
2190 Dialog * createGuiCitation(GuiView & lv);
2191 Dialog * createGuiDelimiter(GuiView & lv);
2192 Dialog * createGuiDocument(GuiView & lv);
2193 Dialog * createGuiErrorList(GuiView & lv);
2194 Dialog * createGuiERT(GuiView & lv);
2195 Dialog * createGuiExternal(GuiView & lv);
2196 Dialog * createGuiFloat(GuiView & lv);
2197 Dialog * createGuiGraphics(GuiView & lv);
2198 Dialog * createGuiHSpace(GuiView & lv);
2199 Dialog * createGuiInclude(GuiView & lv);
2200 Dialog * createGuiLabel(GuiView & lv);
2201 Dialog * createGuiListings(GuiView & lv);
2202 Dialog * createGuiLog(GuiView & lv);
2203 Dialog * createGuiMathMatrix(GuiView & lv);
2204 Dialog * createGuiNomenclature(GuiView & lv);
2205 Dialog * createGuiNote(GuiView & lv);
2206 Dialog * createGuiParagraph(GuiView & lv);
2207 Dialog * createGuiPreferences(GuiView & lv);
2208 Dialog * createGuiPrint(GuiView & lv);
2209 Dialog * createGuiRef(GuiView & lv);
2210 Dialog * createGuiSearch(GuiView & lv);
2211 Dialog * createGuiSendTo(GuiView & lv);
2212 Dialog * createGuiShowFile(GuiView & lv);
2213 Dialog * createGuiSpellchecker(GuiView & lv);
2214 Dialog * createGuiSymbols(GuiView & lv);
2215 Dialog * createGuiTabularCreate(GuiView & lv);
2216 Dialog * createGuiTabular(GuiView & lv);
2217 Dialog * createGuiTexInfo(GuiView & lv);
2218 Dialog * createGuiToc(GuiView & lv);
2219 Dialog * createGuiThesaurus(GuiView & lv);
2220 Dialog * createGuiHyperlink(GuiView & lv);
2221 Dialog * createGuiVSpace(GuiView & lv);
2222 Dialog * createGuiViewSource(GuiView & lv);
2223 Dialog * createGuiWrap(GuiView & lv);
2226 Dialog * GuiView::build(string const & name)
2228 LASSERT(isValidName(name), /**/);
2230 if (name == "aboutlyx")
2231 return createGuiAbout(*this);
2232 if (name == "bibitem")
2233 return createGuiBibitem(*this);
2234 if (name == "bibtex")
2235 return createGuiBibtex(*this);
2237 return createGuiBox(*this);
2238 if (name == "branch")
2239 return createGuiBranch(*this);
2240 if (name == "changes")
2241 return createGuiChanges(*this);
2242 if (name == "character")
2243 return createGuiCharacter(*this);
2244 if (name == "citation")
2245 return createGuiCitation(*this);
2246 if (name == "document")
2247 return createGuiDocument(*this);
2248 if (name == "errorlist")
2249 return createGuiErrorList(*this);
2251 return createGuiERT(*this);
2252 if (name == "external")
2253 return createGuiExternal(*this);
2255 return createGuiShowFile(*this);
2256 if (name == "findreplace")
2257 return createGuiSearch(*this);
2258 if (name == "float")
2259 return createGuiFloat(*this);
2260 if (name == "graphics")
2261 return createGuiGraphics(*this);
2262 if (name == "include")
2263 return createGuiInclude(*this);
2264 if (name == "nomenclature")
2265 return createGuiNomenclature(*this);
2266 if (name == "label")
2267 return createGuiLabel(*this);
2269 return createGuiLog(*this);
2270 if (name == "view-source")
2271 return createGuiViewSource(*this);
2272 if (name == "mathdelimiter")
2273 return createGuiDelimiter(*this);
2274 if (name == "mathmatrix")
2275 return createGuiMathMatrix(*this);
2277 return createGuiNote(*this);
2278 if (name == "paragraph")
2279 return createGuiParagraph(*this);
2280 if (name == "prefs")
2281 return createGuiPreferences(*this);
2282 if (name == "print")
2283 return createGuiPrint(*this);
2285 return createGuiRef(*this);
2286 if (name == "sendto")
2287 return createGuiSendTo(*this);
2288 if (name == "space")
2289 return createGuiHSpace(*this);
2290 if (name == "spellchecker")
2291 return createGuiSpellchecker(*this);
2292 if (name == "symbols")
2293 return createGuiSymbols(*this);
2294 if (name == "tabular")
2295 return createGuiTabular(*this);
2296 if (name == "tabularcreate")
2297 return createGuiTabularCreate(*this);
2298 if (name == "texinfo")
2299 return createGuiTexInfo(*this);
2300 #ifdef HAVE_LIBAIKSAURUS
2301 if (name == "thesaurus")
2302 return createGuiThesaurus(*this);
2305 return createGuiToc(*this);
2307 return createGuiHyperlink(*this);
2308 if (name == "vspace")
2309 return createGuiVSpace(*this);
2311 return createGuiWrap(*this);
2312 if (name == "listings")
2313 return createGuiListings(*this);
2319 } // namespace frontend
2322 #include "GuiView_moc.cpp"