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);
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 = dlg.open(toqstr(lyxrc.template_path),
1121 QStringList(qt_("LyX Documents (*.lyx)")));
1123 if (result.first == FileDialog::Later)
1125 if (result.second.isEmpty())
1127 return FileName(fromqstr(result.second));
1131 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1135 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1138 message(_("Document not loaded."));
1143 setBuffer(newBuffer);
1145 // scroll to the position when the file was last closed
1146 if (lyxrc.use_lastfilepos) {
1147 LastFilePosSection::FilePos filepos =
1148 LyX::ref().session().lastFilePos().load(filename);
1149 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1153 LyX::ref().session().lastFiles().add(filename);
1160 void GuiView::openDocument(string const & fname)
1162 string initpath = lyxrc.document_path;
1165 string const trypath = buffer()->filePath();
1166 // If directory is writeable, use this as default.
1167 if (FileName(trypath).isDirWritable())
1173 if (fname.empty()) {
1174 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1175 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1176 dlg.setButton2(qt_("Examples|#E#e"),
1177 toqstr(addPath(package().system_support().absFilename(), "examples")));
1179 FileDialog::Result result =
1180 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1182 if (result.first == FileDialog::Later)
1185 filename = fromqstr(result.second);
1187 // check selected filename
1188 if (filename.empty()) {
1189 message(_("Canceled."));
1195 // get absolute path of file and add ".lyx" to the filename if
1197 FileName const fullname =
1198 fileSearch(string(), filename, "lyx", support::may_not_exist);
1199 if (!fullname.empty())
1200 filename = fullname.absFilename();
1202 // if the file doesn't exist, let the user create one
1203 if (!fullname.exists()) {
1204 // the user specifically chose this name. Believe him.
1205 Buffer * const b = newFile(filename, string(), true);
1211 docstring const disp_fn = makeDisplayPath(filename);
1212 message(bformat(_("Opening document %1$s..."), disp_fn));
1215 Buffer * buf = loadDocument(fullname);
1220 buf->errors("Parse");
1221 str2 = bformat(_("Document %1$s opened."), disp_fn);
1223 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1228 // FIXME: clean that
1229 static bool import(GuiView * lv, FileName const & filename,
1230 string const & format, ErrorList & errorList)
1232 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1234 string loader_format;
1235 vector<string> loaders = theConverters().loaders();
1236 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1237 for (vector<string>::const_iterator it = loaders.begin();
1238 it != loaders.end(); ++it) {
1239 if (!theConverters().isReachable(format, *it))
1242 string const tofile =
1243 support::changeExtension(filename.absFilename(),
1244 formats.extension(*it));
1245 if (!theConverters().convert(0, filename, FileName(tofile),
1246 filename, format, *it, errorList))
1248 loader_format = *it;
1251 if (loader_format.empty()) {
1252 frontend::Alert::error(_("Couldn't import file"),
1253 bformat(_("No information for importing the format %1$s."),
1254 formats.prettyName(format)));
1258 loader_format = format;
1260 if (loader_format == "lyx") {
1261 Buffer * buf = lv->loadDocument(lyxfile);
1266 buf->errors("Parse");
1268 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1272 bool as_paragraphs = loader_format == "textparagraph";
1273 string filename2 = (loader_format == format) ? filename.absFilename()
1274 : support::changeExtension(filename.absFilename(),
1275 formats.extension(loader_format));
1276 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1277 theLyXFunc().setLyXView(lv);
1278 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1285 void GuiView::importDocument(string const & argument)
1288 string filename = split(argument, format, ' ');
1290 LYXERR(Debug::INFO, format << " file: " << filename);
1292 // need user interaction
1293 if (filename.empty()) {
1294 string initpath = lyxrc.document_path;
1296 Buffer const * buf = buffer();
1298 string const trypath = buf->filePath();
1299 // If directory is writeable, use this as default.
1300 if (FileName(trypath).isDirWritable())
1304 docstring const text = bformat(_("Select %1$s file to import"),
1305 formats.prettyName(format));
1307 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1308 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1309 dlg.setButton2(qt_("Examples|#E#e"),
1310 toqstr(addPath(package().system_support().absFilename(), "examples")));
1312 docstring filter = formats.prettyName(format);
1315 filter += from_utf8(formats.extension(format));
1318 FileDialog::Result result =
1319 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1321 if (result.first == FileDialog::Later)
1324 filename = fromqstr(result.second);
1326 // check selected filename
1327 if (filename.empty())
1328 message(_("Canceled."));
1331 if (filename.empty())
1334 // get absolute path of file
1335 FileName const fullname(support::makeAbsPath(filename));
1337 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1339 // Check if the document already is open
1340 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1343 if (!closeBuffer()) {
1344 message(_("Canceled."));
1349 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1351 // if the file exists already, and we didn't do
1352 // -i lyx thefile.lyx, warn
1353 if (lyxfile.exists() && fullname != lyxfile) {
1355 docstring text = bformat(_("The document %1$s already exists.\n\n"
1356 "Do you want to overwrite that document?"), displaypath);
1357 int const ret = Alert::prompt(_("Overwrite document?"),
1358 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1361 message(_("Canceled."));
1366 message(bformat(_("Importing %1$s..."), displaypath));
1367 ErrorList errorList;
1368 if (import(this, fullname, format, errorList))
1369 message(_("imported."));
1371 message(_("file not imported!"));
1373 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1377 void GuiView::newDocument(string const & filename, bool from_template)
1379 FileName initpath(lyxrc.document_path);
1380 Buffer * buf = buffer();
1382 FileName const trypath(buf->filePath());
1383 // If directory is writeable, use this as default.
1384 if (trypath.isDirWritable())
1388 string templatefile = from_template ?
1389 selectTemplateFile().absFilename() : string();
1391 if (filename.empty())
1392 b = newUnnamedFile(templatefile, initpath);
1394 b = newFile(filename, templatefile, true);
1398 // Ensure the cursor is correctly positionned on screen.
1399 view()->showCursor();
1403 void GuiView::insertLyXFile(docstring const & fname)
1405 BufferView * bv = view();
1410 FileName filename(to_utf8(fname));
1412 if (!filename.empty()) {
1413 bv->insertLyXFile(filename);
1417 // Launch a file browser
1419 string initpath = lyxrc.document_path;
1420 string const trypath = bv->buffer().filePath();
1421 // If directory is writeable, use this as default.
1422 if (FileName(trypath).isDirWritable())
1426 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1427 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1428 dlg.setButton2(qt_("Examples|#E#e"),
1429 toqstr(addPath(package().system_support().absFilename(),
1432 FileDialog::Result result = dlg.open(toqstr(initpath),
1433 QStringList(qt_("LyX Documents (*.lyx)")));
1435 if (result.first == FileDialog::Later)
1439 filename.set(fromqstr(result.second));
1441 // check selected filename
1442 if (filename.empty()) {
1443 // emit message signal.
1444 message(_("Canceled."));
1448 bv->insertLyXFile(filename);
1452 void GuiView::insertPlaintextFile(docstring const & fname,
1455 BufferView * bv = view();
1460 FileName filename(to_utf8(fname));
1462 if (!filename.empty()) {
1463 bv->insertPlaintextFile(filename, asParagraph);
1467 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1468 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1470 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1473 if (result.first == FileDialog::Later)
1477 filename.set(fromqstr(result.second));
1479 // check selected filename
1480 if (filename.empty()) {
1481 // emit message signal.
1482 message(_("Canceled."));
1486 bv->insertPlaintextFile(filename, asParagraph);
1490 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1492 FileName fname = b.fileName();
1493 FileName const oldname = fname;
1495 if (!newname.empty()) {
1497 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1499 // Switch to this Buffer.
1502 /// No argument? Ask user through dialog.
1504 FileDialog dlg(qt_("Choose a filename to save document as"),
1505 LFUN_BUFFER_WRITE_AS);
1506 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1507 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1509 if (!isLyXFilename(fname.absFilename()))
1510 fname.changeExtension(".lyx");
1512 FileDialog::Result result =
1513 dlg.save(toqstr(fname.onlyPath().absFilename()),
1514 QStringList(qt_("LyX Documents (*.lyx)")),
1515 toqstr(fname.onlyFileName()));
1517 if (result.first == FileDialog::Later)
1520 fname.set(fromqstr(result.second));
1525 if (!isLyXFilename(fname.absFilename()))
1526 fname.changeExtension(".lyx");
1529 if (FileName(fname).exists()) {
1530 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1531 docstring text = bformat(_("The document %1$s already "
1532 "exists.\n\nDo you want to "
1533 "overwrite that document?"),
1535 int const ret = Alert::prompt(_("Overwrite document?"),
1536 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1539 case 1: return renameBuffer(b, docstring());
1540 case 2: return false;
1544 // Ok, change the name of the buffer
1545 b.setFileName(fname.absFilename());
1547 bool unnamed = b.isUnnamed();
1548 b.setUnnamed(false);
1549 b.saveCheckSum(fname);
1551 if (!saveBuffer(b)) {
1552 b.setFileName(oldname.absFilename());
1553 b.setUnnamed(unnamed);
1554 b.saveCheckSum(oldname);
1562 bool GuiView::saveBuffer(Buffer & b)
1565 return renameBuffer(b, docstring());
1568 LyX::ref().session().lastFiles().add(b.fileName());
1572 // Switch to this Buffer.
1575 // FIXME: we don't tell the user *WHY* the save failed !!
1576 docstring const file = makeDisplayPath(b.absFileName(), 30);
1577 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1578 "Do you want to rename the document and "
1579 "try again?"), file);
1580 int const ret = Alert::prompt(_("Rename and save?"),
1581 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1584 if (!renameBuffer(b, docstring()))
1593 return saveBuffer(b);
1597 bool GuiView::closeBuffer()
1599 Buffer * buf = buffer();
1600 return buf && closeBuffer(*buf);
1604 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1606 // goto bookmark to update bookmark pit.
1607 //FIXME: we should update only the bookmarks related to this buffer!
1608 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1609 theLyXFunc().gotoBookmark(i+1, false, false);
1611 if (buf.isClean() || buf.paragraphs().empty()) {
1612 if (buf.masterBuffer() == &buf && tolastopened)
1613 LyX::ref().session().lastOpened().add(buf.fileName());
1614 theBufferList().release(&buf);
1617 // Switch to this Buffer.
1622 if (buf.isUnnamed())
1623 file = from_utf8(buf.fileName().onlyFileName());
1625 file = buf.fileName().displayName(30);
1627 // Bring this window to top before asking questions.
1631 docstring const text = bformat(_("The document %1$s has unsaved changes."
1632 "\n\nDo you want to save the document or discard the changes?"), file);
1633 int const ret = Alert::prompt(_("Save changed document?"),
1634 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1638 if (!saveBuffer(buf))
1642 // if we crash after this we could
1643 // have no autosave file but I guess
1644 // this is really improbable (Jug)
1645 removeAutosaveFile(buf.absFileName());
1651 // save file names to .lyx/session
1652 // if master/slave are both open, do not save slave since it
1653 // will be automatically loaded when the master is loaded
1654 if (buf.masterBuffer() == &buf && tolastopened)
1655 LyX::ref().session().lastOpened().add(buf.fileName());
1657 theBufferList().release(&buf);
1662 bool GuiView::dispatch(FuncRequest const & cmd)
1664 BufferView * bv = view();
1665 // By default we won't need any update.
1667 bv->cursor().updateFlags(Update::None);
1669 switch(cmd.action) {
1670 case LFUN_BUFFER_IMPORT:
1671 importDocument(to_utf8(cmd.argument()));
1674 case LFUN_BUFFER_SWITCH:
1675 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1678 case LFUN_BUFFER_NEXT:
1679 setBuffer(theBufferList().next(buffer()));
1682 case LFUN_BUFFER_PREVIOUS:
1683 setBuffer(theBufferList().previous(buffer()));
1686 case LFUN_COMMAND_EXECUTE: {
1687 bool const show_it = cmd.argument() != "off";
1688 d.toolbars_->showCommandBuffer(show_it);
1691 case LFUN_DROP_LAYOUTS_CHOICE:
1693 d.layout_->showPopup();
1696 case LFUN_MENU_OPEN:
1697 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1698 menu->exec(QCursor::pos());
1701 case LFUN_FILE_INSERT:
1702 insertLyXFile(cmd.argument());
1704 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1705 insertPlaintextFile(cmd.argument(), true);
1708 case LFUN_FILE_INSERT_PLAINTEXT:
1709 insertPlaintextFile(cmd.argument(), false);
1712 case LFUN_BUFFER_WRITE:
1714 saveBuffer(bv->buffer());
1717 case LFUN_BUFFER_WRITE_AS:
1719 renameBuffer(bv->buffer(), cmd.argument());
1722 case LFUN_BUFFER_WRITE_ALL: {
1723 Buffer * first = theBufferList().first();
1726 message(_("Saving all documents..."));
1727 // We cannot use a for loop as the buffer list cycles.
1730 if (!b->isClean()) {
1732 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1734 b = theBufferList().next(b);
1735 } while (b != first);
1736 message(_("All documents saved."));
1740 case LFUN_TOOLBAR_TOGGLE: {
1741 string const name = cmd.getArg(0);
1742 bool const allowauto = cmd.getArg(1) == "allowauto";
1743 // it is possible to get current toolbar status like this,...
1744 // but I decide to obey the order of ToolbarBackend::flags
1745 // and disregard real toolbar status.
1746 // toolbars_->saveToolbarInfo();
1748 // toggle state on/off/auto
1749 d.toolbars_->toggleToolbarState(name, allowauto);
1753 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1755 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1759 if (tbi->flags & ToolbarInfo::ON)
1761 else if (tbi->flags & ToolbarInfo::OFF)
1763 else if (tbi->flags & ToolbarInfo::AUTO)
1766 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1767 _(tbi->gui_name), state));
1771 case LFUN_DIALOG_UPDATE: {
1772 string const name = to_utf8(cmd.argument());
1773 // Can only update a dialog connected to an existing inset
1774 Inset * inset = getOpenInset(name);
1776 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1777 inset->dispatch(view()->cursor(), fr);
1778 } else if (name == "paragraph") {
1779 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1780 } else if (name == "prefs") {
1781 updateDialog(name, string());
1786 case LFUN_DIALOG_TOGGLE: {
1787 if (isDialogVisible(cmd.getArg(0)))
1788 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1790 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1794 case LFUN_DIALOG_DISCONNECT_INSET:
1795 disconnectDialog(to_utf8(cmd.argument()));
1798 case LFUN_DIALOG_HIDE: {
1799 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1803 case LFUN_DIALOG_SHOW: {
1804 string const name = cmd.getArg(0);
1805 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1807 if (name == "character") {
1808 data = freefont2string();
1810 showDialog("character", data);
1811 } else if (name == "latexlog") {
1812 Buffer::LogType type;
1813 string const logfile = buffer()->logName(&type);
1815 case Buffer::latexlog:
1818 case Buffer::buildlog:
1822 data += Lexer::quoteString(logfile);
1823 showDialog("log", data);
1824 } else if (name == "vclog") {
1825 string const data = "vc " +
1826 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1827 showDialog("log", data);
1828 } else if (name == "symbols") {
1829 data = bv->cursor().getEncoding()->name();
1831 showDialog("symbols", data);
1833 showDialog(name, data);
1837 case LFUN_INSET_APPLY: {
1838 string const name = cmd.getArg(0);
1839 Inset * inset = getOpenInset(name);
1841 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1842 inset->dispatch(view()->cursor(), fr);
1844 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1850 case LFUN_UI_TOGGLE:
1852 // Make sure the keyboard focus stays in the work area.
1856 case LFUN_COMPLETION_INLINE:
1857 if (d.current_work_area_)
1858 d.current_work_area_->completer().showInline();
1861 case LFUN_SPLIT_VIEW:
1862 if (Buffer * buf = buffer()) {
1863 string const orientation = cmd.getArg(0);
1864 d.splitter_->setOrientation(orientation == "vertical"
1865 ? Qt::Vertical : Qt::Horizontal);
1866 TabWorkArea * twa = addTabWorkArea();
1867 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1868 setCurrentWorkArea(wa);
1872 case LFUN_CLOSE_TAB_GROUP:
1873 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1875 twa = d.currentTabWorkArea();
1876 // Switch to the next GuiWorkArea in the found TabWorkArea.
1877 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1878 if (d.splitter_->count() == 0)
1879 // No more work area, switch to the background widget.
1884 case LFUN_COMPLETION_POPUP:
1885 if (d.current_work_area_)
1886 d.current_work_area_->completer().showPopup();
1890 case LFUN_COMPLETION_COMPLETE:
1891 if (d.current_work_area_)
1892 d.current_work_area_->completer().tab();
1903 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1905 string const arg = cmd.getArg(0);
1906 if (arg == "scrollbar") {
1907 // hide() is of no help
1908 if (d.current_work_area_->verticalScrollBarPolicy() ==
1909 Qt::ScrollBarAlwaysOff)
1911 d.current_work_area_->setVerticalScrollBarPolicy(
1912 Qt::ScrollBarAsNeeded);
1914 d.current_work_area_->setVerticalScrollBarPolicy(
1915 Qt::ScrollBarAlwaysOff);
1918 if (arg == "statusbar") {
1919 statusBar()->setVisible(!statusBar()->isVisible());
1922 if (arg == "menubar") {
1923 menuBar()->setVisible(!menuBar()->isVisible());
1926 #if QT_VERSION >= 0x040300
1927 if (arg == "frame") {
1929 getContentsMargins(&l, &t, &r, &b);
1930 //are the frames in default state?
1931 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1933 setContentsMargins(-2, -2, -2, -2);
1935 setContentsMargins(0, 0, 0, 0);
1940 if (arg != "fullscreen") {
1941 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1945 if (lyxrc.full_screen_toolbars)
1946 d.toolbars_->toggleFullScreen(!isFullScreen());
1948 if (isFullScreen()) {
1949 for (int i = 0; i != d.splitter_->count(); ++i)
1950 d.tabWorkArea(i)->setFullScreen(false);
1951 #if QT_VERSION >= 0x040300
1952 setContentsMargins(0, 0, 0, 0);
1954 setWindowState(windowState() ^ Qt::WindowFullScreen);
1956 statusBar()->show();
1958 for (int i = 0; i != d.splitter_->count(); ++i)
1959 d.tabWorkArea(i)->setFullScreen(true);
1960 #if QT_VERSION >= 0x040300
1961 setContentsMargins(-2, -2, -2, -2);
1963 setWindowState(windowState() ^ Qt::WindowFullScreen);
1964 statusBar()->hide();
1970 Buffer const * GuiView::updateInset(Inset const * inset)
1972 if (!d.current_work_area_)
1976 d.current_work_area_->scheduleRedraw();
1978 return &d.current_work_area_->bufferView().buffer();
1982 void GuiView::restartCursor()
1984 /* When we move around, or type, it's nice to be able to see
1985 * the cursor immediately after the keypress.
1987 if (d.current_work_area_)
1988 d.current_work_area_->startBlinkingCursor();
1990 // Take this occasion to update the other GUI elements.
1997 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1999 if (d.current_work_area_)
2000 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2005 // This list should be kept in sync with the list of insets in
2006 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2007 // dialog should have the same name as the inset.
2009 char const * const dialognames[] = {
2010 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2011 "citation", "document", "errorlist", "ert", "external", "file",
2012 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2013 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2014 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2016 #ifdef HAVE_LIBAIKSAURUS
2020 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2022 char const * const * const end_dialognames =
2023 dialognames + (sizeof(dialognames) / sizeof(char *));
2027 cmpCStr(char const * name) : name_(name) {}
2028 bool operator()(char const * other) {
2029 return strcmp(other, name_) == 0;
2036 bool isValidName(string const & name)
2038 return find_if(dialognames, end_dialognames,
2039 cmpCStr(name.c_str())) != end_dialognames;
2045 void GuiView::resetDialogs()
2047 // Make sure that no LFUN uses any LyXView.
2048 theLyXFunc().setLyXView(0);
2049 // FIXME: the "math panels" toolbar takes an awful lot of time to
2050 // initialise so we don't do that for the time being.
2051 //d.toolbars_->init();
2052 guiApp->menus().fillMenuBar(menuBar(), this);
2054 d.layout_->updateContents(true);
2055 // Now update controls with current buffer.
2056 theLyXFunc().setLyXView(this);
2061 Dialog * GuiView::find_or_build(string const & name)
2063 if (!isValidName(name))
2066 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2068 if (it != d.dialogs_.end())
2069 return it->second.get();
2071 Dialog * dialog = build(name);
2072 d.dialogs_[name].reset(dialog);
2073 if (lyxrc.allow_geometry_session)
2074 dialog->restoreSession();
2079 void GuiView::showDialog(string const & name, string const & data,
2086 Dialog * dialog = find_or_build(name);
2088 dialog->showData(data);
2090 d.open_insets_[name] = inset;
2096 bool GuiView::isDialogVisible(string const & name) const
2098 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2099 if (it == d.dialogs_.end())
2101 return it->second.get()->isVisibleView();
2105 void GuiView::hideDialog(string const & name, Inset * inset)
2107 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2108 if (it == d.dialogs_.end())
2111 if (inset && inset != getOpenInset(name))
2114 Dialog * const dialog = it->second.get();
2115 if (dialog->isVisibleView())
2117 d.open_insets_[name] = 0;
2121 void GuiView::disconnectDialog(string const & name)
2123 if (!isValidName(name))
2126 if (d.open_insets_.find(name) != d.open_insets_.end())
2127 d.open_insets_[name] = 0;
2131 Inset * GuiView::getOpenInset(string const & name) const
2133 if (!isValidName(name))
2136 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2137 return it == d.open_insets_.end() ? 0 : it->second;
2141 void GuiView::hideAll() const
2143 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2144 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2146 for(; it != end; ++it)
2147 it->second->hideView();
2151 void GuiView::hideBufferDependent() const
2153 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2154 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2156 for(; it != end; ++it) {
2157 Dialog * dialog = it->second.get();
2158 if (dialog->isBufferDependent())
2164 void GuiView::updateBufferDependent(bool switched) const
2166 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2167 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2169 for(; it != end; ++it) {
2170 Dialog * dialog = it->second.get();
2171 if (!dialog->isVisibleView())
2173 if (switched && dialog->isBufferDependent()) {
2174 if (dialog->initialiseParams(""))
2175 dialog->updateView();
2179 // A bit clunky, but the dialog will request
2180 // that the kernel provides it with the necessary
2182 dialog->updateDialog();
2188 void GuiView::checkStatus()
2190 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2191 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2193 for(; it != end; ++it) {
2194 Dialog * const dialog = it->second.get();
2195 if (dialog && dialog->isVisibleView())
2196 dialog->checkStatus();
2202 // will be replaced by a proper factory...
2203 Dialog * createGuiAbout(GuiView & lv);
2204 Dialog * createGuiBibitem(GuiView & lv);
2205 Dialog * createGuiBibtex(GuiView & lv);
2206 Dialog * createGuiBox(GuiView & lv);
2207 Dialog * createGuiBranch(GuiView & lv);
2208 Dialog * createGuiChanges(GuiView & lv);
2209 Dialog * createGuiCharacter(GuiView & lv);
2210 Dialog * createGuiCitation(GuiView & lv);
2211 Dialog * createGuiDelimiter(GuiView & lv);
2212 Dialog * createGuiDocument(GuiView & lv);
2213 Dialog * createGuiErrorList(GuiView & lv);
2214 Dialog * createGuiERT(GuiView & lv);
2215 Dialog * createGuiExternal(GuiView & lv);
2216 Dialog * createGuiFloat(GuiView & lv);
2217 Dialog * createGuiGraphics(GuiView & lv);
2218 Dialog * createGuiHSpace(GuiView & lv);
2219 Dialog * createGuiInclude(GuiView & lv);
2220 Dialog * createGuiLabel(GuiView & lv);
2221 Dialog * createGuiListings(GuiView & lv);
2222 Dialog * createGuiLog(GuiView & lv);
2223 Dialog * createGuiMathMatrix(GuiView & lv);
2224 Dialog * createGuiNomenclature(GuiView & lv);
2225 Dialog * createGuiNote(GuiView & lv);
2226 Dialog * createGuiParagraph(GuiView & lv);
2227 Dialog * createGuiPreferences(GuiView & lv);
2228 Dialog * createGuiPrint(GuiView & lv);
2229 Dialog * createGuiRef(GuiView & lv);
2230 Dialog * createGuiSearch(GuiView & lv);
2231 Dialog * createGuiSendTo(GuiView & lv);
2232 Dialog * createGuiShowFile(GuiView & lv);
2233 Dialog * createGuiSpellchecker(GuiView & lv);
2234 Dialog * createGuiSymbols(GuiView & lv);
2235 Dialog * createGuiTabularCreate(GuiView & lv);
2236 Dialog * createGuiTabular(GuiView & lv);
2237 Dialog * createGuiTexInfo(GuiView & lv);
2238 Dialog * createGuiToc(GuiView & lv);
2239 Dialog * createGuiThesaurus(GuiView & lv);
2240 Dialog * createGuiHyperlink(GuiView & lv);
2241 Dialog * createGuiVSpace(GuiView & lv);
2242 Dialog * createGuiViewSource(GuiView & lv);
2243 Dialog * createGuiWrap(GuiView & lv);
2246 Dialog * GuiView::build(string const & name)
2248 LASSERT(isValidName(name), /**/);
2250 if (name == "aboutlyx")
2251 return createGuiAbout(*this);
2252 if (name == "bibitem")
2253 return createGuiBibitem(*this);
2254 if (name == "bibtex")
2255 return createGuiBibtex(*this);
2257 return createGuiBox(*this);
2258 if (name == "branch")
2259 return createGuiBranch(*this);
2260 if (name == "changes")
2261 return createGuiChanges(*this);
2262 if (name == "character")
2263 return createGuiCharacter(*this);
2264 if (name == "citation")
2265 return createGuiCitation(*this);
2266 if (name == "document")
2267 return createGuiDocument(*this);
2268 if (name == "errorlist")
2269 return createGuiErrorList(*this);
2271 return createGuiERT(*this);
2272 if (name == "external")
2273 return createGuiExternal(*this);
2275 return createGuiShowFile(*this);
2276 if (name == "findreplace")
2277 return createGuiSearch(*this);
2278 if (name == "float")
2279 return createGuiFloat(*this);
2280 if (name == "graphics")
2281 return createGuiGraphics(*this);
2282 if (name == "include")
2283 return createGuiInclude(*this);
2284 if (name == "nomenclature")
2285 return createGuiNomenclature(*this);
2286 if (name == "label")
2287 return createGuiLabel(*this);
2289 return createGuiLog(*this);
2290 if (name == "view-source")
2291 return createGuiViewSource(*this);
2292 if (name == "mathdelimiter")
2293 return createGuiDelimiter(*this);
2294 if (name == "mathmatrix")
2295 return createGuiMathMatrix(*this);
2297 return createGuiNote(*this);
2298 if (name == "paragraph")
2299 return createGuiParagraph(*this);
2300 if (name == "prefs")
2301 return createGuiPreferences(*this);
2302 if (name == "print")
2303 return createGuiPrint(*this);
2305 return createGuiRef(*this);
2306 if (name == "sendto")
2307 return createGuiSendTo(*this);
2308 if (name == "space")
2309 return createGuiHSpace(*this);
2310 if (name == "spellchecker")
2311 return createGuiSpellchecker(*this);
2312 if (name == "symbols")
2313 return createGuiSymbols(*this);
2314 if (name == "tabular")
2315 return createGuiTabular(*this);
2316 if (name == "tabularcreate")
2317 return createGuiTabularCreate(*this);
2318 if (name == "texinfo")
2319 return createGuiTexInfo(*this);
2320 #ifdef HAVE_LIBAIKSAURUS
2321 if (name == "thesaurus")
2322 return createGuiThesaurus(*this);
2325 return createGuiToc(*this);
2327 return createGuiHyperlink(*this);
2328 if (name == "vspace")
2329 return createGuiVSpace(*this);
2331 return createGuiWrap(*this);
2332 if (name == "listings")
2333 return createGuiListings(*this);
2339 } // namespace frontend
2342 #include "GuiView_moc.cpp"