玉兔远程控制 0.1.0-bate8
载入中...
搜索中...
未找到
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;
235 CFavoriteDatabase::Item item(TreeItem::Leaf);
236 // Check if it already exists
237 auto items = m_pDatabase->GetFavorite(szFile);
238 if(items.isEmpty()) {
239 // Add
240 id = m_pDatabase->AddFavorite(szFile, szName, icon, szDescription, parentId);
241 if(id <= 0 ) return false;
242
243 item.id = id;
244 item.parentId = parentId;
245 item.szName = szName;
246 item.szFile = szFile;
247 item.icon = icon;
248 item.szDescription = szDescription;
249 AddTree(item, parentId);
250 } else {
251 // Update
252 auto it = items.at(0);
253 if(it.id <= 0) return false;
254 bool ok = MoveTree(it, parentId);
255 if(!ok) return false;
256 m_pDatabase->Move(it.id, parentId);
257 }
258
259 return true;
260}
261
262bool CFavoriteModel::UpdateFavorite(
263 const QString &szFile, const QString &szName,
264 const QString &szDescription, const QIcon &icon)
265{
266 if(!m_pDatabase) return false;
267 m_pDatabase->UpdateFavorite(szFile, szName, icon, szDescription);
268 UpdateTree(szFile);
269 return true;
270}
271
272bool CFavoriteModel::Move(QModelIndex index, QModelIndex parentIndex)
273{
274 if(!index.isValid()) return false;
275 tree* ip = GetTree(index);
276 if(!ip) return false;
277 tree* ipParent = GetTree(parentIndex);
278 if(!ipParent || ipParent->item.isFavorite()) return false;
279 int nParentId = ipParent->item.id;
280 auto& item = ip->item;
281 bool bRet = false;
282 if(item.isFavorite())
283 bRet = m_pDatabase->Move(item.id, nParentId);
284 else {
285 if(item.id != nParentId && ip->FindRecursive(ipParent->item).isEmpty())
286 bRet = m_pDatabase->MoveNode(item.id, nParentId);
287 else {
288 if(item.id == nParentId)
289 qWarning(log) << "The same node:" << item.id;
290 else
291 qWarning(log) << "The destination node is a child node of this node."
292 << item.id << ipParent->item.id;
293 }
294 }
295 if(bRet)
296 bRet = MoveTree(ip->item, ipParent->item.id);
297 return bRet;
298}
299
300// TODO: not test!!!
301bool CFavoriteModel::Copy(QModelIndex index, QModelIndex parentIndex)
302{
303 bool bRet = false;
304 if(!index.isValid()) return false;
305 tree* ip = GetTree(index);
306 if(!ip) return false;
307 tree* ipParent = GetTree(parentIndex);
308 if(!ipParent || ipParent->item.isFavorite()) return false;
309 int nParentId = ipParent->item.id;
310 auto& item = ip->item;
311 if(item.isFavorite())
312 bRet = AddFavorite(item.szFile, item.szName, item.GetIcon(),
313 item.szDescription, nParentId);
314 else {
315 if(item.id != nParentId)
316 bRet = m_pDatabase->AddNode(item.szName, nParentId);
317 if(bRet)
318 bRet = AddTree(item, nParentId);
319 }
320 return bRet;
321}
322
323CFavoriteDatabase::Item CFavoriteModel::GetFavorite(const QString &szFile)
324{
325 CFavoriteDatabase::Item item(TreeItem::TYPE::Leaf);
326 if(!m_pDatabase) return item;
327 auto items = m_pDatabase->GetFavorite(szFile);
328 if(!items.isEmpty()) {
329 item = items.at(0);
330 }
331 return item;
332}
333
334void CFavoriteModel::Refresh()
335{
336 beginResetModel();
337 ClearTree(m_pRoot);
338 m_pRoot = nullptr;
339 endResetModel();
340}
341
342bool CFavoriteModel::AddNode(const QString& szName, int parentId)
343{
344 if(!m_pDatabase || !m_Folders.contains(parentId)) return false;
345
346 int id = m_pDatabase->AddNode(szName, parentId);
347
348 auto item = m_pDatabase->GetGroup(id);
349 auto parent = GetTree(parentId);
350 if(!parent) return false;
351
352 auto t = new tree();
353 if(!t) return false;
354
355 QModelIndex index = CreateIndex(parent);
356 t->item = item;
357 int pos = parent->GetInserIndex(t);
358 beginInsertRows(index, pos, pos);
359 parent->InsertChild(pos, t);
360 m_Folders[id] = t;
361 endInsertRows();
362 emit dataChanged(index, index);
363
364 return true;
365}
366
367void CFavoriteModel::ClearTree(tree* node)
368{
369 if(!node) return;
370 if(node->item.isFolder()) {
371 foreach(auto child, node->children) {
372 ClearTree(child);
373 }
374 m_Folders.remove(node->item.id);
375 }
376 delete node;
377}
378
379CFavoriteModel::tree* CFavoriteModel::GetTree(int id) const
380{
381 if(0 == id) return m_pRoot;
382 if(m_Folders.contains(id))
383 return m_Folders[id];
384 return nullptr;
385}
386
387CFavoriteModel::tree* CFavoriteModel::GetTree(QModelIndex index) const
388{
389 tree* ip = nullptr;
390 if(index.isValid())
391 ip = static_cast<tree*>(index.internalPointer());
392 else
393 ip = m_pRoot;
394 return ip;
395}
396
397QModelIndex CFavoriteModel::CreateIndex(tree* t) const
398{
399 if(!t)
400 return QModelIndex();
401
402 // 如果是根节点,返回QModelIndex()
403 if(t == m_pRoot)
404 return QModelIndex();
405
406 // 确保父节点存在且行号有效
407 if(!t->parent)
408 return QModelIndex();
409
410 return createIndex(t->GetRow(), 0, t);
411}
412
413bool CFavoriteModel::AddTree(const CFavoriteDatabase::Item &item, int parentId)
414{
415 if (item.id == 0) return false;
416
417 auto parent = GetTree(parentId);
418 if(!parent) {
419 qCritical(log) << QString("m_Folders[%1] is nullptr").arg(parentId);
420 return false;
421 }
422
423 auto t = new tree(item);
424 if (!t) {
425 qCritical(log) << "Failed to allocate memory for tree node";
426 return false;
427 }
428
429 int pos = parent->GetInserIndex(t);
430
431 QModelIndex parentIndex = CreateIndex(parent);
432
433 beginInsertRows(parentIndex, pos, pos);
434
435 parent->InsertChild(pos, t);
436
437 if (item.isFolder()) {
438 m_Folders[item.id] = t;
439 }
440
441 endInsertRows();
442
443 emit dataChanged(parentIndex, parentIndex);
444
445 return true;
446}
447
448bool CFavoriteModel::UpdateTree(const QString &szFile)
449{
450 auto items = m_pDatabase->GetFavorite(szFile);
451 foreach(auto it, items) {
452 if(it.id <= 0) continue;
453 tree* parent = GetTree(it.parentId);
454 if(!parent) continue;
455 QList<tree*> children = parent->FindChild(it);
456 if(children.isEmpty()) continue;
457 foreach(auto c, children) {
458 c->item = it;
459 QModelIndex changedIndex = CreateIndex(parent);
460 if (changedIndex.isValid()) {
461 emit dataChanged(changedIndex, changedIndex);
462 }
463 }
464 }
465 return true;
466}
467
468bool CFavoriteModel::MoveTree(const CFavoriteDatabase::Item &item, int newParentId)
469{
470 if(0 == item.id)
471 return false;
472
473 int parentId = item.parentId;
474 if(parentId == newParentId)
475 return true;
476
477 if(item.isFolder() && item.id == newParentId)
478 return true;
479
480 tree* parent = GetTree(parentId);
481 if(!parent) return false;
482
483 tree* newParent = GetTree(newParentId);
484 if(!newParent) return false;
485
486 auto children = parent->FindChild(item);
487 foreach(auto cur, children) {
488 int sourcePos = parent->children.indexOf(cur);
489 if(sourcePos < 0)
490 return false;
491 int desPos = newParent->GetInserIndex(cur);
492 QModelIndex index = CreateIndex(parent);
493 QModelIndex newIndex = CreateIndex(newParent);
494 beginMoveRows(index, sourcePos, sourcePos, newIndex, desPos);
495 parent->RemoveChild(cur);
496 newParent->AddChild(cur);
497 endMoveRows();
498 }
499 return true;
500}
501
502CFavoriteModel::tree::tree(): item(TreeItem::TYPE::Node)
503{}
504
505CFavoriteModel::tree::tree(CFavoriteDatabase::Item i)
506 : item(i)
507{}
508
509CFavoriteModel::tree::~tree()
510{
511}
512
513int CFavoriteModel::tree::GetRow() const
514{
515 return m_row;
516}
517
518void CFavoriteModel::tree::SetRow(int r)
519{
520 m_row = r;
521}
522
523bool CFavoriteModel::tree::IsFolder() const
524{
525 return item.isFolder();
526}
527
528bool CFavoriteModel::tree::IsFavorite() const
529{
530 return item.isFavorite();
531}
532
533int CFavoriteModel::tree::ChildCount() const
534{
535 return children.size();
536}
537
538CFavoriteModel::tree* CFavoriteModel::tree::ChildAt(int index) const
539{
540 if (index < 0 || index >= children.size()) {
541 return nullptr;
542 }
543 return children[index];
544}
545
546int CFavoriteModel::tree::GetInserIndex(tree *child)
547{
548 int index = 0;
549 if(!child) return 0;
550 if(child->IsFavorite()) {
551 index = children.size();
552 } else {
553 foreach (const auto &c, children) {
554 if (c && c->item.isFolder()) {
555 index++;
556 }
557 }
558 }
559 return index;
560}
561
562bool CFavoriteModel::tree::AddChild(tree *child)
563{
564 if (!child) return false;
565 child->parent = this;
566 return InsertChild(GetInserIndex(child), child);
567}
568
569bool CFavoriteModel::tree::InsertChild(int index, tree *child)
570{
571 if(0 > index || ChildCount() < index || !child)
572 return false;
573 children.insert(index, child);
574 child->parent = this;
575 // 更新剩余子节点的行号
576 for (int i = index; i < ChildCount(); ++i) {
577 children[i]->SetRow(i);
578 }
579 return true;
580}
581
582bool CFavoriteModel::tree::RemoveChild(tree *child)
583{
584 if (!child) return false;
585
586 int index = children.indexOf(child);
587 if (index == -1) return false;
588
589 children.remove(index);
590
591 // 更新剩余子节点的行号
592 for (int i = index; i < children.size(); ++i) {
593 children[i]->SetRow(i);
594 }
595
596 return true;
597}
598
599QList<CFavoriteModel::tree*> CFavoriteModel::tree::FindChild(const CFavoriteDatabase::Item &item) const
600{
601 QList<tree*> lstChildren;
602 for (auto child : children) {
603 if (child->item.id == item.id && child->item.type == item.type) {
604 lstChildren << child;
605 }
606 }
607 return lstChildren;
608}
609
610QList<CFavoriteModel::tree*> CFavoriteModel::tree::FindRecursive(const CFavoriteDatabase::Item &item) const
611{
612 QList<tree*> lstChildren;
613 if (item.id == this->item.id && item.type == this->item.type) {
614 lstChildren << const_cast<tree*>(this);
615 return lstChildren;
616 }
617 for (auto child : children) {
618 QList<tree*> found = child->FindRecursive(item);
619 if (!found.isEmpty()) {
620 lstChildren << found;
621 }
622 }
623 return lstChildren;
624}
int GetCount(int parentId=0)
得到指定id节点下的所有节点和叶子数。不递归。
The CFavoriteDatabase class