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"
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_);
144 /// Toolbar store providing access to individual toolbars by name.
145 typedef std::map<std::string, GuiToolbar *> ToolbarMap;
147 typedef boost::shared_ptr<Dialog> DialogPtr;
152 struct GuiView::GuiViewPrivate
155 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
158 // hardcode here the platform specific icon size
159 smallIconSize = 14; // scaling problems
160 normalIconSize = 20; // ok, default
161 bigIconSize = 26; // better for some math icons
163 splitter_ = new QSplitter;
164 bg_widget_ = new BackgroundWidget;
165 stack_widget_ = new QStackedWidget;
166 stack_widget_->addWidget(bg_widget_);
167 stack_widget_->addWidget(splitter_);
175 delete stack_widget_;
178 QMenu * toolBarPopup(GuiView * parent)
180 // FIXME: translation
181 QMenu * menu = new QMenu(parent);
182 QActionGroup * iconSizeGroup = new QActionGroup(parent);
184 QAction * smallIcons = new QAction(iconSizeGroup);
185 smallIcons->setText(qt_("Small-sized icons"));
186 smallIcons->setCheckable(true);
187 QObject::connect(smallIcons, SIGNAL(triggered()),
188 parent, SLOT(smallSizedIcons()));
189 menu->addAction(smallIcons);
191 QAction * normalIcons = new QAction(iconSizeGroup);
192 normalIcons->setText(qt_("Normal-sized icons"));
193 normalIcons->setCheckable(true);
194 QObject::connect(normalIcons, SIGNAL(triggered()),
195 parent, SLOT(normalSizedIcons()));
196 menu->addAction(normalIcons);
198 QAction * bigIcons = new QAction(iconSizeGroup);
199 bigIcons->setText(qt_("Big-sized icons"));
200 bigIcons->setCheckable(true);
201 QObject::connect(bigIcons, SIGNAL(triggered()),
202 parent, SLOT(bigSizedIcons()));
203 menu->addAction(bigIcons);
205 unsigned int cur = parent->iconSize().width();
206 if ( cur == parent->d.smallIconSize)
207 smallIcons->setChecked(true);
208 else if (cur == parent->d.normalIconSize)
209 normalIcons->setChecked(true);
210 else if (cur == parent->d.bigIconSize)
211 bigIcons->setChecked(true);
218 stack_widget_->setCurrentWidget(bg_widget_);
219 bg_widget_->setUpdatesEnabled(true);
222 TabWorkArea * tabWorkArea(int i)
224 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
227 TabWorkArea * currentTabWorkArea()
229 if (splitter_->count() == 1)
230 // The first TabWorkArea is always the first one, if any.
231 return tabWorkArea(0);
233 for (int i = 0; i != splitter_->count(); ++i) {
234 TabWorkArea * twa = tabWorkArea(i);
235 if (current_work_area_ == twa->currentWorkArea())
239 // None has the focus so we just take the first one.
240 return tabWorkArea(0);
244 GuiWorkArea * current_work_area_;
245 QSplitter * splitter_;
246 QStackedWidget * stack_widget_;
247 BackgroundWidget * bg_widget_;
249 ToolbarMap toolbars_;
250 /// The main layout box.
252 * \warning Don't Delete! The layout box is actually owned by
253 * whichever toolbar contains it. All the GuiView class needs is a
254 * means of accessing it.
256 * FIXME: replace that with a proper model so that we are not limited
257 * to only one dialog.
259 GuiLayoutBox * layout_;
262 map<string, Inset *> open_insets_;
265 map<string, DialogPtr> dialogs_;
267 unsigned int smallIconSize;
268 unsigned int normalIconSize;
269 unsigned int bigIconSize;
271 QTimer statusbar_timer_;
272 /// auto-saving of buffers
273 Timeout autosave_timeout_;
274 /// flag against a race condition due to multiclicks, see bug #1119
278 TocModels toc_models_;
282 GuiView::GuiView(int id)
283 : d(*new GuiViewPrivate), id_(id)
285 // GuiToolbars *must* be initialised before the menu bar.
288 // set ourself as the current view. This is needed for the menu bar
289 // filling, at least for the static special menu item on Mac. Otherwise
290 // they are greyed out.
291 theLyXFunc().setLyXView(this);
293 // Fill up the menu bar.
294 guiApp->menus().fillMenuBar(menuBar(), this, true);
296 setCentralWidget(d.stack_widget_);
298 // Start autosave timer
299 if (lyxrc.autosave) {
300 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
301 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
302 d.autosave_timeout_.start();
304 connect(&d.statusbar_timer_, SIGNAL(timeout()),
305 this, SLOT(clearMessage()));
307 // We don't want to keep the window in memory if it is closed.
308 setAttribute(Qt::WA_DeleteOnClose, true);
310 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
311 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
312 // since the icon is provided in the application bundle.
313 setWindowIcon(QPixmap(":/images/lyx.png"));
317 setAcceptDrops(true);
319 statusBar()->setSizeGripEnabled(true);
321 // Forbid too small unresizable window because it can happen
322 // with some window manager under X11.
323 setMinimumSize(300, 200);
325 // Now take care of session management.
328 if (!lyxrc.allow_geometry_session) {
329 // No session handling, default to a sane size.
330 setGeometry(50, 50, 690, 510);
336 QString const key = "view-" + QString::number(id_);
338 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
339 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
343 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
344 setGeometry(50, 50, 690, 510);
346 if (!restoreState(settings.value(key + "/layout").toByteArray(), 0))
349 setIconSize(settings.value(key + "/icon_size").toSize());
359 GuiToolbar * GuiView::toolbar(string const & name)
361 ToolbarMap::iterator it = d.toolbars_.find(name);
362 if (it != d.toolbars_.end())
365 LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
366 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
371 void GuiView::constructToolbars()
373 ToolbarMap::iterator it = d.toolbars_.begin();
374 for (; it != d.toolbars_.end(); ++it)
378 // extracts the toolbars from the backend
379 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
380 Toolbars::Infos::iterator end = guiApp->toolbars().end();
381 for (; cit != end; ++cit)
382 d.toolbars_[cit->name] = new GuiToolbar(*cit, *this);
386 void GuiView::initToolbars()
388 // extracts the toolbars from the backend
389 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
390 Toolbars::Infos::iterator end = guiApp->toolbars().end();
391 for (; cit != end; ++cit) {
392 GuiToolbar * tb = toolbar(cit->name);
395 int const visibility = guiApp->toolbars().defaultVisibility(cit->name);
397 tb->setVisible(false);
398 tb->setVisibility(visibility);
400 if (visibility & Toolbars::TOP) {
402 addToolBarBreak(Qt::TopToolBarArea);
403 addToolBar(Qt::TopToolBarArea, tb);
406 if (visibility & Toolbars::BOTTOM) {
407 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
408 #if (QT_VERSION >= 0x040202)
409 addToolBarBreak(Qt::BottomToolBarArea);
411 addToolBar(Qt::BottomToolBarArea, tb);
414 if (visibility & Toolbars::LEFT) {
415 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
416 #if (QT_VERSION >= 0x040202)
417 addToolBarBreak(Qt::LeftToolBarArea);
419 addToolBar(Qt::LeftToolBarArea, tb);
422 if (visibility & Toolbars::RIGHT) {
423 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
424 #if (QT_VERSION >= 0x040202)
425 addToolBarBreak(Qt::RightToolBarArea);
427 addToolBar(Qt::RightToolBarArea, tb);
430 if (visibility & Toolbars::ON)
431 tb->setVisible(true);
436 TocModels & GuiView::tocModels()
438 return d.toc_models_;
442 void GuiView::setFocus()
444 if (d.current_work_area_)
445 d.current_work_area_->setFocus();
451 QMenu * GuiView::createPopupMenu()
453 return d.toolBarPopup(this);
457 void GuiView::showEvent(QShowEvent * e)
459 LYXERR(Debug::GUI, "Passed Geometry "
460 << size().height() << "x" << size().width()
461 << "+" << pos().x() << "+" << pos().y());
463 if (d.splitter_->count() == 0)
464 // No work area, switch to the background widget.
467 QMainWindow::showEvent(e);
471 void GuiView::closeEvent(QCloseEvent * close_event)
473 // it can happen that this event arrives without selecting the view,
474 // e.g. when clicking the close button on a background window.
475 theLyXFunc().setLyXView(this);
477 while (Buffer * b = buffer()) {
479 // This is a child document, just close the tab after saving
480 // but keep the file loaded.
481 if (!saveBuffer(*b)) {
482 close_event->ignore();
485 removeWorkArea(d.current_work_area_);
489 QList<int> const ids = guiApp->viewIds();
490 for (int i = 0; i != ids.size(); ++i) {
493 if (guiApp->view(ids[i]).workArea(*b)) {
494 // FIXME 1: should we put an alert box here that the buffer
495 // is viewed elsewhere?
496 // FIXME 2: should we try to save this buffer in any case?
499 // This buffer is also opened in another view, so
500 // but close the associated work area nevertheless.
501 removeWorkArea(d.current_work_area_);
502 // but don't close it.
507 if (b && !closeBuffer(*b, true)) {
508 close_event->ignore();
513 // Make sure that nothing will use this close to be closed View.
514 guiApp->unregisterView(this);
516 // Save toolbars configuration
517 if (isFullScreen()) {
518 // d.toolbars_->toggleFullScreen(!isFullScreen());
522 // Make sure the timer time out will not trigger a statusbar update.
523 d.statusbar_timer_.stop();
525 // Saving fullscreen requires additional tweaks in the toolbar code.
526 // It wouldn't also work under linux natively.
527 if (lyxrc.allow_geometry_session && !isFullScreen()) {
529 QString const key = "view-" + QString::number(id_);
531 settings.setValue(key + "/pos", pos());
532 settings.setValue(key + "/size", size());
534 settings.setValue(key + "/geometry", saveGeometry());
536 settings.setValue(key + "/icon_size", iconSize());
537 settings.setValue(key + "/layout", saveState(0));
539 ToolbarMap::iterator end = d.toolbars_.end();
540 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
541 it->second->saveSession();
542 // Now take care of all other dialogs:
543 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
544 for (; it!= d.dialogs_.end(); ++it)
545 it->second->saveSession();
548 close_event->accept();
552 void GuiView::dragEnterEvent(QDragEnterEvent * event)
554 if (event->mimeData()->hasUrls())
556 /// \todo Ask lyx-devel is this is enough:
557 /// if (event->mimeData()->hasFormat("text/plain"))
558 /// event->acceptProposedAction();
562 void GuiView::dropEvent(QDropEvent* event)
564 QList<QUrl> files = event->mimeData()->urls();
568 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
569 for (int i = 0; i != files.size(); ++i) {
570 string const file = os::internal_path(fromqstr(
571 files.at(i).toLocalFile()));
573 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
578 void GuiView::message(docstring const & str)
580 if (ForkedProcess::iAmAChild())
583 statusBar()->showMessage(toqstr(str));
584 d.statusbar_timer_.stop();
585 d.statusbar_timer_.start(3000);
589 void GuiView::smallSizedIcons()
591 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
595 void GuiView::normalSizedIcons()
597 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
601 void GuiView::bigSizedIcons()
603 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
607 void GuiView::clearMessage()
611 theLyXFunc().setLyXView(this);
612 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
613 d.statusbar_timer_.stop();
617 void GuiView::updateWindowTitle(GuiWorkArea * wa)
619 if (wa != d.current_work_area_)
621 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
622 setWindowIconText(wa->windowIconText());
626 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
629 disconnectBufferView();
630 connectBufferView(wa->bufferView());
631 connectBuffer(wa->bufferView().buffer());
632 d.current_work_area_ = wa;
633 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
634 this, SLOT(updateWindowTitle(GuiWorkArea *)));
635 updateWindowTitle(wa);
639 // The document settings needs to be reinitialised.
640 updateDialog("document", "");
642 // Buffer-dependent dialogs must be updated. This is done here because
643 // some dialogs require buffer()->text.
648 void GuiView::on_lastWorkAreaRemoved()
651 // On Mac close the view if there is no Tab open anymore,
652 // but only if no splitter is visible
653 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
654 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
655 if (twa && twa->count() == 0) {
656 // close the view, as no tab is open anymore
657 QTimer::singleShot(0, this, SLOT(close()));
662 // The document settings needs to be reinitialised.
663 updateDialog("document", "");
669 void GuiView::updateStatusBar()
671 // let the user see the explicit message
672 if (d.statusbar_timer_.isActive())
675 theLyXFunc().setLyXView(this);
676 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
680 bool GuiView::hasFocus() const
682 return qApp->activeWindow() == this;
686 bool GuiView::event(QEvent * e)
690 // Useful debug code:
691 //case QEvent::ActivationChange:
692 //case QEvent::WindowDeactivate:
693 //case QEvent::Paint:
694 //case QEvent::Enter:
695 //case QEvent::Leave:
696 //case QEvent::HoverEnter:
697 //case QEvent::HoverLeave:
698 //case QEvent::HoverMove:
699 //case QEvent::StatusTip:
700 //case QEvent::DragEnter:
701 //case QEvent::DragLeave:
705 case QEvent::WindowActivate: {
706 if (this == guiApp->currentView()) {
708 return QMainWindow::event(e);
710 guiApp->setCurrentView(this);
711 if (d.current_work_area_) {
712 BufferView & bv = d.current_work_area_->bufferView();
713 connectBufferView(bv);
714 connectBuffer(bv.buffer());
715 // The document structure, name and dialogs might have
716 // changed in another view.
718 // The document settings needs to be reinitialised.
719 updateDialog("document", "");
722 setWindowTitle(qt_("LyX"));
723 setWindowIconText(qt_("LyX"));
726 return QMainWindow::event(e);
729 case QEvent::ShortcutOverride: {
731 if (isFullScreen() && menuBar()->isHidden()) {
732 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
733 // FIXME: we should also try to detect special LyX shortcut such as
734 // Alt-P and Alt-M. Right now there is a hack in
735 // GuiWorkArea::processKeySym() that hides again the menubar for
737 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt)
739 return QMainWindow::event(e);
742 if (d.current_work_area_)
743 // Nothing special to do.
744 return QMainWindow::event(e);
746 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
747 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
749 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
750 || ke->key() == Qt::Key_Backtab)
751 return QMainWindow::event(e);
753 // Allow processing of shortcuts that are allowed even when no Buffer
755 theLyXFunc().setLyXView(this);
757 setKeySymbol(&sym, ke);
758 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
764 return QMainWindow::event(e);
769 bool GuiView::focusNextPrevChild(bool /*next*/)
776 void GuiView::setBusy(bool busy)
778 if (d.current_work_area_) {
779 d.current_work_area_->setUpdatesEnabled(!busy);
781 d.current_work_area_->stopBlinkingCursor();
783 d.current_work_area_->startBlinkingCursor();
787 QApplication::setOverrideCursor(Qt::WaitCursor);
789 QApplication::restoreOverrideCursor();
793 GuiWorkArea * GuiView::workArea(Buffer & buffer)
795 if (TabWorkArea * twa = d.currentTabWorkArea())
796 return twa->workArea(buffer);
801 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
803 // Automatically create a TabWorkArea if there are none yet.
804 TabWorkArea * tab_widget = d.splitter_->count()
805 ? d.currentTabWorkArea() : addTabWorkArea();
806 return tab_widget->addWorkArea(buffer, *this);
810 TabWorkArea * GuiView::addTabWorkArea()
812 TabWorkArea * twa = new TabWorkArea;
813 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
814 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
815 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
816 this, SLOT(on_lastWorkAreaRemoved()));
818 d.splitter_->addWidget(twa);
819 d.stack_widget_->setCurrentWidget(d.splitter_);
824 GuiWorkArea const * GuiView::currentWorkArea() const
826 return d.current_work_area_;
830 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
833 d.current_work_area_ = wa;
834 for (int i = 0; i != d.splitter_->count(); ++i) {
835 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
841 void GuiView::removeWorkArea(GuiWorkArea * wa)
844 if (wa == d.current_work_area_) {
846 disconnectBufferView();
847 d.current_work_area_ = 0;
850 for (int i = 0; i != d.splitter_->count(); ++i) {
851 TabWorkArea * twa = d.tabWorkArea(i);
852 if (!twa->removeWorkArea(wa))
853 // Not found in this tab group.
856 // We found and removed the GuiWorkArea.
858 // No more WorkAreas in this tab group, so delete it.
863 if (d.current_work_area_)
864 // This means that we are not closing the current GuiWorkArea;
867 // Switch to the next GuiWorkArea in the found TabWorkArea.
868 d.current_work_area_ = twa->currentWorkArea();
872 if (d.splitter_->count() == 0)
873 // No more work area, switch to the background widget.
878 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
884 void GuiView::updateLayoutList()
887 d.layout_->updateContents(false);
891 void GuiView::updateToolbars()
893 ToolbarMap::iterator end = d.toolbars_.end();
894 if (d.current_work_area_) {
896 d.current_work_area_->bufferView().cursor().inMathed();
898 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
900 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
901 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
902 bool const mathmacrotemplate =
903 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
905 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
906 it->second->update(math, table, review, mathmacrotemplate);
908 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
909 it->second->update(false, false, false, false);
913 Buffer * GuiView::buffer()
915 if (d.current_work_area_)
916 return &d.current_work_area_->bufferView().buffer();
921 Buffer const * GuiView::buffer() const
923 if (d.current_work_area_)
924 return &d.current_work_area_->bufferView().buffer();
929 void GuiView::setBuffer(Buffer * newBuffer)
931 LASSERT(newBuffer, /**/);
934 GuiWorkArea * wa = workArea(*newBuffer);
936 updateLabels(*newBuffer->masterBuffer());
937 wa = addWorkArea(*newBuffer);
939 //Disconnect the old buffer...there's no new one.
942 connectBuffer(*newBuffer);
943 connectBufferView(wa->bufferView());
944 setCurrentWorkArea(wa);
950 void GuiView::connectBuffer(Buffer & buf)
952 buf.setGuiDelegate(this);
956 void GuiView::disconnectBuffer()
958 if (d.current_work_area_)
959 d.current_work_area_->bufferView().setGuiDelegate(0);
963 void GuiView::connectBufferView(BufferView & bv)
965 bv.setGuiDelegate(this);
969 void GuiView::disconnectBufferView()
971 if (d.current_work_area_)
972 d.current_work_area_->bufferView().setGuiDelegate(0);
976 void GuiView::errors(string const & error_type)
978 ErrorList & el = buffer()->errorList(error_type);
980 showDialog("errorlist", error_type);
984 void GuiView::structureChanged()
986 d.toc_models_.reset(view());
987 // Navigator needs more than a simple update in this case. It needs to be
989 updateDialog("toc", "");
993 void GuiView::updateDialog(string const & name, string const & data)
995 if (!isDialogVisible(name))
998 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
999 if (it == d.dialogs_.end())
1002 Dialog * const dialog = it->second.get();
1003 if (dialog->isVisibleView())
1004 dialog->initialiseParams(data);
1008 BufferView * GuiView::view()
1010 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1014 void GuiView::autoSave()
1016 LYXERR(Debug::INFO, "Running autoSave()");
1019 view()->buffer().autoSave();
1023 void GuiView::resetAutosaveTimers()
1026 d.autosave_timeout_.restart();
1030 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1033 Buffer * buf = buffer();
1035 /* In LyX/Mac, when a dialog is open, the menus of the
1036 application can still be accessed without giving focus to
1037 the main window. In this case, we want to disable the menu
1038 entries that are buffer-related.
1040 Note that this code is not perfect, as bug 1941 attests:
1041 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1043 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1046 switch(cmd.action) {
1047 case LFUN_BUFFER_WRITE:
1048 enable = buf && (buf->isUnnamed() || !buf->isClean());
1051 case LFUN_BUFFER_WRITE_AS:
1055 case LFUN_SPLIT_VIEW:
1059 case LFUN_CLOSE_TAB_GROUP:
1060 enable = d.currentTabWorkArea();
1063 case LFUN_TOOLBAR_TOGGLE:
1064 if (GuiToolbar * t = toolbar(cmd.getArg(0)))
1065 flag.setOnOff(t->isVisible());
1068 case LFUN_UI_TOGGLE:
1069 flag.setOnOff(isFullScreen());
1072 case LFUN_DIALOG_TOGGLE:
1073 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1074 // fall through to set "enable"
1075 case LFUN_DIALOG_SHOW: {
1076 string const name = cmd.getArg(0);
1078 enable = name == "aboutlyx"
1079 || name == "file" //FIXME: should be removed.
1081 || name == "texinfo";
1082 else if (name == "print")
1083 enable = buf->isExportable("dvi")
1084 && lyxrc.print_command != "none";
1085 else if (name == "character") {
1089 InsetCode ic = view()->cursor().inset().lyxCode();
1090 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1093 else if (name == "symbols") {
1094 if (!view() || view()->cursor().inMathed())
1097 InsetCode ic = view()->cursor().inset().lyxCode();
1098 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1101 else if (name == "latexlog")
1102 enable = FileName(buf->logName()).isReadableFile();
1103 else if (name == "spellchecker")
1104 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1105 enable = !buf->isReadonly();
1109 else if (name == "vclog")
1110 enable = buf->lyxvc().inUse();
1114 case LFUN_DIALOG_UPDATE: {
1115 string const name = cmd.getArg(0);
1117 enable = name == "prefs";
1121 case LFUN_INSET_APPLY: {
1122 string const name = cmd.getArg(0);
1123 Inset * inset = getOpenInset(name);
1125 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1127 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1128 // Every inset is supposed to handle this
1129 LASSERT(false, /**/);
1133 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1134 flag |= lyx::getStatus(fr);
1136 enable = flag.enabled();
1140 case LFUN_COMPLETION_INLINE:
1141 if (!d.current_work_area_
1142 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1146 case LFUN_COMPLETION_POPUP:
1147 if (!d.current_work_area_
1148 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1152 case LFUN_COMPLETION_COMPLETE:
1153 if (!d.current_work_area_
1154 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1163 flag.enabled(false);
1169 static FileName selectTemplateFile()
1171 FileDialog dlg(qt_("Select template file"));
1172 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1173 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1175 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1176 QStringList(qt_("LyX Documents (*.lyx)")));
1178 if (result.first == FileDialog::Later)
1180 if (result.second.isEmpty())
1182 return FileName(fromqstr(result.second));
1186 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1190 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1193 message(_("Document not loaded."));
1198 setBuffer(newBuffer);
1200 // scroll to the position when the file was last closed
1201 if (lyxrc.use_lastfilepos) {
1202 LastFilePosSection::FilePos filepos =
1203 LyX::ref().session().lastFilePos().load(filename);
1204 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1208 LyX::ref().session().lastFiles().add(filename);
1215 void GuiView::openDocument(string const & fname)
1217 string initpath = lyxrc.document_path;
1220 string const trypath = buffer()->filePath();
1221 // If directory is writeable, use this as default.
1222 if (FileName(trypath).isDirWritable())
1228 if (fname.empty()) {
1229 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1230 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1231 dlg.setButton2(qt_("Examples|#E#e"),
1232 toqstr(addPath(package().system_support().absFilename(), "examples")));
1234 FileDialog::Result result =
1235 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1237 if (result.first == FileDialog::Later)
1240 filename = fromqstr(result.second);
1242 // check selected filename
1243 if (filename.empty()) {
1244 message(_("Canceled."));
1250 // get absolute path of file and add ".lyx" to the filename if
1252 FileName const fullname =
1253 fileSearch(string(), filename, "lyx", support::may_not_exist);
1254 if (!fullname.empty())
1255 filename = fullname.absFilename();
1257 // if the file doesn't exist, let the user create one
1258 if (!fullname.exists()) {
1259 // the user specifically chose this name. Believe him.
1260 Buffer * const b = newFile(filename, string(), true);
1266 docstring const disp_fn = makeDisplayPath(filename);
1267 message(bformat(_("Opening document %1$s..."), disp_fn));
1270 Buffer * buf = loadDocument(fullname);
1275 buf->errors("Parse");
1276 str2 = bformat(_("Document %1$s opened."), disp_fn);
1278 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1283 // FIXME: clean that
1284 static bool import(GuiView * lv, FileName const & filename,
1285 string const & format, ErrorList & errorList)
1287 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1289 string loader_format;
1290 vector<string> loaders = theConverters().loaders();
1291 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1292 for (vector<string>::const_iterator it = loaders.begin();
1293 it != loaders.end(); ++it) {
1294 if (!theConverters().isReachable(format, *it))
1297 string const tofile =
1298 support::changeExtension(filename.absFilename(),
1299 formats.extension(*it));
1300 if (!theConverters().convert(0, filename, FileName(tofile),
1301 filename, format, *it, errorList))
1303 loader_format = *it;
1306 if (loader_format.empty()) {
1307 frontend::Alert::error(_("Couldn't import file"),
1308 bformat(_("No information for importing the format %1$s."),
1309 formats.prettyName(format)));
1313 loader_format = format;
1315 if (loader_format == "lyx") {
1316 Buffer * buf = lv->loadDocument(lyxfile);
1321 buf->errors("Parse");
1323 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1327 bool as_paragraphs = loader_format == "textparagraph";
1328 string filename2 = (loader_format == format) ? filename.absFilename()
1329 : support::changeExtension(filename.absFilename(),
1330 formats.extension(loader_format));
1331 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1332 theLyXFunc().setLyXView(lv);
1333 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1340 void GuiView::importDocument(string const & argument)
1343 string filename = split(argument, format, ' ');
1345 LYXERR(Debug::INFO, format << " file: " << filename);
1347 // need user interaction
1348 if (filename.empty()) {
1349 string initpath = lyxrc.document_path;
1351 Buffer const * buf = buffer();
1353 string const trypath = buf->filePath();
1354 // If directory is writeable, use this as default.
1355 if (FileName(trypath).isDirWritable())
1359 docstring const text = bformat(_("Select %1$s file to import"),
1360 formats.prettyName(format));
1362 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1363 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1364 dlg.setButton2(qt_("Examples|#E#e"),
1365 toqstr(addPath(package().system_support().absFilename(), "examples")));
1367 docstring filter = formats.prettyName(format);
1370 filter += from_utf8(formats.extension(format));
1373 FileDialog::Result result =
1374 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1376 if (result.first == FileDialog::Later)
1379 filename = fromqstr(result.second);
1381 // check selected filename
1382 if (filename.empty())
1383 message(_("Canceled."));
1386 if (filename.empty())
1389 // get absolute path of file
1390 FileName const fullname(support::makeAbsPath(filename));
1392 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1394 // Check if the document already is open
1395 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1398 if (!closeBuffer()) {
1399 message(_("Canceled."));
1404 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1406 // if the file exists already, and we didn't do
1407 // -i lyx thefile.lyx, warn
1408 if (lyxfile.exists() && fullname != lyxfile) {
1410 docstring text = bformat(_("The document %1$s already exists.\n\n"
1411 "Do you want to overwrite that document?"), displaypath);
1412 int const ret = Alert::prompt(_("Overwrite document?"),
1413 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1416 message(_("Canceled."));
1421 message(bformat(_("Importing %1$s..."), displaypath));
1422 ErrorList errorList;
1423 if (import(this, fullname, format, errorList))
1424 message(_("imported."));
1426 message(_("file not imported!"));
1428 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1432 void GuiView::newDocument(string const & filename, bool from_template)
1434 FileName initpath(lyxrc.document_path);
1435 Buffer * buf = buffer();
1437 FileName const trypath(buf->filePath());
1438 // If directory is writeable, use this as default.
1439 if (trypath.isDirWritable())
1443 string templatefile = from_template ?
1444 selectTemplateFile().absFilename() : string();
1446 if (filename.empty())
1447 b = newUnnamedFile(templatefile, initpath);
1449 b = newFile(filename, templatefile, true);
1453 // Ensure the cursor is correctly positionned on screen.
1454 view()->showCursor();
1458 void GuiView::insertLyXFile(docstring const & fname)
1460 BufferView * bv = view();
1465 FileName filename(to_utf8(fname));
1467 if (!filename.empty()) {
1468 bv->insertLyXFile(filename);
1472 // Launch a file browser
1474 string initpath = lyxrc.document_path;
1475 string const trypath = bv->buffer().filePath();
1476 // If directory is writeable, use this as default.
1477 if (FileName(trypath).isDirWritable())
1481 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1482 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1483 dlg.setButton2(qt_("Examples|#E#e"),
1484 toqstr(addPath(package().system_support().absFilename(),
1487 FileDialog::Result result = dlg.open(toqstr(initpath),
1488 QStringList(qt_("LyX Documents (*.lyx)")));
1490 if (result.first == FileDialog::Later)
1494 filename.set(fromqstr(result.second));
1496 // check selected filename
1497 if (filename.empty()) {
1498 // emit message signal.
1499 message(_("Canceled."));
1503 bv->insertLyXFile(filename);
1507 void GuiView::insertPlaintextFile(docstring const & fname,
1510 BufferView * bv = view();
1515 FileName filename(to_utf8(fname));
1517 if (!filename.empty()) {
1518 bv->insertPlaintextFile(filename, asParagraph);
1522 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1523 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1525 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1528 if (result.first == FileDialog::Later)
1532 filename.set(fromqstr(result.second));
1534 // check selected filename
1535 if (filename.empty()) {
1536 // emit message signal.
1537 message(_("Canceled."));
1541 bv->insertPlaintextFile(filename, asParagraph);
1545 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1547 FileName fname = b.fileName();
1548 FileName const oldname = fname;
1550 if (!newname.empty()) {
1552 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1554 // Switch to this Buffer.
1557 /// No argument? Ask user through dialog.
1559 FileDialog dlg(qt_("Choose a filename to save document as"),
1560 LFUN_BUFFER_WRITE_AS);
1561 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1562 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1564 if (!isLyXFilename(fname.absFilename()))
1565 fname.changeExtension(".lyx");
1567 FileDialog::Result result =
1568 dlg.save(toqstr(fname.onlyPath().absFilename()),
1569 QStringList(qt_("LyX Documents (*.lyx)")),
1570 toqstr(fname.onlyFileName()));
1572 if (result.first == FileDialog::Later)
1575 fname.set(fromqstr(result.second));
1580 if (!isLyXFilename(fname.absFilename()))
1581 fname.changeExtension(".lyx");
1584 if (FileName(fname).exists()) {
1585 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1586 docstring text = bformat(_("The document %1$s already "
1587 "exists.\n\nDo you want to "
1588 "overwrite that document?"),
1590 int const ret = Alert::prompt(_("Overwrite document?"),
1591 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1594 case 1: return renameBuffer(b, docstring());
1595 case 2: return false;
1599 // Ok, change the name of the buffer
1600 b.setFileName(fname.absFilename());
1602 bool unnamed = b.isUnnamed();
1603 b.setUnnamed(false);
1604 b.saveCheckSum(fname);
1606 if (!saveBuffer(b)) {
1607 b.setFileName(oldname.absFilename());
1608 b.setUnnamed(unnamed);
1609 b.saveCheckSum(oldname);
1617 bool GuiView::saveBuffer(Buffer & b)
1620 return renameBuffer(b, docstring());
1623 LyX::ref().session().lastFiles().add(b.fileName());
1627 // Switch to this Buffer.
1630 // FIXME: we don't tell the user *WHY* the save failed !!
1631 docstring const file = makeDisplayPath(b.absFileName(), 30);
1632 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1633 "Do you want to rename the document and "
1634 "try again?"), file);
1635 int const ret = Alert::prompt(_("Rename and save?"),
1636 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1639 if (!renameBuffer(b, docstring()))
1648 return saveBuffer(b);
1652 bool GuiView::closeBuffer()
1654 Buffer * buf = buffer();
1655 return buf && closeBuffer(*buf);
1659 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1661 // goto bookmark to update bookmark pit.
1662 //FIXME: we should update only the bookmarks related to this buffer!
1663 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1664 theLyXFunc().gotoBookmark(i+1, false, false);
1666 if (buf.isClean() || buf.paragraphs().empty()) {
1667 if (buf.masterBuffer() == &buf && tolastopened)
1668 LyX::ref().session().lastOpened().add(buf.fileName());
1669 theBufferList().release(&buf);
1672 // Switch to this Buffer.
1677 if (buf.isUnnamed())
1678 file = from_utf8(buf.fileName().onlyFileName());
1680 file = buf.fileName().displayName(30);
1682 // Bring this window to top before asking questions.
1686 docstring const text = bformat(_("The document %1$s has unsaved changes."
1687 "\n\nDo you want to save the document or discard the changes?"), file);
1688 int const ret = Alert::prompt(_("Save changed document?"),
1689 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1693 if (!saveBuffer(buf))
1697 // if we crash after this we could
1698 // have no autosave file but I guess
1699 // this is really improbable (Jug)
1700 removeAutosaveFile(buf.absFileName());
1706 // save file names to .lyx/session
1707 // if master/slave are both open, do not save slave since it
1708 // will be automatically loaded when the master is loaded
1709 if (buf.masterBuffer() == &buf && tolastopened)
1710 LyX::ref().session().lastOpened().add(buf.fileName());
1712 theBufferList().release(&buf);
1717 bool GuiView::dispatch(FuncRequest const & cmd)
1719 BufferView * bv = view();
1720 // By default we won't need any update.
1722 bv->cursor().updateFlags(Update::None);
1723 bool dispatched = true;
1725 switch(cmd.action) {
1726 case LFUN_BUFFER_IMPORT:
1727 importDocument(to_utf8(cmd.argument()));
1730 case LFUN_BUFFER_SWITCH:
1731 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1734 case LFUN_BUFFER_NEXT:
1735 setBuffer(theBufferList().next(buffer()));
1738 case LFUN_BUFFER_PREVIOUS:
1739 setBuffer(theBufferList().previous(buffer()));
1742 case LFUN_COMMAND_EXECUTE: {
1743 bool const show_it = cmd.argument() != "off";
1744 // FIXME: this is a hack, "minibuffer" should not be
1746 if (GuiToolbar * t = toolbar("minibuffer"))
1747 t->setVisible(show_it);
1750 case LFUN_DROP_LAYOUTS_CHOICE:
1752 d.layout_->showPopup();
1755 case LFUN_MENU_OPEN:
1756 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1757 menu->exec(QCursor::pos());
1760 case LFUN_FILE_INSERT:
1761 insertLyXFile(cmd.argument());
1763 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1764 insertPlaintextFile(cmd.argument(), true);
1767 case LFUN_FILE_INSERT_PLAINTEXT:
1768 insertPlaintextFile(cmd.argument(), false);
1771 case LFUN_BUFFER_WRITE:
1773 saveBuffer(bv->buffer());
1776 case LFUN_BUFFER_WRITE_AS:
1778 renameBuffer(bv->buffer(), cmd.argument());
1781 case LFUN_BUFFER_WRITE_ALL: {
1782 Buffer * first = theBufferList().first();
1785 message(_("Saving all documents..."));
1786 // We cannot use a for loop as the buffer list cycles.
1789 if (!b->isClean()) {
1791 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1793 b = theBufferList().next(b);
1794 } while (b != first);
1795 message(_("All documents saved."));
1799 case LFUN_TOOLBAR_TOGGLE: {
1800 string const name = cmd.getArg(0);
1801 if (GuiToolbar * t = toolbar(name))
1806 case LFUN_DIALOG_UPDATE: {
1807 string const name = to_utf8(cmd.argument());
1808 // Can only update a dialog connected to an existing inset
1809 Inset * inset = getOpenInset(name);
1811 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1812 inset->dispatch(view()->cursor(), fr);
1813 } else if (name == "paragraph") {
1814 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1815 } else if (name == "prefs") {
1816 updateDialog(name, string());
1821 case LFUN_DIALOG_TOGGLE: {
1822 if (isDialogVisible(cmd.getArg(0)))
1823 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1825 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1829 case LFUN_DIALOG_DISCONNECT_INSET:
1830 disconnectDialog(to_utf8(cmd.argument()));
1833 case LFUN_DIALOG_HIDE: {
1834 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1838 case LFUN_DIALOG_SHOW: {
1839 string const name = cmd.getArg(0);
1840 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1842 if (name == "character") {
1843 data = freefont2string();
1845 showDialog("character", data);
1846 } else if (name == "latexlog") {
1847 Buffer::LogType type;
1848 string const logfile = buffer()->logName(&type);
1850 case Buffer::latexlog:
1853 case Buffer::buildlog:
1857 data += Lexer::quoteString(logfile);
1858 showDialog("log", data);
1859 } else if (name == "vclog") {
1860 string const data = "vc " +
1861 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1862 showDialog("log", data);
1863 } else if (name == "symbols") {
1864 data = bv->cursor().getEncoding()->name();
1866 showDialog("symbols", data);
1868 showDialog(name, data);
1872 case LFUN_INSET_APPLY: {
1873 view()->cursor().recordUndoFullDocument();
1874 string const name = cmd.getArg(0);
1875 Inset * inset = getOpenInset(name);
1877 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1878 inset->dispatch(view()->cursor(), fr);
1880 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1886 case LFUN_UI_TOGGLE:
1888 // Make sure the keyboard focus stays in the work area.
1892 case LFUN_COMPLETION_INLINE:
1893 if (d.current_work_area_)
1894 d.current_work_area_->completer().showInline();
1897 case LFUN_SPLIT_VIEW:
1898 if (Buffer * buf = buffer()) {
1899 string const orientation = cmd.getArg(0);
1900 d.splitter_->setOrientation(orientation == "vertical"
1901 ? Qt::Vertical : Qt::Horizontal);
1902 TabWorkArea * twa = addTabWorkArea();
1903 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1904 setCurrentWorkArea(wa);
1908 case LFUN_CLOSE_TAB_GROUP:
1909 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1911 twa = d.currentTabWorkArea();
1912 // Switch to the next GuiWorkArea in the found TabWorkArea.
1913 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1914 if (d.splitter_->count() == 0)
1915 // No more work area, switch to the background widget.
1920 case LFUN_COMPLETION_POPUP:
1921 if (d.current_work_area_)
1922 d.current_work_area_->completer().showPopup();
1926 case LFUN_COMPLETION_COMPLETE:
1927 if (d.current_work_area_)
1928 d.current_work_area_->completer().tab();
1936 if (isFullScreen()) {
1937 if (menuBar()->isVisible())
1939 if (statusBar()->isVisible())
1940 statusBar()->hide();
1947 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1949 string const arg = cmd.getArg(0);
1950 if (arg == "scrollbar") {
1951 // hide() is of no help
1952 if (d.current_work_area_->verticalScrollBarPolicy() ==
1953 Qt::ScrollBarAlwaysOff)
1955 d.current_work_area_->setVerticalScrollBarPolicy(
1956 Qt::ScrollBarAsNeeded);
1958 d.current_work_area_->setVerticalScrollBarPolicy(
1959 Qt::ScrollBarAlwaysOff);
1962 if (arg == "statusbar") {
1963 statusBar()->setVisible(!statusBar()->isVisible());
1966 if (arg == "menubar") {
1967 menuBar()->setVisible(!menuBar()->isVisible());
1970 #if QT_VERSION >= 0x040300
1971 if (arg == "frame") {
1973 getContentsMargins(&l, &t, &r, &b);
1974 //are the frames in default state?
1975 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1977 setContentsMargins(-2, -2, -2, -2);
1979 setContentsMargins(0, 0, 0, 0);
1984 if (arg != "fullscreen") {
1985 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1989 if (lyxrc.full_screen_toolbars) {
1990 ToolbarMap::iterator end = d.toolbars_.end();
1991 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
1992 ; //it->second->toggleFullScreen(!isFullScreen());
1994 // d.toolbars_->toggleFullScreen(!isFullScreen());
1996 if (isFullScreen()) {
1997 for (int i = 0; i != d.splitter_->count(); ++i)
1998 d.tabWorkArea(i)->setFullScreen(false);
1999 #if QT_VERSION >= 0x040300
2000 setContentsMargins(0, 0, 0, 0);
2002 setWindowState(windowState() ^ Qt::WindowFullScreen);
2004 statusBar()->show();
2006 for (int i = 0; i != d.splitter_->count(); ++i)
2007 d.tabWorkArea(i)->setFullScreen(true);
2008 #if QT_VERSION >= 0x040300
2009 setContentsMargins(-2, -2, -2, -2);
2011 setWindowState(windowState() ^ Qt::WindowFullScreen);
2012 statusBar()->hide();
2018 Buffer const * GuiView::updateInset(Inset const * inset)
2020 if (!d.current_work_area_)
2024 d.current_work_area_->scheduleRedraw();
2026 return &d.current_work_area_->bufferView().buffer();
2030 void GuiView::restartCursor()
2032 /* When we move around, or type, it's nice to be able to see
2033 * the cursor immediately after the keypress.
2035 if (d.current_work_area_)
2036 d.current_work_area_->startBlinkingCursor();
2038 // Take this occasion to update the other GUI elements.
2043 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2045 if (d.current_work_area_)
2046 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2051 // This list should be kept in sync with the list of insets in
2052 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2053 // dialog should have the same name as the inset.
2055 char const * const dialognames[] = {
2056 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2057 "citation", "document", "errorlist", "ert", "external", "file",
2058 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2059 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2060 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2062 #ifdef HAVE_LIBAIKSAURUS
2066 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2068 char const * const * const end_dialognames =
2069 dialognames + (sizeof(dialognames) / sizeof(char *));
2073 cmpCStr(char const * name) : name_(name) {}
2074 bool operator()(char const * other) {
2075 return strcmp(other, name_) == 0;
2082 bool isValidName(string const & name)
2084 return find_if(dialognames, end_dialognames,
2085 cmpCStr(name.c_str())) != end_dialognames;
2091 void GuiView::resetDialogs()
2093 // Make sure that no LFUN uses any LyXView.
2094 theLyXFunc().setLyXView(0);
2095 // FIXME: the "math panels" toolbar takes an awful lot of time to
2096 // initialise so we don't do that for the time being.
2098 guiApp->menus().fillMenuBar(menuBar(), this);
2100 d.layout_->updateContents(true);
2101 // Now update controls with current buffer.
2102 theLyXFunc().setLyXView(this);
2107 Dialog * GuiView::find_or_build(string const & name)
2109 if (!isValidName(name))
2112 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2114 if (it != d.dialogs_.end())
2115 return it->second.get();
2117 Dialog * dialog = build(name);
2118 d.dialogs_[name].reset(dialog);
2119 if (lyxrc.allow_geometry_session)
2120 dialog->restoreSession();
2125 void GuiView::showDialog(string const & name, string const & data,
2132 Dialog * dialog = find_or_build(name);
2134 dialog->showData(data);
2136 d.open_insets_[name] = inset;
2142 bool GuiView::isDialogVisible(string const & name) const
2144 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2145 if (it == d.dialogs_.end())
2147 return it->second.get()->isVisibleView();
2151 void GuiView::hideDialog(string const & name, Inset * inset)
2153 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2154 if (it == d.dialogs_.end())
2157 if (inset && inset != getOpenInset(name))
2160 Dialog * const dialog = it->second.get();
2161 if (dialog->isVisibleView())
2163 d.open_insets_[name] = 0;
2167 void GuiView::disconnectDialog(string const & name)
2169 if (!isValidName(name))
2172 if (d.open_insets_.find(name) != d.open_insets_.end())
2173 d.open_insets_[name] = 0;
2177 Inset * GuiView::getOpenInset(string const & name) const
2179 if (!isValidName(name))
2182 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2183 return it == d.open_insets_.end() ? 0 : it->second;
2187 void GuiView::hideAll() const
2189 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2190 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2192 for(; it != end; ++it)
2193 it->second->hideView();
2197 void GuiView::updateDialogs()
2199 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2200 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2202 for(; it != end; ++it) {
2203 Dialog * dialog = it->second.get();
2204 if (dialog && dialog->isVisibleView())
2205 dialog->checkStatus();
2213 // will be replaced by a proper factory...
2214 Dialog * createGuiAbout(GuiView & lv);
2215 Dialog * createGuiBibitem(GuiView & lv);
2216 Dialog * createGuiBibtex(GuiView & lv);
2217 Dialog * createGuiBox(GuiView & lv);
2218 Dialog * createGuiBranch(GuiView & lv);
2219 Dialog * createGuiChanges(GuiView & lv);
2220 Dialog * createGuiCharacter(GuiView & lv);
2221 Dialog * createGuiCitation(GuiView & lv);
2222 Dialog * createGuiDelimiter(GuiView & lv);
2223 Dialog * createGuiDocument(GuiView & lv);
2224 Dialog * createGuiErrorList(GuiView & lv);
2225 Dialog * createGuiERT(GuiView & lv);
2226 Dialog * createGuiExternal(GuiView & lv);
2227 Dialog * createGuiFloat(GuiView & lv);
2228 Dialog * createGuiGraphics(GuiView & lv);
2229 Dialog * createGuiHSpace(GuiView & lv);
2230 Dialog * createGuiInclude(GuiView & lv);
2231 Dialog * createGuiLabel(GuiView & lv);
2232 Dialog * createGuiListings(GuiView & lv);
2233 Dialog * createGuiLog(GuiView & lv);
2234 Dialog * createGuiMathMatrix(GuiView & lv);
2235 Dialog * createGuiNomenclature(GuiView & lv);
2236 Dialog * createGuiNote(GuiView & lv);
2237 Dialog * createGuiParagraph(GuiView & lv);
2238 Dialog * createGuiPreferences(GuiView & lv);
2239 Dialog * createGuiPrint(GuiView & lv);
2240 Dialog * createGuiRef(GuiView & lv);
2241 Dialog * createGuiSearch(GuiView & lv);
2242 Dialog * createGuiSendTo(GuiView & lv);
2243 Dialog * createGuiShowFile(GuiView & lv);
2244 Dialog * createGuiSpellchecker(GuiView & lv);
2245 Dialog * createGuiSymbols(GuiView & lv);
2246 Dialog * createGuiTabularCreate(GuiView & lv);
2247 Dialog * createGuiTabular(GuiView & lv);
2248 Dialog * createGuiTexInfo(GuiView & lv);
2249 Dialog * createGuiToc(GuiView & lv);
2250 Dialog * createGuiThesaurus(GuiView & lv);
2251 Dialog * createGuiHyperlink(GuiView & lv);
2252 Dialog * createGuiVSpace(GuiView & lv);
2253 Dialog * createGuiViewSource(GuiView & lv);
2254 Dialog * createGuiWrap(GuiView & lv);
2257 Dialog * GuiView::build(string const & name)
2259 LASSERT(isValidName(name), /**/);
2261 if (name == "aboutlyx")
2262 return createGuiAbout(*this);
2263 if (name == "bibitem")
2264 return createGuiBibitem(*this);
2265 if (name == "bibtex")
2266 return createGuiBibtex(*this);
2268 return createGuiBox(*this);
2269 if (name == "branch")
2270 return createGuiBranch(*this);
2271 if (name == "changes")
2272 return createGuiChanges(*this);
2273 if (name == "character")
2274 return createGuiCharacter(*this);
2275 if (name == "citation")
2276 return createGuiCitation(*this);
2277 if (name == "document")
2278 return createGuiDocument(*this);
2279 if (name == "errorlist")
2280 return createGuiErrorList(*this);
2282 return createGuiERT(*this);
2283 if (name == "external")
2284 return createGuiExternal(*this);
2286 return createGuiShowFile(*this);
2287 if (name == "findreplace")
2288 return createGuiSearch(*this);
2289 if (name == "float")
2290 return createGuiFloat(*this);
2291 if (name == "graphics")
2292 return createGuiGraphics(*this);
2293 if (name == "include")
2294 return createGuiInclude(*this);
2295 if (name == "nomenclature")
2296 return createGuiNomenclature(*this);
2297 if (name == "label")
2298 return createGuiLabel(*this);
2300 return createGuiLog(*this);
2301 if (name == "view-source")
2302 return createGuiViewSource(*this);
2303 if (name == "mathdelimiter")
2304 return createGuiDelimiter(*this);
2305 if (name == "mathmatrix")
2306 return createGuiMathMatrix(*this);
2308 return createGuiNote(*this);
2309 if (name == "paragraph")
2310 return createGuiParagraph(*this);
2311 if (name == "prefs")
2312 return createGuiPreferences(*this);
2313 if (name == "print")
2314 return createGuiPrint(*this);
2316 return createGuiRef(*this);
2317 if (name == "sendto")
2318 return createGuiSendTo(*this);
2319 if (name == "space")
2320 return createGuiHSpace(*this);
2321 if (name == "spellchecker")
2322 return createGuiSpellchecker(*this);
2323 if (name == "symbols")
2324 return createGuiSymbols(*this);
2325 if (name == "tabular")
2326 return createGuiTabular(*this);
2327 if (name == "tabularcreate")
2328 return createGuiTabularCreate(*this);
2329 if (name == "texinfo")
2330 return createGuiTexInfo(*this);
2331 #ifdef HAVE_LIBAIKSAURUS
2332 if (name == "thesaurus")
2333 return createGuiThesaurus(*this);
2336 return createGuiToc(*this);
2338 return createGuiHyperlink(*this);
2339 if (name == "vspace")
2340 return createGuiVSpace(*this);
2342 return createGuiWrap(*this);
2343 if (name == "listings")
2344 return createGuiListings(*this);
2350 } // namespace frontend
2353 #include "GuiView_moc.cpp"