玉兔远程控制 0.1.0-bate8
载入中...
搜索中...
未找到
RemoteFileSystemModel.cpp
1// Copyright Copyright (c) Kang Lin studio, All Rights Reserved
2// Author: Kang Lin <kl222@126.com>
3
4#include <QStyle>
5#include <QApplication>
6#include <QIcon>
7#include <QFileInfo>
8#include <QLoggingCategory>
9#include <QMessageBox>
10
11#if defined(Q_OS_LINUX)
12#include <sys/stat.h>
13#endif
14
15#include "Stats.h"
16#include "RemoteFileSystemModel.h"
17
18Q_DECLARE_METATYPE(CRemoteFileSystem::TYPES)
19
20static Q_LOGGING_CATEGORY(log, "RemoteFileSystem.Model")
21
22static int g_CRemoteFileSystem = qRegisterMetaType<CRemoteFileSystem>("CRemoteFileSystem");
23
25 const QString& szPath, TYPES type)
26 : QObject()
27 , m_pParent(nullptr)
28 , m_szPath(szPath)
29 , m_nSize(0)
30 , m_Type(type)
31 , m_Permissions(QFileDevice::Permission::WriteOwner | QFileDevice::Permission::ReadOwner)
32 , m_State(State::No)
33{
34}
35
36CRemoteFileSystem::~CRemoteFileSystem()
37{
38 //qDebug(log) << Q_FUNC_INFO << m_szPath;
39}
40
41CRemoteFileSystem::CRemoteFileSystem(const CRemoteFileSystem &file)
42{
43 m_pParent = file.m_pParent;
44 m_vChild = file.m_vChild;
45 m_szPath = file.m_szPath;
46 m_nSize = file.m_nSize;
47 m_Type = file.m_Type;
48 m_createTime = file.m_createTime;
49 m_lastModifed = file.m_lastModifed;
50 m_Permissions = file.m_Permissions;
51 m_szOwner = file.m_szOwner;
52 m_State = file.m_State;
53}
54
55#if defined(Q_OS_LINUX)
56void uint32_to_permstr(uint32_t mode, char *str) {
57 str[0] = S_ISDIR(mode) ? 'd' :
58 S_ISLNK(mode) ? 'l' :
59 S_ISCHR(mode) ? 'c' :
60 S_ISBLK(mode) ? 'b' :
61 S_ISFIFO(mode) ? 'p' :
62 S_ISSOCK(mode) ? 's' : '-';
63
64 // User
65 str[1] = (mode & S_IRUSR) ? 'r' : '-';
66 str[2] = (mode & S_IWUSR) ? 'w' : '-';
67 str[3] = (mode & S_IXUSR) ? ((mode & S_ISUID) ? 's' : 'x') : ((mode & S_ISUID) ? 'S' : '-');
68 // Group
69 str[4] = (mode & S_IRGRP) ? 'r' : '-';
70 str[5] = (mode & S_IWGRP) ? 'w' : '-';
71 str[6] = (mode & S_IXGRP) ? ((mode & S_ISGID) ? 's' : 'x') : ((mode & S_ISGID) ? 'S' : '-');
72 // Others
73 str[7] = (mode & S_IROTH) ? 'r' : '-';
74 str[8] = (mode & S_IWOTH) ? 'w' : '-';
75 str[9] = (mode & S_IXOTH) ? ((mode & S_ISVTX) ? 't' : 'x') : ((mode & S_ISVTX) ? 'T' : '-');
76 str[10] = '\0';
77}
78#endif
79
80QVariant CRemoteFileSystem::Data(int column)
81{
82 switch((ColumnValue)column) {
83 case ColumnValue::Name: {
84 return GetName();
85 }
86 case ColumnValue::Size: {
87 return CStats::Convertbytes(GetSize());
88 }
89 case ColumnValue::Type: {
90 if(GetType() & TYPE::FILE)
91 return tr("File");
92 if(GetType() & TYPE::DIR)
93 return tr("Folder");
94 if(GetType() & TYPE::DRIVE)
95 return tr("Drive");
96 if(GetType() & TYPE::SYMLINK)
97 return tr("Symlink");
98 if(GetType() & TYPE::SPECIAL)
99 return tr("Special");
100 break;
101 }
102 case ColumnValue::LastModified: {
103 return GetLastModified();
104 }
105 case ColumnValue::Permission: {
106#if defined(Q_OS_LINUX)
107 quint32 permissions = (quint32)GetPermissions();
108 char buf[11];
109 uint32_to_permstr(permissions, buf);
110 return QString(buf);
111#endif
112 break;
113 }
114 case ColumnValue::Owner:
115 return GetOwner();
116 default:
117 break;
118 }
119 return QVariant();
120}
121
122QString CRemoteFileSystem::HeaderData(int section)
123{
124 switch ((ColumnValue)section) {
125 case ColumnValue::Name:
126 return tr("File name");
127 case ColumnValue::Size:
128 return tr("File size");
129 case ColumnValue::Type:
130 return tr("File type");
131 case ColumnValue::LastModified:
132 return tr("File last modified time");
133 case ColumnValue::Permission:
134 return tr("Permissions");
135 case ColumnValue::Owner:
136 return tr("Owner/Group");
137 default:
138 break;
139 }
140 return QString();
141}
142
143int CRemoteFileSystem::ColumnCount()
144{
145#if defined(Q_OS_WIN)
146 return (int)ColumnValue::Permission;
147#else
148 return (int)ColumnValue::End;
149#endif
150}
151
152int CRemoteFileSystem::ChildCount()
153{
154 return m_vChild.size();
155}
156
157void CRemoteFileSystem::SetParent(CRemoteFileSystem *pParent)
158{
159 m_pParent = pParent;
160}
161
162CRemoteFileSystem* CRemoteFileSystem::GetParent()
163{
164 return m_pParent;
165}
166
168{
169 Q_ASSERT_X(pChild->GetType(), "AppendChild", "Must set all the properties before call them");
170
171 // if(m_vChild.contains(pChild)) {
172 // qDebug(log) << pChild->GetName() << "is exist";
173 // return 0;
174 // }
175 if(-1 != IndexOf(pChild->GetPath()))
176 {
177 qDebug(log) << pChild->GetName() << "is exist";
178 return 0;
179 }
180
181 m_vChild.append(pChild);
182 pChild->SetParent(this);
183 return 0;
184}
185
186int CRemoteFileSystem::RemoveChild(int index)
187{
188 if(0 > index || m_vChild.size() < index)
189 return -1;
190 m_vChild.removeAt(index);
191 return 0;
192}
193
194CRemoteFileSystem* CRemoteFileSystem::GetChild(int nIndex)
195{
196 if(nIndex < 0 || nIndex >= m_vChild.size())
197 return nullptr;
198 return m_vChild.at(nIndex);
199}
200
201int CRemoteFileSystem::IndexOf(CRemoteFileSystem* pChild)
202{
203 return m_vChild.indexOf(pChild);
204}
205
206int CRemoteFileSystem::IndexOf(const QString& szPath)
207{
208 for(int i = 0; i < m_vChild.size(); i++) {
209 auto p = m_vChild[i];
210 if(p && p->GetPath() == szPath)
211 return i;
212 }
213 return -1;
214}
215
216int CRemoteFileSystem::IndexOfParent()
217{
218 int nIndex = -1;
219 if(GetParent())
220 nIndex= GetParent()->IndexOf(this);
221 return nIndex;
222}
223
224QString CRemoteFileSystem::GetPath()
225{
226 return m_szPath;
227}
228
229QString CRemoteFileSystem::GetName()
230{
231 QString szName;
232 QString szPath = GetPath();
233 if(szPath == '/')
234 return szPath;
235 int nIndex = szPath.lastIndexOf('/');
236 if(-1 == nIndex)
237 return QString();
238 szName = szPath.right(szPath.size() - nIndex - 1);
239 if(GetState() == State::Getting)
240 szName += "(" + tr("getting") + " ......)";
241 return szName;
242}
243
244quint64 CRemoteFileSystem::GetSize()
245{
246 return m_nSize;
247}
248
249void CRemoteFileSystem::SetSize(quint64 size)
250{
251 m_nSize = size;
252}
253
254bool CRemoteFileSystem::IsDir()
255{
256 return !(GetType() & TYPE::FILE);
257}
258
259QIcon CRemoteFileSystem::Icon()
260{
261 if(GetType() & TYPE::DRIVE)
262 return QIcon::fromTheme("drive-harddisk");
263 if(GetType() & TYPE::DIR)
264 return QIcon::fromTheme("folder-remote");
265 if(GetType() & TYPE::FILE || GetType() & TYPE::SPECIAL)
266 return QApplication::style()->standardIcon(QStyle::SP_FileIcon);
267 if(GetType() & TYPE::SYMLINK)
268 return QIcon::fromTheme("emblem-symbolic-link");
269 return QIcon();
270}
271
272CRemoteFileSystem::TYPES CRemoteFileSystem::GetType()
273{
274 return m_Type;
275}
276
277QDateTime CRemoteFileSystem::GetCreateTime()
278{
279 return m_createTime;
280}
281
282void CRemoteFileSystem::SetCreateTime(const QDateTime &date)
283{
284 m_createTime = date;
285}
286
287QDateTime CRemoteFileSystem::GetLastModified()
288{
289 return m_lastModifed;
290}
291
292void CRemoteFileSystem::SetLastModified(const QDateTime &date)
293{
294 m_lastModifed = date;
295}
296
297QFileDevice::Permissions CRemoteFileSystem::GetPermissions()
298{
299 return m_Permissions;
300}
301
302void CRemoteFileSystem::SetPermissions(QFileDevice::Permissions privileges)
303{
304 m_Permissions = privileges;
305}
306
307QString CRemoteFileSystem::GetOwner()
308{
309 return m_szOwner;
310}
311
312void CRemoteFileSystem::SetOwner(QString szOwner)
313{
314 m_szOwner = szOwner;
315}
316
317void CRemoteFileSystem::SetState(State a)
318{
319 m_State = a;
320}
321
322const CRemoteFileSystem::State CRemoteFileSystem::GetState() const
323{
324 return m_State;
325}
326
327CRemoteFileSystemModel::CRemoteFileSystemModel(
328 QObject *parent, CRemoteFileSystem::TYPES filter)
329 : QAbstractItemModel(parent)
330 , m_pRoot(nullptr)
331 , m_Filter(filter)
332{}
333
334CRemoteFileSystemModel::~CRemoteFileSystemModel()
335{
336 qDebug(log) << Q_FUNC_INFO;
337
338 DeleteRemoteFileSystem(m_pRoot);
339}
340
341void CRemoteFileSystemModel::DeleteRemoteFileSystem(CRemoteFileSystem* p)
342{
343 if(!p) return;
344 for(int i = 0; i < p->ChildCount(); i++) {
345 auto pChild = p->GetChild(i);
346 if(pChild)
347 DeleteRemoteFileSystem(pChild);
348 }
349 p->deleteLater();
350}
351
352QModelIndex CRemoteFileSystemModel::SetRootPath(const QString &szPath)
353{
354 if(szPath.isEmpty()) return QModelIndex();
355 if(m_pRoot && m_pRoot->GetPath() == szPath)
356 return index(m_pRoot);
357 beginResetModel();
358 m_GetFolder.clear();
359 if(m_pRoot) {
360 DeleteRemoteFileSystem(m_pRoot);
361 m_pRoot = nullptr;
362 }
363 m_pRoot = new CRemoteFileSystem(szPath, CRemoteFileSystem::TYPE::DIR);
364 QModelIndex idx = index(m_pRoot);
365 endResetModel();
366 qDebug(log) << "SetRootPath:" << this << idx << szPath;
367 return idx;
368}
369
370CRemoteFileSystem* CRemoteFileSystemModel::GetRoot()
371{
372 return m_pRoot;
373}
374
375CRemoteFileSystem* CRemoteFileSystemModel::GetRemoteFileSystemFromIndex(const QModelIndex &index) const
376{
377 if(index.isValid())
378 return static_cast<CRemoteFileSystem*>(index.internalPointer());
379 return nullptr;
380}
381
382CRemoteFileSystem::TYPES CRemoteFileSystemModel::GetFilter()
383{
384 return m_Filter;
385}
386
387QVariant CRemoteFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const
388{
389 if(Qt::DisplayRole != role)
390 return QVariant();
391 if(Qt::Vertical == orientation) {
392 return QString::number(section + 1);
393 } else {
394 return CRemoteFileSystem::HeaderData(section);
395 }
396 return QVariant();
397}
398
399int CRemoteFileSystemModel::rowCount(const QModelIndex &parent) const
400{
401 //qDebug(log) << Q_FUNC_INFO << parent;
402 if(!parent.isValid()) return 0;
403 CRemoteFileSystem* pItem = nullptr;
404 pItem = GetRemoteFileSystemFromIndex(parent);
405 if(pItem)
406 return pItem->ChildCount();
407 return 0;
408}
409
410int CRemoteFileSystemModel::columnCount(const QModelIndex &parent) const
411{
412 if(!parent.isValid()) return 0;
413 return CRemoteFileSystem::ColumnCount();
414}
415
416QVariant CRemoteFileSystemModel::data(const QModelIndex &index, int role) const
417{
418 /*
419 qDebug(log) << Q_FUNC_INFO << index << role;//*/
420 if (!index.isValid())
421 return QVariant();
422 if (role != Qt::DisplayRole && role != Qt::DecorationRole)
423 return QVariant();
424 //qDebug(log) << Q_FUNC_INFO << index;
425 CRemoteFileSystem* pItem = GetRemoteFileSystemFromIndex(index);
426 if(!pItem)
427 return QVariant();
428 if(!(pItem->GetType() & m_Filter))
429 return QVariant();
430 if(Qt::DecorationRole == role && index.column() == 0)
431 return pItem->Icon();
432 if(Qt::DisplayRole == role || Qt::EditRole == role)
433 return pItem->Data(index.column());
434 if(Qt::ToolTipRole == role)
435 return pItem->GetPath();
436 return QVariant();
437}
438
439QModelIndex CRemoteFileSystemModel::index(const QString& szPath) const
440{
441 int r = 0;
442 qDebug(log) << Q_FUNC_INFO << szPath;
443 QModelIndex idxParent;
444 QModelIndex idx = index(0, 0);
445 while(idx.isValid()) {
446 idx = index(r++, 0, idxParent);
447 CRemoteFileSystem* pRemoteFileSystem = GetRemoteFileSystemFromIndex(idx);
448 if(!pRemoteFileSystem)
449 continue;
450 QString szDir = pRemoteFileSystem->GetPath();
451 qDebug(log) << szDir << szPath;
452 if(szDir == szPath)
453 return idx;
454 if(pRemoteFileSystem->GetType() & CRemoteFileSystem::TYPE::FILE) {
455 qDebug(log) << szDir << "Is file:";
456 continue;
457 }
458 if(szDir.right(1) != '/')
459 szDir += '/';
460 if(szPath.left(szDir.size()) == szDir) {
461 qDebug(log) << "Contain:" << szPath << szDir;
462 idxParent = idx;
463 r = 0;
464 continue;
465 }
466 }
467 return QModelIndex();
468}
469
470QModelIndex CRemoteFileSystemModel::index(CRemoteFileSystem* node, int column) const
471{
472 if(nullptr == node) return QModelIndex();
473 int row = -1;
474 CRemoteFileSystem* parent = node->GetParent();
475 if(parent) {
476 row = node->IndexOfParent();
477 } else if(node == m_pRoot) {
478 row = 0;
479 }
480 if(0 > row || 0 > column || CRemoteFileSystem::ColumnCount() < column)
481 return QModelIndex();
482 return createIndex(row, column, node);
483}
484
485QModelIndex CRemoteFileSystemModel::index(int row, int column, const QModelIndex &parent) const
486{
487 //qDebug(log) << Q_FUNC_INFO << parent << row << column;
488 if (!hasIndex(row, column, parent))
489 return QModelIndex();
490 if(!parent.isValid())
491 return index(m_pRoot, column);
492 CRemoteFileSystem* pItem = nullptr;
493 pItem = GetRemoteFileSystemFromIndex(parent);
494 if(!pItem)
495 return QModelIndex();
496 pItem = pItem->GetChild(row);
497 if(pItem)
498 return createIndex(row, column, pItem);
499 else
500 return QModelIndex();
501}
502
503QModelIndex CRemoteFileSystemModel::parent(const QModelIndex &child) const
504{
505 //qDebug(log) << Q_FUNC_INFO << child;
506 if (!child.isValid())
507 return QModelIndex();
508 CRemoteFileSystem* pItem = GetRemoteFileSystemFromIndex(child);
509 if(!pItem)
510 return QModelIndex();
511 CRemoteFileSystem* pItemParent = pItem->GetParent();
512 if(pItemParent)
513 return index(pItemParent);
514 return QModelIndex();
515}
516
517bool CRemoteFileSystemModel::canFetchMore(const QModelIndex &parent) const
518{
519 if(!parent.isValid()) {
520 qDebug(log) << "canFetchMore: parent is valid" << parent;
521 return true;
522 }
523 CRemoteFileSystem* p = GetRemoteFileSystemFromIndex(parent);
524 if(p && p->GetState() == CRemoteFileSystem::State::No
525 && !(p->GetType() & CRemoteFileSystem::TYPE::FILE)) {
526 qDebug(log) << "canFetchMore:" << parent << p->GetPath() << "true";
527 return true;
528 }
529 qDebug(log) << Q_FUNC_INFO << parent;
530 return false;
531}
532
533void CRemoteFileSystemModel::fetchMore(const QModelIndex &parent)
534{
535 qDebug(log) << Q_FUNC_INFO << parent;
536 auto p = GetRemoteFileSystemFromIndex(parent);
537 if(!p) p = m_pRoot;
538 if(!p) {
539 qCritical(log) << "fetchMore:" << parent << "The pointer is nullptr";
540 return;
541 }
542 if(p->GetType() & CRemoteFileSystem::TYPE::FILE) {
543 qCritical(log) << "fetchMore:" << parent << "The node is file";
544 return;
545 }
546 QString szPath = p->GetPath();
547 if(szPath.isEmpty()) {
548 qCritical(log) << "fetchMore:" << parent << "The path is empty";
549 return;
550 }
551 if(p->GetState() != CRemoteFileSystem::State::No) {
552 qDebug(log) << "fetchMore:" << parent << p->GetState() << "The state is not NO";
553 return;
554 }
555 if(m_GetFolder.indexOf(p) != -1)
556 return;
557 m_GetFolder.append(p);
558 p->SetState(CRemoteFileSystem::State::Getting);
559 emit sigGetDir(p);
560 qDebug(log) << "fetchMore:" << parent << p << szPath;
561}
562
563void CRemoteFileSystemModel::slotGetDir(
565 QVector<QSharedPointer<CRemoteFileSystem> > contents,
566 bool bEnd)
567{
568 if(!p) {
569 qCritical(log) << "The pointer is nullptr";
570 return;
571 }
572 int nIndex = m_GetFolder.indexOf(p);
573 if(-1 == nIndex) {
574 qDebug(log) << "Is not the model";
575 return;
576 }
577 //qDebug(log) << Q_FUNC_INFO << p->GetPath() << contents.size() << bEnd;
578 m_GetFolder.removeAt(nIndex);
579 QModelIndex parentIndex;
580 parentIndex = index(p, 0);
581 qDebug(log) << "slotGetDir:" << p << p << p->GetPath() << parentIndex << contents.size();
582 p->SetState(CRemoteFileSystem::State::Ok);
583 if(contents.size() > 0) {
584 int nCount = 0;
585 foreach(auto c, contents) {
586 if(!c) continue;
587 if(!(c->GetType() & GetFilter())) continue;
588 nCount++;
589 }
590 beginInsertRows(parentIndex, 0, nCount);
591 foreach(auto c, contents) {
592 if(!c) continue;
593 if(!(c->GetType() & GetFilter())) continue;
594 CRemoteFileSystem* pRfs =
595 new CRemoteFileSystem(c->GetPath(), c->GetType());
596 pRfs->SetSize(c->GetSize());
597 pRfs->SetPermissions(c->GetPermissions());
598 pRfs->SetLastModified(c->GetLastModified());
599 pRfs->SetCreateTime(c->GetCreateTime());
600 p->AppendChild(pRfs);
601 }
602 endInsertRows();
603 auto topleft = index(0, 0, parentIndex);
604 auto bottomRight = index(p->ChildCount(), p->ColumnCount(), parentIndex);
605 if(topleft.isValid() && bottomRight.isValid())
606 emit dataChanged(topleft, bottomRight);
607 } else
608 emit dataChanged(parentIndex, parentIndex);
609}
610
611void CRemoteFileSystemModel::CreateDir(QModelIndex index, const QString &dir)
612{
613 auto p = GetRemoteFileSystemFromIndex(index);
614 if(!p) p = m_pRoot;
615 if(p && !p->GetPath().isEmpty()) {
616 QString szPath = p->GetPath() + "/" + dir;
617 if(p->IndexOf(szPath) > -1) {
618 qCritical(log) << "The path is exist:" << szPath;
619 QMessageBox::critical(nullptr, tr("Error"), tr("The path is exist: %1").arg(szPath));
620 return;
621 }
622 emit sigMakeDir(szPath);
623 p->SetState(CRemoteFileSystem::State::No);
624 fetchMore(parent(this->index(p)));
625 }
626}
627
628void CRemoteFileSystemModel::RemoveDir(QModelIndex index)
629{
630 auto p = GetRemoteFileSystemFromIndex(index);
631 if(p && !p->GetPath().isEmpty()) {
632 if(QMessageBox::question(
633 nullptr, tr("Delete directory"),
634 tr("Are you sure you want to delete '%1'?").arg(p->GetPath()),
635 QMessageBox::Yes | QMessageBox::No)
636 != QMessageBox::Yes)
637 return;
638 if(p->GetType() & CRemoteFileSystem::TYPE::DIR)
639 emit sigRemoveDir(p->GetPath());
640 else
641 emit sigRemoveFile(p->GetPath());
642
643 auto pParent = p->GetParent();
644 if(pParent) {
645 int nIdx = pParent->IndexOf(p);
646 beginRemoveRows(index.parent(), nIdx, nIdx);
647 pParent->RemoveChild(nIdx);
648 DeleteRemoteFileSystem(p);
649 endRemoveRows();
650 pParent->SetState(CRemoteFileSystem::State::No);
651 fetchMore(index.parent());
652 }
653 }
654}
655
656bool CRemoteFileSystemModel::setData(
657 const QModelIndex &index, const QVariant &value, int role)
658{
659 qDebug(log) << Q_FUNC_INFO << index << value << role;
660 if(!index.isValid())
661 return false;
662 if(Qt::EditRole != role) {
663 return QAbstractItemModel::setData(index, value, role);
664 }
665
666 // Rename
667 auto p = GetRemoteFileSystemFromIndex(index);
668 QString szName = value.toString();
669 if(p && !p->GetPath().isEmpty() && p->GetName() != szName) {
670 QFileInfo fi(p->GetPath());
671 szName = fi.path() + "/" + szName;
672 emit sigRename(p->GetPath(), szName);
673 auto pParent = p->GetParent();
674 if(pParent) {
675 Q_ASSERT(pParent == GetRemoteFileSystemFromIndex(index.parent()));
676 int nIdx = pParent->IndexOf(p);
677 beginRemoveRows(index.parent(), nIdx, nIdx);
678 pParent->RemoveChild(nIdx);
679 DeleteRemoteFileSystem(p);
680 endRemoveRows();
681 pParent->SetState(CRemoteFileSystem::State::No);
682 fetchMore(index.parent());
683 }
684 }
685 return true;
686}
687
688Qt::ItemFlags CRemoteFileSystemModel::flags(const QModelIndex &index) const
689{
690 Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
691 if (!index.isValid())
692 return defaultFlags;
693 // 只允许名称列可编辑
694 if (index.column() == (int)CRemoteFileSystem::ColumnValue::Name)
695 return defaultFlags | Qt::ItemIsEditable;
696 return defaultFlags;
697}
int AppendChild(CRemoteFileSystem *pChild)
Append child