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.
18 #include "GuiImplementation.h"
19 #include "GuiWorkArea.h"
20 #include "QLMenubar.h"
21 #include "QLToolbar.h"
22 #include "QCommandBuffer.h"
23 #include "qt_helpers.h"
25 #include "frontends/Application.h"
26 #include "frontends/Gui.h"
27 #include "frontends/WorkArea.h"
29 #include "support/filetools.h"
30 #include "support/convert.h"
31 #include "support/lstrings.h"
33 #include "BufferView.h"
34 #include "bufferlist.h"
36 #include "funcrequest.h"
42 #include "MenuBackend.h"
44 #include "bufferlist.h"
47 #include <QApplication>
48 #include <QCloseEvent>
53 #include <QDesktopWidget>
54 #include <QVBoxLayout>
56 #include <boost/bind.hpp>
64 using support::FileName;
65 using support::onlyFilename;
67 using support::libFileSearch;
73 int const statusbar_timer_value = 3000;
78 class WidgetWithTabBar : public QWidget
82 WidgetWithTabBar(QWidget* w)
85 QVBoxLayout* l = new QVBoxLayout;
93 struct GuiView::GuiViewPrivate
95 typedef std::map<int, FuncRequest> FuncMap;
96 typedef std::pair<int, FuncRequest> FuncMapPair;
97 typedef std::map<string, QString> NameMap;
98 typedef std::pair<string, QString> NameMapPair;
102 WidgetWithTabBar* wt;
107 GuiViewPrivate() : wt(0), posx_offset(0), posy_offset(0)
110 unsigned int smallIconSize;
111 unsigned int normalIconSize;
112 unsigned int bigIconSize;
113 // static needed by "New Window"
114 static unsigned int lastIconSize;
116 QMenu* toolBarPopup(GuiView *parent)
118 QMenu* menu = new QMenu(parent);
119 QActionGroup *iconSizeGroup = new QActionGroup(parent);
121 QAction *smallIcons = new QAction(iconSizeGroup);
122 smallIcons->setText("Small sized icons");
123 smallIcons->setCheckable(true);
124 QObject::connect(smallIcons, SIGNAL(triggered()), parent, SLOT(smallSizedIcons()));
125 menu->addAction(smallIcons);
127 QAction *normalIcons = new QAction(iconSizeGroup);
128 normalIcons->setText("Normal sized icons");
129 normalIcons->setCheckable(true);
130 QObject::connect(normalIcons, SIGNAL(triggered()), parent, SLOT(normalSizedIcons()));
131 menu->addAction(normalIcons);
134 QAction *bigIcons = new QAction(iconSizeGroup);
135 bigIcons->setText("Big sized icons");
136 bigIcons->setCheckable(true);
137 QObject::connect(bigIcons, SIGNAL(triggered()), parent, SLOT(bigSizedIcons()));
138 menu->addAction(bigIcons);
140 int cur = parent->iconSize().width();
141 if ( cur == parent->d.smallIconSize)
142 smallIcons->setChecked(true);
143 else if (cur == parent->d.normalIconSize)
144 normalIcons->setChecked(true);
145 else if (cur == parent->d.bigIconSize)
146 bigIcons->setChecked(true);
152 unsigned int GuiView::GuiViewPrivate::lastIconSize = 0;
154 GuiView::GuiView(int id)
155 : QMainWindow(), LyXView(id), commandbuffer_(0), d(*new GuiViewPrivate)
157 // hardcode here the platform specific icon size
158 d.smallIconSize = 14; // scaling problems
159 d.normalIconSize = 20; // ok, default
160 d.bigIconSize = 26; // better for some math icons
162 //bufferview_.reset(new BufferView(this, width, height));
165 // assign an icon to main form. We do not do it under Qt/Mac,
166 // since the icon is provided in the application bundle.
167 FileName const iconname = libFileSearch("images", "lyx", "xpm");
168 if (!iconname.empty())
169 setWindowIcon(QPixmap(toqstr(iconname.absFilename())));
180 void GuiView::close()
182 QMainWindow::close();
185 QMenu* GuiView::createPopupMenu()
187 return d.toolBarPopup(this);
192 menubar_.reset(new QLMenubar(this, menubackend));
193 QObject::connect(menuBar(), SIGNAL(triggered(QAction *)),
194 this, SLOT(updateMenu(QAction *)));
196 getToolbars().init();
198 statusBar()->setSizeGripEnabled(false);
200 QObject::connect(&statusbar_timer_, SIGNAL(timeout()),
201 this, SLOT(update_view_state_qt()));
203 if (!work_area_->bufferView().buffer() && !theBufferList().empty())
204 setBuffer(theBufferList().first());
206 // make sure the buttons are disabled if needed
208 updateLayoutChoice();
213 void GuiView::saveGeometry()
216 // change the ifdef to 'geometry = normalGeometry();' only
217 // when Trolltech has fixed the broken normalGeometry on X11:
218 // http://www.trolltech.com/developer/task-tracker/index_html?id=119684+&method=entry
219 // Then also the moveEvent, resizeEvent, and the
220 // code for floatingGeometry_ can be removed;
221 // adjust GuiView::setGeometry()
223 QRect geometry = normalGeometry();
225 updateFloatingGeometry();
226 QRect geometry = floatingGeometry_;
229 // save windows size and position
230 Session & session = LyX::ref().session();
231 session.sessionInfo().save("WindowWidth", convert<string>(geometry.width()));
232 session.sessionInfo().save("WindowHeight", convert<string>(geometry.height()));
233 session.sessionInfo().save("WindowIsMaximized", (isMaximized() ? "yes" : "no"));
234 session.sessionInfo().save("IconSizeXY", convert<string>(iconSize().width()));
235 if (lyxrc.geometry_xysaved) {
236 session.sessionInfo().save("WindowPosX", convert<string>(geometry.x() + d.posx_offset));
237 session.sessionInfo().save("WindowPosY", convert<string>(geometry.y() + d.posy_offset));
239 getToolbars().saveToolbarInfo();
242 void GuiView::setGeometry(unsigned int width,
246 unsigned int iconSizeXY)
248 // use last value (not at startup)
249 if (d.lastIconSize != 0)
250 setIconSize(d.lastIconSize);
251 else if (iconSizeXY != 0)
252 setIconSize(iconSizeXY);
254 setIconSize(d.normalIconSize);
256 // only true when the -geometry option was NOT used
257 if (width != 0 && height != 0) {
258 if (posx != -1 && posy != -1) {
259 // if there are ever startup positioning problems
260 // on a virtual desktop then check the 6 lines below
261 // http://doc.trolltech.com/4.2/qdesktopwidget.html
262 QDesktopWidget& dw = *qApp->desktop();
263 QRect desk = dw.availableGeometry(dw.primaryScreen());
264 (posx >= desk.width() ? posx = 50 : true);
265 (posy >= desk.height()? posy = 50 : true);
267 // FIXME: use setGeometry only when Trolltech has fixed the qt4/X11 bug
268 QWidget::setGeometry(posx, posy, width, height);
270 resize(width, height);
274 resize(width, height);
278 setWindowState(Qt::WindowMaximized);
283 // For an unknown reason, the Window title update is not effective for
284 // the second windows up until it is shown on screen (Qt bug?).
287 // after show geometry() has changed (Qt bug?)
288 // we compensate the drift when storing the position
291 if (width != 0 && height != 0)
292 if (posx != -1 && posy != -1) {
294 d.posx_offset = posx - normalGeometry().x();
295 d.posy_offset = posy - normalGeometry().y();
298 d.posx_offset = posx - geometry().x();
299 d.posy_offset = posy - geometry().y();
306 void GuiView::updateMenu(QAction * /*action*/)
312 void GuiView::setWindowTitle(docstring const & t, docstring const & it)
314 QString title = windowTitle();
315 QString new_title = toqstr(t);
316 if (title != new_title) {
317 QMainWindow::setWindowTitle(new_title);
318 QMainWindow::setWindowIconText(toqstr(it));
323 void GuiView::addCommandBuffer(QToolBar * toolbar)
325 commandbuffer_ = new QCommandBuffer(this, *controlcommand_);
326 focus_command_buffer.connect(boost::bind(&GuiView::focus_command_widget, this));
327 toolbar->addWidget(commandbuffer_);
331 void GuiView::message(docstring const & str)
333 statusBar()->showMessage(toqstr(str));
334 statusbar_timer_.stop();
335 statusbar_timer_.start(statusbar_timer_value);
339 void GuiView::clearMessage()
341 update_view_state_qt();
344 void GuiView::setIconSize(unsigned int size)
346 d.lastIconSize = size;
347 QMainWindow::setIconSize(QSize(size, size));
350 void GuiView::smallSizedIcons()
352 setIconSize(d.smallIconSize);
355 void GuiView::normalSizedIcons()
357 setIconSize(d.normalIconSize);
360 void GuiView::bigSizedIcons()
362 setIconSize(d.bigIconSize);
366 void GuiView::focus_command_widget()
369 commandbuffer_->focus_command();
373 void GuiView::update_view_state_qt()
375 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
376 statusbar_timer_.stop();
379 void GuiView::initTab(QWidget* workarea)
381 d.wt = new WidgetWithTabBar(workarea);
382 setCentralWidget(d.wt);
383 QObject::connect(d.wt->tabbar, SIGNAL(currentChanged(int)),
384 this, SLOT(currentTabChanged(int)));
387 void GuiView::updateTab()
389 QTabBar& tb = *d.wt->tabbar;
391 // update when all is done
392 tb.blockSignals(true);
394 typedef std::vector<string> Strings;
395 Strings const names = theBufferList().getFileNames();
396 size_t n_size = names.size();
399 // show tabs only when there is more
400 // than one file opened
403 for (size_t i = 0; i != n_size; i++)
404 if (d.namemap.find(names[i]) == d.namemap.end())
405 addtab.push_back(names.at(i));
408 for(size_t i = 0; i<addtab.size(); i++)
410 QString tab_name = lyx::toqstr(onlyFilename(addtab.at(i)));
411 d.namemap.insert(GuiViewPrivate::NameMapPair(addtab.at(i), tab_name));
415 // check if all names showed by the tabs
416 // are also in the current bufferlist
421 std::map<string, QString>::iterator tabit = d.namemap.begin();
422 for (;tabit != d.namemap.end(); ++tabit)
425 for (size_t i = 0; i != n_size; i++)
426 if (tabit->first == names.at(i) && notall)
429 removetab.push_back(tabit->first);
434 for(size_t i = 0; i<removetab.size(); i++)
436 if (d.namemap.find(removetab.at(i)) != d.namemap.end())
438 tabit = d.namemap.find(removetab.at(i));
439 for (int i = 0; i < tb.count(); i++)
440 if (tb.tabText(i) == tabit->second)
445 d.namemap.erase(tabit);
450 if (removetab.size() > 0 || addtab.size() > 0)
453 tabit = d.namemap.begin();
454 for (;tabit != d.namemap.end(); ++tabit)
456 QTabBar& tb = *d.wt->tabbar;
457 for (int i = 0; i < tb.count(); i++)
459 if (tb.tabText(i) == tabit->second)
461 FuncRequest func(LFUN_BUFFER_SWITCH, tabit->first);
462 d.funcmap.insert(GuiViewPrivate::FuncMapPair(i, func));
470 if (view()->buffer())
472 string cur_title = view()->buffer()->fileName();
473 if (d.namemap.find(cur_title) != d.namemap.end())
475 QString tabname = d.namemap.find(cur_title)->second;
476 for (int i = 0; i < tb.count(); i++)
477 if (tb.tabText(i) == tabname)
479 tb.setCurrentIndex(i);
485 tb.blockSignals(false);
489 void GuiView::currentTabChanged (int index)
491 std::map<int, FuncRequest>::const_iterator it = d.funcmap.find(index);
492 if (it != d.funcmap.end())
493 activated(it->second);
497 void GuiView::updateStatusBar()
499 // let the user see the explicit message
500 if (statusbar_timer_.isActive())
503 statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
507 void GuiView::activated(FuncRequest const & func)
513 bool GuiView::hasFocus() const
515 return qApp->activeWindow() == this;
519 void GuiView::updateFloatingGeometry()
522 floatingGeometry_ = QRect(x(), y(), width(), height());
526 void GuiView::resizeEvent(QResizeEvent *)
528 updateFloatingGeometry();
532 void GuiView::moveEvent(QMoveEvent *)
534 updateFloatingGeometry();
538 void GuiView::closeEvent(QCloseEvent * close_event)
540 GuiImplementation & gui
541 = static_cast<GuiImplementation &>(theApp->gui());
543 vector<int> const & view_ids = gui.viewIds();
545 if (view_ids.size() == 1 && !theBufferList().quitWriteAll()) {
546 close_event->ignore();
551 hide(); // don't remove this hide, it prevents a crash on exit
552 gui.unregisterView(this);
558 QMainWindow::setWindowTitle(qt_("LyX"));
560 updateFloatingGeometry();
564 void GuiView::busy(bool yes)
566 static_cast<GuiWorkArea *>(work_area_)->setUpdatesEnabled(!yes);
569 work_area_->stopBlinkingCursor();
570 QApplication::setOverrideCursor(Qt::WaitCursor);
573 work_area_->startBlinkingCursor();
574 QApplication::restoreOverrideCursor();
579 Toolbars::ToolbarPtr GuiView::makeToolbar(ToolbarBackend::Toolbar const & tbb)
581 QLToolbar * Tb = new QLToolbar(tbb, *this);
582 //static QLToolbar * lastTb = 0;
584 if (tbb.flags & ToolbarBackend::TOP) {
585 addToolBar(Qt::TopToolBarArea, Tb);
586 addToolBarBreak(Qt::TopToolBarArea);
588 if (tbb.flags & ToolbarBackend::BOTTOM) {
589 addToolBar(Qt::BottomToolBarArea, Tb);
592 // http://www.trolltech.com/developer/task-tracker/index_html?id=137015&method=entry
593 // Doesn't work because the toolbar will evtl. be hidden.
595 insertToolBarBreak(lastTb);
599 if (tbb.flags & ToolbarBackend::LEFT) {
600 addToolBar(Qt::LeftToolBarArea, Tb);
602 if (tbb.flags & ToolbarBackend::RIGHT) {
603 addToolBar(Qt::RightToolBarArea, Tb);
606 return Toolbars::ToolbarPtr(Tb);
609 } // namespace frontend
612 #include "GuiView_moc.cpp"