3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * \author Abdelrazak Younes
11 * Full author contact details are available in file CREDITS.
19 #include "FileDialog.h"
20 #include "GuiApplication.h"
21 #include "GuiCompleter.h"
22 #include "GuiWorkArea.h"
23 #include "GuiKeySymbol.h"
24 #include "GuiToolbar.h"
25 #include "GuiToolbars.h"
29 #include "qt_helpers.h"
31 #include "frontends/alert.h"
33 #include "buffer_funcs.h"
35 #include "BufferList.h"
36 #include "BufferParams.h"
37 #include "BufferView.h"
38 #include "Converter.h"
41 #include "ErrorList.h"
43 #include "FuncStatus.h"
44 #include "FuncRequest.h"
52 #include "Paragraph.h"
53 #include "TextClass.h"
55 #include "ToolbarBackend.h"
58 #include "support/lassert.h"
59 #include "support/debug.h"
60 #include "support/FileName.h"
61 #include "support/filetools.h"
62 #include "support/gettext.h"
63 #include "support/ForkedCalls.h"
64 #include "support/lstrings.h"
65 #include "support/os.h"
66 #include "support/Package.h"
67 #include "support/Timeout.h"
70 #include <QApplication>
71 #include <QCloseEvent>
73 #include <QDesktopWidget>
74 #include <QDragEnterEvent>
82 #include <QPushButton>
86 #include <QStackedWidget>
93 #include <boost/bind.hpp>
95 #ifdef HAVE_SYS_TIME_H
96 # include <sys/time.h>
103 using namespace lyx::support;
110 class BackgroundWidget : public QWidget
115 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
116 /// The text to be written on top of the pixmap
117 QString const text = lyx_version ?
118 qt_("version ") + lyx_version : qt_("unknown version");
119 splash_ = QPixmap(":/images/banner.png");
121 QPainter pain(&splash_);
122 pain.setPen(QColor(0, 0, 0));
124 // The font used to display the version info
125 font.setStyleHint(QFont::SansSerif);
126 font.setWeight(QFont::Bold);
127 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
129 pain.drawText(190, 225, text);
132 void paintEvent(QPaintEvent *)
134 int x = (width() - splash_.width()) / 2;
135 int y = (height() - splash_.height()) / 2;
137 pain.drawPixmap(x, y, splash_);
147 typedef boost::shared_ptr<Dialog> DialogPtr;
149 struct GuiView::GuiViewPrivate
152 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
155 // hardcode here the platform specific icon size
156 smallIconSize = 14; // scaling problems
157 normalIconSize = 20; // ok, default
158 bigIconSize = 26; // better for some math icons
160 splitter_ = new QSplitter;
161 bg_widget_ = new BackgroundWidget;
162 stack_widget_ = new QStackedWidget;
163 stack_widget_->addWidget(bg_widget_);
164 stack_widget_->addWidget(splitter_);
172 delete stack_widget_;
176 QMenu * toolBarPopup(GuiView * parent)
178 // FIXME: translation
179 QMenu * menu = new QMenu(parent);
180 QActionGroup * iconSizeGroup = new QActionGroup(parent);
182 QAction * smallIcons = new QAction(iconSizeGroup);
183 smallIcons->setText(qt_("Small-sized icons"));
184 smallIcons->setCheckable(true);
185 QObject::connect(smallIcons, SIGNAL(triggered()),
186 parent, SLOT(smallSizedIcons()));
187 menu->addAction(smallIcons);
189 QAction * normalIcons = new QAction(iconSizeGroup);
190 normalIcons->setText(qt_("Normal-sized icons"));
191 normalIcons->setCheckable(true);
192 QObject::connect(normalIcons, SIGNAL(triggered()),
193 parent, SLOT(normalSizedIcons()));
194 menu->addAction(normalIcons);
196 QAction * bigIcons = new QAction(iconSizeGroup);
197 bigIcons->setText(qt_("Big-sized icons"));
198 bigIcons->setCheckable(true);
199 QObject::connect(bigIcons, SIGNAL(triggered()),
200 parent, SLOT(bigSizedIcons()));
201 menu->addAction(bigIcons);
203 unsigned int cur = parent->iconSize().width();
204 if ( cur == parent->d.smallIconSize)
205 smallIcons->setChecked(true);
206 else if (cur == parent->d.normalIconSize)
207 normalIcons->setChecked(true);
208 else if (cur == parent->d.bigIconSize)
209 bigIcons->setChecked(true);
216 stack_widget_->setCurrentWidget(bg_widget_);
217 bg_widget_->setUpdatesEnabled(true);
220 TabWorkArea * tabWorkArea(int i)
222 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
225 TabWorkArea * currentTabWorkArea()
227 if (splitter_->count() == 1)
228 // The first TabWorkArea is always the first one, if any.
229 return tabWorkArea(0);
231 for (int i = 0; i != splitter_->count(); ++i) {
232 TabWorkArea * twa = tabWorkArea(i);
233 if (current_work_area_ == twa->currentWorkArea())
237 // None has the focus so we just take the first one.
238 return tabWorkArea(0);
242 GuiWorkArea * current_work_area_;
243 QSplitter * splitter_;
244 QStackedWidget * stack_widget_;
245 BackgroundWidget * bg_widget_;
247 GuiToolbars * toolbars_;
248 /// The main layout box.
250 * \warning Don't Delete! The layout box is actually owned by
251 * whichever toolbar contains it. All the GuiView class needs is a
252 * means of accessing it.
254 * FIXME: replace that with a proper model so that we are not limited
255 * to only one dialog.
257 GuiLayoutBox * layout_;
260 map<string, Inset *> open_insets_;
263 map<string, DialogPtr> dialogs_;
265 unsigned int smallIconSize;
266 unsigned int normalIconSize;
267 unsigned int bigIconSize;
269 QTimer statusbar_timer_;
270 /// auto-saving of buffers
271 Timeout autosave_timeout_;
272 /// flag against a race condition due to multiclicks, see bug #1119
276 TocModels toc_models_;
280 GuiView::GuiView(int id)
281 : d(*new GuiViewPrivate), id_(id)
283 // GuiToolbars *must* be initialised before the menu bar.
284 d.toolbars_ = new GuiToolbars(*this);
286 // set ourself as the current view. This is needed for the menu bar
287 // filling, at least for the static special menu item on Mac. Otherwise
288 // they are greyed out.
289 theLyXFunc().setLyXView(this);
291 // Fill up the menu bar.
292 guiApp->menus().fillMenuBar(menuBar(), this, true);
294 setCentralWidget(d.stack_widget_);
296 // Start autosave timer
297 if (lyxrc.autosave) {
298 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
299 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
300 d.autosave_timeout_.start();
302 connect(&d.statusbar_timer_, SIGNAL(timeout()),
303 this, SLOT(clearMessage()));
305 // We don't want to keep the window in memory if it is closed.
306 setAttribute(Qt::WA_DeleteOnClose, true);
308 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
309 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
310 // since the icon is provided in the application bundle.
311 setWindowIcon(QPixmap(":/images/lyx.png"));
315 setAcceptDrops(true);
317 statusBar()->setSizeGripEnabled(true);
319 // Forbid too small unresizable window because it can happen
320 // with some window manager under X11.
321 setMinimumSize(300, 200);
323 if (!lyxrc.allow_geometry_session)
324 // No session handling, default to a sane size.
325 setGeometry(50, 50, 690, 510);
327 // Now take care of session management.
329 QString const key = "view-" + QString::number(id_);
331 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
332 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
336 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
337 setGeometry(50, 50, 690, 510);
339 setIconSize(settings.value(key + "/icon_size").toSize());
345 if (guiApp->currentView() == this)
346 guiApp->setCurrentView(0);
347 theLyXFunc().setLyXView(0);
353 TocModels & GuiView::tocModels()
355 return d.toc_models_;
359 void GuiView::setFocus()
361 if (d.current_work_area_)
362 d.current_work_area_->setFocus();
368 QMenu * GuiView::createPopupMenu()
370 return d.toolBarPopup(this);
374 void GuiView::showEvent(QShowEvent * e)
376 LYXERR(Debug::GUI, "Passed Geometry "
377 << size().height() << "x" << size().width()
378 << "+" << pos().x() << "+" << pos().y());
380 if (d.splitter_->count() == 0)
381 // No work area, switch to the background widget.
384 QMainWindow::showEvent(e);
388 void GuiView::closeEvent(QCloseEvent * close_event)
390 // it can happen that this event arrives without selecting the view,
391 // e.g. when clicking the close button on a background window.
392 theLyXFunc().setLyXView(this);
394 while (Buffer * b = buffer()) {
396 // This is a child document, just close the tab after saving
397 // but keep the file loaded.
398 if (!saveBuffer(*b)) {
399 close_event->ignore();
402 removeWorkArea(d.current_work_area_);
406 std::vector<int> const & ids = guiApp->viewIds();
407 for (size_type i = 0; i != ids.size(); ++i) {
410 if (guiApp->view(ids[i]).workArea(*b)) {
411 // FIXME 1: should we put an alert box here that the buffer
412 // is viewed elsewhere?
413 // FIXME 2: should we try to save this buffer in any case?
416 // This buffer is also opened in another view, so
417 // but close the associated work area nevertheless.
418 removeWorkArea(d.current_work_area_);
419 // but don't close it.
424 if (b && !closeBuffer(*b, true)) {
425 close_event->ignore();
430 // Make sure that no LFUN use this close to be closed View.
431 theLyXFunc().setLyXView(0);
433 // Save toolbars configuration
434 if (isFullScreen()) {
435 d.toolbars_->toggleFullScreen(!isFullScreen());
439 // Make sure the timer time out will not trigger a statusbar update.
440 d.statusbar_timer_.stop();
442 // Saving fullscreen requires additional tweaks in the toolbar code.
443 // It wouldn't also work under linux natively.
444 if (lyxrc.allow_geometry_session && !isFullScreen()) {
446 QString const key = "view-" + QString::number(id_);
448 settings.setValue(key + "/pos", pos());
449 settings.setValue(key + "/size", size());
451 settings.setValue(key + "/geometry", saveGeometry());
453 settings.setValue(key + "/icon_size", iconSize());
454 d.toolbars_->saveToolbarInfo();
455 // Now take care of all other dialogs:
456 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
457 for (; it!= d.dialogs_.end(); ++it)
458 it->second->saveSession();
461 guiApp->unregisterView(id_);
462 close_event->accept();
466 void GuiView::dragEnterEvent(QDragEnterEvent * event)
468 if (event->mimeData()->hasUrls())
470 /// \todo Ask lyx-devel is this is enough:
471 /// if (event->mimeData()->hasFormat("text/plain"))
472 /// event->acceptProposedAction();
476 void GuiView::dropEvent(QDropEvent* event)
478 QList<QUrl> files = event->mimeData()->urls();
482 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
483 for (int i = 0; i != files.size(); ++i) {
484 string const file = os::internal_path(fromqstr(
485 files.at(i).toLocalFile()));
487 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
492 void GuiView::message(docstring const & str)
494 if (ForkedProcess::iAmAChild())
497 statusBar()->showMessage(toqstr(str));
498 d.statusbar_timer_.stop();
499 d.statusbar_timer_.start(3000);
503 void GuiView::smallSizedIcons()
505 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
509 void GuiView::normalSizedIcons()
511 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
515 void GuiView::bigSizedIcons()
517 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
521 void GuiView::clearMessage()
525 theLyXFunc().setLyXView(this);
526 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
527 d.statusbar_timer_.stop();
531 void GuiView::updateWindowTitle(GuiWorkArea * wa)
533 if (wa != d.current_work_area_)
535 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
536 setWindowIconText(wa->windowIconText());
540 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
543 disconnectBufferView();
544 connectBufferView(wa->bufferView());
545 connectBuffer(wa->bufferView().buffer());
546 d.current_work_area_ = wa;
547 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
548 this, SLOT(updateWindowTitle(GuiWorkArea *)));
549 updateWindowTitle(wa);
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 FuncStatus GuiView::getStatus(FuncRequest const & cmd)
992 Buffer * buf = buffer();
994 /* In LyX/Mac, when a dialog is open, the menus of the
995 application can still be accessed without giving focus to
996 the main window. In this case, we want to disable the menu
997 entries that are buffer-related.
999 Note that this code is not perfect, as bug 1941 attests:
1000 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1002 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1005 switch(cmd.action) {
1006 case LFUN_BUFFER_WRITE:
1007 enable = buf && (buf->isUnnamed() || !buf->isClean());
1010 case LFUN_BUFFER_WRITE_AS:
1014 case LFUN_SPLIT_VIEW:
1018 case LFUN_CLOSE_TAB_GROUP:
1019 enable = d.currentTabWorkArea();
1022 case LFUN_TOOLBAR_TOGGLE:
1023 flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
1026 case LFUN_UI_TOGGLE:
1027 flag.setOnOff(isFullScreen());
1030 case LFUN_DIALOG_TOGGLE:
1031 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1032 // fall through to set "enable"
1033 case LFUN_DIALOG_SHOW: {
1034 string const name = cmd.getArg(0);
1036 enable = name == "aboutlyx"
1037 || name == "file" //FIXME: should be removed.
1039 || name == "texinfo";
1040 else if (name == "print")
1041 enable = buf->isExportable("dvi")
1042 && lyxrc.print_command != "none";
1043 else if (name == "character") {
1047 InsetCode ic = view()->cursor().inset().lyxCode();
1048 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1051 else if (name == "symbols") {
1052 if (!view() || view()->cursor().inMathed())
1055 InsetCode ic = view()->cursor().inset().lyxCode();
1056 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1059 else if (name == "latexlog")
1060 enable = FileName(buf->logName()).isReadableFile();
1061 else if (name == "spellchecker")
1062 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1063 enable = !buf->isReadonly();
1067 else if (name == "vclog")
1068 enable = buf->lyxvc().inUse();
1072 case LFUN_DIALOG_UPDATE: {
1073 string const name = cmd.getArg(0);
1075 enable = name == "prefs";
1079 case LFUN_INSET_APPLY: {
1084 string const name = cmd.getArg(0);
1085 Inset * inset = getOpenInset(name);
1087 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1089 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1090 // Every inset is supposed to handle this
1091 LASSERT(false, /**/);
1095 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1096 flag |= getStatus(fr);
1098 enable = flag.enabled();
1102 case LFUN_COMPLETION_INLINE:
1103 if (!d.current_work_area_
1104 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1108 case LFUN_COMPLETION_POPUP:
1109 if (!d.current_work_area_
1110 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1114 case LFUN_COMPLETION_COMPLETE:
1115 if (!d.current_work_area_
1116 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1128 flag.enabled(false);
1134 static FileName selectTemplateFile()
1136 FileDialog dlg(qt_("Select template file"));
1137 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1138 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1140 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1141 QStringList(qt_("LyX Documents (*.lyx)")));
1143 if (result.first == FileDialog::Later)
1145 if (result.second.isEmpty())
1147 return FileName(fromqstr(result.second));
1151 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1155 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1158 message(_("Document not loaded."));
1163 setBuffer(newBuffer);
1165 // scroll to the position when the file was last closed
1166 if (lyxrc.use_lastfilepos) {
1167 LastFilePosSection::FilePos filepos =
1168 LyX::ref().session().lastFilePos().load(filename);
1169 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1173 LyX::ref().session().lastFiles().add(filename);
1180 void GuiView::openDocument(string const & fname)
1182 string initpath = lyxrc.document_path;
1185 string const trypath = buffer()->filePath();
1186 // If directory is writeable, use this as default.
1187 if (FileName(trypath).isDirWritable())
1193 if (fname.empty()) {
1194 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1195 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1196 dlg.setButton2(qt_("Examples|#E#e"),
1197 toqstr(addPath(package().system_support().absFilename(), "examples")));
1199 FileDialog::Result result =
1200 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1202 if (result.first == FileDialog::Later)
1205 filename = fromqstr(result.second);
1207 // check selected filename
1208 if (filename.empty()) {
1209 message(_("Canceled."));
1215 // get absolute path of file and add ".lyx" to the filename if
1217 FileName const fullname =
1218 fileSearch(string(), filename, "lyx", support::may_not_exist);
1219 if (!fullname.empty())
1220 filename = fullname.absFilename();
1222 // if the file doesn't exist, let the user create one
1223 if (!fullname.exists()) {
1224 // the user specifically chose this name. Believe him.
1225 Buffer * const b = newFile(filename, string(), true);
1231 docstring const disp_fn = makeDisplayPath(filename);
1232 message(bformat(_("Opening document %1$s..."), disp_fn));
1235 Buffer * buf = loadDocument(fullname);
1240 buf->errors("Parse");
1241 str2 = bformat(_("Document %1$s opened."), disp_fn);
1243 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1248 // FIXME: clean that
1249 static bool import(GuiView * lv, FileName const & filename,
1250 string const & format, ErrorList & errorList)
1252 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1254 string loader_format;
1255 vector<string> loaders = theConverters().loaders();
1256 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1257 for (vector<string>::const_iterator it = loaders.begin();
1258 it != loaders.end(); ++it) {
1259 if (!theConverters().isReachable(format, *it))
1262 string const tofile =
1263 support::changeExtension(filename.absFilename(),
1264 formats.extension(*it));
1265 if (!theConverters().convert(0, filename, FileName(tofile),
1266 filename, format, *it, errorList))
1268 loader_format = *it;
1271 if (loader_format.empty()) {
1272 frontend::Alert::error(_("Couldn't import file"),
1273 bformat(_("No information for importing the format %1$s."),
1274 formats.prettyName(format)));
1278 loader_format = format;
1280 if (loader_format == "lyx") {
1281 Buffer * buf = lv->loadDocument(lyxfile);
1286 buf->errors("Parse");
1288 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1292 bool as_paragraphs = loader_format == "textparagraph";
1293 string filename2 = (loader_format == format) ? filename.absFilename()
1294 : support::changeExtension(filename.absFilename(),
1295 formats.extension(loader_format));
1296 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1297 theLyXFunc().setLyXView(lv);
1298 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1305 void GuiView::importDocument(string const & argument)
1308 string filename = split(argument, format, ' ');
1310 LYXERR(Debug::INFO, format << " file: " << filename);
1312 // need user interaction
1313 if (filename.empty()) {
1314 string initpath = lyxrc.document_path;
1316 Buffer const * buf = buffer();
1318 string const trypath = buf->filePath();
1319 // If directory is writeable, use this as default.
1320 if (FileName(trypath).isDirWritable())
1324 docstring const text = bformat(_("Select %1$s file to import"),
1325 formats.prettyName(format));
1327 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1328 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1329 dlg.setButton2(qt_("Examples|#E#e"),
1330 toqstr(addPath(package().system_support().absFilename(), "examples")));
1332 docstring filter = formats.prettyName(format);
1335 filter += from_utf8(formats.extension(format));
1338 FileDialog::Result result =
1339 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1341 if (result.first == FileDialog::Later)
1344 filename = fromqstr(result.second);
1346 // check selected filename
1347 if (filename.empty())
1348 message(_("Canceled."));
1351 if (filename.empty())
1354 // get absolute path of file
1355 FileName const fullname(support::makeAbsPath(filename));
1357 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1359 // Check if the document already is open
1360 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1363 if (!closeBuffer()) {
1364 message(_("Canceled."));
1369 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1371 // if the file exists already, and we didn't do
1372 // -i lyx thefile.lyx, warn
1373 if (lyxfile.exists() && fullname != lyxfile) {
1375 docstring text = bformat(_("The document %1$s already exists.\n\n"
1376 "Do you want to overwrite that document?"), displaypath);
1377 int const ret = Alert::prompt(_("Overwrite document?"),
1378 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1381 message(_("Canceled."));
1386 message(bformat(_("Importing %1$s..."), displaypath));
1387 ErrorList errorList;
1388 if (import(this, fullname, format, errorList))
1389 message(_("imported."));
1391 message(_("file not imported!"));
1393 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1397 void GuiView::newDocument(string const & filename, bool from_template)
1399 FileName initpath(lyxrc.document_path);
1400 Buffer * buf = buffer();
1402 FileName const trypath(buf->filePath());
1403 // If directory is writeable, use this as default.
1404 if (trypath.isDirWritable())
1408 string templatefile = from_template ?
1409 selectTemplateFile().absFilename() : string();
1411 if (filename.empty())
1412 b = newUnnamedFile(templatefile, initpath);
1414 b = newFile(filename, templatefile, true);
1418 // Ensure the cursor is correctly positionned on screen.
1419 view()->showCursor();
1423 void GuiView::insertLyXFile(docstring const & fname)
1425 BufferView * bv = view();
1430 FileName filename(to_utf8(fname));
1432 if (!filename.empty()) {
1433 bv->insertLyXFile(filename);
1437 // Launch a file browser
1439 string initpath = lyxrc.document_path;
1440 string const trypath = bv->buffer().filePath();
1441 // If directory is writeable, use this as default.
1442 if (FileName(trypath).isDirWritable())
1446 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1447 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1448 dlg.setButton2(qt_("Examples|#E#e"),
1449 toqstr(addPath(package().system_support().absFilename(),
1452 FileDialog::Result result = dlg.open(toqstr(initpath),
1453 QStringList(qt_("LyX Documents (*.lyx)")));
1455 if (result.first == FileDialog::Later)
1459 filename.set(fromqstr(result.second));
1461 // check selected filename
1462 if (filename.empty()) {
1463 // emit message signal.
1464 message(_("Canceled."));
1468 bv->insertLyXFile(filename);
1472 void GuiView::insertPlaintextFile(docstring const & fname,
1475 BufferView * bv = view();
1480 FileName filename(to_utf8(fname));
1482 if (!filename.empty()) {
1483 bv->insertPlaintextFile(filename, asParagraph);
1487 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1488 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1490 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1493 if (result.first == FileDialog::Later)
1497 filename.set(fromqstr(result.second));
1499 // check selected filename
1500 if (filename.empty()) {
1501 // emit message signal.
1502 message(_("Canceled."));
1506 bv->insertPlaintextFile(filename, asParagraph);
1510 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1512 FileName fname = b.fileName();
1513 FileName const oldname = fname;
1515 if (!newname.empty()) {
1517 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1519 // Switch to this Buffer.
1522 /// No argument? Ask user through dialog.
1524 FileDialog dlg(qt_("Choose a filename to save document as"),
1525 LFUN_BUFFER_WRITE_AS);
1526 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1527 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1529 if (!isLyXFilename(fname.absFilename()))
1530 fname.changeExtension(".lyx");
1532 FileDialog::Result result =
1533 dlg.save(toqstr(fname.onlyPath().absFilename()),
1534 QStringList(qt_("LyX Documents (*.lyx)")),
1535 toqstr(fname.onlyFileName()));
1537 if (result.first == FileDialog::Later)
1540 fname.set(fromqstr(result.second));
1545 if (!isLyXFilename(fname.absFilename()))
1546 fname.changeExtension(".lyx");
1549 if (FileName(fname).exists()) {
1550 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1551 docstring text = bformat(_("The document %1$s already "
1552 "exists.\n\nDo you want to "
1553 "overwrite that document?"),
1555 int const ret = Alert::prompt(_("Overwrite document?"),
1556 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1559 case 1: return renameBuffer(b, docstring());
1560 case 2: return false;
1564 // Ok, change the name of the buffer
1565 b.setFileName(fname.absFilename());
1567 bool unnamed = b.isUnnamed();
1568 b.setUnnamed(false);
1569 b.saveCheckSum(fname);
1571 if (!saveBuffer(b)) {
1572 b.setFileName(oldname.absFilename());
1573 b.setUnnamed(unnamed);
1574 b.saveCheckSum(oldname);
1582 bool GuiView::saveBuffer(Buffer & b)
1585 return renameBuffer(b, docstring());
1588 LyX::ref().session().lastFiles().add(b.fileName());
1592 // Switch to this Buffer.
1595 // FIXME: we don't tell the user *WHY* the save failed !!
1596 docstring const file = makeDisplayPath(b.absFileName(), 30);
1597 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1598 "Do you want to rename the document and "
1599 "try again?"), file);
1600 int const ret = Alert::prompt(_("Rename and save?"),
1601 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1604 if (!renameBuffer(b, docstring()))
1613 return saveBuffer(b);
1617 bool GuiView::closeBuffer()
1619 Buffer * buf = buffer();
1620 return buf && closeBuffer(*buf);
1624 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1626 // goto bookmark to update bookmark pit.
1627 //FIXME: we should update only the bookmarks related to this buffer!
1628 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1629 theLyXFunc().gotoBookmark(i+1, false, false);
1631 if (buf.isClean() || buf.paragraphs().empty()) {
1632 if (buf.masterBuffer() == &buf && tolastopened)
1633 LyX::ref().session().lastOpened().add(buf.fileName());
1634 theBufferList().release(&buf);
1637 // Switch to this Buffer.
1642 if (buf.isUnnamed())
1643 file = from_utf8(buf.fileName().onlyFileName());
1645 file = buf.fileName().displayName(30);
1647 // Bring this window to top before asking questions.
1651 docstring const text = bformat(_("The document %1$s has unsaved changes."
1652 "\n\nDo you want to save the document or discard the changes?"), file);
1653 int const ret = Alert::prompt(_("Save changed document?"),
1654 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1658 if (!saveBuffer(buf))
1662 // if we crash after this we could
1663 // have no autosave file but I guess
1664 // this is really improbable (Jug)
1665 removeAutosaveFile(buf.absFileName());
1671 // save file names to .lyx/session
1672 // if master/slave are both open, do not save slave since it
1673 // will be automatically loaded when the master is loaded
1674 if (buf.masterBuffer() == &buf && tolastopened)
1675 LyX::ref().session().lastOpened().add(buf.fileName());
1677 theBufferList().release(&buf);
1682 bool GuiView::dispatch(FuncRequest const & cmd)
1684 BufferView * bv = view();
1685 // By default we won't need any update.
1687 bv->cursor().updateFlags(Update::None);
1688 bool dispatched = true;
1690 switch(cmd.action) {
1691 case LFUN_BUFFER_IMPORT:
1692 importDocument(to_utf8(cmd.argument()));
1695 case LFUN_BUFFER_SWITCH:
1696 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1699 case LFUN_BUFFER_NEXT:
1700 setBuffer(theBufferList().next(buffer()));
1703 case LFUN_BUFFER_PREVIOUS:
1704 setBuffer(theBufferList().previous(buffer()));
1707 case LFUN_COMMAND_EXECUTE: {
1708 bool const show_it = cmd.argument() != "off";
1709 d.toolbars_->showCommandBuffer(show_it);
1712 case LFUN_DROP_LAYOUTS_CHOICE:
1714 d.layout_->showPopup();
1717 case LFUN_MENU_OPEN:
1718 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1719 menu->exec(QCursor::pos());
1722 case LFUN_FILE_INSERT:
1723 insertLyXFile(cmd.argument());
1725 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1726 insertPlaintextFile(cmd.argument(), true);
1729 case LFUN_FILE_INSERT_PLAINTEXT:
1730 insertPlaintextFile(cmd.argument(), false);
1733 case LFUN_BUFFER_WRITE:
1735 saveBuffer(bv->buffer());
1738 case LFUN_BUFFER_WRITE_AS:
1740 renameBuffer(bv->buffer(), cmd.argument());
1743 case LFUN_BUFFER_WRITE_ALL: {
1744 Buffer * first = theBufferList().first();
1747 message(_("Saving all documents..."));
1748 // We cannot use a for loop as the buffer list cycles.
1751 if (!b->isClean()) {
1753 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1755 b = theBufferList().next(b);
1756 } while (b != first);
1757 message(_("All documents saved."));
1761 case LFUN_TOOLBAR_TOGGLE: {
1762 string const name = cmd.getArg(0);
1763 bool const allowauto = cmd.getArg(1) == "allowauto";
1764 // it is possible to get current toolbar status like this,...
1765 // but I decide to obey the order of ToolbarBackend::flags
1766 // and disregard real toolbar status.
1767 // toolbars_->saveToolbarInfo();
1769 // toggle state on/off/auto
1770 d.toolbars_->toggleToolbarState(name, allowauto);
1774 ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
1776 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
1780 if (tbi->flags & ToolbarInfo::ON)
1782 else if (tbi->flags & ToolbarInfo::OFF)
1784 else if (tbi->flags & ToolbarInfo::AUTO)
1787 message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1788 _(tbi->gui_name), state));
1792 case LFUN_DIALOG_UPDATE: {
1793 string const name = to_utf8(cmd.argument());
1794 // Can only update a dialog connected to an existing inset
1795 Inset * inset = getOpenInset(name);
1797 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1798 inset->dispatch(view()->cursor(), fr);
1799 } else if (name == "paragraph") {
1800 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1801 } else if (name == "prefs") {
1802 updateDialog(name, string());
1807 case LFUN_DIALOG_TOGGLE: {
1808 if (isDialogVisible(cmd.getArg(0)))
1809 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1811 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1815 case LFUN_DIALOG_DISCONNECT_INSET:
1816 disconnectDialog(to_utf8(cmd.argument()));
1819 case LFUN_DIALOG_HIDE: {
1820 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1824 case LFUN_DIALOG_SHOW: {
1825 string const name = cmd.getArg(0);
1826 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1828 if (name == "character") {
1829 data = freefont2string();
1831 showDialog("character", data);
1832 } else if (name == "latexlog") {
1833 Buffer::LogType type;
1834 string const logfile = buffer()->logName(&type);
1836 case Buffer::latexlog:
1839 case Buffer::buildlog:
1843 data += Lexer::quoteString(logfile);
1844 showDialog("log", data);
1845 } else if (name == "vclog") {
1846 string const data = "vc " +
1847 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1848 showDialog("log", data);
1849 } else if (name == "symbols") {
1850 data = bv->cursor().getEncoding()->name();
1852 showDialog("symbols", data);
1854 showDialog(name, data);
1858 case LFUN_INSET_APPLY: {
1859 view()->cursor().recordUndoFullDocument();
1860 string const name = cmd.getArg(0);
1861 Inset * inset = getOpenInset(name);
1863 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1864 inset->dispatch(view()->cursor(), fr);
1866 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1872 case LFUN_UI_TOGGLE:
1874 // Make sure the keyboard focus stays in the work area.
1878 case LFUN_COMPLETION_INLINE:
1879 if (d.current_work_area_)
1880 d.current_work_area_->completer().showInline();
1883 case LFUN_SPLIT_VIEW:
1884 if (Buffer * buf = buffer()) {
1885 string const orientation = cmd.getArg(0);
1886 d.splitter_->setOrientation(orientation == "vertical"
1887 ? Qt::Vertical : Qt::Horizontal);
1888 TabWorkArea * twa = addTabWorkArea();
1889 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1890 setCurrentWorkArea(wa);
1894 case LFUN_CLOSE_TAB_GROUP:
1895 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1897 twa = d.currentTabWorkArea();
1898 // Switch to the next GuiWorkArea in the found TabWorkArea.
1899 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1900 if (d.splitter_->count() == 0)
1901 // No more work area, switch to the background widget.
1906 case LFUN_COMPLETION_POPUP:
1907 if (d.current_work_area_)
1908 d.current_work_area_->completer().showPopup();
1912 case LFUN_COMPLETION_COMPLETE:
1913 if (d.current_work_area_)
1914 d.current_work_area_->completer().tab();
1922 if (isFullScreen()) {
1923 if (menuBar()->isVisible())
1925 if (statusBar()->isVisible())
1926 statusBar()->hide();
1933 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1935 string const arg = cmd.getArg(0);
1936 if (arg == "scrollbar") {
1937 // hide() is of no help
1938 if (d.current_work_area_->verticalScrollBarPolicy() ==
1939 Qt::ScrollBarAlwaysOff)
1941 d.current_work_area_->setVerticalScrollBarPolicy(
1942 Qt::ScrollBarAsNeeded);
1944 d.current_work_area_->setVerticalScrollBarPolicy(
1945 Qt::ScrollBarAlwaysOff);
1948 if (arg == "statusbar") {
1949 statusBar()->setVisible(!statusBar()->isVisible());
1952 if (arg == "menubar") {
1953 menuBar()->setVisible(!menuBar()->isVisible());
1956 #if QT_VERSION >= 0x040300
1957 if (arg == "frame") {
1959 getContentsMargins(&l, &t, &r, &b);
1960 //are the frames in default state?
1961 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1963 setContentsMargins(-2, -2, -2, -2);
1965 setContentsMargins(0, 0, 0, 0);
1970 if (arg != "fullscreen") {
1971 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1975 if (lyxrc.full_screen_toolbars)
1976 d.toolbars_->toggleFullScreen(!isFullScreen());
1978 if (isFullScreen()) {
1979 for (int i = 0; i != d.splitter_->count(); ++i)
1980 d.tabWorkArea(i)->setFullScreen(false);
1981 #if QT_VERSION >= 0x040300
1982 setContentsMargins(0, 0, 0, 0);
1984 setWindowState(windowState() ^ Qt::WindowFullScreen);
1986 statusBar()->show();
1988 for (int i = 0; i != d.splitter_->count(); ++i)
1989 d.tabWorkArea(i)->setFullScreen(true);
1990 #if QT_VERSION >= 0x040300
1991 setContentsMargins(-2, -2, -2, -2);
1993 setWindowState(windowState() ^ Qt::WindowFullScreen);
1994 statusBar()->hide();
2000 Buffer const * GuiView::updateInset(Inset const * inset)
2002 if (!d.current_work_area_)
2006 d.current_work_area_->scheduleRedraw();
2008 return &d.current_work_area_->bufferView().buffer();
2012 void GuiView::restartCursor()
2014 /* When we move around, or type, it's nice to be able to see
2015 * the cursor immediately after the keypress.
2017 if (d.current_work_area_)
2018 d.current_work_area_->startBlinkingCursor();
2020 // Take this occasion to update the other GUI elements.
2025 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2027 if (d.current_work_area_)
2028 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2033 // This list should be kept in sync with the list of insets in
2034 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2035 // dialog should have the same name as the inset.
2037 char const * const dialognames[] = {
2038 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2039 "citation", "document", "errorlist", "ert", "external", "file",
2040 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2041 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2042 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2044 #ifdef HAVE_LIBAIKSAURUS
2048 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2050 char const * const * const end_dialognames =
2051 dialognames + (sizeof(dialognames) / sizeof(char *));
2055 cmpCStr(char const * name) : name_(name) {}
2056 bool operator()(char const * other) {
2057 return strcmp(other, name_) == 0;
2064 bool isValidName(string const & name)
2066 return find_if(dialognames, end_dialognames,
2067 cmpCStr(name.c_str())) != end_dialognames;
2073 void GuiView::resetDialogs()
2075 // Make sure that no LFUN uses any LyXView.
2076 theLyXFunc().setLyXView(0);
2077 // FIXME: the "math panels" toolbar takes an awful lot of time to
2078 // initialise so we don't do that for the time being.
2079 //d.toolbars_->init();
2080 guiApp->menus().fillMenuBar(menuBar(), this);
2082 d.layout_->updateContents(true);
2083 // Now update controls with current buffer.
2084 theLyXFunc().setLyXView(this);
2089 Dialog * GuiView::find_or_build(string const & name)
2091 if (!isValidName(name))
2094 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2096 if (it != d.dialogs_.end())
2097 return it->second.get();
2099 Dialog * dialog = build(name);
2100 d.dialogs_[name].reset(dialog);
2101 if (lyxrc.allow_geometry_session)
2102 dialog->restoreSession();
2107 void GuiView::showDialog(string const & name, string const & data,
2114 Dialog * dialog = find_or_build(name);
2116 dialog->showData(data);
2118 d.open_insets_[name] = inset;
2124 bool GuiView::isDialogVisible(string const & name) const
2126 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2127 if (it == d.dialogs_.end())
2129 return it->second.get()->isVisibleView();
2133 void GuiView::hideDialog(string const & name, Inset * inset)
2135 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2136 if (it == d.dialogs_.end())
2139 if (inset && inset != getOpenInset(name))
2142 Dialog * const dialog = it->second.get();
2143 if (dialog->isVisibleView())
2145 d.open_insets_[name] = 0;
2149 void GuiView::disconnectDialog(string const & name)
2151 if (!isValidName(name))
2154 if (d.open_insets_.find(name) != d.open_insets_.end())
2155 d.open_insets_[name] = 0;
2159 Inset * GuiView::getOpenInset(string const & name) const
2161 if (!isValidName(name))
2164 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2165 return it == d.open_insets_.end() ? 0 : it->second;
2169 void GuiView::hideAll() const
2171 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2172 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2174 for(; it != end; ++it)
2175 it->second->hideView();
2179 void GuiView::updateDialogs()
2181 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2182 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2184 for(; it != end; ++it) {
2185 Dialog * dialog = it->second.get();
2186 if (dialog && dialog->isVisibleView())
2187 dialog->checkStatus();
2195 // will be replaced by a proper factory...
2196 Dialog * createGuiAbout(GuiView & lv);
2197 Dialog * createGuiBibitem(GuiView & lv);
2198 Dialog * createGuiBibtex(GuiView & lv);
2199 Dialog * createGuiBox(GuiView & lv);
2200 Dialog * createGuiBranch(GuiView & lv);
2201 Dialog * createGuiChanges(GuiView & lv);
2202 Dialog * createGuiCharacter(GuiView & lv);
2203 Dialog * createGuiCitation(GuiView & lv);
2204 Dialog * createGuiDelimiter(GuiView & lv);
2205 Dialog * createGuiDocument(GuiView & lv);
2206 Dialog * createGuiErrorList(GuiView & lv);
2207 Dialog * createGuiERT(GuiView & lv);
2208 Dialog * createGuiExternal(GuiView & lv);
2209 Dialog * createGuiFloat(GuiView & lv);
2210 Dialog * createGuiGraphics(GuiView & lv);
2211 Dialog * createGuiHSpace(GuiView & lv);
2212 Dialog * createGuiInclude(GuiView & lv);
2213 Dialog * createGuiLabel(GuiView & lv);
2214 Dialog * createGuiListings(GuiView & lv);
2215 Dialog * createGuiLog(GuiView & lv);
2216 Dialog * createGuiMathMatrix(GuiView & lv);
2217 Dialog * createGuiNomenclature(GuiView & lv);
2218 Dialog * createGuiNote(GuiView & lv);
2219 Dialog * createGuiParagraph(GuiView & lv);
2220 Dialog * createGuiPreferences(GuiView & lv);
2221 Dialog * createGuiPrint(GuiView & lv);
2222 Dialog * createGuiRef(GuiView & lv);
2223 Dialog * createGuiSearch(GuiView & lv);
2224 Dialog * createGuiSendTo(GuiView & lv);
2225 Dialog * createGuiShowFile(GuiView & lv);
2226 Dialog * createGuiSpellchecker(GuiView & lv);
2227 Dialog * createGuiSymbols(GuiView & lv);
2228 Dialog * createGuiTabularCreate(GuiView & lv);
2229 Dialog * createGuiTabular(GuiView & lv);
2230 Dialog * createGuiTexInfo(GuiView & lv);
2231 Dialog * createGuiToc(GuiView & lv);
2232 Dialog * createGuiThesaurus(GuiView & lv);
2233 Dialog * createGuiHyperlink(GuiView & lv);
2234 Dialog * createGuiVSpace(GuiView & lv);
2235 Dialog * createGuiViewSource(GuiView & lv);
2236 Dialog * createGuiWrap(GuiView & lv);
2239 Dialog * GuiView::build(string const & name)
2241 LASSERT(isValidName(name), /**/);
2243 if (name == "aboutlyx")
2244 return createGuiAbout(*this);
2245 if (name == "bibitem")
2246 return createGuiBibitem(*this);
2247 if (name == "bibtex")
2248 return createGuiBibtex(*this);
2250 return createGuiBox(*this);
2251 if (name == "branch")
2252 return createGuiBranch(*this);
2253 if (name == "changes")
2254 return createGuiChanges(*this);
2255 if (name == "character")
2256 return createGuiCharacter(*this);
2257 if (name == "citation")
2258 return createGuiCitation(*this);
2259 if (name == "document")
2260 return createGuiDocument(*this);
2261 if (name == "errorlist")
2262 return createGuiErrorList(*this);
2264 return createGuiERT(*this);
2265 if (name == "external")
2266 return createGuiExternal(*this);
2268 return createGuiShowFile(*this);
2269 if (name == "findreplace")
2270 return createGuiSearch(*this);
2271 if (name == "float")
2272 return createGuiFloat(*this);
2273 if (name == "graphics")
2274 return createGuiGraphics(*this);
2275 if (name == "include")
2276 return createGuiInclude(*this);
2277 if (name == "nomenclature")
2278 return createGuiNomenclature(*this);
2279 if (name == "label")
2280 return createGuiLabel(*this);
2282 return createGuiLog(*this);
2283 if (name == "view-source")
2284 return createGuiViewSource(*this);
2285 if (name == "mathdelimiter")
2286 return createGuiDelimiter(*this);
2287 if (name == "mathmatrix")
2288 return createGuiMathMatrix(*this);
2290 return createGuiNote(*this);
2291 if (name == "paragraph")
2292 return createGuiParagraph(*this);
2293 if (name == "prefs")
2294 return createGuiPreferences(*this);
2295 if (name == "print")
2296 return createGuiPrint(*this);
2298 return createGuiRef(*this);
2299 if (name == "sendto")
2300 return createGuiSendTo(*this);
2301 if (name == "space")
2302 return createGuiHSpace(*this);
2303 if (name == "spellchecker")
2304 return createGuiSpellchecker(*this);
2305 if (name == "symbols")
2306 return createGuiSymbols(*this);
2307 if (name == "tabular")
2308 return createGuiTabular(*this);
2309 if (name == "tabularcreate")
2310 return createGuiTabularCreate(*this);
2311 if (name == "texinfo")
2312 return createGuiTexInfo(*this);
2313 #ifdef HAVE_LIBAIKSAURUS
2314 if (name == "thesaurus")
2315 return createGuiThesaurus(*this);
2318 return createGuiToc(*this);
2320 return createGuiHyperlink(*this);
2321 if (name == "vspace")
2322 return createGuiVSpace(*this);
2324 return createGuiWrap(*this);
2325 if (name == "listings")
2326 return createGuiListings(*this);
2332 } // namespace frontend
2335 #include "GuiView_moc.cpp"