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 // The document settings needs to be reinitialised.
554 updateDialog("document", "");
556 // Buffer-dependent dialogs must be updated. This is done here because
557 // some dialogs require buffer()->text.
562 void GuiView::on_lastWorkAreaRemoved()
565 // On Mac close the view if there is no Tab open anymore,
566 // but only if no splitter is visible
567 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
568 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
569 if (twa && twa->count() == 0) {
570 // close the view, as no tab is open anymore
571 QTimer::singleShot(0, this, SLOT(close()));
576 // The document settings needs to be reinitialised.
577 updateDialog("document", "");
583 void GuiView::updateStatusBar()
585 // let the user see the explicit message
586 if (d.statusbar_timer_.isActive())
589 theLyXFunc().setLyXView(this);
590 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
594 bool GuiView::hasFocus() const
596 return qApp->activeWindow() == this;
600 bool GuiView::event(QEvent * e)
604 // Useful debug code:
605 //case QEvent::ActivationChange:
606 //case QEvent::WindowDeactivate:
607 //case QEvent::Paint:
608 //case QEvent::Enter:
609 //case QEvent::Leave:
610 //case QEvent::HoverEnter:
611 //case QEvent::HoverLeave:
612 //case QEvent::HoverMove:
613 //case QEvent::StatusTip:
614 //case QEvent::DragEnter:
615 //case QEvent::DragLeave:
619 case QEvent::WindowActivate: {
620 if (this == guiApp->currentView()) {
622 return QMainWindow::event(e);
624 guiApp->setCurrentView(this);
625 if (d.current_work_area_) {
626 BufferView & bv = d.current_work_area_->bufferView();
627 connectBufferView(bv);
628 connectBuffer(bv.buffer());
629 // The document structure, name and dialogs might have
630 // changed in another view.
632 // The document settings needs to be reinitialised.
633 updateDialog("document", "");
636 setWindowTitle(qt_("LyX"));
637 setWindowIconText(qt_("LyX"));
640 return QMainWindow::event(e);
643 case QEvent::ShortcutOverride: {
644 if (d.current_work_area_)
645 // Nothing special to do.
646 return QMainWindow::event(e);
648 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
650 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
652 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
653 || ke->key() == Qt::Key_Backtab)
654 return QMainWindow::event(e);
656 // Allow processing of shortcuts that are allowed even when no Buffer
658 theLyXFunc().setLyXView(this);
660 setKeySymbol(&sym, ke);
661 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
667 return QMainWindow::event(e);
672 bool GuiView::focusNextPrevChild(bool /*next*/)
679 void GuiView::setBusy(bool busy)
681 if (d.current_work_area_) {
682 d.current_work_area_->setUpdatesEnabled(!busy);
684 d.current_work_area_->stopBlinkingCursor();
686 d.current_work_area_->startBlinkingCursor();
690 QApplication::setOverrideCursor(Qt::WaitCursor);
692 QApplication::restoreOverrideCursor();
696 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
698 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
700 if (tbinfo.flags & ToolbarInfo::TOP) {
702 addToolBarBreak(Qt::TopToolBarArea);
703 addToolBar(Qt::TopToolBarArea, toolBar);
706 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
707 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
708 #if (QT_VERSION >= 0x040202)
710 addToolBarBreak(Qt::BottomToolBarArea);
712 addToolBar(Qt::BottomToolBarArea, toolBar);
715 if (tbinfo.flags & ToolbarInfo::LEFT) {
716 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
717 #if (QT_VERSION >= 0x040202)
719 addToolBarBreak(Qt::LeftToolBarArea);
721 addToolBar(Qt::LeftToolBarArea, toolBar);
724 if (tbinfo.flags & ToolbarInfo::RIGHT) {
725 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
726 #if (QT_VERSION >= 0x040202)
728 addToolBarBreak(Qt::RightToolBarArea);
730 addToolBar(Qt::RightToolBarArea, toolBar);
733 // The following does not work so I cannot restore to exact toolbar location
735 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
736 toolBar->move(tbinfo.posx, tbinfo.posy);
743 GuiWorkArea * GuiView::workArea(Buffer & buffer)
745 if (TabWorkArea * twa = d.currentTabWorkArea())
746 return twa->workArea(buffer);
751 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
753 // Automatically create a TabWorkArea if there are none yet.
754 TabWorkArea * tab_widget = d.splitter_->count()
755 ? d.currentTabWorkArea() : addTabWorkArea();
756 return tab_widget->addWorkArea(buffer, *this);
760 TabWorkArea * GuiView::addTabWorkArea()
762 TabWorkArea * twa = new TabWorkArea;
763 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
764 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
765 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
766 this, SLOT(on_lastWorkAreaRemoved()));
768 d.splitter_->addWidget(twa);
769 d.stack_widget_->setCurrentWidget(d.splitter_);
774 GuiWorkArea const * GuiView::currentWorkArea() const
776 return d.current_work_area_;
780 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
783 d.current_work_area_ = wa;
784 for (int i = 0; i != d.splitter_->count(); ++i) {
785 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
791 void GuiView::removeWorkArea(GuiWorkArea * wa)
794 if (wa == d.current_work_area_) {
796 disconnectBufferView();
797 d.current_work_area_ = 0;
800 for (int i = 0; i != d.splitter_->count(); ++i) {
801 TabWorkArea * twa = d.tabWorkArea(i);
802 if (!twa->removeWorkArea(wa))
803 // Not found in this tab group.
806 // We found and removed the GuiWorkArea.
808 // No more WorkAreas in this tab group, so delete it.
813 if (d.current_work_area_)
814 // This means that we are not closing the current GuiWorkArea;
817 // Switch to the next GuiWorkArea in the found TabWorkArea.
818 d.current_work_area_ = twa->currentWorkArea();
822 if (d.splitter_->count() == 0)
823 // No more work area, switch to the background widget.
828 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
834 void GuiView::updateLayoutList()
837 d.layout_->updateContents(false);
841 void GuiView::updateToolbars()
843 if (d.current_work_area_) {
845 d.current_work_area_->bufferView().cursor().inMathed();
847 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
849 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
850 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
851 bool const mathmacrotemplate =
852 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
854 d.toolbars_->update(math, table, review, mathmacrotemplate);
856 d.toolbars_->update(false, false, false, false);
860 Buffer * GuiView::buffer()
862 if (d.current_work_area_)
863 return &d.current_work_area_->bufferView().buffer();
868 Buffer const * GuiView::buffer() const
870 if (d.current_work_area_)
871 return &d.current_work_area_->bufferView().buffer();
876 void GuiView::setBuffer(Buffer * newBuffer)
878 LASSERT(newBuffer, /**/);
881 GuiWorkArea * wa = workArea(*newBuffer);
883 updateLabels(*newBuffer->masterBuffer());
884 wa = addWorkArea(*newBuffer);
886 //Disconnect the old buffer...there's no new one.
889 connectBuffer(*newBuffer);
890 connectBufferView(wa->bufferView());
891 setCurrentWorkArea(wa);
897 void GuiView::connectBuffer(Buffer & buf)
899 buf.setGuiDelegate(this);
903 void GuiView::disconnectBuffer()
905 if (d.current_work_area_)
906 d.current_work_area_->bufferView().setGuiDelegate(0);
910 void GuiView::connectBufferView(BufferView & bv)
912 bv.setGuiDelegate(this);
916 void GuiView::disconnectBufferView()
918 if (d.current_work_area_)
919 d.current_work_area_->bufferView().setGuiDelegate(0);
923 void GuiView::errors(string const & error_type)
925 ErrorList & el = buffer()->errorList(error_type);
927 showDialog("errorlist", error_type);
931 void GuiView::structureChanged()
933 d.toc_models_.reset(view());
934 // Navigator needs more than a simple update in this case. It needs to be
936 updateDialog("toc", "");
940 void GuiView::updateDialog(string const & name, string const & data)
942 if (!isDialogVisible(name))
945 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
946 if (it == d.dialogs_.end())
949 Dialog * const dialog = it->second.get();
950 if (dialog->isVisibleView())
951 dialog->initialiseParams(data);
955 BufferView * GuiView::view()
957 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
961 void GuiView::autoSave()
963 LYXERR(Debug::INFO, "Running autoSave()");
966 view()->buffer().autoSave();
970 void GuiView::resetAutosaveTimers()
973 d.autosave_timeout_.restart();
977 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
981 Buffer * buf = buffer();
983 /* In LyX/Mac, when a dialog is open, the menus of the
984 application can still be accessed without giving focus to
985 the main window. In this case, we want to disable the menu
986 entries that are buffer-related.
988 Note that this code is not perfect, as bug 1941 attests:
989 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
991 if (cmd.origin == FuncRequest::MENU && !hasFocus())
995 case LFUN_BUFFER_WRITE:
996 enable = buf && (buf->isUnnamed() || !buf->isClean());
999 case LFUN_BUFFER_WRITE_AS:
1003 case LFUN_SPLIT_VIEW:
1007 case LFUN_CLOSE_TAB_GROUP:
1008 enable = d.currentTabWorkArea();
1011 case LFUN_TOOLBAR_TOGGLE:
1012 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1015 case LFUN_UI_TOGGLE:
1016 flag.setOnOff(isFullScreen());
1019 case LFUN_DIALOG_TOGGLE:
1020 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1021 // fall through to set "enable"
1022 case LFUN_DIALOG_SHOW: {
1023 string const name = cmd.getArg(0);
1025 enable = name == "aboutlyx"
1026 || name == "file" //FIXME: should be removed.
1028 || name == "texinfo";
1029 else if (name == "print")
1030 enable = buf->isExportable("dvi")
1031 && lyxrc.print_command != "none";
1032 else if (name == "character") {
1036 InsetCode ic = view()->cursor().inset().lyxCode();
1037 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1040 else if (name == "symbols") {
1041 if (!view() || view()->cursor().inMathed())
1044 InsetCode ic = view()->cursor().inset().lyxCode();
1045 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1048 else if (name == "latexlog")
1049 enable = FileName(buf->logName()).isReadableFile();
1050 else if (name == "spellchecker")
1051 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1052 enable = !buf->isReadonly();
1056 else if (name == "vclog")
1057 enable = buf->lyxvc().inUse();
1061 case LFUN_DIALOG_UPDATE: {
1062 string const name = cmd.getArg(0);
1064 enable = name == "prefs";
1068 case LFUN_INSET_APPLY: {
1073 string const name = cmd.getArg(0);
1074 Inset * inset = getOpenInset(name);
1076 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1078 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1079 // Every inset is supposed to handle this
1080 LASSERT(false, /**/);
1084 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1085 flag |= getStatus(fr);
1087 enable = flag.enabled();
1091 case LFUN_COMPLETION_INLINE:
1092 if (!d.current_work_area_
1093 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1097 case LFUN_COMPLETION_POPUP:
1098 if (!d.current_work_area_
1099 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1103 case LFUN_COMPLETION_COMPLETE:
1104 if (!d.current_work_area_
1105 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1117 flag.enabled(false);
1123 static FileName selectTemplateFile()
1125 FileDialog dlg(qt_("Select template file"));
1126 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1127 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1129 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1130 QStringList(qt_("LyX Documents (*.lyx)")));
1132 if (result.first == FileDialog::Later)
1134 if (result.second.isEmpty())
1136 return FileName(fromqstr(result.second));
1140 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1144 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1147 message(_("Document not loaded."));
1152 setBuffer(newBuffer);
1154 // scroll to the position when the file was last closed
1155 if (lyxrc.use_lastfilepos) {
1156 LastFilePosSection::FilePos filepos =
1157 LyX::ref().session().lastFilePos().load(filename);
1158 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1162 LyX::ref().session().lastFiles().add(filename);
1169 void GuiView::openDocument(string const & fname)
1171 string initpath = lyxrc.document_path;
1174 string const trypath = buffer()->filePath();
1175 // If directory is writeable, use this as default.
1176 if (FileName(trypath).isDirWritable())
1182 if (fname.empty()) {
1183 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1184 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1185 dlg.setButton2(qt_("Examples|#E#e"),
1186 toqstr(addPath(package().system_support().absFilename(), "examples")));
1188 FileDialog::Result result =
1189 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1191 if (result.first == FileDialog::Later)
1194 filename = fromqstr(result.second);
1196 // check selected filename
1197 if (filename.empty()) {
1198 message(_("Canceled."));
1204 // get absolute path of file and add ".lyx" to the filename if
1206 FileName const fullname =
1207 fileSearch(string(), filename, "lyx", support::may_not_exist);
1208 if (!fullname.empty())
1209 filename = fullname.absFilename();
1211 // if the file doesn't exist, let the user create one
1212 if (!fullname.exists()) {
1213 // the user specifically chose this name. Believe him.
1214 Buffer * const b = newFile(filename, string(), true);
1220 docstring const disp_fn = makeDisplayPath(filename);
1221 message(bformat(_("Opening document %1$s..."), disp_fn));
1224 Buffer * buf = loadDocument(fullname);
1229 buf->errors("Parse");
1230 str2 = bformat(_("Document %1$s opened."), disp_fn);
1232 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1237 // FIXME: clean that
1238 static bool import(GuiView * lv, FileName const & filename,
1239 string const & format, ErrorList & errorList)
1241 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1243 string loader_format;
1244 vector<string> loaders = theConverters().loaders();
1245 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1246 for (vector<string>::const_iterator it = loaders.begin();
1247 it != loaders.end(); ++it) {
1248 if (!theConverters().isReachable(format, *it))
1251 string const tofile =
1252 support::changeExtension(filename.absFilename(),
1253 formats.extension(*it));
1254 if (!theConverters().convert(0, filename, FileName(tofile),
1255 filename, format, *it, errorList))
1257 loader_format = *it;
1260 if (loader_format.empty()) {
1261 frontend::Alert::error(_("Couldn't import file"),
1262 bformat(_("No information for importing the format %1$s."),
1263 formats.prettyName(format)));
1267 loader_format = format;
1269 if (loader_format == "lyx") {
1270 Buffer * buf = lv->loadDocument(lyxfile);
1275 buf->errors("Parse");
1277 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1281 bool as_paragraphs = loader_format == "textparagraph";
1282 string filename2 = (loader_format == format) ? filename.absFilename()
1283 : support::changeExtension(filename.absFilename(),
1284 formats.extension(loader_format));
1285 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1286 theLyXFunc().setLyXView(lv);
1287 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1294 void GuiView::importDocument(string const & argument)
1297 string filename = split(argument, format, ' ');
1299 LYXERR(Debug::INFO, format << " file: " << filename);
1301 // need user interaction
1302 if (filename.empty()) {
1303 string initpath = lyxrc.document_path;
1305 Buffer const * buf = buffer();
1307 string const trypath = buf->filePath();
1308 // If directory is writeable, use this as default.
1309 if (FileName(trypath).isDirWritable())
1313 docstring const text = bformat(_("Select %1$s file to import"),
1314 formats.prettyName(format));
1316 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1317 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1318 dlg.setButton2(qt_("Examples|#E#e"),
1319 toqstr(addPath(package().system_support().absFilename(), "examples")));
1321 docstring filter = formats.prettyName(format);
1324 filter += from_utf8(formats.extension(format));
1327 FileDialog::Result result =
1328 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1330 if (result.first == FileDialog::Later)
1333 filename = fromqstr(result.second);
1335 // check selected filename
1336 if (filename.empty())
1337 message(_("Canceled."));
1340 if (filename.empty())
1343 // get absolute path of file
1344 FileName const fullname(support::makeAbsPath(filename));
1346 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1348 // Check if the document already is open
1349 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1352 if (!closeBuffer()) {
1353 message(_("Canceled."));
1358 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1360 // if the file exists already, and we didn't do
1361 // -i lyx thefile.lyx, warn
1362 if (lyxfile.exists() && fullname != lyxfile) {
1364 docstring text = bformat(_("The document %1$s already exists.\n\n"
1365 "Do you want to overwrite that document?"), displaypath);
1366 int const ret = Alert::prompt(_("Overwrite document?"),
1367 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1370 message(_("Canceled."));
1375 message(bformat(_("Importing %1$s..."), displaypath));
1376 ErrorList errorList;
1377 if (import(this, fullname, format, errorList))
1378 message(_("imported."));
1380 message(_("file not imported!"));
1382 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1386 void GuiView::newDocument(string const & filename, bool from_template)
1388 FileName initpath(lyxrc.document_path);
1389 Buffer * buf = buffer();
1391 FileName const trypath(buf->filePath());
1392 // If directory is writeable, use this as default.
1393 if (trypath.isDirWritable())
1397 string templatefile = from_template ?
1398 selectTemplateFile().absFilename() : string();
1400 if (filename.empty())
1401 b = newUnnamedFile(templatefile, initpath);
1403 b = newFile(filename, templatefile, true);
1407 // Ensure the cursor is correctly positionned on screen.
1408 view()->showCursor();
1412 void GuiView::insertLyXFile(docstring const & fname)
1414 BufferView * bv = view();
1419 FileName filename(to_utf8(fname));
1421 if (!filename.empty()) {
1422 bv->insertLyXFile(filename);
1426 // Launch a file browser
1428 string initpath = lyxrc.document_path;
1429 string const trypath = bv->buffer().filePath();
1430 // If directory is writeable, use this as default.
1431 if (FileName(trypath).isDirWritable())
1435 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1436 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1437 dlg.setButton2(qt_("Examples|#E#e"),
1438 toqstr(addPath(package().system_support().absFilename(),
1441 FileDialog::Result result = dlg.open(toqstr(initpath),
1442 QStringList(qt_("LyX Documents (*.lyx)")));
1444 if (result.first == FileDialog::Later)
1448 filename.set(fromqstr(result.second));
1450 // check selected filename
1451 if (filename.empty()) {
1452 // emit message signal.
1453 message(_("Canceled."));
1457 bv->insertLyXFile(filename);
1461 void GuiView::insertPlaintextFile(docstring const & fname,
1464 BufferView * bv = view();
1469 FileName filename(to_utf8(fname));
1471 if (!filename.empty()) {
1472 bv->insertPlaintextFile(filename, asParagraph);
1476 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1477 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1479 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1482 if (result.first == FileDialog::Later)
1486 filename.set(fromqstr(result.second));
1488 // check selected filename
1489 if (filename.empty()) {
1490 // emit message signal.
1491 message(_("Canceled."));
1495 bv->insertPlaintextFile(filename, asParagraph);
1499 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1501 FileName fname = b.fileName();
1502 FileName const oldname = fname;
1504 if (!newname.empty()) {
1506 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1508 // Switch to this Buffer.
1511 /// No argument? Ask user through dialog.
1513 FileDialog dlg(qt_("Choose a filename to save document as"),
1514 LFUN_BUFFER_WRITE_AS);
1515 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1516 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1518 if (!isLyXFilename(fname.absFilename()))
1519 fname.changeExtension(".lyx");
1521 FileDialog::Result result =
1522 dlg.save(toqstr(fname.onlyPath().absFilename()),
1523 QStringList(qt_("LyX Documents (*.lyx)")),
1524 toqstr(fname.onlyFileName()));
1526 if (result.first == FileDialog::Later)
1529 fname.set(fromqstr(result.second));
1534 if (!isLyXFilename(fname.absFilename()))
1535 fname.changeExtension(".lyx");
1538 if (FileName(fname).exists()) {
1539 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1540 docstring text = bformat(_("The document %1$s already "
1541 "exists.\n\nDo you want to "
1542 "overwrite that document?"),
1544 int const ret = Alert::prompt(_("Overwrite document?"),
1545 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1548 case 1: return renameBuffer(b, docstring());
1549 case 2: return false;
1553 // Ok, change the name of the buffer
1554 b.setFileName(fname.absFilename());
1556 bool unnamed = b.isUnnamed();
1557 b.setUnnamed(false);
1558 b.saveCheckSum(fname);
1560 if (!saveBuffer(b)) {
1561 b.setFileName(oldname.absFilename());
1562 b.setUnnamed(unnamed);
1563 b.saveCheckSum(oldname);
1571 bool GuiView::saveBuffer(Buffer & b)
1574 return renameBuffer(b, docstring());
1577 LyX::ref().session().lastFiles().add(b.fileName());
1581 // Switch to this Buffer.
1584 // FIXME: we don't tell the user *WHY* the save failed !!
1585 docstring const file = makeDisplayPath(b.absFileName(), 30);
1586 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1587 "Do you want to rename the document and "
1588 "try again?"), file);
1589 int const ret = Alert::prompt(_("Rename and save?"),
1590 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1593 if (!renameBuffer(b, docstring()))
1602 return saveBuffer(b);
1606 bool GuiView::closeBuffer()
1608 Buffer * buf = buffer();
1609 return buf && closeBuffer(*buf);
1613 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1615 // goto bookmark to update bookmark pit.
1616 //FIXME: we should update only the bookmarks related to this buffer!
1617 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1618 theLyXFunc().gotoBookmark(i+1, false, false);
1620 if (buf.isClean() || buf.paragraphs().empty()) {
1621 if (buf.masterBuffer() == &buf && tolastopened)
1622 LyX::ref().session().lastOpened().add(buf.fileName());
1623 theBufferList().release(&buf);
1626 // Switch to this Buffer.
1631 if (buf.isUnnamed())
1632 file = from_utf8(buf.fileName().onlyFileName());
1634 file = buf.fileName().displayName(30);
1636 // Bring this window to top before asking questions.
1640 docstring const text = bformat(_("The document %1$s has unsaved changes."
1641 "\n\nDo you want to save the document or discard the changes?"), file);
1642 int const ret = Alert::prompt(_("Save changed document?"),
1643 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1647 if (!saveBuffer(buf))
1651 // if we crash after this we could
1652 // have no autosave file but I guess
1653 // this is really improbable (Jug)
1654 removeAutosaveFile(buf.absFileName());
1660 // save file names to .lyx/session
1661 // if master/slave are both open, do not save slave since it
1662 // will be automatically loaded when the master is loaded
1663 if (buf.masterBuffer() == &buf && tolastopened)
1664 LyX::ref().session().lastOpened().add(buf.fileName());
1666 theBufferList().release(&buf);
1671 bool GuiView::dispatch(FuncRequest const & cmd)
1673 BufferView * bv = view();
1674 // By default we won't need any update.
1676 bv->cursor().updateFlags(Update::None);
1678 switch(cmd.action) {
1679 case LFUN_BUFFER_IMPORT:
1680 importDocument(to_utf8(cmd.argument()));
1683 case LFUN_BUFFER_SWITCH:
1684 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1687 case LFUN_BUFFER_NEXT:
1688 setBuffer(theBufferList().next(buffer()));
1691 case LFUN_BUFFER_PREVIOUS:
1692 setBuffer(theBufferList().previous(buffer()));
1695 case LFUN_COMMAND_EXECUTE: {
1696 bool const show_it = cmd.argument() != "off";
1697 d.toolbars_->showCommandBuffer(show_it);
1700 case LFUN_DROP_LAYOUTS_CHOICE:
1702 d.layout_->showPopup();
1705 case LFUN_MENU_OPEN:
1706 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1707 menu->exec(QCursor::pos());
1710 case LFUN_FILE_INSERT:
1711 insertLyXFile(cmd.argument());
1713 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1714 insertPlaintextFile(cmd.argument(), true);
1717 case LFUN_FILE_INSERT_PLAINTEXT:
1718 insertPlaintextFile(cmd.argument(), false);
1721 case LFUN_BUFFER_WRITE:
1723 saveBuffer(bv->buffer());
1726 case LFUN_BUFFER_WRITE_AS:
1728 renameBuffer(bv->buffer(), cmd.argument());
1731 case LFUN_BUFFER_WRITE_ALL: {
1732 Buffer * first = theBufferList().first();
1735 message(_("Saving all documents..."));
1736 // We cannot use a for loop as the buffer list cycles.
1739 if (!b->isClean()) {
1741 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1743 b = theBufferList().next(b);
1744 } while (b != first);
1745 message(_("All documents saved."));
1749 case LFUN_TOOLBAR_TOGGLE: {
1750 string const name = cmd.getArg(0);
1751 bool const allowauto = cmd.getArg(1) == "allowauto";
1752 // it is possible to get current toolbar status like this,...
1753 // but I decide to obey the order of ToolbarBackend::flags
1754 // and disregard real toolbar status.
1755 // toolbars_->saveToolbarInfo();
1757 // toggle state on/off/auto
1758 d.toolbars_->toggleToolbarState(name, allowauto);
1762 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1764 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1768 if (tbi->flags & ToolbarInfo::ON)
1770 else if (tbi->flags & ToolbarInfo::OFF)
1772 else if (tbi->flags & ToolbarInfo::AUTO)
1775 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1776 _(tbi->gui_name), state));
1780 case LFUN_DIALOG_UPDATE: {
1781 string const name = to_utf8(cmd.argument());
1782 // Can only update a dialog connected to an existing inset
1783 Inset * inset = getOpenInset(name);
1785 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1786 inset->dispatch(view()->cursor(), fr);
1787 } else if (name == "paragraph") {
1788 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1789 } else if (name == "prefs") {
1790 updateDialog(name, string());
1795 case LFUN_DIALOG_TOGGLE: {
1796 if (isDialogVisible(cmd.getArg(0)))
1797 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1799 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1803 case LFUN_DIALOG_DISCONNECT_INSET:
1804 disconnectDialog(to_utf8(cmd.argument()));
1807 case LFUN_DIALOG_HIDE: {
1808 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1812 case LFUN_DIALOG_SHOW: {
1813 string const name = cmd.getArg(0);
1814 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1816 if (name == "character") {
1817 data = freefont2string();
1819 showDialog("character", data);
1820 } else if (name == "latexlog") {
1821 Buffer::LogType type;
1822 string const logfile = buffer()->logName(&type);
1824 case Buffer::latexlog:
1827 case Buffer::buildlog:
1831 data += Lexer::quoteString(logfile);
1832 showDialog("log", data);
1833 } else if (name == "vclog") {
1834 string const data = "vc " +
1835 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1836 showDialog("log", data);
1837 } else if (name == "symbols") {
1838 data = bv->cursor().getEncoding()->name();
1840 showDialog("symbols", data);
1842 showDialog(name, data);
1846 case LFUN_INSET_APPLY: {
1847 view()->cursor().recordUndoFullDocument();
1848 string const name = cmd.getArg(0);
1849 Inset * inset = getOpenInset(name);
1851 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1852 inset->dispatch(view()->cursor(), fr);
1854 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1860 case LFUN_UI_TOGGLE:
1862 // Make sure the keyboard focus stays in the work area.
1866 case LFUN_COMPLETION_INLINE:
1867 if (d.current_work_area_)
1868 d.current_work_area_->completer().showInline();
1871 case LFUN_SPLIT_VIEW:
1872 if (Buffer * buf = buffer()) {
1873 string const orientation = cmd.getArg(0);
1874 d.splitter_->setOrientation(orientation == "vertical"
1875 ? Qt::Vertical : Qt::Horizontal);
1876 TabWorkArea * twa = addTabWorkArea();
1877 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1878 setCurrentWorkArea(wa);
1882 case LFUN_CLOSE_TAB_GROUP:
1883 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1885 twa = d.currentTabWorkArea();
1886 // Switch to the next GuiWorkArea in the found TabWorkArea.
1887 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1888 if (d.splitter_->count() == 0)
1889 // No more work area, switch to the background widget.
1894 case LFUN_COMPLETION_POPUP:
1895 if (d.current_work_area_)
1896 d.current_work_area_->completer().showPopup();
1900 case LFUN_COMPLETION_COMPLETE:
1901 if (d.current_work_area_)
1902 d.current_work_area_->completer().tab();
1913 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1915 string const arg = cmd.getArg(0);
1916 if (arg == "scrollbar") {
1917 // hide() is of no help
1918 if (d.current_work_area_->verticalScrollBarPolicy() ==
1919 Qt::ScrollBarAlwaysOff)
1921 d.current_work_area_->setVerticalScrollBarPolicy(
1922 Qt::ScrollBarAsNeeded);
1924 d.current_work_area_->setVerticalScrollBarPolicy(
1925 Qt::ScrollBarAlwaysOff);
1928 if (arg == "statusbar") {
1929 statusBar()->setVisible(!statusBar()->isVisible());
1932 if (arg == "menubar") {
1933 menuBar()->setVisible(!menuBar()->isVisible());
1936 #if QT_VERSION >= 0x040300
1937 if (arg == "frame") {
1939 getContentsMargins(&l, &t, &r, &b);
1940 //are the frames in default state?
1941 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1943 setContentsMargins(-2, -2, -2, -2);
1945 setContentsMargins(0, 0, 0, 0);
1950 if (arg != "fullscreen") {
1951 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1955 if (lyxrc.full_screen_toolbars)
1956 d.toolbars_->toggleFullScreen(!isFullScreen());
1958 if (isFullScreen()) {
1959 for (int i = 0; i != d.splitter_->count(); ++i)
1960 d.tabWorkArea(i)->setFullScreen(false);
1961 #if QT_VERSION >= 0x040300
1962 setContentsMargins(0, 0, 0, 0);
1964 setWindowState(windowState() ^ Qt::WindowFullScreen);
1966 statusBar()->show();
1968 for (int i = 0; i != d.splitter_->count(); ++i)
1969 d.tabWorkArea(i)->setFullScreen(true);
1970 #if QT_VERSION >= 0x040300
1971 setContentsMargins(-2, -2, -2, -2);
1973 setWindowState(windowState() ^ Qt::WindowFullScreen);
1974 statusBar()->hide();
1980 Buffer const * GuiView::updateInset(Inset const * inset)
1982 if (!d.current_work_area_)
1986 d.current_work_area_->scheduleRedraw();
1988 return &d.current_work_area_->bufferView().buffer();
1992 void GuiView::restartCursor()
1994 /* When we move around, or type, it's nice to be able to see
1995 * the cursor immediately after the keypress.
1997 if (d.current_work_area_)
1998 d.current_work_area_->startBlinkingCursor();
2000 // Take this occasion to update the other GUI elements.
2005 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2007 if (d.current_work_area_)
2008 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2013 // This list should be kept in sync with the list of insets in
2014 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2015 // dialog should have the same name as the inset.
2017 char const * const dialognames[] = {
2018 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2019 "citation", "document", "errorlist", "ert", "external", "file",
2020 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2021 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2022 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2024 #ifdef HAVE_LIBAIKSAURUS
2028 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2030 char const * const * const end_dialognames =
2031 dialognames + (sizeof(dialognames) / sizeof(char *));
2035 cmpCStr(char const * name) : name_(name) {}
2036 bool operator()(char const * other) {
2037 return strcmp(other, name_) == 0;
2044 bool isValidName(string const & name)
2046 return find_if(dialognames, end_dialognames,
2047 cmpCStr(name.c_str())) != end_dialognames;
2053 void GuiView::resetDialogs()
2055 // Make sure that no LFUN uses any LyXView.
2056 theLyXFunc().setLyXView(0);
2057 // FIXME: the "math panels" toolbar takes an awful lot of time to
2058 // initialise so we don't do that for the time being.
2059 //d.toolbars_->init();
2060 guiApp->menus().fillMenuBar(menuBar(), this);
2062 d.layout_->updateContents(true);
2063 // Now update controls with current buffer.
2064 theLyXFunc().setLyXView(this);
2069 Dialog * GuiView::find_or_build(string const & name)
2071 if (!isValidName(name))
2074 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2076 if (it != d.dialogs_.end())
2077 return it->second.get();
2079 Dialog * dialog = build(name);
2080 d.dialogs_[name].reset(dialog);
2081 if (lyxrc.allow_geometry_session)
2082 dialog->restoreSession();
2087 void GuiView::showDialog(string const & name, string const & data,
2094 Dialog * dialog = find_or_build(name);
2096 dialog->showData(data);
2098 d.open_insets_[name] = inset;
2104 bool GuiView::isDialogVisible(string const & name) const
2106 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2107 if (it == d.dialogs_.end())
2109 return it->second.get()->isVisibleView();
2113 void GuiView::hideDialog(string const & name, Inset * inset)
2115 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2116 if (it == d.dialogs_.end())
2119 if (inset && inset != getOpenInset(name))
2122 Dialog * const dialog = it->second.get();
2123 if (dialog->isVisibleView())
2125 d.open_insets_[name] = 0;
2129 void GuiView::disconnectDialog(string const & name)
2131 if (!isValidName(name))
2134 if (d.open_insets_.find(name) != d.open_insets_.end())
2135 d.open_insets_[name] = 0;
2139 Inset * GuiView::getOpenInset(string const & name) const
2141 if (!isValidName(name))
2144 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2145 return it == d.open_insets_.end() ? 0 : it->second;
2149 void GuiView::hideAll() const
2151 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2152 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2154 for(; it != end; ++it)
2155 it->second->hideView();
2159 void GuiView::updateDialogs()
2161 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2162 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2164 for(; it != end; ++it) {
2165 Dialog * dialog = it->second.get();
2166 if (dialog && dialog->isVisibleView())
2167 dialog->checkStatus();
2175 // will be replaced by a proper factory...
2176 Dialog * createGuiAbout(GuiView & lv);
2177 Dialog * createGuiBibitem(GuiView & lv);
2178 Dialog * createGuiBibtex(GuiView & lv);
2179 Dialog * createGuiBox(GuiView & lv);
2180 Dialog * createGuiBranch(GuiView & lv);
2181 Dialog * createGuiChanges(GuiView & lv);
2182 Dialog * createGuiCharacter(GuiView & lv);
2183 Dialog * createGuiCitation(GuiView & lv);
2184 Dialog * createGuiDelimiter(GuiView & lv);
2185 Dialog * createGuiDocument(GuiView & lv);
2186 Dialog * createGuiErrorList(GuiView & lv);
2187 Dialog * createGuiERT(GuiView & lv);
2188 Dialog * createGuiExternal(GuiView & lv);
2189 Dialog * createGuiFloat(GuiView & lv);
2190 Dialog * createGuiGraphics(GuiView & lv);
2191 Dialog * createGuiHSpace(GuiView & lv);
2192 Dialog * createGuiInclude(GuiView & lv);
2193 Dialog * createGuiLabel(GuiView & lv);
2194 Dialog * createGuiListings(GuiView & lv);
2195 Dialog * createGuiLog(GuiView & lv);
2196 Dialog * createGuiMathMatrix(GuiView & lv);
2197 Dialog * createGuiNomenclature(GuiView & lv);
2198 Dialog * createGuiNote(GuiView & lv);
2199 Dialog * createGuiParagraph(GuiView & lv);
2200 Dialog * createGuiPreferences(GuiView & lv);
2201 Dialog * createGuiPrint(GuiView & lv);
2202 Dialog * createGuiRef(GuiView & lv);
2203 Dialog * createGuiSearch(GuiView & lv);
2204 Dialog * createGuiSendTo(GuiView & lv);
2205 Dialog * createGuiShowFile(GuiView & lv);
2206 Dialog * createGuiSpellchecker(GuiView & lv);
2207 Dialog * createGuiSymbols(GuiView & lv);
2208 Dialog * createGuiTabularCreate(GuiView & lv);
2209 Dialog * createGuiTabular(GuiView & lv);
2210 Dialog * createGuiTexInfo(GuiView & lv);
2211 Dialog * createGuiToc(GuiView & lv);
2212 Dialog * createGuiThesaurus(GuiView & lv);
2213 Dialog * createGuiHyperlink(GuiView & lv);
2214 Dialog * createGuiVSpace(GuiView & lv);
2215 Dialog * createGuiViewSource(GuiView & lv);
2216 Dialog * createGuiWrap(GuiView & lv);
2219 Dialog * GuiView::build(string const & name)
2221 LASSERT(isValidName(name), /**/);
2223 if (name == "aboutlyx")
2224 return createGuiAbout(*this);
2225 if (name == "bibitem")
2226 return createGuiBibitem(*this);
2227 if (name == "bibtex")
2228 return createGuiBibtex(*this);
2230 return createGuiBox(*this);
2231 if (name == "branch")
2232 return createGuiBranch(*this);
2233 if (name == "changes")
2234 return createGuiChanges(*this);
2235 if (name == "character")
2236 return createGuiCharacter(*this);
2237 if (name == "citation")
2238 return createGuiCitation(*this);
2239 if (name == "document")
2240 return createGuiDocument(*this);
2241 if (name == "errorlist")
2242 return createGuiErrorList(*this);
2244 return createGuiERT(*this);
2245 if (name == "external")
2246 return createGuiExternal(*this);
2248 return createGuiShowFile(*this);
2249 if (name == "findreplace")
2250 return createGuiSearch(*this);
2251 if (name == "float")
2252 return createGuiFloat(*this);
2253 if (name == "graphics")
2254 return createGuiGraphics(*this);
2255 if (name == "include")
2256 return createGuiInclude(*this);
2257 if (name == "nomenclature")
2258 return createGuiNomenclature(*this);
2259 if (name == "label")
2260 return createGuiLabel(*this);
2262 return createGuiLog(*this);
2263 if (name == "view-source")
2264 return createGuiViewSource(*this);
2265 if (name == "mathdelimiter")
2266 return createGuiDelimiter(*this);
2267 if (name == "mathmatrix")
2268 return createGuiMathMatrix(*this);
2270 return createGuiNote(*this);
2271 if (name == "paragraph")
2272 return createGuiParagraph(*this);
2273 if (name == "prefs")
2274 return createGuiPreferences(*this);
2275 if (name == "print")
2276 return createGuiPrint(*this);
2278 return createGuiRef(*this);
2279 if (name == "sendto")
2280 return createGuiSendTo(*this);
2281 if (name == "space")
2282 return createGuiHSpace(*this);
2283 if (name == "spellchecker")
2284 return createGuiSpellchecker(*this);
2285 if (name == "symbols")
2286 return createGuiSymbols(*this);
2287 if (name == "tabular")
2288 return createGuiTabular(*this);
2289 if (name == "tabularcreate")
2290 return createGuiTabularCreate(*this);
2291 if (name == "texinfo")
2292 return createGuiTexInfo(*this);
2293 #ifdef HAVE_LIBAIKSAURUS
2294 if (name == "thesaurus")
2295 return createGuiThesaurus(*this);
2298 return createGuiToc(*this);
2300 return createGuiHyperlink(*this);
2301 if (name == "vspace")
2302 return createGuiVSpace(*this);
2304 return createGuiWrap(*this);
2305 if (name == "listings")
2306 return createGuiListings(*this);
2312 } // namespace frontend
2315 #include "GuiView_moc.cpp"