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 // set ourself as the current view. This is needed for the menu bar
281 // filling, at least for the static special menu item on Mac. Otherwise
282 // they are greyed out.
283 theLyXFunc().setLyXView(this);
285 // Fill up the menu bar.
286 guiApp->menus().fillMenuBar(menuBar(), this);
288 setCentralWidget(d.stack_widget_);
290 // Start autosave timer
291 if (lyxrc.autosave) {
292 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
293 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
294 d.autosave_timeout_.start();
296 connect(&d.statusbar_timer_, SIGNAL(timeout()),
297 this, SLOT(clearMessage()));
299 // We don't want to keep the window in memory if it is closed.
300 setAttribute(Qt::WA_DeleteOnClose, true);
303 // assign an icon to main form. We do not do it under Qt/Mac,
304 // since the icon is provided in the application bundle.
305 setWindowIcon(QPixmap(":/images/lyx.png"));
309 setAcceptDrops(true);
311 statusBar()->setSizeGripEnabled(true);
313 // Forbid too small unresizable window because it can happen
314 // with some window manager under X11.
315 setMinimumSize(300, 200);
317 if (!lyxrc.allow_geometry_session)
318 // No session handling, default to a sane size.
319 setGeometry(50, 50, 690, 510);
321 // Now take care of session management.
323 QString const key = "view-" + QString::number(id_);
325 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
326 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
330 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
331 setGeometry(50, 50, 690, 510);
333 setIconSize(settings.value(key + "/icon_size").toSize());
343 void GuiView::setFocus()
345 if (d.current_work_area_)
346 d.current_work_area_->setFocus();
352 QMenu * GuiView::createPopupMenu()
354 return d.toolBarPopup(this);
358 void GuiView::showEvent(QShowEvent * e)
360 LYXERR(Debug::GUI, "Passed Geometry "
361 << size().height() << "x" << size().width()
362 << "+" << pos().x() << "+" << pos().y());
364 if (d.splitter_->count() == 0)
365 // No work area, switch to the background widget.
368 QMainWindow::showEvent(e);
372 void GuiView::closeEvent(QCloseEvent * close_event)
374 // it can happen that this event arrives without selecting the view,
375 // e.g. when clicking the close button on a background window.
376 theLyXFunc().setLyXView(this);
378 while (Buffer * b = buffer()) {
380 // This is a child document, just close the tab after saving
381 // but keep the file loaded.
382 if (!saveBuffer(*b)) {
383 close_event->ignore();
386 removeWorkArea(d.current_work_area_);
390 std::vector<int> const & ids = guiApp->viewIds();
391 for (size_type i = 0; i != ids.size(); ++i) {
394 if (guiApp->view(ids[i]).workArea(*b)) {
395 // FIXME 1: should we put an alert box here that the buffer
396 // is viewed elsewhere?
397 // FIXME 2: should we try to save this buffer in any case?
400 // This buffer is also opened in another view, so
401 // but close the associated work area nevertheless.
402 removeWorkArea(d.current_work_area_);
403 // but don't close it.
408 if (b && !closeBuffer(*b)) {
409 close_event->ignore();
414 // Make sure that no LFUN use this close to be closed View.
415 theLyXFunc().setLyXView(0);
417 // Save toolbars configuration
418 if (isFullScreen()) {
419 d.toolbars_->toggleFullScreen(!isFullScreen());
423 // Make sure the timer time out will not trigger a statusbar update.
424 d.statusbar_timer_.stop();
426 // Saving fullscreen requires additional tweaks in the toolbar code.
427 // It wouldn't also work under linux natively.
428 if (lyxrc.allow_geometry_session && !isFullScreen()) {
430 QString const key = "view-" + QString::number(id_);
432 settings.setValue(key + "/pos", pos());
433 settings.setValue(key + "/size", size());
435 settings.setValue(key + "/geometry", saveGeometry());
437 settings.setValue(key + "/icon_size", iconSize());
438 d.toolbars_->saveToolbarInfo();
439 // Now take care of all other dialogs:
440 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
441 for (; it!= d.dialogs_.end(); ++it)
442 it->second->saveSession();
445 guiApp->unregisterView(id_);
446 close_event->accept();
450 void GuiView::dragEnterEvent(QDragEnterEvent * event)
452 if (event->mimeData()->hasUrls())
454 /// \todo Ask lyx-devel is this is enough:
455 /// if (event->mimeData()->hasFormat("text/plain"))
456 /// event->acceptProposedAction();
460 void GuiView::dropEvent(QDropEvent* event)
462 QList<QUrl> files = event->mimeData()->urls();
466 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
467 for (int i = 0; i != files.size(); ++i) {
468 string const file = os::internal_path(fromqstr(
469 files.at(i).toLocalFile()));
471 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
476 void GuiView::message(docstring const & str)
478 if (ForkedProcess::iAmAChild())
481 statusBar()->showMessage(toqstr(str));
482 d.statusbar_timer_.stop();
483 d.statusbar_timer_.start(3000);
487 void GuiView::smallSizedIcons()
489 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
493 void GuiView::normalSizedIcons()
495 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
499 void GuiView::bigSizedIcons()
501 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
505 void GuiView::clearMessage()
509 theLyXFunc().setLyXView(this);
510 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
511 d.statusbar_timer_.stop();
515 void GuiView::updateWindowTitle(GuiWorkArea * wa)
517 if (wa != d.current_work_area_)
519 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
520 setWindowIconText(wa->windowIconText());
524 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
527 disconnectBufferView();
528 connectBufferView(wa->bufferView());
529 connectBuffer(wa->bufferView().buffer());
530 d.current_work_area_ = wa;
531 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
532 this, SLOT(updateWindowTitle(GuiWorkArea *)));
533 updateWindowTitle(wa);
536 // Buffer-dependent dialogs should be updated or
537 // hidden. This should go here because some dialogs (eg ToC)
538 // require bv_->text.
539 updateBufferDependent(true);
546 void GuiView::on_lastWorkAreaRemoved()
549 // On Mac close the view if there is no Tab open anymore,
550 // but only if no splitter is visible
551 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
552 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
553 if (twa && twa->count() == 0) {
554 // close the view, as no tab is open anymore
555 QTimer::singleShot(0, this, SLOT(close()));
562 void GuiView::updateStatusBar()
564 // let the user see the explicit message
565 if (d.statusbar_timer_.isActive())
568 theLyXFunc().setLyXView(this);
569 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
573 bool GuiView::hasFocus() const
575 return qApp->activeWindow() == this;
579 bool GuiView::event(QEvent * e)
583 // Useful debug code:
584 //case QEvent::ActivationChange:
585 //case QEvent::WindowDeactivate:
586 //case QEvent::Paint:
587 //case QEvent::Enter:
588 //case QEvent::Leave:
589 //case QEvent::HoverEnter:
590 //case QEvent::HoverLeave:
591 //case QEvent::HoverMove:
592 //case QEvent::StatusTip:
593 //case QEvent::DragEnter:
594 //case QEvent::DragLeave:
598 case QEvent::WindowActivate: {
599 if (this == guiApp->currentView()) {
601 return QMainWindow::event(e);
603 guiApp->setCurrentView(*this);
604 if (d.current_work_area_) {
605 BufferView & bv = d.current_work_area_->bufferView();
606 connectBufferView(bv);
607 connectBuffer(bv.buffer());
608 // The document structure, name and dialogs might have
609 // changed in another view.
610 updateBufferDependent(true);
615 setWindowTitle(qt_("LyX"));
616 setWindowIconText(qt_("LyX"));
619 return QMainWindow::event(e);
622 case QEvent::ShortcutOverride: {
623 if (d.current_work_area_)
624 // Nothing special to do.
625 return QMainWindow::event(e);
627 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
629 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
631 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
632 || ke->key() == Qt::Key_Backtab)
633 return QMainWindow::event(e);
635 // Allow processing of shortcuts that are allowed even when no Buffer
637 theLyXFunc().setLyXView(this);
639 setKeySymbol(&sym, ke);
640 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
646 return QMainWindow::event(e);
651 bool GuiView::focusNextPrevChild(bool /*next*/)
658 void GuiView::setBusy(bool busy)
660 if (d.current_work_area_) {
661 d.current_work_area_->setUpdatesEnabled(!busy);
663 d.current_work_area_->stopBlinkingCursor();
665 d.current_work_area_->startBlinkingCursor();
669 QApplication::setOverrideCursor(Qt::WaitCursor);
671 QApplication::restoreOverrideCursor();
675 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
677 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
679 if (tbinfo.flags & ToolbarInfo::TOP) {
681 addToolBarBreak(Qt::TopToolBarArea);
682 addToolBar(Qt::TopToolBarArea, toolBar);
685 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
686 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
687 #if (QT_VERSION >= 0x040202)
689 addToolBarBreak(Qt::BottomToolBarArea);
691 addToolBar(Qt::BottomToolBarArea, toolBar);
694 if (tbinfo.flags & ToolbarInfo::LEFT) {
695 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
696 #if (QT_VERSION >= 0x040202)
698 addToolBarBreak(Qt::LeftToolBarArea);
700 addToolBar(Qt::LeftToolBarArea, toolBar);
703 if (tbinfo.flags & ToolbarInfo::RIGHT) {
704 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
705 #if (QT_VERSION >= 0x040202)
707 addToolBarBreak(Qt::RightToolBarArea);
709 addToolBar(Qt::RightToolBarArea, toolBar);
712 // The following does not work so I cannot restore to exact toolbar location
714 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
715 toolBar->move(tbinfo.posx, tbinfo.posy);
722 GuiWorkArea * GuiView::workArea(Buffer & buffer)
724 if (TabWorkArea * twa = d.currentTabWorkArea())
725 return twa->workArea(buffer);
730 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
732 // Automatically create a TabWorkArea if there are none yet.
733 TabWorkArea * tab_widget = d.splitter_->count()
734 ? d.currentTabWorkArea() : addTabWorkArea();
735 return tab_widget->addWorkArea(buffer, *this);
739 TabWorkArea * GuiView::addTabWorkArea()
741 TabWorkArea * twa = new TabWorkArea;
742 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
743 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
744 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
745 this, SLOT(on_lastWorkAreaRemoved()));
747 d.splitter_->addWidget(twa);
748 d.stack_widget_->setCurrentWidget(d.splitter_);
753 GuiWorkArea const * GuiView::currentWorkArea() const
755 return d.current_work_area_;
759 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
763 // Changing work area can result from opening a file so
764 // update the toc in any case.
767 d.current_work_area_ = wa;
768 for (int i = 0; i != d.splitter_->count(); ++i) {
769 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
775 void GuiView::removeWorkArea(GuiWorkArea * wa)
778 if (wa == d.current_work_area_) {
780 disconnectBufferView();
781 hideBufferDependent();
782 d.current_work_area_ = 0;
785 for (int i = 0; i != d.splitter_->count(); ++i) {
786 TabWorkArea * twa = d.tabWorkArea(i);
787 if (!twa->removeWorkArea(wa))
788 // Not found in this tab group.
791 // We found and removed the GuiWorkArea.
793 // No more WorkAreas in this tab group, so delete it.
798 if (d.current_work_area_)
799 // This means that we are not closing the current GuiWorkArea;
802 // Switch to the next GuiWorkArea in the found TabWorkArea.
803 d.current_work_area_ = twa->currentWorkArea();
807 if (d.splitter_->count() == 0)
808 // No more work area, switch to the background widget.
813 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
819 void GuiView::updateLayoutList()
822 d.layout_->updateContents(false);
826 void GuiView::updateToolbars()
828 if (d.current_work_area_) {
830 d.current_work_area_->bufferView().cursor().inMathed();
832 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
834 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
835 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
836 bool const mathmacrotemplate =
837 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
839 d.toolbars_->update(math, table, review, mathmacrotemplate);
841 d.toolbars_->update(false, false, false, false);
843 // update read-only status of open dialogs.
848 Buffer * GuiView::buffer()
850 if (d.current_work_area_)
851 return &d.current_work_area_->bufferView().buffer();
856 Buffer const * GuiView::buffer() const
858 if (d.current_work_area_)
859 return &d.current_work_area_->bufferView().buffer();
864 void GuiView::setBuffer(Buffer * newBuffer)
866 BOOST_ASSERT(newBuffer);
869 GuiWorkArea * wa = workArea(*newBuffer);
871 updateLabels(*newBuffer->masterBuffer());
872 wa = addWorkArea(*newBuffer);
874 //Disconnect the old buffer...there's no new one.
877 connectBuffer(*newBuffer);
878 connectBufferView(wa->bufferView());
879 setCurrentWorkArea(wa);
885 void GuiView::connectBuffer(Buffer & buf)
887 buf.setGuiDelegate(this);
891 void GuiView::disconnectBuffer()
893 if (d.current_work_area_)
894 d.current_work_area_->bufferView().setGuiDelegate(0);
898 void GuiView::connectBufferView(BufferView & bv)
900 bv.setGuiDelegate(this);
904 void GuiView::disconnectBufferView()
906 if (d.current_work_area_)
907 d.current_work_area_->bufferView().setGuiDelegate(0);
911 void GuiView::errors(string const & error_type)
913 ErrorList & el = buffer()->errorList(error_type);
915 showDialog("errorlist", error_type);
919 void GuiView::updateDialog(string const & name, string const & data)
921 if (!isDialogVisible(name))
924 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
925 if (it == d.dialogs_.end())
928 Dialog * const dialog = it->second.get();
929 if (dialog->isVisibleView())
930 dialog->updateData(data);
934 BufferView * GuiView::view()
936 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
940 void GuiView::updateToc()
942 updateDialog("toc", "");
946 void GuiView::updateEmbeddedFiles()
948 updateDialog("embedding", "");
952 void GuiView::autoSave()
954 LYXERR(Debug::INFO, "Running autoSave()");
957 view()->buffer().autoSave();
961 void GuiView::resetAutosaveTimers()
964 d.autosave_timeout_.restart();
968 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
972 Buffer * buf = buffer();
974 /* In LyX/Mac, when a dialog is open, the menus of the
975 application can still be accessed without giving focus to
976 the main window. In this case, we want to disable the menu
977 entries that are buffer-related.
979 Note that this code is not perfect, as bug 1941 attests:
980 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
982 if (cmd.origin == FuncRequest::MENU && !hasFocus())
986 case LFUN_BUFFER_WRITE:
987 enable = buf && (buf->isUnnamed() || !buf->isClean());
990 case LFUN_BUFFER_WRITE_AS:
994 case LFUN_SPLIT_VIEW:
998 case LFUN_CLOSE_TAB_GROUP:
999 enable = d.currentTabWorkArea();
1002 case LFUN_TOOLBAR_TOGGLE:
1003 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1006 case LFUN_DIALOG_TOGGLE:
1007 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1008 // fall through to set "enable"
1009 case LFUN_DIALOG_SHOW: {
1010 string const name = cmd.getArg(0);
1012 enable = name == "aboutlyx"
1013 || name == "file" //FIXME: should be removed.
1015 || name == "texinfo";
1016 else if (name == "print")
1017 enable = buf->isExportable("dvi")
1018 && lyxrc.print_command != "none";
1019 else if (name == "character") {
1023 InsetCode ic = view()->cursor().inset().lyxCode();
1024 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1027 else if (name == "symbols") {
1028 if (!view() || view()->cursor().inMathed())
1031 InsetCode ic = view()->cursor().inset().lyxCode();
1032 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1035 else if (name == "latexlog")
1036 enable = FileName(buf->logName()).isReadableFile();
1037 else if (name == "spellchecker")
1038 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1039 enable = !buf->isReadonly();
1043 else if (name == "vclog")
1044 enable = buf->lyxvc().inUse();
1048 case LFUN_DIALOG_UPDATE: {
1049 string const name = cmd.getArg(0);
1051 enable = name == "prefs";
1055 case LFUN_INSET_APPLY: {
1060 string const name = cmd.getArg(0);
1061 Inset * inset = getOpenInset(name);
1063 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1065 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1066 // Every inset is supposed to handle this
1067 BOOST_ASSERT(false);
1071 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1072 flag |= getStatus(fr);
1074 enable = flag.enabled();
1078 case LFUN_COMPLETION_INLINE:
1079 if (!d.current_work_area_
1080 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1084 case LFUN_COMPLETION_POPUP:
1085 if (!d.current_work_area_
1086 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1090 case LFUN_COMPLETION_COMPLETE:
1091 if (!d.current_work_area_
1092 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1104 flag.enabled(false);
1110 static FileName selectTemplateFile()
1112 FileDialog dlg(qt_("Select template file"));
1113 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1114 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1116 FileDialog::Result result =
1117 dlg.open(toqstr(lyxrc.template_path),
1118 FileFilterList(_("LyX Documents (*.lyx)")));
1120 if (result.first == FileDialog::Later)
1122 if (result.second.isEmpty())
1124 return FileName(fromqstr(result.second));
1128 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1132 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1135 message(_("Document not loaded."));
1140 setBuffer(newBuffer);
1142 // scroll to the position when the file was last closed
1143 if (lyxrc.use_lastfilepos) {
1144 LastFilePosSection::FilePos filepos =
1145 LyX::ref().session().lastFilePos().load(filename);
1146 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1150 LyX::ref().session().lastFiles().add(filename);
1157 void GuiView::openDocument(string const & fname)
1159 string initpath = lyxrc.document_path;
1162 string const trypath = buffer()->filePath();
1163 // If directory is writeable, use this as default.
1164 if (FileName(trypath).isDirWritable())
1170 if (fname.empty()) {
1171 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1172 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1173 dlg.setButton2(qt_("Examples|#E#e"),
1174 toqstr(addPath(package().system_support().absFilename(), "examples")));
1176 FileDialog::Result result =
1177 dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1179 if (result.first == FileDialog::Later)
1182 filename = fromqstr(result.second);
1184 // check selected filename
1185 if (filename.empty()) {
1186 message(_("Canceled."));
1192 // get absolute path of file and add ".lyx" to the filename if
1194 FileName const fullname =
1195 fileSearch(string(), filename, "lyx", support::may_not_exist);
1196 if (!fullname.empty())
1197 filename = fullname.absFilename();
1199 // if the file doesn't exist, let the user create one
1200 if (!fullname.exists()) {
1201 // the user specifically chose this name. Believe him.
1202 Buffer * const b = newFile(filename, string(), true);
1208 docstring const disp_fn = makeDisplayPath(filename);
1209 message(bformat(_("Opening document %1$s..."), disp_fn));
1212 Buffer * buf = loadDocument(fullname);
1217 buf->errors("Parse");
1218 str2 = bformat(_("Document %1$s opened."), disp_fn);
1220 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1225 // FIXME: clean that
1226 static bool import(GuiView * lv, FileName const & filename,
1227 string const & format, ErrorList & errorList)
1229 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1231 string loader_format;
1232 vector<string> loaders = theConverters().loaders();
1233 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1234 for (vector<string>::const_iterator it = loaders.begin();
1235 it != loaders.end(); ++it) {
1236 if (!theConverters().isReachable(format, *it))
1239 string const tofile =
1240 support::changeExtension(filename.absFilename(),
1241 formats.extension(*it));
1242 if (!theConverters().convert(0, filename, FileName(tofile),
1243 filename, format, *it, errorList))
1245 loader_format = *it;
1248 if (loader_format.empty()) {
1249 frontend::Alert::error(_("Couldn't import file"),
1250 bformat(_("No information for importing the format %1$s."),
1251 formats.prettyName(format)));
1255 loader_format = format;
1257 if (loader_format == "lyx") {
1258 Buffer * buf = lv->loadDocument(lyxfile);
1263 buf->errors("Parse");
1265 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1269 bool as_paragraphs = loader_format == "textparagraph";
1270 string filename2 = (loader_format == format) ? filename.absFilename()
1271 : support::changeExtension(filename.absFilename(),
1272 formats.extension(loader_format));
1273 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1274 theLyXFunc().setLyXView(lv);
1275 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1282 void GuiView::importDocument(string const & argument)
1285 string filename = split(argument, format, ' ');
1287 LYXERR(Debug::INFO, format << " file: " << filename);
1289 // need user interaction
1290 if (filename.empty()) {
1291 string initpath = lyxrc.document_path;
1293 Buffer const * buf = buffer();
1295 string const trypath = buf->filePath();
1296 // If directory is writeable, use this as default.
1297 if (FileName(trypath).isDirWritable())
1301 docstring const text = bformat(_("Select %1$s file to import"),
1302 formats.prettyName(format));
1304 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1305 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1306 dlg.setButton2(qt_("Examples|#E#e"),
1307 toqstr(addPath(package().system_support().absFilename(), "examples")));
1309 docstring filter = formats.prettyName(format);
1312 filter += from_utf8(formats.extension(format));
1315 FileDialog::Result result =
1316 dlg.open(toqstr(initpath), FileFilterList(filter));
1318 if (result.first == FileDialog::Later)
1321 filename = fromqstr(result.second);
1323 // check selected filename
1324 if (filename.empty())
1325 message(_("Canceled."));
1328 if (filename.empty())
1331 // get absolute path of file
1332 FileName const fullname(makeAbsPath(filename));
1334 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1336 // Check if the document already is open
1337 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1340 if (!closeBuffer()) {
1341 message(_("Canceled."));
1346 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1348 // if the file exists already, and we didn't do
1349 // -i lyx thefile.lyx, warn
1350 if (lyxfile.exists() && fullname != lyxfile) {
1352 docstring text = bformat(_("The document %1$s already exists.\n\n"
1353 "Do you want to overwrite that document?"), displaypath);
1354 int const ret = Alert::prompt(_("Overwrite document?"),
1355 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1358 message(_("Canceled."));
1363 message(bformat(_("Importing %1$s..."), displaypath));
1364 ErrorList errorList;
1365 if (import(this, fullname, format, errorList))
1366 message(_("imported."));
1368 message(_("file not imported!"));
1370 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1374 void GuiView::newDocument(string const & filename, bool from_template)
1376 FileName initpath(lyxrc.document_path);
1377 Buffer * buf = buffer();
1379 FileName const trypath(buf->filePath());
1380 // If directory is writeable, use this as default.
1381 if (trypath.isDirWritable())
1385 string templatefile = from_template ?
1386 selectTemplateFile().absFilename() : string();
1388 if (filename.empty())
1389 b = newUnnamedFile(templatefile, initpath);
1391 b = newFile(filename, templatefile, true);
1395 // Ensure the cursor is correctly positionned on screen.
1396 view()->showCursor();
1400 void GuiView::insertLyXFile(docstring const & fname)
1402 BufferView * bv = view();
1407 FileName filename(to_utf8(fname));
1409 if (!filename.empty()) {
1410 bv->insertLyXFile(filename);
1414 // Launch a file browser
1416 string initpath = lyxrc.document_path;
1417 string const trypath = bv->buffer().filePath();
1418 // If directory is writeable, use this as default.
1419 if (FileName(trypath).isDirWritable())
1423 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1424 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1425 dlg.setButton2(qt_("Examples|#E#e"),
1426 toqstr(addPath(package().system_support().absFilename(),
1429 FileDialog::Result result =
1430 dlg.open(toqstr(initpath),
1431 FileFilterList(_("LyX Documents (*.lyx)")));
1433 if (result.first == FileDialog::Later)
1437 filename.set(fromqstr(result.second));
1439 // check selected filename
1440 if (filename.empty()) {
1441 // emit message signal.
1442 message(_("Canceled."));
1446 bv->insertLyXFile(filename);
1450 void GuiView::insertPlaintextFile(docstring const & fname,
1453 BufferView * bv = view();
1458 FileName filename(to_utf8(fname));
1460 if (!filename.empty()) {
1461 bv->insertPlaintextFile(filename, asParagraph);
1465 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1466 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1468 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1471 if (result.first == FileDialog::Later)
1475 filename.set(fromqstr(result.second));
1477 // check selected filename
1478 if (filename.empty()) {
1479 // emit message signal.
1480 message(_("Canceled."));
1484 bv->insertPlaintextFile(filename, asParagraph);
1488 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1490 FileName fname = b.fileName();
1491 FileName const oldname = fname;
1493 if (!newname.empty()) {
1495 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1497 // Switch to this Buffer.
1500 /// No argument? Ask user through dialog.
1502 FileDialog dlg(qt_("Choose a filename to save document as"),
1503 LFUN_BUFFER_WRITE_AS);
1504 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1505 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1507 if (!isLyXFilename(fname.absFilename()))
1508 fname.changeExtension(".lyx");
1510 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1512 FileDialog::Result result =
1513 dlg.save(toqstr(fname.onlyPath().absFilename()),
1515 toqstr(fname.onlyFileName()));
1517 if (result.first == FileDialog::Later)
1520 fname.set(fromqstr(result.second));
1525 if (!isLyXFilename(fname.absFilename()))
1526 fname.changeExtension(".lyx");
1529 if (FileName(fname).exists()) {
1530 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1531 docstring text = bformat(_("The document %1$s already "
1532 "exists.\n\nDo you want to "
1533 "overwrite that document?"),
1535 int const ret = Alert::prompt(_("Overwrite document?"),
1536 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1539 case 1: return renameBuffer(b, docstring());
1540 case 2: return false;
1544 // Ok, change the name of the buffer
1545 b.setFileName(fname.absFilename());
1547 bool unnamed = b.isUnnamed();
1548 b.setUnnamed(false);
1549 b.saveCheckSum(fname);
1551 if (!saveBuffer(b)) {
1552 b.setFileName(oldname.absFilename());
1553 b.setUnnamed(unnamed);
1554 b.saveCheckSum(oldname);
1562 bool GuiView::saveBuffer(Buffer & b)
1565 return renameBuffer(b, docstring());
1568 LyX::ref().session().lastFiles().add(b.fileName());
1572 // Switch to this Buffer.
1575 // FIXME: we don't tell the user *WHY* the save failed !!
1576 docstring const file = makeDisplayPath(b.absFileName(), 30);
1577 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1578 "Do you want to rename the document and "
1579 "try again?"), file);
1580 int const ret = Alert::prompt(_("Rename and save?"),
1581 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1584 if (!renameBuffer(b, docstring()))
1593 return saveBuffer(b);
1597 bool GuiView::closeBuffer()
1599 Buffer * buf = buffer();
1600 return buf && closeBuffer(*buf);
1604 bool GuiView::closeBuffer(Buffer & buf)
1606 // goto bookmark to update bookmark pit.
1607 //FIXME: we should update only the bookmarks related to this buffer!
1608 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1609 theLyXFunc().gotoBookmark(i+1, false, false);
1611 if (buf.isClean() || buf.paragraphs().empty()) {
1612 if (buf.masterBuffer() == &buf)
1613 LyX::ref().session().lastOpened().add(buf.fileName());
1614 theBufferList().release(&buf);
1617 // Switch to this Buffer.
1622 if (buf.isUnnamed())
1623 file = from_utf8(buf.fileName().onlyFileName());
1625 file = buf.fileName().displayName(30);
1627 // Bring this window to top before asking questions.
1631 docstring const text = bformat(_("The document %1$s has unsaved changes."
1632 "\n\nDo you want to save the document or discard the changes?"), file);
1633 int const ret = Alert::prompt(_("Save changed document?"),
1634 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1638 if (!saveBuffer(buf))
1642 // if we crash after this we could
1643 // have no autosave file but I guess
1644 // this is really improbable (Jug)
1645 removeAutosaveFile(buf.absFileName());
1651 // save file names to .lyx/session
1652 // if master/slave are both open, do not save slave since it
1653 // will be automatically loaded when the master is loaded
1654 if (buf.masterBuffer() == &buf)
1655 LyX::ref().session().lastOpened().add(buf.fileName());
1657 theBufferList().release(&buf);
1662 bool GuiView::dispatch(FuncRequest const & cmd)
1664 BufferView * bv = view();
1665 // By default we won't need any update.
1667 bv->cursor().updateFlags(Update::None);
1669 switch(cmd.action) {
1670 case LFUN_BUFFER_IMPORT:
1671 importDocument(to_utf8(cmd.argument()));
1674 case LFUN_BUFFER_SWITCH:
1675 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1678 case LFUN_BUFFER_NEXT:
1679 setBuffer(theBufferList().next(buffer()));
1682 case LFUN_BUFFER_PREVIOUS:
1683 setBuffer(theBufferList().previous(buffer()));
1686 case LFUN_COMMAND_EXECUTE: {
1687 bool const show_it = cmd.argument() != "off";
1688 d.toolbars_->showCommandBuffer(show_it);
1691 case LFUN_DROP_LAYOUTS_CHOICE:
1693 d.layout_->showPopup();
1696 case LFUN_MENU_OPEN:
1697 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1698 menu->exec(QCursor::pos());
1701 case LFUN_FILE_INSERT:
1702 insertLyXFile(cmd.argument());
1704 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1705 insertPlaintextFile(cmd.argument(), true);
1708 case LFUN_FILE_INSERT_PLAINTEXT:
1709 insertPlaintextFile(cmd.argument(), false);
1712 case LFUN_BUFFER_WRITE:
1714 saveBuffer(bv->buffer());
1717 case LFUN_BUFFER_WRITE_AS:
1719 renameBuffer(bv->buffer(), cmd.argument());
1722 case LFUN_BUFFER_WRITE_ALL: {
1723 Buffer * first = theBufferList().first();
1726 message(_("Saving all documents..."));
1727 // We cannot use a for loop as the buffer list cycles.
1733 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1734 b = theBufferList().next(b);
1735 } while (b != first);
1736 message(_("All documents saved."));
1740 case LFUN_TOOLBAR_TOGGLE: {
1741 string const name = cmd.getArg(0);
1742 bool const allowauto = cmd.getArg(1) == "allowauto";
1743 // it is possible to get current toolbar status like this,...
1744 // but I decide to obey the order of ToolbarBackend::flags
1745 // and disregard real toolbar status.
1746 // toolbars_->saveToolbarInfo();
1748 // toggle state on/off/auto
1749 d.toolbars_->toggleToolbarState(name, allowauto);
1753 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1755 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1759 if (tbi->flags & ToolbarInfo::ON)
1761 else if (tbi->flags & ToolbarInfo::OFF)
1763 else if (tbi->flags & ToolbarInfo::AUTO)
1766 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1767 _(tbi->gui_name), state));
1771 case LFUN_DIALOG_UPDATE: {
1772 string const name = to_utf8(cmd.argument());
1773 // Can only update a dialog connected to an existing inset
1774 Inset * inset = getOpenInset(name);
1776 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1777 inset->dispatch(view()->cursor(), fr);
1778 } else if (name == "paragraph") {
1779 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1780 } else if (name == "prefs") {
1781 updateDialog(name, string());
1786 case LFUN_DIALOG_TOGGLE: {
1787 if (isDialogVisible(cmd.getArg(0)))
1788 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1790 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1794 case LFUN_DIALOG_DISCONNECT_INSET:
1795 disconnectDialog(to_utf8(cmd.argument()));
1798 case LFUN_DIALOG_HIDE: {
1799 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1803 case LFUN_DIALOG_SHOW: {
1804 string const name = cmd.getArg(0);
1805 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1807 if (name == "character") {
1808 data = freefont2string();
1810 showDialog("character", data);
1811 } else if (name == "latexlog") {
1812 Buffer::LogType type;
1813 string const logfile = buffer()->logName(&type);
1815 case Buffer::latexlog:
1818 case Buffer::buildlog:
1822 data += Lexer::quoteString(logfile);
1823 showDialog("log", data);
1824 } else if (name == "vclog") {
1825 string const data = "vc " +
1826 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1827 showDialog("log", data);
1828 } else if (name == "symbols") {
1829 data = bv->cursor().getEncoding()->name();
1831 showDialog("symbols", data);
1833 showDialog(name, data);
1837 case LFUN_INSET_APPLY: {
1838 string const name = cmd.getArg(0);
1839 Inset * inset = getOpenInset(name);
1841 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1842 inset->dispatch(view()->cursor(), fr);
1844 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1850 case LFUN_UI_TOGGLE:
1852 // Make sure the keyboard focus stays in the work area.
1856 case LFUN_COMPLETION_INLINE:
1857 if (d.current_work_area_)
1858 d.current_work_area_->completer().showInline();
1861 case LFUN_SPLIT_VIEW:
1862 if (Buffer * buf = buffer()) {
1863 string const orientation = cmd.getArg(0);
1864 d.splitter_->setOrientation(orientation == "vertical"
1865 ? Qt::Vertical : Qt::Horizontal);
1866 TabWorkArea * twa = addTabWorkArea();
1867 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1868 setCurrentWorkArea(wa);
1872 case LFUN_CLOSE_TAB_GROUP:
1873 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1875 twa = d.currentTabWorkArea();
1876 // Switch to the next GuiWorkArea in the found TabWorkArea.
1877 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1878 if (d.splitter_->count() == 0)
1879 // No more work area, switch to the background widget.
1884 case LFUN_COMPLETION_POPUP:
1885 if (d.current_work_area_)
1886 d.current_work_area_->completer().showPopup();
1890 case LFUN_COMPLETION_COMPLETE:
1891 if (d.current_work_area_)
1892 d.current_work_area_->completer().tab();
1903 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1905 string const arg = cmd.getArg(0);
1906 if (arg == "scrollbar") {
1907 // hide() is of no help
1908 if (d.current_work_area_->verticalScrollBarPolicy() ==
1909 Qt::ScrollBarAlwaysOff)
1911 d.current_work_area_->setVerticalScrollBarPolicy(
1912 Qt::ScrollBarAsNeeded);
1914 d.current_work_area_->setVerticalScrollBarPolicy(
1915 Qt::ScrollBarAlwaysOff);
1918 if (arg == "statusbar") {
1919 statusBar()->setVisible(!statusBar()->isVisible());
1922 if (arg == "menubar") {
1923 menuBar()->setVisible(!menuBar()->isVisible());
1926 #if QT_VERSION >= 0x040300
1927 if (arg == "frame") {
1929 getContentsMargins(&l, &t, &r, &b);
1930 //are the frames in default state?
1931 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1933 setContentsMargins(-2, -2, -2, -2);
1935 setContentsMargins(0, 0, 0, 0);
1940 if (arg != "fullscreen") {
1941 message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
1945 if (lyxrc.full_screen_toolbars)
1946 d.toolbars_->toggleFullScreen(!isFullScreen());
1948 if (isFullScreen()) {
1949 for (int i = 0; i != d.splitter_->count(); ++i)
1950 d.tabWorkArea(i)->setFullScreen(false);
1951 #if QT_VERSION >= 0x040300
1952 setContentsMargins(0, 0, 0, 0);
1956 statusBar()->show();
1958 for (int i = 0; i != d.splitter_->count(); ++i)
1959 d.tabWorkArea(i)->setFullScreen(true);
1960 #if QT_VERSION >= 0x040300
1961 setContentsMargins(-2, -2, -2, -2);
1964 statusBar()->hide();
1970 Buffer const * GuiView::updateInset(Inset const * inset)
1972 if (!d.current_work_area_)
1976 d.current_work_area_->scheduleRedraw();
1978 return &d.current_work_area_->bufferView().buffer();
1982 void GuiView::restartCursor()
1984 /* When we move around, or type, it's nice to be able to see
1985 * the cursor immediately after the keypress.
1987 if (d.current_work_area_)
1988 d.current_work_area_->startBlinkingCursor();
1990 // 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", "embedding", "errorlist", "ert", "external", "file",
2012 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2013 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2014 "ref", "sendto", "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::hideBufferDependent() const
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->isBufferDependent())
2164 void GuiView::updateBufferDependent(bool switched) const
2166 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2167 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2169 for(; it != end; ++it) {
2170 Dialog * dialog = it->second.get();
2171 if (!dialog->isVisibleView())
2173 if (switched && dialog->isBufferDependent()) {
2174 if (dialog->initialiseParams(""))
2175 dialog->updateView();
2179 // A bit clunky, but the dialog will request
2180 // that the kernel provides it with the necessary
2182 dialog->updateDialog();
2188 void GuiView::checkStatus()
2190 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2191 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2193 for(; it != end; ++it) {
2194 Dialog * const dialog = it->second.get();
2195 if (dialog && dialog->isVisibleView())
2196 dialog->checkStatus();
2202 // will be replaced by a proper factory...
2203 Dialog * createGuiAbout(GuiView & lv);
2204 Dialog * createGuiBibitem(GuiView & lv);
2205 Dialog * createGuiBibtex(GuiView & lv);
2206 Dialog * createGuiBox(GuiView & lv);
2207 Dialog * createGuiBranch(GuiView & lv);
2208 Dialog * createGuiChanges(GuiView & lv);
2209 Dialog * createGuiCharacter(GuiView & lv);
2210 Dialog * createGuiCitation(GuiView & lv);
2211 Dialog * createGuiDelimiter(GuiView & lv);
2212 Dialog * createGuiDocument(GuiView & lv);
2213 Dialog * createGuiErrorList(GuiView & lv);
2214 Dialog * createGuiERT(GuiView & lv);
2215 Dialog * createGuiExternal(GuiView & lv);
2216 Dialog * createGuiFloat(GuiView & lv);
2217 Dialog * createGuiGraphics(GuiView & lv);
2218 Dialog * createGuiInclude(GuiView & lv);
2219 Dialog * createGuiLabel(GuiView & lv);
2220 Dialog * createGuiListings(GuiView & lv);
2221 Dialog * createGuiLog(GuiView & lv);
2222 Dialog * createGuiMathMatrix(GuiView & lv);
2223 Dialog * createGuiNomenclature(GuiView & lv);
2224 Dialog * createGuiNote(GuiView & lv);
2225 Dialog * createGuiParagraph(GuiView & lv);
2226 Dialog * createGuiPreferences(GuiView & lv);
2227 Dialog * createGuiPrint(GuiView & lv);
2228 Dialog * createGuiRef(GuiView & lv);
2229 Dialog * createGuiSearch(GuiView & lv);
2230 Dialog * createGuiSendTo(GuiView & lv);
2231 Dialog * createGuiShowFile(GuiView & lv);
2232 Dialog * createGuiSpellchecker(GuiView & lv);
2233 Dialog * createGuiSymbols(GuiView & lv);
2234 Dialog * createGuiTabularCreate(GuiView & lv);
2235 Dialog * createGuiTabular(GuiView & lv);
2236 Dialog * createGuiTexInfo(GuiView & lv);
2237 Dialog * createGuiToc(GuiView & lv);
2238 Dialog * createGuiThesaurus(GuiView & lv);
2239 Dialog * createGuiHyperlink(GuiView & lv);
2240 Dialog * createGuiVSpace(GuiView & lv);
2241 Dialog * createGuiViewSource(GuiView & lv);
2242 Dialog * createGuiWrap(GuiView & lv);
2245 Dialog * GuiView::build(string const & name)
2247 BOOST_ASSERT(isValidName(name));
2249 if (name == "aboutlyx")
2250 return createGuiAbout(*this);
2251 if (name == "bibitem")
2252 return createGuiBibitem(*this);
2253 if (name == "bibtex")
2254 return createGuiBibtex(*this);
2256 return createGuiBox(*this);
2257 if (name == "branch")
2258 return createGuiBranch(*this);
2259 if (name == "changes")
2260 return createGuiChanges(*this);
2261 if (name == "character")
2262 return createGuiCharacter(*this);
2263 if (name == "citation")
2264 return createGuiCitation(*this);
2265 if (name == "document")
2266 return createGuiDocument(*this);
2267 if (name == "errorlist")
2268 return createGuiErrorList(*this);
2270 return createGuiERT(*this);
2271 if (name == "external")
2272 return createGuiExternal(*this);
2274 return createGuiShowFile(*this);
2275 if (name == "findreplace")
2276 return createGuiSearch(*this);
2277 if (name == "float")
2278 return createGuiFloat(*this);
2279 if (name == "graphics")
2280 return createGuiGraphics(*this);
2281 if (name == "include")
2282 return createGuiInclude(*this);
2283 if (name == "nomenclature")
2284 return createGuiNomenclature(*this);
2285 if (name == "label")
2286 return createGuiLabel(*this);
2288 return createGuiLog(*this);
2289 if (name == "view-source")
2290 return createGuiViewSource(*this);
2291 if (name == "mathdelimiter")
2292 return createGuiDelimiter(*this);
2293 if (name == "mathmatrix")
2294 return createGuiMathMatrix(*this);
2296 return createGuiNote(*this);
2297 if (name == "paragraph")
2298 return createGuiParagraph(*this);
2299 if (name == "prefs")
2300 return createGuiPreferences(*this);
2301 if (name == "print")
2302 return createGuiPrint(*this);
2304 return createGuiRef(*this);
2305 if (name == "sendto")
2306 return createGuiSendTo(*this);
2307 if (name == "spellchecker")
2308 return createGuiSpellchecker(*this);
2309 if (name == "symbols")
2310 return createGuiSymbols(*this);
2311 if (name == "tabular")
2312 return createGuiTabular(*this);
2313 if (name == "tabularcreate")
2314 return createGuiTabularCreate(*this);
2315 if (name == "texinfo")
2316 return createGuiTexInfo(*this);
2317 #ifdef HAVE_LIBAIKSAURUS
2318 if (name == "thesaurus")
2319 return createGuiThesaurus(*this);
2322 return createGuiToc(*this);
2324 return createGuiHyperlink(*this);
2325 if (name == "vspace")
2326 return createGuiVSpace(*this);
2328 return createGuiWrap(*this);
2329 if (name == "listings")
2330 return createGuiListings(*this);
2336 } // namespace frontend
2339 #include "GuiView_moc.cpp"