3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiCompleter.h"
22 #include "GuiWorkArea.h"
23 #include "GuiKeySymbol.h"
24 #include "GuiToolbar.h"
25 #include "GuiToolbars.h"
29 #include "qt_helpers.h"
31 #include "frontends/alert.h"
33 #include "buffer_funcs.h"
35 #include "BufferList.h"
36 #include "BufferParams.h"
37 #include "BufferView.h"
38 #include "Converter.h"
41 #include "ErrorList.h"
43 #include "FuncStatus.h"
44 #include "FuncRequest.h"
52 #include "Paragraph.h"
53 #include "TextClass.h"
55 #include "ToolbarBackend.h"
58 #include "support/lassert.h"
59 #include "support/debug.h"
60 #include "support/FileName.h"
61 #include "support/filetools.h"
62 #include "support/gettext.h"
63 #include "support/ForkedCalls.h"
64 #include "support/lstrings.h"
65 #include "support/os.h"
66 #include "support/Package.h"
67 #include "support/Timeout.h"
70 #include <QApplication>
71 #include <QCloseEvent>
73 #include <QDesktopWidget>
74 #include <QDragEnterEvent>
82 #include <QPushButton>
86 #include <QStackedWidget>
93 #include <boost/bind.hpp>
95 #ifdef HAVE_SYS_TIME_H
96 # include <sys/time.h>
103 using namespace lyx::support;
110 class BackgroundWidget : public QWidget
115 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
116 /// The text to be written on top of the pixmap
117 QString const text = lyx_version ?
118 qt_("version ") + lyx_version : qt_("unknown version");
119 splash_ = QPixmap(":/images/banner.png");
121 QPainter pain(&splash_);
122 pain.setPen(QColor(0, 0, 0));
124 // The font used to display the version info
125 font.setStyleHint(QFont::SansSerif);
126 font.setWeight(QFont::Bold);
127 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
129 pain.drawText(190, 225, text);
132 void paintEvent(QPaintEvent *)
134 int x = (width() - splash_.width()) / 2;
135 int y = (height() - splash_.height()) / 2;
137 pain.drawPixmap(x, y, splash_);
147 typedef boost::shared_ptr<Dialog> DialogPtr;
149 struct GuiView::GuiViewPrivate
152 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
155 // hardcode here the platform specific icon size
156 smallIconSize = 14; // scaling problems
157 normalIconSize = 20; // ok, default
158 bigIconSize = 26; // better for some math icons
160 splitter_ = new QSplitter;
161 bg_widget_ = new BackgroundWidget;
162 stack_widget_ = new QStackedWidget;
163 stack_widget_->addWidget(bg_widget_);
164 stack_widget_->addWidget(splitter_);
172 delete stack_widget_;
176 QMenu * toolBarPopup(GuiView * parent)
178 // FIXME: translation
179 QMenu * menu = new QMenu(parent);
180 QActionGroup * iconSizeGroup = new QActionGroup(parent);
182 QAction * smallIcons = new QAction(iconSizeGroup);
183 smallIcons->setText(qt_("Small-sized icons"));
184 smallIcons->setCheckable(true);
185 QObject::connect(smallIcons, SIGNAL(triggered()),
186 parent, SLOT(smallSizedIcons()));
187 menu->addAction(smallIcons);
189 QAction * normalIcons = new QAction(iconSizeGroup);
190 normalIcons->setText(qt_("Normal-sized icons"));
191 normalIcons->setCheckable(true);
192 QObject::connect(normalIcons, SIGNAL(triggered()),
193 parent, SLOT(normalSizedIcons()));
194 menu->addAction(normalIcons);
196 QAction * bigIcons = new QAction(iconSizeGroup);
197 bigIcons->setText(qt_("Big-sized icons"));
198 bigIcons->setCheckable(true);
199 QObject::connect(bigIcons, SIGNAL(triggered()),
200 parent, SLOT(bigSizedIcons()));
201 menu->addAction(bigIcons);
203 unsigned int cur = parent->iconSize().width();
204 if ( cur == parent->d.smallIconSize)
205 smallIcons->setChecked(true);
206 else if (cur == parent->d.normalIconSize)
207 normalIcons->setChecked(true);
208 else if (cur == parent->d.bigIconSize)
209 bigIcons->setChecked(true);
216 stack_widget_->setCurrentWidget(bg_widget_);
217 bg_widget_->setUpdatesEnabled(true);
220 TabWorkArea * tabWorkArea(int i)
222 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
225 TabWorkArea * currentTabWorkArea()
227 if (splitter_->count() == 1)
228 // The first TabWorkArea is always the first one, if any.
229 return tabWorkArea(0);
231 for (int i = 0; i != splitter_->count(); ++i) {
232 TabWorkArea * twa = tabWorkArea(i);
233 if (current_work_area_ == twa->currentWorkArea())
237 // None has the focus so we just take the first one.
238 return tabWorkArea(0);
242 GuiWorkArea * current_work_area_;
243 QSplitter * splitter_;
244 QStackedWidget * stack_widget_;
245 BackgroundWidget * bg_widget_;
247 GuiToolbars * toolbars_;
248 /// The main layout box.
250 * \warning Don't Delete! The layout box is actually owned by
251 * whichever toolbar contains it. All the GuiView class needs is a
252 * means of accessing it.
254 * FIXME: replace that with a proper model so that we are not limited
255 * to only one dialog.
257 GuiLayoutBox * layout_;
260 map<string, Inset *> open_insets_;
263 map<string, DialogPtr> dialogs_;
265 unsigned int smallIconSize;
266 unsigned int normalIconSize;
267 unsigned int bigIconSize;
269 QTimer statusbar_timer_;
270 /// auto-saving of buffers
271 Timeout autosave_timeout_;
272 /// flag against a race condition due to multiclicks, see bug #1119
276 TocModels toc_models_;
280 GuiView::GuiView(int id)
281 : d(*new GuiViewPrivate), id_(id)
283 // GuiToolbars *must* be initialised before the menu bar.
284 d.toolbars_ = new GuiToolbars(*this);
286 // set ourself as the current view. This is needed for the menu bar
287 // filling, at least for the static special menu item on Mac. Otherwise
288 // they are greyed out.
289 theLyXFunc().setLyXView(this);
291 // Fill up the menu bar.
292 guiApp->menus().fillMenuBar(menuBar(), this, true);
294 setCentralWidget(d.stack_widget_);
296 // Start autosave timer
297 if (lyxrc.autosave) {
298 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
299 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
300 d.autosave_timeout_.start();
302 connect(&d.statusbar_timer_, SIGNAL(timeout()),
303 this, SLOT(clearMessage()));
305 // We don't want to keep the window in memory if it is closed.
306 setAttribute(Qt::WA_DeleteOnClose, true);
308 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
309 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
310 // since the icon is provided in the application bundle.
311 setWindowIcon(QPixmap(":/images/lyx.png"));
315 setAcceptDrops(true);
317 statusBar()->setSizeGripEnabled(true);
319 // Forbid too small unresizable window because it can happen
320 // with some window manager under X11.
321 setMinimumSize(300, 200);
323 if (!lyxrc.allow_geometry_session)
324 // No session handling, default to a sane size.
325 setGeometry(50, 50, 690, 510);
327 // Now take care of session management.
329 QString const key = "view-" + QString::number(id_);
331 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
332 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
336 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
337 setGeometry(50, 50, 690, 510);
339 setIconSize(settings.value(key + "/icon_size").toSize());
345 if (guiApp->currentView() == this)
346 guiApp->setCurrentView(0);
347 theLyXFunc().setLyXView(0);
353 TocModels & GuiView::tocModels()
355 return d.toc_models_;
359 void GuiView::setFocus()
361 if (d.current_work_area_)
362 d.current_work_area_->setFocus();
368 QMenu * GuiView::createPopupMenu()
370 return d.toolBarPopup(this);
374 void GuiView::showEvent(QShowEvent * e)
376 LYXERR(Debug::GUI, "Passed Geometry "
377 << size().height() << "x" << size().width()
378 << "+" << pos().x() << "+" << pos().y());
380 if (d.splitter_->count() == 0)
381 // No work area, switch to the background widget.
384 QMainWindow::showEvent(e);
388 void GuiView::closeEvent(QCloseEvent * close_event)
390 // it can happen that this event arrives without selecting the view,
391 // e.g. when clicking the close button on a background window.
392 theLyXFunc().setLyXView(this);
394 while (Buffer * b = buffer()) {
396 // This is a child document, just close the tab after saving
397 // but keep the file loaded.
398 if (!saveBuffer(*b)) {
399 close_event->ignore();
402 removeWorkArea(d.current_work_area_);
406 QVector<int> const ids = guiApp->viewIds();
407 for (int i = 0; i != ids.size(); ++i) {
410 if (guiApp->view(ids[i]).workArea(*b)) {
411 // FIXME 1: should we put an alert box here that the buffer
412 // is viewed elsewhere?
413 // FIXME 2: should we try to save this buffer in any case?
416 // This buffer is also opened in another view, so
417 // but close the associated work area nevertheless.
418 removeWorkArea(d.current_work_area_);
419 // but don't close it.
424 if (b && !closeBuffer(*b, true)) {
425 close_event->ignore();
430 // Make sure that no LFUN use this close to be closed View.
431 theLyXFunc().setLyXView(0);
433 // Save toolbars configuration
434 if (isFullScreen()) {
435 d.toolbars_->toggleFullScreen(!isFullScreen());
439 // Make sure the timer time out will not trigger a statusbar update.
440 d.statusbar_timer_.stop();
442 // Saving fullscreen requires additional tweaks in the toolbar code.
443 // It wouldn't also work under linux natively.
444 if (lyxrc.allow_geometry_session && !isFullScreen()) {
446 QString const key = "view-" + QString::number(id_);
448 settings.setValue(key + "/pos", pos());
449 settings.setValue(key + "/size", size());
451 settings.setValue(key + "/geometry", saveGeometry());
453 settings.setValue(key + "/icon_size", iconSize());
454 d.toolbars_->saveToolbarInfo();
455 // Now take care of all other dialogs:
456 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
457 for (; it!= d.dialogs_.end(); ++it)
458 it->second->saveSession();
461 guiApp->unregisterView(id_);
462 close_event->accept();
466 void GuiView::dragEnterEvent(QDragEnterEvent * event)
468 if (event->mimeData()->hasUrls())
470 /// \todo Ask lyx-devel is this is enough:
471 /// if (event->mimeData()->hasFormat("text/plain"))
472 /// event->acceptProposedAction();
476 void GuiView::dropEvent(QDropEvent* event)
478 QList<QUrl> files = event->mimeData()->urls();
482 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
483 for (int i = 0; i != files.size(); ++i) {
484 string const file = os::internal_path(fromqstr(
485 files.at(i).toLocalFile()));
487 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
492 void GuiView::message(docstring const & str)
494 if (ForkedProcess::iAmAChild())
497 statusBar()->showMessage(toqstr(str));
498 d.statusbar_timer_.stop();
499 d.statusbar_timer_.start(3000);
503 void GuiView::smallSizedIcons()
505 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
509 void GuiView::normalSizedIcons()
511 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
515 void GuiView::bigSizedIcons()
517 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
521 void GuiView::clearMessage()
525 theLyXFunc().setLyXView(this);
526 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
527 d.statusbar_timer_.stop();
531 void GuiView::updateWindowTitle(GuiWorkArea * wa)
533 if (wa != d.current_work_area_)
535 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
536 setWindowIconText(wa->windowIconText());
540 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
543 disconnectBufferView();
544 connectBufferView(wa->bufferView());
545 connectBuffer(wa->bufferView().buffer());
546 d.current_work_area_ = wa;
547 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
548 this, SLOT(updateWindowTitle(GuiWorkArea *)));
549 updateWindowTitle(wa);
553 // The document settings needs to be reinitialised.
554 updateDialog("document", "");
556 // Buffer-dependent dialogs must be updated. This is done here because
557 // some dialogs require buffer()->text.
562 void GuiView::on_lastWorkAreaRemoved()
565 // On Mac close the view if there is no Tab open anymore,
566 // but only if no splitter is visible
567 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
568 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
569 if (twa && twa->count() == 0) {
570 // close the view, as no tab is open anymore
571 QTimer::singleShot(0, this, SLOT(close()));
576 // The document settings needs to be reinitialised.
577 updateDialog("document", "");
583 void GuiView::updateStatusBar()
585 // let the user see the explicit message
586 if (d.statusbar_timer_.isActive())
589 theLyXFunc().setLyXView(this);
590 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
594 bool GuiView::hasFocus() const
596 return qApp->activeWindow() == this;
600 bool GuiView::event(QEvent * e)
604 // Useful debug code:
605 //case QEvent::ActivationChange:
606 //case QEvent::WindowDeactivate:
607 //case QEvent::Paint:
608 //case QEvent::Enter:
609 //case QEvent::Leave:
610 //case QEvent::HoverEnter:
611 //case QEvent::HoverLeave:
612 //case QEvent::HoverMove:
613 //case QEvent::StatusTip:
614 //case QEvent::DragEnter:
615 //case QEvent::DragLeave:
619 case QEvent::WindowActivate: {
620 if (this == guiApp->currentView()) {
622 return QMainWindow::event(e);
624 guiApp->setCurrentView(this);
625 if (d.current_work_area_) {
626 BufferView & bv = d.current_work_area_->bufferView();
627 connectBufferView(bv);
628 connectBuffer(bv.buffer());
629 // The document structure, name and dialogs might have
630 // changed in another view.
632 // The document settings needs to be reinitialised.
633 updateDialog("document", "");
636 setWindowTitle(qt_("LyX"));
637 setWindowIconText(qt_("LyX"));
640 return QMainWindow::event(e);
643 case QEvent::ShortcutOverride: {
645 if (isFullScreen() && menuBar()->isHidden()) {
646 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
647 // FIXME: we should also try to detect special LyX shortcut such as
648 // Alt-P and Alt-M. Right now there is a hack in
649 // GuiWorkArea::processKeySym() that hides again the menubar for
651 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt)
653 return QMainWindow::event(e);
656 if (d.current_work_area_)
657 // Nothing special to do.
658 return QMainWindow::event(e);
660 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
661 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
663 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
664 || ke->key() == Qt::Key_Backtab)
665 return QMainWindow::event(e);
667 // Allow processing of shortcuts that are allowed even when no Buffer
669 theLyXFunc().setLyXView(this);
671 setKeySymbol(&sym, ke);
672 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
678 return QMainWindow::event(e);
683 bool GuiView::focusNextPrevChild(bool /*next*/)
690 void GuiView::setBusy(bool busy)
692 if (d.current_work_area_) {
693 d.current_work_area_->setUpdatesEnabled(!busy);
695 d.current_work_area_->stopBlinkingCursor();
697 d.current_work_area_->startBlinkingCursor();
701 QApplication::setOverrideCursor(Qt::WaitCursor);
703 QApplication::restoreOverrideCursor();
707 GuiToolbar * GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
709 GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
711 if (tbinfo.flags & ToolbarInfo::TOP) {
713 addToolBarBreak(Qt::TopToolBarArea);
714 addToolBar(Qt::TopToolBarArea, toolBar);
717 if (tbinfo.flags & ToolbarInfo::BOTTOM) {
718 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
719 #if (QT_VERSION >= 0x040202)
721 addToolBarBreak(Qt::BottomToolBarArea);
723 addToolBar(Qt::BottomToolBarArea, toolBar);
726 if (tbinfo.flags & ToolbarInfo::LEFT) {
727 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
728 #if (QT_VERSION >= 0x040202)
730 addToolBarBreak(Qt::LeftToolBarArea);
732 addToolBar(Qt::LeftToolBarArea, toolBar);
735 if (tbinfo.flags & ToolbarInfo::RIGHT) {
736 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
737 #if (QT_VERSION >= 0x040202)
739 addToolBarBreak(Qt::RightToolBarArea);
741 addToolBar(Qt::RightToolBarArea, toolBar);
744 // The following does not work so I cannot restore to exact toolbar location
746 ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
747 toolBar->move(tbinfo.posx, tbinfo.posy);
754 GuiWorkArea * GuiView::workArea(Buffer & buffer)
756 if (TabWorkArea * twa = d.currentTabWorkArea())
757 return twa->workArea(buffer);
762 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
764 // Automatically create a TabWorkArea if there are none yet.
765 TabWorkArea * tab_widget = d.splitter_->count()
766 ? d.currentTabWorkArea() : addTabWorkArea();
767 return tab_widget->addWorkArea(buffer, *this);
771 TabWorkArea * GuiView::addTabWorkArea()
773 TabWorkArea * twa = new TabWorkArea;
774 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
775 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
776 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
777 this, SLOT(on_lastWorkAreaRemoved()));
779 d.splitter_->addWidget(twa);
780 d.stack_widget_->setCurrentWidget(d.splitter_);
785 GuiWorkArea const * GuiView::currentWorkArea() const
787 return d.current_work_area_;
791 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
794 d.current_work_area_ = wa;
795 for (int i = 0; i != d.splitter_->count(); ++i) {
796 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
802 void GuiView::removeWorkArea(GuiWorkArea * wa)
805 if (wa == d.current_work_area_) {
807 disconnectBufferView();
808 d.current_work_area_ = 0;
811 for (int i = 0; i != d.splitter_->count(); ++i) {
812 TabWorkArea * twa = d.tabWorkArea(i);
813 if (!twa->removeWorkArea(wa))
814 // Not found in this tab group.
817 // We found and removed the GuiWorkArea.
819 // No more WorkAreas in this tab group, so delete it.
824 if (d.current_work_area_)
825 // This means that we are not closing the current GuiWorkArea;
828 // Switch to the next GuiWorkArea in the found TabWorkArea.
829 d.current_work_area_ = twa->currentWorkArea();
833 if (d.splitter_->count() == 0)
834 // No more work area, switch to the background widget.
839 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
845 void GuiView::updateLayoutList()
848 d.layout_->updateContents(false);
852 void GuiView::updateToolbars()
854 if (d.current_work_area_) {
856 d.current_work_area_->bufferView().cursor().inMathed();
858 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
860 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
861 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
862 bool const mathmacrotemplate =
863 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
865 d.toolbars_->update(math, table, review, mathmacrotemplate);
867 d.toolbars_->update(false, false, false, false);
871 Buffer * GuiView::buffer()
873 if (d.current_work_area_)
874 return &d.current_work_area_->bufferView().buffer();
879 Buffer const * GuiView::buffer() const
881 if (d.current_work_area_)
882 return &d.current_work_area_->bufferView().buffer();
887 void GuiView::setBuffer(Buffer * newBuffer)
889 LASSERT(newBuffer, /**/);
892 GuiWorkArea * wa = workArea(*newBuffer);
894 updateLabels(*newBuffer->masterBuffer());
895 wa = addWorkArea(*newBuffer);
897 //Disconnect the old buffer...there's no new one.
900 connectBuffer(*newBuffer);
901 connectBufferView(wa->bufferView());
902 setCurrentWorkArea(wa);
908 void GuiView::connectBuffer(Buffer & buf)
910 buf.setGuiDelegate(this);
914 void GuiView::disconnectBuffer()
916 if (d.current_work_area_)
917 d.current_work_area_->bufferView().setGuiDelegate(0);
921 void GuiView::connectBufferView(BufferView & bv)
923 bv.setGuiDelegate(this);
927 void GuiView::disconnectBufferView()
929 if (d.current_work_area_)
930 d.current_work_area_->bufferView().setGuiDelegate(0);
934 void GuiView::errors(string const & error_type)
936 ErrorList & el = buffer()->errorList(error_type);
938 showDialog("errorlist", error_type);
942 void GuiView::structureChanged()
944 d.toc_models_.reset(view());
945 // Navigator needs more than a simple update in this case. It needs to be
947 updateDialog("toc", "");
951 void GuiView::updateDialog(string const & name, string const & data)
953 if (!isDialogVisible(name))
956 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
957 if (it == d.dialogs_.end())
960 Dialog * const dialog = it->second.get();
961 if (dialog->isVisibleView())
962 dialog->initialiseParams(data);
966 BufferView * GuiView::view()
968 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
972 void GuiView::autoSave()
974 LYXERR(Debug::INFO, "Running autoSave()");
977 view()->buffer().autoSave();
981 void GuiView::resetAutosaveTimers()
984 d.autosave_timeout_.restart();
988 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
991 Buffer * buf = buffer();
993 /* In LyX/Mac, when a dialog is open, the menus of the
994 application can still be accessed without giving focus to
995 the main window. In this case, we want to disable the menu
996 entries that are buffer-related.
998 Note that this code is not perfect, as bug 1941 attests:
999 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1001 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1004 switch(cmd.action) {
1005 case LFUN_BUFFER_WRITE:
1006 enable = buf && (buf->isUnnamed() || !buf->isClean());
1009 case LFUN_BUFFER_WRITE_AS:
1013 case LFUN_SPLIT_VIEW:
1017 case LFUN_CLOSE_TAB_GROUP:
1018 enable = d.currentTabWorkArea();
1021 case LFUN_TOOLBAR_TOGGLE:
1022 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1025 case LFUN_UI_TOGGLE:
1026 flag.setOnOff(isFullScreen());
1029 case LFUN_DIALOG_TOGGLE:
1030 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1031 // fall through to set "enable"
1032 case LFUN_DIALOG_SHOW: {
1033 string const name = cmd.getArg(0);
1035 enable = name == "aboutlyx"
1036 || name == "file" //FIXME: should be removed.
1038 || name == "texinfo";
1039 else if (name == "print")
1040 enable = buf->isExportable("dvi")
1041 && lyxrc.print_command != "none";
1042 else if (name == "character") {
1046 InsetCode ic = view()->cursor().inset().lyxCode();
1047 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1050 else if (name == "symbols") {
1051 if (!view() || view()->cursor().inMathed())
1054 InsetCode ic = view()->cursor().inset().lyxCode();
1055 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1058 else if (name == "latexlog")
1059 enable = FileName(buf->logName()).isReadableFile();
1060 else if (name == "spellchecker")
1061 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1062 enable = !buf->isReadonly();
1066 else if (name == "vclog")
1067 enable = buf->lyxvc().inUse();
1071 case LFUN_DIALOG_UPDATE: {
1072 string const name = cmd.getArg(0);
1074 enable = name == "prefs";
1078 case LFUN_INSET_APPLY: {
1079 string const name = cmd.getArg(0);
1080 Inset * inset = getOpenInset(name);
1082 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1084 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1085 // Every inset is supposed to handle this
1086 LASSERT(false, /**/);
1090 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1091 flag |= lyx::getStatus(fr);
1093 enable = flag.enabled();
1097 case LFUN_COMPLETION_INLINE:
1098 if (!d.current_work_area_
1099 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1103 case LFUN_COMPLETION_POPUP:
1104 if (!d.current_work_area_
1105 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1109 case LFUN_COMPLETION_COMPLETE:
1110 if (!d.current_work_area_
1111 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1120 flag.enabled(false);
1126 static FileName selectTemplateFile()
1128 FileDialog dlg(qt_("Select template file"));
1129 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1130 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1132 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1133 QStringList(qt_("LyX Documents (*.lyx)")));
1135 if (result.first == FileDialog::Later)
1137 if (result.second.isEmpty())
1139 return FileName(fromqstr(result.second));
1143 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1147 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1150 message(_("Document not loaded."));
1155 setBuffer(newBuffer);
1157 // scroll to the position when the file was last closed
1158 if (lyxrc.use_lastfilepos) {
1159 LastFilePosSection::FilePos filepos =
1160 LyX::ref().session().lastFilePos().load(filename);
1161 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1165 LyX::ref().session().lastFiles().add(filename);
1172 void GuiView::openDocument(string const & fname)
1174 string initpath = lyxrc.document_path;
1177 string const trypath = buffer()->filePath();
1178 // If directory is writeable, use this as default.
1179 if (FileName(trypath).isDirWritable())
1185 if (fname.empty()) {
1186 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1187 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1188 dlg.setButton2(qt_("Examples|#E#e"),
1189 toqstr(addPath(package().system_support().absFilename(), "examples")));
1191 FileDialog::Result result =
1192 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1194 if (result.first == FileDialog::Later)
1197 filename = fromqstr(result.second);
1199 // check selected filename
1200 if (filename.empty()) {
1201 message(_("Canceled."));
1207 // get absolute path of file and add ".lyx" to the filename if
1209 FileName const fullname =
1210 fileSearch(string(), filename, "lyx", support::may_not_exist);
1211 if (!fullname.empty())
1212 filename = fullname.absFilename();
1214 // if the file doesn't exist, let the user create one
1215 if (!fullname.exists()) {
1216 // the user specifically chose this name. Believe him.
1217 Buffer * const b = newFile(filename, string(), true);
1223 docstring const disp_fn = makeDisplayPath(filename);
1224 message(bformat(_("Opening document %1$s..."), disp_fn));
1227 Buffer * buf = loadDocument(fullname);
1232 buf->errors("Parse");
1233 str2 = bformat(_("Document %1$s opened."), disp_fn);
1235 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1240 // FIXME: clean that
1241 static bool import(GuiView * lv, FileName const & filename,
1242 string const & format, ErrorList & errorList)
1244 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1246 string loader_format;
1247 vector<string> loaders = theConverters().loaders();
1248 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1249 for (vector<string>::const_iterator it = loaders.begin();
1250 it != loaders.end(); ++it) {
1251 if (!theConverters().isReachable(format, *it))
1254 string const tofile =
1255 support::changeExtension(filename.absFilename(),
1256 formats.extension(*it));
1257 if (!theConverters().convert(0, filename, FileName(tofile),
1258 filename, format, *it, errorList))
1260 loader_format = *it;
1263 if (loader_format.empty()) {
1264 frontend::Alert::error(_("Couldn't import file"),
1265 bformat(_("No information for importing the format %1$s."),
1266 formats.prettyName(format)));
1270 loader_format = format;
1272 if (loader_format == "lyx") {
1273 Buffer * buf = lv->loadDocument(lyxfile);
1278 buf->errors("Parse");
1280 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1284 bool as_paragraphs = loader_format == "textparagraph";
1285 string filename2 = (loader_format == format) ? filename.absFilename()
1286 : support::changeExtension(filename.absFilename(),
1287 formats.extension(loader_format));
1288 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1289 theLyXFunc().setLyXView(lv);
1290 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1297 void GuiView::importDocument(string const & argument)
1300 string filename = split(argument, format, ' ');
1302 LYXERR(Debug::INFO, format << " file: " << filename);
1304 // need user interaction
1305 if (filename.empty()) {
1306 string initpath = lyxrc.document_path;
1308 Buffer const * buf = buffer();
1310 string const trypath = buf->filePath();
1311 // If directory is writeable, use this as default.
1312 if (FileName(trypath).isDirWritable())
1316 docstring const text = bformat(_("Select %1$s file to import"),
1317 formats.prettyName(format));
1319 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1320 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1321 dlg.setButton2(qt_("Examples|#E#e"),
1322 toqstr(addPath(package().system_support().absFilename(), "examples")));
1324 docstring filter = formats.prettyName(format);
1327 filter += from_utf8(formats.extension(format));
1330 FileDialog::Result result =
1331 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1333 if (result.first == FileDialog::Later)
1336 filename = fromqstr(result.second);
1338 // check selected filename
1339 if (filename.empty())
1340 message(_("Canceled."));
1343 if (filename.empty())
1346 // get absolute path of file
1347 FileName const fullname(support::makeAbsPath(filename));
1349 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1351 // Check if the document already is open
1352 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1355 if (!closeBuffer()) {
1356 message(_("Canceled."));
1361 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1363 // if the file exists already, and we didn't do
1364 // -i lyx thefile.lyx, warn
1365 if (lyxfile.exists() && fullname != lyxfile) {
1367 docstring text = bformat(_("The document %1$s already exists.\n\n"
1368 "Do you want to overwrite that document?"), displaypath);
1369 int const ret = Alert::prompt(_("Overwrite document?"),
1370 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1373 message(_("Canceled."));
1378 message(bformat(_("Importing %1$s..."), displaypath));
1379 ErrorList errorList;
1380 if (import(this, fullname, format, errorList))
1381 message(_("imported."));
1383 message(_("file not imported!"));
1385 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1389 void GuiView::newDocument(string const & filename, bool from_template)
1391 FileName initpath(lyxrc.document_path);
1392 Buffer * buf = buffer();
1394 FileName const trypath(buf->filePath());
1395 // If directory is writeable, use this as default.
1396 if (trypath.isDirWritable())
1400 string templatefile = from_template ?
1401 selectTemplateFile().absFilename() : string();
1403 if (filename.empty())
1404 b = newUnnamedFile(templatefile, initpath);
1406 b = newFile(filename, templatefile, true);
1410 // Ensure the cursor is correctly positionned on screen.
1411 view()->showCursor();
1415 void GuiView::insertLyXFile(docstring const & fname)
1417 BufferView * bv = view();
1422 FileName filename(to_utf8(fname));
1424 if (!filename.empty()) {
1425 bv->insertLyXFile(filename);
1429 // Launch a file browser
1431 string initpath = lyxrc.document_path;
1432 string const trypath = bv->buffer().filePath();
1433 // If directory is writeable, use this as default.
1434 if (FileName(trypath).isDirWritable())
1438 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1439 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1440 dlg.setButton2(qt_("Examples|#E#e"),
1441 toqstr(addPath(package().system_support().absFilename(),
1444 FileDialog::Result result = dlg.open(toqstr(initpath),
1445 QStringList(qt_("LyX Documents (*.lyx)")));
1447 if (result.first == FileDialog::Later)
1451 filename.set(fromqstr(result.second));
1453 // check selected filename
1454 if (filename.empty()) {
1455 // emit message signal.
1456 message(_("Canceled."));
1460 bv->insertLyXFile(filename);
1464 void GuiView::insertPlaintextFile(docstring const & fname,
1467 BufferView * bv = view();
1472 FileName filename(to_utf8(fname));
1474 if (!filename.empty()) {
1475 bv->insertPlaintextFile(filename, asParagraph);
1479 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1480 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1482 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1485 if (result.first == FileDialog::Later)
1489 filename.set(fromqstr(result.second));
1491 // check selected filename
1492 if (filename.empty()) {
1493 // emit message signal.
1494 message(_("Canceled."));
1498 bv->insertPlaintextFile(filename, asParagraph);
1502 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1504 FileName fname = b.fileName();
1505 FileName const oldname = fname;
1507 if (!newname.empty()) {
1509 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1511 // Switch to this Buffer.
1514 /// No argument? Ask user through dialog.
1516 FileDialog dlg(qt_("Choose a filename to save document as"),
1517 LFUN_BUFFER_WRITE_AS);
1518 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1519 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1521 if (!isLyXFilename(fname.absFilename()))
1522 fname.changeExtension(".lyx");
1524 FileDialog::Result result =
1525 dlg.save(toqstr(fname.onlyPath().absFilename()),
1526 QStringList(qt_("LyX Documents (*.lyx)")),
1527 toqstr(fname.onlyFileName()));
1529 if (result.first == FileDialog::Later)
1532 fname.set(fromqstr(result.second));
1537 if (!isLyXFilename(fname.absFilename()))
1538 fname.changeExtension(".lyx");
1541 if (FileName(fname).exists()) {
1542 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1543 docstring text = bformat(_("The document %1$s already "
1544 "exists.\n\nDo you want to "
1545 "overwrite that document?"),
1547 int const ret = Alert::prompt(_("Overwrite document?"),
1548 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1551 case 1: return renameBuffer(b, docstring());
1552 case 2: return false;
1556 // Ok, change the name of the buffer
1557 b.setFileName(fname.absFilename());
1559 bool unnamed = b.isUnnamed();
1560 b.setUnnamed(false);
1561 b.saveCheckSum(fname);
1563 if (!saveBuffer(b)) {
1564 b.setFileName(oldname.absFilename());
1565 b.setUnnamed(unnamed);
1566 b.saveCheckSum(oldname);
1574 bool GuiView::saveBuffer(Buffer & b)
1577 return renameBuffer(b, docstring());
1580 LyX::ref().session().lastFiles().add(b.fileName());
1584 // Switch to this Buffer.
1587 // FIXME: we don't tell the user *WHY* the save failed !!
1588 docstring const file = makeDisplayPath(b.absFileName(), 30);
1589 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1590 "Do you want to rename the document and "
1591 "try again?"), file);
1592 int const ret = Alert::prompt(_("Rename and save?"),
1593 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1596 if (!renameBuffer(b, docstring()))
1605 return saveBuffer(b);
1609 bool GuiView::closeBuffer()
1611 Buffer * buf = buffer();
1612 return buf && closeBuffer(*buf);
1616 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1618 // goto bookmark to update bookmark pit.
1619 //FIXME: we should update only the bookmarks related to this buffer!
1620 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1621 theLyXFunc().gotoBookmark(i+1, false, false);
1623 if (buf.isClean() || buf.paragraphs().empty()) {
1624 if (buf.masterBuffer() == &buf && tolastopened)
1625 LyX::ref().session().lastOpened().add(buf.fileName());
1626 theBufferList().release(&buf);
1629 // Switch to this Buffer.
1634 if (buf.isUnnamed())
1635 file = from_utf8(buf.fileName().onlyFileName());
1637 file = buf.fileName().displayName(30);
1639 // Bring this window to top before asking questions.
1643 docstring const text = bformat(_("The document %1$s has unsaved changes."
1644 "\n\nDo you want to save the document or discard the changes?"), file);
1645 int const ret = Alert::prompt(_("Save changed document?"),
1646 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1650 if (!saveBuffer(buf))
1654 // if we crash after this we could
1655 // have no autosave file but I guess
1656 // this is really improbable (Jug)
1657 removeAutosaveFile(buf.absFileName());
1663 // save file names to .lyx/session
1664 // if master/slave are both open, do not save slave since it
1665 // will be automatically loaded when the master is loaded
1666 if (buf.masterBuffer() == &buf && tolastopened)
1667 LyX::ref().session().lastOpened().add(buf.fileName());
1669 theBufferList().release(&buf);
1674 bool GuiView::dispatch(FuncRequest const & cmd)
1676 BufferView * bv = view();
1677 // By default we won't need any update.
1679 bv->cursor().updateFlags(Update::None);
1680 bool dispatched = true;
1682 switch(cmd.action) {
1683 case LFUN_BUFFER_IMPORT:
1684 importDocument(to_utf8(cmd.argument()));
1687 case LFUN_BUFFER_SWITCH:
1688 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1691 case LFUN_BUFFER_NEXT:
1692 setBuffer(theBufferList().next(buffer()));
1695 case LFUN_BUFFER_PREVIOUS:
1696 setBuffer(theBufferList().previous(buffer()));
1699 case LFUN_COMMAND_EXECUTE: {
1700 bool const show_it = cmd.argument() != "off";
1701 d.toolbars_->showCommandBuffer(show_it);
1704 case LFUN_DROP_LAYOUTS_CHOICE:
1706 d.layout_->showPopup();
1709 case LFUN_MENU_OPEN:
1710 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1711 menu->exec(QCursor::pos());
1714 case LFUN_FILE_INSERT:
1715 insertLyXFile(cmd.argument());
1717 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1718 insertPlaintextFile(cmd.argument(), true);
1721 case LFUN_FILE_INSERT_PLAINTEXT:
1722 insertPlaintextFile(cmd.argument(), false);
1725 case LFUN_BUFFER_WRITE:
1727 saveBuffer(bv->buffer());
1730 case LFUN_BUFFER_WRITE_AS:
1732 renameBuffer(bv->buffer(), cmd.argument());
1735 case LFUN_BUFFER_WRITE_ALL: {
1736 Buffer * first = theBufferList().first();
1739 message(_("Saving all documents..."));
1740 // We cannot use a for loop as the buffer list cycles.
1743 if (!b->isClean()) {
1745 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1747 b = theBufferList().next(b);
1748 } while (b != first);
1749 message(_("All documents saved."));
1753 case LFUN_TOOLBAR_TOGGLE: {
1754 string const name = cmd.getArg(0);
1755 bool const allowauto = cmd.getArg(1) == "allowauto";
1756 // it is possible to get current toolbar status like this,...
1757 // but I decide to obey the order of ToolbarBackend::flags
1758 // and disregard real toolbar status.
1759 // toolbars_->saveToolbarInfo();
1761 // toggle state on/off/auto
1762 d.toolbars_->toggleToolbarState(name, allowauto);
1766 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1768 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1772 if (tbi->flags & ToolbarInfo::ON)
1774 else if (tbi->flags & ToolbarInfo::OFF)
1776 else if (tbi->flags & ToolbarInfo::AUTO)
1779 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1780 _(tbi->gui_name), state));
1784 case LFUN_DIALOG_UPDATE: {
1785 string const name = to_utf8(cmd.argument());
1786 // Can only update a dialog connected to an existing inset
1787 Inset * inset = getOpenInset(name);
1789 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1790 inset->dispatch(view()->cursor(), fr);
1791 } else if (name == "paragraph") {
1792 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1793 } else if (name == "prefs") {
1794 updateDialog(name, string());
1799 case LFUN_DIALOG_TOGGLE: {
1800 if (isDialogVisible(cmd.getArg(0)))
1801 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1803 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1807 case LFUN_DIALOG_DISCONNECT_INSET:
1808 disconnectDialog(to_utf8(cmd.argument()));
1811 case LFUN_DIALOG_HIDE: {
1812 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1816 case LFUN_DIALOG_SHOW: {
1817 string const name = cmd.getArg(0);
1818 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1820 if (name == "character") {
1821 data = freefont2string();
1823 showDialog("character", data);
1824 } else if (name == "latexlog") {
1825 Buffer::LogType type;
1826 string const logfile = buffer()->logName(&type);
1828 case Buffer::latexlog:
1831 case Buffer::buildlog:
1835 data += Lexer::quoteString(logfile);
1836 showDialog("log", data);
1837 } else if (name == "vclog") {
1838 string const data = "vc " +
1839 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1840 showDialog("log", data);
1841 } else if (name == "symbols") {
1842 data = bv->cursor().getEncoding()->name();
1844 showDialog("symbols", data);
1846 showDialog(name, data);
1850 case LFUN_INSET_APPLY: {
1851 view()->cursor().recordUndoFullDocument();
1852 string const name = cmd.getArg(0);
1853 Inset * inset = getOpenInset(name);
1855 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1856 inset->dispatch(view()->cursor(), fr);
1858 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1864 case LFUN_UI_TOGGLE:
1866 // Make sure the keyboard focus stays in the work area.
1870 case LFUN_COMPLETION_INLINE:
1871 if (d.current_work_area_)
1872 d.current_work_area_->completer().showInline();
1875 case LFUN_SPLIT_VIEW:
1876 if (Buffer * buf = buffer()) {
1877 string const orientation = cmd.getArg(0);
1878 d.splitter_->setOrientation(orientation == "vertical"
1879 ? Qt::Vertical : Qt::Horizontal);
1880 TabWorkArea * twa = addTabWorkArea();
1881 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1882 setCurrentWorkArea(wa);
1886 case LFUN_CLOSE_TAB_GROUP:
1887 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1889 twa = d.currentTabWorkArea();
1890 // Switch to the next GuiWorkArea in the found TabWorkArea.
1891 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1892 if (d.splitter_->count() == 0)
1893 // No more work area, switch to the background widget.
1898 case LFUN_COMPLETION_POPUP:
1899 if (d.current_work_area_)
1900 d.current_work_area_->completer().showPopup();
1904 case LFUN_COMPLETION_COMPLETE:
1905 if (d.current_work_area_)
1906 d.current_work_area_->completer().tab();
1914 if (isFullScreen()) {
1915 if (menuBar()->isVisible())
1917 if (statusBar()->isVisible())
1918 statusBar()->hide();
1925 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1927 string const arg = cmd.getArg(0);
1928 if (arg == "scrollbar") {
1929 // hide() is of no help
1930 if (d.current_work_area_->verticalScrollBarPolicy() ==
1931 Qt::ScrollBarAlwaysOff)
1933 d.current_work_area_->setVerticalScrollBarPolicy(
1934 Qt::ScrollBarAsNeeded);
1936 d.current_work_area_->setVerticalScrollBarPolicy(
1937 Qt::ScrollBarAlwaysOff);
1940 if (arg == "statusbar") {
1941 statusBar()->setVisible(!statusBar()->isVisible());
1944 if (arg == "menubar") {
1945 menuBar()->setVisible(!menuBar()->isVisible());
1948 #if QT_VERSION >= 0x040300
1949 if (arg == "frame") {
1951 getContentsMargins(&l, &t, &r, &b);
1952 //are the frames in default state?
1953 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1955 setContentsMargins(-2, -2, -2, -2);
1957 setContentsMargins(0, 0, 0, 0);
1962 if (arg != "fullscreen") {
1963 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1967 if (lyxrc.full_screen_toolbars)
1968 d.toolbars_->toggleFullScreen(!isFullScreen());
1970 if (isFullScreen()) {
1971 for (int i = 0; i != d.splitter_->count(); ++i)
1972 d.tabWorkArea(i)->setFullScreen(false);
1973 #if QT_VERSION >= 0x040300
1974 setContentsMargins(0, 0, 0, 0);
1976 setWindowState(windowState() ^ Qt::WindowFullScreen);
1978 statusBar()->show();
1980 for (int i = 0; i != d.splitter_->count(); ++i)
1981 d.tabWorkArea(i)->setFullScreen(true);
1982 #if QT_VERSION >= 0x040300
1983 setContentsMargins(-2, -2, -2, -2);
1985 setWindowState(windowState() ^ Qt::WindowFullScreen);
1986 statusBar()->hide();
1992 Buffer const * GuiView::updateInset(Inset const * inset)
1994 if (!d.current_work_area_)
1998 d.current_work_area_->scheduleRedraw();
2000 return &d.current_work_area_->bufferView().buffer();
2004 void GuiView::restartCursor()
2006 /* When we move around, or type, it's nice to be able to see
2007 * the cursor immediately after the keypress.
2009 if (d.current_work_area_)
2010 d.current_work_area_->startBlinkingCursor();
2012 // Take this occasion to update the other GUI elements.
2017 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2019 if (d.current_work_area_)
2020 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2025 // This list should be kept in sync with the list of insets in
2026 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2027 // dialog should have the same name as the inset.
2029 char const * const dialognames[] = {
2030 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2031 "citation", "document", "errorlist", "ert", "external", "file",
2032 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2033 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2034 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2036 #ifdef HAVE_LIBAIKSAURUS
2040 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2042 char const * const * const end_dialognames =
2043 dialognames + (sizeof(dialognames) / sizeof(char *));
2047 cmpCStr(char const * name) : name_(name) {}
2048 bool operator()(char const * other) {
2049 return strcmp(other, name_) == 0;
2056 bool isValidName(string const & name)
2058 return find_if(dialognames, end_dialognames,
2059 cmpCStr(name.c_str())) != end_dialognames;
2065 void GuiView::resetDialogs()
2067 // Make sure that no LFUN uses any LyXView.
2068 theLyXFunc().setLyXView(0);
2069 // FIXME: the "math panels" toolbar takes an awful lot of time to
2070 // initialise so we don't do that for the time being.
2071 //d.toolbars_->init();
2072 guiApp->menus().fillMenuBar(menuBar(), this);
2074 d.layout_->updateContents(true);
2075 // Now update controls with current buffer.
2076 theLyXFunc().setLyXView(this);
2081 Dialog * GuiView::find_or_build(string const & name)
2083 if (!isValidName(name))
2086 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2088 if (it != d.dialogs_.end())
2089 return it->second.get();
2091 Dialog * dialog = build(name);
2092 d.dialogs_[name].reset(dialog);
2093 if (lyxrc.allow_geometry_session)
2094 dialog->restoreSession();
2099 void GuiView::showDialog(string const & name, string const & data,
2106 Dialog * dialog = find_or_build(name);
2108 dialog->showData(data);
2110 d.open_insets_[name] = inset;
2116 bool GuiView::isDialogVisible(string const & name) const
2118 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2119 if (it == d.dialogs_.end())
2121 return it->second.get()->isVisibleView();
2125 void GuiView::hideDialog(string const & name, Inset * inset)
2127 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2128 if (it == d.dialogs_.end())
2131 if (inset && inset != getOpenInset(name))
2134 Dialog * const dialog = it->second.get();
2135 if (dialog->isVisibleView())
2137 d.open_insets_[name] = 0;
2141 void GuiView::disconnectDialog(string const & name)
2143 if (!isValidName(name))
2146 if (d.open_insets_.find(name) != d.open_insets_.end())
2147 d.open_insets_[name] = 0;
2151 Inset * GuiView::getOpenInset(string const & name) const
2153 if (!isValidName(name))
2156 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2157 return it == d.open_insets_.end() ? 0 : it->second;
2161 void GuiView::hideAll() const
2163 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2164 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2166 for(; it != end; ++it)
2167 it->second->hideView();
2171 void GuiView::updateDialogs()
2173 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2174 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2176 for(; it != end; ++it) {
2177 Dialog * dialog = it->second.get();
2178 if (dialog && dialog->isVisibleView())
2179 dialog->checkStatus();
2187 // will be replaced by a proper factory...
2188 Dialog * createGuiAbout(GuiView & lv);
2189 Dialog * createGuiBibitem(GuiView & lv);
2190 Dialog * createGuiBibtex(GuiView & lv);
2191 Dialog * createGuiBox(GuiView & lv);
2192 Dialog * createGuiBranch(GuiView & lv);
2193 Dialog * createGuiChanges(GuiView & lv);
2194 Dialog * createGuiCharacter(GuiView & lv);
2195 Dialog * createGuiCitation(GuiView & lv);
2196 Dialog * createGuiDelimiter(GuiView & lv);
2197 Dialog * createGuiDocument(GuiView & lv);
2198 Dialog * createGuiErrorList(GuiView & lv);
2199 Dialog * createGuiERT(GuiView & lv);
2200 Dialog * createGuiExternal(GuiView & lv);
2201 Dialog * createGuiFloat(GuiView & lv);
2202 Dialog * createGuiGraphics(GuiView & lv);
2203 Dialog * createGuiHSpace(GuiView & lv);
2204 Dialog * createGuiInclude(GuiView & lv);
2205 Dialog * createGuiLabel(GuiView & lv);
2206 Dialog * createGuiListings(GuiView & lv);
2207 Dialog * createGuiLog(GuiView & lv);
2208 Dialog * createGuiMathMatrix(GuiView & lv);
2209 Dialog * createGuiNomenclature(GuiView & lv);
2210 Dialog * createGuiNote(GuiView & lv);
2211 Dialog * createGuiParagraph(GuiView & lv);
2212 Dialog * createGuiPreferences(GuiView & lv);
2213 Dialog * createGuiPrint(GuiView & lv);
2214 Dialog * createGuiRef(GuiView & lv);
2215 Dialog * createGuiSearch(GuiView & lv);
2216 Dialog * createGuiSendTo(GuiView & lv);
2217 Dialog * createGuiShowFile(GuiView & lv);
2218 Dialog * createGuiSpellchecker(GuiView & lv);
2219 Dialog * createGuiSymbols(GuiView & lv);
2220 Dialog * createGuiTabularCreate(GuiView & lv);
2221 Dialog * createGuiTabular(GuiView & lv);
2222 Dialog * createGuiTexInfo(GuiView & lv);
2223 Dialog * createGuiToc(GuiView & lv);
2224 Dialog * createGuiThesaurus(GuiView & lv);
2225 Dialog * createGuiHyperlink(GuiView & lv);
2226 Dialog * createGuiVSpace(GuiView & lv);
2227 Dialog * createGuiViewSource(GuiView & lv);
2228 Dialog * createGuiWrap(GuiView & lv);
2231 Dialog * GuiView::build(string const & name)
2233 LASSERT(isValidName(name), /**/);
2235 if (name == "aboutlyx")
2236 return createGuiAbout(*this);
2237 if (name == "bibitem")
2238 return createGuiBibitem(*this);
2239 if (name == "bibtex")
2240 return createGuiBibtex(*this);
2242 return createGuiBox(*this);
2243 if (name == "branch")
2244 return createGuiBranch(*this);
2245 if (name == "changes")
2246 return createGuiChanges(*this);
2247 if (name == "character")
2248 return createGuiCharacter(*this);
2249 if (name == "citation")
2250 return createGuiCitation(*this);
2251 if (name == "document")
2252 return createGuiDocument(*this);
2253 if (name == "errorlist")
2254 return createGuiErrorList(*this);
2256 return createGuiERT(*this);
2257 if (name == "external")
2258 return createGuiExternal(*this);
2260 return createGuiShowFile(*this);
2261 if (name == "findreplace")
2262 return createGuiSearch(*this);
2263 if (name == "float")
2264 return createGuiFloat(*this);
2265 if (name == "graphics")
2266 return createGuiGraphics(*this);
2267 if (name == "include")
2268 return createGuiInclude(*this);
2269 if (name == "nomenclature")
2270 return createGuiNomenclature(*this);
2271 if (name == "label")
2272 return createGuiLabel(*this);
2274 return createGuiLog(*this);
2275 if (name == "view-source")
2276 return createGuiViewSource(*this);
2277 if (name == "mathdelimiter")
2278 return createGuiDelimiter(*this);
2279 if (name == "mathmatrix")
2280 return createGuiMathMatrix(*this);
2282 return createGuiNote(*this);
2283 if (name == "paragraph")
2284 return createGuiParagraph(*this);
2285 if (name == "prefs")
2286 return createGuiPreferences(*this);
2287 if (name == "print")
2288 return createGuiPrint(*this);
2290 return createGuiRef(*this);
2291 if (name == "sendto")
2292 return createGuiSendTo(*this);
2293 if (name == "space")
2294 return createGuiHSpace(*this);
2295 if (name == "spellchecker")
2296 return createGuiSpellchecker(*this);
2297 if (name == "symbols")
2298 return createGuiSymbols(*this);
2299 if (name == "tabular")
2300 return createGuiTabular(*this);
2301 if (name == "tabularcreate")
2302 return createGuiTabularCreate(*this);
2303 if (name == "texinfo")
2304 return createGuiTexInfo(*this);
2305 #ifdef HAVE_LIBAIKSAURUS
2306 if (name == "thesaurus")
2307 return createGuiThesaurus(*this);
2310 return createGuiToc(*this);
2312 return createGuiHyperlink(*this);
2313 if (name == "vspace")
2314 return createGuiVSpace(*this);
2316 return createGuiWrap(*this);
2317 if (name == "listings")
2318 return createGuiListings(*this);
2324 } // namespace frontend
2327 #include "GuiView_moc.cpp"