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