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"
28 #include "qt_helpers.h"
30 #include "frontends/alert.h"
32 #include "buffer_funcs.h"
34 #include "BufferList.h"
35 #include "BufferParams.h"
36 #include "BufferView.h"
37 #include "Converter.h"
40 #include "ErrorList.h"
42 #include "FuncStatus.h"
43 #include "FuncRequest.h"
51 #include "Paragraph.h"
52 #include "TextClass.h"
54 #include "ToolbarBackend.h"
57 #include "support/assert.h"
58 #include "support/debug.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, true)) {
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);
541 // Navigator needs more than a simple update in this case. It needs to be
545 // Buffer-dependent dialogs must be updated. This is done here because
546 // some dialogs require buffer()->text.
551 void GuiView::on_lastWorkAreaRemoved()
554 // On Mac close the view if there is no Tab open anymore,
555 // but only if no splitter is visible
556 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
557 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
558 if (twa && twa->count() == 0) {
559 // close the view, as no tab is open anymore
560 QTimer::singleShot(0, this, SLOT(close()));
570 void GuiView::updateStatusBar()
572 // let the user see the explicit message
573 if (d.statusbar_timer_.isActive())
576 theLyXFunc().setLyXView(this);
577 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
581 bool GuiView::hasFocus() const
583 return qApp->activeWindow() == this;
587 bool GuiView::event(QEvent * e)
591 // Useful debug code:
592 //case QEvent::ActivationChange:
593 //case QEvent::WindowDeactivate:
594 //case QEvent::Paint:
595 //case QEvent::Enter:
596 //case QEvent::Leave:
597 //case QEvent::HoverEnter:
598 //case QEvent::HoverLeave:
599 //case QEvent::HoverMove:
600 //case QEvent::StatusTip:
601 //case QEvent::DragEnter:
602 //case QEvent::DragLeave:
606 case QEvent::WindowActivate: {
607 if (this == guiApp->currentView()) {
609 return QMainWindow::event(e);
611 guiApp->setCurrentView(this);
612 if (d.current_work_area_) {
613 BufferView & bv = d.current_work_area_->bufferView();
614 connectBufferView(bv);
615 connectBuffer(bv.buffer());
616 // The document structure, name and dialogs might have
617 // changed in another view.
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)
768 d.current_work_area_ = wa;
769 for (int i = 0; i != d.splitter_->count(); ++i) {
770 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
776 void GuiView::removeWorkArea(GuiWorkArea * wa)
779 if (wa == d.current_work_area_) {
781 disconnectBufferView();
782 d.current_work_area_ = 0;
785 for (int i = 0; i != d.splitter_->count(); ++i) {
786 TabWorkArea * twa = d.tabWorkArea(i);
787 if (!twa->removeWorkArea(wa))
788 // Not found in this tab group.
791 // We found and removed the GuiWorkArea.
793 // No more WorkAreas in this tab group, so delete it.
798 if (d.current_work_area_)
799 // This means that we are not closing the current GuiWorkArea;
802 // Switch to the next GuiWorkArea in the found TabWorkArea.
803 d.current_work_area_ = twa->currentWorkArea();
807 if (d.splitter_->count() == 0)
808 // No more work area, switch to the background widget.
813 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
819 void GuiView::updateLayoutList()
822 d.layout_->updateContents(false);
826 void GuiView::updateToolbars()
828 if (d.current_work_area_) {
830 d.current_work_area_->bufferView().cursor().inMathed();
832 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
834 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
835 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
836 bool const mathmacrotemplate =
837 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
839 d.toolbars_->update(math, table, review, mathmacrotemplate);
841 d.toolbars_->update(false, false, false, false);
843 // update read-only status of open dialogs.
848 Buffer * GuiView::buffer()
850 if (d.current_work_area_)
851 return &d.current_work_area_->bufferView().buffer();
856 Buffer const * GuiView::buffer() const
858 if (d.current_work_area_)
859 return &d.current_work_area_->bufferView().buffer();
864 void GuiView::setBuffer(Buffer * newBuffer)
866 LASSERT(newBuffer, /**/);
869 GuiWorkArea * wa = workArea(*newBuffer);
871 updateLabels(*newBuffer->masterBuffer());
872 wa = addWorkArea(*newBuffer);
874 //Disconnect the old buffer...there's no new one.
877 connectBuffer(*newBuffer);
878 connectBufferView(wa->bufferView());
879 setCurrentWorkArea(wa);
885 void GuiView::connectBuffer(Buffer & buf)
887 buf.setGuiDelegate(this);
891 void GuiView::disconnectBuffer()
893 if (d.current_work_area_)
894 d.current_work_area_->bufferView().setGuiDelegate(0);
898 void GuiView::connectBufferView(BufferView & bv)
900 bv.setGuiDelegate(this);
904 void GuiView::disconnectBufferView()
906 if (d.current_work_area_)
907 d.current_work_area_->bufferView().setGuiDelegate(0);
911 void GuiView::errors(string const & error_type)
913 ErrorList & el = buffer()->errorList(error_type);
915 showDialog("errorlist", error_type);
919 void GuiView::structureChanged()
921 updateDialog("toc", "");
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::autoSave()
948 LYXERR(Debug::INFO, "Running autoSave()");
951 view()->buffer().autoSave();
955 void GuiView::resetAutosaveTimers()
958 d.autosave_timeout_.restart();
962 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
966 Buffer * buf = buffer();
968 /* In LyX/Mac, when a dialog is open, the menus of the
969 application can still be accessed without giving focus to
970 the main window. In this case, we want to disable the menu
971 entries that are buffer-related.
973 Note that this code is not perfect, as bug 1941 attests:
974 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
976 if (cmd.origin == FuncRequest::MENU && !hasFocus())
980 case LFUN_BUFFER_WRITE:
981 enable = buf && (buf->isUnnamed() || !buf->isClean());
984 case LFUN_BUFFER_WRITE_AS:
988 case LFUN_SPLIT_VIEW:
992 case LFUN_CLOSE_TAB_GROUP:
993 enable = d.currentTabWorkArea();
996 case LFUN_TOOLBAR_TOGGLE:
997 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1000 case LFUN_UI_TOGGLE:
1001 flag.setOnOff(isFullScreen());
1004 case LFUN_DIALOG_TOGGLE:
1005 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1006 // fall through to set "enable"
1007 case LFUN_DIALOG_SHOW: {
1008 string const name = cmd.getArg(0);
1010 enable = name == "aboutlyx"
1011 || name == "file" //FIXME: should be removed.
1013 || name == "texinfo";
1014 else if (name == "print")
1015 enable = buf->isExportable("dvi")
1016 && lyxrc.print_command != "none";
1017 else if (name == "character") {
1021 InsetCode ic = view()->cursor().inset().lyxCode();
1022 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1025 else if (name == "symbols") {
1026 if (!view() || view()->cursor().inMathed())
1029 InsetCode ic = view()->cursor().inset().lyxCode();
1030 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1033 else if (name == "latexlog")
1034 enable = FileName(buf->logName()).isReadableFile();
1035 else if (name == "spellchecker")
1036 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1037 enable = !buf->isReadonly();
1041 else if (name == "vclog")
1042 enable = buf->lyxvc().inUse();
1046 case LFUN_DIALOG_UPDATE: {
1047 string const name = cmd.getArg(0);
1049 enable = name == "prefs";
1053 case LFUN_INSET_APPLY: {
1058 string const name = cmd.getArg(0);
1059 Inset * inset = getOpenInset(name);
1061 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1063 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1064 // Every inset is supposed to handle this
1065 LASSERT(false, /**/);
1069 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1070 flag |= getStatus(fr);
1072 enable = flag.enabled();
1076 case LFUN_COMPLETION_INLINE:
1077 if (!d.current_work_area_
1078 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1082 case LFUN_COMPLETION_POPUP:
1083 if (!d.current_work_area_
1084 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1088 case LFUN_COMPLETION_COMPLETE:
1089 if (!d.current_work_area_
1090 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1102 flag.enabled(false);
1108 static FileName selectTemplateFile()
1110 FileDialog dlg(qt_("Select template file"));
1111 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1112 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1114 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1115 QStringList(qt_("LyX Documents (*.lyx)")));
1117 if (result.first == FileDialog::Later)
1119 if (result.second.isEmpty())
1121 return FileName(fromqstr(result.second));
1125 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1129 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1132 message(_("Document not loaded."));
1137 setBuffer(newBuffer);
1139 // scroll to the position when the file was last closed
1140 if (lyxrc.use_lastfilepos) {
1141 LastFilePosSection::FilePos filepos =
1142 LyX::ref().session().lastFilePos().load(filename);
1143 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1147 LyX::ref().session().lastFiles().add(filename);
1154 void GuiView::openDocument(string const & fname)
1156 string initpath = lyxrc.document_path;
1159 string const trypath = buffer()->filePath();
1160 // If directory is writeable, use this as default.
1161 if (FileName(trypath).isDirWritable())
1167 if (fname.empty()) {
1168 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1169 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1170 dlg.setButton2(qt_("Examples|#E#e"),
1171 toqstr(addPath(package().system_support().absFilename(), "examples")));
1173 FileDialog::Result result =
1174 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1176 if (result.first == FileDialog::Later)
1179 filename = fromqstr(result.second);
1181 // check selected filename
1182 if (filename.empty()) {
1183 message(_("Canceled."));
1189 // get absolute path of file and add ".lyx" to the filename if
1191 FileName const fullname =
1192 fileSearch(string(), filename, "lyx", support::may_not_exist);
1193 if (!fullname.empty())
1194 filename = fullname.absFilename();
1196 // if the file doesn't exist, let the user create one
1197 if (!fullname.exists()) {
1198 // the user specifically chose this name. Believe him.
1199 Buffer * const b = newFile(filename, string(), true);
1205 docstring const disp_fn = makeDisplayPath(filename);
1206 message(bformat(_("Opening document %1$s..."), disp_fn));
1209 Buffer * buf = loadDocument(fullname);
1214 buf->errors("Parse");
1215 str2 = bformat(_("Document %1$s opened."), disp_fn);
1217 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1222 // FIXME: clean that
1223 static bool import(GuiView * lv, FileName const & filename,
1224 string const & format, ErrorList & errorList)
1226 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1228 string loader_format;
1229 vector<string> loaders = theConverters().loaders();
1230 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1231 for (vector<string>::const_iterator it = loaders.begin();
1232 it != loaders.end(); ++it) {
1233 if (!theConverters().isReachable(format, *it))
1236 string const tofile =
1237 support::changeExtension(filename.absFilename(),
1238 formats.extension(*it));
1239 if (!theConverters().convert(0, filename, FileName(tofile),
1240 filename, format, *it, errorList))
1242 loader_format = *it;
1245 if (loader_format.empty()) {
1246 frontend::Alert::error(_("Couldn't import file"),
1247 bformat(_("No information for importing the format %1$s."),
1248 formats.prettyName(format)));
1252 loader_format = format;
1254 if (loader_format == "lyx") {
1255 Buffer * buf = lv->loadDocument(lyxfile);
1260 buf->errors("Parse");
1262 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1266 bool as_paragraphs = loader_format == "textparagraph";
1267 string filename2 = (loader_format == format) ? filename.absFilename()
1268 : support::changeExtension(filename.absFilename(),
1269 formats.extension(loader_format));
1270 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1271 theLyXFunc().setLyXView(lv);
1272 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1279 void GuiView::importDocument(string const & argument)
1282 string filename = split(argument, format, ' ');
1284 LYXERR(Debug::INFO, format << " file: " << filename);
1286 // need user interaction
1287 if (filename.empty()) {
1288 string initpath = lyxrc.document_path;
1290 Buffer const * buf = buffer();
1292 string const trypath = buf->filePath();
1293 // If directory is writeable, use this as default.
1294 if (FileName(trypath).isDirWritable())
1298 docstring const text = bformat(_("Select %1$s file to import"),
1299 formats.prettyName(format));
1301 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1302 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1303 dlg.setButton2(qt_("Examples|#E#e"),
1304 toqstr(addPath(package().system_support().absFilename(), "examples")));
1306 docstring filter = formats.prettyName(format);
1309 filter += from_utf8(formats.extension(format));
1312 FileDialog::Result result =
1313 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1315 if (result.first == FileDialog::Later)
1318 filename = fromqstr(result.second);
1320 // check selected filename
1321 if (filename.empty())
1322 message(_("Canceled."));
1325 if (filename.empty())
1328 // get absolute path of file
1329 FileName const fullname(support::makeAbsPath(filename));
1331 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1333 // Check if the document already is open
1334 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1337 if (!closeBuffer()) {
1338 message(_("Canceled."));
1343 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1345 // if the file exists already, and we didn't do
1346 // -i lyx thefile.lyx, warn
1347 if (lyxfile.exists() && fullname != lyxfile) {
1349 docstring text = bformat(_("The document %1$s already exists.\n\n"
1350 "Do you want to overwrite that document?"), displaypath);
1351 int const ret = Alert::prompt(_("Overwrite document?"),
1352 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1355 message(_("Canceled."));
1360 message(bformat(_("Importing %1$s..."), displaypath));
1361 ErrorList errorList;
1362 if (import(this, fullname, format, errorList))
1363 message(_("imported."));
1365 message(_("file not imported!"));
1367 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1371 void GuiView::newDocument(string const & filename, bool from_template)
1373 FileName initpath(lyxrc.document_path);
1374 Buffer * buf = buffer();
1376 FileName const trypath(buf->filePath());
1377 // If directory is writeable, use this as default.
1378 if (trypath.isDirWritable())
1382 string templatefile = from_template ?
1383 selectTemplateFile().absFilename() : string();
1385 if (filename.empty())
1386 b = newUnnamedFile(templatefile, initpath);
1388 b = newFile(filename, templatefile, true);
1392 // Ensure the cursor is correctly positionned on screen.
1393 view()->showCursor();
1397 void GuiView::insertLyXFile(docstring const & fname)
1399 BufferView * bv = view();
1404 FileName filename(to_utf8(fname));
1406 if (!filename.empty()) {
1407 bv->insertLyXFile(filename);
1411 // Launch a file browser
1413 string initpath = lyxrc.document_path;
1414 string const trypath = bv->buffer().filePath();
1415 // If directory is writeable, use this as default.
1416 if (FileName(trypath).isDirWritable())
1420 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1421 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1422 dlg.setButton2(qt_("Examples|#E#e"),
1423 toqstr(addPath(package().system_support().absFilename(),
1426 FileDialog::Result result = dlg.open(toqstr(initpath),
1427 QStringList(qt_("LyX Documents (*.lyx)")));
1429 if (result.first == FileDialog::Later)
1433 filename.set(fromqstr(result.second));
1435 // check selected filename
1436 if (filename.empty()) {
1437 // emit message signal.
1438 message(_("Canceled."));
1442 bv->insertLyXFile(filename);
1446 void GuiView::insertPlaintextFile(docstring const & fname,
1449 BufferView * bv = view();
1454 FileName filename(to_utf8(fname));
1456 if (!filename.empty()) {
1457 bv->insertPlaintextFile(filename, asParagraph);
1461 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1462 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1464 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1467 if (result.first == FileDialog::Later)
1471 filename.set(fromqstr(result.second));
1473 // check selected filename
1474 if (filename.empty()) {
1475 // emit message signal.
1476 message(_("Canceled."));
1480 bv->insertPlaintextFile(filename, asParagraph);
1484 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1486 FileName fname = b.fileName();
1487 FileName const oldname = fname;
1489 if (!newname.empty()) {
1491 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1493 // Switch to this Buffer.
1496 /// No argument? Ask user through dialog.
1498 FileDialog dlg(qt_("Choose a filename to save document as"),
1499 LFUN_BUFFER_WRITE_AS);
1500 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1501 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1503 if (!isLyXFilename(fname.absFilename()))
1504 fname.changeExtension(".lyx");
1506 FileDialog::Result result =
1507 dlg.save(toqstr(fname.onlyPath().absFilename()),
1508 QStringList(qt_("LyX Documents (*.lyx)")),
1509 toqstr(fname.onlyFileName()));
1511 if (result.first == FileDialog::Later)
1514 fname.set(fromqstr(result.second));
1519 if (!isLyXFilename(fname.absFilename()))
1520 fname.changeExtension(".lyx");
1523 if (FileName(fname).exists()) {
1524 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1525 docstring text = bformat(_("The document %1$s already "
1526 "exists.\n\nDo you want to "
1527 "overwrite that document?"),
1529 int const ret = Alert::prompt(_("Overwrite document?"),
1530 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1533 case 1: return renameBuffer(b, docstring());
1534 case 2: return false;
1538 // Ok, change the name of the buffer
1539 b.setFileName(fname.absFilename());
1541 bool unnamed = b.isUnnamed();
1542 b.setUnnamed(false);
1543 b.saveCheckSum(fname);
1545 if (!saveBuffer(b)) {
1546 b.setFileName(oldname.absFilename());
1547 b.setUnnamed(unnamed);
1548 b.saveCheckSum(oldname);
1556 bool GuiView::saveBuffer(Buffer & b)
1559 return renameBuffer(b, docstring());
1562 LyX::ref().session().lastFiles().add(b.fileName());
1566 // Switch to this Buffer.
1569 // FIXME: we don't tell the user *WHY* the save failed !!
1570 docstring const file = makeDisplayPath(b.absFileName(), 30);
1571 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1572 "Do you want to rename the document and "
1573 "try again?"), file);
1574 int const ret = Alert::prompt(_("Rename and save?"),
1575 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1578 if (!renameBuffer(b, docstring()))
1587 return saveBuffer(b);
1591 bool GuiView::closeBuffer()
1593 Buffer * buf = buffer();
1594 return buf && closeBuffer(*buf);
1598 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1600 // goto bookmark to update bookmark pit.
1601 //FIXME: we should update only the bookmarks related to this buffer!
1602 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1603 theLyXFunc().gotoBookmark(i+1, false, false);
1605 if (buf.isClean() || buf.paragraphs().empty()) {
1606 if (buf.masterBuffer() == &buf && tolastopened)
1607 LyX::ref().session().lastOpened().add(buf.fileName());
1608 theBufferList().release(&buf);
1611 // Switch to this Buffer.
1616 if (buf.isUnnamed())
1617 file = from_utf8(buf.fileName().onlyFileName());
1619 file = buf.fileName().displayName(30);
1621 // Bring this window to top before asking questions.
1625 docstring const text = bformat(_("The document %1$s has unsaved changes."
1626 "\n\nDo you want to save the document or discard the changes?"), file);
1627 int const ret = Alert::prompt(_("Save changed document?"),
1628 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1632 if (!saveBuffer(buf))
1636 // if we crash after this we could
1637 // have no autosave file but I guess
1638 // this is really improbable (Jug)
1639 removeAutosaveFile(buf.absFileName());
1645 // save file names to .lyx/session
1646 // if master/slave are both open, do not save slave since it
1647 // will be automatically loaded when the master is loaded
1648 if (buf.masterBuffer() == &buf && tolastopened)
1649 LyX::ref().session().lastOpened().add(buf.fileName());
1651 theBufferList().release(&buf);
1656 bool GuiView::dispatch(FuncRequest const & cmd)
1658 BufferView * bv = view();
1659 // By default we won't need any update.
1661 bv->cursor().updateFlags(Update::None);
1663 switch(cmd.action) {
1664 case LFUN_BUFFER_IMPORT:
1665 importDocument(to_utf8(cmd.argument()));
1668 case LFUN_BUFFER_SWITCH:
1669 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1672 case LFUN_BUFFER_NEXT:
1673 setBuffer(theBufferList().next(buffer()));
1676 case LFUN_BUFFER_PREVIOUS:
1677 setBuffer(theBufferList().previous(buffer()));
1680 case LFUN_COMMAND_EXECUTE: {
1681 bool const show_it = cmd.argument() != "off";
1682 d.toolbars_->showCommandBuffer(show_it);
1685 case LFUN_DROP_LAYOUTS_CHOICE:
1687 d.layout_->showPopup();
1690 case LFUN_MENU_OPEN:
1691 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1692 menu->exec(QCursor::pos());
1695 case LFUN_FILE_INSERT:
1696 insertLyXFile(cmd.argument());
1698 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1699 insertPlaintextFile(cmd.argument(), true);
1702 case LFUN_FILE_INSERT_PLAINTEXT:
1703 insertPlaintextFile(cmd.argument(), false);
1706 case LFUN_BUFFER_WRITE:
1708 saveBuffer(bv->buffer());
1711 case LFUN_BUFFER_WRITE_AS:
1713 renameBuffer(bv->buffer(), cmd.argument());
1716 case LFUN_BUFFER_WRITE_ALL: {
1717 Buffer * first = theBufferList().first();
1720 message(_("Saving all documents..."));
1721 // We cannot use a for loop as the buffer list cycles.
1724 if (!b->isClean()) {
1726 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1728 b = theBufferList().next(b);
1729 } while (b != first);
1730 message(_("All documents saved."));
1734 case LFUN_TOOLBAR_TOGGLE: {
1735 string const name = cmd.getArg(0);
1736 bool const allowauto = cmd.getArg(1) == "allowauto";
1737 // it is possible to get current toolbar status like this,...
1738 // but I decide to obey the order of ToolbarBackend::flags
1739 // and disregard real toolbar status.
1740 // toolbars_->saveToolbarInfo();
1742 // toggle state on/off/auto
1743 d.toolbars_->toggleToolbarState(name, allowauto);
1747 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1749 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1753 if (tbi->flags & ToolbarInfo::ON)
1755 else if (tbi->flags & ToolbarInfo::OFF)
1757 else if (tbi->flags & ToolbarInfo::AUTO)
1760 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1761 _(tbi->gui_name), state));
1765 case LFUN_DIALOG_UPDATE: {
1766 string const name = to_utf8(cmd.argument());
1767 // Can only update a dialog connected to an existing inset
1768 Inset * inset = getOpenInset(name);
1770 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1771 inset->dispatch(view()->cursor(), fr);
1772 } else if (name == "paragraph") {
1773 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1774 } else if (name == "prefs") {
1775 updateDialog(name, string());
1780 case LFUN_DIALOG_TOGGLE: {
1781 if (isDialogVisible(cmd.getArg(0)))
1782 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1784 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1788 case LFUN_DIALOG_DISCONNECT_INSET:
1789 disconnectDialog(to_utf8(cmd.argument()));
1792 case LFUN_DIALOG_HIDE: {
1793 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1797 case LFUN_DIALOG_SHOW: {
1798 string const name = cmd.getArg(0);
1799 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1801 if (name == "character") {
1802 data = freefont2string();
1804 showDialog("character", data);
1805 } else if (name == "latexlog") {
1806 Buffer::LogType type;
1807 string const logfile = buffer()->logName(&type);
1809 case Buffer::latexlog:
1812 case Buffer::buildlog:
1816 data += Lexer::quoteString(logfile);
1817 showDialog("log", data);
1818 } else if (name == "vclog") {
1819 string const data = "vc " +
1820 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1821 showDialog("log", data);
1822 } else if (name == "symbols") {
1823 data = bv->cursor().getEncoding()->name();
1825 showDialog("symbols", data);
1827 showDialog(name, data);
1831 case LFUN_INSET_APPLY: {
1832 string const name = cmd.getArg(0);
1833 Inset * inset = getOpenInset(name);
1835 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1836 inset->dispatch(view()->cursor(), fr);
1838 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1844 case LFUN_UI_TOGGLE:
1846 // Make sure the keyboard focus stays in the work area.
1850 case LFUN_COMPLETION_INLINE:
1851 if (d.current_work_area_)
1852 d.current_work_area_->completer().showInline();
1855 case LFUN_SPLIT_VIEW:
1856 if (Buffer * buf = buffer()) {
1857 string const orientation = cmd.getArg(0);
1858 d.splitter_->setOrientation(orientation == "vertical"
1859 ? Qt::Vertical : Qt::Horizontal);
1860 TabWorkArea * twa = addTabWorkArea();
1861 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1862 setCurrentWorkArea(wa);
1866 case LFUN_CLOSE_TAB_GROUP:
1867 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1869 twa = d.currentTabWorkArea();
1870 // Switch to the next GuiWorkArea in the found TabWorkArea.
1871 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1872 if (d.splitter_->count() == 0)
1873 // No more work area, switch to the background widget.
1878 case LFUN_COMPLETION_POPUP:
1879 if (d.current_work_area_)
1880 d.current_work_area_->completer().showPopup();
1884 case LFUN_COMPLETION_COMPLETE:
1885 if (d.current_work_area_)
1886 d.current_work_area_->completer().tab();
1897 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1899 string const arg = cmd.getArg(0);
1900 if (arg == "scrollbar") {
1901 // hide() is of no help
1902 if (d.current_work_area_->verticalScrollBarPolicy() ==
1903 Qt::ScrollBarAlwaysOff)
1905 d.current_work_area_->setVerticalScrollBarPolicy(
1906 Qt::ScrollBarAsNeeded);
1908 d.current_work_area_->setVerticalScrollBarPolicy(
1909 Qt::ScrollBarAlwaysOff);
1912 if (arg == "statusbar") {
1913 statusBar()->setVisible(!statusBar()->isVisible());
1916 if (arg == "menubar") {
1917 menuBar()->setVisible(!menuBar()->isVisible());
1920 #if QT_VERSION >= 0x040300
1921 if (arg == "frame") {
1923 getContentsMargins(&l, &t, &r, &b);
1924 //are the frames in default state?
1925 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1927 setContentsMargins(-2, -2, -2, -2);
1929 setContentsMargins(0, 0, 0, 0);
1934 if (arg != "fullscreen") {
1935 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1939 if (lyxrc.full_screen_toolbars)
1940 d.toolbars_->toggleFullScreen(!isFullScreen());
1942 if (isFullScreen()) {
1943 for (int i = 0; i != d.splitter_->count(); ++i)
1944 d.tabWorkArea(i)->setFullScreen(false);
1945 #if QT_VERSION >= 0x040300
1946 setContentsMargins(0, 0, 0, 0);
1948 setWindowState(windowState() ^ Qt::WindowFullScreen);
1950 statusBar()->show();
1952 for (int i = 0; i != d.splitter_->count(); ++i)
1953 d.tabWorkArea(i)->setFullScreen(true);
1954 #if QT_VERSION >= 0x040300
1955 setContentsMargins(-2, -2, -2, -2);
1957 setWindowState(windowState() ^ Qt::WindowFullScreen);
1958 statusBar()->hide();
1964 Buffer const * GuiView::updateInset(Inset const * inset)
1966 if (!d.current_work_area_)
1970 d.current_work_area_->scheduleRedraw();
1972 return &d.current_work_area_->bufferView().buffer();
1976 void GuiView::restartCursor()
1978 /* When we move around, or type, it's nice to be able to see
1979 * the cursor immediately after the keypress.
1981 if (d.current_work_area_)
1982 d.current_work_area_->startBlinkingCursor();
1984 // Take this occasion to update the other GUI elements.
1991 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1993 if (d.current_work_area_)
1994 d.current_work_area_->completer().updateVisibility(cur, start, keep);
1999 // This list should be kept in sync with the list of insets in
2000 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2001 // dialog should have the same name as the inset.
2003 char const * const dialognames[] = {
2004 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2005 "citation", "document", "errorlist", "ert", "external", "file",
2006 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2007 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2008 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2010 #ifdef HAVE_LIBAIKSAURUS
2014 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2016 char const * const * const end_dialognames =
2017 dialognames + (sizeof(dialognames) / sizeof(char *));
2021 cmpCStr(char const * name) : name_(name) {}
2022 bool operator()(char const * other) {
2023 return strcmp(other, name_) == 0;
2030 bool isValidName(string const & name)
2032 return find_if(dialognames, end_dialognames,
2033 cmpCStr(name.c_str())) != end_dialognames;
2039 void GuiView::resetDialogs()
2041 // Make sure that no LFUN uses any LyXView.
2042 theLyXFunc().setLyXView(0);
2043 // FIXME: the "math panels" toolbar takes an awful lot of time to
2044 // initialise so we don't do that for the time being.
2045 //d.toolbars_->init();
2046 guiApp->menus().fillMenuBar(menuBar(), this);
2048 d.layout_->updateContents(true);
2049 // Now update controls with current buffer.
2050 theLyXFunc().setLyXView(this);
2055 Dialog * GuiView::find_or_build(string const & name)
2057 if (!isValidName(name))
2060 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2062 if (it != d.dialogs_.end())
2063 return it->second.get();
2065 Dialog * dialog = build(name);
2066 d.dialogs_[name].reset(dialog);
2067 if (lyxrc.allow_geometry_session)
2068 dialog->restoreSession();
2073 void GuiView::showDialog(string const & name, string const & data,
2080 Dialog * dialog = find_or_build(name);
2082 dialog->showData(data);
2084 d.open_insets_[name] = inset;
2090 bool GuiView::isDialogVisible(string const & name) const
2092 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2093 if (it == d.dialogs_.end())
2095 return it->second.get()->isVisibleView();
2099 void GuiView::hideDialog(string const & name, Inset * inset)
2101 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2102 if (it == d.dialogs_.end())
2105 if (inset && inset != getOpenInset(name))
2108 Dialog * const dialog = it->second.get();
2109 if (dialog->isVisibleView())
2111 d.open_insets_[name] = 0;
2115 void GuiView::disconnectDialog(string const & name)
2117 if (!isValidName(name))
2120 if (d.open_insets_.find(name) != d.open_insets_.end())
2121 d.open_insets_[name] = 0;
2125 Inset * GuiView::getOpenInset(string const & name) const
2127 if (!isValidName(name))
2130 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2131 return it == d.open_insets_.end() ? 0 : it->second;
2135 void GuiView::hideAll() const
2137 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2138 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2140 for(; it != end; ++it)
2141 it->second->hideView();
2145 void GuiView::updateDialogs()
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 Dialog * dialog = it->second.get();
2152 if (!dialog->isVisibleView())
2154 if (dialog->isBufferDependent()) {
2156 dialog->updateView();
2158 dialog->enableView(false);
2160 // A bit clunky, but the dialog will request
2161 // that the kernel provides it with the necessary
2163 dialog->updateDialog();
2172 void GuiView::checkStatus()
2174 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2175 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2177 for(; it != end; ++it) {
2178 Dialog * const dialog = it->second.get();
2179 if (dialog && dialog->isVisibleView())
2180 dialog->checkStatus();
2186 // will be replaced by a proper factory...
2187 Dialog * createGuiAbout(GuiView & lv);
2188 Dialog * createGuiBibitem(GuiView & lv);
2189 Dialog * createGuiBibtex(GuiView & lv);
2190 Dialog * createGuiBox(GuiView & lv);
2191 Dialog * createGuiBranch(GuiView & lv);
2192 Dialog * createGuiChanges(GuiView & lv);
2193 Dialog * createGuiCharacter(GuiView & lv);
2194 Dialog * createGuiCitation(GuiView & lv);
2195 Dialog * createGuiDelimiter(GuiView & lv);
2196 Dialog * createGuiDocument(GuiView & lv);
2197 Dialog * createGuiErrorList(GuiView & lv);
2198 Dialog * createGuiERT(GuiView & lv);
2199 Dialog * createGuiExternal(GuiView & lv);
2200 Dialog * createGuiFloat(GuiView & lv);
2201 Dialog * createGuiGraphics(GuiView & lv);
2202 Dialog * createGuiHSpace(GuiView & lv);
2203 Dialog * createGuiInclude(GuiView & lv);
2204 Dialog * createGuiLabel(GuiView & lv);
2205 Dialog * createGuiListings(GuiView & lv);
2206 Dialog * createGuiLog(GuiView & lv);
2207 Dialog * createGuiMathMatrix(GuiView & lv);
2208 Dialog * createGuiNomenclature(GuiView & lv);
2209 Dialog * createGuiNote(GuiView & lv);
2210 Dialog * createGuiParagraph(GuiView & lv);
2211 Dialog * createGuiPreferences(GuiView & lv);
2212 Dialog * createGuiPrint(GuiView & lv);
2213 Dialog * createGuiRef(GuiView & lv);
2214 Dialog * createGuiSearch(GuiView & lv);
2215 Dialog * createGuiSendTo(GuiView & lv);
2216 Dialog * createGuiShowFile(GuiView & lv);
2217 Dialog * createGuiSpellchecker(GuiView & lv);
2218 Dialog * createGuiSymbols(GuiView & lv);
2219 Dialog * createGuiTabularCreate(GuiView & lv);
2220 Dialog * createGuiTabular(GuiView & lv);
2221 Dialog * createGuiTexInfo(GuiView & lv);
2222 Dialog * createGuiToc(GuiView & lv);
2223 Dialog * createGuiThesaurus(GuiView & lv);
2224 Dialog * createGuiHyperlink(GuiView & lv);
2225 Dialog * createGuiVSpace(GuiView & lv);
2226 Dialog * createGuiViewSource(GuiView & lv);
2227 Dialog * createGuiWrap(GuiView & lv);
2230 Dialog * GuiView::build(string const & name)
2232 LASSERT(isValidName(name), /**/);
2234 if (name == "aboutlyx")
2235 return createGuiAbout(*this);
2236 if (name == "bibitem")
2237 return createGuiBibitem(*this);
2238 if (name == "bibtex")
2239 return createGuiBibtex(*this);
2241 return createGuiBox(*this);
2242 if (name == "branch")
2243 return createGuiBranch(*this);
2244 if (name == "changes")
2245 return createGuiChanges(*this);
2246 if (name == "character")
2247 return createGuiCharacter(*this);
2248 if (name == "citation")
2249 return createGuiCitation(*this);
2250 if (name == "document")
2251 return createGuiDocument(*this);
2252 if (name == "errorlist")
2253 return createGuiErrorList(*this);
2255 return createGuiERT(*this);
2256 if (name == "external")
2257 return createGuiExternal(*this);
2259 return createGuiShowFile(*this);
2260 if (name == "findreplace")
2261 return createGuiSearch(*this);
2262 if (name == "float")
2263 return createGuiFloat(*this);
2264 if (name == "graphics")
2265 return createGuiGraphics(*this);
2266 if (name == "include")
2267 return createGuiInclude(*this);
2268 if (name == "nomenclature")
2269 return createGuiNomenclature(*this);
2270 if (name == "label")
2271 return createGuiLabel(*this);
2273 return createGuiLog(*this);
2274 if (name == "view-source")
2275 return createGuiViewSource(*this);
2276 if (name == "mathdelimiter")
2277 return createGuiDelimiter(*this);
2278 if (name == "mathmatrix")
2279 return createGuiMathMatrix(*this);
2281 return createGuiNote(*this);
2282 if (name == "paragraph")
2283 return createGuiParagraph(*this);
2284 if (name == "prefs")
2285 return createGuiPreferences(*this);
2286 if (name == "print")
2287 return createGuiPrint(*this);
2289 return createGuiRef(*this);
2290 if (name == "sendto")
2291 return createGuiSendTo(*this);
2292 if (name == "space")
2293 return createGuiHSpace(*this);
2294 if (name == "spellchecker")
2295 return createGuiSpellchecker(*this);
2296 if (name == "symbols")
2297 return createGuiSymbols(*this);
2298 if (name == "tabular")
2299 return createGuiTabular(*this);
2300 if (name == "tabularcreate")
2301 return createGuiTabularCreate(*this);
2302 if (name == "texinfo")
2303 return createGuiTexInfo(*this);
2304 #ifdef HAVE_LIBAIKSAURUS
2305 if (name == "thesaurus")
2306 return createGuiThesaurus(*this);
2309 return createGuiToc(*this);
2311 return createGuiHyperlink(*this);
2312 if (name == "vspace")
2313 return createGuiVSpace(*this);
2315 return createGuiWrap(*this);
2316 if (name == "listings")
2317 return createGuiListings(*this);
2323 } // namespace frontend
2326 #include "GuiView_moc.cpp"