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"
28 #include "qt_helpers.h"
30 #include "frontends/alert.h"
32 #include "buffer_funcs.h"
34 #include "BufferList.h"
35 #include "BufferParams.h"
36 #include "BufferView.h"
37 #include "Converter.h"
40 #include "ErrorList.h"
42 #include "FuncStatus.h"
43 #include "FuncRequest.h"
51 #include "Paragraph.h"
52 #include "TextClass.h"
57 #include "support/lassert.h"
58 #include "support/debug.h"
59 #include "support/FileName.h"
60 #include "support/filetools.h"
61 #include "support/gettext.h"
62 #include "support/ForkedCalls.h"
63 #include "support/lstrings.h"
64 #include "support/os.h"
65 #include "support/Package.h"
66 #include "support/Timeout.h"
69 #include <QApplication>
70 #include <QCloseEvent>
72 #include <QDesktopWidget>
73 #include <QDragEnterEvent>
81 #include <QPushButton>
85 #include <QStackedWidget>
92 #include <boost/bind.hpp>
94 #ifdef HAVE_SYS_TIME_H
95 # include <sys/time.h>
102 using namespace lyx::support;
109 class BackgroundWidget : public QWidget
114 LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
115 /// The text to be written on top of the pixmap
116 QString const text = lyx_version ?
117 qt_("version ") + lyx_version : qt_("unknown version");
118 splash_ = QPixmap(":/images/banner.png");
120 QPainter pain(&splash_);
121 pain.setPen(QColor(0, 0, 0));
123 // The font used to display the version info
124 font.setStyleHint(QFont::SansSerif);
125 font.setWeight(QFont::Bold);
126 font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
128 pain.drawText(190, 225, text);
131 void paintEvent(QPaintEvent *)
133 int x = (width() - splash_.width()) / 2;
134 int y = (height() - splash_.height()) / 2;
136 pain.drawPixmap(x, y, splash_);
143 /// Toolbar store providing access to individual toolbars by name.
144 typedef std::map<std::string, GuiToolbar *> ToolbarMap;
146 typedef boost::shared_ptr<Dialog> DialogPtr;
151 struct GuiView::GuiViewPrivate
154 : current_work_area_(0), layout_(0), autosave_timeout_(5000),
157 // hardcode here the platform specific icon size
158 smallIconSize = 14; // scaling problems
159 normalIconSize = 20; // ok, default
160 bigIconSize = 26; // better for some math icons
162 splitter_ = new QSplitter;
163 bg_widget_ = new BackgroundWidget;
164 stack_widget_ = new QStackedWidget;
165 stack_widget_->addWidget(bg_widget_);
166 stack_widget_->addWidget(splitter_);
174 delete stack_widget_;
177 QMenu * toolBarPopup(GuiView * parent)
179 // FIXME: translation
180 QMenu * menu = new QMenu(parent);
181 QActionGroup * iconSizeGroup = new QActionGroup(parent);
183 QAction * smallIcons = new QAction(iconSizeGroup);
184 smallIcons->setText(qt_("Small-sized icons"));
185 smallIcons->setCheckable(true);
186 QObject::connect(smallIcons, SIGNAL(triggered()),
187 parent, SLOT(smallSizedIcons()));
188 menu->addAction(smallIcons);
190 QAction * normalIcons = new QAction(iconSizeGroup);
191 normalIcons->setText(qt_("Normal-sized icons"));
192 normalIcons->setCheckable(true);
193 QObject::connect(normalIcons, SIGNAL(triggered()),
194 parent, SLOT(normalSizedIcons()));
195 menu->addAction(normalIcons);
197 QAction * bigIcons = new QAction(iconSizeGroup);
198 bigIcons->setText(qt_("Big-sized icons"));
199 bigIcons->setCheckable(true);
200 QObject::connect(bigIcons, SIGNAL(triggered()),
201 parent, SLOT(bigSizedIcons()));
202 menu->addAction(bigIcons);
204 unsigned int cur = parent->iconSize().width();
205 if ( cur == parent->d.smallIconSize)
206 smallIcons->setChecked(true);
207 else if (cur == parent->d.normalIconSize)
208 normalIcons->setChecked(true);
209 else if (cur == parent->d.bigIconSize)
210 bigIcons->setChecked(true);
217 stack_widget_->setCurrentWidget(bg_widget_);
218 bg_widget_->setUpdatesEnabled(true);
221 TabWorkArea * tabWorkArea(int i)
223 return dynamic_cast<TabWorkArea *>(splitter_->widget(i));
226 TabWorkArea * currentTabWorkArea()
228 if (splitter_->count() == 1)
229 // The first TabWorkArea is always the first one, if any.
230 return tabWorkArea(0);
232 for (int i = 0; i != splitter_->count(); ++i) {
233 TabWorkArea * twa = tabWorkArea(i);
234 if (current_work_area_ == twa->currentWorkArea())
238 // None has the focus so we just take the first one.
239 return tabWorkArea(0);
243 GuiWorkArea * current_work_area_;
244 QSplitter * splitter_;
245 QStackedWidget * stack_widget_;
246 BackgroundWidget * bg_widget_;
248 ToolbarMap toolbars_;
249 /// The main layout box.
251 * \warning Don't Delete! The layout box is actually owned by
252 * whichever toolbar contains it. All the GuiView class needs is a
253 * means of accessing it.
255 * FIXME: replace that with a proper model so that we are not limited
256 * to only one dialog.
258 GuiLayoutBox * layout_;
261 map<string, Inset *> open_insets_;
264 map<string, DialogPtr> dialogs_;
266 unsigned int smallIconSize;
267 unsigned int normalIconSize;
268 unsigned int bigIconSize;
270 QTimer statusbar_timer_;
271 /// auto-saving of buffers
272 Timeout autosave_timeout_;
273 /// flag against a race condition due to multiclicks, see bug #1119
277 TocModels toc_models_;
281 GuiView::GuiView(int id)
282 : d(*new GuiViewPrivate), id_(id)
284 // GuiToolbars *must* be initialised before the menu bar.
287 // set ourself as the current view. This is needed for the menu bar
288 // filling, at least for the static special menu item on Mac. Otherwise
289 // they are greyed out.
290 theLyXFunc().setLyXView(this);
292 // Fill up the menu bar.
293 guiApp->menus().fillMenuBar(menuBar(), this, true);
295 setCentralWidget(d.stack_widget_);
297 // Start autosave timer
298 if (lyxrc.autosave) {
299 d.autosave_timeout_.timeout.connect(boost::bind(&GuiView::autoSave, this));
300 d.autosave_timeout_.setTimeout(lyxrc.autosave * 1000);
301 d.autosave_timeout_.start();
303 connect(&d.statusbar_timer_, SIGNAL(timeout()),
304 this, SLOT(clearMessage()));
306 // We don't want to keep the window in memory if it is closed.
307 setAttribute(Qt::WA_DeleteOnClose, true);
309 #if (!defined(Q_WS_WIN) && !defined(Q_WS_MACX))
310 // assign an icon to main form. We do not do it under Qt/Win or Qt/Mac,
311 // since the icon is provided in the application bundle.
312 setWindowIcon(QPixmap(":/images/lyx.png"));
316 setAcceptDrops(true);
318 statusBar()->setSizeGripEnabled(true);
320 // Forbid too small unresizable window because it can happen
321 // with some window manager under X11.
322 setMinimumSize(300, 200);
324 // Now take care of session management.
327 if (!lyxrc.allow_geometry_session) {
328 // No session handling, default to a sane size.
329 setGeometry(50, 50, 690, 510);
335 QString const key = "view-" + QString::number(id_);
337 QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
338 QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
342 if (!restoreGeometry(settings.value(key + "/geometry").toByteArray()))
343 setGeometry(50, 50, 690, 510);
345 if (!restoreState(settings.value(key + "/layout").toByteArray(), 0))
348 setIconSize(settings.value(key + "/icon_size").toSize());
358 GuiToolbar * GuiView::toolbar(string const & name)
360 ToolbarMap::iterator it = d.toolbars_.find(name);
361 if (it != d.toolbars_.end())
364 LYXERR(Debug::GUI, "Toolbar::display: no toolbar named " << name);
365 message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
370 void GuiView::constructToolbars()
372 ToolbarMap::iterator it = d.toolbars_.begin();
373 for (; it != d.toolbars_.end(); ++it)
377 // extracts the toolbars from the backend
378 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
379 Toolbars::Infos::iterator end = guiApp->toolbars().end();
380 for (; cit != end; ++cit)
381 d.toolbars_[cit->name] = new GuiToolbar(*cit, *this);
385 void GuiView::initToolbars()
387 // extracts the toolbars from the backend
388 Toolbars::Infos::iterator cit = guiApp->toolbars().begin();
389 Toolbars::Infos::iterator end = guiApp->toolbars().end();
390 for (; cit != end; ++cit) {
391 GuiToolbar * tb = toolbar(cit->name);
394 int const visibility = guiApp->toolbars().defaultVisibility(cit->name);
396 tb->setVisible(false);
397 tb->setVisibility(visibility);
399 if (visibility & Toolbars::TOP) {
401 addToolBarBreak(Qt::TopToolBarArea);
402 addToolBar(Qt::TopToolBarArea, tb);
405 if (visibility & Toolbars::BOTTOM) {
406 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
407 #if (QT_VERSION >= 0x040202)
408 addToolBarBreak(Qt::BottomToolBarArea);
410 addToolBar(Qt::BottomToolBarArea, tb);
413 if (visibility & Toolbars::LEFT) {
414 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
415 #if (QT_VERSION >= 0x040202)
416 addToolBarBreak(Qt::LeftToolBarArea);
418 addToolBar(Qt::LeftToolBarArea, tb);
421 if (visibility & Toolbars::RIGHT) {
422 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
423 #if (QT_VERSION >= 0x040202)
424 addToolBarBreak(Qt::RightToolBarArea);
426 addToolBar(Qt::RightToolBarArea, tb);
429 if (visibility & Toolbars::ON)
430 tb->setVisible(true);
435 TocModels & GuiView::tocModels()
437 return d.toc_models_;
441 void GuiView::setFocus()
443 if (d.current_work_area_)
444 d.current_work_area_->setFocus();
450 QMenu * GuiView::createPopupMenu()
452 return d.toolBarPopup(this);
456 void GuiView::showEvent(QShowEvent * e)
458 LYXERR(Debug::GUI, "Passed Geometry "
459 << size().height() << "x" << size().width()
460 << "+" << pos().x() << "+" << pos().y());
462 if (d.splitter_->count() == 0)
463 // No work area, switch to the background widget.
466 QMainWindow::showEvent(e);
470 void GuiView::closeEvent(QCloseEvent * close_event)
472 // it can happen that this event arrives without selecting the view,
473 // e.g. when clicking the close button on a background window.
474 theLyXFunc().setLyXView(this);
476 while (Buffer * b = buffer()) {
478 // This is a child document, just close the tab after saving
479 // but keep the file loaded.
480 if (!saveBuffer(*b)) {
481 close_event->ignore();
484 removeWorkArea(d.current_work_area_);
488 QList<int> const ids = guiApp->viewIds();
489 for (int i = 0; i != ids.size(); ++i) {
492 if (guiApp->view(ids[i]).workArea(*b)) {
493 // FIXME 1: should we put an alert box here that the buffer
494 // is viewed elsewhere?
495 // FIXME 2: should we try to save this buffer in any case?
498 // This buffer is also opened in another view, so
499 // but close the associated work area nevertheless.
500 removeWorkArea(d.current_work_area_);
501 // but don't close it.
506 if (b && !closeBuffer(*b, true)) {
507 close_event->ignore();
512 // Make sure that nothing will use this close to be closed View.
513 guiApp->unregisterView(this);
515 // Save toolbars configuration
516 if (isFullScreen()) {
517 // d.toolbars_->toggleFullScreen(!isFullScreen());
521 // Make sure the timer time out will not trigger a statusbar update.
522 d.statusbar_timer_.stop();
524 // Saving fullscreen requires additional tweaks in the toolbar code.
525 // It wouldn't also work under linux natively.
526 if (lyxrc.allow_geometry_session && !isFullScreen()) {
528 QString const key = "view-" + QString::number(id_);
530 settings.setValue(key + "/pos", pos());
531 settings.setValue(key + "/size", size());
533 settings.setValue(key + "/geometry", saveGeometry());
535 settings.setValue(key + "/icon_size", iconSize());
536 settings.setValue(key + "/layout", saveState(0));
538 ToolbarMap::iterator end = d.toolbars_.end();
539 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
540 it->second->saveSession();
541 // Now take care of all other dialogs:
542 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
543 for (; it!= d.dialogs_.end(); ++it)
544 it->second->saveSession();
547 close_event->accept();
551 void GuiView::dragEnterEvent(QDragEnterEvent * event)
553 if (event->mimeData()->hasUrls())
555 /// \todo Ask lyx-devel is this is enough:
556 /// if (event->mimeData()->hasFormat("text/plain"))
557 /// event->acceptProposedAction();
561 void GuiView::dropEvent(QDropEvent* event)
563 QList<QUrl> files = event->mimeData()->urls();
567 LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
568 for (int i = 0; i != files.size(); ++i) {
569 string const file = os::internal_path(fromqstr(
570 files.at(i).toLocalFile()));
572 lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
577 void GuiView::message(docstring const & str)
579 if (ForkedProcess::iAmAChild())
582 statusBar()->showMessage(toqstr(str));
583 d.statusbar_timer_.stop();
584 d.statusbar_timer_.start(3000);
588 void GuiView::smallSizedIcons()
590 setIconSize(QSize(d.smallIconSize, d.smallIconSize));
594 void GuiView::normalSizedIcons()
596 setIconSize(QSize(d.normalIconSize, d.normalIconSize));
600 void GuiView::bigSizedIcons()
602 setIconSize(QSize(d.bigIconSize, d.bigIconSize));
606 void GuiView::clearMessage()
610 theLyXFunc().setLyXView(this);
611 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
612 d.statusbar_timer_.stop();
616 void GuiView::updateWindowTitle(GuiWorkArea * wa)
618 if (wa != d.current_work_area_)
620 setWindowTitle(qt_("LyX: ") + wa->windowTitle());
621 setWindowIconText(wa->windowIconText());
625 void GuiView::on_currentWorkAreaChanged(GuiWorkArea * wa)
628 disconnectBufferView();
629 connectBufferView(wa->bufferView());
630 connectBuffer(wa->bufferView().buffer());
631 d.current_work_area_ = wa;
632 QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
633 this, SLOT(updateWindowTitle(GuiWorkArea *)));
634 updateWindowTitle(wa);
638 // The document settings needs to be reinitialised.
639 updateDialog("document", "");
641 // Buffer-dependent dialogs must be updated. This is done here because
642 // some dialogs require buffer()->text.
647 void GuiView::on_lastWorkAreaRemoved()
650 // On Mac close the view if there is no Tab open anymore,
651 // but only if no splitter is visible
652 if (!lyxrc.open_buffers_in_tabs && d.splitter_->count() == 1) {
653 TabWorkArea * twa = qobject_cast<TabWorkArea *>(d.splitter_->widget(0));
654 if (twa && twa->count() == 0) {
655 // close the view, as no tab is open anymore
656 QTimer::singleShot(0, this, SLOT(close()));
661 // The document settings needs to be reinitialised.
662 updateDialog("document", "");
668 void GuiView::updateStatusBar()
670 // let the user see the explicit message
671 if (d.statusbar_timer_.isActive())
674 theLyXFunc().setLyXView(this);
675 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
679 bool GuiView::hasFocus() const
681 return qApp->activeWindow() == this;
685 bool GuiView::event(QEvent * e)
689 // Useful debug code:
690 //case QEvent::ActivationChange:
691 //case QEvent::WindowDeactivate:
692 //case QEvent::Paint:
693 //case QEvent::Enter:
694 //case QEvent::Leave:
695 //case QEvent::HoverEnter:
696 //case QEvent::HoverLeave:
697 //case QEvent::HoverMove:
698 //case QEvent::StatusTip:
699 //case QEvent::DragEnter:
700 //case QEvent::DragLeave:
704 case QEvent::WindowActivate: {
705 if (this == guiApp->currentView()) {
707 return QMainWindow::event(e);
709 guiApp->setCurrentView(this);
710 if (d.current_work_area_) {
711 BufferView & bv = d.current_work_area_->bufferView();
712 connectBufferView(bv);
713 connectBuffer(bv.buffer());
714 // The document structure, name and dialogs might have
715 // changed in another view.
717 // The document settings needs to be reinitialised.
718 updateDialog("document", "");
721 setWindowTitle(qt_("LyX"));
722 setWindowIconText(qt_("LyX"));
725 return QMainWindow::event(e);
728 case QEvent::ShortcutOverride: {
730 if (isFullScreen() && menuBar()->isHidden()) {
731 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
732 // FIXME: we should also try to detect special LyX shortcut such as
733 // Alt-P and Alt-M. Right now there is a hack in
734 // GuiWorkArea::processKeySym() that hides again the menubar for
736 if (ke->modifiers() & Qt::AltModifier && ke->key() != Qt::Key_Alt)
738 return QMainWindow::event(e);
741 if (d.current_work_area_)
742 // Nothing special to do.
743 return QMainWindow::event(e);
745 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
746 // Let Qt handle menu access and the Tab keys to navigate keys to navigate
748 if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
749 || ke->key() == Qt::Key_Backtab)
750 return QMainWindow::event(e);
752 // Allow processing of shortcuts that are allowed even when no Buffer
754 theLyXFunc().setLyXView(this);
756 setKeySymbol(&sym, ke);
757 theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
763 return QMainWindow::event(e);
768 bool GuiView::focusNextPrevChild(bool /*next*/)
775 void GuiView::setBusy(bool busy)
777 if (d.current_work_area_) {
778 d.current_work_area_->setUpdatesEnabled(!busy);
780 d.current_work_area_->stopBlinkingCursor();
782 d.current_work_area_->startBlinkingCursor();
786 QApplication::setOverrideCursor(Qt::WaitCursor);
788 QApplication::restoreOverrideCursor();
792 GuiWorkArea * GuiView::workArea(Buffer & buffer)
794 if (TabWorkArea * twa = d.currentTabWorkArea())
795 return twa->workArea(buffer);
800 GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
802 // Automatically create a TabWorkArea if there are none yet.
803 TabWorkArea * tab_widget = d.splitter_->count()
804 ? d.currentTabWorkArea() : addTabWorkArea();
805 return tab_widget->addWorkArea(buffer, *this);
809 TabWorkArea * GuiView::addTabWorkArea()
811 TabWorkArea * twa = new TabWorkArea;
812 QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
813 this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
814 QObject::connect(twa, SIGNAL(lastWorkAreaRemoved()),
815 this, SLOT(on_lastWorkAreaRemoved()));
817 d.splitter_->addWidget(twa);
818 d.stack_widget_->setCurrentWidget(d.splitter_);
823 GuiWorkArea const * GuiView::currentWorkArea() const
825 return d.current_work_area_;
829 void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
832 d.current_work_area_ = wa;
833 for (int i = 0; i != d.splitter_->count(); ++i) {
834 if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
840 void GuiView::removeWorkArea(GuiWorkArea * wa)
843 if (wa == d.current_work_area_) {
845 disconnectBufferView();
846 d.current_work_area_ = 0;
849 for (int i = 0; i != d.splitter_->count(); ++i) {
850 TabWorkArea * twa = d.tabWorkArea(i);
851 if (!twa->removeWorkArea(wa))
852 // Not found in this tab group.
855 // We found and removed the GuiWorkArea.
857 // No more WorkAreas in this tab group, so delete it.
862 if (d.current_work_area_)
863 // This means that we are not closing the current GuiWorkArea;
866 // Switch to the next GuiWorkArea in the found TabWorkArea.
867 d.current_work_area_ = twa->currentWorkArea();
871 if (d.splitter_->count() == 0)
872 // No more work area, switch to the background widget.
877 void GuiView::setLayoutDialog(GuiLayoutBox * layout)
883 void GuiView::updateLayoutList()
886 d.layout_->updateContents(false);
890 void GuiView::updateToolbars()
892 ToolbarMap::iterator end = d.toolbars_.end();
893 if (d.current_work_area_) {
895 d.current_work_area_->bufferView().cursor().inMathed();
897 lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
899 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
900 lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
901 bool const mathmacrotemplate =
902 lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
904 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
905 it->second->update(math, table, review, mathmacrotemplate);
907 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
908 it->second->update(false, false, false, false);
912 Buffer * GuiView::buffer()
914 if (d.current_work_area_)
915 return &d.current_work_area_->bufferView().buffer();
920 Buffer const * GuiView::buffer() const
922 if (d.current_work_area_)
923 return &d.current_work_area_->bufferView().buffer();
928 void GuiView::setBuffer(Buffer * newBuffer)
930 LASSERT(newBuffer, /**/);
933 GuiWorkArea * wa = workArea(*newBuffer);
935 updateLabels(*newBuffer->masterBuffer());
936 wa = addWorkArea(*newBuffer);
938 //Disconnect the old buffer...there's no new one.
941 connectBuffer(*newBuffer);
942 connectBufferView(wa->bufferView());
943 setCurrentWorkArea(wa);
949 void GuiView::connectBuffer(Buffer & buf)
951 buf.setGuiDelegate(this);
955 void GuiView::disconnectBuffer()
957 if (d.current_work_area_)
958 d.current_work_area_->bufferView().setGuiDelegate(0);
962 void GuiView::connectBufferView(BufferView & bv)
964 bv.setGuiDelegate(this);
968 void GuiView::disconnectBufferView()
970 if (d.current_work_area_)
971 d.current_work_area_->bufferView().setGuiDelegate(0);
975 void GuiView::errors(string const & error_type)
977 ErrorList & el = buffer()->errorList(error_type);
979 showDialog("errorlist", error_type);
983 void GuiView::structureChanged()
985 d.toc_models_.reset(view());
986 // Navigator needs more than a simple update in this case. It needs to be
988 updateDialog("toc", "");
992 void GuiView::updateDialog(string const & name, string const & data)
994 if (!isDialogVisible(name))
997 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
998 if (it == d.dialogs_.end())
1001 Dialog * const dialog = it->second.get();
1002 if (dialog->isVisibleView())
1003 dialog->initialiseParams(data);
1007 BufferView * GuiView::view()
1009 return d.current_work_area_ ? &d.current_work_area_->bufferView() : 0;
1013 void GuiView::autoSave()
1015 LYXERR(Debug::INFO, "Running autoSave()");
1018 view()->buffer().autoSave();
1022 void GuiView::resetAutosaveTimers()
1025 d.autosave_timeout_.restart();
1029 bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
1032 Buffer * buf = buffer();
1034 /* In LyX/Mac, when a dialog is open, the menus of the
1035 application can still be accessed without giving focus to
1036 the main window. In this case, we want to disable the menu
1037 entries that are buffer-related.
1039 Note that this code is not perfect, as bug 1941 attests:
1040 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1042 if (cmd.origin == FuncRequest::MENU && !hasFocus())
1045 switch(cmd.action) {
1046 case LFUN_BUFFER_WRITE:
1047 enable = buf && (buf->isUnnamed() || !buf->isClean());
1050 case LFUN_BUFFER_WRITE_AS:
1054 case LFUN_SPLIT_VIEW:
1058 case LFUN_CLOSE_TAB_GROUP:
1059 enable = d.currentTabWorkArea();
1062 case LFUN_TOOLBAR_TOGGLE:
1063 if (GuiToolbar * t = toolbar(cmd.getArg(0)))
1064 flag.setOnOff(t->isVisible());
1067 case LFUN_UI_TOGGLE:
1068 flag.setOnOff(isFullScreen());
1071 case LFUN_DIALOG_TOGGLE:
1072 flag.setOnOff(isDialogVisible(cmd.getArg(0)));
1073 // fall through to set "enable"
1074 case LFUN_DIALOG_SHOW: {
1075 string const name = cmd.getArg(0);
1077 enable = name == "aboutlyx"
1078 || name == "file" //FIXME: should be removed.
1080 || name == "texinfo";
1081 else if (name == "print")
1082 enable = buf->isExportable("dvi")
1083 && lyxrc.print_command != "none";
1084 else if (name == "character") {
1088 InsetCode ic = view()->cursor().inset().lyxCode();
1089 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1092 else if (name == "symbols") {
1093 if (!view() || view()->cursor().inMathed())
1096 InsetCode ic = view()->cursor().inset().lyxCode();
1097 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
1100 else if (name == "latexlog")
1101 enable = FileName(buf->logName()).isReadableFile();
1102 else if (name == "spellchecker")
1103 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
1104 enable = !buf->isReadonly();
1108 else if (name == "vclog")
1109 enable = buf->lyxvc().inUse();
1113 case LFUN_DIALOG_UPDATE: {
1114 string const name = cmd.getArg(0);
1116 enable = name == "prefs";
1120 case LFUN_INSET_APPLY: {
1121 string const name = cmd.getArg(0);
1122 Inset * inset = getOpenInset(name);
1124 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1126 if (!inset->getStatus(view()->cursor(), fr, fs)) {
1127 // Every inset is supposed to handle this
1128 LASSERT(false, /**/);
1132 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1133 flag |= lyx::getStatus(fr);
1135 enable = flag.enabled();
1139 case LFUN_COMPLETION_INLINE:
1140 if (!d.current_work_area_
1141 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1145 case LFUN_COMPLETION_POPUP:
1146 if (!d.current_work_area_
1147 || !d.current_work_area_->completer().popupPossible(view()->cursor()))
1151 case LFUN_COMPLETION_COMPLETE:
1152 if (!d.current_work_area_
1153 || !d.current_work_area_->completer().inlinePossible(view()->cursor()))
1162 flag.enabled(false);
1168 static FileName selectTemplateFile()
1170 FileDialog dlg(qt_("Select template file"));
1171 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1172 dlg.setButton1(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1174 FileDialog::Result result = dlg.open(toqstr(lyxrc.template_path),
1175 QStringList(qt_("LyX Documents (*.lyx)")));
1177 if (result.first == FileDialog::Later)
1179 if (result.second.isEmpty())
1181 return FileName(fromqstr(result.second));
1185 Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
1189 Buffer * newBuffer = checkAndLoadLyXFile(filename);
1192 message(_("Document not loaded."));
1197 setBuffer(newBuffer);
1199 // scroll to the position when the file was last closed
1200 if (lyxrc.use_lastfilepos) {
1201 LastFilePosSection::FilePos filepos =
1202 LyX::ref().session().lastFilePos().load(filename);
1203 view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
1207 LyX::ref().session().lastFiles().add(filename);
1214 void GuiView::openDocument(string const & fname)
1216 string initpath = lyxrc.document_path;
1219 string const trypath = buffer()->filePath();
1220 // If directory is writeable, use this as default.
1221 if (FileName(trypath).isDirWritable())
1227 if (fname.empty()) {
1228 FileDialog dlg(qt_("Select document to open"), LFUN_FILE_OPEN);
1229 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1230 dlg.setButton2(qt_("Examples|#E#e"),
1231 toqstr(addPath(package().system_support().absFilename(), "examples")));
1233 FileDialog::Result result =
1234 dlg.open(toqstr(initpath), QStringList(qt_("LyX Documents (*.lyx)")));
1236 if (result.first == FileDialog::Later)
1239 filename = fromqstr(result.second);
1241 // check selected filename
1242 if (filename.empty()) {
1243 message(_("Canceled."));
1249 // get absolute path of file and add ".lyx" to the filename if
1251 FileName const fullname =
1252 fileSearch(string(), filename, "lyx", support::may_not_exist);
1253 if (!fullname.empty())
1254 filename = fullname.absFilename();
1256 // if the file doesn't exist, let the user create one
1257 if (!fullname.exists()) {
1258 // the user specifically chose this name. Believe him.
1259 Buffer * const b = newFile(filename, string(), true);
1265 docstring const disp_fn = makeDisplayPath(filename);
1266 message(bformat(_("Opening document %1$s..."), disp_fn));
1269 Buffer * buf = loadDocument(fullname);
1274 buf->errors("Parse");
1275 str2 = bformat(_("Document %1$s opened."), disp_fn);
1277 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1282 // FIXME: clean that
1283 static bool import(GuiView * lv, FileName const & filename,
1284 string const & format, ErrorList & errorList)
1286 FileName const lyxfile(support::changeExtension(filename.absFilename(), ".lyx"));
1288 string loader_format;
1289 vector<string> loaders = theConverters().loaders();
1290 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
1291 for (vector<string>::const_iterator it = loaders.begin();
1292 it != loaders.end(); ++it) {
1293 if (!theConverters().isReachable(format, *it))
1296 string const tofile =
1297 support::changeExtension(filename.absFilename(),
1298 formats.extension(*it));
1299 if (!theConverters().convert(0, filename, FileName(tofile),
1300 filename, format, *it, errorList))
1302 loader_format = *it;
1305 if (loader_format.empty()) {
1306 frontend::Alert::error(_("Couldn't import file"),
1307 bformat(_("No information for importing the format %1$s."),
1308 formats.prettyName(format)));
1312 loader_format = format;
1314 if (loader_format == "lyx") {
1315 Buffer * buf = lv->loadDocument(lyxfile);
1320 buf->errors("Parse");
1322 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
1326 bool as_paragraphs = loader_format == "textparagraph";
1327 string filename2 = (loader_format == format) ? filename.absFilename()
1328 : support::changeExtension(filename.absFilename(),
1329 formats.extension(loader_format));
1330 lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
1331 theLyXFunc().setLyXView(lv);
1332 lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
1339 void GuiView::importDocument(string const & argument)
1342 string filename = split(argument, format, ' ');
1344 LYXERR(Debug::INFO, format << " file: " << filename);
1346 // need user interaction
1347 if (filename.empty()) {
1348 string initpath = lyxrc.document_path;
1350 Buffer const * buf = buffer();
1352 string const trypath = buf->filePath();
1353 // If directory is writeable, use this as default.
1354 if (FileName(trypath).isDirWritable())
1358 docstring const text = bformat(_("Select %1$s file to import"),
1359 formats.prettyName(format));
1361 FileDialog dlg(toqstr(text), LFUN_BUFFER_IMPORT);
1362 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1363 dlg.setButton2(qt_("Examples|#E#e"),
1364 toqstr(addPath(package().system_support().absFilename(), "examples")));
1366 docstring filter = formats.prettyName(format);
1369 filter += from_utf8(formats.extension(format));
1372 FileDialog::Result result =
1373 dlg.open(toqstr(initpath), fileFilters(toqstr(filter)));
1375 if (result.first == FileDialog::Later)
1378 filename = fromqstr(result.second);
1380 // check selected filename
1381 if (filename.empty())
1382 message(_("Canceled."));
1385 if (filename.empty())
1388 // get absolute path of file
1389 FileName const fullname(support::makeAbsPath(filename));
1391 FileName const lyxfile(support::changeExtension(fullname.absFilename(), ".lyx"));
1393 // Check if the document already is open
1394 Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
1397 if (!closeBuffer()) {
1398 message(_("Canceled."));
1403 docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
1405 // if the file exists already, and we didn't do
1406 // -i lyx thefile.lyx, warn
1407 if (lyxfile.exists() && fullname != lyxfile) {
1409 docstring text = bformat(_("The document %1$s already exists.\n\n"
1410 "Do you want to overwrite that document?"), displaypath);
1411 int const ret = Alert::prompt(_("Overwrite document?"),
1412 text, 0, 1, _("&Overwrite"), _("&Cancel"));
1415 message(_("Canceled."));
1420 message(bformat(_("Importing %1$s..."), displaypath));
1421 ErrorList errorList;
1422 if (import(this, fullname, format, errorList))
1423 message(_("imported."));
1425 message(_("file not imported!"));
1427 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1431 void GuiView::newDocument(string const & filename, bool from_template)
1433 FileName initpath(lyxrc.document_path);
1434 Buffer * buf = buffer();
1436 FileName const trypath(buf->filePath());
1437 // If directory is writeable, use this as default.
1438 if (trypath.isDirWritable())
1442 string templatefile = from_template ?
1443 selectTemplateFile().absFilename() : string();
1445 if (filename.empty())
1446 b = newUnnamedFile(templatefile, initpath);
1448 b = newFile(filename, templatefile, true);
1452 // Ensure the cursor is correctly positionned on screen.
1453 view()->showCursor();
1457 void GuiView::insertLyXFile(docstring const & fname)
1459 BufferView * bv = view();
1464 FileName filename(to_utf8(fname));
1466 if (!filename.empty()) {
1467 bv->insertLyXFile(filename);
1471 // Launch a file browser
1473 string initpath = lyxrc.document_path;
1474 string const trypath = bv->buffer().filePath();
1475 // If directory is writeable, use this as default.
1476 if (FileName(trypath).isDirWritable())
1480 FileDialog dlg(qt_("Select LyX document to insert"), LFUN_FILE_INSERT);
1481 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1482 dlg.setButton2(qt_("Examples|#E#e"),
1483 toqstr(addPath(package().system_support().absFilename(),
1486 FileDialog::Result result = dlg.open(toqstr(initpath),
1487 QStringList(qt_("LyX Documents (*.lyx)")));
1489 if (result.first == FileDialog::Later)
1493 filename.set(fromqstr(result.second));
1495 // check selected filename
1496 if (filename.empty()) {
1497 // emit message signal.
1498 message(_("Canceled."));
1502 bv->insertLyXFile(filename);
1506 void GuiView::insertPlaintextFile(docstring const & fname,
1509 BufferView * bv = view();
1514 FileName filename(to_utf8(fname));
1516 if (!filename.empty()) {
1517 bv->insertPlaintextFile(filename, asParagraph);
1521 FileDialog dlg(qt_("Select file to insert"), (asParagraph ?
1522 LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
1524 FileDialog::Result result = dlg.open(toqstr(bv->buffer().filePath()),
1527 if (result.first == FileDialog::Later)
1531 filename.set(fromqstr(result.second));
1533 // check selected filename
1534 if (filename.empty()) {
1535 // emit message signal.
1536 message(_("Canceled."));
1540 bv->insertPlaintextFile(filename, asParagraph);
1544 bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
1546 FileName fname = b.fileName();
1547 FileName const oldname = fname;
1549 if (!newname.empty()) {
1551 fname = support::makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
1553 // Switch to this Buffer.
1556 /// No argument? Ask user through dialog.
1558 FileDialog dlg(qt_("Choose a filename to save document as"),
1559 LFUN_BUFFER_WRITE_AS);
1560 dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
1561 dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
1563 if (!isLyXFilename(fname.absFilename()))
1564 fname.changeExtension(".lyx");
1566 FileDialog::Result result =
1567 dlg.save(toqstr(fname.onlyPath().absFilename()),
1568 QStringList(qt_("LyX Documents (*.lyx)")),
1569 toqstr(fname.onlyFileName()));
1571 if (result.first == FileDialog::Later)
1574 fname.set(fromqstr(result.second));
1579 if (!isLyXFilename(fname.absFilename()))
1580 fname.changeExtension(".lyx");
1583 if (FileName(fname).exists()) {
1584 docstring const file = makeDisplayPath(fname.absFilename(), 30);
1585 docstring text = bformat(_("The document %1$s already "
1586 "exists.\n\nDo you want to "
1587 "overwrite that document?"),
1589 int const ret = Alert::prompt(_("Overwrite document?"),
1590 text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
1593 case 1: return renameBuffer(b, docstring());
1594 case 2: return false;
1598 // Ok, change the name of the buffer
1599 b.setFileName(fname.absFilename());
1601 bool unnamed = b.isUnnamed();
1602 b.setUnnamed(false);
1603 b.saveCheckSum(fname);
1605 if (!saveBuffer(b)) {
1606 b.setFileName(oldname.absFilename());
1607 b.setUnnamed(unnamed);
1608 b.saveCheckSum(oldname);
1616 bool GuiView::saveBuffer(Buffer & b)
1619 return renameBuffer(b, docstring());
1622 LyX::ref().session().lastFiles().add(b.fileName());
1626 // Switch to this Buffer.
1629 // FIXME: we don't tell the user *WHY* the save failed !!
1630 docstring const file = makeDisplayPath(b.absFileName(), 30);
1631 docstring text = bformat(_("The document %1$s could not be saved.\n\n"
1632 "Do you want to rename the document and "
1633 "try again?"), file);
1634 int const ret = Alert::prompt(_("Rename and save?"),
1635 text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
1638 if (!renameBuffer(b, docstring()))
1647 return saveBuffer(b);
1651 bool GuiView::closeBuffer()
1653 Buffer * buf = buffer();
1654 return buf && closeBuffer(*buf);
1658 bool GuiView::closeBuffer(Buffer & buf, bool tolastopened)
1660 // goto bookmark to update bookmark pit.
1661 //FIXME: we should update only the bookmarks related to this buffer!
1662 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1663 theLyXFunc().gotoBookmark(i+1, false, false);
1665 if (buf.isClean() || buf.paragraphs().empty()) {
1666 if (buf.masterBuffer() == &buf && tolastopened)
1667 LyX::ref().session().lastOpened().add(buf.fileName());
1668 theBufferList().release(&buf);
1671 // Switch to this Buffer.
1676 if (buf.isUnnamed())
1677 file = from_utf8(buf.fileName().onlyFileName());
1679 file = buf.fileName().displayName(30);
1681 // Bring this window to top before asking questions.
1685 docstring const text = bformat(_("The document %1$s has unsaved changes."
1686 "\n\nDo you want to save the document or discard the changes?"), file);
1687 int const ret = Alert::prompt(_("Save changed document?"),
1688 text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
1692 if (!saveBuffer(buf))
1696 // if we crash after this we could
1697 // have no autosave file but I guess
1698 // this is really improbable (Jug)
1699 removeAutosaveFile(buf.absFileName());
1705 // save file names to .lyx/session
1706 // if master/slave are both open, do not save slave since it
1707 // will be automatically loaded when the master is loaded
1708 if (buf.masterBuffer() == &buf && tolastopened)
1709 LyX::ref().session().lastOpened().add(buf.fileName());
1711 theBufferList().release(&buf);
1716 bool GuiView::dispatch(FuncRequest const & cmd)
1718 BufferView * bv = view();
1719 // By default we won't need any update.
1721 bv->cursor().updateFlags(Update::None);
1722 bool dispatched = true;
1724 switch(cmd.action) {
1725 case LFUN_BUFFER_IMPORT:
1726 importDocument(to_utf8(cmd.argument()));
1729 case LFUN_BUFFER_SWITCH:
1730 setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
1733 case LFUN_BUFFER_NEXT:
1734 setBuffer(theBufferList().next(buffer()));
1737 case LFUN_BUFFER_PREVIOUS:
1738 setBuffer(theBufferList().previous(buffer()));
1741 case LFUN_COMMAND_EXECUTE: {
1742 bool const show_it = cmd.argument() != "off";
1743 // FIXME: this is a hack, "minibuffer" should not be
1745 if (GuiToolbar * t = toolbar("minibuffer"))
1746 t->setVisible(show_it);
1749 case LFUN_DROP_LAYOUTS_CHOICE:
1751 d.layout_->showPopup();
1754 case LFUN_MENU_OPEN:
1755 if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument()), *this))
1756 menu->exec(QCursor::pos());
1759 case LFUN_FILE_INSERT:
1760 insertLyXFile(cmd.argument());
1762 case LFUN_FILE_INSERT_PLAINTEXT_PARA:
1763 insertPlaintextFile(cmd.argument(), true);
1766 case LFUN_FILE_INSERT_PLAINTEXT:
1767 insertPlaintextFile(cmd.argument(), false);
1770 case LFUN_BUFFER_WRITE:
1772 saveBuffer(bv->buffer());
1775 case LFUN_BUFFER_WRITE_AS:
1777 renameBuffer(bv->buffer(), cmd.argument());
1780 case LFUN_BUFFER_WRITE_ALL: {
1781 Buffer * first = theBufferList().first();
1784 message(_("Saving all documents..."));
1785 // We cannot use a for loop as the buffer list cycles.
1788 if (!b->isClean()) {
1790 LYXERR(Debug::ACTION, "Saved " << b->absFileName());
1792 b = theBufferList().next(b);
1793 } while (b != first);
1794 message(_("All documents saved."));
1798 case LFUN_TOOLBAR_TOGGLE: {
1799 string const name = cmd.getArg(0);
1800 if (GuiToolbar * t = toolbar(name))
1805 case LFUN_DIALOG_UPDATE: {
1806 string const name = to_utf8(cmd.argument());
1807 // Can only update a dialog connected to an existing inset
1808 Inset * inset = getOpenInset(name);
1810 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1811 inset->dispatch(view()->cursor(), fr);
1812 } else if (name == "paragraph") {
1813 lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1814 } else if (name == "prefs") {
1815 updateDialog(name, string());
1820 case LFUN_DIALOG_TOGGLE: {
1821 if (isDialogVisible(cmd.getArg(0)))
1822 dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
1824 dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
1828 case LFUN_DIALOG_DISCONNECT_INSET:
1829 disconnectDialog(to_utf8(cmd.argument()));
1832 case LFUN_DIALOG_HIDE: {
1833 guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
1837 case LFUN_DIALOG_SHOW: {
1838 string const name = cmd.getArg(0);
1839 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1841 if (name == "character") {
1842 data = freefont2string();
1844 showDialog("character", data);
1845 } else if (name == "latexlog") {
1846 Buffer::LogType type;
1847 string const logfile = buffer()->logName(&type);
1849 case Buffer::latexlog:
1852 case Buffer::buildlog:
1856 data += Lexer::quoteString(logfile);
1857 showDialog("log", data);
1858 } else if (name == "vclog") {
1859 string const data = "vc " +
1860 Lexer::quoteString(buffer()->lyxvc().getLogFile());
1861 showDialog("log", data);
1862 } else if (name == "symbols") {
1863 data = bv->cursor().getEncoding()->name();
1865 showDialog("symbols", data);
1867 showDialog(name, data);
1871 case LFUN_INSET_APPLY: {
1872 view()->cursor().recordUndoFullDocument();
1873 string const name = cmd.getArg(0);
1874 Inset * inset = getOpenInset(name);
1876 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
1877 inset->dispatch(view()->cursor(), fr);
1879 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
1885 case LFUN_UI_TOGGLE:
1887 // Make sure the keyboard focus stays in the work area.
1891 case LFUN_COMPLETION_INLINE:
1892 if (d.current_work_area_)
1893 d.current_work_area_->completer().showInline();
1896 case LFUN_SPLIT_VIEW:
1897 if (Buffer * buf = buffer()) {
1898 string const orientation = cmd.getArg(0);
1899 d.splitter_->setOrientation(orientation == "vertical"
1900 ? Qt::Vertical : Qt::Horizontal);
1901 TabWorkArea * twa = addTabWorkArea();
1902 GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
1903 setCurrentWorkArea(wa);
1907 case LFUN_CLOSE_TAB_GROUP:
1908 if (TabWorkArea * twa = d.currentTabWorkArea()) {
1910 twa = d.currentTabWorkArea();
1911 // Switch to the next GuiWorkArea in the found TabWorkArea.
1912 d.current_work_area_ = twa? twa->currentWorkArea() : 0;
1913 if (d.splitter_->count() == 0)
1914 // No more work area, switch to the background widget.
1919 case LFUN_COMPLETION_POPUP:
1920 if (d.current_work_area_)
1921 d.current_work_area_->completer().showPopup();
1925 case LFUN_COMPLETION_COMPLETE:
1926 if (d.current_work_area_)
1927 d.current_work_area_->completer().tab();
1935 if (isFullScreen()) {
1936 if (menuBar()->isVisible())
1938 if (statusBar()->isVisible())
1939 statusBar()->hide();
1946 void GuiView::lfunUiToggle(FuncRequest const & cmd)
1948 string const arg = cmd.getArg(0);
1949 if (arg == "scrollbar") {
1950 // hide() is of no help
1951 if (d.current_work_area_->verticalScrollBarPolicy() ==
1952 Qt::ScrollBarAlwaysOff)
1954 d.current_work_area_->setVerticalScrollBarPolicy(
1955 Qt::ScrollBarAsNeeded);
1957 d.current_work_area_->setVerticalScrollBarPolicy(
1958 Qt::ScrollBarAlwaysOff);
1961 if (arg == "statusbar") {
1962 statusBar()->setVisible(!statusBar()->isVisible());
1965 if (arg == "menubar") {
1966 menuBar()->setVisible(!menuBar()->isVisible());
1969 #if QT_VERSION >= 0x040300
1970 if (arg == "frame") {
1972 getContentsMargins(&l, &t, &r, &b);
1973 //are the frames in default state?
1974 d.current_work_area_->setFrameStyle(QFrame::NoFrame);
1976 setContentsMargins(-2, -2, -2, -2);
1978 setContentsMargins(0, 0, 0, 0);
1983 if (arg != "fullscreen") {
1984 message(bformat("LFUN_UI_TOGGLE " + _("%1$s unknown command!"), from_utf8(arg)));
1989 QString const key = "view-" + QString::number(id_);
1991 if (isFullScreen()) {
1992 for (int i = 0; i != d.splitter_->count(); ++i)
1993 d.tabWorkArea(i)->setFullScreen(false);
1994 #if QT_VERSION >= 0x040300
1995 setContentsMargins(0, 0, 0, 0);
1997 setWindowState(windowState() ^ Qt::WindowFullScreen);
1999 statusBar()->show();
2000 if (lyxrc.full_screen_toolbars) {
2001 if (!restoreState(settings.value(key + "/layout").toByteArray(), 0))
2005 for (int i = 0; i != d.splitter_->count(); ++i)
2006 d.tabWorkArea(i)->setFullScreen(true);
2007 #if QT_VERSION >= 0x040300
2008 setContentsMargins(-2, -2, -2, -2);
2010 setWindowState(windowState() ^ Qt::WindowFullScreen);
2011 statusBar()->hide();
2013 if (lyxrc.full_screen_toolbars) {
2014 settings.setValue(key + "/layout", saveState(0));
2015 ToolbarMap::iterator end = d.toolbars_.end();
2016 for (ToolbarMap::iterator it = d.toolbars_.begin(); it != end; ++it)
2023 Buffer const * GuiView::updateInset(Inset const * inset)
2025 if (!d.current_work_area_)
2029 d.current_work_area_->scheduleRedraw();
2031 return &d.current_work_area_->bufferView().buffer();
2035 void GuiView::restartCursor()
2037 /* When we move around, or type, it's nice to be able to see
2038 * the cursor immediately after the keypress.
2040 if (d.current_work_area_)
2041 d.current_work_area_->startBlinkingCursor();
2043 // Take this occasion to update the other GUI elements.
2048 void GuiView::updateCompletion(Cursor & cur, bool start, bool keep)
2050 if (d.current_work_area_)
2051 d.current_work_area_->completer().updateVisibility(cur, start, keep);
2056 // This list should be kept in sync with the list of insets in
2057 // src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
2058 // dialog should have the same name as the inset.
2060 char const * const dialognames[] = {
2061 "aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
2062 "citation", "document", "errorlist", "ert", "external", "file",
2063 "findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
2064 "mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
2065 "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate",
2067 #ifdef HAVE_LIBAIKSAURUS
2071 "texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
2073 char const * const * const end_dialognames =
2074 dialognames + (sizeof(dialognames) / sizeof(char *));
2078 cmpCStr(char const * name) : name_(name) {}
2079 bool operator()(char const * other) {
2080 return strcmp(other, name_) == 0;
2087 bool isValidName(string const & name)
2089 return find_if(dialognames, end_dialognames,
2090 cmpCStr(name.c_str())) != end_dialognames;
2096 void GuiView::resetDialogs()
2098 // Make sure that no LFUN uses any LyXView.
2099 theLyXFunc().setLyXView(0);
2100 // FIXME: the "math panels" toolbar takes an awful lot of time to
2101 // initialise so we don't do that for the time being.
2103 guiApp->menus().fillMenuBar(menuBar(), this);
2105 d.layout_->updateContents(true);
2106 // Now update controls with current buffer.
2107 theLyXFunc().setLyXView(this);
2112 Dialog * GuiView::find_or_build(string const & name)
2114 if (!isValidName(name))
2117 map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
2119 if (it != d.dialogs_.end())
2120 return it->second.get();
2122 Dialog * dialog = build(name);
2123 d.dialogs_[name].reset(dialog);
2124 if (lyxrc.allow_geometry_session)
2125 dialog->restoreSession();
2130 void GuiView::showDialog(string const & name, string const & data,
2137 Dialog * dialog = find_or_build(name);
2139 dialog->showData(data);
2141 d.open_insets_[name] = inset;
2147 bool GuiView::isDialogVisible(string const & name) const
2149 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2150 if (it == d.dialogs_.end())
2152 return it->second.get()->isVisibleView();
2156 void GuiView::hideDialog(string const & name, Inset * inset)
2158 map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
2159 if (it == d.dialogs_.end())
2162 if (inset && inset != getOpenInset(name))
2165 Dialog * const dialog = it->second.get();
2166 if (dialog->isVisibleView())
2168 d.open_insets_[name] = 0;
2172 void GuiView::disconnectDialog(string const & name)
2174 if (!isValidName(name))
2177 if (d.open_insets_.find(name) != d.open_insets_.end())
2178 d.open_insets_[name] = 0;
2182 Inset * GuiView::getOpenInset(string const & name) const
2184 if (!isValidName(name))
2187 map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
2188 return it == d.open_insets_.end() ? 0 : it->second;
2192 void GuiView::hideAll() const
2194 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2195 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2197 for(; it != end; ++it)
2198 it->second->hideView();
2202 void GuiView::updateDialogs()
2204 map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
2205 map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
2207 for(; it != end; ++it) {
2208 Dialog * dialog = it->second.get();
2209 if (dialog && dialog->isVisibleView())
2210 dialog->checkStatus();
2218 // will be replaced by a proper factory...
2219 Dialog * createGuiAbout(GuiView & lv);
2220 Dialog * createGuiBibitem(GuiView & lv);
2221 Dialog * createGuiBibtex(GuiView & lv);
2222 Dialog * createGuiBox(GuiView & lv);
2223 Dialog * createGuiBranch(GuiView & lv);
2224 Dialog * createGuiChanges(GuiView & lv);
2225 Dialog * createGuiCharacter(GuiView & lv);
2226 Dialog * createGuiCitation(GuiView & lv);
2227 Dialog * createGuiDelimiter(GuiView & lv);
2228 Dialog * createGuiDocument(GuiView & lv);
2229 Dialog * createGuiErrorList(GuiView & lv);
2230 Dialog * createGuiERT(GuiView & lv);
2231 Dialog * createGuiExternal(GuiView & lv);
2232 Dialog * createGuiFloat(GuiView & lv);
2233 Dialog * createGuiGraphics(GuiView & lv);
2234 Dialog * createGuiHSpace(GuiView & lv);
2235 Dialog * createGuiInclude(GuiView & lv);
2236 Dialog * createGuiLabel(GuiView & lv);
2237 Dialog * createGuiListings(GuiView & lv);
2238 Dialog * createGuiLog(GuiView & lv);
2239 Dialog * createGuiMathMatrix(GuiView & lv);
2240 Dialog * createGuiNomenclature(GuiView & lv);
2241 Dialog * createGuiNote(GuiView & lv);
2242 Dialog * createGuiParagraph(GuiView & lv);
2243 Dialog * createGuiPreferences(GuiView & lv);
2244 Dialog * createGuiPrint(GuiView & lv);
2245 Dialog * createGuiRef(GuiView & lv);
2246 Dialog * createGuiSearch(GuiView & lv);
2247 Dialog * createGuiSendTo(GuiView & lv);
2248 Dialog * createGuiShowFile(GuiView & lv);
2249 Dialog * createGuiSpellchecker(GuiView & lv);
2250 Dialog * createGuiSymbols(GuiView & lv);
2251 Dialog * createGuiTabularCreate(GuiView & lv);
2252 Dialog * createGuiTabular(GuiView & lv);
2253 Dialog * createGuiTexInfo(GuiView & lv);
2254 Dialog * createGuiToc(GuiView & lv);
2255 Dialog * createGuiThesaurus(GuiView & lv);
2256 Dialog * createGuiHyperlink(GuiView & lv);
2257 Dialog * createGuiVSpace(GuiView & lv);
2258 Dialog * createGuiViewSource(GuiView & lv);
2259 Dialog * createGuiWrap(GuiView & lv);
2262 Dialog * GuiView::build(string const & name)
2264 LASSERT(isValidName(name), /**/);
2266 if (name == "aboutlyx")
2267 return createGuiAbout(*this);
2268 if (name == "bibitem")
2269 return createGuiBibitem(*this);
2270 if (name == "bibtex")
2271 return createGuiBibtex(*this);
2273 return createGuiBox(*this);
2274 if (name == "branch")
2275 return createGuiBranch(*this);
2276 if (name == "changes")
2277 return createGuiChanges(*this);
2278 if (name == "character")
2279 return createGuiCharacter(*this);
2280 if (name == "citation")
2281 return createGuiCitation(*this);
2282 if (name == "document")
2283 return createGuiDocument(*this);
2284 if (name == "errorlist")
2285 return createGuiErrorList(*this);
2287 return createGuiERT(*this);
2288 if (name == "external")
2289 return createGuiExternal(*this);
2291 return createGuiShowFile(*this);
2292 if (name == "findreplace")
2293 return createGuiSearch(*this);
2294 if (name == "float")
2295 return createGuiFloat(*this);
2296 if (name == "graphics")
2297 return createGuiGraphics(*this);
2298 if (name == "include")
2299 return createGuiInclude(*this);
2300 if (name == "nomenclature")
2301 return createGuiNomenclature(*this);
2302 if (name == "label")
2303 return createGuiLabel(*this);
2305 return createGuiLog(*this);
2306 if (name == "view-source")
2307 return createGuiViewSource(*this);
2308 if (name == "mathdelimiter")
2309 return createGuiDelimiter(*this);
2310 if (name == "mathmatrix")
2311 return createGuiMathMatrix(*this);
2313 return createGuiNote(*this);
2314 if (name == "paragraph")
2315 return createGuiParagraph(*this);
2316 if (name == "prefs")
2317 return createGuiPreferences(*this);
2318 if (name == "print")
2319 return createGuiPrint(*this);
2321 return createGuiRef(*this);
2322 if (name == "sendto")
2323 return createGuiSendTo(*this);
2324 if (name == "space")
2325 return createGuiHSpace(*this);
2326 if (name == "spellchecker")
2327 return createGuiSpellchecker(*this);
2328 if (name == "symbols")
2329 return createGuiSymbols(*this);
2330 if (name == "tabular")
2331 return createGuiTabular(*this);
2332 if (name == "tabularcreate")
2333 return createGuiTabularCreate(*this);
2334 if (name == "texinfo")
2335 return createGuiTexInfo(*this);
2336 #ifdef HAVE_LIBAIKSAURUS
2337 if (name == "thesaurus")
2338 return createGuiThesaurus(*this);
2341 return createGuiToc(*this);
2343 return createGuiHyperlink(*this);
2344 if (name == "vspace")
2345 return createGuiVSpace(*this);
2347 return createGuiWrap(*this);
2348 if (name == "listings")
2349 return createGuiListings(*this);
2355 } // namespace frontend
2358 #include "GuiView_moc.cpp"