1 /*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "historymodel.h"
8 #include "historyimageitem.h"
9 #include "historystringitem.h"
10 #include "historyurlitem.h"
11
HistoryModel(QObject * parent)12 HistoryModel::HistoryModel(QObject *parent)
13 : QAbstractListModel(parent)
14 , m_maxSize(0)
15 , m_displayImages(true)
16 , m_mutex(QMutex::Recursive)
17 {
18 }
19
~HistoryModel()20 HistoryModel::~HistoryModel()
21 {
22 clear();
23 }
24
clear()25 void HistoryModel::clear()
26 {
27 QMutexLocker lock(&m_mutex);
28 beginResetModel();
29 m_items.clear();
30 endResetModel();
31 }
32
setMaxSize(int size)33 void HistoryModel::setMaxSize(int size)
34 {
35 if (m_maxSize == size) {
36 return;
37 }
38 QMutexLocker lock(&m_mutex);
39 m_maxSize = size;
40 if (m_items.count() > m_maxSize) {
41 removeRows(m_maxSize, m_items.count() - m_maxSize);
42 }
43 }
44
rowCount(const QModelIndex & parent) const45 int HistoryModel::rowCount(const QModelIndex &parent) const
46 {
47 if (parent.isValid()) {
48 return 0;
49 }
50 return m_items.count();
51 }
52
data(const QModelIndex & index,int role) const53 QVariant HistoryModel::data(const QModelIndex &index, int role) const
54 {
55 if (!index.isValid() || index.row() >= m_items.count() || index.column() != 0) {
56 return QVariant();
57 }
58
59 QSharedPointer<HistoryItem> item = m_items.at(index.row());
60 HistoryItemType type = HistoryItemType::Text;
61 if (dynamic_cast<HistoryStringItem *>(item.data())) {
62 type = HistoryItemType::Text;
63 } else if (dynamic_cast<HistoryImageItem *>(item.data())) {
64 type = HistoryItemType::Image;
65 } else if (dynamic_cast<HistoryURLItem *>(item.data())) {
66 type = HistoryItemType::Url;
67 }
68
69 switch (role) {
70 case Qt::DisplayRole:
71 return item->text();
72 case Qt::DecorationRole:
73 return item->image();
74 case Qt::UserRole:
75 return QVariant::fromValue<HistoryItemConstPtr>(qSharedPointerConstCast<const HistoryItem>(item));
76 case Qt::UserRole + 1:
77 return item->uuid();
78 case Qt::UserRole + 2:
79 return QVariant::fromValue<HistoryItemType>(type);
80 case Qt::UserRole + 3:
81 return item->uuid().toBase64();
82 case Qt::UserRole + 4:
83 return int(type);
84 }
85 return QVariant();
86 }
87
removeRows(int row,int count,const QModelIndex & parent)88 bool HistoryModel::removeRows(int row, int count, const QModelIndex &parent)
89 {
90 if (parent.isValid()) {
91 return false;
92 }
93 if ((row + count) > m_items.count()) {
94 return false;
95 }
96 QMutexLocker lock(&m_mutex);
97 beginRemoveRows(QModelIndex(), row, row + count - 1);
98 for (int i = 0; i < count; ++i) {
99 m_items.removeAt(row);
100 }
101 endRemoveRows();
102 return true;
103 }
104
remove(const QByteArray & uuid)105 bool HistoryModel::remove(const QByteArray &uuid)
106 {
107 QModelIndex index = indexOf(uuid);
108 if (!index.isValid()) {
109 return false;
110 }
111 return removeRow(index.row(), QModelIndex());
112 }
113
indexOf(const QByteArray & uuid) const114 QModelIndex HistoryModel::indexOf(const QByteArray &uuid) const
115 {
116 for (int i = 0; i < m_items.count(); ++i) {
117 if (m_items.at(i)->uuid() == uuid) {
118 return index(i);
119 }
120 }
121 return QModelIndex();
122 }
123
indexOf(const HistoryItem * item) const124 QModelIndex HistoryModel::indexOf(const HistoryItem *item) const
125 {
126 if (!item) {
127 return QModelIndex();
128 }
129 return indexOf(item->uuid());
130 }
131
insert(QSharedPointer<HistoryItem> item)132 void HistoryModel::insert(QSharedPointer<HistoryItem> item)
133 {
134 if (item.isNull()) {
135 return;
136 }
137 const QModelIndex existingItem = indexOf(item.data());
138 if (existingItem.isValid()) {
139 // move to top
140 moveToTop(existingItem.row());
141 return;
142 }
143
144 QMutexLocker lock(&m_mutex);
145 if (m_items.count() == m_maxSize) {
146 // remove last item
147 if (m_maxSize == 0) {
148 // special case - cannot insert any items
149 return;
150 }
151 beginRemoveRows(QModelIndex(), m_items.count() - 1, m_items.count() - 1);
152 m_items.removeLast();
153 endRemoveRows();
154 }
155
156 beginInsertRows(QModelIndex(), 0, 0);
157 item->setModel(this);
158 m_items.prepend(item);
159 endInsertRows();
160 }
161
moveToTop(const QByteArray & uuid)162 void HistoryModel::moveToTop(const QByteArray &uuid)
163 {
164 const QModelIndex existingItem = indexOf(uuid);
165 if (!existingItem.isValid()) {
166 return;
167 }
168 moveToTop(existingItem.row());
169 }
170
moveToTop(int row)171 void HistoryModel::moveToTop(int row)
172 {
173 if (row == 0 || row >= m_items.count()) {
174 return;
175 }
176 QMutexLocker lock(&m_mutex);
177 beginMoveRows(QModelIndex(), row, row, QModelIndex(), 0);
178 m_items.move(row, 0);
179 endMoveRows();
180 }
181
moveTopToBack()182 void HistoryModel::moveTopToBack()
183 {
184 if (m_items.count() < 2) {
185 return;
186 }
187 QMutexLocker lock(&m_mutex);
188 beginMoveRows(QModelIndex(), 0, 0, QModelIndex(), m_items.count());
189 auto item = m_items.takeFirst();
190 m_items.append(item);
191 endMoveRows();
192 }
193
moveBackToTop()194 void HistoryModel::moveBackToTop()
195 {
196 moveToTop(m_items.count() - 1);
197 }
198
roleNames() const199 QHash<int, QByteArray> HistoryModel::roleNames() const
200 {
201 QHash<int, QByteArray> hash;
202 hash.insert(Qt::DisplayRole, QByteArrayLiteral("DisplayRole"));
203 hash.insert(Qt::DecorationRole, QByteArrayLiteral("DecorationRole"));
204 hash.insert(Qt::UserRole + 3, QByteArrayLiteral("UuidRole"));
205 hash.insert(Qt::UserRole + 4, QByteArrayLiteral("TypeRole"));
206 return hash;
207 }
208