3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiCompleter.h"
22 #include "GuiWorkArea.h"
23 #include "GuiKeySymbol.h"
24 #include "GuiToolbar.h"
25 #include "GuiToolbars.h"
29 #include "qt_helpers.h"
31 #include "frontends/alert.h"
33 #include "buffer_funcs.h"
35 #include "BufferList.h"
36 #include "BufferParams.h"
37 #include "BufferView.h"
38 #include "Converter.h"
41 #include "ErrorList.h"
43 #include "FuncStatus.h"
44 #include "FuncRequest.h"
52 #include "Paragraph.h"
53 #include "TextClass.h"
55 #include "ToolbarBackend.h"
58 #include "support/lassert.h"
59 #include "support/debug.h"
60 #include "support/FileName.h"
61 #include "support/filetools.h"
62 #include "support/gettext.h"
63 #include "support/ForkedCalls.h"
64 #include "support/lstrings.h"
65 #include "support/os.h"
66 #include "support/Package.h"
67 #include "support/Timeout.h"
70 #include <QApplication>
71 #include <QCloseEvent>
73 #include <QDesktopWidget>
74 #include <QDragEnterEvent>
82 #include <QPushButton>
86 #include <QStackedWidget>
93 #include <boost/bind.hpp>
95 #ifdef HAVE_SYS_TIME_H
96 # include <sys/time.h>
103 using namespace lyx::support;
110 class BackgroundWidget : public QWidget
115 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
116 /// The text to be written on top of the pixmap
117 QString const text = lyx_version ?
118 qt_("version ") + lyx_version : qt_("unknown version");
119 splash_ = QPixmap(":/images/banner.png");
121 QPainter pain(&splash_);
122 pain.setPen(QColor(0, 0, 0));
124 // The font used to display the version info
125 font.setStyleHint(QFont::SansSerif);
126 font.setWeight(QFont::Bold);
127 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
129 pain.drawText(190, 225, text);
132 void paintEvent(QPaintEvent *)
134 int x = (width() - splash_.width()) / 2;
135 int y = (height() - splash_.height()) / 2;
137 pain.drawPixmap(x, y, splash_);
147 typedef boost::shared_ptr<Dialog> DialogPtr;
149 struct GuiView::GuiViewPrivate
152 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
155 // hardcode here the platform specific icon size
156 smallIconSize = 14; // scaling problems
157 normalIconSize = 20; // ok, default
158 bigIconSize = 26; // better for some math icons
160 splitter_ = new QSplitter;
161 bg_widget_ = new BackgroundWidget;
162 stack_widget_ = new QStackedWidget;
163 stack_widget_->addWidget(bg_widget_);
164 stack_widget_->addWidget(splitter_);
172 delete stack_widget_;
176 QMenu * toolBarPopup(GuiView * parent)
178 // FIXME: translation
179 QMenu * menu = new QMenu(parent);
180 QActionGroup * iconSizeGroup = new QActionGroup(parent);
182 QAction * smallIcons = new QAction(iconSizeGroup);
183 smallIcons->setText(qt_("Small-sized icons"));
184 smallIcons->setCheckable(true);
185 QObject::connect(smallIcons, SIGNAL(triggered()),
186 parent, SLOT(smallSizedIcons()));
187 menu->addAction(smallIcons);
189 QAction * normalIcons = new QAction(iconSizeGroup);
190 normalIcons->setText(qt_("Normal-sized icons"));
191 normalIcons->setCheckable(true);
192 QObject::connect(normalIcons, SIGNAL(triggered()),
193 parent, SLOT(normalSizedIcons()));
194 menu->addAction(normalIcons);
196 QAction * bigIcons = new QAction(iconSizeGroup);
197 bigIcons->setText(qt_("Big-sized icons"));
198 bigIcons->setCheckable(true);
199 QObject::connect(bigIcons, SIGNAL(triggered()),
200 parent, SLOT(bigSizedIcons()));
201 menu->addAction(bigIcons);
203 unsigned int cur = parent->iconSize().width();
204 if ( cur == parent->d.smallIconSize)
205 smallIcons->setChecked(true);
206 else if (cur == parent->d.normalIconSize)
207 normalIcons->setChecked(true);
208 else if (cur == parent->d.bigIconSize)
209 bigIcons->setChecked(true);
216 stack_widget_->setCurrentWidget(bg_widget_);
217 bg_widget_->setUpdatesEnabled(true);
220 TabWorkArea * tabWorkArea(int i)
222 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
225 TabWorkArea * currentTabWorkArea()
227 if (splitter_->count() == 1)
228 // The first TabWorkArea is always the first one, if any.
229 return tabWorkArea(0);
231 for (int i = 0; i != splitter_->count(); ++i) {
232 TabWorkArea * twa = tabWorkArea(i);
233 if (current_work_area_ == twa->currentWorkArea())
237 // None has the focus so we just take the first one.
238 return tabWorkArea(0);
242 GuiWorkArea * current_work_area_;
243 QSplitter * splitter_;
244 QStackedWidget * stack_widget_;
245 BackgroundWidget * bg_widget_;
247 GuiToolbars * toolbars_;
248 /// The main layout box.
250 * \warning Don't Delete! The layout box is actually owned by
251 * whichever toolbar contains it. All the GuiView class needs is a
252 * means of accessing it.
254 * FIXME: replace that with a proper model so that we are not limited
255 * to only one dialog.
257 GuiLayoutBox * layout_;
260 map<string, Inset *> open_insets_;
263 map<string, DialogPtr> dialogs_;
265 unsigned int smallIconSize;
266 unsigned int normalIconSize;
267 unsigned int bigIconSize;
269 QTimer statusbar_timer_;
270 /// auto-saving of buffers
271 Timeout autosave_timeout_;
272 /// flag against a race condition due to multiclicks, see bug #1119
276 TocModels toc_models_;
280 GuiView::GuiView(int id)
281 : d(*new GuiViewPrivate), id_(id)
283 // GuiToolbars *must* be initialised before the menu bar.
284 d.toolbars_ = new GuiToolbars(*this);
286 // set ourself as the current view. This is needed for the menu bar
287 // filling, at least for the static special menu item on Mac. Otherwise
288 // they are greyed out.
289 theLyXFunc().setLyXView(this);
291 // Fill up the menu bar.
292 guiApp->menus().fillMenuBar(menuBar(), this, true);
294 setCentralWidget(d.stack_widget_);
296 // Start autosave timer
297 if (lyxrc.autosave) {
298 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
299 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
300 d.autosave_timeout_.start();
302 connect(&d.statusbar_timer_, SIGNAL(timeout()),
303 this, SLOT(clearMessage()));
305 // We don't want to keep the window in memory if it is closed.
306 setAttribute(Qt::WA_DeleteOnClose, true);
308 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
309 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
310 // since the icon is provided in the application bundle.
311 setWindowIcon(QPixmap(":/images/lyx.png"));
315 setAcceptDrops(true);
317 statusBar()->setSizeGripEnabled(true);
319 // Forbid too small unresizable window because it can happen
320 // with some window manager under X11.
321 setMinimumSize(300, 200);
323 if (!lyxrc.allow_geometry_session)
324 // No session handling, default to a sane size.
325 setGeometry(50, 50, 690, 510);
327 // Now take care of session management.
329 QString const key = "view-" + QString::number(id_);
331 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
332 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
336 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
337 setGeometry(50, 50, 690, 510);
339 setIconSize(settings.value(key + "/icon_size").toSize());
345 if (guiApp->currentView() == this)
346 guiApp->setCurrentView(0);
347 theLyXFunc().setLyXView(0);
353 TocModels & GuiView::tocModels()
355 return d.toc_models_;
359 void GuiView::setFocus()
361 if (d.current_work_area_)
362 d.current_work_area_->setFocus();
368 QMenu * GuiView::createPopupMenu()
370 return d.toolBarPopup(this);
374 void GuiView::showEvent(QShowEvent * e)
376 LYXERR(Debug::GUI, "Passed Geometry "
377 << size().height() << "x" << size().width()
378 << "+" << pos().x() << "+" << pos().y());
380 if (d.splitter_->count() == 0)
381 // No work area, switch to the background widget.
384 QMainWindow::showEvent(e);
388 void GuiView::closeEvent(QCloseEvent * close_event)
390 // it can happen that this event arrives without selecting the view,
391 // e.g. when clicking the close button on a background window.
392 theLyXFunc().setLyXView(this);
394 while (Buffer * b = buffer()) {
396 // This is a child document, just close the tab after saving
397 // but keep the file loaded.
398 if (!saveBuffer(*b)) {
399 close_event->ignore();
402 removeWorkArea(d.current_work_area_);
406 std::vector<int> const & ids = guiApp->viewIds();
407 for (size_type i = 0; i != ids.size(); ++i) {
410 if (guiApp->view(ids[i]).workArea(*b)) {
411 // FIXME 1: should we put an alert box here that the buffer
412 // is viewed elsewhere?
413 // FIXME 2: should we try to save this buffer in any case?
416 // This buffer is also opened in another view, so
417 // but close the associated work area nevertheless.
418 removeWorkArea(d.current_work_area_);
419 // but don't close it.
424 if (b && !closeBuffer(*b, true)) {
425 close_event->ignore();
430 // Make sure that no LFUN use this close to be closed View.
431 theLyXFunc().setLyXView(0);
433 // Save toolbars configuration
434 if (isFullScreen()) {
435 d.toolbars_->toggleFullScreen(!isFullScreen());
439 // Make sure the timer time out will not trigger a statusbar update.
440 d.statusbar_timer_.stop();
442 // Saving fullscreen requires additional tweaks in the toolbar code.
443 // It wouldn't also work under linux natively.
444 if (lyxrc.allow_geometry_session && !isFullScreen()) {
446 QString const key = "view-" + QString::number(id_);
448 settings.setValue(key + "/pos", pos());
449 settings.setValue(key + "/size", size());
451 settings.setValue(key + "/geometry", saveGeometry());
453 settings.setValue(key + "/icon_size", iconSize());
454 d.toolbars_->saveToolbarInfo();
455 // Now take care of all other dialogs:
456 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
457 for (; it!= d.dialogs_.end(); ++it)
458 it->second->saveSession();
461 guiApp->unregisterView(id_);
462 close_event->accept();
466 void GuiView::dragEnterEvent(QDragEnterEvent * event)
468 if (event->mimeData()->hasUrls())
470 /// \todo Ask lyx-devel is this is enough:
471 /// if (event->mimeData()->hasFormat("text/plain"))
472 /// event->acceptProposedAction();
476 void GuiView::dropEvent(QDropEvent* event)
478 QList<QUrl> files = event->mimeData()->urls();
482 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
483 for (int i = 0; i != files.size(); ++i) {
484 string const file = os::internal_path(fromqstr(
485 files.at(i).toLocalFile()));
487 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
492 void GuiView::message(docstring const & str)
494 if (ForkedProcess::iAmAChild())
497 statusBar()->showMessage(toqstr(str));
498 d.statusbar_timer_.stop();
499 d.statusbar_timer_.start(3000);
503 void GuiView::smallSizedIcons()
505 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
509 void GuiView::normalSizedIcons()
511 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
515 void GuiView::bigSizedIcons()
517 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
521 void GuiView::clearMessage()
525 theLyXFunc().setLyXView(this);
526 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
527 d.statusbar_timer_.stop();
531 void GuiView::updateWindowTitle(GuiWorkArea * wa)
533 if (wa != d.current_work_area_)
535 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
536 setWindowIconText(wa->windowIconText());
540 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
543 disconnectBufferView();
544 connectBufferView(wa->bufferView());
545 connectBuffer(wa->bufferView().buffer());
546 d.current_work_area_ = wa;
547 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
548 this, SLOT(updateWindowTitle(GuiWorkArea *)));
549 updateWindowTitle(wa);
551 // Navigator needs more than a simple update in this case. It needs to be
555 // Buffer-dependent dialogs must be updated. This is done here because
556 // some dialogs require buffer()->text.
561 void GuiView::on_lastWorkAreaRemoved()
564 // On Mac close the view if there is no Tab open anymore,
565 // but only if no splitter is visible
566 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
567 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
568 if (twa && twa->count() == 0) {
569 // close the view, as no tab is open anymore
570 QTimer::singleShot(0, this, SLOT(close()));
580 void GuiView::updateStatusBar()
582 // let the user see the explicit message
583 if (d.statusbar_timer_.isActive())
586 theLyXFunc().setLyXView(this);
587 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
591 bool GuiView::hasFocus() const
593 return qApp->activeWindow() == this;
597 bool GuiView::event(QEvent * e)
601 // Useful debug code:
602 //case QEvent::ActivationChange:
603 //case QEvent::WindowDeactivate:
604 //case QEvent::Paint:
605 //case QEvent::Enter:
606 //case QEvent::Leave:
607 //case QEvent::HoverEnter:
608 //case QEvent::HoverLeave:
609 //case QEvent::HoverMove:
610 //case QEvent::StatusTip:
611 //case QEvent::DragEnter:
612 //case QEvent::DragLeave:
616 case QEvent::WindowActivate: {
617 if (this == guiApp->currentView()) {
619 return QMainWindow::event(e);
621 guiApp->setCurrentView(this);
622 if (d.current_work_area_) {
623 BufferView & bv = d.current_work_area_->bufferView();
624 connectBufferView(bv);
625 connectBuffer(bv.buffer());
626 // The document structure, name and dialogs might have
627 // changed in another view.
631 setWindowTitle(qt_("LyX"));
632 setWindowIconText(qt_("LyX"));
635 return QMainWindow::event(e);
638 case QEvent::ShortcutOverride: {
639 if (d.current_work_area_)
640 // Nothing special to do.
641 return QMainWindow::event(e);
643 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
645 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
647 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
648 || ke->key() == Qt::Key_Backtab)
649 return QMainWindow::event(e);
651 // Allow processing of shortcuts that are allowed even when no Buffer
653 theLyXFunc().setLyXView(this);
655 setKeySymbol(&sym, ke);
656 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
662 return QMainWindow::event(e);
667 bool GuiView::focusNextPrevChild(bool /*next*/)
674 void GuiView::setBusy(bool busy)
676 if (d.current_work_area_) {
677 d.current_work_area_->setUpdatesEnabled(!busy);
679 d.current_work_area_->stopBlinkingCursor();
681 d.current_work_area_->startBlinkingCursor();
685 QApplication::setOverrideCursor(Qt::WaitCursor);
687 QApplication::restoreOverrideCursor();
691 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
693 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
695 if (tbinfo.flags & ToolbarInfo::TOP) {
697 addToolBarBreak(Qt::TopToolBarArea);
698 addToolBar(Qt::TopToolBarArea, toolBar);
701 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
702 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
703 #if (QT_VERSION >= 0x040202)
705 addToolBarBreak(Qt::BottomToolBarArea);
707 addToolBar(Qt::BottomToolBarArea, toolBar);
710 if (tbinfo.flags & ToolbarInfo::LEFT) {
711 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
712 #if (QT_VERSION >= 0x040202)
714 addToolBarBreak(Qt::LeftToolBarArea);
716 addToolBar(Qt::LeftToolBarArea, toolBar);
719 if (tbinfo.flags & ToolbarInfo::RIGHT) {
720 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
721 #if (QT_VERSION >= 0x040202)
723 addToolBarBreak(Qt::RightToolBarArea);
725 addToolBar(Qt::RightToolBarArea, toolBar);
728 // The following does not work so I cannot restore to exact toolbar location
730 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
731 toolBar->move(tbinfo.posx, tbinfo.posy);
738 GuiWorkArea * GuiView::workArea(Buffer & buffer)
740 if (TabWorkArea * twa = d.currentTabWorkArea())
741 return twa->workArea(buffer);
746 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
748 // Automatically create a TabWorkArea if there are none yet.
749 TabWorkArea * tab_widget = d.splitter_->count()
750 ? d.currentTabWorkArea() : addTabWorkArea();
751 return tab_widget->addWorkArea(buffer, *this);
755 TabWorkArea * GuiView::addTabWorkArea()
757 TabWorkArea * twa = new TabWorkArea;
758 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
759 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
760 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
761 this, SLOT(on_lastWorkAreaRemoved()));
763 d.splitter_->addWidget(twa);
764 d.stack_widget_->setCurrentWidget(d.splitter_);
769 GuiWorkArea const * GuiView::currentWorkArea() const
771 return d.current_work_area_;
775 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
778 d.current_work_area_ = wa;
779 for (int i = 0; i != d.splitter_->count(); ++i) {
780 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
786 void GuiView::removeWorkArea(GuiWorkArea * wa)
789 if (wa == d.current_work_area_) {
791 disconnectBufferView();
792 d.current_work_area_ = 0;
795 for (int i = 0; i != d.splitter_->count(); ++i) {
796 TabWorkArea * twa = d.tabWorkArea(i);
797 if (!twa->removeWorkArea(wa))
798 // Not found in this tab group.
801 // We found and removed the GuiWorkArea.
803 // No more WorkAreas in this tab group, so delete it.
808 if (d.current_work_area_)
809 // This means that we are not closing the current GuiWorkArea;
812 // Switch to the next GuiWorkArea in the found TabWorkArea.
813 d.current_work_area_ = twa->currentWorkArea();
817 if (d.splitter_->count() == 0)
818 // No more work area, switch to the background widget.
823 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
829 void GuiView::updateLayoutList()
832 d.layout_->updateContents(false);
836 void GuiView::updateToolbars()
838 if (d.current_work_area_) {
840 d.current_work_area_->bufferView().cursor().inMathed();
842 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
844 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
845 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
846 bool const mathmacrotemplate =
847 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
849 d.toolbars_->update(math, table, review, mathmacrotemplate);
851 d.toolbars_->update(false, false, false, false);
855 Buffer * GuiView::buffer()
857 if (d.current_work_area_)
858 return &d.current_work_area_->bufferView().buffer();
863 Buffer const * GuiView::buffer() const
865 if (d.current_work_area_)
866 return &d.current_work_area_->bufferView().buffer();
871 void GuiView::setBuffer(Buffer * newBuffer)
873 LASSERT(newBuffer, /**/);
876 GuiWorkArea * wa = workArea(*newBuffer);
878 updateLabels(*newBuffer->masterBuffer());
879 wa = addWorkArea(*newBuffer);
881 //Disconnect the old buffer...there's no new one.
884 connectBuffer(*newBuffer);
885 connectBufferView(wa->bufferView());
886 setCurrentWorkArea(wa);
892 void GuiView::connectBuffer(Buffer & buf)
894 buf.setGuiDelegate(this);
898 void GuiView::disconnectBuffer()
900 if (d.current_work_area_)
901 d.current_work_area_->bufferView().setGuiDelegate(0);
905 void GuiView::connectBufferView(BufferView & bv)
907 bv.setGuiDelegate(this);
911 void GuiView::disconnectBufferView()
913 if (d.current_work_area_)
914 d.current_work_area_->bufferView().setGuiDelegate(0);
918 void GuiView::errors(string const & error_type)
920 ErrorList & el = buffer()->errorList(error_type);
922 showDialog("errorlist", error_type);
926 void GuiView::structureChanged()
928 d.toc_models_.reset(view());
929 updateDialog("toc", "");
933 void GuiView::updateDialog(string const & name, string const & data)
935 if (!isDialogVisible(name))
938 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
939 if (it == d.dialogs_.end())
942 Dialog * const dialog = it->second.get();
943 if (dialog->isVisibleView())
944 dialog->initialiseParams(data);
948 BufferView * GuiView::view()
950 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
954 void GuiView::autoSave()
956 LYXERR(Debug::INFO, "Running autoSave()");
959 view()->buffer().autoSave();
963 void GuiView::resetAutosaveTimers()
966 d.autosave_timeout_.restart();
970 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
974 Buffer * buf = buffer();
976 /* In LyX/Mac, when a dialog is open, the menus of the
977 application can still be accessed without giving focus to
978 the main window. In this case, we want to disable the menu
979 entries that are buffer-related.
981 Note that this code is not perfect, as bug 1941 attests:
982 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
984 if (cmd.origin == FuncRequest::MENU && !hasFocus())
988 case LFUN_BUFFER_WRITE:
989 enable = buf && (buf->isUnnamed() || !buf->isClean());
992 case LFUN_BUFFER_WRITE_AS:
996 case LFUN_SPLIT_VIEW:
1000 case LFUN_CLOSE_TAB_GROUP:
1001 enable = d.currentTabWorkArea();
1004 case LFUN_TOOLBAR_TOGGLE:
1005 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1008 case LFUN_UI_TOGGLE:
1009 flag.setOnOff(isFullScreen());
1012 case LFUN_DIALOG_TOGGLE:
1013 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1014 // fall through to set "enable"
1015 case LFUN_DIALOG_SHOW: {
1016 string const name = cmd.getArg(0);
1018 enable = name == "aboutlyx"
1019 || name == "file" //FIXME: should be removed.
1021 || name == "texinfo";
1022 else if (name == "print")
1023 enable = buf->isExportable("dvi")
1024 && lyxrc.print_command != "none";
1025 else if (name == "character") {
1029 InsetCode ic = view()->cursor().inset().lyxCode();
1030 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1033 else if (name == "symbols") {
1034 if (!view() || view()->cursor().inMathed())
1037 InsetCode ic = view()->cursor().inset().lyxCode();
1038 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1041 else if (name == "latexlog")
1042 enable = FileName(buf->logName()).isReadableFile();
1043 else if (name == "spellchecker")
1044 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1045 enable = !buf->isReadonly();
1049 else if (name == "vclog")
1050 enable = buf->lyxvc().inUse();
1054 case LFUN_DIALOG_UPDATE: {
1055 string const name = cmd.getArg(0);
1057 enable = name == "prefs";
1061 case LFUN_INSET_APPLY: {
1066 string const name = cmd.getArg(0);
1067 Inset * inset = getOpenInset(name);
1069 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1071 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1072 // Every inset is supposed to handle this
1073 LASSERT(false, /**/);
1077 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1078 flag |= getStatus(fr);
1080 enable = flag.enabled();
1084 case LFUN_COMPLETION_INLINE:
1085 if (!d.current_work_area_
1086 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1090 case LFUN_COMPLETION_POPUP:
1091 if (!d.current_work_area_
1092 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1096 case LFUN_COMPLETION_COMPLETE:
1097 if (!d.current_work_area_
1098 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1110 flag.enabled(false);
1116 static FileName selectTemplateFile()
1118 FileDialog dlg(qt_("Select template file"));
1119 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1120 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1122 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1123 QStringList(qt_("LyX Documents (*.lyx)")));
1125 if (result.first == FileDialog::Later)
1127 if (result.second.isEmpty())
1129 return FileName(fromqstr(result.second));
1133 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1137 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1140 message(_("Document not loaded."));
1145 setBuffer(newBuffer);
1147 // scroll to the position when the file was last closed
1148 if (lyxrc.use_lastfilepos) {
1149 LastFilePosSection::FilePos filepos =
1150 LyX::ref().session().lastFilePos().load(filename);
1151 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1155 LyX::ref().session().lastFiles().add(filename);
1162 void GuiView::openDocument(string const & fname)
1164 string initpath = lyxrc.document_path;
1167 string const trypath = buffer()->filePath();
1168 // If directory is writeable, use this as default.
1169 if (FileName(trypath).isDirWritable())
1175 if (fname.empty()) {
1176 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1177 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1178 dlg.setButton2(qt_("Examples|#E#e"),
1179 toqstr(addPath(package().system_support().absFilename(), "examples")));
1181 FileDialog::Result result =
1182 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1184 if (result.first == FileDialog::Later)
1187 filename = fromqstr(result.second);
1189 // check selected filename
1190 if (filename.empty()) {
1191 message(_("Canceled."));
1197 // get absolute path of file and add ".lyx" to the filename if
1199 FileName const fullname =
1200 fileSearch(string(), filename, "lyx", support::may_not_exist);
1201 if (!fullname.empty())
1202 filename = fullname.absFilename();
1204 // if the file doesn't exist, let the user create one
1205 if (!fullname.exists()) {
1206 // the user specifically chose this name. Believe him.
1207 Buffer * const b = newFile(filename, string(), true);
1213 docstring const disp_fn = makeDisplayPath(filename);
1214 message(bformat(_("Opening document %1$s..."), disp_fn));
1217 Buffer * buf = loadDocument(fullname);
1222 buf->errors("Parse");
1223 str2 = bformat(_("Document %1$s opened."), disp_fn);
1225 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1230 // FIXME: clean that
1231 static bool import(GuiView * lv, FileName const & filename,
1232 string const & format, ErrorList & errorList)
1234 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1236 string loader_format;
1237 vector<string> loaders = theConverters().loaders();
1238 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1239 for (vector<string>::const_iterator it = loaders.begin();
1240 it != loaders.end(); ++it) {
1241 if (!theConverters().isReachable(format, *it))
1244 string const tofile =
1245 support::changeExtension(filename.absFilename(),
1246 formats.extension(*it));
1247 if (!theConverters().convert(0, filename, FileName(tofile),
1248 filename, format, *it, errorList))
1250 loader_format = *it;
1253 if (loader_format.empty()) {
1254 frontend::Alert::error(_("Couldn't import file"),
1255 bformat(_("No information for importing the format %1$s."),
1256 formats.prettyName(format)));
1260 loader_format = format;
1262 if (loader_format == "lyx") {
1263 Buffer * buf = lv->loadDocument(lyxfile);
1268 buf->errors("Parse");
1270 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1274 bool as_paragraphs = loader_format == "textparagraph";
1275 string filename2 = (loader_format == format) ? filename.absFilename()
1276 : support::changeExtension(filename.absFilename(),
1277 formats.extension(loader_format));
1278 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1279 theLyXFunc().setLyXView(lv);
1280 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1287 void GuiView::importDocument(string const & argument)
1290 string filename = split(argument, format, ' ');
1292 LYXERR(Debug::INFO, format << " file: " << filename);
1294 // need user interaction
1295 if (filename.empty()) {
1296 string initpath = lyxrc.document_path;
1298 Buffer const * buf = buffer();
1300 string const trypath = buf->filePath();
1301 // If directory is writeable, use this as default.
1302 if (FileName(trypath).isDirWritable())
1306 docstring const text = bformat(_("Select %1$s file to import"),
1307 formats.prettyName(format));
1309 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1310 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1311 dlg.setButton2(qt_("Examples|#E#e"),
1312 toqstr(addPath(package().system_support().absFilename(), "examples")));
1314 docstring filter = formats.prettyName(format);
1317 filter += from_utf8(formats.extension(format));
1320 FileDialog::Result result =
1321 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1323 if (result.first == FileDialog::Later)
1326 filename = fromqstr(result.second);
1328 // check selected filename
1329 if (filename.empty())
1330 message(_("Canceled."));
1333 if (filename.empty())
1336 // get absolute path of file
1337 FileName const fullname(support::makeAbsPath(filename));
1339 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1341 // Check if the document already is open
1342 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1345 if (!closeBuffer()) {
1346 message(_("Canceled."));
1351 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1353 // if the file exists already, and we didn't do
1354 // -i lyx thefile.lyx, warn
1355 if (lyxfile.exists() && fullname != lyxfile) {
1357 docstring text = bformat(_("The document %1$s already exists.\n\n"
1358 "Do you want to overwrite that document?"), displaypath);
1359 int const ret = Alert::prompt(_("Overwrite document?"),
1360 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1363 message(_("Canceled."));
1368 message(bformat(_("Importing %1$s..."), displaypath));
1369 ErrorList errorList;
1370 if (import(this, fullname, format, errorList))
1371 message(_("imported."));
1373 message(_("file not imported!"));
1375 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1379 void GuiView::newDocument(string const & filename, bool from_template)
1381 FileName initpath(lyxrc.document_path);
1382 Buffer * buf = buffer();
1384 FileName const trypath(buf->filePath());
1385 // If directory is writeable, use this as default.
1386 if (trypath.isDirWritable())
1390 string templatefile = from_template ?
1391 selectTemplateFile().absFilename() : string();
1393 if (filename.empty())
1394 b = newUnnamedFile(templatefile, initpath);
1396 b = newFile(filename, templatefile, true);
1400 // Ensure the cursor is correctly positionned on screen.
1401 view()->showCursor();
1405 void GuiView::insertLyXFile(docstring const & fname)
1407 BufferView * bv = view();
1412 FileName filename(to_utf8(fname));
1414 if (!filename.empty()) {
1415 bv->insertLyXFile(filename);
1419 // Launch a file browser
1421 string initpath = lyxrc.document_path;
1422 string const trypath = bv->buffer().filePath();
1423 // If directory is writeable, use this as default.
1424 if (FileName(trypath).isDirWritable())
1428 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1429 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1430 dlg.setButton2(qt_("Examples|#E#e"),
1431 toqstr(addPath(package().system_support().absFilename(),
1434 FileDialog::Result result = dlg.open(toqstr(initpath),
1435 QStringList(qt_("LyX Documents (*.lyx)")));
1437 if (result.first == FileDialog::Later)
1441 filename.set(fromqstr(result.second));
1443 // check selected filename
1444 if (filename.empty()) {
1445 // emit message signal.
1446 message(_("Canceled."));
1450 bv->insertLyXFile(filename);
1454 void GuiView::insertPlaintextFile(docstring const & fname,
1457 BufferView * bv = view();
1462 FileName filename(to_utf8(fname));
1464 if (!filename.empty()) {
1465 bv->insertPlaintextFile(filename, asParagraph);
1469 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1470 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1472 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1475 if (result.first == FileDialog::Later)
1479 filename.set(fromqstr(result.second));
1481 // check selected filename
1482 if (filename.empty()) {
1483 // emit message signal.
1484 message(_("Canceled."));
1488 bv->insertPlaintextFile(filename, asParagraph);
1492 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1494 FileName fname = b.fileName();
1495 FileName const oldname = fname;
1497 if (!newname.empty()) {
1499 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1501 // Switch to this Buffer.
1504 /// No argument? Ask user through dialog.
1506 FileDialog dlg(qt_("Choose a filename to save document as"),
1507 LFUN_BUFFER_WRITE_AS);
1508 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1509 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1511 if (!isLyXFilename(fname.absFilename()))
1512 fname.changeExtension(".lyx");
1514 FileDialog::Result result =
1515 dlg.save(toqstr(fname.onlyPath().absFilename()),
1516 QStringList(qt_("LyX Documents (*.lyx)")),
1517 toqstr(fname.onlyFileName()));
1519 if (result.first == FileDialog::Later)
1522 fname.set(fromqstr(result.second));
1527 if (!isLyXFilename(fname.absFilename()))
1528 fname.changeExtension(".lyx");
1531 if (FileName(fname).exists()) {
1532 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1533 docstring text = bformat(_("The document %1$s already "
1534 "exists.\n\nDo you want to "
1535 "overwrite that document?"),
1537 int const ret = Alert::prompt(_("Overwrite document?"),
1538 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1541 case 1: return renameBuffer(b, docstring());
1542 case 2: return false;
1546 // Ok, change the name of the buffer
1547 b.setFileName(fname.absFilename());
1549 bool unnamed = b.isUnnamed();
1550 b.setUnnamed(false);
1551 b.saveCheckSum(fname);
1553 if (!saveBuffer(b)) {
1554 b.setFileName(oldname.absFilename());
1555 b.setUnnamed(unnamed);
1556 b.saveCheckSum(oldname);
1564 bool GuiView::saveBuffer(Buffer & b)
1567 return renameBuffer(b, docstring());
1570 LyX::ref().session().lastFiles().add(b.fileName());
1574 // Switch to this Buffer.
1577 // FIXME: we don't tell the user *WHY* the save failed !!
1578 docstring const file = makeDisplayPath(b.absFileName(), 30);
1579 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1580 "Do you want to rename the document and "
1581 "try again?"), file);
1582 int const ret = Alert::prompt(_("Rename and save?"),
1583 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1586 if (!renameBuffer(b, docstring()))
1595 return saveBuffer(b);
1599 bool GuiView::closeBuffer()
1601 Buffer * buf = buffer();
1602 return buf && closeBuffer(*buf);
1606 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1608 // goto bookmark to update bookmark pit.
1609 //FIXME: we should update only the bookmarks related to this buffer!
1610 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1611 theLyXFunc().gotoBookmark(i+1, false, false);
1613 if (buf.isClean() || buf.paragraphs().empty()) {
1614 if (buf.masterBuffer() == &buf && tolastopened)
1615 LyX::ref().session().lastOpened().add(buf.fileName());
1616 theBufferList().release(&buf);
1619 // Switch to this Buffer.
1624 if (buf.isUnnamed())
1625 file = from_utf8(buf.fileName().onlyFileName());
1627 file = buf.fileName().displayName(30);
1629 // Bring this window to top before asking questions.
1633 docstring const text = bformat(_("The document %1$s has unsaved changes."
1634 "\n\nDo you want to save the document or discard the changes?"), file);
1635 int const ret = Alert::prompt(_("Save changed document?"),
1636 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1640 if (!saveBuffer(buf))
1644 // if we crash after this we could
1645 // have no autosave file but I guess
1646 // this is really improbable (Jug)
1647 removeAutosaveFile(buf.absFileName());
1653 // save file names to .lyx/session
1654 // if master/slave are both open, do not save slave since it
1655 // will be automatically loaded when the master is loaded
1656 if (buf.masterBuffer() == &buf && tolastopened)
1657 LyX::ref().session().lastOpened().add(buf.fileName());
1659 theBufferList().release(&buf);
1664 bool GuiView::dispatch(FuncRequest const & cmd)
1666 BufferView * bv = view();
1667 // By default we won't need any update.
1669 bv->cursor().updateFlags(Update::None);
1671 switch(cmd.action) {
1672 case LFUN_BUFFER_IMPORT:
1673 importDocument(to_utf8(cmd.argument()));
1676 case LFUN_BUFFER_SWITCH:
1677 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1680 case LFUN_BUFFER_NEXT:
1681 setBuffer(theBufferList().next(buffer()));
1684 case LFUN_BUFFER_PREVIOUS:
1685 setBuffer(theBufferList().previous(buffer()));
1688 case LFUN_COMMAND_EXECUTE: {
1689 bool const show_it = cmd.argument() != "off";
1690 d.toolbars_->showCommandBuffer(show_it);
1693 case LFUN_DROP_LAYOUTS_CHOICE:
1695 d.layout_->showPopup();
1698 case LFUN_MENU_OPEN:
1699 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1700 menu->exec(QCursor::pos());
1703 case LFUN_FILE_INSERT:
1704 insertLyXFile(cmd.argument());
1706 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1707 insertPlaintextFile(cmd.argument(), true);
1710 case LFUN_FILE_INSERT_PLAINTEXT:
1711 insertPlaintextFile(cmd.argument(), false);
1714 case LFUN_BUFFER_WRITE:
1716 saveBuffer(bv->buffer());
1719 case LFUN_BUFFER_WRITE_AS:
1721 renameBuffer(bv->buffer(), cmd.argument());
1724 case LFUN_BUFFER_WRITE_ALL: {
1725 Buffer * first = theBufferList().first();
1728 message(_("Saving all documents..."));
1729 // We cannot use a for loop as the buffer list cycles.
1732 if (!b->isClean()) {
1734 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1736 b = theBufferList().next(b);
1737 } while (b != first);
1738 message(_("All documents saved."));
1742 case LFUN_TOOLBAR_TOGGLE: {
1743 string const name = cmd.getArg(0);
1744 bool const allowauto = cmd.getArg(1) == "allowauto";
1745 // it is possible to get current toolbar status like this,...
1746 // but I decide to obey the order of ToolbarBackend::flags
1747 // and disregard real toolbar status.
1748 // toolbars_->saveToolbarInfo();
1750 // toggle state on/off/auto
1751 d.toolbars_->toggleToolbarState(name, allowauto);
1755 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1757 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1761 if (tbi->flags & ToolbarInfo::ON)
1763 else if (tbi->flags & ToolbarInfo::OFF)
1765 else if (tbi->flags & ToolbarInfo::AUTO)
1768 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1769 _(tbi->gui_name), state));
1773 case LFUN_DIALOG_UPDATE: {
1774 string const name = to_utf8(cmd.argument());
1775 // Can only update a dialog connected to an existing inset
1776 Inset * inset = getOpenInset(name);
1778 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1779 inset->dispatch(view()->cursor(), fr);
1780 } else if (name == "paragraph") {
1781 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1782 } else if (name == "prefs") {
1783 updateDialog(name, string());
1788 case LFUN_DIALOG_TOGGLE: {
1789 if (isDialogVisible(cmd.getArg(0)))
1790 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1792 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1796 case LFUN_DIALOG_DISCONNECT_INSET:
1797 disconnectDialog(to_utf8(cmd.argument()));
1800 case LFUN_DIALOG_HIDE: {
1801 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1805 case LFUN_DIALOG_SHOW: {
1806 string const name = cmd.getArg(0);
1807 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1809 if (name == "character") {
1810 data = freefont2string();
1812 showDialog("character", data);
1813 } else if (name == "latexlog") {
1814 Buffer::LogType type;
1815 string const logfile = buffer()->logName(&type);
1817 case Buffer::latexlog:
1820 case Buffer::buildlog:
1824 data += Lexer::quoteString(logfile);
1825 showDialog("log", data);
1826 } else if (name == "vclog") {
1827 string const data = "vc " +
1828 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1829 showDialog("log", data);
1830 } else if (name == "symbols") {
1831 data = bv->cursor().getEncoding()->name();
1833 showDialog("symbols", data);
1835 showDialog(name, data);
1839 case LFUN_INSET_APPLY: {
1840 string const name = cmd.getArg(0);
1841 Inset * inset = getOpenInset(name);
1843 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1844 inset->dispatch(view()->cursor(), fr);
1846 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1852 case LFUN_UI_TOGGLE:
1854 // Make sure the keyboard focus stays in the work area.
1858 case LFUN_COMPLETION_INLINE:
1859 if (d.current_work_area_)
1860 d.current_work_area_->completer().showInline();
1863 case LFUN_SPLIT_VIEW:
1864 if (Buffer * buf = buffer()) {
1865 string const orientation = cmd.getArg(0);
1866 d.splitter_->setOrientation(orientation == "vertical"
1867 ? Qt::Vertical : Qt::Horizontal);
1868 TabWorkArea * twa = addTabWorkArea();
1869 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1870 setCurrentWorkArea(wa);
1874 case LFUN_CLOSE_TAB_GROUP:
1875 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1877 twa = d.currentTabWorkArea();
1878 // Switch to the next GuiWorkArea in the found TabWorkArea.
1879 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1880 if (d.splitter_->count() == 0)
1881 // No more work area, switch to the background widget.
1886 case LFUN_COMPLETION_POPUP:
1887 if (d.current_work_area_)
1888 d.current_work_area_->completer().showPopup();
1892 case LFUN_COMPLETION_COMPLETE:
1893 if (d.current_work_area_)
1894 d.current_work_area_->completer().tab();
1905 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1907 string const arg = cmd.getArg(0);
1908 if (arg == "scrollbar") {
1909 // hide() is of no help
1910 if (d.current_work_area_->verticalScrollBarPolicy() ==
1911 Qt::ScrollBarAlwaysOff)
1913 d.current_work_area_->setVerticalScrollBarPolicy(
1914 Qt::ScrollBarAsNeeded);
1916 d.current_work_area_->setVerticalScrollBarPolicy(
1917 Qt::ScrollBarAlwaysOff);
1920 if (arg == "statusbar") {
1921 statusBar()->setVisible(!statusBar()->isVisible());
1924 if (arg == "menubar") {
1925 menuBar()->setVisible(!menuBar()->isVisible());
1928 #if QT_VERSION >= 0x040300
1929 if (arg == "frame") {
1931 getContentsMargins(&l, &t, &r, &b);
1932 //are the frames in default state?
1933 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1935 setContentsMargins(-2, -2, -2, -2);
1937 setContentsMargins(0, 0, 0, 0);
1942 if (arg != "fullscreen") {
1943 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1947 if (lyxrc.full_screen_toolbars)
1948 d.toolbars_->toggleFullScreen(!isFullScreen());
1950 if (isFullScreen()) {
1951 for (int i = 0; i != d.splitter_->count(); ++i)
1952 d.tabWorkArea(i)->setFullScreen(false);
1953 #if QT_VERSION >= 0x040300
1954 setContentsMargins(0, 0, 0, 0);
1956 setWindowState(windowState() ^ Qt::WindowFullScreen);
1958 statusBar()->show();
1960 for (int i = 0; i != d.splitter_->count(); ++i)
1961 d.tabWorkArea(i)->setFullScreen(true);
1962 #if QT_VERSION >= 0x040300
1963 setContentsMargins(-2, -2, -2, -2);
1965 setWindowState(windowState() ^ Qt::WindowFullScreen);
1966 statusBar()->hide();
1972 Buffer const * GuiView::updateInset(Inset const * inset)
1974 if (!d.current_work_area_)
1978 d.current_work_area_->scheduleRedraw();
1980 return &d.current_work_area_->bufferView().buffer();
1984 void GuiView::restartCursor()
1986 /* When we move around, or type, it's nice to be able to see
1987 * the cursor immediately after the keypress.
1989 if (d.current_work_area_)
1990 d.current_work_area_->startBlinkingCursor();
1992 // Take this occasion to update the other GUI elements.
1997 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1999 if (d.current_work_area_)
2000 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2005 // This list should be kept in sync with the list of insets in
2006 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2007 // dialog should have the same name as the inset.
2009 char const * const dialognames[] = {
2010 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2011 "citation", "document", "errorlist", "ert", "external", "file",
2012 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2013 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2014 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2016 #ifdef HAVE_LIBAIKSAURUS
2020 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2022 char const * const * const end_dialognames =
2023 dialognames + (sizeof(dialognames) / sizeof(char *));
2027 cmpCStr(char const * name) : name_(name) {}
2028 bool operator()(char const * other) {
2029 return strcmp(other, name_) == 0;
2036 bool isValidName(string const & name)
2038 return find_if(dialognames, end_dialognames,
2039 cmpCStr(name.c_str())) != end_dialognames;
2045 void GuiView::resetDialogs()
2047 // Make sure that no LFUN uses any LyXView.
2048 theLyXFunc().setLyXView(0);
2049 // FIXME: the "math panels" toolbar takes an awful lot of time to
2050 // initialise so we don't do that for the time being.
2051 //d.toolbars_->init();
2052 guiApp->menus().fillMenuBar(menuBar(), this);
2054 d.layout_->updateContents(true);
2055 // Now update controls with current buffer.
2056 theLyXFunc().setLyXView(this);
2061 Dialog * GuiView::find_or_build(string const & name)
2063 if (!isValidName(name))
2066 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2068 if (it != d.dialogs_.end())
2069 return it->second.get();
2071 Dialog * dialog = build(name);
2072 d.dialogs_[name].reset(dialog);
2073 if (lyxrc.allow_geometry_session)
2074 dialog->restoreSession();
2079 void GuiView::showDialog(string const & name, string const & data,
2086 Dialog * dialog = find_or_build(name);
2088 dialog->showData(data);
2090 d.open_insets_[name] = inset;
2096 bool GuiView::isDialogVisible(string const & name) const
2098 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2099 if (it == d.dialogs_.end())
2101 return it->second.get()->isVisibleView();
2105 void GuiView::hideDialog(string const & name, Inset * inset)
2107 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2108 if (it == d.dialogs_.end())
2111 if (inset && inset != getOpenInset(name))
2114 Dialog * const dialog = it->second.get();
2115 if (dialog->isVisibleView())
2117 d.open_insets_[name] = 0;
2121 void GuiView::disconnectDialog(string const & name)
2123 if (!isValidName(name))
2126 if (d.open_insets_.find(name) != d.open_insets_.end())
2127 d.open_insets_[name] = 0;
2131 Inset * GuiView::getOpenInset(string const & name) const
2133 if (!isValidName(name))
2136 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2137 return it == d.open_insets_.end() ? 0 : it->second;
2141 void GuiView::hideAll() const
2143 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2144 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2146 for(; it != end; ++it)
2147 it->second->hideView();
2151 void GuiView::updateDialogs()
2153 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2154 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2156 for(; it != end; ++it) {
2157 Dialog * dialog = it->second.get();
2158 if (dialog && dialog->isVisibleView())
2159 dialog->checkStatus();
2167 // will be replaced by a proper factory...
2168 Dialog * createGuiAbout(GuiView & lv);
2169 Dialog * createGuiBibitem(GuiView & lv);
2170 Dialog * createGuiBibtex(GuiView & lv);
2171 Dialog * createGuiBox(GuiView & lv);
2172 Dialog * createGuiBranch(GuiView & lv);
2173 Dialog * createGuiChanges(GuiView & lv);
2174 Dialog * createGuiCharacter(GuiView & lv);
2175 Dialog * createGuiCitation(GuiView & lv);
2176 Dialog * createGuiDelimiter(GuiView & lv);
2177 Dialog * createGuiDocument(GuiView & lv);
2178 Dialog * createGuiErrorList(GuiView & lv);
2179 Dialog * createGuiERT(GuiView & lv);
2180 Dialog * createGuiExternal(GuiView & lv);
2181 Dialog * createGuiFloat(GuiView & lv);
2182 Dialog * createGuiGraphics(GuiView & lv);
2183 Dialog * createGuiHSpace(GuiView & lv);
2184 Dialog * createGuiInclude(GuiView & lv);
2185 Dialog * createGuiLabel(GuiView & lv);
2186 Dialog * createGuiListings(GuiView & lv);
2187 Dialog * createGuiLog(GuiView & lv);
2188 Dialog * createGuiMathMatrix(GuiView & lv);
2189 Dialog * createGuiNomenclature(GuiView & lv);
2190 Dialog * createGuiNote(GuiView & lv);
2191 Dialog * createGuiParagraph(GuiView & lv);
2192 Dialog * createGuiPreferences(GuiView & lv);
2193 Dialog * createGuiPrint(GuiView & lv);
2194 Dialog * createGuiRef(GuiView & lv);
2195 Dialog * createGuiSearch(GuiView & lv);
2196 Dialog * createGuiSendTo(GuiView & lv);
2197 Dialog * createGuiShowFile(GuiView & lv);
2198 Dialog * createGuiSpellchecker(GuiView & lv);
2199 Dialog * createGuiSymbols(GuiView & lv);
2200 Dialog * createGuiTabularCreate(GuiView & lv);
2201 Dialog * createGuiTabular(GuiView & lv);
2202 Dialog * createGuiTexInfo(GuiView & lv);
2203 Dialog * createGuiToc(GuiView & lv);
2204 Dialog * createGuiThesaurus(GuiView & lv);
2205 Dialog * createGuiHyperlink(GuiView & lv);
2206 Dialog * createGuiVSpace(GuiView & lv);
2207 Dialog * createGuiViewSource(GuiView & lv);
2208 Dialog * createGuiWrap(GuiView & lv);
2211 Dialog * GuiView::build(string const & name)
2213 LASSERT(isValidName(name), /**/);
2215 if (name == "aboutlyx")
2216 return createGuiAbout(*this);
2217 if (name == "bibitem")
2218 return createGuiBibitem(*this);
2219 if (name == "bibtex")
2220 return createGuiBibtex(*this);
2222 return createGuiBox(*this);
2223 if (name == "branch")
2224 return createGuiBranch(*this);
2225 if (name == "changes")
2226 return createGuiChanges(*this);
2227 if (name == "character")
2228 return createGuiCharacter(*this);
2229 if (name == "citation")
2230 return createGuiCitation(*this);
2231 if (name == "document")
2232 return createGuiDocument(*this);
2233 if (name == "errorlist")
2234 return createGuiErrorList(*this);
2236 return createGuiERT(*this);
2237 if (name == "external")
2238 return createGuiExternal(*this);
2240 return createGuiShowFile(*this);
2241 if (name == "findreplace")
2242 return createGuiSearch(*this);
2243 if (name == "float")
2244 return createGuiFloat(*this);
2245 if (name == "graphics")
2246 return createGuiGraphics(*this);
2247 if (name == "include")
2248 return createGuiInclude(*this);
2249 if (name == "nomenclature")
2250 return createGuiNomenclature(*this);
2251 if (name == "label")
2252 return createGuiLabel(*this);
2254 return createGuiLog(*this);
2255 if (name == "view-source")
2256 return createGuiViewSource(*this);
2257 if (name == "mathdelimiter")
2258 return createGuiDelimiter(*this);
2259 if (name == "mathmatrix")
2260 return createGuiMathMatrix(*this);
2262 return createGuiNote(*this);
2263 if (name == "paragraph")
2264 return createGuiParagraph(*this);
2265 if (name == "prefs")
2266 return createGuiPreferences(*this);
2267 if (name == "print")
2268 return createGuiPrint(*this);
2270 return createGuiRef(*this);
2271 if (name == "sendto")
2272 return createGuiSendTo(*this);
2273 if (name == "space")
2274 return createGuiHSpace(*this);
2275 if (name == "spellchecker")
2276 return createGuiSpellchecker(*this);
2277 if (name == "symbols")
2278 return createGuiSymbols(*this);
2279 if (name == "tabular")
2280 return createGuiTabular(*this);
2281 if (name == "tabularcreate")
2282 return createGuiTabularCreate(*this);
2283 if (name == "texinfo")
2284 return createGuiTexInfo(*this);
2285 #ifdef HAVE_LIBAIKSAURUS
2286 if (name == "thesaurus")
2287 return createGuiThesaurus(*this);
2290 return createGuiToc(*this);
2292 return createGuiHyperlink(*this);
2293 if (name == "vspace")
2294 return createGuiVSpace(*this);
2296 return createGuiWrap(*this);
2297 if (name == "listings")
2298 return createGuiListings(*this);
2304 } // namespace frontend
2307 #include "GuiView_moc.cpp"