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 "GuiWorkArea.h"
22 #include "GuiKeySymbol.h"
23 #include "GuiToolbar.h"
24 #include "GuiToolbars.h"
27 #include "qt_helpers.h"
29 #include "frontends/alert.h"
31 #include "buffer_funcs.h"
33 #include "BufferList.h"
34 #include "BufferParams.h"
35 #include "BufferView.h"
36 #include "Converter.h"
38 #include "ErrorList.h"
40 #include "FuncStatus.h"
41 #include "FuncRequest.h"
42 #include "support/gettext.h"
50 #include "Paragraph.h"
51 #include "TextClass.h"
53 #include "ToolbarBackend.h"
56 #include "support/debug.h"
57 #include "support/FileFilterList.h"
58 #include "support/FileName.h"
59 #include "support/filetools.h"
60 #include "support/ForkedCalls.h"
61 #include "support/lstrings.h"
62 #include "support/os.h"
63 #include "support/Package.h"
64 #include "support/Timeout.h"
67 #include <QApplication>
68 #include <QCloseEvent>
70 #include <QDesktopWidget>
71 #include <QDragEnterEvent>
79 #include <QPushButton>
83 #include <QStackedWidget>
90 #include <boost/assert.hpp>
91 #include <boost/bind.hpp>
93 #ifdef HAVE_SYS_TIME_H
94 # include <sys/time.h>
101 using namespace lyx::support;
108 class BackgroundWidget : public QWidget
113 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
114 /// The text to be written on top of the pixmap
115 QString const text = lyx_version ? lyx_version : qt_("unknown version");
116 splash_ = QPixmap(":/images/banner.png");
118 QPainter pain(&splash_);
119 pain.setPen(QColor(255, 255, 0));
121 // The font used to display the version info
122 font.setStyleHint(QFont::SansSerif);
123 font.setWeight(QFont::Bold);
124 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
126 pain.drawText(260, 270, text);
129 void paintEvent(QPaintEvent *)
131 int x = (width() - splash_.width()) / 2;
132 int y = (height() - splash_.height()) / 2;
134 pain.drawPixmap(x, y, splash_);
144 typedef boost::shared_ptr<Dialog> DialogPtr;
146 struct GuiView::GuiViewPrivate
149 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
152 // hardcode here the platform specific icon size
153 smallIconSize = 14; // scaling problems
154 normalIconSize = 20; // ok, default
155 bigIconSize = 26; // better for some math icons
157 splitter_ = new QSplitter;
158 bg_widget_ = new BackgroundWidget;
159 stack_widget_ = new QStackedWidget;
160 stack_widget_->addWidget(bg_widget_);
161 stack_widget_->addWidget(splitter_);
169 delete stack_widget_;
173 QMenu * toolBarPopup(GuiView * parent)
175 // FIXME: translation
176 QMenu * menu = new QMenu(parent);
177 QActionGroup * iconSizeGroup = new QActionGroup(parent);
179 QAction * smallIcons = new QAction(iconSizeGroup);
180 smallIcons->setText(qt_("Small-sized icons"));
181 smallIcons->setCheckable(true);
182 QObject::connect(smallIcons, SIGNAL(triggered()),
183 parent, SLOT(smallSizedIcons()));
184 menu->addAction(smallIcons);
186 QAction * normalIcons = new QAction(iconSizeGroup);
187 normalIcons->setText(qt_("Normal-sized icons"));
188 normalIcons->setCheckable(true);
189 QObject::connect(normalIcons, SIGNAL(triggered()),
190 parent, SLOT(normalSizedIcons()));
191 menu->addAction(normalIcons);
193 QAction * bigIcons = new QAction(iconSizeGroup);
194 bigIcons->setText(qt_("Big-sized icons"));
195 bigIcons->setCheckable(true);
196 QObject::connect(bigIcons, SIGNAL(triggered()),
197 parent, SLOT(bigSizedIcons()));
198 menu->addAction(bigIcons);
200 unsigned int cur = parent->iconSize().width();
201 if ( cur == parent->d.smallIconSize)
202 smallIcons->setChecked(true);
203 else if (cur == parent->d.normalIconSize)
204 normalIcons->setChecked(true);
205 else if (cur == parent->d.bigIconSize)
206 bigIcons->setChecked(true);
213 stack_widget_->setCurrentWidget(bg_widget_);
214 bg_widget_->setUpdatesEnabled(true);
217 TabWorkArea * tabWorkArea(int i)
219 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
222 TabWorkArea * currentTabWorkArea()
224 if (splitter_->count() == 1)
225 // The first TabWorkArea is always the first one, if any.
226 return tabWorkArea(0);
228 for (int i = 0; i != splitter_->count(); ++i) {
229 TabWorkArea * twa = tabWorkArea(i);
230 if (current_work_area_ == twa->currentWorkArea())
234 // None has the focus so we just take the first one.
235 return tabWorkArea(0);
239 GuiWorkArea * current_work_area_;
240 QSplitter * splitter_;
241 QStackedWidget * stack_widget_;
242 BackgroundWidget * bg_widget_;
244 GuiToolbars * toolbars_;
245 /// The main layout box.
247 * \warning Don't Delete! The layout box is actually owned by
248 * whichever toolbar contains it. All the GuiView class needs is a
249 * means of accessing it.
251 * FIXME: replace that with a proper model so that we are not limited
252 * to only one dialog.
254 GuiLayoutBox * layout_;
257 map<string, Inset *> open_insets_;
260 map<string, DialogPtr> dialogs_;
262 unsigned int smallIconSize;
263 unsigned int normalIconSize;
264 unsigned int bigIconSize;
266 QTimer statusbar_timer_;
267 /// auto-saving of buffers
268 Timeout autosave_timeout_;
269 /// flag against a race condition due to multiclicks, see bug #1119
274 GuiView::GuiView(int id)
275 : d(*new GuiViewPrivate), id_(id)
277 // GuiToolbars *must* be initialised before the menu bar.
278 d.toolbars_ = new GuiToolbars(*this);
280 // Fill up the menu bar.
281 guiApp->menus().fillMenuBar(menuBar(), this);
283 setCentralWidget(d.stack_widget_);
285 // Start autosave timer
286 if (lyxrc.autosave) {
287 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
288 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
289 d.autosave_timeout_.start();
291 connect(&d.statusbar_timer_, SIGNAL(timeout()),
292 this, SLOT(clearMessage()));
294 // We don't want to keep the window in memory if it is closed.
295 setAttribute(Qt::WA_DeleteOnClose, true);
298 // assign an icon to main form. We do not do it under Qt/Mac,
299 // since the icon is provided in the application bundle.
300 setWindowIcon(QPixmap(":/images/lyx.png"));
304 setAcceptDrops(true);
306 statusBar()->setSizeGripEnabled(true);
308 // Forbid too small unresizable window because it can happen
309 // with some window manager under X11.
310 setMinimumSize(300, 200);
312 if (!lyxrc.allow_geometry_session)
313 // No session handling, default to a sane size.
314 setGeometry(50, 50, 690, 510);
316 // Now take care of session management.
318 QString const key = "view-" + QString::number(id_);
320 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
321 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
325 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
326 setGeometry(50, 50, 690, 510);
328 setIconSize(settings.value(key + "/icon_size").toSize());
338 void GuiView::setFocus()
340 if (d.current_work_area_)
341 d.current_work_area_->setFocus();
347 QMenu * GuiView::createPopupMenu()
349 return d.toolBarPopup(this);
353 void GuiView::showEvent(QShowEvent * e)
355 LYXERR(Debug::GUI, "Passed Geometry "
356 << size().height() << "x" << size().width()
357 << "+" << pos().x() << "+" << pos().y());
359 if (d.splitter_->count() == 0)
360 // No work area, switch to the background widget.
363 QMainWindow::showEvent(e);
367 void GuiView::closeEvent(QCloseEvent * close_event)
369 while (Buffer * b = buffer()) {
371 // This is a child document, just close the tab after saving
372 // but keep the file loaded.
373 if (!saveBuffer(*b)) {
374 close_event->ignore();
377 removeWorkArea(d.current_work_area_);
381 std::vector<int> const & ids = guiApp->viewIds();
382 for (size_type i = 0; i != ids.size(); ++i) {
385 if (guiApp->view(ids[i]).workArea(*b)) {
386 // FIXME 1: should we put an alert box here that the buffer
387 // is viewed elsewhere?
388 // FIXME 2: should we try to save this buffer in any case?
391 // This buffer is also opened in another view, so
392 // but close the associated work area nevertheless.
393 removeWorkArea(d.current_work_area_);
394 // but don't close it.
399 if (b && !closeBuffer(*b)) {
400 close_event->ignore();
405 // Make sure that no LFUN use this close to be closed View.
406 theLyXFunc().setLyXView(0);
408 // Save toolbars configuration
409 if (isFullScreen()) {
410 d.toolbars_->toggleFullScreen(!isFullScreen());
414 // Make sure the timer time out will not trigger a statusbar update.
415 d.statusbar_timer_.stop();
417 // Saving fullscreen requires additional tweaks in the toolbar code.
418 // It wouldn't also work under linux natively.
419 if (lyxrc.allow_geometry_session && !isFullScreen()) {
421 QString const key = "view-" + QString::number(id_);
423 settings.setValue(key + "/pos", pos());
424 settings.setValue(key + "/size", size());
426 settings.setValue(key + "/geometry", saveGeometry());
428 settings.setValue(key + "/icon_size", iconSize());
429 d.toolbars_->saveToolbarInfo();
430 // Now take care of all other dialogs:
431 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
432 for (; it!= d.dialogs_.end(); ++it)
433 it->second->saveSession();
436 guiApp->unregisterView(id_);
437 close_event->accept();
441 void GuiView::dragEnterEvent(QDragEnterEvent * event)
443 if (event->mimeData()->hasUrls())
445 /// \todo Ask lyx-devel is this is enough:
446 /// if (event->mimeData()->hasFormat("text/plain"))
447 /// event->acceptProposedAction();
451 void GuiView::dropEvent(QDropEvent* event)
453 QList<QUrl> files = event->mimeData()->urls();
457 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
458 for (int i = 0; i != files.size(); ++i) {
459 string const file = os::internal_path(fromqstr(
460 files.at(i).toLocalFile()));
462 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
467 void GuiView::message(docstring const & str)
469 if (ForkedProcess::iAmAChild())
472 statusBar()->showMessage(toqstr(str));
473 d.statusbar_timer_.stop();
474 d.statusbar_timer_.start(3000);
478 void GuiView::smallSizedIcons()
480 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
484 void GuiView::normalSizedIcons()
486 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
490 void GuiView::bigSizedIcons()
492 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
496 void GuiView::clearMessage()
500 theLyXFunc().setLyXView(this);
501 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
502 d.statusbar_timer_.stop();
506 void GuiView::updateWindowTitle(GuiWorkArea * wa)
508 if (wa != d.current_work_area_)
510 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
511 setWindowIconText(wa->windowIconText());
515 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
518 disconnectBufferView();
519 connectBufferView(wa->bufferView());
520 connectBuffer(wa->bufferView().buffer());
521 d.current_work_area_ = wa;
522 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
523 this, SLOT(updateWindowTitle(GuiWorkArea *)));
524 updateWindowTitle(wa);
527 // Buffer-dependent dialogs should be updated or
528 // hidden. This should go here because some dialogs (eg ToC)
529 // require bv_->text.
530 updateBufferDependent(true);
537 void GuiView::on_lastWorkAreaRemoved()
540 // On Mac close the view if there is no Tab open anymore,
541 // but only if no splitter is visible
542 if (d.splitter_->count() == 1) {
543 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
544 if (twa && twa->count() == 0) {
545 // close the view, as no tab is open anymore
546 QTimer::singleShot(0, this, SLOT(close()));
553 void GuiView::updateStatusBar()
555 // let the user see the explicit message
556 if (d.statusbar_timer_.isActive())
559 theLyXFunc().setLyXView(this);
560 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
564 bool GuiView::hasFocus() const
566 return qApp->activeWindow() == this;
570 bool GuiView::event(QEvent * e)
574 // Useful debug code:
575 //case QEvent::ActivationChange:
576 //case QEvent::WindowDeactivate:
577 //case QEvent::Paint:
578 //case QEvent::Enter:
579 //case QEvent::Leave:
580 //case QEvent::HoverEnter:
581 //case QEvent::HoverLeave:
582 //case QEvent::HoverMove:
583 //case QEvent::StatusTip:
584 //case QEvent::DragEnter:
585 //case QEvent::DragLeave:
589 case QEvent::WindowActivate: {
590 if (this == guiApp->currentView()) {
592 return QMainWindow::event(e);
594 guiApp->setCurrentView(*this);
595 if (d.current_work_area_) {
596 BufferView & bv = d.current_work_area_->bufferView();
597 connectBufferView(bv);
598 connectBuffer(bv.buffer());
599 // The document structure, name and dialogs might have
600 // changed in another view.
601 updateBufferDependent(true);
606 setWindowTitle(qt_("LyX"));
607 setWindowIconText(qt_("LyX"));
610 return QMainWindow::event(e);
613 case QEvent::ShortcutOverride: {
614 if (d.current_work_area_)
615 // Nothing special to do.
616 return QMainWindow::event(e);
618 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
620 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
622 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
623 || ke->key() == Qt::Key_Backtab)
624 return QMainWindow::event(e);
626 // Allow processing of shortcuts that are allowed even when no Buffer
628 theLyXFunc().setLyXView(this);
630 setKeySymbol(&sym, ke);
631 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
637 return QMainWindow::event(e);
642 bool GuiView::focusNextPrevChild(bool /*next*/)
649 void GuiView::setBusy(bool busy)
651 if (d.current_work_area_) {
652 d.current_work_area_->setUpdatesEnabled(!busy);
654 d.current_work_area_->stopBlinkingCursor();
656 d.current_work_area_->startBlinkingCursor();
660 QApplication::setOverrideCursor(Qt::WaitCursor);
662 QApplication::restoreOverrideCursor();
666 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
668 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
670 if (tbinfo.flags & ToolbarInfo::TOP) {
672 addToolBarBreak(Qt::TopToolBarArea);
673 addToolBar(Qt::TopToolBarArea, toolBar);
676 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
677 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
678 #if (QT_VERSION >= 0x040202)
680 addToolBarBreak(Qt::BottomToolBarArea);
682 addToolBar(Qt::BottomToolBarArea, toolBar);
685 if (tbinfo.flags & ToolbarInfo::LEFT) {
686 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
687 #if (QT_VERSION >= 0x040202)
689 addToolBarBreak(Qt::LeftToolBarArea);
691 addToolBar(Qt::LeftToolBarArea, toolBar);
694 if (tbinfo.flags & ToolbarInfo::RIGHT) {
695 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
696 #if (QT_VERSION >= 0x040202)
698 addToolBarBreak(Qt::RightToolBarArea);
700 addToolBar(Qt::RightToolBarArea, toolBar);
703 // The following does not work so I cannot restore to exact toolbar location
705 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
706 toolBar->move(tbinfo.posx, tbinfo.posy);
713 GuiWorkArea * GuiView::workArea(Buffer & buffer)
715 if (TabWorkArea * twa = d.currentTabWorkArea())
716 return twa->workArea(buffer);
721 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
723 // Automatically create a TabWorkArea if there are none yet.
724 TabWorkArea * tab_widget = d.splitter_->count()
725 ? d.currentTabWorkArea() : addTabWorkArea();
726 return tab_widget->addWorkArea(buffer, *this);
730 TabWorkArea * GuiView::addTabWorkArea()
732 TabWorkArea * twa = new TabWorkArea;
733 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
734 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
735 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
736 this, SLOT(on_lastWorkAreaRemoved()));
738 d.splitter_->addWidget(twa);
739 d.stack_widget_->setCurrentWidget(d.splitter_);
744 GuiWorkArea const * GuiView::currentWorkArea() const
746 return d.current_work_area_;
750 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
754 // Changing work area can result from opening a file so
755 // update the toc in any case.
758 d.current_work_area_ = wa;
759 for (int i = 0; i != d.splitter_->count(); ++i) {
760 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
766 void GuiView::removeWorkArea(GuiWorkArea * wa)
769 if (wa == d.current_work_area_) {
771 disconnectBufferView();
772 hideBufferDependent();
773 d.current_work_area_ = 0;
776 for (int i = 0; i != d.splitter_->count(); ++i) {
777 TabWorkArea * twa = d.tabWorkArea(i);
778 if (!twa->removeWorkArea(wa))
779 // Not found in this tab group.
782 // We found and removed the GuiWorkArea.
784 // No more WorkAreas in this tab group, so delete it.
789 if (d.current_work_area_)
790 // This means that we are not closing the current GuiWorkArea;
793 // Switch to the next GuiWorkArea in the found TabWorkArea.
794 d.current_work_area_ = twa->currentWorkArea();
798 if (d.splitter_->count() == 0)
799 // No more work area, switch to the background widget.
804 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
810 void GuiView::updateLayoutList()
813 d.layout_->updateContents(false);
817 void GuiView::updateToolbars()
819 if (d.current_work_area_) {
821 d.current_work_area_->bufferView().cursor().inMathed();
823 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
825 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
826 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
827 bool const mathmacrotemplate =
828 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
830 d.toolbars_->update(math, table, review, mathmacrotemplate);
832 d.toolbars_->update(false, false, false, false);
834 // update read-only status of open dialogs.
839 Buffer * GuiView::buffer()
841 if (d.current_work_area_)
842 return &d.current_work_area_->bufferView().buffer();
847 Buffer const * GuiView::buffer() const
849 if (d.current_work_area_)
850 return &d.current_work_area_->bufferView().buffer();
855 void GuiView::setBuffer(Buffer * newBuffer)
857 BOOST_ASSERT(newBuffer);
860 GuiWorkArea * wa = workArea(*newBuffer);
862 updateLabels(*newBuffer->masterBuffer());
863 wa = addWorkArea(*newBuffer);
865 //Disconnect the old buffer...there's no new one.
868 connectBuffer(*newBuffer);
869 connectBufferView(wa->bufferView());
870 setCurrentWorkArea(wa);
876 void GuiView::connectBuffer(Buffer & buf)
878 buf.setGuiDelegate(this);
882 void GuiView::disconnectBuffer()
884 if (d.current_work_area_)
885 d.current_work_area_->bufferView().setGuiDelegate(0);
889 void GuiView::connectBufferView(BufferView & bv)
891 bv.setGuiDelegate(this);
895 void GuiView::disconnectBufferView()
897 if (d.current_work_area_)
898 d.current_work_area_->bufferView().setGuiDelegate(0);
902 void GuiView::errors(string const & error_type)
904 ErrorList & el = buffer()->errorList(error_type);
906 showDialog("errorlist", error_type);
910 void GuiView::updateDialog(string const & name, string const & data)
912 if (!isDialogVisible(name))
915 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
916 if (it == d.dialogs_.end())
919 Dialog * const dialog = it->second.get();
920 if (dialog->isVisibleView())
921 dialog->updateData(data);
925 BufferView * GuiView::view()
927 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
931 void GuiView::updateToc()
933 updateDialog("toc", "");
937 void GuiView::updateEmbeddedFiles()
939 updateDialog("embedding", "");
943 void GuiView::autoSave()
945 LYXERR(Debug::INFO, "Running autoSave()");
948 view()->buffer().autoSave();
952 void GuiView::resetAutosaveTimers()
955 d.autosave_timeout_.restart();
959 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
963 Buffer * buf = buffer();
965 /* In LyX/Mac, when a dialog is open, the menus of the
966 application can still be accessed without giving focus to
967 the main window. In this case, we want to disable the menu
968 entries that are buffer-related.
970 Note that this code is not perfect, as bug 1941 attests:
971 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
973 if (cmd.origin == FuncRequest::MENU && !hasFocus())
977 case LFUN_BUFFER_WRITE:
978 enable = buf && (buf->isUnnamed() || !buf->isClean());
981 case LFUN_BUFFER_WRITE_AS:
985 case LFUN_SPLIT_VIEW:
989 case LFUN_CLOSE_TAB_GROUP:
990 enable = d.currentTabWorkArea();
993 case LFUN_TOOLBAR_TOGGLE:
994 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
997 case LFUN_DIALOG_TOGGLE:
998 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
999 // fall through to set "enable"
1000 case LFUN_DIALOG_SHOW: {
1001 string const name = cmd.getArg(0);
1003 enable = name == "aboutlyx"
1004 || name == "file" //FIXME: should be removed.
1006 || name == "texinfo";
1007 else if (name == "print")
1008 enable = buf->isExportable("dvi")
1009 && lyxrc.print_command != "none";
1010 else if (name == "character") {
1014 InsetCode ic = view()->cursor().inset().lyxCode();
1015 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1018 else if (name == "symbols") {
1019 if (!view() || view()->cursor().inMathed())
1022 InsetCode ic = view()->cursor().inset().lyxCode();
1023 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1026 else if (name == "latexlog")
1027 enable = FileName(buf->logName()).isReadableFile();
1028 else if (name == "spellchecker")
1029 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1030 enable = !buf->isReadonly();
1034 else if (name == "vclog")
1035 enable = buf->lyxvc().inUse();
1039 case LFUN_DIALOG_UPDATE: {
1040 string const name = cmd.getArg(0);
1042 enable = name == "prefs";
1046 case LFUN_INSET_APPLY: {
1051 string const name = cmd.getArg(0);
1052 Inset * inset = getOpenInset(name);
1054 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1056 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1057 // Every inset is supposed to handle this
1058 BOOST_ASSERT(false);
1062 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1063 flag |= getStatus(fr);
1065 enable = flag.enabled();
1069 case LFUN_COMPLETION_INLINE:
1070 if (!d.current_work_area_
1071 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1075 case LFUN_COMPLETION_POPUP:
1076 if (!d.current_work_area_
1077 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1081 case LFUN_COMPLETION_COMPLETE:
1082 if (!d.current_work_area_
1083 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1095 flag.enabled(false);
1101 static FileName selectTemplateFile()
1103 FileDialog dlg(qt_("Select template file"));
1104 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1105 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1107 FileDialog::Result result =
1108 dlg.open(toqstr(lyxrc.template_path),
1109 FileFilterList(_("LyX Documents (*.lyx)")));
1111 if (result.first == FileDialog::Later)
1113 if (result.second.isEmpty())
1115 return FileName(fromqstr(result.second));
1119 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1123 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1126 message(_("Document not loaded."));
1131 setBuffer(newBuffer);
1133 // scroll to the position when the file was last closed
1134 if (lyxrc.use_lastfilepos) {
1135 LastFilePosSection::FilePos filepos =
1136 LyX::ref().session().lastFilePos().load(filename);
1137 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1141 LyX::ref().session().lastFiles().add(filename);
1148 void GuiView::openDocument(string const & fname)
1150 string initpath = lyxrc.document_path;
1153 string const trypath = buffer()->filePath();
1154 // If directory is writeable, use this as default.
1155 if (FileName(trypath).isDirWritable())
1161 if (fname.empty()) {
1162 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1163 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1164 dlg.setButton2(qt_("Examples|#E#e"),
1165 toqstr(addPath(package().system_support().absFilename(), "examples")));
1167 FileDialog::Result result =
1168 dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1170 if (result.first == FileDialog::Later)
1173 filename = fromqstr(result.second);
1175 // check selected filename
1176 if (filename.empty()) {
1177 message(_("Canceled."));
1183 // get absolute path of file and add ".lyx" to the filename if
1185 FileName const fullname =
1186 fileSearch(string(), filename, "lyx", support::may_not_exist);
1187 if (!fullname.empty())
1188 filename = fullname.absFilename();
1190 // if the file doesn't exist, let the user create one
1191 if (!fullname.exists()) {
1192 // the user specifically chose this name. Believe him.
1193 Buffer * const b = newFile(filename, string(), true);
1199 docstring const disp_fn = makeDisplayPath(filename);
1200 message(bformat(_("Opening document %1$s..."), disp_fn));
1203 Buffer * buf = loadDocument(fullname);
1208 buf->errors("Parse");
1209 str2 = bformat(_("Document %1$s opened."), disp_fn);
1211 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1216 // FIXME: clean that
1217 static bool import(GuiView * lv, FileName const & filename,
1218 string const & format, ErrorList & errorList)
1220 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1222 string loader_format;
1223 vector<string> loaders = theConverters().loaders();
1224 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1225 for (vector<string>::const_iterator it = loaders.begin();
1226 it != loaders.end(); ++it) {
1227 if (!theConverters().isReachable(format, *it))
1230 string const tofile =
1231 support::changeExtension(filename.absFilename(),
1232 formats.extension(*it));
1233 if (!theConverters().convert(0, filename, FileName(tofile),
1234 filename, format, *it, errorList))
1236 loader_format = *it;
1239 if (loader_format.empty()) {
1240 frontend::Alert::error(_("Couldn't import file"),
1241 bformat(_("No information for importing the format %1$s."),
1242 formats.prettyName(format)));
1246 loader_format = format;
1248 if (loader_format == "lyx") {
1249 Buffer * buf = lv->loadDocument(lyxfile);
1254 buf->errors("Parse");
1256 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1260 bool as_paragraphs = loader_format == "textparagraph";
1261 string filename2 = (loader_format == format) ? filename.absFilename()
1262 : support::changeExtension(filename.absFilename(),
1263 formats.extension(loader_format));
1264 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1265 theLyXFunc().setLyXView(lv);
1266 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1273 void GuiView::importDocument(string const & argument)
1276 string filename = split(argument, format, ' ');
1278 LYXERR(Debug::INFO, format << " file: " << filename);
1280 // need user interaction
1281 if (filename.empty()) {
1282 string initpath = lyxrc.document_path;
1284 Buffer const * buf = buffer();
1286 string const trypath = buf->filePath();
1287 // If directory is writeable, use this as default.
1288 if (FileName(trypath).isDirWritable())
1292 docstring const text = bformat(_("Select %1$s file to import"),
1293 formats.prettyName(format));
1295 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1296 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1297 dlg.setButton2(qt_("Examples|#E#e"),
1298 toqstr(addPath(package().system_support().absFilename(), "examples")));
1300 docstring filter = formats.prettyName(format);
1303 filter += from_utf8(formats.extension(format));
1306 FileDialog::Result result =
1307 dlg.open(toqstr(initpath), FileFilterList(filter));
1309 if (result.first == FileDialog::Later)
1312 filename = fromqstr(result.second);
1314 // check selected filename
1315 if (filename.empty())
1316 message(_("Canceled."));
1319 if (filename.empty())
1322 // get absolute path of file
1323 FileName const fullname(makeAbsPath(filename));
1325 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1327 // Check if the document already is open
1328 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1331 if (!closeBuffer()) {
1332 message(_("Canceled."));
1337 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1339 // if the file exists already, and we didn't do
1340 // -i lyx thefile.lyx, warn
1341 if (lyxfile.exists() && fullname != lyxfile) {
1343 docstring text = bformat(_("The document %1$s already exists.\n\n"
1344 "Do you want to overwrite that document?"), displaypath);
1345 int const ret = Alert::prompt(_("Overwrite document?"),
1346 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1349 message(_("Canceled."));
1354 message(bformat(_("Importing %1$s..."), displaypath));
1355 ErrorList errorList;
1356 if (import(this, fullname, format, errorList))
1357 message(_("imported."));
1359 message(_("file not imported!"));
1361 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1365 void GuiView::newDocument(string const & filename, bool from_template)
1367 FileName initpath(lyxrc.document_path);
1368 Buffer * buf = buffer();
1370 FileName const trypath(buf->filePath());
1371 // If directory is writeable, use this as default.
1372 if (trypath.isDirWritable())
1376 string templatefile = from_template ?
1377 selectTemplateFile().absFilename() : string();
1379 if (filename.empty())
1380 b = newUnnamedFile(templatefile, initpath);
1382 b = newFile(filename, templatefile, true);
1386 // Ensure the cursor is correctly positionned on screen.
1387 view()->showCursor();
1391 void GuiView::insertLyXFile(docstring const & fname)
1393 BufferView * bv = view();
1398 FileName filename(to_utf8(fname));
1400 if (!filename.empty()) {
1401 bv->insertLyXFile(filename);
1405 // Launch a file browser
1407 string initpath = lyxrc.document_path;
1408 string const trypath = bv->buffer().filePath();
1409 // If directory is writeable, use this as default.
1410 if (FileName(trypath).isDirWritable())
1414 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1415 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1416 dlg.setButton2(qt_("Examples|#E#e"),
1417 toqstr(addPath(package().system_support().absFilename(),
1420 FileDialog::Result result =
1421 dlg.open(toqstr(initpath),
1422 FileFilterList(_("LyX Documents (*.lyx)")));
1424 if (result.first == FileDialog::Later)
1428 filename.set(fromqstr(result.second));
1430 // check selected filename
1431 if (filename.empty()) {
1432 // emit message signal.
1433 message(_("Canceled."));
1437 bv->insertLyXFile(filename);
1441 void GuiView::insertPlaintextFile(docstring const & fname,
1444 BufferView * bv = view();
1449 FileName filename(to_utf8(fname));
1451 if (!filename.empty()) {
1452 bv->insertPlaintextFile(filename, asParagraph);
1456 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1457 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1459 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1462 if (result.first == FileDialog::Later)
1466 filename.set(fromqstr(result.second));
1468 // check selected filename
1469 if (filename.empty()) {
1470 // emit message signal.
1471 message(_("Canceled."));
1475 bv->insertPlaintextFile(filename, asParagraph);
1479 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1481 FileName fname = b.fileName();
1482 FileName const oldname = fname;
1484 if (!newname.empty()) {
1486 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1488 // Switch to this Buffer.
1491 /// No argument? Ask user through dialog.
1493 FileDialog dlg(qt_("Choose a filename to save document as"),
1494 LFUN_BUFFER_WRITE_AS);
1495 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1496 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1498 if (!isLyXFilename(fname.absFilename()))
1499 fname.changeExtension(".lyx");
1501 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1503 FileDialog::Result result =
1504 dlg.save(toqstr(fname.onlyPath().absFilename()),
1506 toqstr(fname.onlyFileName()));
1508 if (result.first == FileDialog::Later)
1511 fname.set(fromqstr(result.second));
1516 if (!isLyXFilename(fname.absFilename()))
1517 fname.changeExtension(".lyx");
1520 if (FileName(fname).exists()) {
1521 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1522 docstring text = bformat(_("The document %1$s already "
1523 "exists.\n\nDo you want to "
1524 "overwrite that document?"),
1526 int const ret = Alert::prompt(_("Overwrite document?"),
1527 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1530 case 1: return renameBuffer(b, docstring());
1531 case 2: return false;
1535 // Ok, change the name of the buffer
1536 b.setFileName(fname.absFilename());
1538 bool unnamed = b.isUnnamed();
1539 b.setUnnamed(false);
1540 b.saveCheckSum(fname);
1542 if (!saveBuffer(b)) {
1543 b.setFileName(oldname.absFilename());
1544 b.setUnnamed(unnamed);
1545 b.saveCheckSum(oldname);
1553 bool GuiView::saveBuffer(Buffer & b)
1556 return renameBuffer(b, docstring());
1559 LyX::ref().session().lastFiles().add(b.fileName());
1563 // Switch to this Buffer.
1566 // FIXME: we don't tell the user *WHY* the save failed !!
1567 docstring const file = makeDisplayPath(b.absFileName(), 30);
1568 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1569 "Do you want to rename the document and "
1570 "try again?"), file);
1571 int const ret = Alert::prompt(_("Rename and save?"),
1572 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1575 if (!renameBuffer(b, docstring()))
1584 return saveBuffer(b);
1588 bool GuiView::closeBuffer()
1590 Buffer * buf = buffer();
1591 return buf && closeBuffer(*buf);
1595 bool GuiView::closeBuffer(Buffer & buf)
1597 // goto bookmark to update bookmark pit.
1598 //FIXME: we should update only the bookmarks related to this buffer!
1599 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1600 theLyXFunc().gotoBookmark(i+1, false, false);
1602 if (buf.isClean() || buf.paragraphs().empty()) {
1603 if (buf.masterBuffer() == &buf)
1604 LyX::ref().session().lastOpened().add(buf.fileName());
1605 theBufferList().release(&buf);
1608 // Switch to this Buffer.
1613 if (buf.isUnnamed())
1614 file = from_utf8(buf.fileName().onlyFileName());
1616 file = buf.fileName().displayName(30);
1618 // Bring this window to top before asking questions.
1622 docstring const text = bformat(_("The document %1$s has unsaved changes."
1623 "\n\nDo you want to save the document or discard the changes?"), file);
1624 int const ret = Alert::prompt(_("Save changed document?"),
1625 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1629 if (!saveBuffer(buf))
1633 // if we crash after this we could
1634 // have no autosave file but I guess
1635 // this is really improbable (Jug)
1636 removeAutosaveFile(buf.absFileName());
1642 // save file names to .lyx/session
1643 // if master/slave are both open, do not save slave since it
1644 // will be automatically loaded when the master is loaded
1645 if (buf.masterBuffer() == &buf)
1646 LyX::ref().session().lastOpened().add(buf.fileName());
1648 theBufferList().release(&buf);
1653 bool GuiView::dispatch(FuncRequest const & cmd)
1655 BufferView * bv = view();
1656 // By default we won't need any update.
1658 bv->cursor().updateFlags(Update::None);
1660 switch(cmd.action) {
1661 case LFUN_BUFFER_IMPORT:
1662 importDocument(to_utf8(cmd.argument()));
1665 case LFUN_BUFFER_SWITCH:
1666 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1669 case LFUN_BUFFER_NEXT:
1670 setBuffer(theBufferList().next(buffer()));
1673 case LFUN_BUFFER_PREVIOUS:
1674 setBuffer(theBufferList().previous(buffer()));
1677 case LFUN_COMMAND_EXECUTE: {
1678 bool const show_it = cmd.argument() != "off";
1679 d.toolbars_->showCommandBuffer(show_it);
1682 case LFUN_DROP_LAYOUTS_CHOICE:
1684 d.layout_->showPopup();
1687 case LFUN_MENU_OPEN:
1688 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1689 menu->exec(QCursor::pos());
1692 case LFUN_FILE_INSERT:
1693 insertLyXFile(cmd.argument());
1695 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1696 insertPlaintextFile(cmd.argument(), true);
1699 case LFUN_FILE_INSERT_PLAINTEXT:
1700 insertPlaintextFile(cmd.argument(), false);
1703 case LFUN_BUFFER_WRITE:
1705 saveBuffer(bv->buffer());
1708 case LFUN_BUFFER_WRITE_AS:
1710 renameBuffer(bv->buffer(), cmd.argument());
1713 case LFUN_BUFFER_WRITE_ALL: {
1714 Buffer * first = theBufferList().first();
1717 message(_("Saving all documents..."));
1718 // We cannot use a for loop as the buffer list cycles.
1724 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1725 b = theBufferList().next(b);
1726 } while (b != first);
1727 message(_("All documents saved."));
1731 case LFUN_TOOLBAR_TOGGLE: {
1732 string const name = cmd.getArg(0);
1733 bool const allowauto = cmd.getArg(1) == "allowauto";
1734 // it is possible to get current toolbar status like this,...
1735 // but I decide to obey the order of ToolbarBackend::flags
1736 // and disregard real toolbar status.
1737 // toolbars_->saveToolbarInfo();
1739 // toggle state on/off/auto
1740 d.toolbars_->toggleToolbarState(name, allowauto);
1744 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1746 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1750 if (tbi->flags & ToolbarInfo::ON)
1752 else if (tbi->flags & ToolbarInfo::OFF)
1754 else if (tbi->flags & ToolbarInfo::AUTO)
1757 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1758 _(tbi->gui_name), state));
1762 case LFUN_DIALOG_UPDATE: {
1763 string const name = to_utf8(cmd.argument());
1764 // Can only update a dialog connected to an existing inset
1765 Inset * inset = getOpenInset(name);
1767 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1768 inset->dispatch(view()->cursor(), fr);
1769 } else if (name == "paragraph") {
1770 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1771 } else if (name == "prefs") {
1772 updateDialog(name, string());
1777 case LFUN_DIALOG_TOGGLE: {
1778 if (isDialogVisible(cmd.getArg(0)))
1779 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1781 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1785 case LFUN_DIALOG_DISCONNECT_INSET:
1786 disconnectDialog(to_utf8(cmd.argument()));
1789 case LFUN_DIALOG_HIDE: {
1790 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1794 case LFUN_DIALOG_SHOW: {
1795 string const name = cmd.getArg(0);
1796 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1798 if (name == "character") {
1799 data = freefont2string();
1801 showDialog("character", data);
1802 } else if (name == "latexlog") {
1803 Buffer::LogType type;
1804 string const logfile = buffer()->logName(&type);
1806 case Buffer::latexlog:
1809 case Buffer::buildlog:
1813 data += Lexer::quoteString(logfile);
1814 showDialog("log", data);
1815 } else if (name == "vclog") {
1816 string const data = "vc " +
1817 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1818 showDialog("log", data);
1819 } else if (name == "symbols") {
1820 data = bv->cursor().getEncoding()->name();
1822 showDialog("symbols", data);
1824 showDialog(name, data);
1828 case LFUN_INSET_APPLY: {
1829 string const name = cmd.getArg(0);
1830 Inset * inset = getOpenInset(name);
1832 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1833 inset->dispatch(view()->cursor(), fr);
1835 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1841 case LFUN_UI_TOGGLE:
1843 // Make sure the keyboard focus stays in the work area.
1847 case LFUN_COMPLETION_INLINE:
1848 if (d.current_work_area_)
1849 d.current_work_area_->completer().showInline();
1852 case LFUN_SPLIT_VIEW:
1853 if (Buffer * buf = buffer()) {
1854 string const orientation = cmd.getArg(0);
1855 d.splitter_->setOrientation(orientation == "vertical"
1856 ? Qt::Vertical : Qt::Horizontal);
1857 TabWorkArea * twa = addTabWorkArea();
1858 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1859 setCurrentWorkArea(wa);
1863 case LFUN_CLOSE_TAB_GROUP:
1864 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1866 twa = d.currentTabWorkArea();
1867 // Switch to the next GuiWorkArea in the found TabWorkArea.
1868 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1869 if (d.splitter_->count() == 0)
1870 // No more work area, switch to the background widget.
1875 case LFUN_COMPLETION_POPUP:
1876 if (d.current_work_area_)
1877 d.current_work_area_->completer().showPopup();
1881 case LFUN_COMPLETION_COMPLETE:
1882 if (d.current_work_area_)
1883 d.current_work_area_->completer().tab();
1894 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1896 string const arg = cmd.getArg(0);
1897 if (arg == "scrollbar") {
1898 // hide() is of no help
1899 if (d.current_work_area_->verticalScrollBarPolicy() ==
1900 Qt::ScrollBarAlwaysOff)
1902 d.current_work_area_->setVerticalScrollBarPolicy(
1903 Qt::ScrollBarAsNeeded);
1905 d.current_work_area_->setVerticalScrollBarPolicy(
1906 Qt::ScrollBarAlwaysOff);
1909 if (arg == "statusbar") {
1910 statusBar()->setVisible(!statusBar()->isVisible());
1913 if (arg == "menubar") {
1914 menuBar()->setVisible(!menuBar()->isVisible());
1917 #if QT_VERSION >= 0x040300
1918 if (arg == "frame") {
1920 getContentsMargins(&l, &t, &r, &b);
1921 //are the frames in default state?
1922 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1924 setContentsMargins(-2, -2, -2, -2);
1926 setContentsMargins(0, 0, 0, 0);
1931 if (arg != "fullscreen") {
1932 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1936 if (lyxrc.full_screen_toolbars)
1937 d.toolbars_->toggleFullScreen(!isFullScreen());
1939 if (isFullScreen()) {
1940 for (int i = 0; i != d.splitter_->count(); ++i)
1941 d.tabWorkArea(i)->setFullScreen(false);
1942 #if QT_VERSION >= 0x040300
1943 setContentsMargins(0, 0, 0, 0);
1947 statusBar()->show();
1949 for (int i = 0; i != d.splitter_->count(); ++i)
1950 d.tabWorkArea(i)->setFullScreen(true);
1951 #if QT_VERSION >= 0x040300
1952 setContentsMargins(-2, -2, -2, -2);
1955 statusBar()->hide();
1961 Buffer const * GuiView::updateInset(Inset const * inset)
1963 if (!d.current_work_area_)
1967 d.current_work_area_->scheduleRedraw();
1969 return &d.current_work_area_->bufferView().buffer();
1973 void GuiView::restartCursor()
1975 /* When we move around, or type, it's nice to be able to see
1976 * the cursor immediately after the keypress.
1978 if (d.current_work_area_)
1979 d.current_work_area_->startBlinkingCursor();
1981 // Take this occasion to update the other GUI elements.
1988 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
1990 if (d.current_work_area_)
1991 d.current_work_area_->completer().updateVisibility(cur, start, keep);
1996 // This list should be kept in sync with the list of insets in
1997 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
1998 // dialog should have the same name as the inset.
2000 char const * const dialognames[] = {
2001 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2002 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
2003 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2004 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2005 "ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
2007 #ifdef HAVE_LIBAIKSAURUS
2011 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2013 char const * const * const end_dialognames =
2014 dialognames + (sizeof(dialognames) / sizeof(char *));
2018 cmpCStr(char const * name) : name_(name) {}
2019 bool operator()(char const * other) {
2020 return strcmp(other, name_) == 0;
2027 bool isValidName(string const & name)
2029 return find_if(dialognames, end_dialognames,
2030 cmpCStr(name.c_str())) != end_dialognames;
2036 void GuiView::resetDialogs()
2038 // Make sure that no LFUN uses any LyXView.
2039 theLyXFunc().setLyXView(0);
2040 // FIXME: the "math panels" toolbar takes an awful lot of time to
2041 // initialise so we don't do that for the time being.
2042 //d.toolbars_->init();
2043 guiApp->menus().fillMenuBar(menuBar(), this);
2045 d.layout_->updateContents(true);
2046 // Now update controls with current buffer.
2047 theLyXFunc().setLyXView(this);
2052 Dialog * GuiView::find_or_build(string const & name)
2054 if (!isValidName(name))
2057 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2059 if (it != d.dialogs_.end())
2060 return it->second.get();
2062 Dialog * dialog = build(name);
2063 d.dialogs_[name].reset(dialog);
2064 if (lyxrc.allow_geometry_session)
2065 dialog->restoreSession();
2070 void GuiView::showDialog(string const & name, string const & data,
2077 Dialog * dialog = find_or_build(name);
2079 dialog->showData(data);
2081 d.open_insets_[name] = inset;
2087 bool GuiView::isDialogVisible(string const & name) const
2089 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2090 if (it == d.dialogs_.end())
2092 return it->second.get()->isVisibleView();
2096 void GuiView::hideDialog(string const & name, Inset * inset)
2098 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2099 if (it == d.dialogs_.end())
2102 if (inset && inset != getOpenInset(name))
2105 Dialog * const dialog = it->second.get();
2106 if (dialog->isVisibleView())
2108 d.open_insets_[name] = 0;
2112 void GuiView::disconnectDialog(string const & name)
2114 if (!isValidName(name))
2117 if (d.open_insets_.find(name) != d.open_insets_.end())
2118 d.open_insets_[name] = 0;
2122 Inset * GuiView::getOpenInset(string const & name) const
2124 if (!isValidName(name))
2127 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2128 return it == d.open_insets_.end() ? 0 : it->second;
2132 void GuiView::hideAll() const
2134 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2135 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2137 for(; it != end; ++it)
2138 it->second->hideView();
2142 void GuiView::hideBufferDependent() const
2144 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2145 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2147 for(; it != end; ++it) {
2148 Dialog * dialog = it->second.get();
2149 if (dialog->isBufferDependent())
2155 void GuiView::updateBufferDependent(bool switched) const
2157 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2158 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2160 for(; it != end; ++it) {
2161 Dialog * dialog = it->second.get();
2162 if (!dialog->isVisibleView())
2164 if (switched && dialog->isBufferDependent()) {
2165 if (dialog->initialiseParams(""))
2166 dialog->updateView();
2170 // A bit clunky, but the dialog will request
2171 // that the kernel provides it with the necessary
2173 dialog->updateDialog();
2179 void GuiView::checkStatus()
2181 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2182 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2184 for(; it != end; ++it) {
2185 Dialog * const dialog = it->second.get();
2186 if (dialog && dialog->isVisibleView())
2187 dialog->checkStatus();
2193 // will be replaced by a proper factory...
2194 Dialog * createGuiAbout(GuiView & lv);
2195 Dialog * createGuiBibitem(GuiView & lv);
2196 Dialog * createGuiBibtex(GuiView & lv);
2197 Dialog * createGuiBox(GuiView & lv);
2198 Dialog * createGuiBranch(GuiView & lv);
2199 Dialog * createGuiChanges(GuiView & lv);
2200 Dialog * createGuiCharacter(GuiView & lv);
2201 Dialog * createGuiCitation(GuiView & lv);
2202 Dialog * createGuiDelimiter(GuiView & lv);
2203 Dialog * createGuiDocument(GuiView & lv);
2204 Dialog * createGuiErrorList(GuiView & lv);
2205 Dialog * createGuiERT(GuiView & lv);
2206 Dialog * createGuiExternal(GuiView & lv);
2207 Dialog * createGuiFloat(GuiView & lv);
2208 Dialog * createGuiGraphics(GuiView & lv);
2209 Dialog * createGuiInclude(GuiView & lv);
2210 Dialog * createGuiLabel(GuiView & lv);
2211 Dialog * createGuiListings(GuiView & lv);
2212 Dialog * createGuiLog(GuiView & lv);
2213 Dialog * createGuiMathMatrix(GuiView & lv);
2214 Dialog * createGuiNomenclature(GuiView & lv);
2215 Dialog * createGuiNote(GuiView & lv);
2216 Dialog * createGuiParagraph(GuiView & lv);
2217 Dialog * createGuiPreferences(GuiView & lv);
2218 Dialog * createGuiPrint(GuiView & lv);
2219 Dialog * createGuiRef(GuiView & lv);
2220 Dialog * createGuiSearch(GuiView & lv);
2221 Dialog * createGuiSendTo(GuiView & lv);
2222 Dialog * createGuiShowFile(GuiView & lv);
2223 Dialog * createGuiSpellchecker(GuiView & lv);
2224 Dialog * createGuiSymbols(GuiView & lv);
2225 Dialog * createGuiTabularCreate(GuiView & lv);
2226 Dialog * createGuiTabular(GuiView & lv);
2227 Dialog * createGuiTexInfo(GuiView & lv);
2228 Dialog * createGuiToc(GuiView & lv);
2229 Dialog * createGuiThesaurus(GuiView & lv);
2230 Dialog * createGuiHyperlink(GuiView & lv);
2231 Dialog * createGuiVSpace(GuiView & lv);
2232 Dialog * createGuiViewSource(GuiView & lv);
2233 Dialog * createGuiWrap(GuiView & lv);
2236 Dialog * GuiView::build(string const & name)
2238 BOOST_ASSERT(isValidName(name));
2240 if (name == "aboutlyx")
2241 return createGuiAbout(*this);
2242 if (name == "bibitem")
2243 return createGuiBibitem(*this);
2244 if (name == "bibtex")
2245 return createGuiBibtex(*this);
2247 return createGuiBox(*this);
2248 if (name == "branch")
2249 return createGuiBranch(*this);
2250 if (name == "changes")
2251 return createGuiChanges(*this);
2252 if (name == "character")
2253 return createGuiCharacter(*this);
2254 if (name == "citation")
2255 return createGuiCitation(*this);
2256 if (name == "document")
2257 return createGuiDocument(*this);
2258 if (name == "errorlist")
2259 return createGuiErrorList(*this);
2261 return createGuiERT(*this);
2262 if (name == "external")
2263 return createGuiExternal(*this);
2265 return createGuiShowFile(*this);
2266 if (name == "findreplace")
2267 return createGuiSearch(*this);
2268 if (name == "float")
2269 return createGuiFloat(*this);
2270 if (name == "graphics")
2271 return createGuiGraphics(*this);
2272 if (name == "include")
2273 return createGuiInclude(*this);
2274 if (name == "nomenclature")
2275 return createGuiNomenclature(*this);
2276 if (name == "label")
2277 return createGuiLabel(*this);
2279 return createGuiLog(*this);
2280 if (name == "view-source")
2281 return createGuiViewSource(*this);
2282 if (name == "mathdelimiter")
2283 return createGuiDelimiter(*this);
2284 if (name == "mathmatrix")
2285 return createGuiMathMatrix(*this);
2287 return createGuiNote(*this);
2288 if (name == "paragraph")
2289 return createGuiParagraph(*this);
2290 if (name == "prefs")
2291 return createGuiPreferences(*this);
2292 if (name == "print")
2293 return createGuiPrint(*this);
2295 return createGuiRef(*this);
2296 if (name == "sendto")
2297 return createGuiSendTo(*this);
2298 if (name == "spellchecker")
2299 return createGuiSpellchecker(*this);
2300 if (name == "symbols")
2301 return createGuiSymbols(*this);
2302 if (name == "tabular")
2303 return createGuiTabular(*this);
2304 if (name == "tabularcreate")
2305 return createGuiTabularCreate(*this);
2306 if (name == "texinfo")
2307 return createGuiTexInfo(*this);
2308 #ifdef HAVE_LIBAIKSAURUS
2309 if (name == "thesaurus")
2310 return createGuiThesaurus(*this);
2313 return createGuiToc(*this);
2315 return createGuiHyperlink(*this);
2316 if (name == "vspace")
2317 return createGuiVSpace(*this);
2319 return createGuiWrap(*this);
2320 if (name == "listings")
2321 return createGuiListings(*this);
2327 } // namespace frontend
2330 #include "GuiView_moc.cpp"