VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/globals/UIFileSystemModel.cpp@ 104158

Last change on this file since 104158 was 103710, checked in by vboxsync, 9 months ago

FE/Qt: Get rid of unwanted UICommon includes across whole the GUI.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.2 KB
Line 
1/* $Id: UIFileSystemModel.cpp 103710 2024-03-06 16:53:27Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIFileSystemModel class implementation.
4 */
5
6/*
7 * Copyright (C) 2016-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QApplication>
30#include <QDateTime>
31#include <QHeaderView>
32#include <QIODevice>
33#include <QMimeData>
34
35/* GUI includes: */
36#include "UIFileSystemModel.h"
37#include "UIErrorString.h"
38#include "UIPathOperations.h"
39#include "UITranslator.h"
40
41/* Other VBox includes: */
42#include "iprt/assert.h"
43
44const char *UIFileSystemModel::strUpDirectoryString = "..";
45
46
47/*********************************************************************************************************************************
48* UIFileSystemItem implementation. *
49*********************************************************************************************************************************/
50
51UIFileSystemItem::UIFileSystemItem(const QString &strFileObjectName, UIFileSystemItem *parent, KFsObjType type)
52 : m_parentItem(parent)
53 , m_bIsOpened(false)
54 , m_fIsTargetADirectory(false)
55 , m_type(type)
56 , m_fIsDriveItem(false)
57 , m_fIsHidden(false)
58{
59 for (int i = static_cast<int>(UIFileSystemModelData_Name);
60 i < static_cast<int>(UIFileSystemModelData_Max); ++i)
61 m_itemData[static_cast<UIFileSystemModelData>(i)] = QVariant();
62 m_itemData[UIFileSystemModelData_Name] = strFileObjectName;
63
64 if (parent)
65 {
66 parent->appendChild(this);
67 setParentModel(parent->parentModel());
68 }
69}
70
71UIFileSystemItem::~UIFileSystemItem()
72{
73 reset();
74}
75
76void UIFileSystemItem::appendChild(UIFileSystemItem *item)
77{
78 if (!item)
79 return;
80 if (m_childItems.contains(item))
81 return;
82 m_childItems.append(item);
83}
84
85void UIFileSystemItem::reset()
86{
87 qDeleteAll(m_childItems);
88 m_childItems.clear();
89 m_bIsOpened = false;
90}
91
92UIFileSystemItem *UIFileSystemItem::child(int row) const
93{
94 return m_childItems.value(row);
95}
96
97UIFileSystemItem *UIFileSystemItem::child(const QString &fileObjectName) const
98{
99 foreach (UIFileSystemItem *pItem, m_childItems)
100 if (pItem && pItem->fileObjectName() == fileObjectName)
101 return pItem;
102 return 0;
103}
104
105int UIFileSystemItem::childCount() const
106{
107 return m_childItems.count();
108}
109
110QList<UIFileSystemItem*> UIFileSystemItem::children() const
111{
112 QList<UIFileSystemItem*> childList;
113 foreach (UIFileSystemItem *child, m_childItems)
114 childList << child;
115 return childList;
116}
117
118void UIFileSystemItem::removeChild(UIFileSystemItem *pItem)
119{
120 int iIndex = m_childItems.indexOf(pItem);
121 if (iIndex == -1 || iIndex > m_childItems.size())
122 return;
123 m_childItems.removeAt(iIndex);
124 delete pItem;
125 pItem = 0;
126}
127
128void UIFileSystemItem::removeChildren()
129{
130 reset();
131}
132
133int UIFileSystemItem::columnCount() const
134{
135 return m_itemData.count();
136}
137
138QVariant UIFileSystemItem::data(int column) const
139{
140 return m_itemData.value(static_cast<UIFileSystemModelData>(column), QVariant());
141}
142
143QString UIFileSystemItem::fileObjectName() const
144{
145 QVariant data = m_itemData.value(UIFileSystemModelData_Name, QVariant());
146 if (!data.canConvert(QMetaType(QMetaType::QString)))
147 return QString();
148 return data.toString();
149}
150
151void UIFileSystemItem::setData(const QVariant &data, int index)
152{
153 if (m_itemData[static_cast<UIFileSystemModelData>(index)] == data)
154 return;
155 m_itemData[static_cast<UIFileSystemModelData>(index)] = data;
156}
157
158void UIFileSystemItem::setData(const QVariant &data, UIFileSystemModelData enmColumn)
159{
160 m_itemData[enmColumn] = data;
161}
162
163UIFileSystemItem *UIFileSystemItem::parentItem()
164{
165 return m_parentItem;
166}
167
168UIFileSystemItem *UIFileSystemItem::parentItem() const
169{
170 return m_parentItem;
171}
172
173int UIFileSystemItem::row() const
174{
175 if (m_parentItem)
176 return m_parentItem->m_childItems.indexOf(const_cast<UIFileSystemItem*>(this));
177 return 0;
178}
179
180bool UIFileSystemItem::isDirectory() const
181{
182 return m_type == KFsObjType_Directory;
183}
184
185bool UIFileSystemItem::isSymLink() const
186{
187 return m_type == KFsObjType_Symlink;
188}
189
190bool UIFileSystemItem::isFile() const
191{
192 return m_type == KFsObjType_File;
193}
194
195void UIFileSystemItem::clearChildren()
196{
197 qDeleteAll(m_childItems);
198 m_childItems.clear();
199}
200
201bool UIFileSystemItem::isOpened() const
202{
203 return m_bIsOpened;
204}
205
206void UIFileSystemItem::setIsOpened(bool flag)
207{
208 m_bIsOpened = flag;
209}
210
211QString UIFileSystemItem::path() const
212{
213 const QChar delimiter('/');
214
215 const UIFileSystemItem *pParent = this;
216 QStringList path;
217 while(pParent && pParent->parentItem())
218 {
219 path.prepend(pParent->fileObjectName());
220 pParent = pParent->parentItem();
221 }
222 QString strPath = UIPathOperations::removeMultipleDelimiters(path.join(delimiter));
223 if (m_pParentModel && m_pParentModel->isWindowsFileSystem())
224 {
225 if (!strPath.isEmpty() && strPath.at(0) == delimiter)
226 strPath.remove(0, 1);
227 }
228 return UIPathOperations::removeTrailingDelimiters(strPath);
229}
230
231bool UIFileSystemItem::isUpDirectory() const
232{
233 if (!isDirectory())
234 return false;
235 if (data(0) == UIFileSystemModel::strUpDirectoryString)
236 return true;
237 return false;
238}
239
240KFsObjType UIFileSystemItem::type() const
241{
242 return m_type;
243}
244
245const QString &UIFileSystemItem::targetPath() const
246{
247 return m_strTargetPath;
248}
249
250void UIFileSystemItem::setTargetPath(const QString &path)
251{
252 m_strTargetPath = path;
253}
254
255bool UIFileSystemItem::isSymLinkToADirectory() const
256{
257 return m_fIsTargetADirectory;
258}
259
260void UIFileSystemItem::setIsSymLinkToADirectory(bool flag)
261{
262 m_fIsTargetADirectory = flag;
263}
264
265bool UIFileSystemItem::isSymLinkToAFile() const
266{
267 return isSymLink() && !m_fIsTargetADirectory;
268}
269
270void UIFileSystemItem::setIsDriveItem(bool flag)
271{
272 m_fIsDriveItem = flag;
273}
274
275bool UIFileSystemItem::isDriveItem() const
276{
277 return m_fIsDriveItem;
278}
279
280void UIFileSystemItem::setIsHidden(bool flag)
281{
282 m_fIsHidden = flag;
283}
284
285bool UIFileSystemItem::isHidden() const
286{
287 return m_fIsHidden;
288}
289
290void UIFileSystemItem::setRemovedFromViso(bool fRemoved)
291{
292 m_itemData[UIFileSystemModelData_RemovedFromVISO] = fRemoved;
293}
294
295bool UIFileSystemItem::isRemovedFromViso() const
296{
297 return m_itemData[UIFileSystemModelData_RemovedFromVISO].toBool();
298}
299
300void UIFileSystemItem::setToolTip(const QString &strToolTip)
301{
302 m_strToolTip = strToolTip;
303}
304
305const QString &UIFileSystemItem::toolTip() const
306{
307 return m_strToolTip;
308}
309
310void UIFileSystemItem::setParentModel(UIFileSystemModel *pModel)
311{
312 m_pParentModel = pModel;
313}
314
315UIFileSystemModel *UIFileSystemItem::parentModel()
316{
317 return m_pParentModel;
318}
319
320
321/*********************************************************************************************************************************
322* UIFileSystemProxyModel implementation. *
323*********************************************************************************************************************************/
324
325UIFileSystemProxyModel::UIFileSystemProxyModel(QObject *parent /* = 0 */)
326 :QSortFilterProxyModel(parent)
327 , m_fListDirectoriesOnTop(false)
328 , m_fShowHiddenObjects(true)
329{
330}
331
332bool UIFileSystemProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
333{
334 UIFileSystemItem *pLeftItem = static_cast<UIFileSystemItem*>(left.internalPointer());
335 UIFileSystemItem *pRightItem = static_cast<UIFileSystemItem*>(right.internalPointer());
336
337 if (pLeftItem && pRightItem)
338 {
339 /* List the directories before the files if options say so: */
340 if (m_fListDirectoriesOnTop)
341 {
342 if ((pLeftItem->isDirectory() || pLeftItem->isSymLinkToADirectory()) && !pRightItem->isDirectory())
343 return (sortOrder() == Qt::AscendingOrder);
344 if ((pRightItem->isDirectory() || pRightItem->isSymLinkToADirectory()) && !pLeftItem->isDirectory())
345 return (sortOrder() == Qt::DescendingOrder);
346 }
347 /* Up directory item should be always the first item: */
348 if (pLeftItem->isUpDirectory())
349 return (sortOrder() == Qt::AscendingOrder);
350 else if (pRightItem->isUpDirectory())
351 return (sortOrder() == Qt::DescendingOrder);
352
353 /* If the sort column is QDateTime than handle it correctly: */
354 if (sortColumn() == UIFileSystemModelData_ChangeTime)
355 {
356 QVariant dataLeft = pLeftItem->data(UIFileSystemModelData_ChangeTime);
357 QVariant dataRight = pRightItem->data(UIFileSystemModelData_ChangeTime);
358 QDateTime leftDateTime = dataLeft.toDateTime();
359 QDateTime rightDateTime = dataRight.toDateTime();
360 return (leftDateTime < rightDateTime);
361 }
362 /* When we show human readble sizes in size column sorting gets confused, so do it here: */
363 else if(sortColumn() == UIFileSystemModelData_Size)
364 {
365 qulonglong leftSize = pLeftItem->data(UIFileSystemModelData_Size).toULongLong();
366 qulonglong rightSize = pRightItem->data(UIFileSystemModelData_Size).toULongLong();
367 return (leftSize < rightSize);
368
369 }
370 }
371 return QSortFilterProxyModel::lessThan(left, right);
372}
373
374bool UIFileSystemProxyModel::filterAcceptsRow(int iSourceRow, const QModelIndex &sourceParent) const
375{
376 if (m_fShowHiddenObjects)
377 return true;
378
379 QModelIndex itemIndex = sourceModel()->index(iSourceRow, 0, sourceParent);
380 if (!itemIndex.isValid())
381 return false;
382
383 UIFileSystemItem *item = static_cast<UIFileSystemItem*>(itemIndex.internalPointer());
384 if (!item)
385 return false;
386
387 if (item->isHidden())
388 return false;
389
390 return true;
391}
392
393void UIFileSystemProxyModel::setListDirectoriesOnTop(bool fListDirectoriesOnTop)
394{
395 m_fListDirectoriesOnTop = fListDirectoriesOnTop;
396}
397
398bool UIFileSystemProxyModel::listDirectoriesOnTop() const
399{
400 return m_fListDirectoriesOnTop;
401}
402
403void UIFileSystemProxyModel::setShowHiddenObjects(bool fShowHiddenObjects)
404{
405 m_fShowHiddenObjects = fShowHiddenObjects;
406}
407
408bool UIFileSystemProxyModel::showHiddenObjects() const
409{
410 return m_fShowHiddenObjects;
411}
412
413
414/*********************************************************************************************************************************
415* UIFileSystemModel implementation. *
416*********************************************************************************************************************************/
417
418UIFileSystemModel::UIFileSystemModel(QObject *parent)
419 : QAbstractItemModel(parent)
420 , m_fShowHumanReadableSizes(false)
421 , m_fIsWindowFileSystemModel(false)
422{
423 m_pRootItem = new UIFileSystemItem(QString(), 0, KFsObjType_Directory);
424 m_pRootItem->setParentModel(this);
425}
426
427QStringList UIFileSystemModel::mimeTypes() const
428{
429 QStringList types;
430 types << "application/vnd.text.list";
431 return types;
432}
433
434QMimeData *UIFileSystemModel::mimeData(const QModelIndexList &indexes) const
435{
436 QMimeData *mimeData = new QMimeData();
437 QByteArray encodedData;
438
439 QDataStream stream(&encodedData, QIODevice::WriteOnly);
440
441 foreach (const QModelIndex &index, indexes) {
442 if (index.isValid() && index.column() == 0)
443 {
444 UIFileSystemItem *pItem = static_cast<UIFileSystemItem*>(index.internalPointer());
445 if (!pItem)
446 continue;
447
448 QString strPath = pItem->path();
449 if (!strPath.contains(".."))
450 stream << strPath;
451 }
452 }
453
454 mimeData->setData("application/vnd.text.list", encodedData);
455 return mimeData;
456}
457
458UIFileSystemItem* UIFileSystemModel::rootItem()
459{
460 return m_pRootItem;
461}
462
463const UIFileSystemItem* UIFileSystemModel::rootItem() const
464{
465 return m_pRootItem;
466}
467
468UIFileSystemModel::~UIFileSystemModel()
469{
470 delete m_pRootItem;
471}
472
473int UIFileSystemModel::columnCount(const QModelIndex &parent) const
474{
475 if (parent.isValid())
476 return static_cast<UIFileSystemItem*>(parent.internalPointer())->columnCount();
477 else
478 {
479 if (!rootItem())
480 return 0;
481 else
482 return rootItem()->columnCount();
483 }
484}
485
486bool UIFileSystemModel::setData(const QModelIndex &index, const QVariant &value, int role)
487{
488 if (index.isValid() && role == Qt::EditRole)
489 {
490 if (index.column() == 0 && value.canConvert(QMetaType(QMetaType::QString)))
491 {
492 UIFileSystemItem *pItem = static_cast<UIFileSystemItem*>(index.internalPointer());
493 if (!pItem)
494 return false;
495 QString strOldName = pItem->fileObjectName();
496 QString strOldPath = pItem->path();
497 pItem->setData(value, index.column());
498 emit dataChanged(index, index);
499 emit sigItemRenamed(pItem, strOldPath, strOldName, value.toString());
500 return true;
501 }
502 }
503 return false;
504}
505
506QVariant UIFileSystemModel::data(const QModelIndex &index, int role) const
507{
508 if (!index.isValid())
509 return QVariant();
510 UIFileSystemItem *item = static_cast<UIFileSystemItem*>(index.internalPointer());
511 if (!item)
512 return QVariant();
513
514 if (role == Qt::DisplayRole || role == Qt::EditRole)
515 {
516 /* dont show anything but the name for up directories: */
517 if (item->isUpDirectory() && index.column() != UIFileSystemModelData_Name)
518 return QVariant();
519 /* Format date/time column: */
520 if (item->data(index.column()).canConvert(QMetaType(QMetaType::QDateTime)))
521 {
522 QDateTime dateTime = item->data(index.column()).toDateTime();
523 if (dateTime.isValid())
524 return dateTime.toString("dd.MM.yyyy hh:mm:ss");
525 }
526 /* Decide whether to show human-readable file object sizes: */
527 if (index.column() == UIFileSystemModelData_Size)
528 {
529 if (m_fShowHumanReadableSizes)
530 {
531 qulonglong size = item->data(index.column()).toULongLong();
532 return UITranslator::formatSize(size);
533 }
534 else
535 return item->data(index.column());
536 }
537 if (index.column() == UIFileSystemModelData_DescendantRemovedFromVISO)
538 {
539 if (item->data(UIFileSystemModelData_DescendantRemovedFromVISO).toBool())
540 return QString(QApplication::translate("UIVisoCreatorWidget", "Yes"));
541 else
542 return QString(QApplication::translate("UIVisoCreatorWidget", "No"));
543 }
544 return item->data(index.column());
545 }
546 /* Show file object icons: */
547 QString strContainingISOFile = item->data(UIFileSystemModelData_ISOFilePath).toString();
548 if (role == Qt::DecorationRole && index.column() == 0)
549 {
550 if (item->isDirectory())
551 {
552 if (item->isUpDirectory())
553 return QIcon(":/arrow_up_10px_x2.png");
554 else if(item->isDriveItem())
555 return QIcon(":/hd_32px.png");
556 else if (item->isRemovedFromViso())
557 return QIcon(":/file_manager_folder_remove_16px.png");
558 else if (!strContainingISOFile.isEmpty())
559 return QIcon(":/file_manager_folder_cd_16px.png");
560 else
561 return QIcon(":/file_manager_folder_16px.png");
562 }
563 else if (item->isFile())
564 {
565 if (item->isRemovedFromViso())
566 return QIcon(":/file_manager_file_remove_16px.png");
567 else if (!strContainingISOFile.isEmpty())
568 return QIcon(":/file_manager_file_cd_16px.png");
569 else
570 return QIcon(":/file_manager_file_16px.png");
571 }
572 else if (item->isSymLink())
573 {
574 if (item->isSymLinkToADirectory())
575 return QIcon(":/file_manager_folder_symlink_16px.png");
576 else
577 return QIcon(":/file_manager_file_symlink_16px.png");
578 }
579 }
580 if (role == Qt::ToolTipRole)
581 {
582 if (!item->toolTip().isEmpty())
583 return QString(item->toolTip());
584 }
585 return QVariant();
586}
587
588Qt::ItemFlags UIFileSystemModel::flags(const QModelIndex &index) const
589{
590 if (!index.isValid())
591 return Qt::ItemFlags();
592 UIFileSystemItem *item = static_cast<UIFileSystemItem*>(index.internalPointer());
593 if (!item)
594 return QAbstractItemModel::flags(index);
595
596 if (!item->isUpDirectory() && index.column() == 0)
597 return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
598 return QAbstractItemModel::flags(index);
599}
600
601QVariant UIFileSystemModel::headerData(int section, Qt::Orientation orientation,
602 int role) const
603{
604 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
605 {
606 if (!rootItem())
607 return QVariant();
608 else
609 return rootItem()->data(section);
610 }
611 return QVariant();
612}
613
614QModelIndex UIFileSystemModel::index(const UIFileSystemItem* item)
615{
616 if (!item)
617 return QModelIndex();
618 return createIndex(item->row(), 0, const_cast<UIFileSystemItem*>(item));
619}
620
621QModelIndex UIFileSystemModel::index(int row, int column, const QModelIndex &parent) const
622{
623 if (!hasIndex(row, column, parent))
624 return QModelIndex();
625
626 const UIFileSystemItem* parentItem = rootItem();
627
628 if (parent.isValid())
629 parentItem = static_cast<UIFileSystemItem*>(parent.internalPointer());
630
631 if (!parentItem)
632 return QModelIndex();
633
634 UIFileSystemItem *childItem = parentItem->child(row);
635 if (childItem)
636 return createIndex(row, column, childItem);
637 else
638 return QModelIndex();
639}
640
641
642QModelIndex UIFileSystemModel::parent(const QModelIndex &index) const
643{
644 if (!index.isValid())
645 return QModelIndex();
646
647 UIFileSystemItem *childItem = static_cast<UIFileSystemItem*>(index.internalPointer());
648 UIFileSystemItem *parentItem = childItem->parentItem();
649
650 if (!parentItem || parentItem == rootItem())
651 return QModelIndex();
652
653 return createIndex(parentItem->row(), 0, parentItem);
654}
655
656int UIFileSystemModel::rowCount(const QModelIndex &parent) const
657{
658 if (parent.column() > 0)
659 return 0;
660 const UIFileSystemItem *parentItem = rootItem();
661 if (parent.isValid())
662 parentItem = static_cast<UIFileSystemItem*>(parent.internalPointer());
663 if (!parentItem)
664 return 0;
665 return parentItem->childCount();
666}
667
668void UIFileSystemModel::signalUpdate()
669{
670 emit layoutChanged();
671}
672
673QModelIndex UIFileSystemModel::rootIndex() const
674{
675 if (!rootItem())
676 return QModelIndex();
677 if (!rootItem()->child(0))
678 return QModelIndex();
679 return createIndex(rootItem()->child(0)->row(), 0,
680 rootItem()->child(0));
681}
682
683void UIFileSystemModel::beginReset()
684{
685 beginResetModel();
686}
687
688void UIFileSystemModel::endReset()
689{
690 endResetModel();
691}
692
693void UIFileSystemModel::reset()
694{
695 AssertPtrReturnVoid(m_pRootItem);
696 beginResetModel();
697 m_pRootItem->reset();
698 endResetModel();
699}
700
701void UIFileSystemModel::setShowHumanReadableSizes(bool fShowHumanReadableSizes)
702{
703 m_fShowHumanReadableSizes = fShowHumanReadableSizes;
704}
705
706bool UIFileSystemModel::showHumanReadableSizes() const
707{
708 return m_fShowHumanReadableSizes;
709}
710
711void UIFileSystemModel::deleteItem(UIFileSystemItem* pItem)
712{
713 if (!pItem)
714 return;
715 UIFileSystemItem *pParent = pItem->parentItem();
716 if (pParent)
717 pParent->removeChild(pItem);
718}
719
720void UIFileSystemModel::setIsWindowsFileSystem(bool fIsWindowsFileSystem)
721{
722 m_fIsWindowFileSystemModel = fIsWindowsFileSystem;
723}
724
725bool UIFileSystemModel::isWindowsFileSystem() const
726{
727 return m_fIsWindowFileSystemModel;
728}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette