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