summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2020-07-02 15:53:34 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2020-07-07 21:40:50 +0200
commit359616066e64eed947c6c91cb8902285ed79dd0d (patch)
tree4a152e8d546d691bc931570eb458e5d7378cf0ec /src/widgets
parent652459afde5d1ed350f198f212d19b067ce5c1a3 (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.cpp329
-rw-r--r--src/widgets/widgets/qtabbar_p.h29
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 &current)
{
- 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;