玉兔远程控制 0.1.0-bate6
载入中...
搜索中...
未找到
FavoriteModel.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QLoggingCategory>
4#include "FavoriteModel.h"
5
6static Q_LOGGING_CATEGORY(log, "App.Favorite.Model")
7CFavoriteModel::CFavoriteModel(CFavoriteDatabase *pDatabase, QObject *parent)
8 : QAbstractItemModel(parent)
9 , m_pDatabase(pDatabase)
10 , m_pRoot(nullptr)
11{
12 // 初始化根节点
13 m_pRoot = new tree();
14 if(m_pRoot) {
15 m_pRoot->item.type = TreeItem::TYPE::Node;
16 m_pRoot->item.id = 0;
17 m_pRoot->item.szName = "Root";
18 m_Folders[0] = m_pRoot;
19 }
20}
21
22CFavoriteModel::~CFavoriteModel()
23{
24 if(m_pRoot) {
25 ClearTree(m_pRoot);
26 m_pRoot = nullptr;
27 }
28}
29
30QModelIndex CFavoriteModel::index(int row, int column, const QModelIndex &parent) const
31{
32 //qDebug(log) << "index:" << parent;
33 if(!hasIndex(row, column, parent)) return QModelIndex();
34 if(0 > row || 0 != column) return QModelIndex();
35
36 tree* parentItem = nullptr;
37 if(parent.isValid())
38 parentItem = (tree*)parent.internalPointer();
39 else
40 parentItem = m_pRoot;
41 if(!parentItem)
42 return QModelIndex();
43 if(row < parentItem->children.size()) {
44 return CreateIndex(parentItem->children[row]);
45 //return createIndex(row, column, parentItem->children[row]);
46 }
47
48 return QModelIndex();
49}
50
51QModelIndex CFavoriteModel::parent(const QModelIndex &index) const
52{
53 //qDebug(log) << "parent:" << index;
54 if(!index.isValid()) return QModelIndex();
55 if(0 != index.column()) return QModelIndex();
56 tree* item = (tree*)index.internalPointer();
57 if(!item) return QModelIndex();
58 return CreateIndex(item->parent);
59 /*
60 tree* parentItem = item->parent;
61 if(!parentItem || parentItem == m_pRoot)
62 return QModelIndex();
63 return createIndex(item->GetRow(), index.column(), parentItem);//*/
64}
65
66int CFavoriteModel::rowCount(const QModelIndex &parent) const
67{
68 if(!m_pDatabase) return 0;
69 tree* item = nullptr;
70 if (parent.isValid()) {
71 if(parent.column() != 0) return 0;
72 item = (tree*)parent.internalPointer();
73 } else {
74 item = m_pRoot;
75 }
76
77 if(!item)
78 return 0;
79 if(item->item.isFavorite()) return 0;
80 if(item->children.size())
81 return item->children.size();
82 return m_pDatabase->GetCount(item->item.id);
83}
84
85int CFavoriteModel::columnCount(const QModelIndex &parent) const
86{
87 return 1;
88}
89
90bool CFavoriteModel::canFetchMore(const QModelIndex &parent) const
91{
92 //qDebug(log) << "canFatchMore:" << parent;
93 if(!m_pDatabase) return false;
94 int parentId = 0;
95 if (parent.isValid()) {
96 if(0 != parent.column()) return false;
97 tree* parentItem = static_cast<tree*>(parent.internalPointer());
98 if(!parentItem)
99 return false;
100 if(parentItem->item.isFavorite())
101 return false;
102 parentId = parentItem->item.id;
103 if(parentItem->children.isEmpty())
104 return m_pDatabase->GetCount(parentId) > 0;
105 else
106 return false;
107 }
108 return true;
109}
110
111void CFavoriteModel::fetchMore(const QModelIndex &parent)
112{
113 //qDebug(log) << "fetchMore:" << parent;
114 if(!m_pDatabase) return;
115 tree* parentItem = nullptr;
116 if(parent.isValid())
117 parentItem = static_cast<tree*>(parent.internalPointer());
118 else {
119 if(!m_pRoot) {
120 m_pRoot = new tree();
121 if(m_pRoot) {
122 m_pRoot->item.type = TreeItem::Node;
123 m_Folders[0] = m_pRoot;
124 }
125 }
126 parentItem = m_pRoot;
127 }
128 if(!parentItem) return;
129 if(parentItem->item.isFavorite()) return;
130 if(!parentItem->children.isEmpty()) return;
131
132 auto Nodes = m_pDatabase->GetChildren(parentItem->item.id);
133 if(Nodes.isEmpty()) return;
134 int row = 0;
135 beginInsertRows(parent, 0, Nodes.size() - 1);
136 foreach(auto n, Nodes) {
137 tree* pTree = new tree();
138 pTree->parent = parentItem;
139 pTree->SetRow(row++);
140 pTree->item = n;
141 if(n.isFolder())
142 m_Folders[n.id] = pTree;
143 parentItem->children.append(pTree);
144 }
145 endInsertRows();
146}
147
148QVariant CFavoriteModel::data(const QModelIndex &index, int role) const
149{
150 //qDebug(log) << "date:" << index;
151 if (!index.isValid())
152 return QVariant();
153 if(0 != index.column()) return QVariant();
154 tree* ip = static_cast<tree*>(index.internalPointer());
155 if(!ip) return QVariant();
156 auto item = ip->item;
157 switch(role) {
158 case Qt::DecorationRole:
159 return item.GetIcon();
160 case Qt::DisplayRole:
161 return item.szName;
162 case Qt::ToolTipRole:
163 return item.szDescription;
164 case CFavoriteModel::RoleFile:
165 return item.szFile;
166 case RoleNodeType:
167 return item.type;
168 case RoleItem:
169 return QVariant::fromValue(item);
170 default:
171 break;
172 }
173
174 return QVariant();
175}
176
177bool CFavoriteModel::setData(const QModelIndex &index, const QVariant &value, int role)
178{
179 if(!index.isValid()) return false;
180 if(0 != index.column()) return false;
181 if (data(index, role) != value) {
182 if(Qt::EditRole == role) {
183 tree* ip = (tree*)index.internalPointer();
184 if(!ip) return false;
185 if(ip->item.isFavorite())
186 m_pDatabase->UpdateFavorite(ip->item.id, value.toString());
187 else
188 m_pDatabase->RenameNode(ip->item.id, value.toString());
189 ip->item.szName = value.toString();
190 }
191 emit dataChanged(index, index, {role});
192 return true;
193 }
194 return false;
195}
196
197Qt::ItemFlags CFavoriteModel::flags(const QModelIndex &index) const
198{
199 if (!index.isValid())
200 return Qt::NoItemFlags;
201
202 return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
203}
204
205bool CFavoriteModel::removeRows(int row, int count, const QModelIndex &parent)
206{
207 tree* pItem = GetTree(parent);
208 if(!pItem || 0 > row || row + count > pItem->ChildCount())
209 return false;
210
211 beginRemoveRows(parent, row, row + count - 1);
212 for(int i = row; i < row + count; i++) {
213 auto t = pItem->children[i];
214 if(!t) continue;
215 if(t->item.isFolder()) {
216 m_pDatabase->DeleteNode(t->item.id, true);
217 m_Folders.remove(t->item.id);
218 } else {
219 m_pDatabase->Delete(t->item.id, true);
220 }
221 pItem->RemoveChild(t);
222 ClearTree(t);
223 }
224 endRemoveRows();
225 emit dataChanged(parent, parent);
226 return true;
227}
228
229bool CFavoriteModel::AddFavorite(
230 const QString &szFile, const QString& szName, const QIcon &icon,
231 const QString szDescription, int parentId)
232{
233 if(!m_pDatabase || !m_Folders.contains(parentId)) return false;
234 int id = 0;
236 item.type = TreeItem::Leaf;
237 // Check if it already exists
238 auto items = m_pDatabase->GetFavorite(szFile);
239 if(items.isEmpty()) {
240 // Add
241 id = m_pDatabase->AddFavorite(szFile, szName, icon, szDescription, parentId);
242 if(id <= 0 ) return false;
243
244 item.id = id;
245 item.parentId = parentId;
246 item.szName = szName;
247 item.szFile = szFile;
248 item.icon = icon;
249 item.szDescription = szDescription;
250 AddTree(item, parentId);
251 } else {
252 // Update
253 auto it = items.at(0);
254 if(it.id <= 0) return false;
255 bool ok = MoveTree(it.id, parentId);
256 if(!ok) return false;
257 m_pDatabase->Move(it.id, parentId);
258 }
259
260 return true;
261}
262
263bool CFavoriteModel::UpdateFavorite(
264 const QString &szFile, const QString &szName,
265 const QString &szDescription, const QIcon &icon)
266{
267 if(!m_pDatabase) return false;
268 m_pDatabase->UpdateFavorite(szFile, szName, icon, szDescription);
269 UpdateTree(szFile);
270 return true;
271}
272
273CFavoriteDatabase::Item CFavoriteModel::GetFavorite(const QString &szFile)
274{
276 if(!m_pDatabase) return item;
277 auto items = m_pDatabase->GetFavorite(szFile);
278 if(!items.isEmpty()) {
279 item = items.at(0);
280 }
281 return item;
282}
283
284void CFavoriteModel::Refresh()
285{
286 beginResetModel();
287 ClearTree(m_pRoot);
288 m_pRoot = nullptr;
289 endResetModel();
290}
291
292bool CFavoriteModel::AddNode(const QString& szName, int parentId)
293{
294 if(!m_pDatabase || !m_Folders.contains(parentId)) return false;
295
296 int id = m_pDatabase->AddNode(szName, parentId);
297
298 auto item = m_pDatabase->GetGroup(id);
299 auto parent = GetTree(parentId);
300 if(!parent) return false;
301
302 auto t = new tree();
303 if(!t) return false;
304
305 QModelIndex index = CreateIndex(parent);
306 t->item = item;
307 int pos = parent->GetInserIndex(t);
308 beginInsertRows(index, pos, pos);
309 parent->InsertChild(pos, t);
310 m_Folders[id] = t;
311 endInsertRows();
312 emit dataChanged(index, index);
313
314 return true;
315}
316
317void CFavoriteModel::ClearTree(tree* node)
318{
319 if(!node) return;
320 if(node->item.isFolder()) {
321 foreach(auto child, node->children) {
322 ClearTree(child);
323 }
324 m_Folders.remove(node->item.id);
325 }
326 delete node;
327}
328
329CFavoriteModel::tree* CFavoriteModel::GetTree(int id) const
330{
331 if(0 == id) return m_pRoot;
332 if(m_Folders.contains(id))
333 return m_Folders[id];
334 return nullptr;
335}
336
337CFavoriteModel::tree* CFavoriteModel::GetTree(QModelIndex index) const
338{
339 tree* ip = nullptr;
340 if(index.isValid())
341 ip = static_cast<tree*>(index.internalPointer());
342 else
343 ip = m_pRoot;
344 return ip;
345}
346
347QModelIndex CFavoriteModel::CreateIndex(tree* t) const
348{
349 if(!t)
350 return QModelIndex();
351
352 // 如果是根节点,返回QModelIndex()
353 if(t == m_pRoot)
354 return QModelIndex();
355
356 // 确保父节点存在且行号有效
357 if(!t->parent)
358 return QModelIndex();
359
360 return createIndex(t->GetRow(), 0, t);
361}
362
363bool CFavoriteModel::AddTree(const CFavoriteDatabase::Item &item, int parentId)
364{
365 if (item.id == 0) return false;
366
367 auto parent = GetTree(parentId);
368 if(!parent) {
369 qCritical(log) << QString("m_Folders[%1] is nullptr").arg(parentId);
370 return false;
371 }
372
373 auto t = new tree(item);
374 if (!t) {
375 qCritical(log) << "Failed to allocate memory for tree node";
376 return false;
377 }
378
379 int pos = parent->GetInserIndex(t);
380
381 QModelIndex parentIndex = CreateIndex(parent);
382
383 beginInsertRows(parentIndex, pos, pos);
384
385 parent->InsertChild(pos, t);
386
387 if (item.isFolder()) {
388 m_Folders[item.id] = t;
389 }
390
391 endInsertRows();
392
393 emit dataChanged(parentIndex, parentIndex);
394
395 return true;
396}
397
398bool CFavoriteModel::UpdateTree(const QString &szFile)
399{
400 auto items = m_pDatabase->GetFavorite(szFile);
401 foreach(auto it, items) {
402 if(it.id <= 0) continue;
403 auto leaf = m_pDatabase->GetLeaf(it.id);
404 if(leaf.GetId() == 0)
405 continue;
406 int parentId = leaf.GetParentId();
407 tree* parent = GetTree(parentId);
408 if(!parent) continue;
409 auto c = parent->FindChild(it.id);
410 if(!c) continue;
411 c->item = it;
412 QModelIndex changedIndex = CreateIndex(parent);
413 if (changedIndex.isValid()) {
414 emit dataChanged(changedIndex, changedIndex);
415 }
416 }
417 return true;
418}
419
420bool CFavoriteModel::MoveTree(int id, int newParentId)
421{
422 auto leaf = m_pDatabase->GetLeaf(id);
423 if(leaf.GetId() == 0)
424 return false;
425
426 int parentId = leaf.GetParentId();
427 if(parentId == newParentId)
428 return true;
429
430 tree* parent = GetTree(parentId);
431 if(!parent) return false;
432
433 tree* newParent = GetTree(newParentId);
434 if(!newParent) return false;
435
436 tree* cur = parent->FindChild(id);
437 int sourcePos = parent->children.indexOf(cur);
438 if(sourcePos < 0)
439 return false;
440 int desPos = parent->GetInserIndex(cur);
441 QModelIndex index = CreateIndex(parent);
442 QModelIndex newIndex = CreateIndex(newParent);
443 beginMoveRows(index, sourcePos, sourcePos, newIndex, desPos);
444 parent->RemoveChild(cur);
445 newParent->AddChild(cur);
446 endMoveRows();
447 return true;
448}
449
450CFavoriteModel::tree::tree()
451{}
452
453CFavoriteModel::tree::tree(CFavoriteDatabase::Item i)
454 : item(i)
455{}
456
457CFavoriteModel::tree::~tree()
458{
459}
460
461int CFavoriteModel::tree::GetRow() const
462{
463 return m_row;
464}
465
466void CFavoriteModel::tree::SetRow(int r)
467{
468 m_row = r;
469}
470
471bool CFavoriteModel::tree::IsFolder() const
472{
473 return item.isFolder();
474}
475
476bool CFavoriteModel::tree::IsFavorite() const
477{
478 return item.isFavorite();
479}
480
481int CFavoriteModel::tree::ChildCount() const
482{
483 return children.size();
484}
485
486CFavoriteModel::tree* CFavoriteModel::tree::ChildAt(int index) const
487{
488 if (index < 0 || index >= children.size()) {
489 return nullptr;
490 }
491 return children[index];
492}
493
494int CFavoriteModel::tree::GetInserIndex(tree *child)
495{
496 int index = 0;
497 if(!child) return 0;
498 if(child->IsFavorite()) {
499 index = children.size();
500 } else {
501 foreach (const auto &c, children) {
502 if (c && c->item.isFolder()) {
503 index++;
504 }
505 }
506 }
507 return index;
508}
509
510bool CFavoriteModel::tree::AddChild(tree *child)
511{
512 if (!child) return false;
513 child->parent = this;
514 return InsertChild(GetInserIndex(child), child);
515}
516
517bool CFavoriteModel::tree::InsertChild(int index, tree *child)
518{
519 if(0 > index || ChildCount() < index || !child)
520 return false;
521 children.insert(index, child);
522 child->parent = this;
523 // 更新剩余子节点的行号
524 for (int i = index; i < ChildCount(); ++i) {
525 children[i]->SetRow(i);
526 }
527 return true;
528}
529
530bool CFavoriteModel::tree::RemoveChild(tree *child)
531{
532 if (!child) return false;
533
534 int index = children.indexOf(child);
535 if (index == -1) return false;
536
537 children.remove(index);
538
539 // 更新剩余子节点的行号
540 for (int i = index; i < children.size(); ++i) {
541 children[i]->SetRow(i);
542 }
543
544 return true;
545}
546
547CFavoriteModel::tree* CFavoriteModel::tree::FindChild(int id) const
548{
549 for (auto child : children) {
550 if (child->item.id == id) {
551 return child;
552 }
553 }
554 return nullptr;
555}
556
557CFavoriteModel::tree* CFavoriteModel::tree::FindRecursive(int id) const
558{
559 if (item.id == id) {
560 return const_cast<tree*>(this);
561 }
562
563 for (auto child : children) {
564 tree* found = child->FindRecursive(id);
565 if (found) {
566 return found;
567 }
568 }
569
570 return nullptr;
571}
int GetCount(int parentId=0)
得到指定id节点下的所有节点和叶子数。不递归。