Skip to content

Commit 03beb42

Browse files
committed
fix: many issues with RoleCombineModel
修正 RoleCombineModel 的若干问题,包括索引映射错误,minor 模型变化处理不完整,QAbstractItemModelTester运行失败等. Log:
1 parent 52e2deb commit 03beb42

3 files changed

Lines changed: 458 additions & 21 deletions

File tree

panels/dock/taskmanager/rolecombinemodel.cpp

Lines changed: 207 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,42 +24,133 @@ RoleCombineModel::RoleCombineModel(QAbstractItemModel* major, QAbstractItemModel
2424
}
2525

2626
connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, [this, majorRoles, func](const QModelIndex &parent, int first, int last) {
27-
beginInsertRows(index(parent.row(), parent.column()), first, last);
27+
// 对于QAbstractListModel,parent通常是无效的,我们直接使用QModelIndex()
28+
beginInsertRows(QModelIndex(), first, last);
29+
30+
// 先调整现有映射中后续行的索引
31+
QMap<QPair<int, int>, QPair<int, int>> newIndexMap;
32+
for (auto it = m_indexMap.constBegin(); it != m_indexMap.constEnd(); ++it) {
33+
int row = it.key().first;
34+
int col = it.key().second;
35+
36+
if (row >= first) {
37+
// 将后续行的索引向后移动
38+
int newRow = row + (last - first + 1);
39+
newIndexMap[qMakePair(newRow, col)] = it.value();
40+
} else {
41+
// 保持前面行的映射不变
42+
newIndexMap[it.key()] = it.value();
43+
}
44+
}
45+
m_indexMap = newIndexMap;
46+
47+
// 为新插入的行创建映射
48+
int columnCount = sourceModel()->columnCount();
2849
for (int i = first; i <= last; i++) {
29-
QModelIndex majorIndex = sourceModel()->index(i, 0);
30-
QModelIndex minorIndex = func(majorIndex.data(majorRoles), m_minor);
31-
if (majorIndex.isValid() && minorIndex.isValid())
32-
m_indexMap[qMakePair(i, 0)] = qMakePair(minorIndex.row(), minorIndex.column());
50+
for (int j = 0; j < columnCount; j++) {
51+
QModelIndex majorIndex = sourceModel()->index(i, j);
52+
QModelIndex minorIndex = func(majorIndex.data(majorRoles), m_minor);
53+
if (majorIndex.isValid() && minorIndex.isValid())
54+
m_indexMap[qMakePair(i, j)] = qMakePair(minorIndex.row(), minorIndex.column());
55+
}
3356
}
3457
endInsertRows();
3558
});
59+
3660
connect(sourceModel(), &QAbstractItemModel::columnsInserted, this, [this, majorRoles, func](const QModelIndex &parent, int first, int last) {
37-
beginInsertColumns(index(parent.row(), parent.column()), first, last);
61+
beginInsertColumns(QModelIndex(), first, last);
62+
63+
// 先调整现有映射中后续列的索引
64+
QMap<QPair<int, int>, QPair<int, int>> newIndexMap;
65+
for (auto it = m_indexMap.constBegin(); it != m_indexMap.constEnd(); ++it) {
66+
int row = it.key().first;
67+
int col = it.key().second;
68+
69+
if (col >= first) {
70+
// 将后续列的索引向后移动
71+
int newCol = col + (last - first + 1);
72+
newIndexMap[qMakePair(row, newCol)] = it.value();
73+
} else {
74+
// 保持前面列的映射不变
75+
newIndexMap[it.key()] = it.value();
76+
}
77+
}
78+
m_indexMap = newIndexMap;
79+
80+
// 为新插入的列创建映射
81+
int rowCount = sourceModel()->rowCount();
3882
for (int j = first; j <= last; j++) {
39-
QModelIndex majorIndex = sourceModel()->index(0, j);
40-
QModelIndex minorIndex = func(majorIndex.data(majorRoles), m_minor);
41-
if (majorIndex.isValid() && minorIndex.isValid())
42-
m_indexMap[qMakePair(0, j)] = qMakePair(minorIndex.row(), minorIndex.column());
83+
for (int i = 0; i < rowCount; i++) {
84+
QModelIndex majorIndex = sourceModel()->index(i, j);
85+
QModelIndex minorIndex = func(majorIndex.data(majorRoles), m_minor);
86+
if (majorIndex.isValid() && minorIndex.isValid())
87+
m_indexMap[qMakePair(i, j)] = qMakePair(minorIndex.row(), minorIndex.column());
88+
}
4389
}
4490
endInsertColumns();
4591
});
4692

4793
connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, [this](const QModelIndex &parent, int first, int last) {
48-
beginRemoveRows(index(parent.row(), parent.column()), first, last);
94+
beginRemoveRows(QModelIndex(), first, last);
95+
96+
// 删除被移除行的映射
97+
int columnCount = sourceModel()->columnCount();
4998
for (int i = first; i <= last; i++) {
50-
if (m_indexMap.contains(qMakePair(i, 0))) {
51-
m_indexMap.remove(qMakePair(i, 0));
99+
for (int j = 0; j < columnCount; j++) {
100+
m_indexMap.remove(qMakePair(i, j));
101+
}
102+
}
103+
104+
// 调整后续行的索引映射
105+
QMap<QPair<int, int>, QPair<int, int>> newIndexMap;
106+
for (auto it = m_indexMap.constBegin(); it != m_indexMap.constEnd(); ++it) {
107+
int row = it.key().first;
108+
int col = it.key().second;
109+
110+
if (row > last) {
111+
// 将后续行的索引向前移动
112+
int newRow = row - (last - first + 1);
113+
newIndexMap[qMakePair(newRow, col)] = it.value();
114+
} else if (row < first) {
115+
// 保持前面行的映射不变
116+
newIndexMap[it.key()] = it.value();
52117
}
118+
// 被删除行的映射已经在上面移除了
53119
}
120+
m_indexMap = newIndexMap;
121+
54122
endRemoveRows();
55123
});
124+
56125
connect(sourceModel(), &QAbstractItemModel::columnsRemoved, this, [this](const QModelIndex &parent, int first, int last) {
57-
beginRemoveColumns(index(parent.row(), parent.column()), first, last);
126+
beginRemoveColumns(QModelIndex(), first, last);
127+
128+
// 删除被移除列的映射
129+
int rowCount = sourceModel()->rowCount();
58130
for (int j = first; j <= last; j++) {
59-
if (m_indexMap.contains(qMakePair(0, j))) {
60-
m_indexMap.remove(qMakePair(0, j));
131+
for (int i = 0; i < rowCount; i++) {
132+
m_indexMap.remove(qMakePair(i, j));
133+
}
134+
}
135+
136+
// 调整后续列的索引映射
137+
QMap<QPair<int, int>, QPair<int, int>> newIndexMap;
138+
for (auto it = m_indexMap.constBegin(); it != m_indexMap.constEnd(); ++it) {
139+
int row = it.key().first;
140+
int col = it.key().second;
141+
142+
if (col > last) {
143+
// 将后续列的索引向前移动
144+
int newCol = col - (last - first + 1);
145+
newIndexMap[qMakePair(row, newCol)] = it.value();
146+
} else if (col < first) {
147+
// 保持前面列的映射不变
148+
newIndexMap[it.key()] = it.value();
61149
}
150+
// 被删除列的映射已经在上面移除了
62151
}
152+
m_indexMap = newIndexMap;
153+
63154
endRemoveColumns();
64155
});
65156

@@ -104,13 +195,73 @@ RoleCombineModel::RoleCombineModel(QAbstractItemModel* major, QAbstractItemModel
104195
}
105196
});
106197

