]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiView.C
add missing header
[lyx.git] / src / frontends / qt4 / GuiView.C
1 /**
2  * \file GuiView.C
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  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiView.h"
16
17 #include "GuiImplementation.h"
18 #include "GuiWorkArea.h"
19 #include "QLMenubar.h"
20 #include "QLToolbar.h"
21 #include "QCommandBuffer.h"
22 #include "qt_helpers.h"
23
24 #include "frontends/Application.h"
25 #include "frontends/Gui.h"
26 #include "frontends/WorkArea.h"
27
28 #include "support/filetools.h"
29 #include "support/convert.h"
30 #include "support/lstrings.h"
31
32 #include "BufferView.h"
33 #include "bufferlist.h"
34 #include "debug.h"
35 #include "funcrequest.h"
36 #include "lyx_cb.h"
37 #include "lyxrc.h"
38 #include "lyx_main.h"
39 #include "session.h"
40 #include "lyxfunc.h"
41 #include "MenuBackend.h"
42 #include "buffer.h"
43 #include "bufferlist.h"
44
45 #include <QAction>
46 #include <QApplication>
47 #include <QCloseEvent>
48 #include <QPixmap>
49 #include <QStatusBar>
50 #include <QToolBar>
51 #include <QTabBar>
52 #include <QDesktopWidget>
53
54 #include <boost/bind.hpp>
55
56 using std::endl;
57 using std::string;
58 using std::vector;
59
60 using lyx::support::onlyFilename;
61
62 namespace lyx {
63
64 using support::subst;
65 using support::libFileSearch;
66
67 namespace frontend {
68
69 namespace {
70
71 int const statusbar_timer_value = 3000;
72
73 } // namespace anon
74
75
76 class WidgetWithTabBar : public QWidget
77 {
78 public:
79         QTabBar* tabbar;
80         WidgetWithTabBar(QWidget* w)
81         {
82                 tabbar = new QTabBar;
83                 QVBoxLayout* l = new QVBoxLayout;
84                 l->addWidget(tabbar);
85                 l->addWidget(w);
86                 l->setMargin(0);
87                 setLayout(l);
88         }
89 };
90
91 struct GuiView::GuiViewPrivate
92 {
93         typedef std::map<int, FuncRequest> FuncMap;
94         typedef std::pair<int, FuncRequest> FuncMapPair;
95         typedef std::map<string, QString> NameMap;
96         typedef std::pair<string, QString> NameMapPair;
97
98         FuncMap funcmap;
99         NameMap namemap;
100         WidgetWithTabBar* wt;
101
102         GuiViewPrivate()
103         {}
104 };
105
106 GuiView::GuiView(int id)
107         : QMainWindow(), LyXView(id), commandbuffer_(0), d(*new GuiViewPrivate)
108 {
109         setAttribute(Qt::WA_DeleteOnClose, true);
110         setAttribute(Qt::WA_QuitOnClose, true);
111
112 //      setToolButtonStyle(Qt::ToolButtonIconOnly);
113 //      setIconSize(QSize(12,12));
114
115 //      bufferview_.reset(new BufferView(this, width, height));
116
117 #ifndef Q_WS_MACX
118         //  assign an icon to main form. We do not do it under Qt/Mac,
119         //  since the icon is provided in the application bundle.
120         string const iconname = libFileSearch("images", "lyx", "xpm");
121         if (!iconname.empty())
122                 setWindowIcon(QPixmap(toqstr(iconname)));
123 #endif
124 }
125
126
127 GuiView::~GuiView()
128 {
129         delete &d;
130 }
131
132
133 void GuiView::close()
134 {
135         QMainWindow::close();
136 }
137
138
139 void GuiView::init()
140 {
141         menubar_.reset(new QLMenubar(this, menubackend));
142         QObject::connect(menuBar(), SIGNAL(triggered(QAction *)),
143                 this, SLOT(updateMenu(QAction *)));
144
145         getToolbars().init();
146
147         statusBar()->setSizeGripEnabled(false);
148
149         QObject::connect(&statusbar_timer_, SIGNAL(timeout()),
150                 this, SLOT(update_view_state_qt()));
151
152         // make sure the buttons are disabled if needed
153         updateToolbars();
154         updateLayoutChoice();
155         updateMenubar();
156 }
157
158
159 void GuiView::saveGeometry()
160 {
161         // FIXME:
162         // change the ifdef to 'geometry = normalGeometry();' only
163         // when Trolltech has fixed the broken normalGeometry on X11:
164         // http://www.trolltech.com/developer/task-tracker/index_html?id=119684+&method=entry
165         // Then also the moveEvent, resizeEvent, and the
166         // code for floatingGeometry_ can be removed;
167         // adjust GuiView::setGeometry()
168 #ifdef Q_OS_WIN32
169         QRect geometry = normalGeometry();
170 #else
171         updateFloatingGeometry();
172         QRect geometry = floatingGeometry_;
173 #endif
174
175         // save windows size and position
176         Session & session = LyX::ref().session();
177         session.sessionInfo().save("WindowWidth", convert<string>(geometry.width()));
178         session.sessionInfo().save("WindowHeight", convert<string>(geometry.height()));
179         session.sessionInfo().save("WindowIsMaximized", (isMaximized() ? "yes" : "no"));
180         if (lyxrc.geometry_xysaved) {
181                 session.sessionInfo().save("WindowPosX", convert<string>(geometry.x()));
182                 session.sessionInfo().save("WindowPosY", convert<string>(geometry.y()));
183         }
184 }
185                                                   
186 void GuiView::setGeometry(unsigned int width,
187                                                                   unsigned int height,
188                                                                   int posx, int posy,
189                                                                   bool maximize)
190 {
191         // only true when the -geometry option was NOT used
192         if (width != 0 && height != 0) {
193                 if (posx != -1 && posy != -1) {
194                         // if there are ever startup positioning problems 
195                         // on a virtual desktop then check the 6 lines below
196                         // http://doc.trolltech.com/4.2/qdesktopwidget.html 
197                         QDesktopWidget& dw = *qApp->desktop();
198                         QRect desk = dw.availableGeometry(dw.primaryScreen());
199                         (posx >= desk.width() ? posx = 50 : true);
200                         (posy >= desk.height()? posy = 50 : true);
201 #ifdef Q_WS_WIN
202                         // FIXME: use only setGeoemtry when Trolltech has
203                         // fixed the qt4/X11 bug
204                         QMainWindow::setGeometry(posx, posy,width, height);
205 #else
206                         resize(width, height);
207                         move(posx, posy);
208 #endif
209                 } else {
210                         resize(width, height);
211                 }
212
213                 if (maximize)
214                         setWindowState(Qt::WindowMaximized);
215         }
216         
217         show();
218 }
219
220
221 void GuiView::updateMenu(QAction * /*action*/)
222 {
223         menubar_->update();
224 }
225
226
227 void GuiView::setWindowTitle(docstring const & t, docstring const & it)
228 {
229         QMainWindow::setWindowTitle(toqstr(t));
230         QMainWindow::setWindowIconText(toqstr(it));
231 }
232
233
234 void GuiView::addCommandBuffer(QToolBar * toolbar)
235 {
236         commandbuffer_ = new QCommandBuffer(this, *controlcommand_);
237         focus_command_buffer.connect(boost::bind(&GuiView::focus_command_widget, this));
238         toolbar->addWidget(commandbuffer_);
239 }
240
241
242 void GuiView::message(docstring const & str)
243 {
244         statusBar()->showMessage(toqstr(str));
245         statusbar_timer_.stop();
246         statusbar_timer_.start(statusbar_timer_value);
247 }
248
249
250 void GuiView::clearMessage()
251 {
252         update_view_state_qt();
253 }
254
255
256 void GuiView::focus_command_widget()
257 {
258         if (commandbuffer_)
259                 commandbuffer_->focus_command();
260 }
261
262
263 void GuiView::update_view_state_qt()
264 {
265         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
266         statusbar_timer_.stop();
267 }
268
269 void GuiView::initTab(QWidget* workarea)
270 {
271         d.wt = new WidgetWithTabBar(workarea);
272         setCentralWidget(d.wt);
273         QObject::connect(d.wt->tabbar, SIGNAL(currentChanged(int)),
274                         this, SLOT(currentTabChanged(int)));
275 }
276
277 void GuiView::updateTab()
278 {
279         QTabBar& tb = *d.wt->tabbar;
280
281         // update when all  is done
282         tb.blockSignals(true);
283
284         typedef std::vector<string> Strings;
285         Strings const names = theBufferList().getFileNames();
286         size_t n_size = names.size();
287
288         Strings addtab;
289         // show tabs only when there is more 
290         // than one file opened
291         if (n_size > 1)
292         {
293                 for (size_t i = 0; i != n_size; i++) 
294                         if (d.namemap.find(names[i]) == d.namemap.end())
295                                 addtab.push_back(names.at(i));
296         }
297
298         for(size_t i = 0; i<addtab.size(); i++)
299         {
300                 QString tab_name = lyx::toqstr(onlyFilename(addtab.at(i))); 
301                 d.namemap.insert(GuiViewPrivate::NameMapPair(addtab.at(i), tab_name));
302                 tb.addTab(tab_name);
303         }
304
305         // check if all names showed by the tabs
306         // are also in the current bufferlist
307         Strings removetab;
308         bool notall = true;
309         if (n_size < 2)
310                 notall = false;
311         std::map<string, QString>::iterator tabit = d.namemap.begin();
312         for (;tabit != d.namemap.end(); ++tabit)
313         {
314                 bool found = false;
315                 for (size_t i = 0; i != n_size; i++) 
316                         if (tabit->first == names.at(i) && notall)
317                                 found = true;
318                 if (!found)
319                         removetab.push_back(tabit->first);
320         }
321         
322
323         // remove tabs
324         for(size_t i = 0; i<removetab.size(); i++)
325         {
326                 if (d.namemap.find(removetab.at(i)) != d.namemap.end())
327                 {
328                         tabit = d.namemap.find(removetab.at(i));
329                         for (int i = 0; i < tb.count(); i++)
330                                 if (tb.tabText(i) == tabit->second)
331                                 {
332                                         tb.removeTab(i);
333                                         break;
334                                 }
335                         d.namemap.erase(tabit);
336                 }
337         }
338
339         // rebuild func map
340         if (removetab.size() > 0 || addtab.size() > 0)
341         {
342                 d.funcmap.clear();
343                 tabit = d.namemap.begin();
344                 for (;tabit != d.namemap.end(); ++tabit)
345                 {
346                         QTabBar& tb = *d.wt->tabbar;
347                         for (int i = 0; i < tb.count(); i++)
348                         {
349                                 if (tb.tabText(i) == tabit->second)
350                                 {
351                                         FuncRequest func(LFUN_BUFFER_SWITCH, tabit->first);
352                                         d.funcmap.insert(GuiViewPrivate::FuncMapPair(i, func));
353                                         break;
354                                 }
355                         }
356                 }
357         }
358
359         // set current tab
360         if (view()->buffer()) 
361         {
362                 string cur_title = view()->buffer()->fileName();
363                 if (d.namemap.find(cur_title) != d.namemap.end())
364                 {
365                         QString tabname = d.namemap.find(cur_title)->second;
366                         for (int i = 0; i < tb.count(); i++)
367                                 if (tb.tabText(i) == tabname)
368                                 {
369                                         tb.setCurrentIndex(i);
370                                         break;
371                                 }
372                 }
373         }
374
375         tb.blockSignals(false);
376         d.wt->update();
377 }
378
379 void GuiView::currentTabChanged (int index)
380 {
381         std::map<int, FuncRequest>::const_iterator it = d.funcmap.find(index);
382         if (it != d.funcmap.end())
383                 activated(it->second);
384 }
385
386
387 void GuiView::updateStatusBar()
388 {
389         // let the user see the explicit message
390         if (statusbar_timer_.isActive())
391                 return;
392
393         statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
394 }
395
396
397 void GuiView::activated(FuncRequest const & func)
398 {
399         dispatch(func);
400 }
401
402
403 bool GuiView::hasFocus() const
404 {
405         return qApp->activeWindow() == this;
406 }
407
408
409 void  GuiView::updateFloatingGeometry()
410 {
411         if (!isMaximized())
412                 floatingGeometry_ = QRect(x(), y(), width(), height());
413 }
414
415
416 void GuiView::resizeEvent(QResizeEvent *)
417 {
418         updateFloatingGeometry();
419 }
420
421
422 void GuiView::moveEvent(QMoveEvent *)
423 {
424         updateFloatingGeometry();
425 }
426
427
428 void GuiView::closeEvent(QCloseEvent * close_event)
429 {
430         GuiImplementation & gui 
431                 = static_cast<GuiImplementation &>(theApp->gui());
432
433         vector<int> const & view_ids = gui.viewIds();
434
435         if (view_ids.size() == 1 && !theBufferList().quitWriteAll()) {
436                 close_event->ignore();
437                 return;
438         }
439
440         saveGeometry();
441         gui.unregisterView(this);
442 }
443
444
445 void GuiView::show()
446 {
447         QMainWindow::setWindowTitle(qt_("LyX"));
448         QMainWindow::show();
449         updateFloatingGeometry();
450 }
451
452
453 void GuiView::busy(bool yes)
454 {
455         static_cast<GuiWorkArea *>(work_area_)->setUpdatesEnabled(!yes);
456
457         if (yes) {
458                 work_area_->stopBlinkingCursor();
459                 QApplication::setOverrideCursor(Qt::WaitCursor);
460         }
461         else {
462                 work_area_->startBlinkingCursor();
463                 QApplication::restoreOverrideCursor();
464         }
465 }
466
467
468 Toolbars::ToolbarPtr GuiView::makeToolbar(ToolbarBackend::Toolbar const & tbb)
469 {
470         QLToolbar * Tb = new QLToolbar(tbb, *this);
471         static QLToolbar * lastTb = 0;
472
473         if (tbb.flags & ToolbarBackend::TOP) {
474                         addToolBar(Qt::TopToolBarArea, Tb);
475                         addToolBarBreak(Qt::TopToolBarArea);
476         }
477         if (tbb.flags & ToolbarBackend::BOTTOM) {
478                 addToolBar(Qt::BottomToolBarArea, Tb);
479                 /*
480                 // Qt bug. Doesn't work because the
481                 // toolbar will evtl. be hidden.
482                 if (lastTb)
483                         insertToolBarBreak(lastTb);
484                 lastTb = Tb;
485                 */
486         }
487         if (tbb.flags & ToolbarBackend::LEFT) {
488                 addToolBar(Qt::LeftToolBarArea, Tb);
489         }
490         if (tbb.flags & ToolbarBackend::RIGHT) {
491                 addToolBar(Qt::RightToolBarArea, Tb);
492         }
493
494         return Toolbars::ToolbarPtr(Tb);
495 }
496
497 } // namespace frontend
498 } // namespace lyx
499
500 #include "GuiView_moc.cpp"