1 #include "infotableproxymodel.hpp"
2
3 #include <components/misc/stringops.hpp>
4
5 #include "idtablebase.hpp"
6 #include "columns.hpp"
7
8 namespace
9 {
toLower(const QString & str)10 QString toLower(const QString &str)
11 {
12 return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toUtf8().constData()).c_str());
13 }
14 }
15
InfoTableProxyModel(CSMWorld::UniversalId::Type type,QObject * parent)16 CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent)
17 : IdTableProxyModel(parent),
18 mType(type),
19 mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic :
20 Columns::ColumnId_Journal),
21 mInfoColumnIndex(-1),
22 mLastAddedSourceRow(-1)
23 {
24 Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos);
25 }
26
setSourceModel(QAbstractItemModel * sourceModel)27 void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
28 {
29 IdTableProxyModel::setSourceModel(sourceModel);
30
31 if (mSourceModel != nullptr)
32 {
33 mInfoColumnIndex = mSourceModel->findColumnIndex(mInfoColumnId);
34 mFirstRowCache.clear();
35 }
36 }
37
lessThan(const QModelIndex & left,const QModelIndex & right) const38 bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
39 {
40 Q_ASSERT(mSourceModel != nullptr);
41
42 QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column());
43 QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column());
44
45 // If both indexes are belonged to the same Topic/Journal, compare their original rows only
46 if (first.row() == second.row())
47 {
48 return sortOrder() == Qt::AscendingOrder ? left.row() < right.row() : right.row() < left.row();
49 }
50 return IdTableProxyModel::lessThan(first, second);
51 }
52
getFirstInfoRow(int currentRow) const53 int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const
54 {
55 Q_ASSERT(mSourceModel != nullptr);
56
57 int row = currentRow;
58 int column = mInfoColumnIndex;
59 QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString());
60
61 if (mFirstRowCache.contains(info))
62 {
63 return mFirstRowCache[info];
64 }
65
66 while (--row >= 0 &&
67 toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()) == info);
68 ++row;
69
70 mFirstRowCache[info] = row;
71 return row;
72 }
73
sourceRowsRemoved(const QModelIndex &,int,int)74 void CSMWorld::InfoTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/)
75 {
76 refreshFilter();
77 mFirstRowCache.clear();
78 }
79
sourceRowsInserted(const QModelIndex & parent,int,int end)80 void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end)
81 {
82 refreshFilter();
83
84 if (!parent.isValid())
85 {
86 mFirstRowCache.clear();
87 // We can't re-sort the model here, because the topic of the added row isn't set yet.
88 // Store the row index for using in the first dataChanged() after this row insertion.
89 mLastAddedSourceRow = end;
90 }
91 }
92
sourceDataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)93 void CSMWorld::InfoTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
94 {
95 refreshFilter();
96
97 if (mLastAddedSourceRow != -1 &&
98 topLeft.row() <= mLastAddedSourceRow && bottomRight.row() >= mLastAddedSourceRow)
99 {
100 // Now the topic of the last added row is set,
101 // so we can re-sort the model to ensure the corrent position of this row
102 int column = sortColumn();
103 Qt::SortOrder order = sortOrder();
104 sort(mInfoColumnIndex); // Restore the correct position of an added row
105 sort(column, order); // Restore the original sort order
106 emit rowAdded(getRecordId(mLastAddedSourceRow).toUtf8().constData());
107
108 // Make sure that we perform a re-sorting only in the first dataChanged() after a row insertion
109 mLastAddedSourceRow = -1;
110 }
111 }
112