198+
// 添加对minor模型删除操作的处理
199+
connect(m_minor, &QAbstractItemModel::rowsRemoved, this, [this, majorRoles, func](const QModelIndex &parent, int first, int last) {
200+
// 当minor模型删除行时,需要更新映射并可能触发数据变化信号
201+
QList<QModelIndex> affectedMajorIndexes;
202+
203+
// 找到受影响的major索引
204+
for (auto it = m_indexMap.begin(); it != m_indexMap.end();) {
205+
int minorRow = it.value().first;
206+
int minorCol = it.value().second;
207+
208+
if (minorRow >= first && minorRow <= last) {
209+
// 这个映射指向的minor行被删除了,需要重新建立映射
210+
int majorRow = it.key().first;
211+
int majorCol = it.key().second;
212+
auto majorIndex = sourceModel()->index(majorRow, majorCol);
213+
214+
if (majorIndex.isValid()) {
215+
affectedMajorIndexes.append(majorIndex);
216+
// 尝试重新建立映射
217+
QModelIndex newMinorIndex = func(majorIndex.data(majorRoles), m_minor);
218+
if (newMinorIndex.isValid()) {
219+
it.value() = qMakePair(newMinorIndex.row(), newMinorIndex.column());
220+
++it;
221+
} else {
222+
// 无法建立新映射,删除这个映射
223+
it = m_indexMap.erase(it);
224+
}
225+
} else {
226+
it = m_indexMap.erase(it);
227+
}
228+
} else if (minorRow > last) {
229+
// 调整后续行的索引
230+
int newMinorRow = minorRow - (last - first + 1);
231+
it.value().first = newMinorRow;
232+
++it;
233+
} else {
234+
++it;
235+
}
236+
}
237+
238+
// 对受影响的major索引发送数据变化信号
239+
for (const auto &majorIndex : affectedMajorIndexes) {
240+
Q_EMIT dataChanged(majorIndex, majorIndex, m_minorRolesMap.values());
241+
}
242+
});
243+
244+
connect(m_minor, &QAbstractItemModel::columnsRemoved, this, [this, majorRoles, func](const QModelIndex &parent, int first, int last) {
245+
// 当minor模型删除列时,需要更新映射
246+
for (auto it = m_indexMap.begin(); it != m_indexMap.end(); ++it) {
247+
int minorRow = it.value().first;
248+
int minorCol = it.value().second;
249+
250+
if (minorCol > last) {
251+
// 调整后续列的索引
252+
int newMinorCol = minorCol - (last - first + 1);
253+
it.value().second = newMinorCol;
254+
}
255+
}
256+
});
257+
107258
connect(m_minor, &QAbstractItemModel::rowsInserted, this,
108259
[this, majorRoles, func](const QModelIndex &parent, int first, int last){
109260
auto rowCount = sourceModel()->rowCount();
110261
auto columnCount = sourceModel()->columnCount();
111262
for (int i = 0; i < rowCount; i++) {
112263
for (int j = 0; j < columnCount; j++) {
113-
// alreay bind, pass this
264+
// already bind, pass this
114265
if (m_indexMap.contains(qMakePair(i ,j)))
115266
continue;
116267

@@ -127,8 +278,25 @@ RoleCombineModel::RoleCombineModel(QAbstractItemModel* major, QAbstractItemModel
127278
// create minor role map
128279
auto minorRolenames = m_minor->roleNames();
129280
m_roleNames = createRoleNames();
130-
std::for_each(minorRolenames.constBegin(), minorRolenames.constEnd(), [&minorRolenames, this](auto &roleName) {
131-
m_minorRolesMap.insert(m_roleNames.key(roleName), minorRolenames.key(roleName));
281+
282+
// 修复角色映射逻辑:应该映射到新创建的minor角色,而不是major角色
283+
auto majorRoleNames = sourceModel()->roleNames();
284+
285+
std::for_each(minorRolenames.constBegin(), minorRolenames.constEnd(), [&minorRolenames, &majorRoleNames, this](auto &roleName) {
286+
int minorRoleKey = minorRolenames.key(roleName);
287+
288+
// 在组合角色中找到对应的key,但排除major模型已有的key
289+
int combinedRoleKey = -1;
290+
for (auto it = m_roleNames.constBegin(); it != m_roleNames.constEnd(); ++it) {
291+
if (it.value() == roleName && !majorRoleNames.contains(it.key())) {
292+
combinedRoleKey = it.key();
293+
break;
294+
}
295+
}
296+
297+
if (combinedRoleKey != -1) {
298+
m_minorRolesMap.insert(combinedRoleKey, minorRoleKey);
299+
}
132300
});
133301
}
134302

@@ -152,19 +320,31 @@ QHash<int, QByteArray> RoleCombineModel::roleNames() const
152320

153321
int RoleCombineModel::rowCount(const QModelIndex &parent) const
154322
{
323+
if (parent.isValid())
324+
return 0; // 平坦列表模型:有效的parent表示某个项目,项目没有子项
155325
return sourceModel()->rowCount();
156326
}
157327

158328
int RoleCombineModel::columnCount(const QModelIndex &parent) const
159329
{
330+
if (parent.isValid())
331+
return 0; // 平坦列表模型:有效的parent表示某个项目,项目没有子项
160332
return sourceModel()->columnCount();
161333
}
162334

163335
QVariant RoleCombineModel::data(const QModelIndex &index, int role) const
164336
{
165337
if (m_minorRolesMap.contains(role)) {
166-
int row, column;
167-
std::tie(row, column) = m_indexMap.value(qMakePair(index.row(), index.column()), qMakePair(-1, -1));
338+
auto majorKey = qMakePair(index.row(), index.column());
339+
auto mapping = m_indexMap.value(majorKey, qMakePair(-1, -1));
340+
int row = mapping.first;
341+
int column = mapping.second;
342+
343+
// 检查映射是否有效
344+
if (row == -1 || column == -1) {
345+
return QVariant(); // 返回空值而不是用无效索引访问
346+
}
347+
168348
return m_minor->data(m_minor->index(row, column), m_minorRolesMap[role]);
169349
} else {
170350
return sourceModel()->data(sourceModel()->index(index.row(), index.column()), role);
@@ -176,6 +356,12 @@ bool RoleCombineModel::hasIndex(int row, int column, const QModelIndex &parent)
176356
return sourceModel()->hasIndex(row, column, parent);
177357
}
178358

359+
bool RoleCombineModel::hasChildren(const QModelIndex &parent) const
360+
{
361+
// 平坦列表模型:只有根节点有子项,其他项目都没有子项
362+
return !parent.isValid() && rowCount(parent) > 0;
363+
}
364+
179365
QModelIndex RoleCombineModel::index(int row, int column, const QModelIndex &parent) const
180366
{
181367
if (!hasIndex(row, column, parent))

panels/dock/taskmanager/rolecombinemodel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class RoleCombineModel : public QAbstractProxyModel
2424
QHash<int, QByteArray> roleNames() const override;
2525

2626
bool hasIndex(int row, int column, const QModelIndex &parent = QModelIndex()) const;
27+
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
2728
Q_INVOKABLE virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
2829
Q_INVOKABLE virtual QModelIndex parent(const QModelIndex &child) const override;
2930

0 commit comments

Comments
 (0)