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