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