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