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