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 "GuiCommandBuffer.h"
22 #include "GuiCompleter.h"
23 #include "GuiWorkArea.h"
24 #include "GuiKeySymbol.h"
25 #include "GuiToolbar.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 if (lyxrc.allow_geometry_session) {
326 // Now take care of session management.
331 // No session handling, default to a sane size.
332 setGeometry(50, 50, 690, 510);
334 // This enables to clear session data if any.
346 void GuiView::saveLayout() const
349 QString const key = "view-" + QString::number(id_);
351 settings.setValue(key + "/pos", pos());
352 settings.setValue(key + "/size", size());
354 settings.setValue(key + "/geometry", saveGeometry());
356 settings.setValue(key + "/layout", saveState(0));
357 settings.setValue(key + "/icon_size", iconSize());
361 void GuiView::restoreLayout()
364 QString const key = "view-" + QString::number(id_);
365 setIconSize(settings.value(key + "/icon_size").toSize());
367 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
368 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
372 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
373 setGeometry(50, 50, 690, 510);
375 if (!restoreState(settings.value(key + "/layout").toByteArray(), 0))
380 GuiToolbar * GuiView::toolbar(string const & name)
382 ToolbarMap::iterator it = d.toolbars_.find(name);
383 if (it != d.toolbars_.end())
386 LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
387 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
392 void GuiView::constructToolbars()
394 ToolbarMap::iterator it = d.toolbars_.begin();
395 for (; it != d.toolbars_.end(); ++it)
399 // extracts the toolbars from the backend
400 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
401 Toolbars::Infos::iterator end = guiApp->toolbars().end();
402 for (; cit != end; ++cit)
403 d.toolbars_[cit->name] = new GuiToolbar(*cit, *this);
407 void GuiView::initToolbars()
409 // extracts the toolbars from the backend
410 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
411 Toolbars::Infos::iterator end = guiApp->toolbars().end();
412 for (; cit != end; ++cit) {
413 GuiToolbar * tb = toolbar(cit->name);
416 int const visibility = guiApp->toolbars().defaultVisibility(cit->name);
418 tb->setVisible(false);
419 tb->setVisibility(visibility);
421 if (visibility & Toolbars::TOP) {
423 addToolBarBreak(Qt::TopToolBarArea);
424 addToolBar(Qt::TopToolBarArea, tb);
427 if (visibility & Toolbars::BOTTOM) {
428 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
429 #if (QT_VERSION >= 0x040202)
430 addToolBarBreak(Qt::BottomToolBarArea);
432 addToolBar(Qt::BottomToolBarArea, tb);
435 if (visibility & Toolbars::LEFT) {
436 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
437 #if (QT_VERSION >= 0x040202)
438 addToolBarBreak(Qt::LeftToolBarArea);
440 addToolBar(Qt::LeftToolBarArea, tb);
443 if (visibility & Toolbars::RIGHT) {
444 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
445 #if (QT_VERSION >= 0x040202)
446 addToolBarBreak(Qt::RightToolBarArea);
448 addToolBar(Qt::RightToolBarArea, tb);
451 if (visibility & Toolbars::ON)
452 tb->setVisible(true);
457 TocModels & GuiView::tocModels()
459 return d.toc_models_;
463 void GuiView::setFocus()
465 // Make sure LyXFunc points to the correct view.
466 theLyXFunc().setLyXView(this);
467 if (d.current_work_area_)
468 d.current_work_area_->setFocus();
474 QMenu * GuiView::createPopupMenu()
476 return d.toolBarPopup(this);
480 void GuiView::showEvent(QShowEvent * e)
482 LYXERR(Debug::GUI, "Passed Geometry "
483 << size().height() << "x" << size().width()
484 << "+" << pos().x() << "+" << pos().y());
486 if (d.splitter_->count() == 0)
487 // No work area, switch to the background widget.
490 QMainWindow::showEvent(e);
494 void GuiView::closeEvent(QCloseEvent * close_event)
496 // it can happen that this event arrives without selecting the view,
497 // e.g. when clicking the close button on a background window.
498 theLyXFunc().setLyXView(this);
500 while (Buffer * b = buffer()) {
502 // This is a child document, just close the tab after saving
503 // but keep the file loaded.
504 if (!saveBuffer(*b)) {
505 close_event->ignore();
508 removeWorkArea(d.current_work_area_);
512 QList<int> const ids = guiApp->viewIds();
513 for (int i = 0; i != ids.size(); ++i) {
516 if (guiApp->view(ids[i]).workArea(*b)) {
517 // FIXME 1: should we put an alert box here that the buffer
518 // is viewed elsewhere?
519 // FIXME 2: should we try to save this buffer in any case?
522 // This buffer is also opened in another view, so
523 // but close the associated work area nevertheless.
524 removeWorkArea(d.current_work_area_);
525 // but don't close it.
530 if (b && !closeBuffer(*b, true)) {
531 close_event->ignore();
536 // Make sure that nothing will use this close to be closed View.
537 guiApp->unregisterView(this);
539 if (isFullScreen()) {
540 // Switch off fullscreen before closing.
545 // Make sure the timer time out will not trigger a statusbar update.
546 d.statusbar_timer_.stop();
548 // Saving fullscreen requires additional tweaks in the toolbar code.
549 // It wouldn't also work under linux natively.
550 if (lyxrc.allow_geometry_session) {
551 // Save this window geometry and layout.
553 // Then the toolbar private states.
554 ToolbarMap::iterator end = d.toolbars_.end();
555 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
556 it->second->saveSession();
557 // Now take care of all other dialogs:
558 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
559 for (; it!= d.dialogs_.end(); ++it)
560 it->second->saveSession();
563 close_event->accept();
567 void GuiView::dragEnterEvent(QDragEnterEvent * event)
569 if (event->mimeData()->hasUrls())
571 /// \todo Ask lyx-devel is this is enough:
572 /// if (event->mimeData()->hasFormat("text/plain"))
573 /// event->acceptProposedAction();
577 void GuiView::dropEvent(QDropEvent* event)
579 QList<QUrl> files = event->mimeData()->urls();
583 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
584 for (int i = 0; i != files.size(); ++i) {
585 string const file = os::internal_path(fromqstr(
586 files.at(i).toLocalFile()));
588 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
593 void GuiView::message(docstring const & str)
595 if (ForkedProcess::iAmAChild())
598 statusBar()->showMessage(toqstr(str));
599 d.statusbar_timer_.stop();
600 d.statusbar_timer_.start(3000);
604 void GuiView::smallSizedIcons()
606 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
610 void GuiView::normalSizedIcons()
612 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
616 void GuiView::bigSizedIcons()
618 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
622 void GuiView::clearMessage()
626 theLyXFunc().setLyXView(this);
627 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
628 d.statusbar_timer_.stop();
632 void GuiView::updateWindowTitle(GuiWorkArea * wa)
634 if (wa != d.current_work_area_)
636 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
637 setWindowIconText(wa->windowIconText());
641 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
644 disconnectBufferView();
645 connectBufferView(wa->bufferView());
646 connectBuffer(wa->bufferView().buffer());
647 d.current_work_area_ = wa;
648 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
649 this, SLOT(updateWindowTitle(GuiWorkArea *)));
650 updateWindowTitle(wa);
654 // The document settings needs to be reinitialised.
655 updateDialog("document", "");
657 // Buffer-dependent dialogs must be updated. This is done here because
658 // some dialogs require buffer()->text.
663 void GuiView::on_lastWorkAreaRemoved()
666 // On Mac close the view if there is no Tab open anymore,
667 // but only if no splitter is visible
668 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
669 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
670 if (twa && twa->count() == 0) {
671 // close the view, as no tab is open anymore
672 QTimer::singleShot(0, this, SLOT(close()));
677 // The document settings needs to be reinitialised.
678 updateDialog("document", "");
684 void GuiView::updateStatusBar()
686 // let the user see the explicit message
687 if (d.statusbar_timer_.isActive())
690 theLyXFunc().setLyXView(this);
691 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
695 bool GuiView::hasFocus() const
697 return qApp->activeWindow() == this;
701 bool GuiView::event(QEvent * e)
705 // Useful debug code:
706 //case QEvent::ActivationChange:
707 //case QEvent::WindowDeactivate:
708 //case QEvent::Paint:
709 //case QEvent::Enter:
710 //case QEvent::Leave:
711 //case QEvent::HoverEnter:
712 //case QEvent::HoverLeave:
713 //case QEvent::HoverMove:
714 //case QEvent::StatusTip:
715 //case QEvent::DragEnter:
716 //case QEvent::DragLeave:
720 case QEvent::WindowActivate: {
721 if (this == guiApp->currentView()) {
723 return QMainWindow::event(e);
725 guiApp->setCurrentView(this);
726 if (d.current_work_area_) {
727 BufferView & bv = d.current_work_area_->bufferView();
728 connectBufferView(bv);
729 connectBuffer(bv.buffer());
730 // The document structure, name and dialogs might have
731 // changed in another view.
733 // The document settings needs to be reinitialised.
734 updateDialog("document", "");
737 setWindowTitle(qt_("LyX"));
738 setWindowIconText(qt_("LyX"));
741 return QMainWindow::event(e);
744 case QEvent::ShortcutOverride: {
746 if (isFullScreen() && menuBar()->isHidden()) {
747 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
748 // FIXME: we should also try to detect special LyX shortcut such as
749 // Alt-P and Alt-M. Right now there is a hack in
750 // GuiWorkArea::processKeySym() that hides again the menubar for
752 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt)
754 return QMainWindow::event(e);
757 if (d.current_work_area_)
758 // Nothing special to do.
759 return QMainWindow::event(e);
761 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
762 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
764 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
765 || ke->key() == Qt::Key_Backtab)
766 return QMainWindow::event(e);
768 // Allow processing of shortcuts that are allowed even when no Buffer
770 theLyXFunc().setLyXView(this);
772 setKeySymbol(&sym, ke);
773 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
779 return QMainWindow::event(e);
784 bool GuiView::focusNextPrevChild(bool /*next*/)
791 void GuiView::setBusy(bool busy)
793 if (d.current_work_area_) {
794 d.current_work_area_->setUpdatesEnabled(!busy);
796 d.current_work_area_->stopBlinkingCursor();
798 d.current_work_area_->startBlinkingCursor();
802 QApplication::setOverrideCursor(Qt::WaitCursor);
804 QApplication::restoreOverrideCursor();
808 GuiWorkArea * GuiView::workArea(Buffer & buffer)
810 if (TabWorkArea * twa = d.currentTabWorkArea())
811 return twa->workArea(buffer);
816 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
818 // Automatically create a TabWorkArea if there are none yet.
819 TabWorkArea * tab_widget = d.splitter_->count()
820 ? d.currentTabWorkArea() : addTabWorkArea();
821 return tab_widget->addWorkArea(buffer, *this);
825 TabWorkArea * GuiView::addTabWorkArea()
827 TabWorkArea * twa = new TabWorkArea;
828 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
829 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
830 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
831 this, SLOT(on_lastWorkAreaRemoved()));
833 d.splitter_->addWidget(twa);
834 d.stack_widget_->setCurrentWidget(d.splitter_);
839 GuiWorkArea const * GuiView::currentWorkArea() const
841 return d.current_work_area_;
845 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
848 d.current_work_area_ = wa;
849 for (int i = 0; i != d.splitter_->count(); ++i) {
850 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
856 void GuiView::removeWorkArea(GuiWorkArea * wa)
859 if (wa == d.current_work_area_) {
861 disconnectBufferView();
862 d.current_work_area_ = 0;
865 for (int i = 0; i != d.splitter_->count(); ++i) {
866 TabWorkArea * twa = d.tabWorkArea(i);
867 if (!twa->removeWorkArea(wa))
868 // Not found in this tab group.
871 // We found and removed the GuiWorkArea.
873 // No more WorkAreas in this tab group, so delete it.
878 if (d.current_work_area_)
879 // This means that we are not closing the current GuiWorkArea;
882 // Switch to the next GuiWorkArea in the found TabWorkArea.
883 d.current_work_area_ = twa->currentWorkArea();
887 if (d.splitter_->count() == 0)
888 // No more work area, switch to the background widget.
893 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
899 void GuiView::updateLayoutList()
902 d.layout_->updateContents(false);
906 void GuiView::updateToolbars()
908 ToolbarMap::iterator end = d.toolbars_.end();
909 if (d.current_work_area_) {
911 d.current_work_area_->bufferView().cursor().inMathed();
913 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
915 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
916 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
917 bool const mathmacrotemplate =
918 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
920 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
921 it->second->update(math, table, review, mathmacrotemplate);
923 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
924 it->second->update(false, false, false, false);
928 Buffer * GuiView::buffer()
930 if (d.current_work_area_)
931 return &d.current_work_area_->bufferView().buffer();
936 Buffer const * GuiView::buffer() const
938 if (d.current_work_area_)
939 return &d.current_work_area_->bufferView().buffer();
944 void GuiView::setBuffer(Buffer * newBuffer)
946 LASSERT(newBuffer, /**/);
949 GuiWorkArea * wa = workArea(*newBuffer);
951 updateLabels(*newBuffer->masterBuffer());
952 wa = addWorkArea(*newBuffer);
954 //Disconnect the old buffer...there's no new one.
957 connectBuffer(*newBuffer);
958 connectBufferView(wa->bufferView());
959 setCurrentWorkArea(wa);
965 void GuiView::connectBuffer(Buffer & buf)
967 buf.setGuiDelegate(this);
971 void GuiView::disconnectBuffer()
973 if (d.current_work_area_)
974 d.current_work_area_->bufferView().setGuiDelegate(0);
978 void GuiView::connectBufferView(BufferView & bv)
980 bv.setGuiDelegate(this);
984 void GuiView::disconnectBufferView()
986 if (d.current_work_area_)
987 d.current_work_area_->bufferView().setGuiDelegate(0);
991 void GuiView::errors(string const & error_type)
993 ErrorList & el = buffer()->errorList(error_type);
995 showDialog("errorlist", error_type);
999 void GuiView::structureChanged()
1001 d.toc_models_.reset(view());
1002 // Navigator needs more than a simple update in this case. It needs to be
1004 updateDialog("toc", "");
1008 void GuiView::updateDialog(string const & name, string const & data)
1010 if (!isDialogVisible(name))
1013 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
1014 if (it == d.dialogs_.end())
1017 Dialog * const dialog = it->second.get();
1018 if (dialog->isVisibleView())
1019 dialog->initialiseParams(data);
1023 BufferView * GuiView::view()
1025 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1029 void GuiView::autoSave()
1031 LYXERR(Debug::INFO, "Running autoSave()");
1034 view()->buffer().autoSave();
1038 void GuiView::resetAutosaveTimers()
1041 d.autosave_timeout_.restart();
1045 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1048 Buffer * buf = buffer();
1050 /* In LyX/Mac, when a dialog is open, the menus of the
1051 application can still be accessed without giving focus to
1052 the main window. In this case, we want to disable the menu
1053 entries that are buffer-related.
1055 Note that this code is not perfect, as bug 1941 attests:
1056 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1058 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1061 switch(cmd.action) {
1062 case LFUN_BUFFER_WRITE:
1063 enable = buf && (buf->isUnnamed() || !buf->isClean());
1066 case LFUN_BUFFER_WRITE_AS:
1070 case LFUN_SPLIT_VIEW:
1074 case LFUN_CLOSE_TAB_GROUP:
1075 enable = d.currentTabWorkArea();
1078 case LFUN_TOOLBAR_TOGGLE:
1079 if (GuiToolbar * t = toolbar(cmd.getArg(0)))
1080 flag.setOnOff(t->isVisible());
1083 case LFUN_UI_TOGGLE:
1084 flag.setOnOff(isFullScreen());
1087 case LFUN_DIALOG_TOGGLE:
1088 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1089 // fall through to set "enable"
1090 case LFUN_DIALOG_SHOW: {
1091 string const name = cmd.getArg(0);
1093 enable = name == "aboutlyx"
1094 || name == "file" //FIXME: should be removed.
1096 || name == "texinfo";
1097 else if (name == "print")
1098 enable = buf->isExportable("dvi")
1099 && lyxrc.print_command != "none";
1100 else if (name == "character") {
1104 InsetCode ic = view()->cursor().inset().lyxCode();
1105 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1108 else if (name == "symbols") {
1109 if (!view() || view()->cursor().inMathed())
1112 InsetCode ic = view()->cursor().inset().lyxCode();
1113 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1116 else if (name == "latexlog")
1117 enable = FileName(buf->logName()).isReadableFile();
1118 else if (name == "spellchecker")
1119 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1120 enable = !buf->isReadonly();
1124 else if (name == "vclog")
1125 enable = buf->lyxvc().inUse();
1129 case LFUN_DIALOG_UPDATE: {
1130 string const name = cmd.getArg(0);
1132 enable = name == "prefs";
1136 case LFUN_INSET_APPLY: {
1137 string const name = cmd.getArg(0);
1138 Inset * inset = getOpenInset(name);
1140 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1142 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1143 // Every inset is supposed to handle this
1144 LASSERT(false, /**/);
1148 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1149 flag |= lyx::getStatus(fr);
1151 enable = flag.enabled();
1155 case LFUN_COMPLETION_INLINE:
1156 if (!d.current_work_area_
1157 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1161 case LFUN_COMPLETION_POPUP:
1162 if (!d.current_work_area_
1163 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1167 case LFUN_COMPLETION_COMPLETE:
1168 if (!d.current_work_area_
1169 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1178 flag.setEnabled(false);
1184 static FileName selectTemplateFile()
1186 FileDialog dlg(qt_("Select template file"));
1187 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1188 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1190 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1191 QStringList(qt_("LyX Documents (*.lyx)")));
1193 if (result.first == FileDialog::Later)
1195 if (result.second.isEmpty())
1197 return FileName(fromqstr(result.second));
1201 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1205 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1208 message(_("Document not loaded."));
1213 setBuffer(newBuffer);
1215 // scroll to the position when the file was last closed
1216 if (lyxrc.use_lastfilepos) {
1217 LastFilePosSection::FilePos filepos =
1218 LyX::ref().session().lastFilePos().load(filename);
1219 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1223 LyX::ref().session().lastFiles().add(filename);
1230 void GuiView::openDocument(string const & fname)
1232 string initpath = lyxrc.document_path;
1235 string const trypath = buffer()->filePath();
1236 // If directory is writeable, use this as default.
1237 if (FileName(trypath).isDirWritable())
1243 if (fname.empty()) {
1244 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1245 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1246 dlg.setButton2(qt_("Examples|#E#e"),
1247 toqstr(addPath(package().system_support().absFilename(), "examples")));
1249 FileDialog::Result result =
1250 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1252 if (result.first == FileDialog::Later)
1255 filename = fromqstr(result.second);
1257 // check selected filename
1258 if (filename.empty()) {
1259 message(_("Canceled."));
1265 // get absolute path of file and add ".lyx" to the filename if
1267 FileName const fullname =
1268 fileSearch(string(), filename, "lyx", support::may_not_exist);
1269 if (!fullname.empty())
1270 filename = fullname.absFilename();
1272 // if the file doesn't exist, let the user create one
1273 if (!fullname.exists()) {
1274 // the user specifically chose this name. Believe him.
1275 Buffer * const b = newFile(filename, string(), true);
1281 docstring const disp_fn = makeDisplayPath(filename);
1282 message(bformat(_("Opening document %1$s..."), disp_fn));
1285 Buffer * buf = loadDocument(fullname);
1290 buf->errors("Parse");
1291 str2 = bformat(_("Document %1$s opened."), disp_fn);
1293 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1298 // FIXME: clean that
1299 static bool import(GuiView * lv, FileName const & filename,
1300 string const & format, ErrorList & errorList)
1302 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1304 string loader_format;
1305 vector<string> loaders = theConverters().loaders();
1306 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1307 for (vector<string>::const_iterator it = loaders.begin();
1308 it != loaders.end(); ++it) {
1309 if (!theConverters().isReachable(format, *it))
1312 string const tofile =
1313 support::changeExtension(filename.absFilename(),
1314 formats.extension(*it));
1315 if (!theConverters().convert(0, filename, FileName(tofile),
1316 filename, format, *it, errorList))
1318 loader_format = *it;
1321 if (loader_format.empty()) {
1322 frontend::Alert::error(_("Couldn't import file"),
1323 bformat(_("No information for importing the format %1$s."),
1324 formats.prettyName(format)));
1328 loader_format = format;
1330 if (loader_format == "lyx") {
1331 Buffer * buf = lv->loadDocument(lyxfile);
1336 buf->errors("Parse");
1338 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1342 bool as_paragraphs = loader_format == "textparagraph";
1343 string filename2 = (loader_format == format) ? filename.absFilename()
1344 : support::changeExtension(filename.absFilename(),
1345 formats.extension(loader_format));
1346 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1347 theLyXFunc().setLyXView(lv);
1348 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1355 void GuiView::importDocument(string const & argument)
1358 string filename = split(argument, format, ' ');
1360 LYXERR(Debug::INFO, format << " file: " << filename);
1362 // need user interaction
1363 if (filename.empty()) {
1364 string initpath = lyxrc.document_path;
1366 Buffer const * buf = buffer();
1368 string const trypath = buf->filePath();
1369 // If directory is writeable, use this as default.
1370 if (FileName(trypath).isDirWritable())
1374 docstring const text = bformat(_("Select %1$s file to import"),
1375 formats.prettyName(format));
1377 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1378 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1379 dlg.setButton2(qt_("Examples|#E#e"),
1380 toqstr(addPath(package().system_support().absFilename(), "examples")));
1382 docstring filter = formats.prettyName(format);
1385 filter += from_utf8(formats.extension(format));
1388 FileDialog::Result result =
1389 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1391 if (result.first == FileDialog::Later)
1394 filename = fromqstr(result.second);
1396 // check selected filename
1397 if (filename.empty())
1398 message(_("Canceled."));
1401 if (filename.empty())
1404 // get absolute path of file
1405 FileName const fullname(support::makeAbsPath(filename));
1407 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1409 // Check if the document already is open
1410 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1413 if (!closeBuffer()) {
1414 message(_("Canceled."));
1419 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1421 // if the file exists already, and we didn't do
1422 // -i lyx thefile.lyx, warn
1423 if (lyxfile.exists() && fullname != lyxfile) {
1425 docstring text = bformat(_("The document %1$s already exists.\n\n"
1426 "Do you want to overwrite that document?"), displaypath);
1427 int const ret = Alert::prompt(_("Overwrite document?"),
1428 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1431 message(_("Canceled."));
1436 message(bformat(_("Importing %1$s..."), displaypath));
1437 ErrorList errorList;
1438 if (import(this, fullname, format, errorList))
1439 message(_("imported."));
1441 message(_("file not imported!"));
1443 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1447 void GuiView::newDocument(string const & filename, bool from_template)
1449 FileName initpath(lyxrc.document_path);
1450 Buffer * buf = buffer();
1452 FileName const trypath(buf->filePath());
1453 // If directory is writeable, use this as default.
1454 if (trypath.isDirWritable())
1458 string templatefile = from_template ?
1459 selectTemplateFile().absFilename() : string();
1461 if (filename.empty())
1462 b = newUnnamedFile(templatefile, initpath);
1464 b = newFile(filename, templatefile, true);
1468 // Ensure the cursor is correctly positionned on screen.
1469 view()->showCursor();
1473 void GuiView::insertLyXFile(docstring const & fname)
1475 BufferView * bv = view();
1480 FileName filename(to_utf8(fname));
1482 if (!filename.empty()) {
1483 bv->insertLyXFile(filename);
1487 // Launch a file browser
1489 string initpath = lyxrc.document_path;
1490 string const trypath = bv->buffer().filePath();
1491 // If directory is writeable, use this as default.
1492 if (FileName(trypath).isDirWritable())
1496 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1497 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1498 dlg.setButton2(qt_("Examples|#E#e"),
1499 toqstr(addPath(package().system_support().absFilename(),
1502 FileDialog::Result result = dlg.open(toqstr(initpath),
1503 QStringList(qt_("LyX Documents (*.lyx)")));
1505 if (result.first == FileDialog::Later)
1509 filename.set(fromqstr(result.second));
1511 // check selected filename
1512 if (filename.empty()) {
1513 // emit message signal.
1514 message(_("Canceled."));
1518 bv->insertLyXFile(filename);
1522 void GuiView::insertPlaintextFile(docstring const & fname,
1525 BufferView * bv = view();
1530 FileName filename(to_utf8(fname));
1532 if (!filename.empty()) {
1533 bv->insertPlaintextFile(filename, asParagraph);
1537 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1538 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1540 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1543 if (result.first == FileDialog::Later)
1547 filename.set(fromqstr(result.second));
1549 // check selected filename
1550 if (filename.empty()) {
1551 // emit message signal.
1552 message(_("Canceled."));
1556 bv->insertPlaintextFile(filename, asParagraph);
1560 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1562 FileName fname = b.fileName();
1563 FileName const oldname = fname;
1565 if (!newname.empty()) {
1567 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1569 // Switch to this Buffer.
1572 /// No argument? Ask user through dialog.
1574 FileDialog dlg(qt_("Choose a filename to save document as"),
1575 LFUN_BUFFER_WRITE_AS);
1576 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1577 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1579 if (!isLyXFilename(fname.absFilename()))
1580 fname.changeExtension(".lyx");
1582 FileDialog::Result result =
1583 dlg.save(toqstr(fname.onlyPath().absFilename()),
1584 QStringList(qt_("LyX Documents (*.lyx)")),
1585 toqstr(fname.onlyFileName()));
1587 if (result.first == FileDialog::Later)
1590 fname.set(fromqstr(result.second));
1595 if (!isLyXFilename(fname.absFilename()))
1596 fname.changeExtension(".lyx");
1599 if (FileName(fname).exists()) {
1600 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1601 docstring text = bformat(_("The document %1$s already "
1602 "exists.\n\nDo you want to "
1603 "overwrite that document?"),
1605 int const ret = Alert::prompt(_("Overwrite document?"),
1606 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1609 case 1: return renameBuffer(b, docstring());
1610 case 2: return false;
1614 // Ok, change the name of the buffer
1615 b.setFileName(fname.absFilename());
1617 bool unnamed = b.isUnnamed();
1618 b.setUnnamed(false);
1619 b.saveCheckSum(fname);
1621 if (!saveBuffer(b)) {
1622 b.setFileName(oldname.absFilename());
1623 b.setUnnamed(unnamed);
1624 b.saveCheckSum(oldname);
1632 bool GuiView::saveBuffer(Buffer & b)
1635 return renameBuffer(b, docstring());
1638 LyX::ref().session().lastFiles().add(b.fileName());
1642 // Switch to this Buffer.
1645 // FIXME: we don't tell the user *WHY* the save failed !!
1646 docstring const file = makeDisplayPath(b.absFileName(), 30);
1647 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1648 "Do you want to rename the document and "
1649 "try again?"), file);
1650 int const ret = Alert::prompt(_("Rename and save?"),
1651 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1654 if (!renameBuffer(b, docstring()))
1663 return saveBuffer(b);
1667 bool GuiView::closeBuffer()
1669 Buffer * buf = buffer();
1670 return buf && closeBuffer(*buf);
1674 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1676 // goto bookmark to update bookmark pit.
1677 //FIXME: we should update only the bookmarks related to this buffer!
1678 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1679 theLyXFunc().gotoBookmark(i+1, false, false);
1681 if (buf.isClean() || buf.paragraphs().empty()) {
1682 if (buf.masterBuffer() == &buf && tolastopened)
1683 LyX::ref().session().lastOpened().add(buf.fileName());
1684 theBufferList().release(&buf);
1687 // Switch to this Buffer.
1692 if (buf.isUnnamed())
1693 file = from_utf8(buf.fileName().onlyFileName());
1695 file = buf.fileName().displayName(30);
1697 // Bring this window to top before asking questions.
1701 docstring const text = bformat(_("The document %1$s has unsaved changes."
1702 "\n\nDo you want to save the document or discard the changes?"), file);
1703 int const ret = Alert::prompt(_("Save changed document?"),
1704 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1708 if (!saveBuffer(buf))
1712 // if we crash after this we could
1713 // have no autosave file but I guess
1714 // this is really improbable (Jug)
1715 removeAutosaveFile(buf.absFileName());
1721 // save file names to .lyx/session
1722 // if master/slave are both open, do not save slave since it
1723 // will be automatically loaded when the master is loaded
1724 if (buf.masterBuffer() == &buf && tolastopened)
1725 LyX::ref().session().lastOpened().add(buf.fileName());
1727 theBufferList().release(&buf);
1732 bool GuiView::dispatch(FuncRequest const & cmd)
1734 BufferView * bv = view();
1735 // By default we won't need any update.
1737 bv->cursor().updateFlags(Update::None);
1738 bool dispatched = true;
1740 switch(cmd.action) {
1741 case LFUN_BUFFER_IMPORT:
1742 importDocument(to_utf8(cmd.argument()));
1745 case LFUN_BUFFER_SWITCH:
1746 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1749 case LFUN_BUFFER_NEXT:
1750 setBuffer(theBufferList().next(buffer()));
1753 case LFUN_BUFFER_PREVIOUS:
1754 setBuffer(theBufferList().previous(buffer()));
1757 case LFUN_COMMAND_EXECUTE: {
1758 bool const show_it = cmd.argument() != "off";
1759 // FIXME: this is a hack, "minibuffer" should not be
1761 if (GuiToolbar * t = toolbar("minibuffer")) {
1762 t->setVisible(show_it);
1763 if (show_it && t->commandBuffer())
1764 t->commandBuffer()->setFocus();
1768 case LFUN_DROP_LAYOUTS_CHOICE:
1770 d.layout_->showPopup();
1773 case LFUN_MENU_OPEN:
1774 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1775 menu->exec(QCursor::pos());
1778 case LFUN_FILE_INSERT:
1779 insertLyXFile(cmd.argument());
1781 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1782 insertPlaintextFile(cmd.argument(), true);
1785 case LFUN_FILE_INSERT_PLAINTEXT:
1786 insertPlaintextFile(cmd.argument(), false);
1789 case LFUN_BUFFER_WRITE:
1791 saveBuffer(bv->buffer());
1794 case LFUN_BUFFER_WRITE_AS:
1796 renameBuffer(bv->buffer(), cmd.argument());
1799 case LFUN_BUFFER_WRITE_ALL: {
1800 Buffer * first = theBufferList().first();
1803 message(_("Saving all documents..."));
1804 // We cannot use a for loop as the buffer list cycles.
1807 if (!b->isClean()) {
1809 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1811 b = theBufferList().next(b);
1812 } while (b != first);
1813 message(_("All documents saved."));
1817 case LFUN_TOOLBAR_TOGGLE: {
1818 string const name = cmd.getArg(0);
1819 if (GuiToolbar * t = toolbar(name))
1824 case LFUN_DIALOG_UPDATE: {
1825 string const name = to_utf8(cmd.argument());
1826 // Can only update a dialog connected to an existing inset
1827 Inset * inset = getOpenInset(name);
1829 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1830 inset->dispatch(view()->cursor(), fr);
1831 } else if (name == "paragraph") {
1832 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1833 } else if (name == "prefs") {
1834 updateDialog(name, string());
1839 case LFUN_DIALOG_TOGGLE: {
1840 if (isDialogVisible(cmd.getArg(0)))
1841 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1843 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1847 case LFUN_DIALOG_DISCONNECT_INSET:
1848 disconnectDialog(to_utf8(cmd.argument()));
1851 case LFUN_DIALOG_HIDE: {
1852 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1856 case LFUN_DIALOG_SHOW: {
1857 string const name = cmd.getArg(0);
1858 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1860 if (name == "character") {
1861 data = freefont2string();
1863 showDialog("character", data);
1864 } else if (name == "latexlog") {
1865 Buffer::LogType type;
1866 string const logfile = buffer()->logName(&type);
1868 case Buffer::latexlog:
1871 case Buffer::buildlog:
1875 data += Lexer::quoteString(logfile);
1876 showDialog("log", data);
1877 } else if (name == "vclog") {
1878 string const data = "vc " +
1879 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1880 showDialog("log", data);
1881 } else if (name == "symbols") {
1882 data = bv->cursor().getEncoding()->name();
1884 showDialog("symbols", data);
1886 showDialog(name, data);
1890 case LFUN_INSET_APPLY: {
1891 view()->cursor().recordUndoFullDocument();
1892 string const name = cmd.getArg(0);
1893 Inset * inset = getOpenInset(name);
1895 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1896 inset->dispatch(view()->cursor(), fr);
1898 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1904 case LFUN_UI_TOGGLE:
1906 // Make sure the keyboard focus stays in the work area.
1910 case LFUN_COMPLETION_INLINE:
1911 if (d.current_work_area_)
1912 d.current_work_area_->completer().showInline();
1915 case LFUN_SPLIT_VIEW:
1916 if (Buffer * buf = buffer()) {
1917 string const orientation = cmd.getArg(0);
1918 d.splitter_->setOrientation(orientation == "vertical"
1919 ? Qt::Vertical : Qt::Horizontal);
1920 TabWorkArea * twa = addTabWorkArea();
1921 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1922 setCurrentWorkArea(wa);
1926 case LFUN_CLOSE_TAB_GROUP:
1927 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1929 twa = d.currentTabWorkArea();
1930 // Switch to the next GuiWorkArea in the found TabWorkArea.
1931 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1932 if (d.splitter_->count() == 0)
1933 // No more work area, switch to the background widget.
1938 case LFUN_COMPLETION_POPUP:
1939 if (d.current_work_area_)
1940 d.current_work_area_->completer().showPopup();
1944 case LFUN_COMPLETION_COMPLETE:
1945 if (d.current_work_area_)
1946 d.current_work_area_->completer().tab();
1954 if (isFullScreen()) {
1955 if (menuBar()->isVisible())
1957 if (statusBar()->isVisible())
1958 statusBar()->hide();
1965 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1967 string const arg = cmd.getArg(0);
1968 if (arg == "scrollbar") {
1969 // hide() is of no help
1970 if (d.current_work_area_->verticalScrollBarPolicy() ==
1971 Qt::ScrollBarAlwaysOff)
1973 d.current_work_area_->setVerticalScrollBarPolicy(
1974 Qt::ScrollBarAsNeeded);
1976 d.current_work_area_->setVerticalScrollBarPolicy(
1977 Qt::ScrollBarAlwaysOff);
1980 if (arg == "statusbar") {
1981 statusBar()->setVisible(!statusBar()->isVisible());
1984 if (arg == "menubar") {
1985 menuBar()->setVisible(!menuBar()->isVisible());
1988 #if QT_VERSION >= 0x040300
1989 if (arg == "frame") {
1991 getContentsMargins(&l, &t, &r, &b);
1992 //are the frames in default state?
1993 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1995 setContentsMargins(-2, -2, -2, -2);
1997 setContentsMargins(0, 0, 0, 0);
2002 if (arg == "fullscreen") {
2007 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
2011 void GuiView::toggleFullScreen()
2013 if (isFullScreen()) {
2014 for (int i = 0; i != d.splitter_->count(); ++i)
2015 d.tabWorkArea(i)->setFullScreen(false);
2016 #if QT_VERSION >= 0x040300
2017 setContentsMargins(0, 0, 0, 0);
2019 setWindowState(windowState() ^ Qt::WindowFullScreen);
2022 statusBar()->show();
2024 for (int i = 0; i != d.splitter_->count(); ++i)
2025 d.tabWorkArea(i)->setFullScreen(true);
2026 #if QT_VERSION >= 0x040300
2027 setContentsMargins(-2, -2, -2, -2);
2030 setWindowState(windowState() ^ Qt::WindowFullScreen);
2031 statusBar()->hide();
2033 if (lyxrc.full_screen_toolbars) {
2034 ToolbarMap::iterator end = d.toolbars_.end();
2035 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
2042 Buffer const * GuiView::updateInset(Inset const * inset)
2044 if (!d.current_work_area_)
2048 d.current_work_area_->scheduleRedraw();
2050 return &d.current_work_area_->bufferView().buffer();
2054 void GuiView::restartCursor()
2056 /* When we move around, or type, it's nice to be able to see
2057 * the cursor immediately after the keypress.
2059 if (d.current_work_area_)
2060 d.current_work_area_->startBlinkingCursor();
2062 // Take this occasion to update the other GUI elements.
2067 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2069 if (d.current_work_area_)
2070 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2075 // This list should be kept in sync with the list of insets in
2076 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2077 // dialog should have the same name as the inset.
2079 char const * const dialognames[] = {
2080 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2081 "citation", "document", "errorlist", "ert", "external", "file",
2082 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2083 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2084 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2086 #ifdef HAVE_LIBAIKSAURUS
2090 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2092 char const * const * const end_dialognames =
2093 dialognames + (sizeof(dialognames) / sizeof(char *));
2097 cmpCStr(char const * name) : name_(name) {}
2098 bool operator()(char const * other) {
2099 return strcmp(other, name_) == 0;
2106 bool isValidName(string const & name)
2108 return find_if(dialognames, end_dialognames,
2109 cmpCStr(name.c_str())) != end_dialognames;
2115 void GuiView::resetDialogs()
2117 // Make sure that no LFUN uses any LyXView.
2118 theLyXFunc().setLyXView(0);
2119 // FIXME: the "math panels" toolbar takes an awful lot of time to
2120 // initialise so we don't do that for the time being.
2122 guiApp->menus().fillMenuBar(menuBar(), this);
2124 d.layout_->updateContents(true);
2125 // Now update controls with current buffer.
2126 theLyXFunc().setLyXView(this);
2131 Dialog * GuiView::find_or_build(string const & name)
2133 if (!isValidName(name))
2136 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2138 if (it != d.dialogs_.end())
2139 return it->second.get();
2141 Dialog * dialog = build(name);
2142 d.dialogs_[name].reset(dialog);
2143 if (lyxrc.allow_geometry_session)
2144 dialog->restoreSession();
2149 void GuiView::showDialog(string const & name, string const & data,
2156 Dialog * dialog = find_or_build(name);
2158 dialog->showData(data);
2160 d.open_insets_[name] = inset;
2166 bool GuiView::isDialogVisible(string const & name) const
2168 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2169 if (it == d.dialogs_.end())
2171 return it->second.get()->isVisibleView();
2175 void GuiView::hideDialog(string const & name, Inset * inset)
2177 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2178 if (it == d.dialogs_.end())
2181 if (inset && inset != getOpenInset(name))
2184 Dialog * const dialog = it->second.get();
2185 if (dialog->isVisibleView())
2187 d.open_insets_[name] = 0;
2191 void GuiView::disconnectDialog(string const & name)
2193 if (!isValidName(name))
2196 if (d.open_insets_.find(name) != d.open_insets_.end())
2197 d.open_insets_[name] = 0;
2201 Inset * GuiView::getOpenInset(string const & name) const
2203 if (!isValidName(name))
2206 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2207 return it == d.open_insets_.end() ? 0 : it->second;
2211 void GuiView::hideAll() const
2213 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2214 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2216 for(; it != end; ++it)
2217 it->second->hideView();
2221 void GuiView::updateDialogs()
2223 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2224 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2226 for(; it != end; ++it) {
2227 Dialog * dialog = it->second.get();
2228 if (dialog && dialog->isVisibleView())
2229 dialog->checkStatus();
2237 // will be replaced by a proper factory...
2238 Dialog * createGuiAbout(GuiView & lv);
2239 Dialog * createGuiBibitem(GuiView & lv);
2240 Dialog * createGuiBibtex(GuiView & lv);
2241 Dialog * createGuiBox(GuiView & lv);
2242 Dialog * createGuiBranch(GuiView & lv);
2243 Dialog * createGuiChanges(GuiView & lv);
2244 Dialog * createGuiCharacter(GuiView & lv);
2245 Dialog * createGuiCitation(GuiView & lv);
2246 Dialog * createGuiDelimiter(GuiView & lv);
2247 Dialog * createGuiDocument(GuiView & lv);
2248 Dialog * createGuiErrorList(GuiView & lv);
2249 Dialog * createGuiERT(GuiView & lv);
2250 Dialog * createGuiExternal(GuiView & lv);
2251 Dialog * createGuiFloat(GuiView & lv);
2252 Dialog * createGuiGraphics(GuiView & lv);
2253 Dialog * createGuiHSpace(GuiView & lv);
2254 Dialog * createGuiInclude(GuiView & lv);
2255 Dialog * createGuiLabel(GuiView & lv);
2256 Dialog * createGuiListings(GuiView & lv);
2257 Dialog * createGuiLog(GuiView & lv);
2258 Dialog * createGuiMathMatrix(GuiView & lv);
2259 Dialog * createGuiNomenclature(GuiView & lv);
2260 Dialog * createGuiNote(GuiView & lv);
2261 Dialog * createGuiParagraph(GuiView & lv);
2262 Dialog * createGuiPreferences(GuiView & lv);
2263 Dialog * createGuiPrint(GuiView & lv);
2264 Dialog * createGuiRef(GuiView & lv);
2265 Dialog * createGuiSearch(GuiView & lv);
2266 Dialog * createGuiSendTo(GuiView & lv);
2267 Dialog * createGuiShowFile(GuiView & lv);
2268 Dialog * createGuiSpellchecker(GuiView & lv);
2269 Dialog * createGuiSymbols(GuiView & lv);
2270 Dialog * createGuiTabularCreate(GuiView & lv);
2271 Dialog * createGuiTabular(GuiView & lv);
2272 Dialog * createGuiTexInfo(GuiView & lv);
2273 Dialog * createGuiToc(GuiView & lv);
2274 Dialog * createGuiThesaurus(GuiView & lv);
2275 Dialog * createGuiHyperlink(GuiView & lv);
2276 Dialog * createGuiVSpace(GuiView & lv);
2277 Dialog * createGuiViewSource(GuiView & lv);
2278 Dialog * createGuiWrap(GuiView & lv);
2281 Dialog * GuiView::build(string const & name)
2283 LASSERT(isValidName(name), /**/);
2285 if (name == "aboutlyx")
2286 return createGuiAbout(*this);
2287 if (name == "bibitem")
2288 return createGuiBibitem(*this);
2289 if (name == "bibtex")
2290 return createGuiBibtex(*this);
2292 return createGuiBox(*this);
2293 if (name == "branch")
2294 return createGuiBranch(*this);
2295 if (name == "changes")
2296 return createGuiChanges(*this);
2297 if (name == "character")
2298 return createGuiCharacter(*this);
2299 if (name == "citation")
2300 return createGuiCitation(*this);
2301 if (name == "document")
2302 return createGuiDocument(*this);
2303 if (name == "errorlist")
2304 return createGuiErrorList(*this);
2306 return createGuiERT(*this);
2307 if (name == "external")
2308 return createGuiExternal(*this);
2310 return createGuiShowFile(*this);
2311 if (name == "findreplace")
2312 return createGuiSearch(*this);
2313 if (name == "float")
2314 return createGuiFloat(*this);
2315 if (name == "graphics")
2316 return createGuiGraphics(*this);
2317 if (name == "include")
2318 return createGuiInclude(*this);
2319 if (name == "nomenclature")
2320 return createGuiNomenclature(*this);
2321 if (name == "label")
2322 return createGuiLabel(*this);
2324 return createGuiLog(*this);
2325 if (name == "view-source")
2326 return createGuiViewSource(*this);
2327 if (name == "mathdelimiter")
2328 return createGuiDelimiter(*this);
2329 if (name == "mathmatrix")
2330 return createGuiMathMatrix(*this);
2332 return createGuiNote(*this);
2333 if (name == "paragraph")
2334 return createGuiParagraph(*this);
2335 if (name == "prefs")
2336 return createGuiPreferences(*this);
2337 if (name == "print")
2338 return createGuiPrint(*this);
2340 return createGuiRef(*this);
2341 if (name == "sendto")
2342 return createGuiSendTo(*this);
2343 if (name == "space")
2344 return createGuiHSpace(*this);
2345 if (name == "spellchecker")
2346 return createGuiSpellchecker(*this);
2347 if (name == "symbols")
2348 return createGuiSymbols(*this);
2349 if (name == "tabular")
2350 return createGuiTabular(*this);
2351 if (name == "tabularcreate")
2352 return createGuiTabularCreate(*this);
2353 if (name == "texinfo")
2354 return createGuiTexInfo(*this);
2355 #ifdef HAVE_LIBAIKSAURUS
2356 if (name == "thesaurus")
2357 return createGuiThesaurus(*this);
2360 return createGuiToc(*this);
2362 return createGuiHyperlink(*this);
2363 if (name == "vspace")
2364 return createGuiVSpace(*this);
2366 return createGuiWrap(*this);
2367 if (name == "listings")
2368 return createGuiListings(*this);
2374 } // namespace frontend
2377 #include "GuiView_moc.cpp"