3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiCompleter.h"
22 #include "GuiWorkArea.h"
23 #include "GuiKeySymbol.h"
24 #include "GuiToolbar.h"
25 #include "GuiToolbars.h"
29 #include "qt_helpers.h"
31 #include "frontends/alert.h"
33 #include "buffer_funcs.h"
35 #include "BufferList.h"
36 #include "BufferParams.h"
37 #include "BufferView.h"
38 #include "Converter.h"
41 #include "ErrorList.h"
43 #include "FuncStatus.h"
44 #include "FuncRequest.h"
52 #include "Paragraph.h"
53 #include "TextClass.h"
55 #include "ToolbarBackend.h"
58 #include "support/lassert.h"
59 #include "support/debug.h"
60 #include "support/FileName.h"
61 #include "support/filetools.h"
62 #include "support/gettext.h"
63 #include "support/ForkedCalls.h"
64 #include "support/lstrings.h"
65 #include "support/os.h"
66 #include "support/Package.h"
67 #include "support/Timeout.h"
70 #include <QApplication>
71 #include <QCloseEvent>
73 #include <QDesktopWidget>
74 #include <QDragEnterEvent>
82 #include <QPushButton>
86 #include <QStackedWidget>
93 #include <boost/bind.hpp>
95 #ifdef HAVE_SYS_TIME_H
96 # include <sys/time.h>
103 using namespace lyx::support;
110 class BackgroundWidget : public QWidget
115 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
116 /// The text to be written on top of the pixmap
117 QString const text = lyx_version ?
118 qt_("version ") + lyx_version : qt_("unknown version");
119 splash_ = QPixmap(":/images/banner.png");
121 QPainter pain(&splash_);
122 pain.setPen(QColor(0, 0, 0));
124 // The font used to display the version info
125 font.setStyleHint(QFont::SansSerif);
126 font.setWeight(QFont::Bold);
127 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
129 pain.drawText(190, 225, text);
132 void paintEvent(QPaintEvent *)
134 int x = (width() - splash_.width()) / 2;
135 int y = (height() - splash_.height()) / 2;
137 pain.drawPixmap(x, y, splash_);
147 typedef boost::shared_ptr<Dialog> DialogPtr;
149 struct GuiView::GuiViewPrivate
152 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
155 // hardcode here the platform specific icon size
156 smallIconSize = 14; // scaling problems
157 normalIconSize = 20; // ok, default
158 bigIconSize = 26; // better for some math icons
160 splitter_ = new QSplitter;
161 bg_widget_ = new BackgroundWidget;
162 stack_widget_ = new QStackedWidget;
163 stack_widget_->addWidget(bg_widget_);
164 stack_widget_->addWidget(splitter_);
172 delete stack_widget_;
176 QMenu * toolBarPopup(GuiView * parent)
178 // FIXME: translation
179 QMenu * menu = new QMenu(parent);
180 QActionGroup * iconSizeGroup = new QActionGroup(parent);
182 QAction * smallIcons = new QAction(iconSizeGroup);
183 smallIcons->setText(qt_("Small-sized icons"));
184 smallIcons->setCheckable(true);
185 QObject::connect(smallIcons, SIGNAL(triggered()),
186 parent, SLOT(smallSizedIcons()));
187 menu->addAction(smallIcons);
189 QAction * normalIcons = new QAction(iconSizeGroup);
190 normalIcons->setText(qt_("Normal-sized icons"));
191 normalIcons->setCheckable(true);
192 QObject::connect(normalIcons, SIGNAL(triggered()),
193 parent, SLOT(normalSizedIcons()));
194 menu->addAction(normalIcons);
196 QAction * bigIcons = new QAction(iconSizeGroup);
197 bigIcons->setText(qt_("Big-sized icons"));
198 bigIcons->setCheckable(true);
199 QObject::connect(bigIcons, SIGNAL(triggered()),
200 parent, SLOT(bigSizedIcons()));
201 menu->addAction(bigIcons);
203 unsigned int cur = parent->iconSize().width();
204 if ( cur == parent->d.smallIconSize)
205 smallIcons->setChecked(true);
206 else if (cur == parent->d.normalIconSize)
207 normalIcons->setChecked(true);
208 else if (cur == parent->d.bigIconSize)
209 bigIcons->setChecked(true);
216 stack_widget_->setCurrentWidget(bg_widget_);
217 bg_widget_->setUpdatesEnabled(true);
220 TabWorkArea * tabWorkArea(int i)
222 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
225 TabWorkArea * currentTabWorkArea()
227 if (splitter_->count() == 1)
228 // The first TabWorkArea is always the first one, if any.
229 return tabWorkArea(0);
231 for (int i = 0; i != splitter_->count(); ++i) {
232 TabWorkArea * twa = tabWorkArea(i);
233 if (current_work_area_ == twa->currentWorkArea())
237 // None has the focus so we just take the first one.
238 return tabWorkArea(0);
242 GuiWorkArea * current_work_area_;
243 QSplitter * splitter_;
244 QStackedWidget * stack_widget_;
245 BackgroundWidget * bg_widget_;
247 GuiToolbars * toolbars_;
248 /// The main layout box.
250 * \warning Don't Delete! The layout box is actually owned by
251 * whichever toolbar contains it. All the GuiView class needs is a
252 * means of accessing it.
254 * FIXME: replace that with a proper model so that we are not limited
255 * to only one dialog.
257 GuiLayoutBox * layout_;
260 map<string, Inset *> open_insets_;
263 map<string, DialogPtr> dialogs_;
265 unsigned int smallIconSize;
266 unsigned int normalIconSize;
267 unsigned int bigIconSize;
269 QTimer statusbar_timer_;
270 /// auto-saving of buffers
271 Timeout autosave_timeout_;
272 /// flag against a race condition due to multiclicks, see bug #1119
276 TocModels toc_models_;
280 GuiView::GuiView(int id)
281 : d(*new GuiViewPrivate), id_(id)
283 // GuiToolbars *must* be initialised before the menu bar.
284 d.toolbars_ = new GuiToolbars(*this);
286 // set ourself as the current view. This is needed for the menu bar
287 // filling, at least for the static special menu item on Mac. Otherwise
288 // they are greyed out.
289 theLyXFunc().setLyXView(this);
291 // Fill up the menu bar.
292 guiApp->menus().fillMenuBar(menuBar(), this, true);
294 setCentralWidget(d.stack_widget_);
296 // Start autosave timer
297 if (lyxrc.autosave) {
298 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
299 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
300 d.autosave_timeout_.start();
302 connect(&d.statusbar_timer_, SIGNAL(timeout()),
303 this, SLOT(clearMessage()));
305 // We don't want to keep the window in memory if it is closed.
306 setAttribute(Qt::WA_DeleteOnClose, true);
308 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
309 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
310 // since the icon is provided in the application bundle.
311 setWindowIcon(QPixmap(":/images/lyx.png"));
315 setAcceptDrops(true);
317 statusBar()->setSizeGripEnabled(true);
319 // Forbid too small unresizable window because it can happen
320 // with some window manager under X11.
321 setMinimumSize(300, 200);
323 if (!lyxrc.allow_geometry_session)
324 // No session handling, default to a sane size.
325 setGeometry(50, 50, 690, 510);
327 // Now take care of session management.
329 QString const key = "view-" + QString::number(id_);
331 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
332 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
336 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
337 setGeometry(50, 50, 690, 510);
339 setIconSize(settings.value(key + "/icon_size").toSize());
345 if (guiApp->currentView() == this)
346 guiApp->setCurrentView(0);
347 theLyXFunc().setLyXView(0);
353 TocModels & GuiView::tocModels()
355 return d.toc_models_;
359 void GuiView::setFocus()
361 if (d.current_work_area_)
362 d.current_work_area_->setFocus();
368 QMenu * GuiView::createPopupMenu()
370 return d.toolBarPopup(this);
374 void GuiView::showEvent(QShowEvent * e)
376 LYXERR(Debug::GUI, "Passed Geometry "
377 << size().height() << "x" << size().width()
378 << "+" << pos().x() << "+" << pos().y());
380 if (d.splitter_->count() == 0)
381 // No work area, switch to the background widget.
384 QMainWindow::showEvent(e);
388 void GuiView::closeEvent(QCloseEvent * close_event)
390 // it can happen that this event arrives without selecting the view,
391 // e.g. when clicking the close button on a background window.
392 theLyXFunc().setLyXView(this);
394 while (Buffer * b = buffer()) {
396 // This is a child document, just close the tab after saving
397 // but keep the file loaded.
398 if (!saveBuffer(*b)) {
399 close_event->ignore();
402 removeWorkArea(d.current_work_area_);
406 std::vector<int> const & ids = guiApp->viewIds();
407 for (size_type i = 0; i != ids.size(); ++i) {
410 if (guiApp->view(ids[i]).workArea(*b)) {
411 // FIXME 1: should we put an alert box here that the buffer
412 // is viewed elsewhere?
413 // FIXME 2: should we try to save this buffer in any case?
416 // This buffer is also opened in another view, so
417 // but close the associated work area nevertheless.
418 removeWorkArea(d.current_work_area_);
419 // but don't close it.
424 if (b && !closeBuffer(*b, true)) {
425 close_event->ignore();
430 // Make sure that no LFUN use this close to be closed View.
431 theLyXFunc().setLyXView(0);
433 // Save toolbars configuration
434 if (isFullScreen()) {
435 d.toolbars_->toggleFullScreen(!isFullScreen());
439 // Make sure the timer time out will not trigger a statusbar update.
440 d.statusbar_timer_.stop();
442 // Saving fullscreen requires additional tweaks in the toolbar code.
443 // It wouldn't also work under linux natively.
444 if (lyxrc.allow_geometry_session && !isFullScreen()) {
446 QString const key = "view-" + QString::number(id_);
448 settings.setValue(key + "/pos", pos());
449 settings.setValue(key + "/size", size());
451 settings.setValue(key + "/geometry", saveGeometry());
453 settings.setValue(key + "/icon_size", iconSize());
454 d.toolbars_->saveToolbarInfo();
455 // Now take care of all other dialogs:
456 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
457 for (; it!= d.dialogs_.end(); ++it)
458 it->second->saveSession();
461 guiApp->unregisterView(id_);
462 close_event->accept();
466 void GuiView::dragEnterEvent(QDragEnterEvent * event)
468 if (event->mimeData()->hasUrls())
470 /// \todo Ask lyx-devel is this is enough:
471 /// if (event->mimeData()->hasFormat("text/plain"))
472 /// event->acceptProposedAction();
476 void GuiView::dropEvent(QDropEvent* event)
478 QList<QUrl> files = event->mimeData()->urls();
482 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
483 for (int i = 0; i != files.size(); ++i) {
484 string const file = os::internal_path(fromqstr(
485 files.at(i).toLocalFile()));
487 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
492 void GuiView::message(docstring const & str)
494 if (ForkedProcess::iAmAChild())
497 statusBar()->showMessage(toqstr(str));
498 d.statusbar_timer_.stop();
499 d.statusbar_timer_.start(3000);
503 void GuiView::smallSizedIcons()
505 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
509 void GuiView::normalSizedIcons()
511 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
515 void GuiView::bigSizedIcons()
517 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
521 void GuiView::clearMessage()
525 theLyXFunc().setLyXView(this);
526 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
527 d.statusbar_timer_.stop();
531 void GuiView::updateWindowTitle(GuiWorkArea * wa)
533 if (wa != d.current_work_area_)
535 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
536 setWindowIconText(wa->windowIconText());
540 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
543 disconnectBufferView();
544 connectBufferView(wa->bufferView());
545 connectBuffer(wa->bufferView().buffer());
546 d.current_work_area_ = wa;
547 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
548 this, SLOT(updateWindowTitle(GuiWorkArea *)));
549 updateWindowTitle(wa);
551 // Navigator needs more than a simple update in this case. It needs to be
555 // Buffer-dependent dialogs must be updated. This is done here because
556 // some dialogs require buffer()->text.
561 void GuiView::on_lastWorkAreaRemoved()
564 // On Mac close the view if there is no Tab open anymore,
565 // but only if no splitter is visible
566 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
567 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
568 if (twa && twa->count() == 0) {
569 // close the view, as no tab is open anymore
570 QTimer::singleShot(0, this, SLOT(close()));
580 void GuiView::updateStatusBar()
582 // let the user see the explicit message
583 if (d.statusbar_timer_.isActive())
586 theLyXFunc().setLyXView(this);
587 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
591 bool GuiView::hasFocus() const
593 return qApp->activeWindow() == this;
597 bool GuiView::event(QEvent * e)
601 // Useful debug code:
602 //case QEvent::ActivationChange:
603 //case QEvent::WindowDeactivate:
604 //case QEvent::Paint:
605 //case QEvent::Enter:
606 //case QEvent::Leave:
607 //case QEvent::HoverEnter:
608 //case QEvent::HoverLeave:
609 //case QEvent::HoverMove:
610 //case QEvent::StatusTip:
611 //case QEvent::DragEnter:
612 //case QEvent::DragLeave:
616 case QEvent::WindowActivate: {
617 if (this == guiApp->currentView()) {
619 return QMainWindow::event(e);
621 guiApp->setCurrentView(this);
622 if (d.current_work_area_) {
623 BufferView & bv = d.current_work_area_->bufferView();
624 connectBufferView(bv);
625 connectBuffer(bv.buffer());
626 // The document structure, name and dialogs might have
627 // changed in another view.
631 setWindowTitle(qt_("LyX"));
632 setWindowIconText(qt_("LyX"));
635 return QMainWindow::event(e);
638 case QEvent::ShortcutOverride: {
639 if (d.current_work_area_)
640 // Nothing special to do.
641 return QMainWindow::event(e);
643 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
645 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
647 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
648 || ke->key() == Qt::Key_Backtab)
649 return QMainWindow::event(e);
651 // Allow processing of shortcuts that are allowed even when no Buffer
653 theLyXFunc().setLyXView(this);
655 setKeySymbol(&sym, ke);
656 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
662 return QMainWindow::event(e);
667 bool GuiView::focusNextPrevChild(bool /*next*/)
674 void GuiView::setBusy(bool busy)
676 if (d.current_work_area_) {
677 d.current_work_area_->setUpdatesEnabled(!busy);
679 d.current_work_area_->stopBlinkingCursor();
681 d.current_work_area_->startBlinkingCursor();
685 QApplication::setOverrideCursor(Qt::WaitCursor);
687 QApplication::restoreOverrideCursor();
691 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
693 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
695 if (tbinfo.flags & ToolbarInfo::TOP) {
697 addToolBarBreak(Qt::TopToolBarArea);
698 addToolBar(Qt::TopToolBarArea, toolBar);
701 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
702 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
703 #if (QT_VERSION >= 0x040202)
705 addToolBarBreak(Qt::BottomToolBarArea);
707 addToolBar(Qt::BottomToolBarArea, toolBar);
710 if (tbinfo.flags & ToolbarInfo::LEFT) {
711 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
712 #if (QT_VERSION >= 0x040202)
714 addToolBarBreak(Qt::LeftToolBarArea);
716 addToolBar(Qt::LeftToolBarArea, toolBar);
719 if (tbinfo.flags & ToolbarInfo::RIGHT) {
720 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
721 #if (QT_VERSION >= 0x040202)
723 addToolBarBreak(Qt::RightToolBarArea);
725 addToolBar(Qt::RightToolBarArea, toolBar);
728 // The following does not work so I cannot restore to exact toolbar location
730 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
731 toolBar->move(tbinfo.posx, tbinfo.posy);
738 GuiWorkArea * GuiView::workArea(Buffer & buffer)
740 if (TabWorkArea * twa = d.currentTabWorkArea())
741 return twa->workArea(buffer);
746 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
748 // Automatically create a TabWorkArea if there are none yet.
749 TabWorkArea * tab_widget = d.splitter_->count()
750 ? d.currentTabWorkArea() : addTabWorkArea();
751 return tab_widget->addWorkArea(buffer, *this);
755 TabWorkArea * GuiView::addTabWorkArea()
757 TabWorkArea * twa = new TabWorkArea;
758 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
759 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
760 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
761 this, SLOT(on_lastWorkAreaRemoved()));
763 d.splitter_->addWidget(twa);
764 d.stack_widget_->setCurrentWidget(d.splitter_);
769 GuiWorkArea const * GuiView::currentWorkArea() const
771 return d.current_work_area_;
775 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
778 d.current_work_area_ = wa;
779 for (int i = 0; i != d.splitter_->count(); ++i) {
780 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
786 void GuiView::removeWorkArea(GuiWorkArea * wa)
789 if (wa == d.current_work_area_) {
791 disconnectBufferView();
792 d.current_work_area_ = 0;
795 for (int i = 0; i != d.splitter_->count(); ++i) {
796 TabWorkArea * twa = d.tabWorkArea(i);
797 if (!twa->removeWorkArea(wa))
798 // Not found in this tab group.
801 // We found and removed the GuiWorkArea.
803 // No more WorkAreas in this tab group, so delete it.
808 if (d.current_work_area_)
809 // This means that we are not closing the current GuiWorkArea;
812 // Switch to the next GuiWorkArea in the found TabWorkArea.
813 d.current_work_area_ = twa->currentWorkArea();
817 if (d.splitter_->count() == 0)
818 // No more work area, switch to the background widget.
823 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
829 void GuiView::updateLayoutList()
832 d.layout_->updateContents(false);
836 void GuiView::updateToolbars()
838 if (d.current_work_area_) {
840 d.current_work_area_->bufferView().cursor().inMathed();
842 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
844 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
845 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
846 bool const mathmacrotemplate =
847 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
849 d.toolbars_->update(math, table, review, mathmacrotemplate);
851 d.toolbars_->update(false, false, false, false);
853 // update read-only status of open dialogs.
858 Buffer * GuiView::buffer()
860 if (d.current_work_area_)
861 return &d.current_work_area_->bufferView().buffer();
866 Buffer const * GuiView::buffer() const
868 if (d.current_work_area_)
869 return &d.current_work_area_->bufferView().buffer();
874 void GuiView::setBuffer(Buffer * newBuffer)
876 LASSERT(newBuffer, /**/);
879 GuiWorkArea * wa = workArea(*newBuffer);
881 updateLabels(*newBuffer->masterBuffer());
882 wa = addWorkArea(*newBuffer);
884 //Disconnect the old buffer...there's no new one.
887 connectBuffer(*newBuffer);
888 connectBufferView(wa->bufferView());
889 setCurrentWorkArea(wa);
895 void GuiView::connectBuffer(Buffer & buf)
897 buf.setGuiDelegate(this);
901 void GuiView::disconnectBuffer()
903 if (d.current_work_area_)
904 d.current_work_area_->bufferView().setGuiDelegate(0);
908 void GuiView::connectBufferView(BufferView & bv)
910 bv.setGuiDelegate(this);
914 void GuiView::disconnectBufferView()
916 if (d.current_work_area_)
917 d.current_work_area_->bufferView().setGuiDelegate(0);
921 void GuiView::errors(string const & error_type)
923 ErrorList & el = buffer()->errorList(error_type);
925 showDialog("errorlist", error_type);
929 void GuiView::structureChanged()
931 d.toc_models_.reset(view());
932 updateDialog("toc", "");
936 void GuiView::updateDialog(string const & name, string const & data)
938 if (!isDialogVisible(name))
941 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
942 if (it == d.dialogs_.end())
945 Dialog * const dialog = it->second.get();
946 if (dialog->isVisibleView())
947 dialog->updateData(data);
951 BufferView * GuiView::view()
953 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
957 void GuiView::autoSave()
959 LYXERR(Debug::INFO, "Running autoSave()");
962 view()->buffer().autoSave();
966 void GuiView::resetAutosaveTimers()
969 d.autosave_timeout_.restart();
973 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
977 Buffer * buf = buffer();
979 /* In LyX/Mac, when a dialog is open, the menus of the
980 application can still be accessed without giving focus to
981 the main window. In this case, we want to disable the menu
982 entries that are buffer-related.
984 Note that this code is not perfect, as bug 1941 attests:
985 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
987 if (cmd.origin == FuncRequest::MENU && !hasFocus())
991 case LFUN_BUFFER_WRITE:
992 enable = buf && (buf->isUnnamed() || !buf->isClean());
995 case LFUN_BUFFER_WRITE_AS:
999 case LFUN_SPLIT_VIEW:
1003 case LFUN_CLOSE_TAB_GROUP:
1004 enable = d.currentTabWorkArea();
1007 case LFUN_TOOLBAR_TOGGLE:
1008 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1011 case LFUN_UI_TOGGLE:
1012 flag.setOnOff(isFullScreen());
1015 case LFUN_DIALOG_TOGGLE:
1016 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1017 // fall through to set "enable"
1018 case LFUN_DIALOG_SHOW: {
1019 string const name = cmd.getArg(0);
1021 enable = name == "aboutlyx"
1022 || name == "file" //FIXME: should be removed.
1024 || name == "texinfo";
1025 else if (name == "print")
1026 enable = buf->isExportable("dvi")
1027 && lyxrc.print_command != "none";
1028 else if (name == "character") {
1032 InsetCode ic = view()->cursor().inset().lyxCode();
1033 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1036 else if (name == "symbols") {
1037 if (!view() || view()->cursor().inMathed())
1040 InsetCode ic = view()->cursor().inset().lyxCode();
1041 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1044 else if (name == "latexlog")
1045 enable = FileName(buf->logName()).isReadableFile();
1046 else if (name == "spellchecker")
1047 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1048 enable = !buf->isReadonly();
1052 else if (name == "vclog")
1053 enable = buf->lyxvc().inUse();
1057 case LFUN_DIALOG_UPDATE: {
1058 string const name = cmd.getArg(0);
1060 enable = name == "prefs";
1064 case LFUN_INSET_APPLY: {
1069 string const name = cmd.getArg(0);
1070 Inset * inset = getOpenInset(name);
1072 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1074 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1075 // Every inset is supposed to handle this
1076 LASSERT(false, /**/);
1080 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1081 flag |= getStatus(fr);
1083 enable = flag.enabled();
1087 case LFUN_COMPLETION_INLINE:
1088 if (!d.current_work_area_
1089 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1093 case LFUN_COMPLETION_POPUP:
1094 if (!d.current_work_area_
1095 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1099 case LFUN_COMPLETION_COMPLETE:
1100 if (!d.current_work_area_
1101 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1113 flag.enabled(false);
1119 static FileName selectTemplateFile()
1121 FileDialog dlg(qt_("Select template file"));
1122 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1123 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1125 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1126 QStringList(qt_("LyX Documents (*.lyx)")));
1128 if (result.first == FileDialog::Later)
1130 if (result.second.isEmpty())
1132 return FileName(fromqstr(result.second));
1136 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1140 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1143 message(_("Document not loaded."));
1148 setBuffer(newBuffer);
1150 // scroll to the position when the file was last closed
1151 if (lyxrc.use_lastfilepos) {
1152 LastFilePosSection::FilePos filepos =
1153 LyX::ref().session().lastFilePos().load(filename);
1154 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1158 LyX::ref().session().lastFiles().add(filename);
1165 void GuiView::openDocument(string const & fname)
1167 string initpath = lyxrc.document_path;
1170 string const trypath = buffer()->filePath();
1171 // If directory is writeable, use this as default.
1172 if (FileName(trypath).isDirWritable())
1178 if (fname.empty()) {
1179 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1180 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1181 dlg.setButton2(qt_("Examples|#E#e"),
1182 toqstr(addPath(package().system_support().absFilename(), "examples")));
1184 FileDialog::Result result =
1185 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1187 if (result.first == FileDialog::Later)
1190 filename = fromqstr(result.second);
1192 // check selected filename
1193 if (filename.empty()) {
1194 message(_("Canceled."));
1200 // get absolute path of file and add ".lyx" to the filename if
1202 FileName const fullname =
1203 fileSearch(string(), filename, "lyx", support::may_not_exist);
1204 if (!fullname.empty())
1205 filename = fullname.absFilename();
1207 // if the file doesn't exist, let the user create one
1208 if (!fullname.exists()) {
1209 // the user specifically chose this name. Believe him.
1210 Buffer * const b = newFile(filename, string(), true);
1216 docstring const disp_fn = makeDisplayPath(filename);
1217 message(bformat(_("Opening document %1$s..."), disp_fn));
1220 Buffer * buf = loadDocument(fullname);
1225 buf->errors("Parse");
1226 str2 = bformat(_("Document %1$s opened."), disp_fn);
1228 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1233 // FIXME: clean that
1234 static bool import(GuiView * lv, FileName const & filename,
1235 string const & format, ErrorList & errorList)
1237 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1239 string loader_format;
1240 vector<string> loaders = theConverters().loaders();
1241 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1242 for (vector<string>::const_iterator it = loaders.begin();
1243 it != loaders.end(); ++it) {
1244 if (!theConverters().isReachable(format, *it))
1247 string const tofile =
1248 support::changeExtension(filename.absFilename(),
1249 formats.extension(*it));
1250 if (!theConverters().convert(0, filename, FileName(tofile),
1251 filename, format, *it, errorList))
1253 loader_format = *it;
1256 if (loader_format.empty()) {
1257 frontend::Alert::error(_("Couldn't import file"),
1258 bformat(_("No information for importing the format %1$s."),
1259 formats.prettyName(format)));
1263 loader_format = format;
1265 if (loader_format == "lyx") {
1266 Buffer * buf = lv->loadDocument(lyxfile);
1271 buf->errors("Parse");
1273 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1277 bool as_paragraphs = loader_format == "textparagraph";
1278 string filename2 = (loader_format == format) ? filename.absFilename()
1279 : support::changeExtension(filename.absFilename(),
1280 formats.extension(loader_format));
1281 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1282 theLyXFunc().setLyXView(lv);
1283 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1290 void GuiView::importDocument(string const & argument)
1293 string filename = split(argument, format, ' ');
1295 LYXERR(Debug::INFO, format << " file: " << filename);
1297 // need user interaction
1298 if (filename.empty()) {
1299 string initpath = lyxrc.document_path;
1301 Buffer const * buf = buffer();
1303 string const trypath = buf->filePath();
1304 // If directory is writeable, use this as default.
1305 if (FileName(trypath).isDirWritable())
1309 docstring const text = bformat(_("Select %1$s file to import"),
1310 formats.prettyName(format));
1312 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1313 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1314 dlg.setButton2(qt_("Examples|#E#e"),
1315 toqstr(addPath(package().system_support().absFilename(), "examples")));
1317 docstring filter = formats.prettyName(format);
1320 filter += from_utf8(formats.extension(format));
1323 FileDialog::Result result =
1324 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1326 if (result.first == FileDialog::Later)
1329 filename = fromqstr(result.second);
1331 // check selected filename
1332 if (filename.empty())
1333 message(_("Canceled."));
1336 if (filename.empty())
1339 // get absolute path of file
1340 FileName const fullname(support::makeAbsPath(filename));
1342 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1344 // Check if the document already is open
1345 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1348 if (!closeBuffer()) {
1349 message(_("Canceled."));
1354 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1356 // if the file exists already, and we didn't do
1357 // -i lyx thefile.lyx, warn
1358 if (lyxfile.exists() && fullname != lyxfile) {
1360 docstring text = bformat(_("The document %1$s already exists.\n\n"
1361 "Do you want to overwrite that document?"), displaypath);
1362 int const ret = Alert::prompt(_("Overwrite document?"),
1363 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1366 message(_("Canceled."));
1371 message(bformat(_("Importing %1$s..."), displaypath));
1372 ErrorList errorList;
1373 if (import(this, fullname, format, errorList))
1374 message(_("imported."));
1376 message(_("file not imported!"));
1378 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1382 void GuiView::newDocument(string const & filename, bool from_template)
1384 FileName initpath(lyxrc.document_path);
1385 Buffer * buf = buffer();
1387 FileName const trypath(buf->filePath());
1388 // If directory is writeable, use this as default.
1389 if (trypath.isDirWritable())
1393 string templatefile = from_template ?
1394 selectTemplateFile().absFilename() : string();
1396 if (filename.empty())
1397 b = newUnnamedFile(templatefile, initpath);
1399 b = newFile(filename, templatefile, true);
1403 // Ensure the cursor is correctly positionned on screen.
1404 view()->showCursor();
1408 void GuiView::insertLyXFile(docstring const & fname)
1410 BufferView * bv = view();
1415 FileName filename(to_utf8(fname));
1417 if (!filename.empty()) {
1418 bv->insertLyXFile(filename);
1422 // Launch a file browser
1424 string initpath = lyxrc.document_path;
1425 string const trypath = bv->buffer().filePath();
1426 // If directory is writeable, use this as default.
1427 if (FileName(trypath).isDirWritable())
1431 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1432 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1433 dlg.setButton2(qt_("Examples|#E#e"),
1434 toqstr(addPath(package().system_support().absFilename(),
1437 FileDialog::Result result = dlg.open(toqstr(initpath),
1438 QStringList(qt_("LyX Documents (*.lyx)")));
1440 if (result.first == FileDialog::Later)
1444 filename.set(fromqstr(result.second));
1446 // check selected filename
1447 if (filename.empty()) {
1448 // emit message signal.
1449 message(_("Canceled."));
1453 bv->insertLyXFile(filename);
1457 void GuiView::insertPlaintextFile(docstring const & fname,
1460 BufferView * bv = view();
1465 FileName filename(to_utf8(fname));
1467 if (!filename.empty()) {
1468 bv->insertPlaintextFile(filename, asParagraph);
1472 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1473 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1475 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1478 if (result.first == FileDialog::Later)
1482 filename.set(fromqstr(result.second));
1484 // check selected filename
1485 if (filename.empty()) {
1486 // emit message signal.
1487 message(_("Canceled."));
1491 bv->insertPlaintextFile(filename, asParagraph);
1495 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1497 FileName fname = b.fileName();
1498 FileName const oldname = fname;
1500 if (!newname.empty()) {
1502 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1504 // Switch to this Buffer.
1507 /// No argument? Ask user through dialog.
1509 FileDialog dlg(qt_("Choose a filename to save document as"),
1510 LFUN_BUFFER_WRITE_AS);
1511 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1512 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1514 if (!isLyXFilename(fname.absFilename()))
1515 fname.changeExtension(".lyx");
1517 FileDialog::Result result =
1518 dlg.save(toqstr(fname.onlyPath().absFilename()),
1519 QStringList(qt_("LyX Documents (*.lyx)")),
1520 toqstr(fname.onlyFileName()));
1522 if (result.first == FileDialog::Later)
1525 fname.set(fromqstr(result.second));
1530 if (!isLyXFilename(fname.absFilename()))
1531 fname.changeExtension(".lyx");
1534 if (FileName(fname).exists()) {
1535 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1536 docstring text = bformat(_("The document %1$s already "
1537 "exists.\n\nDo you want to "
1538 "overwrite that document?"),
1540 int const ret = Alert::prompt(_("Overwrite document?"),
1541 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1544 case 1: return renameBuffer(b, docstring());
1545 case 2: return false;
1549 // Ok, change the name of the buffer
1550 b.setFileName(fname.absFilename());
1552 bool unnamed = b.isUnnamed();
1553 b.setUnnamed(false);
1554 b.saveCheckSum(fname);
1556 if (!saveBuffer(b)) {
1557 b.setFileName(oldname.absFilename());
1558 b.setUnnamed(unnamed);
1559 b.saveCheckSum(oldname);
1567 bool GuiView::saveBuffer(Buffer & b)
1570 return renameBuffer(b, docstring());
1573 LyX::ref().session().lastFiles().add(b.fileName());
1577 // Switch to this Buffer.
1580 // FIXME: we don't tell the user *WHY* the save failed !!
1581 docstring const file = makeDisplayPath(b.absFileName(), 30);
1582 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1583 "Do you want to rename the document and "
1584 "try again?"), file);
1585 int const ret = Alert::prompt(_("Rename and save?"),
1586 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1589 if (!renameBuffer(b, docstring()))
1598 return saveBuffer(b);
1602 bool GuiView::closeBuffer()
1604 Buffer * buf = buffer();
1605 return buf && closeBuffer(*buf);
1609 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1611 // goto bookmark to update bookmark pit.
1612 //FIXME: we should update only the bookmarks related to this buffer!
1613 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1614 theLyXFunc().gotoBookmark(i+1, false, false);
1616 if (buf.isClean() || buf.paragraphs().empty()) {
1617 if (buf.masterBuffer() == &buf && tolastopened)
1618 LyX::ref().session().lastOpened().add(buf.fileName());
1619 theBufferList().release(&buf);
1622 // Switch to this Buffer.
1627 if (buf.isUnnamed())
1628 file = from_utf8(buf.fileName().onlyFileName());
1630 file = buf.fileName().displayName(30);
1632 // Bring this window to top before asking questions.
1636 docstring const text = bformat(_("The document %1$s has unsaved changes."
1637 "\n\nDo you want to save the document or discard the changes?"), file);
1638 int const ret = Alert::prompt(_("Save changed document?"),
1639 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1643 if (!saveBuffer(buf))
1647 // if we crash after this we could
1648 // have no autosave file but I guess
1649 // this is really improbable (Jug)
1650 removeAutosaveFile(buf.absFileName());
1656 // save file names to .lyx/session
1657 // if master/slave are both open, do not save slave since it
1658 // will be automatically loaded when the master is loaded
1659 if (buf.masterBuffer() == &buf && tolastopened)
1660 LyX::ref().session().lastOpened().add(buf.fileName());
1662 theBufferList().release(&buf);
1667 bool GuiView::dispatch(FuncRequest const & cmd)
1669 BufferView * bv = view();
1670 // By default we won't need any update.
1672 bv->cursor().updateFlags(Update::None);
1674 switch(cmd.action) {
1675 case LFUN_BUFFER_IMPORT:
1676 importDocument(to_utf8(cmd.argument()));
1679 case LFUN_BUFFER_SWITCH:
1680 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1683 case LFUN_BUFFER_NEXT:
1684 setBuffer(theBufferList().next(buffer()));
1687 case LFUN_BUFFER_PREVIOUS:
1688 setBuffer(theBufferList().previous(buffer()));
1691 case LFUN_COMMAND_EXECUTE: {
1692 bool const show_it = cmd.argument() != "off";
1693 d.toolbars_->showCommandBuffer(show_it);
1696 case LFUN_DROP_LAYOUTS_CHOICE:
1698 d.layout_->showPopup();
1701 case LFUN_MENU_OPEN:
1702 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1703 menu->exec(QCursor::pos());
1706 case LFUN_FILE_INSERT:
1707 insertLyXFile(cmd.argument());
1709 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1710 insertPlaintextFile(cmd.argument(), true);
1713 case LFUN_FILE_INSERT_PLAINTEXT:
1714 insertPlaintextFile(cmd.argument(), false);
1717 case LFUN_BUFFER_WRITE:
1719 saveBuffer(bv->buffer());
1722 case LFUN_BUFFER_WRITE_AS:
1724 renameBuffer(bv->buffer(), cmd.argument());
1727 case LFUN_BUFFER_WRITE_ALL: {
1728 Buffer * first = theBufferList().first();
1731 message(_("Saving all documents..."));
1732 // We cannot use a for loop as the buffer list cycles.
1735 if (!b->isClean()) {
1737 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1739 b = theBufferList().next(b);
1740 } while (b != first);
1741 message(_("All documents saved."));
1745 case LFUN_TOOLBAR_TOGGLE: {
1746 string const name = cmd.getArg(0);
1747 bool const allowauto = cmd.getArg(1) == "allowauto";
1748 // it is possible to get current toolbar status like this,...
1749 // but I decide to obey the order of ToolbarBackend::flags
1750 // and disregard real toolbar status.
1751 // toolbars_->saveToolbarInfo();
1753 // toggle state on/off/auto
1754 d.toolbars_->toggleToolbarState(name, allowauto);
1758 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1760 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1764 if (tbi->flags & ToolbarInfo::ON)
1766 else if (tbi->flags & ToolbarInfo::OFF)
1768 else if (tbi->flags & ToolbarInfo::AUTO)
1771 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1772 _(tbi->gui_name), state));
1776 case LFUN_DIALOG_UPDATE: {
1777 string const name = to_utf8(cmd.argument());
1778 // Can only update a dialog connected to an existing inset
1779 Inset * inset = getOpenInset(name);
1781 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1782 inset->dispatch(view()->cursor(), fr);
1783 } else if (name == "paragraph") {
1784 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1785 } else if (name == "prefs") {
1786 updateDialog(name, string());
1791 case LFUN_DIALOG_TOGGLE: {
1792 if (isDialogVisible(cmd.getArg(0)))
1793 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1795 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1799 case LFUN_DIALOG_DISCONNECT_INSET:
1800 disconnectDialog(to_utf8(cmd.argument()));
1803 case LFUN_DIALOG_HIDE: {
1804 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1808 case LFUN_DIALOG_SHOW: {
1809 string const name = cmd.getArg(0);
1810 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1812 if (name == "character") {
1813 data = freefont2string();
1815 showDialog("character", data);
1816 } else if (name == "latexlog") {
1817 Buffer::LogType type;
1818 string const logfile = buffer()->logName(&type);
1820 case Buffer::latexlog:
1823 case Buffer::buildlog:
1827 data += Lexer::quoteString(logfile);
1828 showDialog("log", data);
1829 } else if (name == "vclog") {
1830 string const data = "vc " +
1831 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1832 showDialog("log", data);
1833 } else if (name == "symbols") {
1834 data = bv->cursor().getEncoding()->name();
1836 showDialog("symbols", data);
1838 showDialog(name, data);
1842 case LFUN_INSET_APPLY: {
1843 string const name = cmd.getArg(0);
1844 Inset * inset = getOpenInset(name);
1846 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1847 inset->dispatch(view()->cursor(), fr);
1849 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1855 case LFUN_UI_TOGGLE:
1857 // Make sure the keyboard focus stays in the work area.
1861 case LFUN_COMPLETION_INLINE:
1862 if (d.current_work_area_)
1863 d.current_work_area_->completer().showInline();
1866 case LFUN_SPLIT_VIEW:
1867 if (Buffer * buf = buffer()) {
1868 string const orientation = cmd.getArg(0);
1869 d.splitter_->setOrientation(orientation == "vertical"
1870 ? Qt::Vertical : Qt::Horizontal);
1871 TabWorkArea * twa = addTabWorkArea();
1872 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1873 setCurrentWorkArea(wa);
1877 case LFUN_CLOSE_TAB_GROUP:
1878 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1880 twa = d.currentTabWorkArea();
1881 // Switch to the next GuiWorkArea in the found TabWorkArea.
1882 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1883 if (d.splitter_->count() == 0)
1884 // No more work area, switch to the background widget.
1889 case LFUN_COMPLETION_POPUP:
1890 if (d.current_work_area_)
1891 d.current_work_area_->completer().showPopup();
1895 case LFUN_COMPLETION_COMPLETE:
1896 if (d.current_work_area_)
1897 d.current_work_area_->completer().tab();
1908 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1910 string const arg = cmd.getArg(0);
1911 if (arg == "scrollbar") {
1912 // hide() is of no help
1913 if (d.current_work_area_->verticalScrollBarPolicy() ==
1914 Qt::ScrollBarAlwaysOff)
1916 d.current_work_area_->setVerticalScrollBarPolicy(
1917 Qt::ScrollBarAsNeeded);
1919 d.current_work_area_->setVerticalScrollBarPolicy(
1920 Qt::ScrollBarAlwaysOff);
1923 if (arg == "statusbar") {
1924 statusBar()->setVisible(!statusBar()->isVisible());
1927 if (arg == "menubar") {
1928 menuBar()->setVisible(!menuBar()->isVisible());
1931 #if QT_VERSION >= 0x040300
1932 if (arg == "frame") {
1934 getContentsMargins(&l, &t, &r, &b);
1935 //are the frames in default state?
1936 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1938 setContentsMargins(-2, -2, -2, -2);
1940 setContentsMargins(0, 0, 0, 0);
1945 if (arg != "fullscreen") {
1946 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1950 if (lyxrc.full_screen_toolbars)
1951 d.toolbars_->toggleFullScreen(!isFullScreen());
1953 if (isFullScreen()) {
1954 for (int i = 0; i != d.splitter_->count(); ++i)
1955 d.tabWorkArea(i)->setFullScreen(false);
1956 #if QT_VERSION >= 0x040300
1957 setContentsMargins(0, 0, 0, 0);
1959 setWindowState(windowState() ^ Qt::WindowFullScreen);
1961 statusBar()->show();
1963 for (int i = 0; i != d.splitter_->count(); ++i)
1964 d.tabWorkArea(i)->setFullScreen(true);
1965 #if QT_VERSION >= 0x040300
1966 setContentsMargins(-2, -2, -2, -2);
1968 setWindowState(windowState() ^ Qt::WindowFullScreen);
1969 statusBar()->hide();
1975 Buffer const * GuiView::updateInset(Inset const * inset)
1977 if (!d.current_work_area_)
1981 d.current_work_area_->scheduleRedraw();
1983 return &d.current_work_area_->bufferView().buffer();
1987 void GuiView::restartCursor()
1989 /* When we move around, or type, it's nice to be able to see
1990 * the cursor immediately after the keypress.
1992 if (d.current_work_area_)
1993 d.current_work_area_->startBlinkingCursor();
1995 // Take this occasion to update the other GUI elements.
2002 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2004 if (d.current_work_area_)
2005 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2010 // This list should be kept in sync with the list of insets in
2011 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2012 // dialog should have the same name as the inset.
2014 char const * const dialognames[] = {
2015 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2016 "citation", "document", "errorlist", "ert", "external", "file",
2017 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2018 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2019 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2021 #ifdef HAVE_LIBAIKSAURUS
2025 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2027 char const * const * const end_dialognames =
2028 dialognames + (sizeof(dialognames) / sizeof(char *));
2032 cmpCStr(char const * name) : name_(name) {}
2033 bool operator()(char const * other) {
2034 return strcmp(other, name_) == 0;
2041 bool isValidName(string const & name)
2043 return find_if(dialognames, end_dialognames,
2044 cmpCStr(name.c_str())) != end_dialognames;
2050 void GuiView::resetDialogs()
2052 // Make sure that no LFUN uses any LyXView.
2053 theLyXFunc().setLyXView(0);
2054 // FIXME: the "math panels" toolbar takes an awful lot of time to
2055 // initialise so we don't do that for the time being.
2056 //d.toolbars_->init();
2057 guiApp->menus().fillMenuBar(menuBar(), this);
2059 d.layout_->updateContents(true);
2060 // Now update controls with current buffer.
2061 theLyXFunc().setLyXView(this);
2066 Dialog * GuiView::find_or_build(string const & name)
2068 if (!isValidName(name))
2071 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2073 if (it != d.dialogs_.end())
2074 return it->second.get();
2076 Dialog * dialog = build(name);
2077 d.dialogs_[name].reset(dialog);
2078 if (lyxrc.allow_geometry_session)
2079 dialog->restoreSession();
2084 void GuiView::showDialog(string const & name, string const & data,
2091 Dialog * dialog = find_or_build(name);
2093 dialog->showData(data);
2095 d.open_insets_[name] = inset;
2101 bool GuiView::isDialogVisible(string const & name) const
2103 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2104 if (it == d.dialogs_.end())
2106 return it->second.get()->isVisibleView();
2110 void GuiView::hideDialog(string const & name, Inset * inset)
2112 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2113 if (it == d.dialogs_.end())
2116 if (inset && inset != getOpenInset(name))
2119 Dialog * const dialog = it->second.get();
2120 if (dialog->isVisibleView())
2122 d.open_insets_[name] = 0;
2126 void GuiView::disconnectDialog(string const & name)
2128 if (!isValidName(name))
2131 if (d.open_insets_.find(name) != d.open_insets_.end())
2132 d.open_insets_[name] = 0;
2136 Inset * GuiView::getOpenInset(string const & name) const
2138 if (!isValidName(name))
2141 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2142 return it == d.open_insets_.end() ? 0 : it->second;
2146 void GuiView::hideAll() const
2148 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2149 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2151 for(; it != end; ++it)
2152 it->second->hideView();
2156 void GuiView::updateDialogs()
2158 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2159 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2161 for(; it != end; ++it) {
2162 Dialog * dialog = it->second.get();
2163 if (!dialog->isVisibleView())
2165 if (dialog->isBufferDependent()) {
2167 dialog->updateView();
2169 dialog->enableView(false);
2171 // A bit clunky, but the dialog will request
2172 // that the kernel provides it with the necessary
2174 dialog->updateDialog();
2183 void GuiView::checkStatus()
2185 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2186 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2188 for(; it != end; ++it) {
2189 Dialog * const dialog = it->second.get();
2190 if (dialog && dialog->isVisibleView())
2191 dialog->checkStatus();
2197 // will be replaced by a proper factory...
2198 Dialog * createGuiAbout(GuiView & lv);
2199 Dialog * createGuiBibitem(GuiView & lv);
2200 Dialog * createGuiBibtex(GuiView & lv);
2201 Dialog * createGuiBox(GuiView & lv);
2202 Dialog * createGuiBranch(GuiView & lv);
2203 Dialog * createGuiChanges(GuiView & lv);
2204 Dialog * createGuiCharacter(GuiView & lv);
2205 Dialog * createGuiCitation(GuiView & lv);
2206 Dialog * createGuiDelimiter(GuiView & lv);
2207 Dialog * createGuiDocument(GuiView & lv);
2208 Dialog * createGuiErrorList(GuiView & lv);
2209 Dialog * createGuiERT(GuiView & lv);
2210 Dialog * createGuiExternal(GuiView & lv);
2211 Dialog * createGuiFloat(GuiView & lv);
2212 Dialog * createGuiGraphics(GuiView & lv);
2213 Dialog * createGuiHSpace(GuiView & lv);
2214 Dialog * createGuiInclude(GuiView & lv);
2215 Dialog * createGuiLabel(GuiView & lv);
2216 Dialog * createGuiListings(GuiView & lv);
2217 Dialog * createGuiLog(GuiView & lv);
2218 Dialog * createGuiMathMatrix(GuiView & lv);
2219 Dialog * createGuiNomenclature(GuiView & lv);
2220 Dialog * createGuiNote(GuiView & lv);
2221 Dialog * createGuiParagraph(GuiView & lv);
2222 Dialog * createGuiPreferences(GuiView & lv);
2223 Dialog * createGuiPrint(GuiView & lv);
2224 Dialog * createGuiRef(GuiView & lv);
2225 Dialog * createGuiSearch(GuiView & lv);
2226 Dialog * createGuiSendTo(GuiView & lv);
2227 Dialog * createGuiShowFile(GuiView & lv);
2228 Dialog * createGuiSpellchecker(GuiView & lv);
2229 Dialog * createGuiSymbols(GuiView & lv);
2230 Dialog * createGuiTabularCreate(GuiView & lv);
2231 Dialog * createGuiTabular(GuiView & lv);
2232 Dialog * createGuiTexInfo(GuiView & lv);
2233 Dialog * createGuiToc(GuiView & lv);
2234 Dialog * createGuiThesaurus(GuiView & lv);
2235 Dialog * createGuiHyperlink(GuiView & lv);
2236 Dialog * createGuiVSpace(GuiView & lv);
2237 Dialog * createGuiViewSource(GuiView & lv);
2238 Dialog * createGuiWrap(GuiView & lv);
2241 Dialog * GuiView::build(string const & name)
2243 LASSERT(isValidName(name), /**/);
2245 if (name == "aboutlyx")
2246 return createGuiAbout(*this);
2247 if (name == "bibitem")
2248 return createGuiBibitem(*this);
2249 if (name == "bibtex")
2250 return createGuiBibtex(*this);
2252 return createGuiBox(*this);
2253 if (name == "branch")
2254 return createGuiBranch(*this);
2255 if (name == "changes")
2256 return createGuiChanges(*this);
2257 if (name == "character")
2258 return createGuiCharacter(*this);
2259 if (name == "citation")
2260 return createGuiCitation(*this);
2261 if (name == "document")
2262 return createGuiDocument(*this);
2263 if (name == "errorlist")
2264 return createGuiErrorList(*this);
2266 return createGuiERT(*this);
2267 if (name == "external")
2268 return createGuiExternal(*this);
2270 return createGuiShowFile(*this);
2271 if (name == "findreplace")
2272 return createGuiSearch(*this);
2273 if (name == "float")
2274 return createGuiFloat(*this);
2275 if (name == "graphics")
2276 return createGuiGraphics(*this);
2277 if (name == "include")
2278 return createGuiInclude(*this);
2279 if (name == "nomenclature")
2280 return createGuiNomenclature(*this);
2281 if (name == "label")
2282 return createGuiLabel(*this);
2284 return createGuiLog(*this);
2285 if (name == "view-source")
2286 return createGuiViewSource(*this);
2287 if (name == "mathdelimiter")
2288 return createGuiDelimiter(*this);
2289 if (name == "mathmatrix")
2290 return createGuiMathMatrix(*this);
2292 return createGuiNote(*this);
2293 if (name == "paragraph")
2294 return createGuiParagraph(*this);
2295 if (name == "prefs")
2296 return createGuiPreferences(*this);
2297 if (name == "print")
2298 return createGuiPrint(*this);
2300 return createGuiRef(*this);
2301 if (name == "sendto")
2302 return createGuiSendTo(*this);
2303 if (name == "space")
2304 return createGuiHSpace(*this);
2305 if (name == "spellchecker")
2306 return createGuiSpellchecker(*this);
2307 if (name == "symbols")
2308 return createGuiSymbols(*this);
2309 if (name == "tabular")
2310 return createGuiTabular(*this);
2311 if (name == "tabularcreate")
2312 return createGuiTabularCreate(*this);
2313 if (name == "texinfo")
2314 return createGuiTexInfo(*this);
2315 #ifdef HAVE_LIBAIKSAURUS
2316 if (name == "thesaurus")
2317 return createGuiThesaurus(*this);
2320 return createGuiToc(*this);
2322 return createGuiHyperlink(*this);
2323 if (name == "vspace")
2324 return createGuiVSpace(*this);
2326 return createGuiWrap(*this);
2327 if (name == "listings")
2328 return createGuiListings(*this);
2334 } // namespace frontend
2337 #include "GuiView_moc.cpp"