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);
553 // Buffer-dependent dialogs must be updated. This is done here because
554 // some dialogs require buffer()->text.
559 void GuiView::on_lastWorkAreaRemoved()
562 // On Mac close the view if there is no Tab open anymore,
563 // but only if no splitter is visible
564 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
565 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
566 if (twa && twa->count() == 0) {
567 // close the view, as no tab is open anymore
568 QTimer::singleShot(0, this, SLOT(close()));
578 void GuiView::updateStatusBar()
580 // let the user see the explicit message
581 if (d.statusbar_timer_.isActive())
584 theLyXFunc().setLyXView(this);
585 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
589 bool GuiView::hasFocus() const
591 return qApp->activeWindow() == this;
595 bool GuiView::event(QEvent * e)
599 // Useful debug code:
600 //case QEvent::ActivationChange:
601 //case QEvent::WindowDeactivate:
602 //case QEvent::Paint:
603 //case QEvent::Enter:
604 //case QEvent::Leave:
605 //case QEvent::HoverEnter:
606 //case QEvent::HoverLeave:
607 //case QEvent::HoverMove:
608 //case QEvent::StatusTip:
609 //case QEvent::DragEnter:
610 //case QEvent::DragLeave:
614 case QEvent::WindowActivate: {
615 if (this == guiApp->currentView()) {
617 return QMainWindow::event(e);
619 guiApp->setCurrentView(this);
620 if (d.current_work_area_) {
621 BufferView & bv = d.current_work_area_->bufferView();
622 connectBufferView(bv);
623 connectBuffer(bv.buffer());
624 // The document structure, name and dialogs might have
625 // changed in another view.
629 setWindowTitle(qt_("LyX"));
630 setWindowIconText(qt_("LyX"));
633 return QMainWindow::event(e);
636 case QEvent::ShortcutOverride: {
637 if (d.current_work_area_)
638 // Nothing special to do.
639 return QMainWindow::event(e);
641 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
643 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
645 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
646 || ke->key() == Qt::Key_Backtab)
647 return QMainWindow::event(e);
649 // Allow processing of shortcuts that are allowed even when no Buffer
651 theLyXFunc().setLyXView(this);
653 setKeySymbol(&sym, ke);
654 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
660 return QMainWindow::event(e);
665 bool GuiView::focusNextPrevChild(bool /*next*/)
672 void GuiView::setBusy(bool busy)
674 if (d.current_work_area_) {
675 d.current_work_area_->setUpdatesEnabled(!busy);
677 d.current_work_area_->stopBlinkingCursor();
679 d.current_work_area_->startBlinkingCursor();
683 QApplication::setOverrideCursor(Qt::WaitCursor);
685 QApplication::restoreOverrideCursor();
689 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
691 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
693 if (tbinfo.flags & ToolbarInfo::TOP) {
695 addToolBarBreak(Qt::TopToolBarArea);
696 addToolBar(Qt::TopToolBarArea, toolBar);
699 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
700 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
701 #if (QT_VERSION >= 0x040202)
703 addToolBarBreak(Qt::BottomToolBarArea);
705 addToolBar(Qt::BottomToolBarArea, toolBar);
708 if (tbinfo.flags & ToolbarInfo::LEFT) {
709 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
710 #if (QT_VERSION >= 0x040202)
712 addToolBarBreak(Qt::LeftToolBarArea);
714 addToolBar(Qt::LeftToolBarArea, toolBar);
717 if (tbinfo.flags & ToolbarInfo::RIGHT) {
718 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
719 #if (QT_VERSION >= 0x040202)
721 addToolBarBreak(Qt::RightToolBarArea);
723 addToolBar(Qt::RightToolBarArea, toolBar);
726 // The following does not work so I cannot restore to exact toolbar location
728 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
729 toolBar->move(tbinfo.posx, tbinfo.posy);
736 GuiWorkArea * GuiView::workArea(Buffer & buffer)
738 if (TabWorkArea * twa = d.currentTabWorkArea())
739 return twa->workArea(buffer);
744 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
746 // Automatically create a TabWorkArea if there are none yet.
747 TabWorkArea * tab_widget = d.splitter_->count()
748 ? d.currentTabWorkArea() : addTabWorkArea();
749 return tab_widget->addWorkArea(buffer, *this);
753 TabWorkArea * GuiView::addTabWorkArea()
755 TabWorkArea * twa = new TabWorkArea;
756 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
757 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
758 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
759 this, SLOT(on_lastWorkAreaRemoved()));
761 d.splitter_->addWidget(twa);
762 d.stack_widget_->setCurrentWidget(d.splitter_);
767 GuiWorkArea const * GuiView::currentWorkArea() const
769 return d.current_work_area_;
773 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
776 d.current_work_area_ = wa;
777 for (int i = 0; i != d.splitter_->count(); ++i) {
778 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
784 void GuiView::removeWorkArea(GuiWorkArea * wa)
787 if (wa == d.current_work_area_) {
789 disconnectBufferView();
790 d.current_work_area_ = 0;
793 for (int i = 0; i != d.splitter_->count(); ++i) {
794 TabWorkArea * twa = d.tabWorkArea(i);
795 if (!twa->removeWorkArea(wa))
796 // Not found in this tab group.
799 // We found and removed the GuiWorkArea.
801 // No more WorkAreas in this tab group, so delete it.
806 if (d.current_work_area_)
807 // This means that we are not closing the current GuiWorkArea;
810 // Switch to the next GuiWorkArea in the found TabWorkArea.
811 d.current_work_area_ = twa->currentWorkArea();
815 if (d.splitter_->count() == 0)
816 // No more work area, switch to the background widget.
821 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
827 void GuiView::updateLayoutList()
830 d.layout_->updateContents(false);
834 void GuiView::updateToolbars()
836 if (d.current_work_area_) {
838 d.current_work_area_->bufferView().cursor().inMathed();
840 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
842 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
843 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
844 bool const mathmacrotemplate =
845 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
847 d.toolbars_->update(math, table, review, mathmacrotemplate);
849 d.toolbars_->update(false, false, false, false);
853 Buffer * GuiView::buffer()
855 if (d.current_work_area_)
856 return &d.current_work_area_->bufferView().buffer();
861 Buffer const * GuiView::buffer() const
863 if (d.current_work_area_)
864 return &d.current_work_area_->bufferView().buffer();
869 void GuiView::setBuffer(Buffer * newBuffer)
871 LASSERT(newBuffer, /**/);
874 GuiWorkArea * wa = workArea(*newBuffer);
876 updateLabels(*newBuffer->masterBuffer());
877 wa = addWorkArea(*newBuffer);
879 //Disconnect the old buffer...there's no new one.
882 connectBuffer(*newBuffer);
883 connectBufferView(wa->bufferView());
884 setCurrentWorkArea(wa);
890 void GuiView::connectBuffer(Buffer & buf)
892 buf.setGuiDelegate(this);
896 void GuiView::disconnectBuffer()
898 if (d.current_work_area_)
899 d.current_work_area_->bufferView().setGuiDelegate(0);
903 void GuiView::connectBufferView(BufferView & bv)
905 bv.setGuiDelegate(this);
909 void GuiView::disconnectBufferView()
911 if (d.current_work_area_)
912 d.current_work_area_->bufferView().setGuiDelegate(0);
916 void GuiView::errors(string const & error_type)
918 ErrorList & el = buffer()->errorList(error_type);
920 showDialog("errorlist", error_type);
924 void GuiView::structureChanged()
926 d.toc_models_.reset(view());
927 // Navigator needs more than a simple update in this case. It needs to be
929 updateDialog("toc", "");
930 // Same for the document settings dialog.
931 updateDialog("document", "");
935 void GuiView::updateDialog(string const & name, string const & data)
937 if (!isDialogVisible(name))
940 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
941 if (it == d.dialogs_.end())
944 Dialog * const dialog = it->second.get();
945 if (dialog->isVisibleView())
946 dialog->initialiseParams(data);
950 BufferView * GuiView::view()
952 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
956 void GuiView::autoSave()
958 LYXERR(Debug::INFO, "Running autoSave()");
961 view()->buffer().autoSave();
965 void GuiView::resetAutosaveTimers()
968 d.autosave_timeout_.restart();
972 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
976 Buffer * buf = buffer();
978 /* In LyX/Mac, when a dialog is open, the menus of the
979 application can still be accessed without giving focus to
980 the main window. In this case, we want to disable the menu
981 entries that are buffer-related.
983 Note that this code is not perfect, as bug 1941 attests:
984 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
986 if (cmd.origin == FuncRequest::MENU && !hasFocus())
990 case LFUN_BUFFER_WRITE:
991 enable = buf && (buf->isUnnamed() || !buf->isClean());
994 case LFUN_BUFFER_WRITE_AS:
998 case LFUN_SPLIT_VIEW:
1002 case LFUN_CLOSE_TAB_GROUP:
1003 enable = d.currentTabWorkArea();
1006 case LFUN_TOOLBAR_TOGGLE:
1007 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1010 case LFUN_UI_TOGGLE:
1011 flag.setOnOff(isFullScreen());
1014 case LFUN_DIALOG_TOGGLE:
1015 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1016 // fall through to set "enable"
1017 case LFUN_DIALOG_SHOW: {
1018 string const name = cmd.getArg(0);
1020 enable = name == "aboutlyx"
1021 || name == "file" //FIXME: should be removed.
1023 || name == "texinfo";
1024 else if (name == "print")
1025 enable = buf->isExportable("dvi")
1026 && lyxrc.print_command != "none";
1027 else if (name == "character") {
1031 InsetCode ic = view()->cursor().inset().lyxCode();
1032 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1035 else if (name == "symbols") {
1036 if (!view() || view()->cursor().inMathed())
1039 InsetCode ic = view()->cursor().inset().lyxCode();
1040 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1043 else if (name == "latexlog")
1044 enable = FileName(buf->logName()).isReadableFile();
1045 else if (name == "spellchecker")
1046 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1047 enable = !buf->isReadonly();
1051 else if (name == "vclog")
1052 enable = buf->lyxvc().inUse();
1056 case LFUN_DIALOG_UPDATE: {
1057 string const name = cmd.getArg(0);
1059 enable = name == "prefs";
1063 case LFUN_INSET_APPLY: {
1068 string const name = cmd.getArg(0);
1069 Inset * inset = getOpenInset(name);
1071 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1073 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1074 // Every inset is supposed to handle this
1075 LASSERT(false, /**/);
1079 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1080 flag |= getStatus(fr);
1082 enable = flag.enabled();
1086 case LFUN_COMPLETION_INLINE:
1087 if (!d.current_work_area_
1088 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1092 case LFUN_COMPLETION_POPUP:
1093 if (!d.current_work_area_
1094 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1098 case LFUN_COMPLETION_COMPLETE:
1099 if (!d.current_work_area_
1100 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1112 flag.enabled(false);
1118 static FileName selectTemplateFile()
1120 FileDialog dlg(qt_("Select template file"));
1121 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1122 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1124 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1125 QStringList(qt_("LyX Documents (*.lyx)")));
1127 if (result.first == FileDialog::Later)
1129 if (result.second.isEmpty())
1131 return FileName(fromqstr(result.second));
1135 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1139 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1142 message(_("Document not loaded."));
1147 setBuffer(newBuffer);
1149 // scroll to the position when the file was last closed
1150 if (lyxrc.use_lastfilepos) {
1151 LastFilePosSection::FilePos filepos =
1152 LyX::ref().session().lastFilePos().load(filename);
1153 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1157 LyX::ref().session().lastFiles().add(filename);
1164 void GuiView::openDocument(string const & fname)
1166 string initpath = lyxrc.document_path;
1169 string const trypath = buffer()->filePath();
1170 // If directory is writeable, use this as default.
1171 if (FileName(trypath).isDirWritable())
1177 if (fname.empty()) {
1178 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1179 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1180 dlg.setButton2(qt_("Examples|#E#e"),
1181 toqstr(addPath(package().system_support().absFilename(), "examples")));
1183 FileDialog::Result result =
1184 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1186 if (result.first == FileDialog::Later)
1189 filename = fromqstr(result.second);
1191 // check selected filename
1192 if (filename.empty()) {
1193 message(_("Canceled."));
1199 // get absolute path of file and add ".lyx" to the filename if
1201 FileName const fullname =
1202 fileSearch(string(), filename, "lyx", support::may_not_exist);
1203 if (!fullname.empty())
1204 filename = fullname.absFilename();
1206 // if the file doesn't exist, let the user create one
1207 if (!fullname.exists()) {
1208 // the user specifically chose this name. Believe him.
1209 Buffer * const b = newFile(filename, string(), true);
1215 docstring const disp_fn = makeDisplayPath(filename);
1216 message(bformat(_("Opening document %1$s..."), disp_fn));
1219 Buffer * buf = loadDocument(fullname);
1224 buf->errors("Parse");
1225 str2 = bformat(_("Document %1$s opened."), disp_fn);
1227 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1232 // FIXME: clean that
1233 static bool import(GuiView * lv, FileName const & filename,
1234 string const & format, ErrorList & errorList)
1236 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1238 string loader_format;
1239 vector<string> loaders = theConverters().loaders();
1240 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1241 for (vector<string>::const_iterator it = loaders.begin();
1242 it != loaders.end(); ++it) {
1243 if (!theConverters().isReachable(format, *it))
1246 string const tofile =
1247 support::changeExtension(filename.absFilename(),
1248 formats.extension(*it));
1249 if (!theConverters().convert(0, filename, FileName(tofile),
1250 filename, format, *it, errorList))
1252 loader_format = *it;
1255 if (loader_format.empty()) {
1256 frontend::Alert::error(_("Couldn't import file"),
1257 bformat(_("No information for importing the format %1$s."),
1258 formats.prettyName(format)));
1262 loader_format = format;
1264 if (loader_format == "lyx") {
1265 Buffer * buf = lv->loadDocument(lyxfile);
1270 buf->errors("Parse");
1272 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1276 bool as_paragraphs = loader_format == "textparagraph";
1277 string filename2 = (loader_format == format) ? filename.absFilename()
1278 : support::changeExtension(filename.absFilename(),
1279 formats.extension(loader_format));
1280 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1281 theLyXFunc().setLyXView(lv);
1282 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1289 void GuiView::importDocument(string const & argument)
1292 string filename = split(argument, format, ' ');
1294 LYXERR(Debug::INFO, format << " file: " << filename);
1296 // need user interaction
1297 if (filename.empty()) {
1298 string initpath = lyxrc.document_path;
1300 Buffer const * buf = buffer();
1302 string const trypath = buf->filePath();
1303 // If directory is writeable, use this as default.
1304 if (FileName(trypath).isDirWritable())
1308 docstring const text = bformat(_("Select %1$s file to import"),
1309 formats.prettyName(format));
1311 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1312 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1313 dlg.setButton2(qt_("Examples|#E#e"),
1314 toqstr(addPath(package().system_support().absFilename(), "examples")));
1316 docstring filter = formats.prettyName(format);
1319 filter += from_utf8(formats.extension(format));
1322 FileDialog::Result result =
1323 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1325 if (result.first == FileDialog::Later)
1328 filename = fromqstr(result.second);
1330 // check selected filename
1331 if (filename.empty())
1332 message(_("Canceled."));
1335 if (filename.empty())
1338 // get absolute path of file
1339 FileName const fullname(support::makeAbsPath(filename));
1341 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1343 // Check if the document already is open
1344 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1347 if (!closeBuffer()) {
1348 message(_("Canceled."));
1353 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1355 // if the file exists already, and we didn't do
1356 // -i lyx thefile.lyx, warn
1357 if (lyxfile.exists() && fullname != lyxfile) {
1359 docstring text = bformat(_("The document %1$s already exists.\n\n"
1360 "Do you want to overwrite that document?"), displaypath);
1361 int const ret = Alert::prompt(_("Overwrite document?"),
1362 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1365 message(_("Canceled."));
1370 message(bformat(_("Importing %1$s..."), displaypath));
1371 ErrorList errorList;
1372 if (import(this, fullname, format, errorList))
1373 message(_("imported."));
1375 message(_("file not imported!"));
1377 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1381 void GuiView::newDocument(string const & filename, bool from_template)
1383 FileName initpath(lyxrc.document_path);
1384 Buffer * buf = buffer();
1386 FileName const trypath(buf->filePath());
1387 // If directory is writeable, use this as default.
1388 if (trypath.isDirWritable())
1392 string templatefile = from_template ?
1393 selectTemplateFile().absFilename() : string();
1395 if (filename.empty())
1396 b = newUnnamedFile(templatefile, initpath);
1398 b = newFile(filename, templatefile, true);
1402 // Ensure the cursor is correctly positionned on screen.
1403 view()->showCursor();
1407 void GuiView::insertLyXFile(docstring const & fname)
1409 BufferView * bv = view();
1414 FileName filename(to_utf8(fname));
1416 if (!filename.empty()) {
1417 bv->insertLyXFile(filename);
1421 // Launch a file browser
1423 string initpath = lyxrc.document_path;
1424 string const trypath = bv->buffer().filePath();
1425 // If directory is writeable, use this as default.
1426 if (FileName(trypath).isDirWritable())
1430 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1431 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1432 dlg.setButton2(qt_("Examples|#E#e"),
1433 toqstr(addPath(package().system_support().absFilename(),
1436 FileDialog::Result result = dlg.open(toqstr(initpath),
1437 QStringList(qt_("LyX Documents (*.lyx)")));
1439 if (result.first == FileDialog::Later)
1443 filename.set(fromqstr(result.second));
1445 // check selected filename
1446 if (filename.empty()) {
1447 // emit message signal.
1448 message(_("Canceled."));
1452 bv->insertLyXFile(filename);
1456 void GuiView::insertPlaintextFile(docstring const & fname,
1459 BufferView * bv = view();
1464 FileName filename(to_utf8(fname));
1466 if (!filename.empty()) {
1467 bv->insertPlaintextFile(filename, asParagraph);
1471 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1472 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1474 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1477 if (result.first == FileDialog::Later)
1481 filename.set(fromqstr(result.second));
1483 // check selected filename
1484 if (filename.empty()) {
1485 // emit message signal.
1486 message(_("Canceled."));
1490 bv->insertPlaintextFile(filename, asParagraph);
1494 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1496 FileName fname = b.fileName();
1497 FileName const oldname = fname;
1499 if (!newname.empty()) {
1501 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1503 // Switch to this Buffer.
1506 /// No argument? Ask user through dialog.
1508 FileDialog dlg(qt_("Choose a filename to save document as"),
1509 LFUN_BUFFER_WRITE_AS);
1510 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1511 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1513 if (!isLyXFilename(fname.absFilename()))
1514 fname.changeExtension(".lyx");
1516 FileDialog::Result result =
1517 dlg.save(toqstr(fname.onlyPath().absFilename()),
1518 QStringList(qt_("LyX Documents (*.lyx)")),
1519 toqstr(fname.onlyFileName()));
1521 if (result.first == FileDialog::Later)
1524 fname.set(fromqstr(result.second));
1529 if (!isLyXFilename(fname.absFilename()))
1530 fname.changeExtension(".lyx");
1533 if (FileName(fname).exists()) {
1534 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1535 docstring text = bformat(_("The document %1$s already "
1536 "exists.\n\nDo you want to "
1537 "overwrite that document?"),
1539 int const ret = Alert::prompt(_("Overwrite document?"),
1540 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1543 case 1: return renameBuffer(b, docstring());
1544 case 2: return false;
1548 // Ok, change the name of the buffer
1549 b.setFileName(fname.absFilename());
1551 bool unnamed = b.isUnnamed();
1552 b.setUnnamed(false);
1553 b.saveCheckSum(fname);
1555 if (!saveBuffer(b)) {
1556 b.setFileName(oldname.absFilename());
1557 b.setUnnamed(unnamed);
1558 b.saveCheckSum(oldname);
1566 bool GuiView::saveBuffer(Buffer & b)
1569 return renameBuffer(b, docstring());
1572 LyX::ref().session().lastFiles().add(b.fileName());
1576 // Switch to this Buffer.
1579 // FIXME: we don't tell the user *WHY* the save failed !!
1580 docstring const file = makeDisplayPath(b.absFileName(), 30);
1581 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1582 "Do you want to rename the document and "
1583 "try again?"), file);
1584 int const ret = Alert::prompt(_("Rename and save?"),
1585 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1588 if (!renameBuffer(b, docstring()))
1597 return saveBuffer(b);
1601 bool GuiView::closeBuffer()
1603 Buffer * buf = buffer();
1604 return buf && closeBuffer(*buf);
1608 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1610 // goto bookmark to update bookmark pit.
1611 //FIXME: we should update only the bookmarks related to this buffer!
1612 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1613 theLyXFunc().gotoBookmark(i+1, false, false);
1615 if (buf.isClean() || buf.paragraphs().empty()) {
1616 if (buf.masterBuffer() == &buf && tolastopened)
1617 LyX::ref().session().lastOpened().add(buf.fileName());
1618 theBufferList().release(&buf);
1621 // Switch to this Buffer.
1626 if (buf.isUnnamed())
1627 file = from_utf8(buf.fileName().onlyFileName());
1629 file = buf.fileName().displayName(30);
1631 // Bring this window to top before asking questions.
1635 docstring const text = bformat(_("The document %1$s has unsaved changes."
1636 "\n\nDo you want to save the document or discard the changes?"), file);
1637 int const ret = Alert::prompt(_("Save changed document?"),
1638 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1642 if (!saveBuffer(buf))
1646 // if we crash after this we could
1647 // have no autosave file but I guess
1648 // this is really improbable (Jug)
1649 removeAutosaveFile(buf.absFileName());
1655 // save file names to .lyx/session
1656 // if master/slave are both open, do not save slave since it
1657 // will be automatically loaded when the master is loaded
1658 if (buf.masterBuffer() == &buf && tolastopened)
1659 LyX::ref().session().lastOpened().add(buf.fileName());
1661 theBufferList().release(&buf);
1666 bool GuiView::dispatch(FuncRequest const & cmd)
1668 BufferView * bv = view();
1669 // By default we won't need any update.
1671 bv->cursor().updateFlags(Update::None);
1673 switch(cmd.action) {
1674 case LFUN_BUFFER_IMPORT:
1675 importDocument(to_utf8(cmd.argument()));
1678 case LFUN_BUFFER_SWITCH:
1679 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1682 case LFUN_BUFFER_NEXT:
1683 setBuffer(theBufferList().next(buffer()));
1686 case LFUN_BUFFER_PREVIOUS:
1687 setBuffer(theBufferList().previous(buffer()));
1690 case LFUN_COMMAND_EXECUTE: {
1691 bool const show_it = cmd.argument() != "off";
1692 d.toolbars_->showCommandBuffer(show_it);
1695 case LFUN_DROP_LAYOUTS_CHOICE:
1697 d.layout_->showPopup();
1700 case LFUN_MENU_OPEN:
1701 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1702 menu->exec(QCursor::pos());
1705 case LFUN_FILE_INSERT:
1706 insertLyXFile(cmd.argument());
1708 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1709 insertPlaintextFile(cmd.argument(), true);
1712 case LFUN_FILE_INSERT_PLAINTEXT:
1713 insertPlaintextFile(cmd.argument(), false);
1716 case LFUN_BUFFER_WRITE:
1718 saveBuffer(bv->buffer());
1721 case LFUN_BUFFER_WRITE_AS:
1723 renameBuffer(bv->buffer(), cmd.argument());
1726 case LFUN_BUFFER_WRITE_ALL: {
1727 Buffer * first = theBufferList().first();
1730 message(_("Saving all documents..."));
1731 // We cannot use a for loop as the buffer list cycles.
1734 if (!b->isClean()) {
1736 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1738 b = theBufferList().next(b);
1739 } while (b != first);
1740 message(_("All documents saved."));
1744 case LFUN_TOOLBAR_TOGGLE: {
1745 string const name = cmd.getArg(0);
1746 bool const allowauto = cmd.getArg(1) == "allowauto";
1747 // it is possible to get current toolbar status like this,...
1748 // but I decide to obey the order of ToolbarBackend::flags
1749 // and disregard real toolbar status.
1750 // toolbars_->saveToolbarInfo();
1752 // toggle state on/off/auto
1753 d.toolbars_->toggleToolbarState(name, allowauto);
1757 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1759 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1763 if (tbi->flags & ToolbarInfo::ON)
1765 else if (tbi->flags & ToolbarInfo::OFF)
1767 else if (tbi->flags & ToolbarInfo::AUTO)
1770 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1771 _(tbi->gui_name), state));
1775 case LFUN_DIALOG_UPDATE: {
1776 string const name = to_utf8(cmd.argument());
1777 // Can only update a dialog connected to an existing inset
1778 Inset * inset = getOpenInset(name);
1780 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1781 inset->dispatch(view()->cursor(), fr);
1782 } else if (name == "paragraph") {
1783 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1784 } else if (name == "prefs") {
1785 updateDialog(name, string());
1790 case LFUN_DIALOG_TOGGLE: {
1791 if (isDialogVisible(cmd.getArg(0)))
1792 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1794 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1798 case LFUN_DIALOG_DISCONNECT_INSET:
1799 disconnectDialog(to_utf8(cmd.argument()));
1802 case LFUN_DIALOG_HIDE: {
1803 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1807 case LFUN_DIALOG_SHOW: {
1808 string const name = cmd.getArg(0);
1809 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1811 if (name == "character") {
1812 data = freefont2string();
1814 showDialog("character", data);
1815 } else if (name == "latexlog") {
1816 Buffer::LogType type;
1817 string const logfile = buffer()->logName(&type);
1819 case Buffer::latexlog:
1822 case Buffer::buildlog:
1826 data += Lexer::quoteString(logfile);
1827 showDialog("log", data);
1828 } else if (name == "vclog") {
1829 string const data = "vc " +
1830 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1831 showDialog("log", data);
1832 } else if (name == "symbols") {
1833 data = bv->cursor().getEncoding()->name();
1835 showDialog("symbols", data);
1837 showDialog(name, data);
1841 case LFUN_INSET_APPLY: {
1842 string const name = cmd.getArg(0);
1843 Inset * inset = getOpenInset(name);
1845 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1846 inset->dispatch(view()->cursor(), fr);
1848 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1854 case LFUN_UI_TOGGLE:
1856 // Make sure the keyboard focus stays in the work area.
1860 case LFUN_COMPLETION_INLINE:
1861 if (d.current_work_area_)
1862 d.current_work_area_->completer().showInline();
1865 case LFUN_SPLIT_VIEW:
1866 if (Buffer * buf = buffer()) {
1867 string const orientation = cmd.getArg(0);
1868 d.splitter_->setOrientation(orientation == "vertical"
1869 ? Qt::Vertical : Qt::Horizontal);
1870 TabWorkArea * twa = addTabWorkArea();
1871 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1872 setCurrentWorkArea(wa);
1876 case LFUN_CLOSE_TAB_GROUP:
1877 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1879 twa = d.currentTabWorkArea();
1880 // Switch to the next GuiWorkArea in the found TabWorkArea.
1881 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1882 if (d.splitter_->count() == 0)
1883 // No more work area, switch to the background widget.
1888 case LFUN_COMPLETION_POPUP:
1889 if (d.current_work_area_)
1890 d.current_work_area_->completer().showPopup();
1894 case LFUN_COMPLETION_COMPLETE:
1895 if (d.current_work_area_)
1896 d.current_work_area_->completer().tab();
1907 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1909 string const arg = cmd.getArg(0);
1910 if (arg == "scrollbar") {
1911 // hide() is of no help
1912 if (d.current_work_area_->verticalScrollBarPolicy() ==
1913 Qt::ScrollBarAlwaysOff)
1915 d.current_work_area_->setVerticalScrollBarPolicy(
1916 Qt::ScrollBarAsNeeded);
1918 d.current_work_area_->setVerticalScrollBarPolicy(
1919 Qt::ScrollBarAlwaysOff);
1922 if (arg == "statusbar") {
1923 statusBar()->setVisible(!statusBar()->isVisible());
1926 if (arg == "menubar") {
1927 menuBar()->setVisible(!menuBar()->isVisible());
1930 #if QT_VERSION >= 0x040300
1931 if (arg == "frame") {
1933 getContentsMargins(&l, &t, &r, &b);
1934 //are the frames in default state?
1935 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1937 setContentsMargins(-2, -2, -2, -2);
1939 setContentsMargins(0, 0, 0, 0);
1944 if (arg != "fullscreen") {
1945 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1949 if (lyxrc.full_screen_toolbars)
1950 d.toolbars_->toggleFullScreen(!isFullScreen());
1952 if (isFullScreen()) {
1953 for (int i = 0; i != d.splitter_->count(); ++i)
1954 d.tabWorkArea(i)->setFullScreen(false);
1955 #if QT_VERSION >= 0x040300
1956 setContentsMargins(0, 0, 0, 0);
1958 setWindowState(windowState() ^ Qt::WindowFullScreen);
1960 statusBar()->show();
1962 for (int i = 0; i != d.splitter_->count(); ++i)
1963 d.tabWorkArea(i)->setFullScreen(true);
1964 #if QT_VERSION >= 0x040300
1965 setContentsMargins(-2, -2, -2, -2);
1967 setWindowState(windowState() ^ Qt::WindowFullScreen);
1968 statusBar()->hide();
1974 Buffer const * GuiView::updateInset(Inset const * inset)
1976 if (!d.current_work_area_)
1980 d.current_work_area_->scheduleRedraw();
1982 return &d.current_work_area_->bufferView().buffer();
1986 void GuiView::restartCursor()
1988 /* When we move around, or type, it's nice to be able to see
1989 * the cursor immediately after the keypress.
1991 if (d.current_work_area_)
1992 d.current_work_area_->startBlinkingCursor();
1994 // Take this occasion to update the other GUI elements.
1999 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2001 if (d.current_work_area_)
2002 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2007 // This list should be kept in sync with the list of insets in
2008 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2009 // dialog should have the same name as the inset.
2011 char const * const dialognames[] = {
2012 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2013 "citation", "document", "errorlist", "ert", "external", "file",
2014 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2015 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2016 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2018 #ifdef HAVE_LIBAIKSAURUS
2022 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2024 char const * const * const end_dialognames =
2025 dialognames + (sizeof(dialognames) / sizeof(char *));
2029 cmpCStr(char const * name) : name_(name) {}
2030 bool operator()(char const * other) {
2031 return strcmp(other, name_) == 0;
2038 bool isValidName(string const & name)
2040 return find_if(dialognames, end_dialognames,
2041 cmpCStr(name.c_str())) != end_dialognames;
2047 void GuiView::resetDialogs()
2049 // Make sure that no LFUN uses any LyXView.
2050 theLyXFunc().setLyXView(0);
2051 // FIXME: the "math panels" toolbar takes an awful lot of time to
2052 // initialise so we don't do that for the time being.
2053 //d.toolbars_->init();
2054 guiApp->menus().fillMenuBar(menuBar(), this);
2056 d.layout_->updateContents(true);
2057 // Now update controls with current buffer.
2058 theLyXFunc().setLyXView(this);
2063 Dialog * GuiView::find_or_build(string const & name)
2065 if (!isValidName(name))
2068 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2070 if (it != d.dialogs_.end())
2071 return it->second.get();
2073 Dialog * dialog = build(name);
2074 d.dialogs_[name].reset(dialog);
2075 if (lyxrc.allow_geometry_session)
2076 dialog->restoreSession();
2081 void GuiView::showDialog(string const & name, string const & data,
2088 Dialog * dialog = find_or_build(name);
2090 dialog->showData(data);
2092 d.open_insets_[name] = inset;
2098 bool GuiView::isDialogVisible(string const & name) const
2100 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2101 if (it == d.dialogs_.end())
2103 return it->second.get()->isVisibleView();
2107 void GuiView::hideDialog(string const & name, Inset * inset)
2109 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2110 if (it == d.dialogs_.end())
2113 if (inset && inset != getOpenInset(name))
2116 Dialog * const dialog = it->second.get();
2117 if (dialog->isVisibleView())
2119 d.open_insets_[name] = 0;
2123 void GuiView::disconnectDialog(string const & name)
2125 if (!isValidName(name))
2128 if (d.open_insets_.find(name) != d.open_insets_.end())
2129 d.open_insets_[name] = 0;
2133 Inset * GuiView::getOpenInset(string const & name) const
2135 if (!isValidName(name))
2138 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2139 return it == d.open_insets_.end() ? 0 : it->second;
2143 void GuiView::hideAll() const
2145 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2146 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2148 for(; it != end; ++it)
2149 it->second->hideView();
2153 void GuiView::updateDialogs()
2155 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2156 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2158 for(; it != end; ++it) {
2159 Dialog * dialog = it->second.get();
2160 if (dialog && dialog->isVisibleView())
2161 dialog->checkStatus();
2169 // will be replaced by a proper factory...
2170 Dialog * createGuiAbout(GuiView & lv);
2171 Dialog * createGuiBibitem(GuiView & lv);
2172 Dialog * createGuiBibtex(GuiView & lv);
2173 Dialog * createGuiBox(GuiView & lv);
2174 Dialog * createGuiBranch(GuiView & lv);
2175 Dialog * createGuiChanges(GuiView & lv);
2176 Dialog * createGuiCharacter(GuiView & lv);
2177 Dialog * createGuiCitation(GuiView & lv);
2178 Dialog * createGuiDelimiter(GuiView & lv);
2179 Dialog * createGuiDocument(GuiView & lv);
2180 Dialog * createGuiErrorList(GuiView & lv);
2181 Dialog * createGuiERT(GuiView & lv);
2182 Dialog * createGuiExternal(GuiView & lv);
2183 Dialog * createGuiFloat(GuiView & lv);
2184 Dialog * createGuiGraphics(GuiView & lv);
2185 Dialog * createGuiHSpace(GuiView & lv);
2186 Dialog * createGuiInclude(GuiView & lv);
2187 Dialog * createGuiLabel(GuiView & lv);
2188 Dialog * createGuiListings(GuiView & lv);
2189 Dialog * createGuiLog(GuiView & lv);
2190 Dialog * createGuiMathMatrix(GuiView & lv);
2191 Dialog * createGuiNomenclature(GuiView & lv);
2192 Dialog * createGuiNote(GuiView & lv);
2193 Dialog * createGuiParagraph(GuiView & lv);
2194 Dialog * createGuiPreferences(GuiView & lv);
2195 Dialog * createGuiPrint(GuiView & lv);
2196 Dialog * createGuiRef(GuiView & lv);
2197 Dialog * createGuiSearch(GuiView & lv);
2198 Dialog * createGuiSendTo(GuiView & lv);
2199 Dialog * createGuiShowFile(GuiView & lv);
2200 Dialog * createGuiSpellchecker(GuiView & lv);
2201 Dialog * createGuiSymbols(GuiView & lv);
2202 Dialog * createGuiTabularCreate(GuiView & lv);
2203 Dialog * createGuiTabular(GuiView & lv);
2204 Dialog * createGuiTexInfo(GuiView & lv);
2205 Dialog * createGuiToc(GuiView & lv);
2206 Dialog * createGuiThesaurus(GuiView & lv);
2207 Dialog * createGuiHyperlink(GuiView & lv);
2208 Dialog * createGuiVSpace(GuiView & lv);
2209 Dialog * createGuiViewSource(GuiView & lv);
2210 Dialog * createGuiWrap(GuiView & lv);
2213 Dialog * GuiView::build(string const & name)
2215 LASSERT(isValidName(name), /**/);
2217 if (name == "aboutlyx")
2218 return createGuiAbout(*this);
2219 if (name == "bibitem")
2220 return createGuiBibitem(*this);
2221 if (name == "bibtex")
2222 return createGuiBibtex(*this);
2224 return createGuiBox(*this);
2225 if (name == "branch")
2226 return createGuiBranch(*this);
2227 if (name == "changes")
2228 return createGuiChanges(*this);
2229 if (name == "character")
2230 return createGuiCharacter(*this);
2231 if (name == "citation")
2232 return createGuiCitation(*this);
2233 if (name == "document")
2234 return createGuiDocument(*this);
2235 if (name == "errorlist")
2236 return createGuiErrorList(*this);
2238 return createGuiERT(*this);
2239 if (name == "external")
2240 return createGuiExternal(*this);
2242 return createGuiShowFile(*this);
2243 if (name == "findreplace")
2244 return createGuiSearch(*this);
2245 if (name == "float")
2246 return createGuiFloat(*this);
2247 if (name == "graphics")
2248 return createGuiGraphics(*this);
2249 if (name == "include")
2250 return createGuiInclude(*this);
2251 if (name == "nomenclature")
2252 return createGuiNomenclature(*this);
2253 if (name == "label")
2254 return createGuiLabel(*this);
2256 return createGuiLog(*this);
2257 if (name == "view-source")
2258 return createGuiViewSource(*this);
2259 if (name == "mathdelimiter")
2260 return createGuiDelimiter(*this);
2261 if (name == "mathmatrix")
2262 return createGuiMathMatrix(*this);
2264 return createGuiNote(*this);
2265 if (name == "paragraph")
2266 return createGuiParagraph(*this);
2267 if (name == "prefs")
2268 return createGuiPreferences(*this);
2269 if (name == "print")
2270 return createGuiPrint(*this);
2272 return createGuiRef(*this);
2273 if (name == "sendto")
2274 return createGuiSendTo(*this);
2275 if (name == "space")
2276 return createGuiHSpace(*this);
2277 if (name == "spellchecker")
2278 return createGuiSpellchecker(*this);
2279 if (name == "symbols")
2280 return createGuiSymbols(*this);
2281 if (name == "tabular")
2282 return createGuiTabular(*this);
2283 if (name == "tabularcreate")
2284 return createGuiTabularCreate(*this);
2285 if (name == "texinfo")
2286 return createGuiTexInfo(*this);
2287 #ifdef HAVE_LIBAIKSAURUS
2288 if (name == "thesaurus")
2289 return createGuiThesaurus(*this);
2292 return createGuiToc(*this);
2294 return createGuiHyperlink(*this);
2295 if (name == "vspace")
2296 return createGuiVSpace(*this);
2298 return createGuiWrap(*this);
2299 if (name == "listings")
2300 return createGuiListings(*this);
2306 } // namespace frontend
2309 #include "GuiView_moc.cpp"