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