diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2020-07-02 15:53:34 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2020-07-07 21:40:50 +0200 |
commit | 359616066e64eed947c6c91cb8902285ed79dd0d (patch) | |
tree | 4a152e8d546d691bc931570eb458e5d7378cf0ec /src/widgets | |
parent | 652459afde5d1ed350f198f212d19b067ce5c1a3 (diff) |
Refactor QTabBarPrivate::Tab and much of its usage in QTabBar
The type was broken in that it pretends to be a value, but didn't
implement the necessary operators for save copy, move, or comparison.
Tabs are supposed to be managed by Tab instance, as the crazy
implementation of operator== demonstrated.
Refactor the code to use it as a pointer consistently, even though this
means additional allocations for each tab. This is however acceptable
since there are not millions of tabs, and there is only a single place
where tabs are removed from the list.
Also use ranged for where possible, and never access the tabList using
operator[] to avoid detaches.
Use a std::unique_ptr for the animation in the tab, which implicitly
protects against attempts to copy a Tab, and allows us to use the
compiler generated default destructor. Add Q_DISABLE_COPY_MOVE for good
measure, the compiler-generated move semantics would not work either
due to the back-pointer from animation to the tab.
Change-Id: I8e8c071472f8f1f401b0f4f1dde074d800842934
Fixes: QTBUG-85394
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/widgets/qtabbar.cpp | 329 | ||||
-rw-r--r-- | src/widgets/widgets/qtabbar_p.h | 29 |
2 files changed, 187 insertions, 171 deletions
diff --git a/src/widgets/widgets/qtabbar.cpp b/src/widgets/widgets/qtabbar.cpp index 68ac7c3c59..7761bcea30 100644 --- a/src/widgets/widgets/qtabbar.cpp +++ b/src/widgets/widgets/qtabbar.cpp @@ -174,7 +174,7 @@ void QTabBarPrivate::initBasicStyleOption(QStyleOptionTab *option, int tabIndex) if (!option || (tabIndex < 0 || tabIndex >= totalTabs)) return; - const QTabBarPrivate::Tab &tab = tabList.at(tabIndex); + const QTabBarPrivate::Tab &tab = *tabList.at(tabIndex); option->initFrom(q); option->state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver); option->rect = q->tabRect(tabIndex); @@ -433,23 +433,13 @@ void QTabBarPrivate::init() useScrollButtons = !q->style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, nullptr, q); } -QTabBarPrivate::Tab *QTabBarPrivate::at(int index) -{ - return validIndex(index)?&tabList[index]:nullptr; -} - -const QTabBarPrivate::Tab *QTabBarPrivate::at(int index) const -{ - return validIndex(index)?&tabList[index]:nullptr; -} - int QTabBarPrivate::indexAtPos(const QPoint &p) const { Q_Q(const QTabBar); if (q->tabRect(currentIndex).contains(p)) return currentIndex; for (int i = 0; i < tabList.count(); ++i) - if (tabList.at(i).enabled && q->tabRect(i).contains(p)) + if (tabList.at(i)->enabled && q->tabRect(i).contains(p)) return i; return -1; } @@ -461,7 +451,6 @@ void QTabBarPrivate::layoutTabs() QSize size = q->size(); int last, available; int maxExtent; - int i; bool vertTabs = verticalTabs(shape); int tabChainIndex = 0; int hiddenTabs = 0; @@ -490,20 +479,21 @@ void QTabBarPrivate::layoutTabs() int minx = 0; int x = 0; int maxHeight = 0; - for (i = 0; i < tabList.count(); ++i) { - if (!tabList.at(i).visible) { + for (int i = 0; i < tabList.count(); ++i) { + const auto tab = tabList.at(i); + if (!tab->visible) { ++hiddenTabs; continue; } QSize sz = q->tabSizeHint(i); - tabList[i].maxRect = QRect(x, 0, sz.width(), sz.height()); + tab->maxRect = QRect(x, 0, sz.width(), sz.height()); x += sz.width(); maxHeight = qMax(maxHeight, sz.height()); sz = q->minimumTabSizeHint(i); - tabList[i].minRect = QRect(minx, 0, sz.width(), sz.height()); + tab->minRect = QRect(minx, 0, sz.width(), sz.height()); minx += sz.width(); tabChain[tabChainIndex].init(); - tabChain[tabChainIndex].sizeHint = tabList.at(i).maxRect.width(); + tabChain[tabChainIndex].sizeHint = tab->maxRect.width(); tabChain[tabChainIndex].minimumSize = sz.width(); tabChain[tabChainIndex].empty = false; tabChain[tabChainIndex].expansive = true; @@ -520,20 +510,21 @@ void QTabBarPrivate::layoutTabs() int miny = 0; int y = 0; int maxWidth = 0; - for (i = 0; i < tabList.count(); ++i) { - if (!tabList.at(i).visible) { + for (int i = 0; i < tabList.count(); ++i) { + auto tab = tabList.at(i); + if (!tab->visible) { ++hiddenTabs; continue; } QSize sz = q->tabSizeHint(i); - tabList[i].maxRect = QRect(0, y, sz.width(), sz.height()); + tab->maxRect = QRect(0, y, sz.width(), sz.height()); y += sz.height(); maxWidth = qMax(maxWidth, sz.width()); sz = q->minimumTabSizeHint(i); - tabList[i].minRect = QRect(0, miny, sz.width(), sz.height()); + tab->data = QRect(0, miny, sz.width(), sz.height()); miny += sz.height(); tabChain[tabChainIndex].init(); - tabChain[tabChainIndex].sizeHint = tabList.at(i).maxRect.height(); + tabChain[tabChainIndex].sizeHint = tab->maxRect.height(); tabChain[tabChainIndex].minimumSize = sz.height(); tabChain[tabChainIndex].empty = false; tabChain[tabChainIndex].expansive = true; @@ -561,17 +552,18 @@ void QTabBarPrivate::layoutTabs() // Use the results hiddenTabs = 0; - for (i = 0; i < tabList.count(); ++i) { - if (!tabList.at(i).visible) { - tabList[i].rect = QRect(); + for (int i = 0; i < tabList.count(); ++i) { + auto tab = tabList.at(i); + if (!tab->visible) { + tab->rect = QRect(); ++hiddenTabs; continue; } const QLayoutStruct &lstruct = tabChain.at(i + 1 - hiddenTabs); if (!vertTabs) - tabList[i].rect.setRect(lstruct.pos, 0, lstruct.size, maxExtent); + tab->rect.setRect(lstruct.pos, 0, lstruct.size, maxExtent); else - tabList[i].rect.setRect(0, lstruct.pos, maxExtent, lstruct.size); + tab->rect.setRect(0, lstruct.pos, maxExtent, lstruct.size); } if (useScrollButtons && tabList.count() && last > available) { @@ -659,7 +651,7 @@ QRect QTabBarPrivate::normalizedScrollRect(int index) } bool tearTopVisible = index != 0 && topEdge != -scrollOffset; - bool tearBottomVisible = index != tabList.size() - 1 && bottomEdge != tabList.constLast().rect.bottom() + 1 - scrollOffset; + bool tearBottomVisible = index != tabList.size() - 1 && bottomEdge != tabList.constLast()->rect.bottom() + 1 - scrollOffset; if (tearTopVisible && !tearLeftRect.isNull()) topEdge = tearLeftRect.bottom() + 1; if (tearBottomVisible && !tearRightRect.isNull()) @@ -690,7 +682,7 @@ QRect QTabBarPrivate::normalizedScrollRect(int index) } bool tearLeftVisible = index != 0 && leftEdge != -scrollOffset; - bool tearRightVisible = index != tabList.size() - 1 && rightEdge != tabList.constLast().rect.right() + 1 - scrollOffset; + bool tearRightVisible = index != tabList.size() - 1 && rightEdge != tabList.constLast()->rect.right() + 1 - scrollOffset; if (tearLeftVisible && !tearLeftRect.isNull()) leftEdge = tearLeftRect.right() + 1; if (tearRightVisible && !tearRightRect.isNull()) @@ -715,12 +707,12 @@ void QTabBarPrivate::makeVisible(int index) if (!validIndex(index) || leftB->isHidden()) return; - const QRect tabRect = tabList.at(index).rect; + const QRect tabRect = tabList.at(index)->rect; const int oldScrollOffset = scrollOffset; const bool horiz = !verticalTabs(shape); const int tabStart = horiz ? tabRect.left() : tabRect.top(); const int tabEnd = horiz ? tabRect.right() : tabRect.bottom(); - const int lastTabEnd = horiz ? tabList.constLast().rect.right() : tabList.constLast().rect.bottom(); + const int lastTabEnd = horiz ? tabList.constLast()->rect.right() : tabList.constLast()->rect.bottom(); const QRect scrollRect = normalizedScrollRect(index); const int scrolledTabBarStart = qMax(1, scrollRect.left() + scrollOffset); const int scrolledTabBarEnd = qMin(lastTabEnd - 1, scrollRect.right() + scrollOffset); @@ -757,34 +749,34 @@ void QTabBarPrivate::layoutTab(int index) Q_Q(QTabBar); Q_ASSERT(index >= 0); - Tab &tab = tabList[index]; + const Tab *tab = tabList.at(index); bool vertical = verticalTabs(shape); - if (!(tab.leftWidget || tab.rightWidget)) + if (!(tab->leftWidget || tab->rightWidget)) return; QStyleOptionTab opt; q->initStyleOption(&opt, index); - if (tab.leftWidget) { + if (tab->leftWidget) { QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabLeftButton, &opt, q); QPoint p = rect.topLeft(); if ((index == pressedIndex) || paintWithOffsets) { if (vertical) - p.setY(p.y() + tabList[index].dragOffset); + p.setY(p.y() + tab->dragOffset); else - p.setX(p.x() + tabList[index].dragOffset); + p.setX(p.x() + tab->dragOffset); } - tab.leftWidget->move(p); + tab->leftWidget->move(p); } - if (tab.rightWidget) { + if (tab->rightWidget) { QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabRightButton, &opt, q); QPoint p = rect.topLeft(); if ((index == pressedIndex) || paintWithOffsets) { if (vertical) - p.setY(p.y() + tab.dragOffset); + p.setY(p.y() + tab->dragOffset); else - p.setX(p.x() + tab.dragOffset); + p.setX(p.x() + tab->dragOffset); } - tab.rightWidget->move(p); + tab->rightWidget->move(p); } } @@ -812,12 +804,12 @@ void QTabBarPrivate::_q_closeTab() QTabBar::ButtonPosition closeSide = (QTabBar::ButtonPosition)q->style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, nullptr, q); for (int i = 0; i < tabList.count(); ++i) { if (closeSide == QTabBar::LeftSide) { - if (tabList.at(i).leftWidget == object) { + if (tabList.at(i)->leftWidget == object) { tabToClose = i; break; } } else { - if (tabList.at(i).rightWidget == object) { + if (tabList.at(i)->rightWidget == object) { tabToClose = i; break; } @@ -837,7 +829,7 @@ void QTabBarPrivate::_q_scrollTabs() if (sender == leftB) { for (i = tabList.count() - 1; i >= 0; --i) { - int start = horizontal ? tabList.at(i).rect.left() : tabList.at(i).rect.top(); + int start = horizontal ? tabList.at(i)->rect.left() : tabList.at(i)->rect.top(); if (start < scrollRect.left() + scrollOffset) { makeVisible(i); return; @@ -845,7 +837,7 @@ void QTabBarPrivate::_q_scrollTabs() } } else if (sender == rightB) { for (i = 0; i < tabList.count(); ++i) { - int end = horizontal ? tabList.at(i).rect.right() : tabList.at(i).rect.bottom(); + int end = horizontal ? tabList.at(i)->rect.right() : tabList.at(i)->rect.bottom(); if (end > scrollRect.right() + scrollOffset) { makeVisible(i); return; @@ -990,12 +982,12 @@ int QTabBar::insertTab(int index, const QIcon& icon, const QString &text) Q_D(QTabBar); if (!d->validIndex(index)) { index = d->tabList.count(); - d->tabList.append(QTabBarPrivate::Tab(icon, text)); + d->tabList.append(new QTabBarPrivate::Tab(icon, text)); } else { - d->tabList.insert(index, QTabBarPrivate::Tab(icon, text)); + d->tabList.insert(index, new QTabBarPrivate::Tab(icon, text)); } #ifndef QT_NO_SHORTCUT - d->tabList[index].shortcutId = grabShortcut(QKeySequence::mnemonic(text)); + d->tabList.at(index)->shortcutId = grabShortcut(QKeySequence::mnemonic(text)); #endif d->firstVisible = qMax(qMin(index, d->firstVisible), 0); d->lastVisible = qMax(index, d->lastVisible); @@ -1016,9 +1008,9 @@ int QTabBar::insertTab(int index, const QIcon& icon, const QString &text) setTabButton(index, closeSide, closeButton); } - for (int i = 0; i < d->tabList.count(); ++i) { - if (d->tabList[i].lastTab >= index) - ++d->tabList[i].lastTab; + for (const auto tab : qAsConst(d->tabList)) { + if (tab->lastTab >= index) + ++tab->lastTab; } tabInserted(index); @@ -1036,30 +1028,32 @@ void QTabBar::removeTab(int index) { Q_D(QTabBar); if (d->validIndex(index)) { + auto removedTab = d->tabList.at(index); if (d->dragInProgress) d->moveTabFinished(d->pressedIndex); #ifndef QT_NO_SHORTCUT - releaseShortcut(d->tabList.at(index).shortcutId); + releaseShortcut(d->tabList.at(index)->shortcutId); #endif - if (d->tabList[index].leftWidget) { - d->tabList[index].leftWidget->hide(); - d->tabList[index].leftWidget->deleteLater(); - d->tabList[index].leftWidget = nullptr; + if (removedTab->leftWidget) { + removedTab->leftWidget->hide(); + removedTab->leftWidget->deleteLater(); + removedTab->leftWidget = nullptr; } - if (d->tabList[index].rightWidget) { - d->tabList[index].rightWidget->hide(); - d->tabList[index].rightWidget->deleteLater(); - d->tabList[index].rightWidget = nullptr; + if (removedTab->rightWidget) { + removedTab->rightWidget->hide(); + removedTab->rightWidget->deleteLater(); + removedTab->rightWidget = nullptr; } - int newIndex = d->tabList[index].lastTab; + int newIndex = removedTab->lastTab; d->tabList.removeAt(index); - for (int i = 0; i < d->tabList.count(); ++i) { - if (d->tabList[i].lastTab == index) - d->tabList[i].lastTab = -1; - if (d->tabList[i].lastTab > index) - --d->tabList[i].lastTab; + delete removedTab; + for (auto tab : qAsConst(d->tabList)) { + if (tab->lastTab == index) + tab->lastTab = -1; + if (tab->lastTab > index) + --tab->lastTab; } d->calculateFirstLastVisible(index, false, true); @@ -1074,7 +1068,7 @@ void QTabBar::removeTab(int index) case SelectPreviousTab: if (newIndex > index) newIndex--; - if (d->validIndex(newIndex) && d->tabList.at(newIndex).visible) + if (d->validIndex(newIndex) && d->tabList.at(newIndex)->visible) break; Q_FALLTHROUGH(); case SelectRightTab: @@ -1091,9 +1085,9 @@ void QTabBar::removeTab(int index) if (d->validIndex(newIndex)) { // don't loose newIndex's old through setCurrentIndex - int bump = d->tabList[newIndex].lastTab; + int bump = d->tabList.at(newIndex)->lastTab; setCurrentIndex(newIndex); - d->tabList[newIndex].lastTab = bump; + d->tabList.at(newIndex)->lastTab = bump; } } else { emit currentChanged(-1); @@ -1161,7 +1155,7 @@ bool QTabBar::isTabVisible(int index) const { Q_D(const QTabBar); if (d->validIndex(index)) - return d->tabList.at(index).visible; + return d->tabList.at(index)->visible; return false; } @@ -1426,13 +1420,15 @@ void QTabBar::setCurrentIndex(int index) Q_D(QTabBar); if (d->dragInProgress && d->pressedIndex != -1) return; + if (d->currentIndex == index) + return; int oldIndex = d->currentIndex; - if (d->validIndex(index) && d->currentIndex != index) { + if (auto tab = d->at(index)) { d->currentIndex = index; update(); d->makeVisible(index); - d->tabList[index].lastTab = oldIndex; + tab->lastTab = oldIndex; if (oldIndex >= 0 && oldIndex < count()) d->layoutTab(oldIndex); d->layoutTab(index); @@ -1501,9 +1497,9 @@ QSize QTabBar::sizeHint() const if (d->layoutDirty) const_cast<QTabBarPrivate*>(d)->layoutTabs(); QRect r; - for (int i = 0; i < d->tabList.count(); ++i) { - if (d->tabList.at(i).visible) - r = r.united(d->tabList.at(i).maxRect); + for (const auto tab : d->tabList) { + if (tab->visible) + r = r.united(tab->maxRect); } return r.size(); } @@ -1517,9 +1513,9 @@ QSize QTabBar::minimumSizeHint() const const_cast<QTabBarPrivate*>(d)->layoutTabs(); if (!d->useScrollButtons) { QRect r; - for (int i = 0; i < d->tabList.count(); ++i) { - if (d->tabList.at(i).visible) - r = r.united(d->tabList.at(i).minRect); + for (const auto tab : d->tabList) { + if (tab->visible) + r = r.united(tab->minRect); } return r.size(); } @@ -1562,11 +1558,11 @@ static QString computeElidedText(Qt::TextElideMode mode, const QString &text) QSize QTabBar::minimumTabSizeHint(int index) const { Q_D(const QTabBar); - QTabBarPrivate::Tab &tab = const_cast<QTabBarPrivate::Tab&>(d->tabList[index]); - QString oldText = tab.text; - tab.text = computeElidedText(d->elideMode, oldText); + QTabBarPrivate::Tab *tab = d->tabList.at(index); + QString oldText = tab->text; + tab->text = computeElidedText(d->elideMode, oldText); QSize size = tabSizeHint(index); - tab.text = oldText; + tab->text = oldText; return size; } @@ -1580,7 +1576,7 @@ QSize QTabBar::tabSizeHint(int index) const if (const QTabBarPrivate::Tab *tab = d->at(index)) { QStyleOptionTab opt; d->initBasicStyleOption(&opt, index); - opt.text = d->tabList.at(index).text; + opt.text = tab->text; QSize iconSize = tab->icon.isNull() ? QSize(0, 0) : opt.iconSize; int hframe = style()->pixelMetric(QStyle::PM_TabBarTabHSpace, &opt, this); int vframe = style()->pixelMetric(QStyle::PM_TabBarTabVSpace, &opt, this); @@ -1746,7 +1742,7 @@ bool QTabBar::event(QEvent *event) case QEvent::Shortcut: { QShortcutEvent *se = static_cast<QShortcutEvent *>(event); for (int i = 0; i < d->tabList.count(); ++i) { - const QTabBarPrivate::Tab *tab = &d->tabList.at(i); + const QTabBarPrivate::Tab *tab = d->tabList.at(i); if (tab->shortcutId == se->shortcutId()) { setCurrentIndex(i); return true; @@ -1836,64 +1832,66 @@ void QTabBar::paintEvent(QPaintEvent *) p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase); for (int i = 0; i < d->tabList.count(); ++i) { - if (!d->at(i)->visible) + const auto tab = d->tabList.at(i); + if (!tab->visible) continue; - QStyleOptionTab tab; - initStyleOption(&tab, i); - if (d->paintWithOffsets && d->tabList[i].dragOffset != 0) { + QStyleOptionTab tabOption; + initStyleOption(&tabOption, i); + if (d->paintWithOffsets && tab->dragOffset != 0) { if (vertical) { - tab.rect.moveTop(tab.rect.y() + d->tabList[i].dragOffset); + tabOption.rect.moveTop(tabOption.rect.y() + tab->dragOffset); } else { - tab.rect.moveLeft(tab.rect.x() + d->tabList[i].dragOffset); + tabOption.rect.moveLeft(tabOption.rect.x() + tab->dragOffset); } } - if (!(tab.state & QStyle::State_Enabled)) { - tab.palette.setCurrentColorGroup(QPalette::Disabled); + if (!(tabOption.state & QStyle::State_Enabled)) { + tabOption.palette.setCurrentColorGroup(QPalette::Disabled); } // If this tab is partially obscured, make a note of it so that we can pass the information // along when we draw the tear. - QRect tabRect = d->tabList[i].rect; + QRect tabRect = tab->rect; int tabStart = vertical ? tabRect.top() : tabRect.left(); int tabEnd = vertical ? tabRect.bottom() : tabRect.right(); if (tabStart < scrollRect.left() + d->scrollOffset) { cutLeft = i; - cutTabLeft = tab; + cutTabLeft = tabOption; } else if (tabEnd > scrollRect.right() + d->scrollOffset) { cutRight = i; - cutTabRight = tab; + cutTabRight = tabOption; } // Don't bother drawing a tab if the entire tab is outside of the visible tab bar. - if ((!vertical && (tab.rect.right() < 0 || tab.rect.left() > width())) - || (vertical && (tab.rect.bottom() < 0 || tab.rect.top() > height()))) + if ((!vertical && (tabOption.rect.right() < 0 || tabOption.rect.left() > width())) + || (vertical && (tabOption.rect.bottom() < 0 || tabOption.rect.top() > height()))) continue; - optTabBase.tabBarRect |= tab.rect; + optTabBase.tabBarRect |= tabOption.rect; if (i == selected) continue; - p.drawControl(QStyle::CE_TabBarTab, tab); + p.drawControl(QStyle::CE_TabBarTab, tabOption); } // Draw the selected tab last to get it "on top" if (selected >= 0) { - QStyleOptionTab tab; - initStyleOption(&tab, selected); - if (d->paintWithOffsets && d->tabList[selected].dragOffset != 0) { + QStyleOptionTab tabOption; + const auto tab = d->tabList.at(selected); + initStyleOption(&tabOption, selected); + if (d->paintWithOffsets && tab->dragOffset != 0) { if (vertical) - tab.rect.moveTop(tab.rect.y() + d->tabList[selected].dragOffset); + tabOption.rect.moveTop(tabOption.rect.y() + tab->dragOffset); else - tab.rect.moveLeft(tab.rect.x() + d->tabList[selected].dragOffset); + tabOption.rect.moveLeft(tabOption.rect.x() + tab->dragOffset); } if (!d->dragInProgress) - p.drawControl(QStyle::CE_TabBarTab, tab); + p.drawControl(QStyle::CE_TabBarTab, tabOption); else { int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, nullptr, this); if (verticalTabs(d->shape)) - d->movingTab->setGeometry(tab.rect.adjusted(0, -taboverlap, 0, taboverlap)); + d->movingTab->setGeometry(tabOption.rect.adjusted(0, -taboverlap, 0, taboverlap)); else - d->movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0)); + d->movingTab->setGeometry(tabOption.rect.adjusted(-taboverlap, 0, taboverlap, 0)); } } @@ -1924,7 +1922,7 @@ void QTabBarPrivate::calculateFirstLastVisible(int index, bool visible, bool rem if (remove || (index == firstVisible)) { firstVisible = -1; for (int i = 0; i < tabList.count(); ++i) { - if (tabList.at(i).visible) { + if (tabList.at(i)->visible) { firstVisible = i; break; } @@ -1935,7 +1933,7 @@ void QTabBarPrivate::calculateFirstLastVisible(int index, bool visible, bool rem if (remove || (index == lastVisible)) { lastVisible = -1; for (int i = tabList.count() - 1; i >= 0; --i) { - if (tabList.at(i).visible) { + if (tabList.at(i)->visible) { lastVisible = i; break; } @@ -1999,53 +1997,57 @@ void QTabBar::moveTab(int from, int to) || !d->validIndex(to)) return; + auto &fromTab = *d->tabList.at(from); + auto &toTab = *d->tabList.at(to); + bool vertical = verticalTabs(d->shape); int oldPressedPosition = 0; if (d->pressedIndex != -1) { // Record the position of the pressed tab before reordering the tabs. - oldPressedPosition = vertical ? d->tabList[d->pressedIndex].rect.y() - : d->tabList[d->pressedIndex].rect.x(); + oldPressedPosition = vertical ? d->tabList.at(d->pressedIndex)->rect.y() + : d->tabList.at(d->pressedIndex)->rect.x(); } // Update the locations of the tabs first int start = qMin(from, to); int end = qMax(from, to); - int width = vertical ? d->tabList[from].rect.height() : d->tabList[from].rect.width(); + int width = vertical ? fromTab.rect.height() : fromTab.rect.width(); if (from < to) width *= -1; bool rtl = isRightToLeft(); for (int i = start; i <= end; ++i) { if (i == from) continue; + auto &tab = *d->tabList.at(i); if (vertical) - d->tabList[i].rect.moveTop(d->tabList[i].rect.y() + width); + tab.rect.moveTop(tab.rect.y() + width); else - d->tabList[i].rect.moveLeft(d->tabList[i].rect.x() + width); + tab.rect.moveLeft(tab.rect.x() + width); int direction = -1; if (rtl && !vertical) direction *= -1; - if (d->tabList[i].dragOffset != 0) - d->tabList[i].dragOffset += (direction * width); + if (tab.dragOffset != 0) + tab.dragOffset += (direction * width); } if (vertical) { if (from < to) - d->tabList[from].rect.moveTop(d->tabList[to].rect.bottom() + 1); + fromTab.rect.moveTop(toTab.rect.bottom() + 1); else - d->tabList[from].rect.moveTop(d->tabList[to].rect.top() - width); + fromTab.rect.moveTop(toTab.rect.top() - width); } else { if (from < to) - d->tabList[from].rect.moveLeft(d->tabList[to].rect.right() + 1); + fromTab.rect.moveLeft(toTab.rect.right() + 1); else - d->tabList[from].rect.moveLeft(d->tabList[to].rect.left() - width); + fromTab.rect.moveLeft(toTab.rect.left() - width); } // Move the actual data structures d->tabList.move(from, to); // update lastTab locations - for (int i = 0; i < d->tabList.count(); ++i) - d->tabList[i].lastTab = d->calculateNewPosition(from, to, d->tabList[i].lastTab); + for (const auto tab : qAsConst(d->tabList)) + tab->lastTab = d->calculateNewPosition(from, to, tab->lastTab); // update external variables int previousIndex = d->currentIndex; @@ -2054,7 +2056,8 @@ void QTabBar::moveTab(int from, int to) // If we are in the middle of a drag update the dragStartPosition if (d->pressedIndex != -1) { d->pressedIndex = d->calculateNewPosition(from, to, d->pressedIndex); - int newPressedPosition = vertical ? d->tabList[d->pressedIndex].rect.top() : d->tabList[d->pressedIndex].rect.left(); + const auto pressedTab = d->tabList.at(d->pressedIndex); + int newPressedPosition = vertical ? pressedTab->rect.top() : pressedTab->rect.left(); int diff = oldPressedPosition - newPressedPosition; if (isRightToLeft() && !vertical) diff *= -1; @@ -2086,15 +2089,15 @@ void QTabBarPrivate::slide(int from, int to) q->setUpdatesEnabled(true); int postLocation = vertical ? q->tabRect(to).y() : q->tabRect(to).x(); int length = postLocation - preLocation; - tabList[to].dragOffset -= length; - tabList[to].startAnimation(this, ANIMATION_DURATION); + tabList.at(to)->dragOffset -= length; + tabList.at(to)->startAnimation(this, ANIMATION_DURATION); } void QTabBarPrivate::moveTab(int index, int offset) { if (!validIndex(index)) return; - tabList[index].dragOffset = offset; + tabList.at(index)->dragOffset = offset; layoutTab(index); // Make buttons follow tab q_func()->update(); } @@ -2166,7 +2169,7 @@ void QTabBar::mouseMoveEvent(QMouseEvent *event) } else { dragDistance = (event->position().toPoint().x() - d->dragStartPosition.x()); } - d->tabList[d->pressedIndex].dragOffset = dragDistance; + d->tabList.at(d->pressedIndex)->dragOffset = dragDistance; QRect startingRect = tabRect(d->pressedIndex); if (vertical) @@ -2243,10 +2246,11 @@ void QTabBarPrivate::setupMovableTab() movingTab->raise(); // Re-arrange widget order to avoid overlaps - if (tabList[pressedIndex].leftWidget) - tabList[pressedIndex].leftWidget->raise(); - if (tabList[pressedIndex].rightWidget) - tabList[pressedIndex].rightWidget->raise(); + const auto &pressedTab = *tabList.at(pressedIndex); + if (pressedTab.leftWidget) + pressedTab.leftWidget->raise(); + if (pressedTab.rightWidget) + pressedTab.rightWidget->raise(); if (leftB) leftB->raise(); if (rightB) @@ -2260,17 +2264,18 @@ void QTabBarPrivate::moveTabFinished(int index) bool cleanup = (pressedIndex == index) || (pressedIndex == -1) || !validIndex(index); bool allAnimationsFinished = true; #if QT_CONFIG(animation) - for(int i = 0; allAnimationsFinished && i < tabList.count(); ++i) { - const Tab &t = tabList.at(i); - if (t.animation && t.animation->state() == QAbstractAnimation::Running) + for (const auto tab : qAsConst(tabList)) { + if (tab->animation && tab->animation->state() == QAbstractAnimation::Running) { allAnimationsFinished = false; + break; + } } #endif // animation if (allAnimationsFinished && cleanup) { if(movingTab) movingTab->setVisible(false); // We might not get a mouse release - for (int i = 0; i < tabList.count(); ++i) { - tabList[i].dragOffset = 0; + for (auto tab : qAsConst(tabList)) { + tab->dragOffset = 0; } if (pressedIndex != -1 && movable) { pressedIndex = -1; @@ -2281,7 +2286,7 @@ void QTabBarPrivate::moveTabFinished(int index) } else { if (!validIndex(index)) return; - tabList[index].dragOffset = 0; + tabList.at(index)->dragOffset = 0; } q->update(); } @@ -2297,13 +2302,13 @@ void QTabBar::mouseReleaseEvent(QMouseEvent *event) } if (d->movable && d->dragInProgress && d->validIndex(d->pressedIndex)) { - int length = d->tabList[d->pressedIndex].dragOffset; + int length = d->tabList.at(d->pressedIndex)->dragOffset; int width = verticalTabs(d->shape) ? tabRect(d->pressedIndex).height() : tabRect(d->pressedIndex).width(); int duration = qMin(ANIMATION_DURATION, (qAbs(length) * ANIMATION_DURATION) / width); - d->tabList[d->pressedIndex].startAnimation(d, duration); + d->tabList.at(d->pressedIndex)->startAnimation(d, duration); d->dragInProgress = false; d->movingTab->setVisible(false); d->dragStartPosition = QPoint(); @@ -2373,7 +2378,7 @@ void QTabBarPrivate::setCurrentNextEnabledIndex(int offset) { Q_Q(QTabBar); for (int index = currentIndex + offset; validIndex(index); index += offset) { - if (tabList.at(index).enabled) { + if (tabList.at(index)->enabled) { q->setCurrentIndex(index); break; } @@ -2502,14 +2507,14 @@ void QTabBar::setTabsClosable(bool closable) d->closeButtonOnTabs = closable; ButtonPosition closeSide = (ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, nullptr, this); if (!closable) { - for (int i = 0; i < d->tabList.count(); ++i) { - if (closeSide == LeftSide && d->tabList[i].leftWidget) { - d->tabList[i].leftWidget->deleteLater(); - d->tabList[i].leftWidget = nullptr; + for (auto tab : qAsConst(d->tabList)) { + if (closeSide == LeftSide && tab->leftWidget) { + tab->leftWidget->deleteLater(); + tab->leftWidget = nullptr; } - if (closeSide == RightSide && d->tabList[i].rightWidget) { - d->tabList[i].rightWidget->deleteLater(); - d->tabList[i].rightWidget = nullptr; + if (closeSide == RightSide && tab->rightWidget) { + tab->rightWidget->deleteLater(); + tab->rightWidget = nullptr; } } } else { @@ -2731,14 +2736,15 @@ void QTabBar::setTabButton(int index, ButtonPosition position, QWidget *widget) widget->lower(); widget->show(); } + auto &tab = *d->tabList.at(index); if (position == LeftSide) { - if (d->tabList[index].leftWidget) - d->tabList[index].leftWidget->hide(); - d->tabList[index].leftWidget = widget; + if (tab.leftWidget) + tab.leftWidget->hide(); + tab.leftWidget = widget; } else { - if (d->tabList[index].rightWidget) - d->tabList[index].rightWidget->hide(); - d->tabList[index].rightWidget = widget; + if (tab.rightWidget) + tab.rightWidget->hide(); + tab.rightWidget = widget; } d->layoutTabs(); d->refresh(); @@ -2752,12 +2758,11 @@ void QTabBar::setTabButton(int index, ButtonPosition position, QWidget *widget) QWidget *QTabBar::tabButton(int index, ButtonPosition position) const { Q_D(const QTabBar); - if (index < 0 || index >= d->tabList.count()) - return nullptr; - if (position == LeftSide) - return d->tabList.at(index).leftWidget; - else - return d->tabList.at(index).rightWidget; + if (const auto tab = d->at(index)) { + return position == LeftSide ? tab->leftWidget + : tab->rightWidget; + } + return nullptr; } #ifndef QT_NO_ACCESSIBILITY @@ -2849,12 +2854,12 @@ void CloseButton::paintEvent(QPaintEvent *) #if QT_CONFIG(animation) void QTabBarPrivate::Tab::TabBarAnimation::updateCurrentValue(const QVariant ¤t) { - priv->moveTab(priv->tabList.indexOf(*tab), current.toInt()); + priv->moveTab(priv->tabList.indexOf(tab), current.toInt()); } void QTabBarPrivate::Tab::TabBarAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State) { - if (newState == Stopped) priv->moveTabFinished(priv->tabList.indexOf(*tab)); + if (newState == Stopped) priv->moveTabFinished(priv->tabList.indexOf(tab)); } #endif diff --git a/src/widgets/widgets/qtabbar_p.h b/src/widgets/widgets/qtabbar_p.h index 1036d819eb..cd0a75c1cc 100644 --- a/src/widgets/widgets/qtabbar_p.h +++ b/src/widgets/widgets/qtabbar_p.h @@ -65,6 +65,7 @@ #define ANIMATION_DURATION 250 #include <qstyleoption.h> +#include <utility> QT_REQUIRE_CONFIG(tabbar); @@ -93,6 +94,10 @@ public: paintWithOffsets(true), movable(false), dragInProgress(false), documentMode(false), autoHide(false), changeCurrentOnDrag(false) {} + ~QTabBarPrivate() + { + qDeleteAll(tabList); + } QRect hoverRect; QPoint dragStartPosition; @@ -131,8 +136,14 @@ public: struct Tab { inline Tab(const QIcon &ico, const QString &txt) : text(txt), icon(ico), enabled(true), visible(true) - {} - bool operator==(const Tab &other) const { return &other == this; } + { + } + /* + Tabs are managed by instance; they are not the same even + if all properties are the same. + */ + Q_DISABLE_COPY_MOVE(Tab); + QString text; #if QT_CONFIG(tooltip) QString toolTip; @@ -159,7 +170,6 @@ public: uint visible : 1; #if QT_CONFIG(animation) - ~Tab() { delete animation; } struct TabBarAnimation : public QVariantAnimation { TabBarAnimation(Tab *t, QTabBarPrivate *_priv) : tab(t), priv(_priv) { setEasingCurve(QEasingCurve::InOutQuad); } @@ -171,15 +181,16 @@ public: //these are needed for the callbacks Tab *tab; QTabBarPrivate *priv; - } *animation = nullptr; + }; + std::unique_ptr<TabBarAnimation> animation; void startAnimation(QTabBarPrivate *priv, int duration) { if (!priv->isAnimated()) { - priv->moveTabFinished(priv->tabList.indexOf(*this)); + priv->moveTabFinished(priv->tabList.indexOf(this)); return; } if (!animation) - animation = new TabBarAnimation(this, priv); + animation = std::make_unique<TabBarAnimation>(this, priv); animation->setStartValue(dragOffset); animation->setEndValue(0); animation->setDuration(duration); @@ -190,7 +201,7 @@ public: { Q_UNUSED(duration); priv->moveTabFinished(priv->tabList.indexOf(*this)); } #endif // animation }; - QList<Tab> tabList; + QList<Tab*> tabList; mutable QHash<QString, QSize> textSizes; void calculateFirstLastVisible(int index, bool visible, bool remove); @@ -199,8 +210,8 @@ public: void slide(int from, int to); void init(); - Tab *at(int index); - const Tab *at(int index) const; + inline Tab *at(int index) { return tabList.value(index, nullptr); } + inline const Tab *at(int index) const { return tabList.value(index, nullptr); } int indexAtPos(const QPoint &p) const; |