]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.cpp
reduce #includes
[lyx.git] / src / frontends / qt4 / GuiView.cpp
1 /**
2  * \file GuiView.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author John Levon
8  * \author Abdelrazak Younes
9  * \author Peter Kümmel
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "GuiView.h"
17
18 #include "GuiImplementation.h"
19 #include "GuiWorkArea.h"
20 #include "GuiKeySymbol.h"
21 #include "GuiMenubar.h"
22 #include "GuiToolbar.h"
23 #include "qt_helpers.h"
24
25 #include "frontends/Application.h"
26 #include "frontends/Dialogs.h"
27 #include "frontends/Gui.h"
28 #include "frontends/WorkArea.h"
29
30 #include "support/filetools.h"
31 #include "support/convert.h"
32 #include "support/lstrings.h"
33 #include "support/os.h"
34
35 #include "Buffer.h"
36 #include "BufferView.h"
37 #include "BufferList.h"
38 #include "callback.h"
39 #include "debug.h"
40 #include "FuncRequest.h"
41 #include "LyX.h"
42 #include "LyXFunc.h"
43 #include "LyXRC.h"
44 #include "MenuBackend.h"
45 #include "Session.h"
46 #include "version.h"
47
48 #include <QAction>
49 #include <QApplication>
50 #include <QCloseEvent>
51 #include <QDesktopWidget>
52 #include <QDragEnterEvent>
53 #include <QDropEvent>
54 #include <QList>
55 #include <QMimeData>
56 #include <QPainter>
57 #include <QPixmap>
58 #include <QPushButton>
59 #include <QStackedWidget>
60 #include <QStatusBar>
61 #include <QTabBar>
62 #include <QToolBar>
63 #include <QTabWidget>
64 #include <QUrl>
65
66 using std::endl;
67 using std::string;
68 using std::vector;
69
70 namespace lyx {
71
72 using support::FileName;
73 using support::libFileSearch;
74 using support::makeDisplayPath;
75
76 namespace frontend {
77
78 namespace {
79
80 int const statusbar_timer_value = 3000;
81
82 class BackgroundWidget : public QWidget
83 {
84 public:
85         BackgroundWidget(QString const & file, QString const & text)
86         {
87                 splash_ = new QPixmap(file);
88                 if (!splash_) {
89                         lyxerr << "could not load splash screen: '" << fromqstr(file) << "'" << endl;
90                         return;
91                 }
92
93                 QPainter pain(splash_);
94                 pain.setPen(QColor(255, 255, 0));
95                 QFont font;
96                 // The font used to display the version info
97                 font.setStyleHint(QFont::SansSerif);
98                 font.setWeight(QFont::Bold);
99                 font.setPointSize(convert<int>(lyxrc.font_sizes[Font::SIZE_LARGE]));
100                 pain.setFont(font);
101                 pain.drawText(260, 270, text);
102         }
103
104         void paintEvent(QPaintEvent *)
105         {
106                 if (!splash_)
107                         return;
108
109                 int x = (width() - splash_->width()) / 2;
110                 int y = (height() - splash_->height()) / 2;
111                 QPainter pain(this);
112                 pain.drawPixmap(x, y, *splash_);
113         }
114
115 private:
116         QPixmap * splash_;
117 };
118
119
120 class TabWidget : public QTabWidget {
121 public:
122         void showBar(bool show) { tabBar()->setVisible(show); }
123 };
124
125
126 } // namespace anon
127
128
129 struct GuiViewBase::GuiViewPrivate
130 {
131         string cur_title;
132
133         int posx_offset;
134         int posy_offset;
135
136         TabWidget * tab_widget_;
137         QStackedWidget * stack_widget_;
138         BackgroundWidget * bg_widget_;
139         /// view's menubar
140         GuiMenubar * menubar_;
141
142         GuiViewPrivate() : posx_offset(0), posy_offset(0) {}
143
144         unsigned int smallIconSize;
145         unsigned int normalIconSize;
146         unsigned int bigIconSize;
147         // static needed by "New Window"
148         static unsigned int lastIconSize;
149
150         QMenu * toolBarPopup(GuiViewBase * parent)
151         {
152                 // FIXME: translation
153                 QMenu * menu = new QMenu(parent);
154                 QActionGroup * iconSizeGroup = new QActionGroup(parent);
155
156                 QAction * smallIcons = new QAction(iconSizeGroup);
157                 smallIcons->setText(qt_("Small-sized icons"));
158                 smallIcons->setCheckable(true);
159                 QObject::connect(smallIcons, SIGNAL(triggered()), parent, SLOT(smallSizedIcons()));
160                 menu->addAction(smallIcons);
161
162                 QAction * normalIcons = new QAction(iconSizeGroup);
163                 normalIcons->setText(qt_("Normal-sized icons"));
164                 normalIcons->setCheckable(true);
165                 QObject::connect(normalIcons, SIGNAL(triggered()), parent, SLOT(normalSizedIcons()));
166                 menu->addAction(normalIcons);
167
168                 QAction * bigIcons = new QAction(iconSizeGroup);
169                 bigIcons->setText(qt_("Big-sized icons"));
170                 bigIcons->setCheckable(true);
171                 QObject::connect(bigIcons, SIGNAL(triggered()), parent, SLOT(bigSizedIcons()));
172                 menu->addAction(bigIcons);
173
174                 unsigned int cur = parent->iconSize().width();
175                 if ( cur == parent->d.smallIconSize)
176                         smallIcons->setChecked(true);
177                 else if (cur == parent->d.normalIconSize)
178                         normalIcons->setChecked(true);
179                 else if (cur == parent->d.bigIconSize)
180                         bigIcons->setChecked(true);
181
182                 return menu;
183         }
184
185         void initBackground()
186         {
187                 bg_widget_ = 0;
188                 LYXERR(Debug::GUI) << "show banner: " << lyxrc.show_banner << endl;
189                 /// The text to be written on top of the pixmap
190                 QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
191                 FileName const file = support::libFileSearch("images", "banner", "png");
192                 if (file.empty())
193                         return;
194
195                 bg_widget_ = new BackgroundWidget(toqstr(file.absFilename()), text);
196         }
197
198         void setBackground()
199         {
200                 if (!bg_widget_)
201                         return;
202
203                 stack_widget_->setCurrentWidget(bg_widget_);
204                 bg_widget_->setUpdatesEnabled(true);
205         }
206 };
207
208
209 unsigned int GuiViewBase::GuiViewPrivate::lastIconSize = 0;
210
211
212 GuiViewBase::GuiViewBase(int id)
213         : QMainWindow(), LyXView(id), quitting_by_menu_(false),
214           d(*new GuiViewPrivate)
215 {
216         // Qt bug? signal lastWindowClosed does not work
217         setAttribute(Qt::WA_QuitOnClose, false);
218         setAttribute(Qt::WA_DeleteOnClose, true);
219
220         // hardcode here the platform specific icon size
221         d.smallIconSize = 14;   // scaling problems
222         d.normalIconSize = 20;  // ok, default
223         d.bigIconSize = 26;             // better for some math icons
224
225 #ifndef Q_WS_MACX
226         // assign an icon to main form. We do not do it under Qt/Mac,
227         // since the icon is provided in the application bundle.
228         FileName const iconname = libFileSearch("images", "lyx", "png");
229         if (!iconname.empty())
230                 setWindowIcon(QPixmap(toqstr(iconname.absFilename())));
231 #endif
232
233         d.tab_widget_ = new TabWidget;
234
235         QPushButton * closeTabButton = new QPushButton(this);
236         FileName const file = support::libFileSearch("images", "closetab", "png");
237         if (!file.empty()) {
238                 QPixmap pm(toqstr(file.absFilename()));
239                 closeTabButton->setIcon(QIcon(pm));
240                 closeTabButton->setMaximumSize(pm.size());
241                 closeTabButton->setFlat(true);
242         } else {
243                 closeTabButton->setText("Close");
244         }
245         closeTabButton->setCursor(Qt::ArrowCursor);
246         closeTabButton->setToolTip(tr("Close tab"));
247         closeTabButton->setEnabled(true);
248
249         QObject::connect(d.tab_widget_, SIGNAL(currentChanged(int)),
250                         this, SLOT(currentTabChanged(int)));
251         QObject::connect(closeTabButton, SIGNAL(clicked()),
252                         this, SLOT(closeCurrentTab()));
253
254         d.tab_widget_->setCornerWidget(closeTabButton);
255 #if QT_VERSION >= 0x040200
256         d.tab_widget_->setUsesScrollButtons(true);
257 #endif
258
259         d.initBackground();
260         if (d.bg_widget_) {
261                 LYXERR(Debug::GUI) << "stack widget!" << endl;
262                 d.stack_widget_ = new QStackedWidget;
263                 d.stack_widget_->addWidget(d.bg_widget_);
264                 d.stack_widget_->addWidget(d.tab_widget_);
265                 setCentralWidget(d.stack_widget_);
266         } else {
267                 d.stack_widget_ = 0;
268                 setCentralWidget(d.tab_widget_);
269         }
270
271         // For Drag&Drop.
272         setAcceptDrops(true);
273 }
274
275
276 GuiViewBase::~GuiViewBase()
277 {
278         delete d.menubar_;
279         delete &d;
280 }
281
282
283 void GuiViewBase::close()
284 {
285         quitting_by_menu_ = true;
286         QMainWindow::close();
287         quitting_by_menu_ = false;
288 }
289
290
291 void GuiViewBase::setFocus()
292 {
293         if (d.tab_widget_->count())
294                 d.tab_widget_->currentWidget()->setFocus();
295 }
296
297
298 QMenu* GuiViewBase::createPopupMenu()
299 {
300         return d.toolBarPopup(this);
301 }
302
303
304 void GuiViewBase::init()
305 {
306         d.menubar_ = new GuiMenubar(this, menubackend);
307
308         toolbars_->init();
309
310         statusBar()->setSizeGripEnabled(true);
311
312         QObject::connect(&statusbar_timer_, SIGNAL(timeout()),
313                 this, SLOT(update_view_state_qt()));
314
315         if (d.stack_widget_)
316                 d.stack_widget_->setCurrentWidget(d.bg_widget_);
317 }
318
319
320 void GuiViewBase::closeEvent(QCloseEvent * close_event)
321 {
322         // we may have been called through the close window button
323         // which bypasses the LFUN machinery.
324         if (!quitting_by_menu_ && theApp()->gui().viewIds().size() == 1) {
325                 if (!theBufferList().quitWriteAll()) {
326                         close_event->ignore();
327                         return;
328                 }
329         }
330
331         // Make sure that no LFUN use this close to be closed View.
332         theLyXFunc().setLyXView(0);
333         // Make sure the timer time out will not trigger a statusbar update.
334         statusbar_timer_.stop();
335
336         theApp()->gui().unregisterView(id());
337         if (!theApp()->gui().viewIds().empty()) {
338                 // Just close the window and do nothing else if this is not the
339                 // last window.
340                 close_event->accept();
341                 return;
342         }
343
344         quitting = true;
345
346         // this is the place where we leave the frontend.
347         // it is the only point at which we start quitting.
348         saveGeometry();
349         close_event->accept();
350         // quit the event loop
351         qApp->quit();
352 }
353
354
355 void GuiViewBase::dragEnterEvent(QDragEnterEvent * event)
356 {
357         if (event->mimeData()->hasUrls())
358                 event->accept();
359         /// \todo Ask lyx-devel is this is enough:
360         /// if (event->mimeData()->hasFormat("text/plain"))
361         ///     event->acceptProposedAction();
362 }
363
364
365 void GuiViewBase::dropEvent(QDropEvent* event)
366 {
367         QList<QUrl> files = event->mimeData()->urls();
368         if (files.isEmpty())
369                 return;
370
371         LYXERR(Debug::GUI) << BOOST_CURRENT_FUNCTION
372                 << " got URLs!" << endl;
373         for (int i = 0; i != files.size(); ++i) {
374                 string const file = support::os::internal_path(fromqstr(
375                         files.at(i).toLocalFile()));
376                 if (!file.empty())
377                         dispatch(FuncRequest(LFUN_FILE_OPEN, file));
378         }
379 }
380
381
382 void GuiViewBase::saveGeometry()
383 {
384         static bool done = false;
385         if (done)
386                 return;
387         else
388                 done = true;
389
390         // FIXME:
391         // change the ifdef to 'geometry = normalGeometry();' only
392         // when Trolltech has fixed the broken normalGeometry on X11:
393         // http://www.trolltech.com/developer/task-tracker/index_html?id=119684+&method=entry
394         // Then also the moveEvent, resizeEvent, and the
395         // code for floatingGeometry_ can be removed;
396         // adjust GuiViewBase::setGeometry()
397
398         QRect normal_geometry;
399         int maximized;
400 #ifdef Q_WS_WIN
401         normal_geometry = normalGeometry();
402         if (isMaximized()) {
403                 maximized = CompletelyMaximized;
404         } else {
405                 maximized = NotMaximized;
406         }
407 #else
408         normal_geometry = updateFloatingGeometry();
409
410         QDesktopWidget& dw = *qApp->desktop();
411         QRect desk = dw.availableGeometry(dw.primaryScreen());
412         // Qt bug on Linux: load completely maximized, vert max. save-> frameGeometry().height() is wrong
413         if (isMaximized() && desk.width() <= frameGeometry().width() && desk.height() <= frameGeometry().height()) {
414                 maximized = CompletelyMaximized;
415                 // maximizing does not work when the window is allready hor. or vert. maximized
416                 // Tested only on KDE
417                 int dh = frameGeometry().height() - height();
418                 if (desk.height() <= normal_geometry.height() + dh)
419                         normal_geometry.setHeight(normal_geometry.height() - 1);
420                 int dw = frameGeometry().width() - width();
421                 if (desk.width() <= normal_geometry.width() + dw)
422                         normal_geometry.setWidth(normal_geometry.width() - 1);
423         } else if (desk.height() <= frameGeometry().height()) {
424                 maximized = VerticallyMaximized;
425         } else if (desk.width() <= frameGeometry().width()) {
426                 maximized = HorizontallyMaximized;
427         } else {
428                 maximized = NotMaximized;
429         }
430
431
432 #endif
433         // save windows size and position
434         Session & session = LyX::ref().session();
435         session.sessionInfo().save("WindowWidth", convert<string>(normal_geometry.width()));
436         session.sessionInfo().save("WindowHeight", convert<string>(normal_geometry.height()));
437         session.sessionInfo().save("WindowMaximized", convert<string>(maximized));
438         session.sessionInfo().save("IconSizeXY", convert<string>(iconSize().width()));
439         if (lyxrc.geometry_xysaved) {
440                 session.sessionInfo().save("WindowPosX", convert<string>(normal_geometry.x() + d.posx_offset));
441                 session.sessionInfo().save("WindowPosY", convert<string>(normal_geometry.y() + d.posy_offset));
442         }
443         toolbars_->saveToolbarInfo();
444 }
445
446
447 void GuiViewBase::setGeometry(unsigned int width,
448                           unsigned int height,
449                           int posx, int posy,
450                           int maximized,
451                           unsigned int iconSizeXY,
452                           const string & geometryArg)
453 {
454         // use last value (not at startup)
455         if (d.lastIconSize != 0)
456                 setIconSize(d.lastIconSize);
457         else if (iconSizeXY != 0)
458                 setIconSize(iconSizeXY);
459         else
460                 setIconSize(d.normalIconSize);
461
462         // only true when the -geometry option was NOT used
463         if (width != 0 && height != 0) {
464                 if (posx != -1 && posy != -1) {
465                         // if there are startup positioning problems:
466                         // http://doc.trolltech.com/4.2/qdesktopwidget.html
467                         QDesktopWidget& dw = *qApp->desktop();
468                         if (dw.isVirtualDesktop()) {
469                                 if(!dw.geometry().contains(posx, posy)) {
470                                         posx = 50;
471                                         posy = 50;
472                                 }
473                         } else {
474                                 // Which system doesn't use a virtual desktop?
475                                 // TODO save also last screen number and check if it is still availabe.
476                         }
477 #ifdef Q_WS_WIN
478                         // FIXME: use setGeometry only when Trolltech has fixed the qt4/X11 bug
479                         QWidget::setGeometry(posx, posy, width, height);
480 #else
481                         resize(width, height);
482                         move(posx, posy);
483 #endif
484                 } else {
485                         resize(width, height);
486                 }
487
488                 // remember original size
489                 floatingGeometry_ = QRect(posx, posy, width, height);
490
491                 if (maximized != NotMaximized) {
492                         if (maximized == CompletelyMaximized) {
493                                 setWindowState(Qt::WindowMaximized);
494                         } else {
495 #ifndef Q_WS_WIN
496                                 // TODO How to set by the window manager?
497                                 //      setWindowState(Qt::WindowVerticallyMaximized);
498                                 //      is not possible
499                                 QDesktopWidget& dw = *qApp->desktop();
500                                 QRect desk = dw.availableGeometry(dw.primaryScreen());
501                                 if (maximized == VerticallyMaximized)
502                                         resize(width, desk.height());
503                                 if (maximized == HorizontallyMaximized)
504                                         resize(desk.width(), height);
505 #endif
506                         }
507                 }
508         }
509         else
510         {
511                 // FIXME: move this code into parse_geometry() (LyX.cpp)
512 #ifdef Q_WS_WIN
513                 int x, y;
514                 int w, h;
515                 QRegExp re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)([+-][0-9]*)){0,1}" );
516                 re.indexIn(toqstr(geometryArg.c_str()));
517                 w = re.cap(1).toInt();
518                 h = re.cap(2).toInt();
519                 x = re.cap(3).toInt();
520                 y = re.cap(4).toInt();
521                 QWidget::setGeometry( x, y, w, h );
522 #else
523                 // silence warning
524                 (void)geometryArg;
525 #endif
526         }
527         
528         d.setBackground();
529         
530         show();
531
532         // For an unknown reason, the Window title update is not effective for
533         // the second windows up until it is shown on screen (Qt bug?).
534         updateWindowTitle();
535
536         // after show geometry() has changed (Qt bug?)
537         // we compensate the drift when storing the position
538         d.posx_offset = 0;
539         d.posy_offset = 0;
540         if (width != 0 && height != 0)
541                 if (posx != -1 && posy != -1) {
542 #ifdef Q_WS_WIN
543                         d.posx_offset = posx - normalGeometry().x();
544                         d.posy_offset = posy - normalGeometry().y();
545 #else
546 #ifndef Q_WS_MACX
547                         if (maximized == NotMaximized) {
548                                 d.posx_offset = posx - geometry().x();
549                                 d.posy_offset = posy - geometry().y();
550                         }
551 #endif
552 #endif
553                 }
554 }
555
556
557 void GuiViewBase::setWindowTitle(docstring const & t, docstring const & it)
558 {
559         QString title = windowTitle();
560         QString new_title = toqstr(t);
561         if (title != new_title) {
562                 QMainWindow::setWindowTitle(new_title);
563                 QMainWindow::setWindowIconText(toqstr(it));
564         }
565 }
566
567
568 void GuiViewBase::message(docstring const & str)
569 {
570         statusBar()->showMessage(toqstr(str));
571         statusbar_timer_.stop();
572         statusbar_timer_.start(statusbar_timer_value);
573 }
574
575
576 void GuiViewBase::clearMessage()
577 {
578         update_view_state_qt();
579 }
580
581
582 void GuiViewBase::setIconSize(unsigned int size)
583 {
584         d.lastIconSize = size;
585         QMainWindow::setIconSize(QSize(size, size));
586 }
587
588
589 void GuiViewBase::smallSizedIcons()
590 {
591         setIconSize(d.smallIconSize);
592 }
593
594
595 void GuiViewBase::normalSizedIcons()
596 {
597         setIconSize(d.normalIconSize);
598 }
599
600
601 void GuiViewBase::bigSizedIcons()
602 {
603         setIconSize(d.bigIconSize);
604 }
605
606
607 void GuiViewBase::update_view_state_qt()
608 {
609         if (!hasFocus())
610                 return;
611         theLyXFunc().setLyXView(this);
612         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
613         statusbar_timer_.stop();
614 }
615
616
617 void GuiViewBase::closeCurrentTab()
618 {
619         dispatch(FuncRequest(LFUN_BUFFER_CLOSE));
620 }
621
622
623 void GuiViewBase::currentTabChanged(int i)
624 {
625         disconnectBuffer();
626         disconnectBufferView();
627         GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(d.tab_widget_->widget(i));
628         BOOST_ASSERT(wa);
629         BufferView & bv = wa->bufferView();
630         connectBufferView(bv);
631         connectBuffer(bv.buffer());
632         bv.updateMetrics(false);
633         bv.cursor().fixIfBroken();
634         wa->setUpdatesEnabled(true);
635         wa->redraw();
636         wa->setFocus();
637
638         updateToc();
639         // Buffer-dependent dialogs should be updated or
640         // hidden. This should go here because some dialogs (eg ToC)
641         // require bv_->text.
642         getDialogs().updateBufferDependent(true);
643         updateToolbars();
644         updateLayoutChoice();
645         updateWindowTitle();
646         updateStatusBar();
647
648         LYXERR(Debug::GUI) << "currentTabChanged " << i
649                 << "File" << bv.buffer().fileName() << endl;
650 }
651
652
653 void GuiViewBase::updateStatusBar()
654 {
655         // let the user see the explicit message
656         if (statusbar_timer_.isActive())
657                 return;
658
659         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
660 }
661
662
663 void GuiViewBase::activated(FuncRequest const & func)
664 {
665         dispatch(func);
666 }
667
668
669 bool GuiViewBase::hasFocus() const
670 {
671         return qApp->activeWindow() == this;
672 }
673
674
675 QRect  GuiViewBase::updateFloatingGeometry()
676 {
677         QDesktopWidget& dw = *qApp->desktop();
678         QRect desk = dw.availableGeometry(dw.primaryScreen());
679         // remember only non-maximized sizes
680         if (!isMaximized() && desk.width() > frameGeometry().width() && desk.height() > frameGeometry().height()) {
681                 floatingGeometry_ = QRect(x(), y(), width(), height());
682         }
683         return floatingGeometry_;
684 }
685
686
687 void GuiViewBase::resizeEvent(QResizeEvent *)
688 {
689         updateFloatingGeometry();
690 }
691
692
693 void GuiViewBase::moveEvent(QMoveEvent *)
694 {
695         updateFloatingGeometry();
696 }
697
698
699 bool GuiViewBase::event(QEvent * e)
700 {
701         switch (e->type())
702         {
703         // Useful debug code:
704         //case QEvent::WindowActivate:
705         //case QEvent::ActivationChange:
706         //case QEvent::WindowDeactivate:
707         //case QEvent::Paint:
708         //case QEvent::Enter:
709         //case QEvent::Leave:
710         //case QEvent::HoverEnter:
711         //case QEvent::HoverLeave:
712         //case QEvent::HoverMove:
713         //case QEvent::StatusTip:
714         //case QEvent::DragEnter:
715         //case QEvent::DragLeave:
716         //case QEvent::Drop:
717         //      break;
718
719         case QEvent::ShortcutOverride: {
720                 QKeyEvent * ke = static_cast<QKeyEvent*>(e);
721                 if (d.tab_widget_->count() == 0) {
722                         theLyXFunc().setLyXView(this);
723                         KeySymbol sym;
724                         setKeySymbol(&sym, ke);
725                         theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
726                         e->accept();
727                         return true;
728                 }
729                 if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
730                         KeySymbol sym;
731                         setKeySymbol(&sym, ke);
732                         currentWorkArea()->processKeySym(sym, key_modifier::none);
733                         e->accept();
734                         return true;
735                 }
736         }
737         default:
738                 return QMainWindow::event(e);
739         }
740 }
741
742
743 bool GuiViewBase::focusNextPrevChild(bool /*next*/)
744 {
745         setFocus();
746         return true;
747 }
748
749
750 void GuiViewBase::showView()
751 {
752         QMainWindow::setWindowTitle(qt_("LyX"));
753         QMainWindow::show();
754         updateFloatingGeometry();
755 }
756
757
758 void GuiViewBase::busy(bool yes)
759 {
760         if (d.tab_widget_->count()) {
761                 GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(d.tab_widget_->currentWidget());
762                 BOOST_ASSERT(wa);
763                 wa->setUpdatesEnabled(!yes);
764                 if (yes)
765                         wa->stopBlinkingCursor();
766                 else
767                         wa->startBlinkingCursor();
768         }
769
770         if (yes)
771                 QApplication::setOverrideCursor(Qt::WaitCursor);
772         else
773                 QApplication::restoreOverrideCursor();
774 }
775
776
777 Toolbar * GuiViewBase::makeToolbar(ToolbarInfo const & tbinfo, bool newline)
778 {
779         GuiToolbar * toolBar = new GuiToolbar(tbinfo, *this);
780
781         if (tbinfo.flags & ToolbarInfo::TOP) {
782                 if (newline)
783                         addToolBarBreak(Qt::TopToolBarArea);
784                 addToolBar(Qt::TopToolBarArea, toolBar);
785         }
786
787         if (tbinfo.flags & ToolbarInfo::BOTTOM) {
788 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
789 #if (QT_VERSION >= 0x040202)
790                 if (newline)
791                         addToolBarBreak(Qt::BottomToolBarArea);
792 #endif
793                 addToolBar(Qt::BottomToolBarArea, toolBar);
794         }
795
796         if (tbinfo.flags & ToolbarInfo::LEFT) {
797 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
798 #if (QT_VERSION >= 0x040202)
799                 if (newline)
800                         addToolBarBreak(Qt::LeftToolBarArea);
801 #endif
802                 addToolBar(Qt::LeftToolBarArea, toolBar);
803         }
804
805         if (tbinfo.flags & ToolbarInfo::RIGHT) {
806 // Qt < 4.2.2 cannot handle ToolBarBreak on non-TOP dock.
807 #if (QT_VERSION >= 0x040202)
808                 if (newline)
809                         addToolBarBreak(Qt::RightToolBarArea);
810 #endif
811                 addToolBar(Qt::RightToolBarArea, toolBar);
812         }
813
814         // The following does not work so I cannot restore to exact toolbar location
815         /*
816         ToolbarSection::ToolbarInfo & tbinfo = LyX::ref().session().toolbars().load(tbinfo.name);
817         toolBar->move(tbinfo.posx, tbinfo.posy);
818         */
819
820         return toolBar;
821 }
822
823
824 WorkArea * GuiViewBase::workArea(Buffer & buffer)
825 {
826         for (int i = 0; i != d.tab_widget_->count(); ++i) {
827                 GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(d.tab_widget_->widget(i));
828                 BOOST_ASSERT(wa);
829                 if (&wa->bufferView().buffer() == &buffer)
830                         return wa;
831         }
832         return 0;
833 }
834
835
836 WorkArea * GuiViewBase::addWorkArea(Buffer & buffer)
837 {
838         GuiWorkArea * wa = new GuiWorkArea(buffer, *this);
839         wa->setUpdatesEnabled(false);
840         d.tab_widget_->addTab(wa, toqstr(makeDisplayPath(buffer.fileName(), 30)));
841         wa->bufferView().updateMetrics(false);
842         if (d.stack_widget_)
843                 d.stack_widget_->setCurrentWidget(d.tab_widget_);
844         // Hide tabbar if there's only one tab.
845         d.tab_widget_->showBar(d.tab_widget_->count() > 1);
846         return wa;
847 }
848
849
850 WorkArea * GuiViewBase::currentWorkArea()
851 {
852         if (d.tab_widget_->count() == 0)
853                 return 0;
854         BOOST_ASSERT(dynamic_cast<GuiWorkArea *>(d.tab_widget_->currentWidget()));
855         return dynamic_cast<GuiWorkArea *>(d.tab_widget_->currentWidget());
856 }
857
858
859 WorkArea const * GuiViewBase::currentWorkArea() const
860 {
861         if (d.tab_widget_->count() == 0)
862                 return 0;
863         BOOST_ASSERT(dynamic_cast<GuiWorkArea const *>(d.tab_widget_->currentWidget()));
864         return dynamic_cast<GuiWorkArea const *>(d.tab_widget_->currentWidget());
865 }
866
867
868 void GuiViewBase::setCurrentWorkArea(WorkArea * work_area)
869 {
870         BOOST_ASSERT(work_area);
871
872         // Changing work area can result from opening a file so
873         // update the toc in any case.
874         updateToc();
875
876         GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(work_area);
877         BOOST_ASSERT(wa);
878         if (wa != d.tab_widget_->currentWidget())
879                 // Switch to the work area.
880                 d.tab_widget_->setCurrentWidget(wa);
881         else
882                 // Make sure the work area is up to date.
883                 currentTabChanged(d.tab_widget_->currentIndex());
884         wa->setFocus();
885 }
886
887
888 void GuiViewBase::removeWorkArea(WorkArea * work_area)
889 {
890         BOOST_ASSERT(work_area);
891         if (work_area == currentWorkArea()) {
892                 disconnectBuffer();
893                 disconnectBufferView();
894         }
895
896         // removing a work area often results from closing a file so
897         // update the toc in any case.
898         updateToc();
899
900         GuiWorkArea * gwa = dynamic_cast<GuiWorkArea *>(work_area);
901         gwa->setUpdatesEnabled(false);
902         BOOST_ASSERT(gwa);
903         int index = d.tab_widget_->indexOf(gwa);
904         d.tab_widget_->removeTab(index);
905
906         delete gwa;
907
908         if (d.tab_widget_->count()) {
909                 // make sure the next work area is enabled.
910                 d.tab_widget_->currentWidget()->setUpdatesEnabled(true);
911                 // Hide tabbar if there's only one tab.
912                 d.tab_widget_->showBar(d.tab_widget_->count() > 1);
913                 return;
914         }
915
916         getDialogs().hideBufferDependent();
917         if (d.stack_widget_) {
918                 // No more work area, switch to the background widget.
919                 d.setBackground();
920         }
921 }
922
923
924 void GuiViewBase::showMiniBuffer(bool visible)
925 {
926         Toolbar * t = toolbars_->display("minibuffer", visible);
927         if (t)
928                 t->focusCommandBuffer();
929 }
930
931
932 void GuiViewBase::openMenu(docstring const & name)
933 {
934         d.menubar_->openByName(name);
935 }
936
937 } // namespace frontend
938 } // namespace lyx
939
940 #include "GuiView_moc.cpp"