swift
Loading...
Searching...
No Matches
infoarea.cpp
1// SPDX-FileCopyrightText: Copyright (C) 2014 swift Project Community / Contributors
2// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3
4#include "gui/infoarea.h"
5
6#include <QAction>
7#include <QCloseEvent>
8#include <QFlags>
9#include <QIcon>
10#include <QKeyEvent>
11#include <QMenu>
12#include <QPixmap>
13#include <QPoint>
14#include <QPointer>
15#include <QScopedPointer>
16#include <QSignalMapper>
17#include <QStatusBar>
18#include <QStyle>
19#include <QTabBar>
20#include <QTimer>
21#include <QVariant>
22#include <QWidget>
23#include <QtGlobal>
24
25#include "gui/dockwidget.h"
27#include "gui/guiapplication.h"
28#include "gui/guiutility.h"
30#include "misc/icons.h"
31#include "misc/logmessage.h"
32#include "misc/verify.h"
33
34using namespace swift::misc;
35
36namespace swift::gui
37{
40 CEnableForFramelessWindow(CEnableForFramelessWindow::WindowTool, false, "framelessInfoArea", this)
41 {
42 this->setWholeInfoAreaFloating(m_infoAreaFloating);
43 }
44
46 {
47 // initInfoArea() needs be called after(!) GUI is setup
48
49 // Ref T184, child areas are now "cached" in m_childInfoAreas
50 // The original version did always use "findChildInfoAreas", so if there are ever any issues T184 might be
51 // reverted
52 m_childInfoAreas = this->findOwnChildInfoAreas();
53 m_dockWidgetInfoAreas = this->findOwnDockWidgetInfoAreas();
54
55 this->setDockArea(Qt::TopDockWidgetArea);
56 this->connectTopLevelChanged();
57 this->setFeaturesForDockableWidgets(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable |
59 this->tabifyAllWidgets();
60
61 // context menu
63 connect(this, &CInfoArea::customContextMenuRequested, this, &CInfoArea::showContextMenu);
64 connect(sGui, &CGuiApplication::styleSheetsChanged, this, &CInfoArea::onStyleSheetChanged,
66
67 // initial style sheet setting
68 this->onStyleSheetChanged();
69
70 // status bar
71 if (this->statusBar())
72 {
73 this->statusBar()->hide();
74 this->statusBar()->setMaximumHeight(0);
75 }
76
77 // fire an initial status
78 QPointer<CInfoArea> myself(this);
79 QTimer::singleShot(5000, this, [=] {
80 if (myself)
81 {
82 myself->emitInfoAreaStatus();
83 }
84 });
85 }
86
88 {
89 if (!menu)
90 {
91 return;
92 }
93 bool hasDockedWidgets = this->countDockedWidgetInfoAreas() > 0;
94 if (hasDockedWidgets)
95 {
96 menu->addAction(CIcons::dockTop16(), "Dock all", this, &CInfoArea::dockAllWidgets);
97 menu->addAction(CIcons::floatAll16(), "Float all", this, &CInfoArea::floatAllWidgets);
98 menu->addAction(CIcons::refresh16(), "Reset all floating to defaults", this,
100 menu->addAction(CIcons::refresh16(), "Reset all to defaults", this, &CInfoArea::resetAllWidgetSettings);
101
102 menu->addAction(CIcons::floatOne16(), QStringLiteral("Dock / float '%1'").arg(this->windowTitle()), this,
104 auto *lockTabBarMenuAction = new QAction(menu);
105 lockTabBarMenuAction->setObjectName(this->objectName().append("LockTabBar"));
106 lockTabBarMenuAction->setIconText("Lock tab bar");
107 lockTabBarMenuAction->setIcon(CIcons::lockClosed16());
108 lockTabBarMenuAction->setCheckable(true);
109 lockTabBarMenuAction->setChecked(m_lockTabBar);
110 menu->addAction(lockTabBarMenuAction);
111 connect(lockTabBarMenuAction, &QAction::toggled, this, &CInfoArea::toggleTabBarLocked);
112
113 menu->addSeparator();
114 auto *subMenuToggleFloat = new QMenu("Toggle Float/Dock", menu);
115 auto *subMenuDisplay = new QMenu("Display", menu);
116 auto *subMenuRestore = new QMenu("Restore from settings", menu);
117 auto *subMenuResetPositions = new QMenu("Reset position", menu);
118 subMenuRestore->setIcon(CIcons::load16());
119 subMenuResetPositions->setIcon(CIcons::refresh16());
120 subMenuRestore->addActions(this->getInfoAreaRestoreActions(subMenuRestore));
121 subMenuDisplay->addActions(this->getInfoAreaSelectActions(false, subMenuDisplay));
122 subMenuResetPositions->addActions(this->getInfoAreaResetPositionActions(subMenuResetPositions));
123
124 auto *signalMapperToggleFloating = new QSignalMapper(menu);
125 bool c = false; // check connections
126
127 for (int i = 0; i < m_dockWidgetInfoAreas.size(); i++)
128 {
129 const CDockWidgetInfoArea *dw = m_dockWidgetInfoAreas.at(i);
130 const QString t = dw->windowTitleBackup();
131 const QPixmap pm = this->indexToPixmap(i);
132 auto *toggleFloatingMenuAction = new QAction(menu);
133 toggleFloatingMenuAction->setObjectName(QString(t).append("ToggleFloatingAction"));
134 toggleFloatingMenuAction->setIconText(t);
135 toggleFloatingMenuAction->setIcon(pm);
136 toggleFloatingMenuAction->setData(QVariant(i));
137 toggleFloatingMenuAction->setCheckable(true);
138 toggleFloatingMenuAction->setChecked(!dw->isFloating());
139 subMenuToggleFloat->addAction(toggleFloatingMenuAction);
140 c = connect(toggleFloatingMenuAction, &QAction::toggled, signalMapperToggleFloating,
141 qOverload<>(&QSignalMapper::map));
142 SWIFT_VERIFY_X(c, Q_FUNC_INFO,
143 "Cannot map floating action"); // do not make that shutdown reason in a release build
144 signalMapperToggleFloating->setMapping(toggleFloatingMenuAction, i);
145 }
146
147 c = connect(signalMapperToggleFloating, &QSignalMapper::mappedInt, this, &CInfoArea::toggleFloatingByIndex);
148 SWIFT_VERIFY_X(c, Q_FUNC_INFO,
149 "Cannot connect mapper"); // do not make that shutdown reason in a release build
150
151 menu->addMenu(subMenuDisplay);
152 if (c)
153 {
154 menu->addMenu(subMenuToggleFloat);
155 }
156 menu->addMenu(subMenuResetPositions);
157 menu->addMenu(subMenuRestore);
158
159 // where and how to display tab bar
160 menu->addSeparator();
161 auto *showMenuText = new QAction(menu);
162 showMenuText->setObjectName("ShowDockedWidgetTextAction");
163 showMenuText->setIconText("Show tab text");
164 showMenuText->setIcon(CIcons::headingOne16());
165 showMenuText->setCheckable(true);
166 showMenuText->setChecked(m_showTabTexts);
167 menu->addAction(showMenuText);
168 connect(showMenuText, &QAction::toggled, this, &CInfoArea::showTabTexts);
169
170 // auto adjust floating widgets
171 auto *showTabbar = new QAction(menu);
172 showTabbar->setObjectName("ShowTabBar");
173 showTabbar->setIconText("Show tab bar");
174 showTabbar->setIcon(CIcons::dockBottom16());
175 showTabbar->setCheckable(true);
176 showTabbar->setChecked(m_showTabBar);
177 menu->addAction(showTabbar);
178 connect(showTabbar, &QAction::toggled, this, &CInfoArea::showTabBar);
179
180 // tab bar position
181 menu->addAction(CIcons::dockBottom16(), "Toggle tabbar position", this, &CInfoArea::toggleTabBarPosition);
182 Q_UNUSED(c)
183 }
184 }
185
187 {
188 if (!infoArea)
189 {
190 return false;
191 }
192 if (infoArea->isFloating())
193 {
194 return false;
195 }
196 if (!infoArea->isWidgetVisible())
197 {
198 return false;
199 }
200 if (!m_tabBar || m_tabBar->count() < 1)
201 {
202 return false;
203 }
204 return true;
205 }
206
208 {
209 // we assume that there can only be 1, non floating info area,
210 // which is the only visible one
211 // selecting is tab text independent (can be hidden)
212 if (!m_tabBar || m_tabBar->count() < 1)
213 {
214 return nullptr;
215 }
216 for (const CDockWidgetInfoArea *ia : m_dockWidgetInfoAreas)
217 {
218 if (ia->isFloating())
219 {
220 continue;
221 }
222 if (ia->isWidgetVisible())
223 {
224 return ia;
225 }
226 }
227 return nullptr;
228 }
229
231 {
233 if (!sel)
234 {
235 return -1;
236 }
237 const QString t(sel->windowTitleBackup());
238 int ia = getAreaIndexByWindowTitle(t);
239 return ia;
240 }
241
243 {
244 return makeRange(m_dockWidgetInfoAreas);
245 }
246
248 {
249 Q_ASSERT(parent);
250 int i = 0;
252 for (const CDockWidgetInfoArea *dockWidgetInfoArea : m_dockWidgetInfoAreas)
253 {
254 const QPixmap pm = this->indexToPixmap(i);
255 const QString wt(dockWidgetInfoArea->windowTitleBackup());
256 static const QString keys("123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
257 auto *action = new QAction(QIcon(pm), wt, parent);
258 action->setData(i);
259 action->setObjectName(this->objectName().append(":getInfoAreaSelectActions:").append(wt));
260 if (withShortcut && i < keys.length())
261 {
262 // T600 The strings "Ctrl", "Shift", "Alt" and "Meta" are recognized
263 // https://doc.qt.io/archives/qt-4.8/qkeysequence.html Standard shortcuts already used
264 // "Ctrl+Shift+%1" als works
265 action->setShortcut(QKeySequence(QStringLiteral("Ctrl+Shift+%1").arg(keys.at(i))));
266 }
267
269 actions.append(action);
270 i++;
271 }
272 return actions;
273 }
274
276 {
277 Q_ASSERT(parent);
278 int i = 0;
280 for (const CDockWidgetInfoArea *dockWidgetInfoArea : m_dockWidgetInfoAreas)
281 {
282 const QPixmap pm = this->indexToPixmap(i);
283 const QString wt(dockWidgetInfoArea->windowTitleBackup());
284 auto *action = new QAction(QIcon(pm), wt, parent);
285 action->setData(i);
286 action->setObjectName(this->objectName().append(":getInfoAreaResetPositionActions:").append(wt));
288 actions.append(action);
289 i++;
290 }
291 return actions;
292 }
293
295 {
296 Q_ASSERT(parent);
297 int i = 0;
299 for (const CDockWidgetInfoArea *dockWidgetInfoArea : m_dockWidgetInfoAreas)
300 {
301 const QPixmap pm = this->indexToPixmap(i);
302 const QString wt(dockWidgetInfoArea->windowTitleBackup());
303 auto *action = new QAction(QIcon(pm), wt, parent);
304 action->setData(i);
305 action->setObjectName(this->objectName().append(":getInfoAreaToggleFloatingActions:").append(wt));
307 actions.append(action);
308 i++;
309 }
310 return actions;
311 }
312
314 {
315 Q_ASSERT(parent);
316 int i = 0;
318 for (const CDockWidgetInfoArea *dockWidgetInfoArea : m_dockWidgetInfoAreas)
319 {
320 const QPixmap pm = this->indexToPixmap(i);
321 const QString wt(dockWidgetInfoArea->windowTitleBackup());
322 auto *action = new QAction(QIcon(pm), wt, parent);
323 action->setData(i);
324 action->setObjectName(this->objectName().append(":getInfoAreaRestoreActions:").append(wt));
326 actions.append(action);
327 i++;
328 }
329 return actions;
330 }
331
333 {
334 QList<int> indexes;
335 for (int i = 0; i < m_dockWidgetInfoAreas.size(); i++)
336 {
337 if (m_dockWidgetInfoAreas.at(i)->isFloating() == floating)
338 {
339 indexes.append(i);
340 }
341 }
342 return indexes;
343 }
344
350
352 {
353 if (event->key() == Qt::Key_Right)
354 {
355 this->selectRightTab();
356 event->accept();
357 }
358 else if (event->key() == Qt::Key_Left)
359 {
360 this->selectLeftTab();
361 event->accept();
362 }
363 else
364 {
366 }
367 }
368
369 void CInfoArea::dockAllWidgets() { this->tabifyAllWidgets(); }
370
372 {
373 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
374 {
375 dw->adjustSize();
376 }
377 }
378
380 {
381 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
382 {
383 if (dw->isFloating())
384 {
385 continue;
386 }
387 dw->toggleFloating();
388 }
389 }
390
392 {
393 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
394 {
395 if (!dw || !dw->isFloating())
396 {
397 continue;
398 }
399 dw->resetSettings();
400 }
401 }
402
404 {
405 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
406 {
407 if (!dw || !dw->isFloating())
408 {
409 continue;
410 }
411 dw->resetSettings();
412 }
413 }
414
416 {
417 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
418 {
419 const bool f = dw->isFloating();
421 if (f)
422 {
423 dw->show();
424 }
425 }
426 }
427
428 void CInfoArea::toggleFloatingWholeInfoArea() { this->setWholeInfoAreaFloating(!m_infoAreaFloating); }
429
431 {
432 if (!this->isValidAreaIndex(areaIndex))
433 {
434 return;
435 }
436 CDockWidgetInfoArea *dw = m_dockWidgetInfoAreas.at(areaIndex);
437 SWIFT_VERIFY_X(dw, Q_FUNC_INFO, "Missing info area");
438 if (!dw)
439 {
440 return;
441 }
442 dw->toggleFloating();
443 }
444
445 void CInfoArea::toggleVisibility(int areaIndex)
446 {
447 if (!this->isValidAreaIndex(areaIndex))
448 {
449 return;
450 }
451 CDockWidgetInfoArea *dw = m_dockWidgetInfoAreas.at(areaIndex);
452 SWIFT_VERIFY_X(dw, Q_FUNC_INFO, "Missing info area");
453 if (!dw)
454 {
455 return;
456 }
457 dw->toggleVisibility();
458 }
459
460 void CInfoArea::selectArea(int areaIndex)
461 {
462 CDockWidgetInfoArea *dw = m_dockWidgetInfoAreas.at(areaIndex);
463 SWIFT_VERIFY_X(dw, Q_FUNC_INFO, "Missing info area");
464 if (!dw)
465 {
466 return;
467 }
468 Q_ASSERT(m_tabBar);
469 if (m_tabBar->count() < 1)
470 {
471 return;
472 }
473
474 if (dw->isFloating())
475 {
476 dw->show();
477 }
478 else
479 {
480 this->selectArea(dw);
481 }
482 }
483
484 void CInfoArea::resetPosition(int areaIndex)
485 {
486 CDockWidgetInfoArea *dw = m_dockWidgetInfoAreas.at(areaIndex);
487 SWIFT_VERIFY_X(dw, Q_FUNC_INFO, "Missing info area");
488 if (!dw)
489 {
490 return;
491 }
492 dw->resetPosition();
493 }
494
496 {
497 const QObject *sender = QObject::sender();
498 const auto *action = qobject_cast<const QAction *>(sender);
499 SWIFT_VERIFY(action);
500 if (!action)
501 {
502 return;
503 }
504 const int index = action->data().toInt();
505 this->selectArea(index);
506 }
507
509 {
510 const QObject *sender = QObject::sender();
511 const auto *action = qobject_cast<const QAction *>(sender);
512 SWIFT_VERIFY(action);
513 if (!action)
514 {
515 return;
516 }
517 const int index = action->data().toInt();
518 this->resetPosition(index);
519 }
520
522 {
523 const QObject *sender = QObject::sender();
524 const auto *action = qobject_cast<const QAction *>(sender);
525 SWIFT_VERIFY(action);
526 if (!action)
527 {
528 return;
529 }
530 const int index = action->data().toInt();
531 this->toggleFloatingByIndex(index);
532 }
533
535 {
536 const QObject *sender = QObject::sender();
537 const auto *action = qobject_cast<const QAction *>(sender);
538 SWIFT_VERIFY(action);
539 if (!action)
540 {
541 return;
542 }
543 const int index = action->data().toInt();
545 }
546
548 {
549 if (!this->isValidAreaIndex(areaIndex))
550 {
551 return;
552 }
553 CDockWidgetInfoArea *dw = m_dockWidgetInfoAreas.at(areaIndex);
554 Q_ASSERT(dw);
555 if (!dw)
556 {
557 return;
558 }
560 }
561
563 {
564 if (!m_tabBar) return;
565 if (m_tabBar->count() < 2) return;
566 if (m_tabBar->currentIndex() > 0)
567 {
568 m_tabBar->setCurrentIndex(m_tabBar->currentIndex() - 1);
569 }
570 else
571 {
572 m_tabBar->setCurrentIndex(m_tabBar->count() - 1);
573 }
574 }
575
577 {
578 if (!m_tabBar) return;
579 if (m_tabBar->count() < 2) return;
580 if (m_tabBar->currentIndex() < m_tabBar->count() - 2)
581 {
582 m_tabBar->setCurrentIndex(m_tabBar->currentIndex() + 1);
583 }
584 else
585 {
586 m_tabBar->setCurrentIndex(0);
587 }
588 }
589
591 {
592 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
593 {
594 dw->displayStatusMessage(statusMessage);
595 }
596 for (CInfoArea *ia : std::as_const(m_childInfoAreas))
597 {
598 ia->displayStatusMessage(statusMessage);
599 }
600 }
601
603 {
604 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
605 {
606 dw->displayStatusMessages(statusMessages);
607 }
608 for (CInfoArea *ia : std::as_const(m_childInfoAreas))
609 {
610 ia->displayStatusMessages(statusMessages);
611 }
612 }
613
614 void CInfoArea::setDockArea(Qt::DockWidgetArea area)
615 {
616 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
617 {
618 auto newAreas = static_cast<Qt::DockWidgetAreas>(area);
619 Qt::DockWidgetAreas oldAreas = dw->allowedAreas();
620 if (oldAreas == newAreas)
621 {
622 continue;
623 }
624 dw->setAllowedAreas(newAreas);
625 this->addDockWidget(area, dw);
626 }
627 }
628
629 void CInfoArea::setWholeInfoAreaFloating(bool floating)
630 {
631 // float whole info area
632 m_infoAreaFloating = floating;
633 if (m_infoAreaFloating)
634 {
638 this->move(p.rx() + 20, p.ry() + 20);
639 this->show(); // not working without show
640 }
641 else
642 {
643 // make this compliant as QWidget
644 // https://qt-project.org/forums/viewthread/17519
645 // http://www.qtcentre.org/threads/12569-QMainWindow-as-a-child-of-QMainWindow
646
647 // this->setParent(m_originalParent, this->windowFlags() & ~Qt::Window);
648 this->setWindowFlags(this->windowFlags() & ~Qt::Window);
649
650 if (this->parentWidget())
651 {
652 this->setVisible(true); // after redocking this is required
653 }
654 }
655
656 emit this->changedWholeInfoAreaFloating(floating);
657 }
658
659 void CInfoArea::tabifyAllWidgets()
660 {
661 if (!sGui || sGui->isShuttingDown())
662 {
663 return;
664 }
666 const bool init = m_tabBar == nullptr;
667
668 for (int i = 0; i < m_dockWidgetInfoAreas.size(); i++)
669 {
670 CDockWidgetInfoArea *first = i > 0 ? m_dockWidgetInfoAreas.at(i - 1) : nullptr;
671 CDockWidgetInfoArea *after = m_dockWidgetInfoAreas.at(i);
672 Q_ASSERT(after);
673
674 // trick, init widget as floating
675 // this completely initializes the tab bar and all docked widgets
676 if (init)
677 {
678 // float
679 const QPoint offset(i * 10, i * 10);
680 // after->setVisible(false);
681 // after->setFloating(true);
682 after->setOffsetWhenFloating(offset, after->isFrameless());
683 const QSize floatingSize = this->getPreferredSizeWhenFloating(i);
684 after->setPreferredSizeWhenFloating(floatingSize);
685 after->initialFloating();
686
687 // dock again
688 // after->setFloating(false);
689 // after->setVisible(true);
690
691 // reset floating flag, we want new resizing and position for first real floating
692 after->resetWasAlreadyFloating();
693 }
694 else
695 {
696 after->setFloating(false);
697 }
698
699 // we can not tabify first
700 if (!first)
701 {
702 continue;
703 }
704
705 this->tabifyDockWidget(first, after);
706 }
707
708 // as now tabified, set tab
709 if (init)
710 {
711 m_tabBar = this->findChild<QTabBar *>();
712
713 // if we have > 1 docked widgets, we have a tab bar
714 if (m_tabBar && sGui)
715 {
717 m_tabBar->setStyleSheet(qss);
718 m_tabBar->setObjectName("comp_MainInfoAreaDockWidgetTab");
719 m_tabBar->setMovable(false);
720 m_tabBar->setElideMode(Qt::ElideNone);
721 m_tabBar->setUsesScrollButtons(true);
722
723 // East / West does not work (shown, but area itself empty)
724 // South does not have any effect
725 m_tabBar->setShape(QTabBar::TriangularSouth);
726
727 // signals, use Qt::QueuedConnection to avoid issues during shutdown
728 connect(m_tabBar, &QTabBar::tabBarDoubleClicked, this, &CInfoArea::onTabBarDoubleClicked,
730 connect(m_tabBar, &QTabBar::currentChanged, this, &CInfoArea::onTabBarIndexChanged,
732 }
733 else
734 {
735 // <= 1 dock widget
736 m_tabBar = new QTabBar(this);
737 m_tabBar->hide();
738 }
739 }
740
741 // set current index, and always set pixmaps
742 if (this->countDockedWidgetInfoAreas() > 0)
743 {
744 m_tabBar->setCurrentIndex(0);
745 }
746 if (m_tabBar->count() > 0)
747 {
748 this->setTabPixmaps();
749 }
750 }
751
752 void CInfoArea::unTabifyAllWidgets()
753 {
754 if (m_dockWidgetInfoAreas.size() < 2) return;
755 CDockWidgetInfoArea *first = m_dockWidgetInfoAreas.constFirst();
756 for (int i = 1; i < m_dockWidgetInfoAreas.size(); i++)
757 {
758 CDockWidgetInfoArea *after = m_dockWidgetInfoAreas.at(i);
759 Q_ASSERT(after);
760 this->splitDockWidget(first, after, Qt::Horizontal);
761 }
762 }
763
764 bool CInfoArea::isValidAreaIndex(int areaIndex) const
765 {
766 if (!m_tabBar)
767 {
768 return false;
769 }
770 return areaIndex >= 0 && areaIndex < m_dockWidgetInfoAreas.size();
771 }
772
773 void CInfoArea::connectTopLevelChanged()
774 {
775 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
776 {
777 connect(dw, &CDockWidgetInfoArea::widgetTopLevelChanged, this, &CInfoArea::onWidgetTopLevelChanged,
779 }
780 }
781
782 QList<CDockWidgetInfoArea *> CInfoArea::findOwnDockWidgetInfoAreas() const
783 {
784 // own dock widget areas without nested ones
786 }
787
788 QList<CInfoArea *> CInfoArea::findOwnChildInfoAreas() const
789 {
791 }
792
793 void CInfoArea::emitInfoAreaStatus()
794 {
795 if (!sGui || sGui->isShuttingDown())
796 {
797 return;
798 } // avoid access to deleted components
799 const int sia = this->getSelectedDockInfoAreaIndex();
800 const QList<int> floating = this->getAreaIndexesDockedOrFloating(true);
801 const QList<int> docked = this->getAreaIndexesDockedOrFloating(false);
802 emit this->changedInfoAreaStatus(sia, docked, floating);
803 }
804
805 void CInfoArea::onTabBarIndexChanged(int tabBarIndex)
806 {
807 emit this->changedInfoAreaTabBarIndex(tabBarIndex);
808 this->emitInfoAreaStatus();
809 }
810
811 int CInfoArea::countDockedWidgetInfoAreas() const
812 {
813 if (!m_tabBar)
814 {
815 return 0;
816 }
817 return m_tabBar->count();
818 }
819
820 CDockWidgetInfoArea *CInfoArea::getDockWidgetInfoAreaByTabBarIndex(int tabBarIndex) const
821 {
822 if (tabBarIndex >= m_dockWidgetInfoAreas.count() || tabBarIndex < 0)
823 {
824 return nullptr;
825 }
826 if (!m_tabBar)
827 {
828 return nullptr;
829 }
830 const QString t(m_tabBar->tabText(tabBarIndex));
831
832 // we have a title and search by that (best option, as order does not matter)
833 if (!t.isEmpty())
834 {
835 return this->getDockWidgetInfoAreaByWindowTitle(t);
836 }
837
838 // no title, we assume the n-th not floating tab is correct
839 // this will work if the order in m_dockWidgetInfoAreas matches
840 int c = 0;
841 for (CDockWidgetInfoArea *dw : m_dockWidgetInfoAreas)
842 {
843 if (dw->isFloating())
844 {
845 continue;
846 }
847 if (c == tabBarIndex)
848 {
849 return dw;
850 }
851 c++;
852 }
853 Q_ASSERT_X(false, Q_FUNC_INFO, "no dock widgte found");
854 return nullptr;
855 }
856
857 CDockWidgetInfoArea *CInfoArea::getDockWidgetInfoAreaByWindowTitle(const QString &title) const
858 {
859 Q_ASSERT_X(!title.isEmpty(), Q_FUNC_INFO, "No title");
860 for (CDockWidgetInfoArea *dw : m_dockWidgetInfoAreas)
861 {
862 if (CGuiUtility::lenientTitleComparison(dw->windowTitleOrBackup(), title))
863 {
864 return dw;
865 }
866 }
867 return nullptr;
868 }
869
870 int CInfoArea::getAreaIndexByWindowTitle(const QString &title) const
871 {
872 Q_ASSERT_X(!title.isEmpty(), Q_FUNC_INFO, "No title");
873
874 for (int i = 0; i < m_dockWidgetInfoAreas.size(); i++)
875 {
876 if (CGuiUtility::lenientTitleComparison(m_dockWidgetInfoAreas.at(i)->windowTitleOrBackup(), title))
877 {
878 return i;
879 }
880 }
881 Q_ASSERT_X(false, Q_FUNC_INFO, "No area for title");
882 return -1;
883 }
884
885 int CInfoArea::getTabBarIndexByTitle(const QString &title) const
886 {
887 SWIFT_VERIFY_X(!title.isEmpty(), Q_FUNC_INFO, "No title");
888 if (title.isEmpty())
889 {
890 return -1;
891 }
892
893 if (m_tabBar->count() < 1)
894 {
895 return -1;
896 }
897 for (int i = 0; i < m_tabBar->count(); i++)
898 {
899 QString tt = m_tabBar->tabText(i);
900 if (tt.isEmpty())
901 {
902 tt = m_tabBar->tabToolTip(i);
903 }
904 if (tt.isEmpty())
905 {
906 continue;
907 } // cannot find by empty text
909 {
910 return i;
911 }
912 }
913 return -1;
914 }
915
916 int CInfoArea::dockWidgetInfoAreaToTabBarIndex(const CDockWidgetInfoArea *dockWidgetInfoArea) const
917 {
918 if (!dockWidgetInfoArea)
919 {
920 return -1;
921 }
922 if (dockWidgetInfoArea->isFloating())
923 {
924 return -1;
925 }
926 int index = this->getTabBarIndexByTitle(dockWidgetInfoArea->windowTitleOrBackup());
927 if (index < 0)
928 {
929 // fallback if the tab has no name and cannot be found
930 int i = 0;
931 for (const CDockWidgetInfoArea *a : m_dockWidgetInfoAreas)
932 {
933 if (a == dockWidgetInfoArea)
934 {
935 index = i;
936 break;
937 }
938 ++i;
939 }
940 }
941
942 // sanity check
943 if (index >= m_tabBar->count())
944 {
945 index = -1;
946 }
947
948 // bye
949 return index;
950 }
951
952 void CInfoArea::selectArea(const CDockWidgetInfoArea *dockWidgetInfoArea)
953 {
954 if (!m_tabBar)
955 {
956 return;
957 }
958 int tabIndex = this->dockWidgetInfoAreaToTabBarIndex(dockWidgetInfoArea);
959 if (tabIndex >= 0 && tabIndex < m_tabBar->count())
960 {
961 m_tabBar->setCurrentIndex(tabIndex);
962 }
963 }
964
965 void CInfoArea::setFeaturesForDockableWidgets(QDockWidget::DockWidgetFeatures features)
966 {
967 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
968 {
969 dw->setFeatures(features);
970 }
971 }
972
973 void CInfoArea::setTabPixmaps()
974 {
975 if (!m_tabBar)
976 {
977 return;
978 }
979 for (int i = 0; i < m_tabBar->count(); i++)
980 {
981 const QString t(m_tabBar->tabText(i));
982 const int areaIndex = t.isEmpty() ? i : this->getAreaIndexByWindowTitle(t);
983 m_tabBar->setTabIcon(i, indexToPixmap(areaIndex));
984 m_tabBar->setTabToolTip(i, t);
985 }
986 }
987
988 void CInfoArea::onTabBarDoubleClicked(int tabBarIndex)
989 {
990 if (m_lockTabBar)
991 {
992 CLogMessage(this).info(u"Locked, double click will not cause floating");
993 return;
994 }
995 CDockWidgetInfoArea *dw = this->getDockWidgetInfoAreaByTabBarIndex(tabBarIndex);
996 if (!dw)
997 {
998 return;
999 }
1000 dw->toggleFloating();
1001
1002 QPointer<CInfoArea> myself(this);
1003 QTimer::singleShot(1000, this, [=] {
1004 if (!myself)
1005 {
1006 return;
1007 }
1008 myself->emitInfoAreaStatus();
1009 });
1010 }
1011
1012 void CInfoArea::onWidgetTopLevelChanged(CDockWidget *dockWidget, bool topLevel)
1013 {
1014 Q_ASSERT(dockWidget);
1015 Q_UNUSED(topLevel)
1016 if (!dockWidget)
1017 {
1018 return;
1019 }
1020
1021 // fix pixmaps
1022 this->setTabPixmaps();
1023
1024 // select index
1025 if (!topLevel)
1026 {
1027 const CDockWidgetInfoArea *dwia = dynamic_cast<CDockWidgetInfoArea *>(dockWidget);
1028 this->selectArea(dwia);
1029 }
1030
1031 // KB commented out with T592
1032 // when toplevel is changed, I need a round in the event loop until
1033 // current tab bar widget is visible
1034 // QTimer::singleShot(250, this, &CInfoArea::emitInfoAreaStatus);
1035 }
1036
1037 void CInfoArea::onStyleSheetChanged()
1038 {
1039 if (m_tabBar)
1040 {
1041 if (!sGui || sGui->isShuttingDown())
1042 {
1043 return;
1044 }
1046 m_tabBar->setStyleSheet(qss);
1047 }
1048 }
1049
1050 void CInfoArea::showContextMenu(const QPoint &pos)
1051 {
1052 QPoint globalPos = this->mapToGlobal(pos);
1053 QScopedPointer<QMenu> contextMenu(new QMenu(this));
1054 this->addToContextMenu(contextMenu.data());
1055
1056 QAction *selectedItem = contextMenu.data()->exec(globalPos);
1057 Q_UNUSED(selectedItem)
1058 }
1059
1060 void CInfoArea::showTabTexts(bool show)
1061 {
1062 if (show == m_showTabTexts)
1063 {
1064 return;
1065 }
1066 m_showTabTexts = show;
1067 for (CDockWidgetInfoArea *dw : std::as_const(m_dockWidgetInfoAreas))
1068 {
1069 dw->showTitleWhenDocked(show);
1070 }
1071 }
1072
1073 void CInfoArea::showTabBar(bool show)
1074 {
1075 if (show == m_showTabBar) return;
1076 m_showTabBar = show;
1077 if (!m_tabBar) return;
1078 m_tabBar->setVisible(show); // not working, but setting right value will not harm anything
1079 m_tabBar->setMaximumHeight(show ? 10000 : 0); // does the trick
1081 }
1082
1083 void CInfoArea::toggleTabBarLocked(bool locked) { m_lockTabBar = locked; }
1084
1086 {
1087 Q_ASSERT_X(position == QTabWidget::North || position == QTabWidget::South, Q_FUNC_INFO,
1088 "Wrong tabbar position");
1089 this->setTabPosition(Qt::TopDockWidgetArea, position);
1090 }
1091
1092 void CInfoArea::toggleTabBarPosition()
1093 {
1096 this->setTabBarPosition(p);
1097 }
1098
1100 {
1101 if (this->isFloating())
1102 {
1104 event->setAccepted(false); // refuse -> do not close
1105 }
1106 else
1107 {
1109 }
1110 }
1111} // namespace swift::gui
bool isShuttingDown() const
Is application shutting down?
Our base class for dockable widgets containing some specialized functionality on top of QDockWidget.
Definition dockwidget.h:52
void toggleVisibility()
Toggle visibility.
void widgetTopLevelChanged(CDockWidget *, bool topLevel)
Top level has changed for given widget.
bool restoreFromSettings()
Restore from settings.
bool isWidgetVisible() const
Is widget visible? Not to be confused with.
void toggleFloating()
Toggle floating.
void resetPosition()
Reset window position.
const QString & windowTitleBackup() const
Window title backup.
Definition dockwidget.h:66
Specialized class for dock widgets serving as info area.
CEnableForFramelessWindow(WindowMode mode, bool isMainApplicationWindow, const char *framelessPropertyname, QWidget *correspondingWidget)
Constructor.
const CStyleSheetUtility & getStyleSheetUtility() const
Style sheet handling.
void styleSheetsChanged()
Style sheet changed.
static bool stayOnTop(bool onTop, QWidget *widget)
Window flags / stay on top.
static QPoint mainWidgetGlobalPosition()
Position of main widget.
static bool lenientTitleComparison(const QString &title, const QString &comparison)
Lenient / relaxed.
virtual void toggleFloatingWholeInfoArea()
Toggle dock / floating of the whole info area.
Definition infoarea.cpp:428
CInfoArea(QWidget *parent=nullptr)
Constructor.
Definition infoarea.cpp:38
void selectLeftTab()
Select next left tab.
Definition infoarea.cpp:562
void changedInfoAreaStatus(int currentTabIndex, QList< int > dockedAreas, QList< int > floatingAreas)
Status of info area changed.
void addToContextMenu(QMenu *menu) const
Add items to context menu.
Definition infoarea.cpp:87
void toggleFloatingByIndex(int areaIndex)
Toggle floating of index.
Definition infoarea.cpp:430
void closeEvent(QCloseEvent *event)
void toggleVisibility(int areaIndex)
Toggle visibilty.
Definition infoarea.cpp:445
void selectArea(int areaIndex)
Select area.
Definition infoarea.cpp:460
void toggleAreaFloatingByAction()
Toggle area floating (sender is QAction).
Definition infoarea.cpp:521
QList< QAction * > getInfoAreaRestoreActions(QWidget *parent) const
Create a list of actions to restore the info areas. This could be used in a menu or somewhere else.
Definition infoarea.cpp:313
void floatAllWidgets()
All widgets floating.
Definition infoarea.cpp:379
QList< QAction * > getInfoAreaToggleFloatingActions(QWidget *parent) const
Create a list of actions to select the info areas and toogle its floating state. This could be used i...
Definition infoarea.cpp:294
void adjustSizeForAllDockWidgets()
Adjust size for all dock widgets.
Definition infoarea.cpp:371
void setTabBarPosition(QTabWidget::TabPosition position)
Tab position for docked widgets tab.
void restoreDockWidgetInfoArea()
Restore dock widget`s state (from settings).
Definition infoarea.cpp:534
void paintEvent(QPaintEvent *event)
Definition infoarea.cpp:345
void selectRightTab()
Select next right tab.
Definition infoarea.cpp:576
void selectAreaByAction()
Select area (sender is QAction).
Definition infoarea.cpp:495
void resetAllWidgetSettings()
Reset all widget settings.
Definition infoarea.cpp:403
void initInfoArea()
Init area after(!) GUI is initialized.
Definition infoarea.cpp:45
void toggleTabBarLocked(bool locked)
Toogle lock tabbar.
void changedInfoAreaTabBarIndex(int index)
Tab bar changed.
QList< const CDockWidgetInfoArea * > getDockWidgetInfoAreas() const
Own dockable widgets.
Definition infoarea.cpp:242
virtual QSize getPreferredSizeWhenFloating(int areaIndex) const =0
Preferred size when floating (size hint).
void changedWholeInfoAreaFloating(bool floating)
Whole info area floating.
void dockAllWidgets()
Dock all widgets.
Definition infoarea.cpp:369
QList< int > getAreaIndexesDockedOrFloating(bool floating) const
Docked area indexes.
Definition infoarea.cpp:332
void restoreDockWidgetInfoAreaByIndex(int areaIndex)
Restore dock widget`s state (from settings).
Definition infoarea.cpp:547
QList< QAction * > getInfoAreaResetPositionActions(QWidget *parent) const
Create a list of actions to reset the position the info areas. This could be used in a menu or somewh...
Definition infoarea.cpp:275
void displayStatusMessages(const swift::misc::CStatusMessageList &statusMessages)
Display status messages in all info areas (according their state).
Definition infoarea.cpp:602
bool isFloating() const
Is the area floating?
Definition infoarea.h:52
bool isSelectedDockWidgetInfoArea(const CDockWidgetInfoArea *infoArea) const
Is given widget selected. Means it is not floating, and the one selected.
Definition infoarea.cpp:186
void resetAllFloatingWidgetSettings()
Reset all floating widget settings.
Definition infoarea.cpp:391
virtual const QPixmap & indexToPixmap(int areaIndex) const =0
Info area (index) to icon.
QList< QAction * > getInfoAreaSelectActions(bool withShortcut, QWidget *parent) const
Create a list of actions to select the info areas. This could be used in a menu or somewhere else.
Definition infoarea.cpp:247
void displayStatusMessage(const swift::misc::CStatusMessage &statusMessage)
Display status message in all info areas (according their state).
Definition infoarea.cpp:590
const CDockWidgetInfoArea * getSelectedDockInfoArea() const
Get the selected info area (non floating, selected in tabbar).
Definition infoarea.cpp:207
void resetPosition(int areaIndex)
Reset position.
Definition infoarea.cpp:484
int getSelectedDockInfoAreaIndex() const
Get the selected info area (non floating, selected in tabbar).
Definition infoarea.cpp:230
void keyPressEvent(QKeyEvent *event)
Definition infoarea.cpp:351
void resetPositionByAction()
Reset window position of area (sender is QAction).
Definition infoarea.cpp:508
void allFloatingOnTop()
All floating info areas on top.
Definition infoarea.cpp:415
static const QString & fileNameDockWidgetTab()
File name dockwidgettab.qss.
static bool useStyleSheetInDerivedWidget(QWidget *derivedWidget, QStyle::PrimitiveElement element=QStyle::PE_Widget)
Use style sheets in derived widgets.
QString style(const QString &fileName) const
Style for given file name.
static const QPixmap & refresh16()
Refresh.
static const QPixmap & floatAll16()
Float all.
static const QPixmap & headingOne16()
Heading 1.
static const QPixmap & dockBottom16()
Docking.
static const QPixmap & floatOne16()
Float all.
static const QPixmap & dockTop16()
Docking.
static const QPixmap & load16()
Load.
static const QPixmap & lockClosed16()
Lock.
Streamable status message, e.g.
Status messages, e.g. from Core -> GUI.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
GUI related classes.
Free functions in swift::misc.
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
Definition range.h:328
void toggled(bool checked)
void triggered(bool checked)
bool isFloating() const const
int key() const const
void append(QList< T > &&value)
QMainWindow(QWidget *parent, Qt::WindowFlags flags)
void addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget)
virtual bool event(QEvent *event) override
void setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
void splitDockWidget(QDockWidget *first, QDockWidget *second, Qt::Orientation orientation)
QStatusBar * statusBar() const const
QTabWidget::TabPosition tabPosition(Qt::DockWidgetArea area) const const
void tabifyDockWidget(QDockWidget *first, QDockWidget *second)
QAction * addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
QAction * addMenu(QMenu *menu)
QAction * addSeparator()
QObject(QObject *parent)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T findChild(QAnyStringView name, Qt::FindChildOptions options) const const
QList< T > findChildren(QAnyStringView name, Qt::FindChildOptions options) const const
QObject * parent() const const
T qobject_cast(QObject *object)
QObject * sender() const const
int & rx()
int & ry()
void mappedInt(int i)
const QChar at(qsizetype position) const const
bool isEmpty() const const
qsizetype length() const const
QueuedConnection
CustomContextMenu
TopDockWidgetArea
FindDirectChildrenOnly
Key_Right
Horizontal
ElideNone
void currentChanged(int index)
void tabBarDoubleClicked(int index)
QWidget(QWidget *parent, Qt::WindowFlags f)
QList< QAction * > actions() const const
virtual void closeEvent(QCloseEvent *event)
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
void customContextMenuRequested(const QPoint &pos)
void hide()
virtual void keyPressEvent(QKeyEvent *event)
QPoint mapToGlobal(const QPoint &pos) const const
void setMaximumHeight(int maxh)
QWidget * parentWidget() const const
void move(const QPoint &)
void show()
virtual void setVisible(bool visible)
void setWindowFlags(Qt::WindowFlags type)
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition verify.h:26
#define SWIFT_VERIFY(COND)
A weaker kind of assert.
Definition verify.h:29