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"
39 #include "ErrorList.h"
41 #include "FuncStatus.h"
42 #include "FuncRequest.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/gettext.h"
61 #include "support/ForkedCalls.h"
62 #include "support/lstrings.h"
63 #include "support/os.h"
64 #include "support/Package.h"
65 #include "support/Timeout.h"
68 #include <QApplication>
69 #include <QCloseEvent>
71 #include <QDesktopWidget>
72 #include <QDragEnterEvent>
80 #include <QPushButton>
84 #include <QStackedWidget>
91 #include <boost/assert.hpp>
92 #include <boost/bind.hpp>
94 #ifdef HAVE_SYS_TIME_H
95 # include <sys/time.h>
102 using namespace lyx::support;
109 class BackgroundWidget : public QWidget
114 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
115 /// The text to be written on top of the pixmap
116 QString const text = lyx_version ? lyx_version : qt_("unknown version");
117 splash_ = QPixmap(":/images/banner.png");
119 QPainter pain(&splash_);
120 pain.setPen(QColor(255, 255, 0));
122 // The font used to display the version info
123 font.setStyleHint(QFont::SansSerif);
124 font.setWeight(QFont::Bold);
125 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
127 pain.drawText(260, 270, text);
130 void paintEvent(QPaintEvent *)
132 int x = (width() - splash_.width()) / 2;
133 int y = (height() - splash_.height()) / 2;
135 pain.drawPixmap(x, y, splash_);
145 typedef boost::shared_ptr<Dialog> DialogPtr;
147 struct GuiView::GuiViewPrivate
150 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
153 // hardcode here the platform specific icon size
154 smallIconSize = 14; // scaling problems
155 normalIconSize = 20; // ok, default
156 bigIconSize = 26; // better for some math icons
158 splitter_ = new QSplitter;
159 bg_widget_ = new BackgroundWidget;
160 stack_widget_ = new QStackedWidget;
161 stack_widget_->addWidget(bg_widget_);
162 stack_widget_->addWidget(splitter_);
170 delete stack_widget_;
174 QMenu * toolBarPopup(GuiView * parent)
176 // FIXME: translation
177 QMenu * menu = new QMenu(parent);
178 QActionGroup * iconSizeGroup = new QActionGroup(parent);
180 QAction * smallIcons = new QAction(iconSizeGroup);
181 smallIcons->setText(qt_("Small-sized icons"));
182 smallIcons->setCheckable(true);
183 QObject::connect(smallIcons, SIGNAL(triggered()),
184 parent, SLOT(smallSizedIcons()));
185 menu->addAction(smallIcons);
187 QAction * normalIcons = new QAction(iconSizeGroup);
188 normalIcons->setText(qt_("Normal-sized icons"));
189 normalIcons->setCheckable(true);
190 QObject::connect(normalIcons, SIGNAL(triggered()),
191 parent, SLOT(normalSizedIcons()));
192 menu->addAction(normalIcons);
194 QAction * bigIcons = new QAction(iconSizeGroup);
195 bigIcons->setText(qt_("Big-sized icons"));
196 bigIcons->setCheckable(true);
197 QObject::connect(bigIcons, SIGNAL(triggered()),
198 parent, SLOT(bigSizedIcons()));
199 menu->addAction(bigIcons);
201 unsigned int cur = parent->iconSize().width();
202 if ( cur == parent->d.smallIconSize)
203 smallIcons->setChecked(true);
204 else if (cur == parent->d.normalIconSize)
205 normalIcons->setChecked(true);
206 else if (cur == parent->d.bigIconSize)
207 bigIcons->setChecked(true);
214 stack_widget_->setCurrentWidget(bg_widget_);
215 bg_widget_->setUpdatesEnabled(true);
218 TabWorkArea * tabWorkArea(int i)
220 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
223 TabWorkArea * currentTabWorkArea()
225 if (splitter_->count() == 1)
226 // The first TabWorkArea is always the first one, if any.
227 return tabWorkArea(0);
229 for (int i = 0; i != splitter_->count(); ++i) {
230 TabWorkArea * twa = tabWorkArea(i);
231 if (current_work_area_ == twa->currentWorkArea())
235 // None has the focus so we just take the first one.
236 return tabWorkArea(0);
240 GuiWorkArea * current_work_area_;
241 QSplitter * splitter_;
242 QStackedWidget * stack_widget_;
243 BackgroundWidget * bg_widget_;
245 GuiToolbars * toolbars_;
246 /// The main layout box.
248 * \warning Don't Delete! The layout box is actually owned by
249 * whichever toolbar contains it. All the GuiView class needs is a
250 * means of accessing it.
252 * FIXME: replace that with a proper model so that we are not limited
253 * to only one dialog.
255 GuiLayoutBox * layout_;
258 map<string, Inset *> open_insets_;
261 map<string, DialogPtr> dialogs_;
263 unsigned int smallIconSize;
264 unsigned int normalIconSize;
265 unsigned int bigIconSize;
267 QTimer statusbar_timer_;
268 /// auto-saving of buffers
269 Timeout autosave_timeout_;
270 /// flag against a race condition due to multiclicks, see bug #1119
275 GuiView::GuiView(int id)
276 : d(*new GuiViewPrivate), id_(id)
278 // GuiToolbars *must* be initialised before the menu bar.
279 d.toolbars_ = new GuiToolbars(*this);
281 // set ourself as the current view. This is needed for the menu bar
282 // filling, at least for the static special menu item on Mac. Otherwise
283 // they are greyed out.
284 theLyXFunc().setLyXView(this);
286 // Fill up the menu bar.
287 guiApp->menus().fillMenuBar(menuBar(), this, true);
289 setCentralWidget(d.stack_widget_);
291 // Start autosave timer
292 if (lyxrc.autosave) {
293 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
294 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
295 d.autosave_timeout_.start();
297 connect(&d.statusbar_timer_, SIGNAL(timeout()),
298 this, SLOT(clearMessage()));
300 // We don't want to keep the window in memory if it is closed.
301 setAttribute(Qt::WA_DeleteOnClose, true);
304 // assign an icon to main form. We do not do it under Qt/Mac,
305 // since the icon is provided in the application bundle.
306 setWindowIcon(QPixmap(":/images/lyx.png"));
310 setAcceptDrops(true);
312 statusBar()->setSizeGripEnabled(true);
314 // Forbid too small unresizable window because it can happen
315 // with some window manager under X11.
316 setMinimumSize(300, 200);
318 if (!lyxrc.allow_geometry_session)
319 // No session handling, default to a sane size.
320 setGeometry(50, 50, 690, 510);
322 // Now take care of session management.
324 QString const key = "view-" + QString::number(id_);
326 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
327 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
331 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
332 setGeometry(50, 50, 690, 510);
334 setIconSize(settings.value(key + "/icon_size").toSize());
340 if (guiApp->currentView() == this)
341 guiApp->setCurrentView(0);
342 theLyXFunc().setLyXView(0);
348 void GuiView::setFocus()
350 if (d.current_work_area_)
351 d.current_work_area_->setFocus();
357 QMenu * GuiView::createPopupMenu()
359 return d.toolBarPopup(this);
363 void GuiView::showEvent(QShowEvent * e)
365 LYXERR(Debug::GUI, "Passed Geometry "
366 << size().height() << "x" << size().width()
367 << "+" << pos().x() << "+" << pos().y());
369 if (d.splitter_->count() == 0)
370 // No work area, switch to the background widget.
373 QMainWindow::showEvent(e);
377 void GuiView::closeEvent(QCloseEvent * close_event)
379 // it can happen that this event arrives without selecting the view,
380 // e.g. when clicking the close button on a background window.
381 theLyXFunc().setLyXView(this);
383 while (Buffer * b = buffer()) {
385 // This is a child document, just close the tab after saving
386 // but keep the file loaded.
387 if (!saveBuffer(*b)) {
388 close_event->ignore();
391 removeWorkArea(d.current_work_area_);
395 std::vector<int> const & ids = guiApp->viewIds();
396 for (size_type i = 0; i != ids.size(); ++i) {
399 if (guiApp->view(ids[i]).workArea(*b)) {
400 // FIXME 1: should we put an alert box here that the buffer
401 // is viewed elsewhere?
402 // FIXME 2: should we try to save this buffer in any case?
405 // This buffer is also opened in another view, so
406 // but close the associated work area nevertheless.
407 removeWorkArea(d.current_work_area_);
408 // but don't close it.
413 if (b && !closeBuffer(*b)) {
414 close_event->ignore();
419 // Make sure that no LFUN use this close to be closed View.
420 theLyXFunc().setLyXView(0);
422 // Save toolbars configuration
423 if (isFullScreen()) {
424 d.toolbars_->toggleFullScreen(!isFullScreen());
428 // Make sure the timer time out will not trigger a statusbar update.
429 d.statusbar_timer_.stop();
431 // Saving fullscreen requires additional tweaks in the toolbar code.
432 // It wouldn't also work under linux natively.
433 if (lyxrc.allow_geometry_session && !isFullScreen()) {
435 QString const key = "view-" + QString::number(id_);
437 settings.setValue(key + "/pos", pos());
438 settings.setValue(key + "/size", size());
440 settings.setValue(key + "/geometry", saveGeometry());
442 settings.setValue(key + "/icon_size", iconSize());
443 d.toolbars_->saveToolbarInfo();
444 // Now take care of all other dialogs:
445 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
446 for (; it!= d.dialogs_.end(); ++it)
447 it->second->saveSession();
450 guiApp->unregisterView(id_);
451 close_event->accept();
455 void GuiView::dragEnterEvent(QDragEnterEvent * event)
457 if (event->mimeData()->hasUrls())
459 /// \todo Ask lyx-devel is this is enough:
460 /// if (event->mimeData()->hasFormat("text/plain"))
461 /// event->acceptProposedAction();
465 void GuiView::dropEvent(QDropEvent* event)
467 QList<QUrl> files = event->mimeData()->urls();
471 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
472 for (int i = 0; i != files.size(); ++i) {
473 string const file = os::internal_path(fromqstr(
474 files.at(i).toLocalFile()));
476 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
481 void GuiView::message(docstring const & str)
483 if (ForkedProcess::iAmAChild())
486 statusBar()->showMessage(toqstr(str));
487 d.statusbar_timer_.stop();
488 d.statusbar_timer_.start(3000);
492 void GuiView::smallSizedIcons()
494 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
498 void GuiView::normalSizedIcons()
500 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
504 void GuiView::bigSizedIcons()
506 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
510 void GuiView::clearMessage()
514 theLyXFunc().setLyXView(this);
515 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
516 d.statusbar_timer_.stop();
520 void GuiView::updateWindowTitle(GuiWorkArea * wa)
522 if (wa != d.current_work_area_)
524 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
525 setWindowIconText(wa->windowIconText());
529 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
532 disconnectBufferView();
533 connectBufferView(wa->bufferView());
534 connectBuffer(wa->bufferView().buffer());
535 d.current_work_area_ = wa;
536 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
537 this, SLOT(updateWindowTitle(GuiWorkArea *)));
538 updateWindowTitle(wa);
541 // Buffer-dependent dialogs should be updated or
542 // hidden. This should go here because some dialogs (eg ToC)
543 // require bv_->text.
544 updateBufferDependent(true);
551 void GuiView::on_lastWorkAreaRemoved()
554 // On Mac close the view if there is no Tab open anymore,
555 // but only if no splitter is visible
556 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
557 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
558 if (twa && twa->count() == 0) {
559 // close the view, as no tab is open anymore
560 QTimer::singleShot(0, this, SLOT(close()));
567 void GuiView::updateStatusBar()
569 // let the user see the explicit message
570 if (d.statusbar_timer_.isActive())
573 theLyXFunc().setLyXView(this);
574 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
578 bool GuiView::hasFocus() const
580 return qApp->activeWindow() == this;
584 bool GuiView::event(QEvent * e)
588 // Useful debug code:
589 //case QEvent::ActivationChange:
590 //case QEvent::WindowDeactivate:
591 //case QEvent::Paint:
592 //case QEvent::Enter:
593 //case QEvent::Leave:
594 //case QEvent::HoverEnter:
595 //case QEvent::HoverLeave:
596 //case QEvent::HoverMove:
597 //case QEvent::StatusTip:
598 //case QEvent::DragEnter:
599 //case QEvent::DragLeave:
603 case QEvent::WindowActivate: {
604 if (this == guiApp->currentView()) {
606 return QMainWindow::event(e);
608 guiApp->setCurrentView(this);
609 if (d.current_work_area_) {
610 BufferView & bv = d.current_work_area_->bufferView();
611 connectBufferView(bv);
612 connectBuffer(bv.buffer());
613 // The document structure, name and dialogs might have
614 // changed in another view.
615 updateBufferDependent(true);
620 setWindowTitle(qt_("LyX"));
621 setWindowIconText(qt_("LyX"));
624 return QMainWindow::event(e);
627 case QEvent::ShortcutOverride: {
628 if (d.current_work_area_)
629 // Nothing special to do.
630 return QMainWindow::event(e);
632 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
634 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
636 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
637 || ke->key() == Qt::Key_Backtab)
638 return QMainWindow::event(e);
640 // Allow processing of shortcuts that are allowed even when no Buffer
642 theLyXFunc().setLyXView(this);
644 setKeySymbol(&sym, ke);
645 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
651 return QMainWindow::event(e);
656 bool GuiView::focusNextPrevChild(bool /*next*/)
663 void GuiView::setBusy(bool busy)
665 if (d.current_work_area_) {
666 d.current_work_area_->setUpdatesEnabled(!busy);
668 d.current_work_area_->stopBlinkingCursor();
670 d.current_work_area_->startBlinkingCursor();
674 QApplication::setOverrideCursor(Qt::WaitCursor);
676 QApplication::restoreOverrideCursor();
680 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
682 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
684 if (tbinfo.flags & ToolbarInfo::TOP) {
686 addToolBarBreak(Qt::TopToolBarArea);
687 addToolBar(Qt::TopToolBarArea, toolBar);
690 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
691 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
692 #if (QT_VERSION >= 0x040202)
694 addToolBarBreak(Qt::BottomToolBarArea);
696 addToolBar(Qt::BottomToolBarArea, toolBar);
699 if (tbinfo.flags & ToolbarInfo::LEFT) {
700 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
701 #if (QT_VERSION >= 0x040202)
703 addToolBarBreak(Qt::LeftToolBarArea);
705 addToolBar(Qt::LeftToolBarArea, toolBar);
708 if (tbinfo.flags & ToolbarInfo::RIGHT) {
709 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
710 #if (QT_VERSION >= 0x040202)
712 addToolBarBreak(Qt::RightToolBarArea);
714 addToolBar(Qt::RightToolBarArea, toolBar);
717 // The following does not work so I cannot restore to exact toolbar location
719 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
720 toolBar->move(tbinfo.posx, tbinfo.posy);
727 GuiWorkArea * GuiView::workArea(Buffer & buffer)
729 if (TabWorkArea * twa = d.currentTabWorkArea())
730 return twa->workArea(buffer);
735 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
737 // Automatically create a TabWorkArea if there are none yet.
738 TabWorkArea * tab_widget = d.splitter_->count()
739 ? d.currentTabWorkArea() : addTabWorkArea();
740 return tab_widget->addWorkArea(buffer, *this);
744 TabWorkArea * GuiView::addTabWorkArea()
746 TabWorkArea * twa = new TabWorkArea;
747 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
748 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
749 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
750 this, SLOT(on_lastWorkAreaRemoved()));
752 d.splitter_->addWidget(twa);
753 d.stack_widget_->setCurrentWidget(d.splitter_);
758 GuiWorkArea const * GuiView::currentWorkArea() const
760 return d.current_work_area_;
764 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
768 // Changing work area can result from opening a file so
769 // update the toc in any case.
772 d.current_work_area_ = wa;
773 for (int i = 0; i != d.splitter_->count(); ++i) {
774 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
780 void GuiView::removeWorkArea(GuiWorkArea * wa)
783 if (wa == d.current_work_area_) {
785 disconnectBufferView();
786 hideBufferDependent();
787 d.current_work_area_ = 0;
790 for (int i = 0; i != d.splitter_->count(); ++i) {
791 TabWorkArea * twa = d.tabWorkArea(i);
792 if (!twa->removeWorkArea(wa))
793 // Not found in this tab group.
796 // We found and removed the GuiWorkArea.
798 // No more WorkAreas in this tab group, so delete it.
803 if (d.current_work_area_)
804 // This means that we are not closing the current GuiWorkArea;
807 // Switch to the next GuiWorkArea in the found TabWorkArea.
808 d.current_work_area_ = twa->currentWorkArea();
812 if (d.splitter_->count() == 0)
813 // No more work area, switch to the background widget.
818 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
824 void GuiView::updateLayoutList()
827 d.layout_->updateContents(false);
831 void GuiView::updateToolbars()
833 if (d.current_work_area_) {
835 d.current_work_area_->bufferView().cursor().inMathed();
837 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
839 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
840 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
841 bool const mathmacrotemplate =
842 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
844 d.toolbars_->update(math, table, review, mathmacrotemplate);
846 d.toolbars_->update(false, false, false, false);
848 // update read-only status of open dialogs.
853 Buffer * GuiView::buffer()
855 if (d.current_work_area_)
856 return &d.current_work_area_->bufferView().buffer();
861 Buffer const * GuiView::buffer() const
863 if (d.current_work_area_)
864 return &d.current_work_area_->bufferView().buffer();
869 void GuiView::setBuffer(Buffer * newBuffer)
871 BOOST_ASSERT(newBuffer);
874 GuiWorkArea * wa = workArea(*newBuffer);
876 updateLabels(*newBuffer->masterBuffer());
877 wa = addWorkArea(*newBuffer);
879 //Disconnect the old buffer...there's no new one.
882 connectBuffer(*newBuffer);
883 connectBufferView(wa->bufferView());
884 setCurrentWorkArea(wa);
890 void GuiView::connectBuffer(Buffer & buf)
892 buf.setGuiDelegate(this);
896 void GuiView::disconnectBuffer()
898 if (d.current_work_area_)
899 d.current_work_area_->bufferView().setGuiDelegate(0);
903 void GuiView::connectBufferView(BufferView & bv)
905 bv.setGuiDelegate(this);
909 void GuiView::disconnectBufferView()
911 if (d.current_work_area_)
912 d.current_work_area_->bufferView().setGuiDelegate(0);
916 void GuiView::errors(string const & error_type)
918 ErrorList & el = buffer()->errorList(error_type);
920 showDialog("errorlist", error_type);
924 void GuiView::updateDialog(string const & name, string const & data)
926 if (!isDialogVisible(name))
929 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
930 if (it == d.dialogs_.end())
933 Dialog * const dialog = it->second.get();
934 if (dialog->isVisibleView())
935 dialog->updateData(data);
939 BufferView * GuiView::view()
941 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
945 void GuiView::updateToc()
947 updateDialog("toc", "");
951 void GuiView::updateEmbeddedFiles()
953 updateDialog("embedding", "");
957 void GuiView::autoSave()
959 LYXERR(Debug::INFO, "Running autoSave()");
962 view()->buffer().autoSave();
966 void GuiView::resetAutosaveTimers()
969 d.autosave_timeout_.restart();
973 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
977 Buffer * buf = buffer();
979 /* In LyX/Mac, when a dialog is open, the menus of the
980 application can still be accessed without giving focus to
981 the main window. In this case, we want to disable the menu
982 entries that are buffer-related.
984 Note that this code is not perfect, as bug 1941 attests:
985 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
987 if (cmd.origin == FuncRequest::MENU && !hasFocus())
991 case LFUN_BUFFER_WRITE:
992 enable = buf && (buf->isUnnamed() || !buf->isClean());
995 case LFUN_BUFFER_WRITE_AS:
999 case LFUN_SPLIT_VIEW:
1003 case LFUN_CLOSE_TAB_GROUP:
1004 enable = d.currentTabWorkArea();
1007 case LFUN_TOOLBAR_TOGGLE:
1008 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1011 case LFUN_UI_TOGGLE:
1012 flag.setOnOff(isFullScreen());
1015 case LFUN_DIALOG_TOGGLE:
1016 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1017 // fall through to set "enable"
1018 case LFUN_DIALOG_SHOW: {
1019 string const name = cmd.getArg(0);
1021 enable = name == "aboutlyx"
1022 || name == "file" //FIXME: should be removed.
1024 || name == "texinfo";
1025 else if (name == "print")
1026 enable = buf->isExportable("dvi")
1027 && lyxrc.print_command != "none";
1028 else if (name == "character") {
1032 InsetCode ic = view()->cursor().inset().lyxCode();
1033 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1036 else if (name == "symbols") {
1037 if (!view() || view()->cursor().inMathed())
1040 InsetCode ic = view()->cursor().inset().lyxCode();
1041 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1044 else if (name == "latexlog")
1045 enable = FileName(buf->logName()).isReadableFile();
1046 else if (name == "spellchecker")
1047 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1048 enable = !buf->isReadonly();
1052 else if (name == "vclog")
1053 enable = buf->lyxvc().inUse();
1057 case LFUN_DIALOG_UPDATE: {
1058 string const name = cmd.getArg(0);
1060 enable = name == "prefs";
1064 case LFUN_INSET_APPLY: {
1069 string const name = cmd.getArg(0);
1070 Inset * inset = getOpenInset(name);
1072 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1074 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1075 // Every inset is supposed to handle this
1076 BOOST_ASSERT(false);
1080 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1081 flag |= getStatus(fr);
1083 enable = flag.enabled();
1087 case LFUN_COMPLETION_INLINE:
1088 if (!d.current_work_area_
1089 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1093 case LFUN_COMPLETION_POPUP:
1094 if (!d.current_work_area_
1095 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1099 case LFUN_COMPLETION_COMPLETE:
1100 if (!d.current_work_area_
1101 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1113 flag.enabled(false);
1119 static FileName selectTemplateFile()
1121 FileDialog dlg(qt_("Select template file"));
1122 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1123 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1125 FileDialog::Result result =
1126 dlg.open(toqstr(lyxrc.template_path),
1127 FileFilterList(_("LyX Documents (*.lyx)")));
1129 if (result.first == FileDialog::Later)
1131 if (result.second.isEmpty())
1133 return FileName(fromqstr(result.second));
1137 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1141 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1144 message(_("Document not loaded."));
1149 setBuffer(newBuffer);
1151 // scroll to the position when the file was last closed
1152 if (lyxrc.use_lastfilepos) {
1153 LastFilePosSection::FilePos filepos =
1154 LyX::ref().session().lastFilePos().load(filename);
1155 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1159 LyX::ref().session().lastFiles().add(filename);
1166 void GuiView::openDocument(string const & fname)
1168 string initpath = lyxrc.document_path;
1171 string const trypath = buffer()->filePath();
1172 // If directory is writeable, use this as default.
1173 if (FileName(trypath).isDirWritable())
1179 if (fname.empty()) {
1180 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1181 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1182 dlg.setButton2(qt_("Examples|#E#e"),
1183 toqstr(addPath(package().system_support().absFilename(), "examples")));
1185 FileDialog::Result result =
1186 dlg.open(toqstr(initpath), FileFilterList(_("LyX Documents (*.lyx)")));
1188 if (result.first == FileDialog::Later)
1191 filename = fromqstr(result.second);
1193 // check selected filename
1194 if (filename.empty()) {
1195 message(_("Canceled."));
1201 // get absolute path of file and add ".lyx" to the filename if
1203 FileName const fullname =
1204 fileSearch(string(), filename, "lyx", support::may_not_exist);
1205 if (!fullname.empty())
1206 filename = fullname.absFilename();
1208 // if the file doesn't exist, let the user create one
1209 if (!fullname.exists()) {
1210 // the user specifically chose this name. Believe him.
1211 Buffer * const b = newFile(filename, string(), true);
1217 docstring const disp_fn = makeDisplayPath(filename);
1218 message(bformat(_("Opening document %1$s..."), disp_fn));
1221 Buffer * buf = loadDocument(fullname);
1226 buf->errors("Parse");
1227 str2 = bformat(_("Document %1$s opened."), disp_fn);
1229 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1234 // FIXME: clean that
1235 static bool import(GuiView * lv, FileName const & filename,
1236 string const & format, ErrorList & errorList)
1238 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1240 string loader_format;
1241 vector<string> loaders = theConverters().loaders();
1242 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1243 for (vector<string>::const_iterator it = loaders.begin();
1244 it != loaders.end(); ++it) {
1245 if (!theConverters().isReachable(format, *it))
1248 string const tofile =
1249 support::changeExtension(filename.absFilename(),
1250 formats.extension(*it));
1251 if (!theConverters().convert(0, filename, FileName(tofile),
1252 filename, format, *it, errorList))
1254 loader_format = *it;
1257 if (loader_format.empty()) {
1258 frontend::Alert::error(_("Couldn't import file"),
1259 bformat(_("No information for importing the format %1$s."),
1260 formats.prettyName(format)));
1264 loader_format = format;
1266 if (loader_format == "lyx") {
1267 Buffer * buf = lv->loadDocument(lyxfile);
1272 buf->errors("Parse");
1274 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1278 bool as_paragraphs = loader_format == "textparagraph";
1279 string filename2 = (loader_format == format) ? filename.absFilename()
1280 : support::changeExtension(filename.absFilename(),
1281 formats.extension(loader_format));
1282 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1283 theLyXFunc().setLyXView(lv);
1284 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1291 void GuiView::importDocument(string const & argument)
1294 string filename = split(argument, format, ' ');
1296 LYXERR(Debug::INFO, format << " file: " << filename);
1298 // need user interaction
1299 if (filename.empty()) {
1300 string initpath = lyxrc.document_path;
1302 Buffer const * buf = buffer();
1304 string const trypath = buf->filePath();
1305 // If directory is writeable, use this as default.
1306 if (FileName(trypath).isDirWritable())
1310 docstring const text = bformat(_("Select %1$s file to import"),
1311 formats.prettyName(format));
1313 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1314 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1315 dlg.setButton2(qt_("Examples|#E#e"),
1316 toqstr(addPath(package().system_support().absFilename(), "examples")));
1318 docstring filter = formats.prettyName(format);
1321 filter += from_utf8(formats.extension(format));
1324 FileDialog::Result result =
1325 dlg.open(toqstr(initpath), FileFilterList(filter));
1327 if (result.first == FileDialog::Later)
1330 filename = fromqstr(result.second);
1332 // check selected filename
1333 if (filename.empty())
1334 message(_("Canceled."));
1337 if (filename.empty())
1340 // get absolute path of file
1341 FileName const fullname(makeAbsPath(filename));
1343 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1345 // Check if the document already is open
1346 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1349 if (!closeBuffer()) {
1350 message(_("Canceled."));
1355 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1357 // if the file exists already, and we didn't do
1358 // -i lyx thefile.lyx, warn
1359 if (lyxfile.exists() && fullname != lyxfile) {
1361 docstring text = bformat(_("The document %1$s already exists.\n\n"
1362 "Do you want to overwrite that document?"), displaypath);
1363 int const ret = Alert::prompt(_("Overwrite document?"),
1364 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1367 message(_("Canceled."));
1372 message(bformat(_("Importing %1$s..."), displaypath));
1373 ErrorList errorList;
1374 if (import(this, fullname, format, errorList))
1375 message(_("imported."));
1377 message(_("file not imported!"));
1379 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1383 void GuiView::newDocument(string const & filename, bool from_template)
1385 FileName initpath(lyxrc.document_path);
1386 Buffer * buf = buffer();
1388 FileName const trypath(buf->filePath());
1389 // If directory is writeable, use this as default.
1390 if (trypath.isDirWritable())
1394 string templatefile = from_template ?
1395 selectTemplateFile().absFilename() : string();
1397 if (filename.empty())
1398 b = newUnnamedFile(templatefile, initpath);
1400 b = newFile(filename, templatefile, true);
1404 // Ensure the cursor is correctly positionned on screen.
1405 view()->showCursor();
1409 void GuiView::insertLyXFile(docstring const & fname)
1411 BufferView * bv = view();
1416 FileName filename(to_utf8(fname));
1418 if (!filename.empty()) {
1419 bv->insertLyXFile(filename);
1423 // Launch a file browser
1425 string initpath = lyxrc.document_path;
1426 string const trypath = bv->buffer().filePath();
1427 // If directory is writeable, use this as default.
1428 if (FileName(trypath).isDirWritable())
1432 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1433 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1434 dlg.setButton2(qt_("Examples|#E#e"),
1435 toqstr(addPath(package().system_support().absFilename(),
1438 FileDialog::Result result =
1439 dlg.open(toqstr(initpath),
1440 FileFilterList(_("LyX Documents (*.lyx)")));
1442 if (result.first == FileDialog::Later)
1446 filename.set(fromqstr(result.second));
1448 // check selected filename
1449 if (filename.empty()) {
1450 // emit message signal.
1451 message(_("Canceled."));
1455 bv->insertLyXFile(filename);
1459 void GuiView::insertPlaintextFile(docstring const & fname,
1462 BufferView * bv = view();
1467 FileName filename(to_utf8(fname));
1469 if (!filename.empty()) {
1470 bv->insertPlaintextFile(filename, asParagraph);
1474 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1475 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1477 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1480 if (result.first == FileDialog::Later)
1484 filename.set(fromqstr(result.second));
1486 // check selected filename
1487 if (filename.empty()) {
1488 // emit message signal.
1489 message(_("Canceled."));
1493 bv->insertPlaintextFile(filename, asParagraph);
1497 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1499 FileName fname = b.fileName();
1500 FileName const oldname = fname;
1502 if (!newname.empty()) {
1504 fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1506 // Switch to this Buffer.
1509 /// No argument? Ask user through dialog.
1511 FileDialog dlg(qt_("Choose a filename to save document as"),
1512 LFUN_BUFFER_WRITE_AS);
1513 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1514 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1516 if (!isLyXFilename(fname.absFilename()))
1517 fname.changeExtension(".lyx");
1519 FileFilterList const filter(_("LyX Documents (*.lyx)"));
1521 FileDialog::Result result =
1522 dlg.save(toqstr(fname.onlyPath().absFilename()),
1524 toqstr(fname.onlyFileName()));
1526 if (result.first == FileDialog::Later)
1529 fname.set(fromqstr(result.second));
1534 if (!isLyXFilename(fname.absFilename()))
1535 fname.changeExtension(".lyx");
1538 if (FileName(fname).exists()) {
1539 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1540 docstring text = bformat(_("The document %1$s already "
1541 "exists.\n\nDo you want to "
1542 "overwrite that document?"),
1544 int const ret = Alert::prompt(_("Overwrite document?"),
1545 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1548 case 1: return renameBuffer(b, docstring());
1549 case 2: return false;
1553 // Ok, change the name of the buffer
1554 b.setFileName(fname.absFilename());
1556 bool unnamed = b.isUnnamed();
1557 b.setUnnamed(false);
1558 b.saveCheckSum(fname);
1560 if (!saveBuffer(b)) {
1561 b.setFileName(oldname.absFilename());
1562 b.setUnnamed(unnamed);
1563 b.saveCheckSum(oldname);
1571 bool GuiView::saveBuffer(Buffer & b)
1574 return renameBuffer(b, docstring());
1577 LyX::ref().session().lastFiles().add(b.fileName());
1581 // Switch to this Buffer.
1584 // FIXME: we don't tell the user *WHY* the save failed !!
1585 docstring const file = makeDisplayPath(b.absFileName(), 30);
1586 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1587 "Do you want to rename the document and "
1588 "try again?"), file);
1589 int const ret = Alert::prompt(_("Rename and save?"),
1590 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1593 if (!renameBuffer(b, docstring()))
1602 return saveBuffer(b);
1606 bool GuiView::closeBuffer()
1608 Buffer * buf = buffer();
1609 return buf && closeBuffer(*buf);
1613 bool GuiView::closeBuffer(Buffer & buf)
1615 // goto bookmark to update bookmark pit.
1616 //FIXME: we should update only the bookmarks related to this buffer!
1617 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1618 theLyXFunc().gotoBookmark(i+1, false, false);
1620 if (buf.isClean() || buf.paragraphs().empty()) {
1621 if (buf.masterBuffer() == &buf)
1622 LyX::ref().session().lastOpened().add(buf.fileName());
1623 theBufferList().release(&buf);
1626 // Switch to this Buffer.
1631 if (buf.isUnnamed())
1632 file = from_utf8(buf.fileName().onlyFileName());
1634 file = buf.fileName().displayName(30);
1636 // Bring this window to top before asking questions.
1640 docstring const text = bformat(_("The document %1$s has unsaved changes."
1641 "\n\nDo you want to save the document or discard the changes?"), file);
1642 int const ret = Alert::prompt(_("Save changed document?"),
1643 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1647 if (!saveBuffer(buf))
1651 // if we crash after this we could
1652 // have no autosave file but I guess
1653 // this is really improbable (Jug)
1654 removeAutosaveFile(buf.absFileName());
1660 // save file names to .lyx/session
1661 // if master/slave are both open, do not save slave since it
1662 // will be automatically loaded when the master is loaded
1663 if (buf.masterBuffer() == &buf)
1664 LyX::ref().session().lastOpened().add(buf.fileName());
1666 theBufferList().release(&buf);
1671 bool GuiView::dispatch(FuncRequest const & cmd)
1673 BufferView * bv = view();
1674 // By default we won't need any update.
1676 bv->cursor().updateFlags(Update::None);
1678 switch(cmd.action) {
1679 case LFUN_BUFFER_IMPORT:
1680 importDocument(to_utf8(cmd.argument()));
1683 case LFUN_BUFFER_SWITCH:
1684 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1687 case LFUN_BUFFER_NEXT:
1688 setBuffer(theBufferList().next(buffer()));
1691 case LFUN_BUFFER_PREVIOUS:
1692 setBuffer(theBufferList().previous(buffer()));
1695 case LFUN_COMMAND_EXECUTE: {
1696 bool const show_it = cmd.argument() != "off";
1697 d.toolbars_->showCommandBuffer(show_it);
1700 case LFUN_DROP_LAYOUTS_CHOICE:
1702 d.layout_->showPopup();
1705 case LFUN_MENU_OPEN:
1706 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1707 menu->exec(QCursor::pos());
1710 case LFUN_FILE_INSERT:
1711 insertLyXFile(cmd.argument());
1713 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1714 insertPlaintextFile(cmd.argument(), true);
1717 case LFUN_FILE_INSERT_PLAINTEXT:
1718 insertPlaintextFile(cmd.argument(), false);
1721 case LFUN_BUFFER_WRITE:
1723 saveBuffer(bv->buffer());
1726 case LFUN_BUFFER_WRITE_AS:
1728 renameBuffer(bv->buffer(), cmd.argument());
1731 case LFUN_BUFFER_WRITE_ALL: {
1732 Buffer * first = theBufferList().first();
1735 message(_("Saving all documents..."));
1736 // We cannot use a for loop as the buffer list cycles.
1739 if (!b->isClean()) {
1741 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1743 b = theBufferList().next(b);
1744 } while (b != first);
1745 message(_("All documents saved."));
1749 case LFUN_TOOLBAR_TOGGLE: {
1750 string const name = cmd.getArg(0);
1751 bool const allowauto = cmd.getArg(1) == "allowauto";
1752 // it is possible to get current toolbar status like this,...
1753 // but I decide to obey the order of ToolbarBackend::flags
1754 // and disregard real toolbar status.
1755 // toolbars_->saveToolbarInfo();
1757 // toggle state on/off/auto
1758 d.toolbars_->toggleToolbarState(name, allowauto);
1762 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1764 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1768 if (tbi->flags & ToolbarInfo::ON)
1770 else if (tbi->flags & ToolbarInfo::OFF)
1772 else if (tbi->flags & ToolbarInfo::AUTO)
1775 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1776 _(tbi->gui_name), state));
1780 case LFUN_DIALOG_UPDATE: {
1781 string const name = to_utf8(cmd.argument());
1782 // Can only update a dialog connected to an existing inset
1783 Inset * inset = getOpenInset(name);
1785 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1786 inset->dispatch(view()->cursor(), fr);
1787 } else if (name == "paragraph") {
1788 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1789 } else if (name == "prefs") {
1790 updateDialog(name, string());
1795 case LFUN_DIALOG_TOGGLE: {
1796 if (isDialogVisible(cmd.getArg(0)))
1797 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1799 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1803 case LFUN_DIALOG_DISCONNECT_INSET:
1804 disconnectDialog(to_utf8(cmd.argument()));
1807 case LFUN_DIALOG_HIDE: {
1808 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1812 case LFUN_DIALOG_SHOW: {
1813 string const name = cmd.getArg(0);
1814 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1816 if (name == "character") {
1817 data = freefont2string();
1819 showDialog("character", data);
1820 } else if (name == "latexlog") {
1821 Buffer::LogType type;
1822 string const logfile = buffer()->logName(&type);
1824 case Buffer::latexlog:
1827 case Buffer::buildlog:
1831 data += Lexer::quoteString(logfile);
1832 showDialog("log", data);
1833 } else if (name == "vclog") {
1834 string const data = "vc " +
1835 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1836 showDialog("log", data);
1837 } else if (name == "symbols") {
1838 data = bv->cursor().getEncoding()->name();
1840 showDialog("symbols", data);
1842 showDialog(name, data);
1846 case LFUN_INSET_APPLY: {
1847 string const name = cmd.getArg(0);
1848 Inset * inset = getOpenInset(name);
1850 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1851 inset->dispatch(view()->cursor(), fr);
1853 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1859 case LFUN_UI_TOGGLE:
1861 // Make sure the keyboard focus stays in the work area.
1865 case LFUN_COMPLETION_INLINE:
1866 if (d.current_work_area_)
1867 d.current_work_area_->completer().showInline();
1870 case LFUN_SPLIT_VIEW:
1871 if (Buffer * buf = buffer()) {
1872 string const orientation = cmd.getArg(0);
1873 d.splitter_->setOrientation(orientation == "vertical"
1874 ? Qt::Vertical : Qt::Horizontal);
1875 TabWorkArea * twa = addTabWorkArea();
1876 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1877 setCurrentWorkArea(wa);
1881 case LFUN_CLOSE_TAB_GROUP:
1882 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1884 twa = d.currentTabWorkArea();
1885 // Switch to the next GuiWorkArea in the found TabWorkArea.
1886 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1887 if (d.splitter_->count() == 0)
1888 // No more work area, switch to the background widget.
1893 case LFUN_COMPLETION_POPUP:
1894 if (d.current_work_area_)
1895 d.current_work_area_->completer().showPopup();
1899 case LFUN_COMPLETION_COMPLETE:
1900 if (d.current_work_area_)
1901 d.current_work_area_->completer().tab();
1912 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1914 string const arg = cmd.getArg(0);
1915 if (arg == "scrollbar") {
1916 // hide() is of no help
1917 if (d.current_work_area_->verticalScrollBarPolicy() ==
1918 Qt::ScrollBarAlwaysOff)
1920 d.current_work_area_->setVerticalScrollBarPolicy(
1921 Qt::ScrollBarAsNeeded);
1923 d.current_work_area_->setVerticalScrollBarPolicy(
1924 Qt::ScrollBarAlwaysOff);
1927 if (arg == "statusbar") {
1928 statusBar()->setVisible(!statusBar()->isVisible());
1931 if (arg == "menubar") {
1932 menuBar()->setVisible(!menuBar()->isVisible());
1935 #if QT_VERSION >= 0x040300
1936 if (arg == "frame") {
1938 getContentsMargins(&l, &t, &r, &b);
1939 //are the frames in default state?
1940 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1942 setContentsMargins(-2, -2, -2, -2);
1944 setContentsMargins(0, 0, 0, 0);
1949 if (arg != "fullscreen") {
1950 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1954 if (lyxrc.full_screen_toolbars)
1955 d.toolbars_->toggleFullScreen(!isFullScreen());
1957 if (isFullScreen()) {
1958 for (int i = 0; i != d.splitter_->count(); ++i)
1959 d.tabWorkArea(i)->setFullScreen(false);
1960 #if QT_VERSION >= 0x040300
1961 setContentsMargins(0, 0, 0, 0);
1965 statusBar()->show();
1967 for (int i = 0; i != d.splitter_->count(); ++i)
1968 d.tabWorkArea(i)->setFullScreen(true);
1969 #if QT_VERSION >= 0x040300
1970 setContentsMargins(-2, -2, -2, -2);
1973 statusBar()->hide();
1979 Buffer const * GuiView::updateInset(Inset const * inset)
1981 if (!d.current_work_area_)
1985 d.current_work_area_->scheduleRedraw();
1987 return &d.current_work_area_->bufferView().buffer();
1991 void GuiView::restartCursor()
1993 /* When we move around, or type, it's nice to be able to see
1994 * the cursor immediately after the keypress.
1996 if (d.current_work_area_)
1997 d.current_work_area_->startBlinkingCursor();
1999 // Take this occasion to update the other GUI elements.
2006 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2008 if (d.current_work_area_)
2009 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2014 // This list should be kept in sync with the list of insets in
2015 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2016 // dialog should have the same name as the inset.
2018 char const * const dialognames[] = {
2019 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2020 "citation", "document", "embedding", "errorlist", "ert", "external", "file",
2021 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2022 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2023 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2025 #ifdef HAVE_LIBAIKSAURUS
2029 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2031 char const * const * const end_dialognames =
2032 dialognames + (sizeof(dialognames) / sizeof(char *));
2036 cmpCStr(char const * name) : name_(name) {}
2037 bool operator()(char const * other) {
2038 return strcmp(other, name_) == 0;
2045 bool isValidName(string const & name)
2047 return find_if(dialognames, end_dialognames,
2048 cmpCStr(name.c_str())) != end_dialognames;
2054 void GuiView::resetDialogs()
2056 // Make sure that no LFUN uses any LyXView.
2057 theLyXFunc().setLyXView(0);
2058 // FIXME: the "math panels" toolbar takes an awful lot of time to
2059 // initialise so we don't do that for the time being.
2060 //d.toolbars_->init();
2061 guiApp->menus().fillMenuBar(menuBar(), this);
2063 d.layout_->updateContents(true);
2064 // Now update controls with current buffer.
2065 theLyXFunc().setLyXView(this);
2070 Dialog * GuiView::find_or_build(string const & name)
2072 if (!isValidName(name))
2075 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2077 if (it != d.dialogs_.end())
2078 return it->second.get();
2080 Dialog * dialog = build(name);
2081 d.dialogs_[name].reset(dialog);
2082 if (lyxrc.allow_geometry_session)
2083 dialog->restoreSession();
2088 void GuiView::showDialog(string const & name, string const & data,
2095 Dialog * dialog = find_or_build(name);
2097 dialog->showData(data);
2099 d.open_insets_[name] = inset;
2105 bool GuiView::isDialogVisible(string const & name) const
2107 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2108 if (it == d.dialogs_.end())
2110 return it->second.get()->isVisibleView();
2114 void GuiView::hideDialog(string const & name, Inset * inset)
2116 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2117 if (it == d.dialogs_.end())
2120 if (inset && inset != getOpenInset(name))
2123 Dialog * const dialog = it->second.get();
2124 if (dialog->isVisibleView())
2126 d.open_insets_[name] = 0;
2130 void GuiView::disconnectDialog(string const & name)
2132 if (!isValidName(name))
2135 if (d.open_insets_.find(name) != d.open_insets_.end())
2136 d.open_insets_[name] = 0;
2140 Inset * GuiView::getOpenInset(string const & name) const
2142 if (!isValidName(name))
2145 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2146 return it == d.open_insets_.end() ? 0 : it->second;
2150 void GuiView::hideAll() const
2152 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2153 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2155 for(; it != end; ++it)
2156 it->second->hideView();
2160 void GuiView::hideBufferDependent() const
2162 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2163 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2165 for(; it != end; ++it) {
2166 Dialog * dialog = it->second.get();
2167 if (dialog->isBufferDependent())
2173 void GuiView::updateBufferDependent(bool switched) const
2175 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2176 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2178 for(; it != end; ++it) {
2179 Dialog * dialog = it->second.get();
2180 if (!dialog->isVisibleView())
2182 if (switched && dialog->isBufferDependent()) {
2183 if (dialog->initialiseParams(""))
2184 dialog->updateView();
2188 // A bit clunky, but the dialog will request
2189 // that the kernel provides it with the necessary
2191 dialog->updateDialog();
2197 void GuiView::checkStatus()
2199 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2200 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2202 for(; it != end; ++it) {
2203 Dialog * const dialog = it->second.get();
2204 if (dialog && dialog->isVisibleView())
2205 dialog->checkStatus();
2211 // will be replaced by a proper factory...
2212 Dialog * createGuiAbout(GuiView & lv);
2213 Dialog * createGuiBibitem(GuiView & lv);
2214 Dialog * createGuiBibtex(GuiView & lv);
2215 Dialog * createGuiBox(GuiView & lv);
2216 Dialog * createGuiBranch(GuiView & lv);
2217 Dialog * createGuiChanges(GuiView & lv);
2218 Dialog * createGuiCharacter(GuiView & lv);
2219 Dialog * createGuiCitation(GuiView & lv);
2220 Dialog * createGuiDelimiter(GuiView & lv);
2221 Dialog * createGuiDocument(GuiView & lv);
2222 Dialog * createGuiErrorList(GuiView & lv);
2223 Dialog * createGuiERT(GuiView & lv);
2224 Dialog * createGuiExternal(GuiView & lv);
2225 Dialog * createGuiFloat(GuiView & lv);
2226 Dialog * createGuiGraphics(GuiView & lv);
2227 Dialog * createGuiHSpace(GuiView & lv);
2228 Dialog * createGuiInclude(GuiView & lv);
2229 Dialog * createGuiLabel(GuiView & lv);
2230 Dialog * createGuiListings(GuiView & lv);
2231 Dialog * createGuiLog(GuiView & lv);
2232 Dialog * createGuiMathMatrix(GuiView & lv);
2233 Dialog * createGuiNomenclature(GuiView & lv);
2234 Dialog * createGuiNote(GuiView & lv);
2235 Dialog * createGuiParagraph(GuiView & lv);
2236 Dialog * createGuiPreferences(GuiView & lv);
2237 Dialog * createGuiPrint(GuiView & lv);
2238 Dialog * createGuiRef(GuiView & lv);
2239 Dialog * createGuiSearch(GuiView & lv);
2240 Dialog * createGuiSendTo(GuiView & lv);
2241 Dialog * createGuiShowFile(GuiView & lv);
2242 Dialog * createGuiSpellchecker(GuiView & lv);
2243 Dialog * createGuiSymbols(GuiView & lv);
2244 Dialog * createGuiTabularCreate(GuiView & lv);
2245 Dialog * createGuiTabular(GuiView & lv);
2246 Dialog * createGuiTexInfo(GuiView & lv);
2247 Dialog * createGuiToc(GuiView & lv);
2248 Dialog * createGuiThesaurus(GuiView & lv);
2249 Dialog * createGuiHyperlink(GuiView & lv);
2250 Dialog * createGuiVSpace(GuiView & lv);
2251 Dialog * createGuiViewSource(GuiView & lv);
2252 Dialog * createGuiWrap(GuiView & lv);
2255 Dialog * GuiView::build(string const & name)
2257 BOOST_ASSERT(isValidName(name));
2259 if (name == "aboutlyx")
2260 return createGuiAbout(*this);
2261 if (name == "bibitem")
2262 return createGuiBibitem(*this);
2263 if (name == "bibtex")
2264 return createGuiBibtex(*this);
2266 return createGuiBox(*this);
2267 if (name == "branch")
2268 return createGuiBranch(*this);
2269 if (name == "changes")
2270 return createGuiChanges(*this);
2271 if (name == "character")
2272 return createGuiCharacter(*this);
2273 if (name == "citation")
2274 return createGuiCitation(*this);
2275 if (name == "document")
2276 return createGuiDocument(*this);
2277 if (name == "errorlist")
2278 return createGuiErrorList(*this);
2280 return createGuiERT(*this);
2281 if (name == "external")
2282 return createGuiExternal(*this);
2284 return createGuiShowFile(*this);
2285 if (name == "findreplace")
2286 return createGuiSearch(*this);
2287 if (name == "float")
2288 return createGuiFloat(*this);
2289 if (name == "graphics")
2290 return createGuiGraphics(*this);
2291 if (name == "include")
2292 return createGuiInclude(*this);
2293 if (name == "nomenclature")
2294 return createGuiNomenclature(*this);
2295 if (name == "label")
2296 return createGuiLabel(*this);
2298 return createGuiLog(*this);
2299 if (name == "view-source")
2300 return createGuiViewSource(*this);
2301 if (name == "mathdelimiter")
2302 return createGuiDelimiter(*this);
2303 if (name == "mathmatrix")
2304 return createGuiMathMatrix(*this);
2306 return createGuiNote(*this);
2307 if (name == "paragraph")
2308 return createGuiParagraph(*this);
2309 if (name == "prefs")
2310 return createGuiPreferences(*this);
2311 if (name == "print")
2312 return createGuiPrint(*this);
2314 return createGuiRef(*this);
2315 if (name == "sendto")
2316 return createGuiSendTo(*this);
2317 if (name == "space")
2318 return createGuiHSpace(*this);
2319 if (name == "spellchecker")
2320 return createGuiSpellchecker(*this);
2321 if (name == "symbols")
2322 return createGuiSymbols(*this);
2323 if (name == "tabular")
2324 return createGuiTabular(*this);
2325 if (name == "tabularcreate")
2326 return createGuiTabularCreate(*this);
2327 if (name == "texinfo")
2328 return createGuiTexInfo(*this);
2329 #ifdef HAVE_LIBAIKSAURUS
2330 if (name == "thesaurus")
2331 return createGuiThesaurus(*this);
2334 return createGuiToc(*this);
2336 return createGuiHyperlink(*this);
2337 if (name == "vspace")
2338 return createGuiVSpace(*this);
2340 return createGuiWrap(*this);
2341 if (name == "listings")
2342 return createGuiListings(*this);
2348 } // namespace frontend
2351 #include "GuiView_moc.cpp"