1 /*
2 * %kadu copyright begin%
3 * Copyright 2011 Tomasz Rostanski (rozteck@interia.pl)
4 * Copyright 2009, 2010, 2011 Piotr Galiszewski (piotr.galiszewski@kadu.im)
5 * Copyright 2010, 2011 Przemysław Rudy (prudy1@o2.pl)
6 * Copyright 2010, 2011 Piotr Dąbrowski (ultr@ultr.pl)
7 * Copyright 2010, 2011, 2012, 2013, 2014 Bartosz Brachaczek (b.brachaczek@gmail.com)
8 * Copyright 2009, 2010, 2011, 2013, 2014 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
9 * %kadu copyright end%
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24 #include <QtGui/QContextMenuEvent>
25 #include <QtWidgets/QMenu>
26
27 #include "accounts/account-manager.h"
28 #include "buddies/buddy-set.h"
29 #include "buddies/buddy.h"
30 #include "configuration/configuration-api.h"
31 #include "configuration/configuration-manager.h"
32 #include "configuration/configuration.h"
33 #include "configuration/configuration.h"
34 #include "configuration/deprecated-configuration-api.h"
35 #include "core/injected-factory.h"
36 #include "core/session-service.h"
37 #include "gui/actions/action.h"
38 #include "gui/actions/actions.h"
39 #include "gui/configuration/toolbar-configuration-manager.h"
40 #include "gui/widgets/talkable-tree-view.h"
41 #include "gui/widgets/toolbar.h"
42 #include "debug.h"
43
44 #include "main-window.h"
45
46 #if defined(Q_OS_UNIX)
47 #include <QtX11Extras/QX11Info>
48
49 #include "os/x11/x11tools.h" // this should be included as last one,
50 #undef KeyPress
51 #undef Status // and Status defined by Xlib.h must be undefined
52 #endif
53
findMainWindow(QWidget * widget)54 MainWindow * MainWindow::findMainWindow(QWidget *widget)
55 {
56 while (widget)
57 {
58 MainWindow *window = qobject_cast<MainWindow *>(widget);
59 if (window)
60 return window;
61 widget = widget->parentWidget();
62 }
63
64 return 0;
65 }
66
MainWindow(ActionContext * context,const QString & windowName,QWidget * parent)67 MainWindow::MainWindow(ActionContext *context, const QString &windowName, QWidget *parent) :
68 QMainWindow(parent), DesktopAwareObject(this), WindowName(windowName), TransparencyEnabled(false), BlurEnabled(false),
69 Context(context)
70 {
71 }
72
~MainWindow()73 MainWindow::~MainWindow()
74 {
75 delete Context;
76 Context = 0;
77 }
78
setActions(Actions * actions)79 void MainWindow::setActions(Actions *actions)
80 {
81 m_actions = actions;
82 }
83
setConfigurationManager(ConfigurationManager * configurationManager)84 void MainWindow::setConfigurationManager(ConfigurationManager *configurationManager)
85 {
86 m_configurationManager = configurationManager;
87 }
88
setConfiguration(Configuration * configuration)89 void MainWindow::setConfiguration(Configuration *configuration)
90 {
91 m_configuration = configuration;
92 }
93
configuration() const94 Configuration * MainWindow::configuration() const
95 {
96 return m_configuration;
97 }
98
setInjectedFactory(InjectedFactory * injectedFactory)99 void MainWindow::setInjectedFactory(InjectedFactory *injectedFactory)
100 {
101 m_injectedFactory = injectedFactory;
102 }
103
setSessionService(SessionService * sessionService)104 void MainWindow::setSessionService(SessionService *sessionService)
105 {
106 m_sessionService = sessionService;
107 }
108
init()109 void MainWindow::init()
110 {
111 connect(m_configurationManager->toolbarConfigurationManager(), SIGNAL(configurationUpdated()),
112 this, SLOT(refreshToolBars()));
113 connect(m_actions, SIGNAL(actionLoaded(ActionDescription*)),
114 this, SLOT(actionLoadedOrUnloaded(ActionDescription*)));
115 connect(m_actions, SIGNAL(actionUnloaded(ActionDescription*)),
116 this, SLOT(actionLoadedOrUnloaded(ActionDescription*)));
117 }
118
injectedFactory() const119 InjectedFactory * MainWindow::injectedFactory() const
120 {
121 return m_injectedFactory;
122 }
123
setActionContext(ActionContext * actionContext)124 void MainWindow::setActionContext(ActionContext *actionContext)
125 {
126 Context = actionContext;
127 }
128
loadToolBarsFromConfig()129 void MainWindow::loadToolBarsFromConfig()
130 {
131 // lame, i know
132
133 foreach (QObject *object, children())
134 {
135 QToolBar *toolBar = qobject_cast<QToolBar *>(object);
136 if (toolBar)
137 {
138 removeToolBar(toolBar);
139 delete toolBar;
140 }
141 }
142
143 loadToolBarsFromConfig(Qt::TopToolBarArea);
144 loadToolBarsFromConfig(Qt::LeftToolBarArea);
145 loadToolBarsFromConfig(Qt::BottomToolBarArea);
146 loadToolBarsFromConfig(Qt::RightToolBarArea);
147 }
148
horizontalToolbarComparator(ToolBar * t1,ToolBar * t2)149 bool horizontalToolbarComparator(ToolBar *t1, ToolBar *t2)
150 {
151 if (t1->yOffset() < t2->yOffset())
152 return true;
153 if (t1->yOffset() > t2->yOffset())
154 return false;
155 return t1->xOffset() < t2->xOffset();
156 }
157
verticalToolbarComparator(ToolBar * t1,ToolBar * t2)158 bool verticalToolbarComparator(ToolBar *t1, ToolBar *t2)
159 {
160 if (t1->xOffset() < t2->xOffset())
161 return true;
162 if (t1->xOffset() > t2->xOffset())
163 return false;
164 return t1->yOffset() < t2->yOffset();
165 }
166
loadToolBarsFromConfigNode(QDomElement dockareaConfig,Qt::ToolBarArea area)167 void MainWindow::loadToolBarsFromConfigNode(QDomElement dockareaConfig, Qt::ToolBarArea area)
168 {
169 QList<ToolBar *> toolBars;
170 for (QDomNode n = dockareaConfig.firstChild(); !n.isNull(); n = n.nextSibling())
171 {
172 const QDomElement &toolbarConfig = n.toElement();
173 if (toolbarConfig.isNull())
174 continue;
175 if (toolbarConfig.tagName() != "ToolBar")
176 continue;
177
178 ToolBar* toolbar = newToolbar(this);
179 toolbar->loadFromConfig(toolbarConfig);
180 toolbar->show();
181 /* show() resets the WA_NoSystemBackground and AutoFillBackground */
182 toolbar->setAttribute(Qt::WA_NoSystemBackground, !TransparencyEnabled);
183 toolbar->setAutoFillBackground(TransparencyEnabled);
184
185 toolBars.append(toolbar);
186 }
187
188 int currentLine = 0;
189 if (area == Qt::LeftToolBarArea || area == Qt::RightToolBarArea)
190 {
191 qSort(toolBars.begin(), toolBars.end(), verticalToolbarComparator);
192 foreach(ToolBar *toolBar, toolBars)
193 {
194 if (toolBar->xOffset() != currentLine)
195 addToolBarBreak(area);
196
197 addToolBar(area, toolBar);
198 currentLine = toolBar->xOffset();
199 }
200 }
201 else
202 {
203 qSort(toolBars.begin(), toolBars.end(), horizontalToolbarComparator);
204 foreach(ToolBar *toolBar, toolBars)
205 {
206 if (toolBar->yOffset() != currentLine)
207 addToolBarBreak(area);
208
209 addToolBar(area, toolBar);
210 currentLine = toolBar->yOffset();
211 }
212 }
213 }
214
loadToolBarsFromConfig(Qt::ToolBarArea area)215 void MainWindow::loadToolBarsFromConfig(Qt::ToolBarArea area)
216 {
217 QDomElement dockareaConfig = getDockAreaConfigElement(area);
218 loadToolBarsFromConfigNode(dockareaConfig, area);
219 }
220
loadOldToolBarsFromConfig(const QString & configName,Qt::ToolBarArea area)221 bool MainWindow::loadOldToolBarsFromConfig(const QString &configName, Qt::ToolBarArea area)
222 {
223 QDomElement toolbarsConfig = m_configuration->api()->findElement(m_configuration->api()->rootElement(), "Toolbars");
224
225 if (toolbarsConfig.isNull())
226 return false;
227
228 QDomElement dockareaConfig = m_configuration->api()->findElementByProperty(toolbarsConfig, "DockArea", "name", configName);
229 if (dockareaConfig.isNull())
230 return false;
231
232 loadToolBarsFromConfigNode(dockareaConfig, area);
233
234 dockareaConfig.parentNode().removeChild(dockareaConfig);
235 return true;
236 }
237
getToolbarsConfigElement(Configuration * configuration)238 QDomElement MainWindow::getToolbarsConfigElement(Configuration *configuration)
239 {
240 QDomElement toolbarsConfig = configuration->api()->findElement(configuration->api()->rootElement(), "Toolbars");
241 if (toolbarsConfig.isNull())
242 toolbarsConfig = configuration->api()->createElement(configuration->api()->rootElement(), "Toolbars");
243
244 return toolbarsConfig;
245 }
246
getDockAreaConfigElement(Qt::ToolBarArea area)247 QDomElement MainWindow::getDockAreaConfigElement(Qt::ToolBarArea area)
248 {
249 QString realPrefix;
250 if (!WindowName.isEmpty())
251 realPrefix = WindowName + '_';
252
253 QString suffix;
254
255 switch (area)
256 {
257 case Qt::TopToolBarArea:
258 suffix = "topDockArea";
259 break;
260 case Qt::LeftToolBarArea:
261 suffix = "leftDockArea";
262 break;
263 case Qt::RightToolBarArea:
264 suffix = "rightDockArea";
265 break;
266 case Qt::BottomToolBarArea:
267 suffix = "bottomDockArea";
268 break;
269 default:
270 return QDomElement();
271 }
272
273 return getDockAreaConfigElement(m_configuration, getToolbarsConfigElement(m_configuration), realPrefix + suffix);
274 }
275
getDockAreaConfigElement(Configuration * configuration,QDomElement toolbarsConfig,const QString & name)276 QDomElement MainWindow::getDockAreaConfigElement(Configuration *configuration, QDomElement toolbarsConfig, const QString &name)
277 {
278 QDomElement dockAreaConfig = configuration->api()->findElementByProperty(toolbarsConfig, "DockArea", "name", name);
279 if (dockAreaConfig.isNull())
280 {
281 dockAreaConfig = configuration->api()->createElement(toolbarsConfig, "DockArea");
282 dockAreaConfig.setAttribute("name", name);
283 }
284
285 return dockAreaConfig;
286 }
287
addToolButton(Configuration * configuration,QDomElement toolbarConfig,const QString & actionName,Qt::ToolButtonStyle style)288 void MainWindow::addToolButton(Configuration *configuration, QDomElement toolbarConfig, const QString &actionName, Qt::ToolButtonStyle style)
289 {
290 QDomElement buttonConfig = configuration->api()->findElementByProperty(toolbarConfig, "ToolButton", "action_name", actionName);
291 //don't add element if exists
292 if (!buttonConfig.isNull())
293 return;
294 buttonConfig = configuration->api()->createElement(toolbarConfig, "ToolButton");
295 buttonConfig.setAttribute("action_name", actionName);
296 buttonConfig.setAttribute("toolbutton_style", style);
297 }
298
findExistingToolbarOnArea(Configuration * configuration,const QString & areaName)299 QDomElement MainWindow::findExistingToolbarOnArea(Configuration *configuration, const QString &areaName)
300 {
301 QDomElement dockAreaConfig = configuration->api()->findElementByProperty(getToolbarsConfigElement(configuration), "DockArea", "name", areaName);
302 QDomElement nullResult;
303
304 if (dockAreaConfig.isNull())
305 return nullResult;
306
307 QDomElement toolbarElement = configuration->api()->findElement(dockAreaConfig, "ToolBar");
308 if (toolbarElement.isNull())
309 return nullResult;
310
311 return toolbarElement;
312 }
313
findExistingToolbar(Configuration * configuration,const QString & prefix)314 QDomElement MainWindow::findExistingToolbar(Configuration *configuration, const QString &prefix)
315 {
316 QString realPrefix;
317 if (!prefix.isEmpty())
318 realPrefix = prefix + '_';
319
320 QDomElement toolbarElement = findExistingToolbarOnArea(configuration, realPrefix + "topDockArea");
321 if (!toolbarElement.isNull())
322 return toolbarElement;
323
324 toolbarElement = findExistingToolbarOnArea(configuration, realPrefix + "leftDockArea");
325 if (!toolbarElement.isNull())
326 return toolbarElement;
327
328 toolbarElement = findExistingToolbarOnArea(configuration, realPrefix + "rightDockArea");
329 if (!toolbarElement.isNull())
330 return toolbarElement;
331
332 toolbarElement = findExistingToolbarOnArea(configuration, realPrefix + "bottomDockArea");
333 if (!toolbarElement.isNull())
334 return toolbarElement;
335
336 QDomElement dockAreaConfig = getDockAreaConfigElement(configuration, getToolbarsConfigElement(configuration), realPrefix + "topDockArea");
337 return configuration->api()->createElement(dockAreaConfig, "ToolBar");
338 }
339
writeToolBarsToConfig()340 void MainWindow::writeToolBarsToConfig()
341 {
342 writeToolBarsToConfig(Qt::TopToolBarArea);
343 writeToolBarsToConfig(Qt::LeftToolBarArea);
344 writeToolBarsToConfig(Qt::BottomToolBarArea);
345 writeToolBarsToConfig(Qt::RightToolBarArea);
346 }
347
writeToolBarsToConfig(Qt::ToolBarArea area)348 void MainWindow::writeToolBarsToConfig(Qt::ToolBarArea area)
349 {
350 QDomElement dockAreaConfig = getDockAreaConfigElement(area);
351 m_configuration->api()->removeChildren(dockAreaConfig);
352
353 // TODO: laaaaame
354 foreach(QObject *child, children())
355 {
356 ToolBar *toolBar = qobject_cast<ToolBar *>(child);
357 if (!toolBar)
358 continue;
359
360 if (toolBarArea(toolBar) != area)
361 continue;
362
363 toolBar->writeToConfig(dockAreaConfig);
364 }
365 }
366
actionLoadedOrUnloaded(ActionDescription * action)367 void MainWindow::actionLoadedOrUnloaded(ActionDescription *action)
368 {
369 if (supportsActionType(action->type()))
370 refreshToolBars();
371 }
372
refreshToolBars()373 void MainWindow::refreshToolBars()
374 {
375 // We don't need it when closing.
376 // BTW, on Mac it caused crashes on exit. TODO: check out why, as there is probably a bug somewhere.
377 if (m_sessionService->isClosing())
378 return;
379
380 loadToolBarsFromConfig();
381 }
382
contextMenuEvent(QContextMenuEvent * event)383 void MainWindow::contextMenuEvent(QContextMenuEvent *event)
384 {
385 if (!ToolBar::isBlockToolbars(m_configuration))
386 {
387 QMenu menu;
388 menu.addAction(tr("Create new toolbar"), this, SLOT(addTopToolbar()));
389 menu.exec(event->globalPos());
390 }
391 }
392
newToolbar(QWidget * parent)393 ToolBar *MainWindow::newToolbar(QWidget *parent)
394 {
395 auto toolBar = m_injectedFactory->makeInjected<ToolBar>(parent);
396 toolBar->setAttribute(Qt::WA_NoSystemBackground, !TransparencyEnabled);
397 toolBar->setAutoFillBackground(TransparencyEnabled);
398
399 connect(toolBar, SIGNAL(updated()), this, SLOT(toolbarUpdated()));
400 connect(toolBar, SIGNAL(removed(ToolBar*)), this, SLOT(toolbarRemoved(ToolBar*)));
401
402 return toolBar;
403 }
404
addTopToolbar()405 void MainWindow::addTopToolbar()
406 {
407 addToolBar(Qt::TopToolBarArea, newToolbar(this));
408 toolbarUpdated();
409 }
410
addBottomToolbar()411 void MainWindow::addBottomToolbar()
412 {
413 addToolBar(Qt::BottomToolBarArea, newToolbar(this));
414 toolbarUpdated();
415 }
416
addLeftToolbar()417 void MainWindow::addLeftToolbar()
418 {
419 addToolBar(Qt::LeftToolBarArea, newToolbar(this));
420 toolbarUpdated();
421 }
422
addRightToolbar()423 void MainWindow::addRightToolbar()
424 {
425 addToolBar(Qt::RightToolBarArea, newToolbar(this));
426 toolbarUpdated();
427 }
428
hasAction(const QString & actionName,ToolBar * exclude)429 bool MainWindow::hasAction(const QString &actionName, ToolBar *exclude)
430 {
431 foreach (QObject *object, children())
432 {
433 ToolBar *toolBar = qobject_cast<ToolBar *>(object);
434 if (toolBar && toolBar != exclude && toolBar->hasAction(actionName))
435 return true;
436 }
437
438 return false;
439 }
440
contact()441 Contact MainWindow::contact()
442 {
443 ContactSet contactSet = actionContext()->contacts();
444 return 1 == contactSet.count()
445 ? *contactSet.constBegin()
446 : Contact::null;
447 }
448
buddy()449 Buddy MainWindow::buddy()
450 {
451 BuddySet buddySet = actionContext()->buddies();
452 return 1 == buddySet.count()
453 ? *buddySet.constBegin()
454 : Buddy::null;
455 }
456
setTransparency(bool enable)457 void MainWindow::setTransparency(bool enable)
458 {
459 /* 1. Do not make MainWindow related to the CompositingAwareObject class
460 * as not every child wants to be compositing aware
461 * 2. Allow child to decide if and when to use transparency or not and
462 * provide means to do this.
463 * Enabling transparency sets main window background transparent whilst
464 * toolbars are opaque, so the central widget can enjoy the transparency.
465 */
466 TransparencyEnabled = enable;
467 if (TransparencyEnabled)
468 {
469 setAttribute(Qt::WA_TranslucentBackground, true);
470
471 foreach (QObject *object, children())
472 {
473 QToolBar *toolBar = qobject_cast<QToolBar *>(object);
474 if (toolBar)
475 {
476 toolBar->setAttribute(Qt::WA_NoSystemBackground, false);
477 toolBar->setAutoFillBackground(true);
478 }
479 }
480 }
481 else
482 {
483 foreach (QObject *object, children())
484 {
485 QToolBar *toolBar = qobject_cast<QToolBar *>(object);
486 if (toolBar)
487 toolBar->setAutoFillBackground(false);
488 }
489 setAttribute(Qt::WA_TranslucentBackground, false);
490 setAttribute(Qt::WA_NoSystemBackground, false);
491 }
492 }
493
toolbarUpdated()494 void MainWindow::toolbarUpdated()
495 {
496 writeToolBarsToConfig();
497
498 m_configurationManager->toolbarConfigurationManager()->notifyConfigurationUpdated();
499 }
500
toolbarRemoved(ToolBar * toolBar)501 void MainWindow::toolbarRemoved(ToolBar *toolBar)
502 {
503 toolBar->hide();
504 toolBar->setParent(0); // remove it from this window
505 toolBar->deleteLater();
506
507 toolbarUpdated();
508 }
509
actionContext()510 ActionContext * MainWindow::actionContext()
511 {
512 return Context;
513 }
514
setBlur(bool enable)515 void MainWindow::setBlur(bool enable)
516 {
517 #if !defined(Q_OS_UNIX)
518 Q_UNUSED(enable);
519 #else
520 BlurEnabled = enable;
521 X11_setBlur(QX11Info::display(), winId(), enable);
522 #endif
523 }
524
525
showEvent(QShowEvent * event)526 void MainWindow::showEvent(QShowEvent * event)
527 {
528 if (BlurEnabled)
529 setBlur(true);
530 QMainWindow::showEvent(event);
531 }
532
533 #include "moc_main-window.cpp"
534