1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 Uwe Kindler
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 or (at your option) any later version.
19 ** The licenses are as published by the Free Software Foundation
20 ** and appearing in the file LICENSE.LGPLv21 included in the packaging
21 ** of this file. Please review the following information to ensure
22 ** the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 3 or (at your option) any later version
28 ** approved by the KDE Free Qt Foundation. The licenses are as published by
29 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
30 ** included in the packaging of this file. Please review the following
31 ** information to ensure the GNU General Public License requirements will
32 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
33 **
34 ****************************************************************************/
35 
36 #include "dockareawidget.h"
37 
38 #include "dockareatabbar.h"
39 #include "dockareatitlebar.h"
40 #include "dockcomponentsfactory.h"
41 #include "dockcontainerwidget.h"
42 #include "dockmanager.h"
43 #include "dockoverlay.h"
44 #include "docksplitter.h"
45 #include "dockwidget.h"
46 #include "dockwidgettab.h"
47 #include "floatingdockcontainer.h"
48 
49 #include <QList>
50 #include <QLoggingCategory>
51 #include <QMenu>
52 #include <QPushButton>
53 #include <QScrollArea>
54 #include <QScrollBar>
55 #include <QSplitter>
56 #include <QStackedLayout>
57 #include <QStyle>
58 #include <QVector>
59 #include <QWheelEvent>
60 #include <QXmlStreamWriter>
61 
62 #include <iostream>
63 
64 static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg)
65 
66 namespace ADS
67 {
68     static const char *const INDEX_PROPERTY = "index";
69     static const char *const ACTION_PROPERTY = "action";
70 
71     /**
72      * Internal dock area layout mimics stack layout but only inserts the current
73      * widget into the internal QLayout object.
74      * \warning Only the current widget has a parent. All other widgets
75      * do not have a parent. That means, a widget that is in this layout may
76      * return nullptr for its parent() function if it is not the current widget.
77      */
78     class DockAreaLayout
79     {
80     private:
81         QBoxLayout *m_parentLayout;
82         QList<QWidget *> m_widgets;
83         int m_currentIndex = -1;
84         QWidget *m_currentWidget = nullptr;
85 
86     public:
87     /**
88       * Creates an instance with the given parent layout
89       */
DockAreaLayout(QBoxLayout * parentLayout)90         DockAreaLayout(QBoxLayout *parentLayout)
91             : m_parentLayout(parentLayout)
92         {}
93 
94         /**
95          * Returns the number of widgets in this layout
96          */
count() const97         int count() const { return m_widgets.count(); }
98 
99         /**
100          * Inserts the widget at the given index position into the internal widget
101          * list
102          */
insertWidget(int index,QWidget * widget)103         void insertWidget(int index, QWidget *widget)
104         {
105             widget->setParent(nullptr);
106             if (index < 0)
107                 index = m_widgets.count();
108 
109             m_widgets.insert(index, widget);
110             if (m_currentIndex < 0) {
111                 setCurrentIndex(index);
112             } else {
113                 if (index <= m_currentIndex)
114                     ++m_currentIndex;
115             }
116         }
117 
118         /**
119          * Removes the given widget from the layout
120          */
removeWidget(QWidget * widget)121         void removeWidget(QWidget *widget)
122         {
123             if (currentWidget() == widget) {
124                 auto layoutItem = m_parentLayout->takeAt(1);
125                 if (layoutItem)
126                     layoutItem->widget()->setParent(nullptr);
127 
128                 m_currentWidget = nullptr;
129                 m_currentIndex = -1;
130             } else if (indexOf(widget) < m_currentIndex) {
131                 --m_currentIndex;
132             }
133             m_widgets.removeOne(widget);
134         }
135 
136         /**
137          * Returns the current selected widget
138          */
currentWidget() const139         QWidget *currentWidget() const { return m_currentWidget; }
140 
141         /**
142          * Activates the widget with the give index.
143          */
setCurrentIndex(int index)144         void setCurrentIndex(int index)
145         {
146             QWidget *prev = currentWidget();
147             QWidget *next = widget(index);
148             if (!next || (next == prev && !m_currentWidget))
149                 return;
150 
151             bool reenableUpdates = false;
152             QWidget *parent = m_parentLayout->parentWidget();
153 
154             if (parent && parent->updatesEnabled()) {
155                 reenableUpdates = true;
156                 parent->setUpdatesEnabled(false);
157             }
158 
159             if (auto layoutItem = m_parentLayout->takeAt(1))
160                 layoutItem->widget()->setParent(nullptr);
161 
162             m_parentLayout->addWidget(next);
163             if (prev)
164                 prev->hide();
165 
166             m_currentIndex = index;
167             m_currentWidget = next;
168 
169             if (reenableUpdates)
170                 parent->setUpdatesEnabled(true);
171         }
172 
173         /**
174          * Returns the index of the current active widget
175          */
currentIndex() const176         int currentIndex() const { return m_currentIndex; }
177 
178         /**
179          * Returns true if there are no widgets in the layout
180          */
isEmpty() const181         bool isEmpty() const { return m_widgets.empty(); }
182 
183         /**
184          * Returns the index of the given widget
185          */
indexOf(QWidget * widget) const186         int indexOf(QWidget *widget) const { return m_widgets.indexOf(widget); }
187 
188         /**
189          * Returns the widget for the given index
190          */
widget(int index) const191         QWidget *widget(int index) const
192         {
193             return (index < m_widgets.size()) ? m_widgets.at(index) : nullptr;
194         }
195 
196         /**
197          * Returns the geometry of the current active widget
198          */
geometry() const199         QRect geometry() const { return m_widgets.empty() ? QRect() : currentWidget()->geometry(); }
200     };
201 
202     /**
203      * Private data class of DockAreaWidget class (pimpl)
204      */
205     struct DockAreaWidgetPrivate
206     {
207         DockAreaWidget *q = nullptr;
208         QBoxLayout *m_layout = nullptr;
209         DockAreaLayout *m_contentsLayout = nullptr;
210         DockAreaTitleBar *m_titleBar = nullptr;
211         DockManager *m_dockManager = nullptr;
212         bool m_updateTitleBarButtons = false;
213         DockWidgetAreas m_allowedAreas = AllDockAreas;
214         QSize m_minSizeHint;
215 
216         /**
217          * Private data constructor
218          */
219         DockAreaWidgetPrivate(DockAreaWidget *parent);
220 
221         /**
222          * Creates the layout for top area with tabs and close button
223          */
224         void createTitleBar();
225 
226         /**
227          * Returns the dock widget with the given index
228          */
dockWidgetAtADS::DockAreaWidgetPrivate229         DockWidget *dockWidgetAt(int index)
230         {
231             return qobject_cast<DockWidget *>(m_contentsLayout->widget(index));
232         }
233 
234         /**
235          * Convenience function to ease title widget access by index
236          */
tabWidgetAtADS::DockAreaWidgetPrivate237         DockWidgetTab *tabWidgetAt(int index) { return dockWidgetAt(index)->tabWidget(); }
238 
239         /**
240          * Returns the tab action of the given dock widget
241          */
dockWidgetTabActionADS::DockAreaWidgetPrivate242         QAction *dockWidgetTabAction(DockWidget *dockWidget) const
243         {
244             return qvariant_cast<QAction *>(dockWidget->property(ACTION_PROPERTY));
245         }
246 
247         /**
248          * Returns the index of the given dock widget
249          */
dockWidgetIndexADS::DockAreaWidgetPrivate250         int dockWidgetIndex(DockWidget *dockWidget) const
251         {
252             return dockWidget->property(INDEX_PROPERTY).toInt();
253         }
254 
255         /**
256          * Convenience function for tabbar access
257          */
tabBarADS::DockAreaWidgetPrivate258         DockAreaTabBar *tabBar() const { return m_titleBar->tabBar(); }
259 
260         /**
261          * Updates the enable state of the close and detach button
262          */
263         void updateTitleBarButtonStates();
264 
265         /**
266          * Scans all contained dock widgets for the max. minimum size hint
267          */
updateMinimumSizeHintADS::DockAreaWidgetPrivate268         void updateMinimumSizeHint()
269         {
270             m_minSizeHint = QSize();
271             for (int i = 0; i < m_contentsLayout->count(); ++i)
272             {
273                 auto widget = m_contentsLayout->widget(i);
274                 m_minSizeHint.setHeight(qMax(m_minSizeHint.height(),
275                                              widget->minimumSizeHint().height()));
276                 m_minSizeHint.setWidth(qMax(m_minSizeHint.width(),
277                                             widget->minimumSizeHint().width()));
278             }
279         }
280     };
281     // struct DockAreaWidgetPrivate
282 
DockAreaWidgetPrivate(DockAreaWidget * parent)283     DockAreaWidgetPrivate::DockAreaWidgetPrivate(DockAreaWidget *parent)
284         : q(parent)
285     {}
286 
createTitleBar()287     void DockAreaWidgetPrivate::createTitleBar()
288     {
289         m_titleBar = componentsFactory()->createDockAreaTitleBar(q);
290         m_layout->addWidget(m_titleBar);
291         QObject::connect(tabBar(),
292                          &DockAreaTabBar::tabCloseRequested,
293                          q,
294                          &DockAreaWidget::onTabCloseRequested);
295         QObject::connect(m_titleBar,
296                          &DockAreaTitleBar::tabBarClicked,
297                          q,
298                          &DockAreaWidget::setCurrentIndex);
299         QObject::connect(tabBar(), &DockAreaTabBar::tabMoved, q, &DockAreaWidget::reorderDockWidget);
300     }
301 
updateTitleBarButtonStates()302     void DockAreaWidgetPrivate::updateTitleBarButtonStates()
303     {
304         if (q->isHidden()) {
305             m_updateTitleBarButtons = true;
306             return;
307         }
308 
309         m_titleBar->button(TitleBarButtonClose)
310             ->setEnabled(q->features().testFlag(DockWidget::DockWidgetClosable));
311         m_titleBar->button(TitleBarButtonUndock)
312             ->setEnabled(q->features().testFlag(DockWidget::DockWidgetFloatable));
313         m_titleBar->updateDockWidgetActionsButtons();
314         m_updateTitleBarButtons = false;
315     }
316 
DockAreaWidget(DockManager * dockManager,DockContainerWidget * parent)317     DockAreaWidget::DockAreaWidget(DockManager *dockManager, DockContainerWidget *parent)
318         : QFrame(parent)
319         , d(new DockAreaWidgetPrivate(this))
320     {
321         d->m_dockManager = dockManager;
322         d->m_layout = new QBoxLayout(QBoxLayout::TopToBottom);
323         d->m_layout->setContentsMargins(0, 0, 0, 0);
324         d->m_layout->setSpacing(0);
325         setLayout(d->m_layout);
326 
327         d->createTitleBar();
328         d->m_contentsLayout = new DockAreaLayout(d->m_layout);
329         if (d->m_dockManager)
330             emit d->m_dockManager->dockAreaCreated(this);
331     }
332 
~DockAreaWidget()333     DockAreaWidget::~DockAreaWidget()
334     {
335         qCInfo(adsLog) << Q_FUNC_INFO;
336         delete d->m_contentsLayout;
337         delete d;
338     }
339 
dockManager() const340     DockManager *DockAreaWidget::dockManager() const { return d->m_dockManager; }
341 
dockContainer() const342     DockContainerWidget *DockAreaWidget::dockContainer() const
343     {
344         return internal::findParent<DockContainerWidget *>(this);
345     }
346 
addDockWidget(DockWidget * dockWidget)347     void DockAreaWidget::addDockWidget(DockWidget *dockWidget)
348     {
349         insertDockWidget(d->m_contentsLayout->count(), dockWidget);
350     }
351 
insertDockWidget(int index,DockWidget * dockWidget,bool activate)352     void DockAreaWidget::insertDockWidget(int index, DockWidget *dockWidget, bool activate)
353     {
354         d->m_contentsLayout->insertWidget(index, dockWidget);
355         dockWidget->setDockArea(this);
356         dockWidget->tabWidget()->setDockAreaWidget(this);
357         auto tabWidget = dockWidget->tabWidget();
358         // Inserting the tab will change the current index which in turn will
359         // make the tab widget visible in the slot
360         d->tabBar()->blockSignals(true);
361         d->tabBar()->insertTab(index, tabWidget);
362         d->tabBar()->blockSignals(false);
363         tabWidget->setVisible(!dockWidget->isClosed());
364         dockWidget->setProperty(INDEX_PROPERTY, index);
365         d->m_minSizeHint.setHeight(qMax(d->m_minSizeHint.height(),
366                                         dockWidget->minimumSizeHint().height()));
367         d->m_minSizeHint.setWidth(qMax(d->m_minSizeHint.width(),
368                                        dockWidget->minimumSizeHint().width()));
369         if (activate)
370             setCurrentIndex(index);
371 
372         // If this dock area is hidden, then we need to make it visible again
373         // by calling dockWidget->toggleViewInternal(true);
374         if (!this->isVisible() && d->m_contentsLayout->count() > 1 && !dockManager()->isRestoringState())
375             dockWidget->toggleViewInternal(true);
376 
377         d->updateTitleBarButtonStates();
378     }
379 
removeDockWidget(DockWidget * dockWidget)380     void DockAreaWidget::removeDockWidget(DockWidget *dockWidget)
381     {
382         qCInfo(adsLog) << Q_FUNC_INFO;
383         auto nextOpen = nextOpenDockWidget(dockWidget);
384 
385         d->m_contentsLayout->removeWidget(dockWidget);
386         auto tabWidget = dockWidget->tabWidget();
387         tabWidget->hide();
388         d->tabBar()->removeTab(tabWidget);
389         DockContainerWidget *dockContainerWidget = dockContainer();
390         if (nextOpen) {
391             setCurrentDockWidget(nextOpen);
392         } else if (d->m_contentsLayout->isEmpty() && dockContainerWidget->dockAreaCount() >= 1) {
393             qCInfo(adsLog) << "Dock Area empty";
394             dockContainerWidget->removeDockArea(this);
395             this->deleteLater();
396         } else {
397             // if contents layout is not empty but there are no more open dock
398             // widgets, then we need to hide the dock area because it does not
399             // contain any visible content
400             hideAreaWithNoVisibleContent();
401         }
402 
403         d->updateTitleBarButtonStates();
404         updateTitleBarVisibility();
405         d->updateMinimumSizeHint();
406         auto topLevelDockWidget = dockContainerWidget->topLevelDockWidget();
407         if (topLevelDockWidget)
408             topLevelDockWidget->emitTopLevelChanged(true);
409 
410 #if (ADS_DEBUG_LEVEL > 0)
411         dockContainerWidget->dumpLayout();
412 #endif
413     }
414 
hideAreaWithNoVisibleContent()415     void DockAreaWidget::hideAreaWithNoVisibleContent()
416     {
417         this->toggleView(false);
418 
419         // Hide empty parent splitters
420         auto splitter = internal::findParent<DockSplitter *>(this);
421         internal::hideEmptyParentSplitters(splitter);
422 
423         //Hide empty floating widget
424         DockContainerWidget *container = this->dockContainer();
425         if (!container->isFloating()
426             && DockManager::testConfigFlag(DockManager::HideSingleCentralWidgetTitleBar))
427             return;
428 
429         updateTitleBarVisibility();
430         auto topLevelWidget = container->topLevelDockWidget();
431         auto floatingWidget = container->floatingWidget();
432         if (topLevelWidget) {
433             if (floatingWidget)
434                 floatingWidget->updateWindowTitle();
435 
436             DockWidget::emitTopLevelEventForWidget(topLevelWidget, true);
437         } else if (container->openedDockAreas().isEmpty() && floatingWidget) {
438             floatingWidget->hide();
439         }
440     }
441 
onTabCloseRequested(int index)442     void DockAreaWidget::onTabCloseRequested(int index)
443     {
444         qCInfo(adsLog) << Q_FUNC_INFO << "index" << index;
445         auto *currentDockWidget = dockWidget(index);
446         if (currentDockWidget->features().testFlag(DockWidget::DockWidgetDeleteOnClose))
447             currentDockWidget->closeDockWidgetInternal();
448         else
449             currentDockWidget->toggleView(false);
450     }
451 
currentDockWidget() const452     DockWidget *DockAreaWidget::currentDockWidget() const
453     {
454         int currentIdx = currentIndex();
455         if (currentIdx < 0)
456             return nullptr;
457 
458         return dockWidget(currentIdx);
459     }
460 
setCurrentDockWidget(DockWidget * dockWidget)461     void DockAreaWidget::setCurrentDockWidget(DockWidget *dockWidget)
462     {
463         if (dockManager()->isRestoringState())
464             return;
465 
466         internalSetCurrentDockWidget(dockWidget);
467     }
468 
internalSetCurrentDockWidget(DockWidget * dockWidget)469     void DockAreaWidget::internalSetCurrentDockWidget(DockWidget *dockWidget)
470     {
471         int index = indexOf(dockWidget);
472         if (index < 0)
473             return;
474 
475         setCurrentIndex(index);
476     }
477 
setCurrentIndex(int index)478     void DockAreaWidget::setCurrentIndex(int index)
479     {
480         auto currentTabBar = d->tabBar();
481         if (index < 0 || index > (currentTabBar->count() - 1)) {
482             qWarning() << Q_FUNC_INFO << "Invalid index" << index;
483             return;
484         }
485 
486         auto cw = d->m_contentsLayout->currentWidget();
487         auto nw = d->m_contentsLayout->widget(index);
488         if (cw == nw && !nw->isHidden())
489             return;
490 
491         emit currentChanging(index);
492         currentTabBar->setCurrentIndex(index);
493         d->m_contentsLayout->setCurrentIndex(index);
494         d->m_contentsLayout->currentWidget()->show();
495         emit currentChanged(index);
496     }
497 
currentIndex() const498     int DockAreaWidget::currentIndex() const { return d->m_contentsLayout->currentIndex(); }
499 
titleBarGeometry() const500     QRect DockAreaWidget::titleBarGeometry() const { return d->m_titleBar->geometry(); }
501 
contentAreaGeometry() const502     QRect DockAreaWidget::contentAreaGeometry() const { return d->m_contentsLayout->geometry(); }
503 
indexOf(DockWidget * dockWidget)504     int DockAreaWidget::indexOf(DockWidget *dockWidget)
505     {
506         return d->m_contentsLayout->indexOf(dockWidget);
507     }
508 
dockWidgets() const509     QList<DockWidget *> DockAreaWidget::dockWidgets() const
510     {
511         QList<DockWidget *> dockWidgetList;
512         for (int i = 0; i < d->m_contentsLayout->count(); ++i)
513             dockWidgetList.append(dockWidget(i));
514 
515         return dockWidgetList;
516     }
517 
openDockWidgetsCount() const518     int DockAreaWidget::openDockWidgetsCount() const
519     {
520         int count = 0;
521         for (int i = 0; i < d->m_contentsLayout->count(); ++i) {
522             if (!dockWidget(i)->isClosed())
523                 ++count;
524         }
525         return count;
526     }
527 
openedDockWidgets() const528     QList<DockWidget *> DockAreaWidget::openedDockWidgets() const
529     {
530         QList<DockWidget *> dockWidgetList;
531         for (int i = 0; i < d->m_contentsLayout->count(); ++i) {
532             DockWidget *currentDockWidget = dockWidget(i);
533             if (!currentDockWidget->isClosed())
534                 dockWidgetList.append(dockWidget(i));
535         }
536         return dockWidgetList;
537     }
538 
indexOfFirstOpenDockWidget() const539     int DockAreaWidget::indexOfFirstOpenDockWidget() const
540     {
541         for (int i = 0; i < d->m_contentsLayout->count(); ++i) {
542             if (!dockWidget(i)->isClosed())
543                 return i;
544         }
545 
546         return - 1;
547     }
548 
dockWidgetsCount() const549     int DockAreaWidget::dockWidgetsCount() const { return d->m_contentsLayout->count(); }
550 
dockWidget(int index) const551     DockWidget *DockAreaWidget::dockWidget(int index) const
552     {
553         return qobject_cast<DockWidget *>(d->m_contentsLayout->widget(index));
554     }
555 
reorderDockWidget(int fromIndex,int toIndex)556     void DockAreaWidget::reorderDockWidget(int fromIndex, int toIndex)
557     {
558         qCInfo(adsLog) << Q_FUNC_INFO;
559         if (fromIndex >= d->m_contentsLayout->count() || fromIndex < 0
560             || toIndex >= d->m_contentsLayout->count() || toIndex < 0 || fromIndex == toIndex) {
561             qCInfo(adsLog) << "Invalid index for tab movement" << fromIndex << toIndex;
562             return;
563         }
564 
565         auto widget = d->m_contentsLayout->widget(fromIndex);
566         d->m_contentsLayout->removeWidget(widget);
567         d->m_contentsLayout->insertWidget(toIndex, widget);
568         setCurrentIndex(toIndex);
569     }
570 
toggleDockWidgetView(DockWidget * dockWidget,bool open)571     void DockAreaWidget::toggleDockWidgetView(DockWidget *dockWidget, bool open)
572     {
573         Q_UNUSED(dockWidget)
574         Q_UNUSED(open)
575         updateTitleBarVisibility();
576     }
577 
updateTitleBarVisibility()578     void DockAreaWidget::updateTitleBarVisibility()
579     {
580         DockContainerWidget *container = dockContainer();
581         if (!container)
582             return;
583 
584         if (DockManager::testConfigFlag(DockManager::AlwaysShowTabs))
585             return;
586 
587         if (d->m_titleBar) {
588             bool hidden = container->hasTopLevelDockWidget() && (container->isFloating()
589                           || DockManager::testConfigFlag(DockManager::HideSingleCentralWidgetTitleBar));
590             d->m_titleBar->setVisible(!hidden);
591         }
592     }
593 
markTitleBarMenuOutdated()594     void DockAreaWidget::markTitleBarMenuOutdated()
595     {
596         if (d->m_titleBar)
597             d->m_titleBar->markTabsMenuOutdated();
598     }
599 
saveState(QXmlStreamWriter & stream) const600     void DockAreaWidget::saveState(QXmlStreamWriter &stream) const
601     {
602         stream.writeStartElement("area");
603         stream.writeAttribute("tabs", QString::number(d->m_contentsLayout->count()));
604         auto localDockWidget = currentDockWidget();
605         QString name = localDockWidget ? localDockWidget->objectName() : "";
606         stream.writeAttribute("current", name);
607         qCInfo(adsLog) << Q_FUNC_INFO << "TabCount: " << d->m_contentsLayout->count()
608                        << " Current: " << name;
609         for (int i = 0; i < d->m_contentsLayout->count(); ++i)
610             dockWidget(i)->saveState(stream);
611 
612         stream.writeEndElement();
613     }
614 
nextOpenDockWidget(DockWidget * dockWidget) const615     DockWidget *DockAreaWidget::nextOpenDockWidget(DockWidget *dockWidget) const
616     {
617         auto openDockWidgets = openedDockWidgets();
618         if (openDockWidgets.count() > 1
619             || (openDockWidgets.count() == 1 && openDockWidgets[0] != dockWidget)) {
620             DockWidget *nextDockWidget;
621             if (openDockWidgets.last() == dockWidget) {
622                 nextDockWidget = openDockWidgets[openDockWidgets.count() - 2];
623             } else {
624                 int nextIndex = openDockWidgets.indexOf(dockWidget) + 1;
625                 nextDockWidget = openDockWidgets[nextIndex];
626             }
627 
628             return nextDockWidget;
629         } else {
630             return nullptr;
631         }
632     }
633 
features(eBitwiseOperator mode) const634     DockWidget::DockWidgetFeatures DockAreaWidget::features(eBitwiseOperator mode) const
635     {
636         if (BitwiseAnd == mode) {
637             DockWidget::DockWidgetFeatures features(DockWidget::AllDockWidgetFeatures);
638             for (const auto dockWidget : dockWidgets())
639                 features &= dockWidget->features();
640 
641             return features;
642         } else {
643             DockWidget::DockWidgetFeatures features(DockWidget::NoDockWidgetFeatures);
644             for (const auto dockWidget : dockWidgets())
645                 features |= dockWidget->features();
646 
647             return features;
648         }
649     }
650 
toggleView(bool open)651     void DockAreaWidget::toggleView(bool open)
652     {
653         setVisible(open);
654 
655         emit viewToggled(open);
656     }
657 
setVisible(bool visible)658     void DockAreaWidget::setVisible(bool visible)
659     {
660         Super::setVisible(visible);
661         if (d->m_updateTitleBarButtons)
662             d->updateTitleBarButtonStates();
663     }
664 
setAllowedAreas(DockWidgetAreas areas)665     void DockAreaWidget::setAllowedAreas(DockWidgetAreas areas)
666     {
667         d->m_allowedAreas = areas;
668     }
669 
allowedAreas() const670     DockWidgetAreas DockAreaWidget::allowedAreas() const
671     {
672         return d->m_allowedAreas;
673     }
674 
titleBarButton(eTitleBarButton which) const675     QAbstractButton *DockAreaWidget::titleBarButton(eTitleBarButton which) const
676     {
677         return d->m_titleBar->button(which);
678     }
679 
closeArea()680     void DockAreaWidget::closeArea()
681     {
682         // If there is only one single dock widget and this widget has the
683         // DeleteOnClose feature, then we delete the dock widget now
684         auto openDockWidgets = openedDockWidgets();
685         if (openDockWidgets.count() == 1
686             && openDockWidgets[0]->features().testFlag(DockWidget::DockWidgetDeleteOnClose)) {
687             openDockWidgets[0]->closeDockWidgetInternal();
688         } else {
689             for (auto dockWidget : openedDockWidgets())
690                 dockWidget->toggleView(false);
691         }
692     }
693 
closeOtherAreas()694     void DockAreaWidget::closeOtherAreas() { dockContainer()->closeOtherAreas(this); }
695 
titleBar() const696     DockAreaTitleBar *DockAreaWidget::titleBar() const { return d->m_titleBar; }
697 
minimumSizeHint() const698     QSize DockAreaWidget::minimumSizeHint() const
699     {
700         return d->m_minSizeHint.isValid() ? d->m_minSizeHint : Super::minimumSizeHint();
701     }
702 
703 } // namespace ADS
704