| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the examples of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU Lesser General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
| 21 | ** packaging of this file. Please review the following information to | 
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
| 24 | ** | 
| 25 | ** GNU General Public License Usage | 
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
| 27 | ** General Public License version 2.0 or (at your option) the GNU General | 
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
| 31 | ** included in the packaging of this file. Please review the following | 
| 32 | ** information to ensure the GNU General Public License requirements will | 
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
| 35 | ** | 
| 36 | ** $QT_END_LICENSE$ | 
| 37 | ** | 
| 38 | ****************************************************************************/ | 
| 39 |  | 
| 40 | //![code] | 
| 41 | #include "qquickfolderlistmodel.h" | 
| 42 | #include "fileinfothread_p.h" | 
| 43 | #include "fileproperty_p.h" | 
| 44 | #include <qqmlcontext.h> | 
| 45 | #include <qqmlfile.h> | 
| 46 |  | 
| 47 | QT_BEGIN_NAMESPACE | 
| 48 |  | 
| 49 | class QQuickFolderListModelPrivate | 
| 50 | { | 
| 51 |     Q_DECLARE_PUBLIC(QQuickFolderListModel) | 
| 52 |  | 
| 53 | public: | 
| 54 |     QQuickFolderListModelPrivate(QQuickFolderListModel *q) : q_ptr(q) { } | 
| 55 |  | 
| 56 |     QQuickFolderListModel *q_ptr; | 
| 57 |     QUrl currentDir; | 
| 58 |     QUrl rootDir; | 
| 59 |     FileInfoThread fileInfoThread; | 
| 60 |     QList<FileProperty> data; | 
| 61 |     QHash<int, QByteArray> roleNames; | 
| 62 |     QQuickFolderListModel::SortField sortField = QQuickFolderListModel::Name; | 
| 63 |     QStringList nameFilters = { QLatin1String("*" ) }; | 
| 64 |     QQuickFolderListModel::Status status = QQuickFolderListModel::Null; | 
| 65 |     bool sortReversed = false; | 
| 66 |     bool showFiles = true; | 
| 67 |     bool showDirs = true; | 
| 68 |     bool showDirsFirst = false; | 
| 69 |     bool showDotAndDotDot = false; | 
| 70 |     bool showOnlyReadable = false; | 
| 71 |     bool showHidden = false; | 
| 72 |     bool caseSensitive = true; | 
| 73 |     bool sortCaseSensitive = true; | 
| 74 |  | 
| 75 |     ~QQuickFolderListModelPrivate() {} | 
| 76 |     void init(); | 
| 77 |     void updateSorting(); | 
| 78 |  | 
| 79 |     // private slots | 
| 80 |     void _q_directoryChanged(const QString &directory, const QList<FileProperty> &list); | 
| 81 |     void _q_directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex); | 
| 82 |     void _q_sortFinished(const QList<FileProperty> &list); | 
| 83 |     void _q_statusChanged(QQuickFolderListModel::Status s); | 
| 84 |  | 
| 85 |     static QString resolvePath(const QUrl &path); | 
| 86 | }; | 
| 87 |  | 
| 88 |  | 
| 89 | void QQuickFolderListModelPrivate::init() | 
| 90 | { | 
| 91 |     Q_Q(QQuickFolderListModel); | 
| 92 |     qRegisterMetaType<QList<FileProperty> >(typeName: "QList<FileProperty>" ); | 
| 93 |     qRegisterMetaType<QQuickFolderListModel::Status>(typeName: "QQuickFolderListModel::Status" ); | 
| 94 |     q->connect(sender: &fileInfoThread, SIGNAL(directoryChanged(QString,QList<FileProperty>)), | 
| 95 |                receiver: q, SLOT(_q_directoryChanged(QString,QList<FileProperty>))); | 
| 96 |     q->connect(sender: &fileInfoThread, SIGNAL(directoryUpdated(QString,QList<FileProperty>,int,int)), | 
| 97 |                receiver: q, SLOT(_q_directoryUpdated(QString,QList<FileProperty>,int,int))); | 
| 98 |     q->connect(sender: &fileInfoThread, SIGNAL(sortFinished(QList<FileProperty>)), | 
| 99 |                receiver: q, SLOT(_q_sortFinished(QList<FileProperty>))); | 
| 100 |     q->connect(sender: &fileInfoThread, SIGNAL(statusChanged(QQuickFolderListModel::Status)), | 
| 101 |                receiver: q, SLOT(_q_statusChanged(QQuickFolderListModel::Status))); | 
| 102 |     q->connect(sender: q, SIGNAL(rowCountChanged()), receiver: q, SIGNAL(countChanged())); | 
| 103 | } | 
| 104 |  | 
| 105 |  | 
| 106 | void QQuickFolderListModelPrivate::updateSorting() | 
| 107 | { | 
| 108 |     Q_Q(QQuickFolderListModel); | 
| 109 |  | 
| 110 |     QDir::SortFlags flags; | 
| 111 |  | 
| 112 |     switch (sortField) { | 
| 113 |         case QQuickFolderListModel::Unsorted: | 
| 114 |             flags |= QDir::Unsorted; | 
| 115 |             break; | 
| 116 |         case QQuickFolderListModel::Name: | 
| 117 |             flags |= QDir::Name; | 
| 118 |             break; | 
| 119 |         case QQuickFolderListModel::Time: | 
| 120 |             flags |= QDir::Time; | 
| 121 |             break; | 
| 122 |         case QQuickFolderListModel::Size: | 
| 123 |             flags |= QDir::Size; | 
| 124 |             break; | 
| 125 |         case QQuickFolderListModel::Type: | 
| 126 |             flags |= QDir::Type; | 
| 127 |             break; | 
| 128 |     } | 
| 129 |  | 
| 130 |     emit q->layoutAboutToBeChanged(); | 
| 131 |  | 
| 132 |     if (sortReversed) | 
| 133 |         flags |= QDir::Reversed; | 
| 134 |     if (!sortCaseSensitive) | 
| 135 |         flags |= QDir::IgnoreCase; | 
| 136 |  | 
| 137 |     fileInfoThread.setSortFlags(flags); | 
| 138 | } | 
| 139 |  | 
| 140 | void QQuickFolderListModelPrivate::_q_directoryChanged(const QString &directory, const QList<FileProperty> &list) | 
| 141 | { | 
| 142 |     Q_Q(QQuickFolderListModel); | 
| 143 |     Q_UNUSED(directory); | 
| 144 |  | 
| 145 |     data = list; | 
| 146 |     q->endResetModel(); | 
| 147 |     emit q->rowCountChanged(); | 
| 148 |     emit q->folderChanged(); | 
| 149 | } | 
| 150 |  | 
| 151 |  | 
| 152 | void QQuickFolderListModelPrivate::_q_directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex) | 
| 153 | { | 
| 154 |     Q_Q(QQuickFolderListModel); | 
| 155 |     Q_UNUSED(directory); | 
| 156 |  | 
| 157 |     QModelIndex parent; | 
| 158 |     if (data.size() == list.size()) { | 
| 159 |         QModelIndex modelIndexFrom = q->createIndex(arow: fromIndex, acolumn: 0); | 
| 160 |         QModelIndex modelIndexTo = q->createIndex(arow: toIndex, acolumn: 0); | 
| 161 |         data = list; | 
| 162 |         emit q->dataChanged(topLeft: modelIndexFrom, bottomRight: modelIndexTo); | 
| 163 |     } else { | 
| 164 |         // File(s) inserted or removed. Since I do not know how many | 
| 165 |         // or where, I need to update the whole list from the first item. | 
| 166 |         // This is a little pessimistic, but optimizing it would require | 
| 167 |         // more information in the signal from FileInfoThread. | 
| 168 |         if (data.size() > 0) { | 
| 169 |             q->beginRemoveRows(parent, first: 0, last: data.size() - 1); | 
| 170 |             q->endRemoveRows(); | 
| 171 |         } | 
| 172 |         data = list; | 
| 173 |         if (list.size() > 0) { | 
| 174 |             if (toIndex > list.size() - 1) | 
| 175 |                 toIndex = list.size() - 1; | 
| 176 |             q->beginInsertRows(parent, first: 0, last: data.size() - 1); | 
| 177 |             q->endInsertRows(); | 
| 178 |         } | 
| 179 |         emit q->rowCountChanged(); | 
| 180 |     } | 
| 181 | } | 
| 182 |  | 
| 183 | void QQuickFolderListModelPrivate::_q_sortFinished(const QList<FileProperty> &list) | 
| 184 | { | 
| 185 |     Q_Q(QQuickFolderListModel); | 
| 186 |  | 
| 187 |     QModelIndex parent; | 
| 188 |     if (data.size() > 0) { | 
| 189 |         q->beginRemoveRows(parent, first: 0, last: data.size()-1); | 
| 190 |         data.clear(); | 
| 191 |         q->endRemoveRows(); | 
| 192 |     } | 
| 193 |  | 
| 194 |     q->beginInsertRows(parent, first: 0, last: list.size()-1); | 
| 195 |     data = list; | 
| 196 |     q->endInsertRows(); | 
| 197 | } | 
| 198 |  | 
| 199 | void QQuickFolderListModelPrivate::_q_statusChanged(QQuickFolderListModel::Status s) | 
| 200 | { | 
| 201 |     Q_Q(QQuickFolderListModel); | 
| 202 |  | 
| 203 |     if (status != s) { | 
| 204 |         status = s; | 
| 205 |         emit q->statusChanged(); | 
| 206 |     } | 
| 207 | } | 
| 208 |  | 
| 209 | QString QQuickFolderListModelPrivate::resolvePath(const QUrl &path) | 
| 210 | { | 
| 211 |     QString localPath = QQmlFile::urlToLocalFileOrQrc(path); | 
| 212 |     QUrl localUrl = QUrl(localPath); | 
| 213 |     QString fullPath = localUrl.path(); | 
| 214 |     if (localUrl.scheme().length()) | 
| 215 |       fullPath = localUrl.scheme() + QLatin1Char(':') + fullPath; | 
| 216 |     return QDir::cleanPath(path: fullPath); | 
| 217 | } | 
| 218 |  | 
| 219 | /*! | 
| 220 |     \qmlmodule Qt.labs.folderlistmodel 2.\QtMinorVersion | 
| 221 |     \title Qt Labs FolderListModel QML Types | 
| 222 |     \ingroup qmlmodules | 
| 223 |     \brief The FolderListModel provides a model of the contents of a file system folder. | 
| 224 |  | 
| 225 |     To use this module, import the module with the following line: | 
| 226 |  | 
| 227 |     \qml \QtMinorVersion | 
| 228 |     import Qt.labs.folderlistmodel 2.\1 | 
| 229 |     \endqml | 
| 230 | */ | 
| 231 |  | 
| 232 |  | 
| 233 | /*! | 
| 234 |     \qmltype FolderListModel | 
| 235 |     \inqmlmodule Qt.labs.folderlistmodel | 
| 236 |     \instantiates QQuickFolderListModel | 
| 237 |     \ingroup qtquick-models | 
| 238 |     \brief The FolderListModel provides a model of the contents of a file system folder. | 
| 239 |  | 
| 240 |     FolderListModel provides access to information about the contents of a folder | 
| 241 |     in the local file system, exposing a list of files to views and other data components. | 
| 242 |  | 
| 243 |     \note This type is made available by importing the \c Qt.labs.folderlistmodel module. | 
| 244 |     \e{Elements in the Qt.labs module are not guaranteed to remain compatible | 
| 245 |     in future versions.} | 
| 246 |  | 
| 247 |     \qml \QtMinorVersion | 
| 248 |     import Qt.labs.folderlistmodel 2.\1 | 
| 249 |     \endqml | 
| 250 |  | 
| 251 |     The \l folder property specifies the folder to access. Information about the | 
| 252 |     files and directories in the folder is supplied via the model's interface. | 
| 253 |     Components access names and paths via the following roles: | 
| 254 |  | 
| 255 |     \list | 
| 256 |     \li \c fileName | 
| 257 |     \li \c filePath | 
| 258 |     \li \c fileURL (since Qt 5.2; deprecated since Qt 5.15) | 
| 259 |     \li \c fileUrl (since Qt 5.15) | 
| 260 |     \li \c fileBaseName | 
| 261 |     \li \c fileSuffix | 
| 262 |     \li \c fileSize | 
| 263 |     \li \c fileModified | 
| 264 |     \li \c fileAccessed | 
| 265 |     \li \c fileIsDir | 
| 266 |     \endlist | 
| 267 |  | 
| 268 |     Additionally a file entry can be differentiated from a folder entry via the | 
| 269 |     isFolder() method. | 
| 270 |  | 
| 271 |     \section1 Filtering | 
| 272 |  | 
| 273 |     Various properties can be set to filter the number of files and directories | 
| 274 |     exposed by the model. | 
| 275 |  | 
| 276 |     The \l nameFilters property can be set to contain a list of wildcard filters | 
| 277 |     that are applied to names of files and directories, causing only those that | 
| 278 |     match the filters to be exposed. | 
| 279 |  | 
| 280 |     Directories can be included or excluded using the \l showDirs property, | 
| 281 |     navigation directories can also be excluded by setting the \l showDotAndDotDot | 
| 282 |     property to false, hidden files can be included or excluded using the | 
| 283 |     \l showHidden property. | 
| 284 |  | 
| 285 |     It is sometimes useful to limit the files and directories exposed to those | 
| 286 |     that the user can access. The \l showOnlyReadable property can be set to | 
| 287 |     enable this feature. | 
| 288 |  | 
| 289 |     \section1 Example Usage | 
| 290 |  | 
| 291 |     The following example shows a FolderListModel being used to provide a list | 
| 292 |     of QML files in a \l ListView: | 
| 293 |  | 
| 294 |     \qml \QtMinorVersion | 
| 295 |     import QtQuick 2.\1 | 
| 296 |     import Qt.labs.folderlistmodel 2.\1 | 
| 297 |  | 
| 298 |     ListView { | 
| 299 |         width: 200; height: 400 | 
| 300 |  | 
| 301 |         FolderListModel { | 
| 302 |             id: folderModel | 
| 303 |             nameFilters: ["*.qml"] | 
| 304 |         } | 
| 305 |  | 
| 306 |         Component { | 
| 307 |             id: fileDelegate | 
| 308 |             Text { text: fileName } | 
| 309 |         } | 
| 310 |  | 
| 311 |         model: folderModel | 
| 312 |         delegate: fileDelegate | 
| 313 |     } | 
| 314 |     \endqml | 
| 315 |  | 
| 316 |     \section1 Path Separators | 
| 317 |  | 
| 318 |     Qt uses "/" as a universal directory separator in the same way that "/" is | 
| 319 |     used as a path separator in URLs. If you always use "/" as a directory | 
| 320 |     separator, Qt will translate your paths to conform to the underlying | 
| 321 |     operating system. | 
| 322 |  | 
| 323 |     \sa {QML Data Models} | 
| 324 | */ | 
| 325 |  | 
| 326 | QQuickFolderListModel::QQuickFolderListModel(QObject *parent) | 
| 327 |     : QAbstractListModel(parent), d_ptr(new QQuickFolderListModelPrivate(this)) | 
| 328 | { | 
| 329 |     Q_D(QQuickFolderListModel); | 
| 330 |     d->roleNames[FileNameRole] = "fileName" ; | 
| 331 |     d->roleNames[FilePathRole] = "filePath" ; | 
| 332 |     d->roleNames[FileBaseNameRole] = "fileBaseName" ; | 
| 333 |     d->roleNames[FileSuffixRole] = "fileSuffix" ; | 
| 334 |     d->roleNames[FileSizeRole] = "fileSize" ; | 
| 335 |     d->roleNames[FileLastModifiedRole] = "fileModified" ; | 
| 336 |     d->roleNames[FileLastReadRole] = "fileAccessed" ; | 
| 337 |     d->roleNames[FileIsDirRole] = "fileIsDir" ; | 
| 338 |     d->roleNames[FileUrlRole] = "fileUrl" ; | 
| 339 |     d->roleNames[FileURLRole] = "fileURL" ; | 
| 340 |     d->init(); | 
| 341 | } | 
| 342 |  | 
| 343 | QQuickFolderListModel::~QQuickFolderListModel() | 
| 344 | { | 
| 345 | } | 
| 346 |  | 
| 347 | QVariant QQuickFolderListModel::data(const QModelIndex &index, int role) const | 
| 348 | { | 
| 349 |     Q_D(const QQuickFolderListModel); | 
| 350 |     QVariant rv; | 
| 351 |  | 
| 352 |     if (index.row() >= d->data.size()) | 
| 353 |         return rv; | 
| 354 |  | 
| 355 |     switch (role) | 
| 356 |     { | 
| 357 |         case FileNameRole: | 
| 358 |             rv = d->data.at(i: index.row()).fileName(); | 
| 359 |             break; | 
| 360 |         case FilePathRole: | 
| 361 |             rv = d->data.at(i: index.row()).filePath(); | 
| 362 |             break; | 
| 363 |         case FileBaseNameRole: | 
| 364 |             rv = d->data.at(i: index.row()).baseName(); | 
| 365 |             break; | 
| 366 |         case FileSuffixRole: | 
| 367 |             rv = d->data.at(i: index.row()).suffix(); | 
| 368 |             break; | 
| 369 |         case FileSizeRole: | 
| 370 |             rv = d->data.at(i: index.row()).size(); | 
| 371 |             break; | 
| 372 |         case FileLastModifiedRole: | 
| 373 |             rv = d->data.at(i: index.row()).lastModified(); | 
| 374 |             break; | 
| 375 |         case FileLastReadRole: | 
| 376 |             rv = d->data.at(i: index.row()).lastRead(); | 
| 377 |             break; | 
| 378 |         case FileIsDirRole: | 
| 379 |             rv = d->data.at(i: index.row()).isDir(); | 
| 380 |             break; | 
| 381 |         case FileUrlRole: | 
| 382 |         case FileURLRole: | 
| 383 |             rv = QUrl::fromLocalFile(localfile: d->data.at(i: index.row()).filePath()); | 
| 384 |             break; | 
| 385 |         default: | 
| 386 |             break; | 
| 387 |     } | 
| 388 |     return rv; | 
| 389 | } | 
| 390 |  | 
| 391 | QHash<int, QByteArray> QQuickFolderListModel::roleNames() const | 
| 392 | { | 
| 393 |     Q_D(const QQuickFolderListModel); | 
| 394 |     return d->roleNames; | 
| 395 | } | 
| 396 |  | 
| 397 | /*! | 
| 398 |     \qmlproperty int FolderListModel::count | 
| 399 |  | 
| 400 |     Returns the number of items in the current folder that match the | 
| 401 |     filter criteria. | 
| 402 | */ | 
| 403 | int QQuickFolderListModel::rowCount(const QModelIndex &parent) const | 
| 404 | { | 
| 405 |     Q_D(const QQuickFolderListModel); | 
| 406 |     Q_UNUSED(parent); | 
| 407 |     return d->data.size(); | 
| 408 | } | 
| 409 |  | 
| 410 | QModelIndex QQuickFolderListModel::index(int row, int , const QModelIndex &) const | 
| 411 | { | 
| 412 |     return createIndex(arow: row, acolumn: 0); | 
| 413 | } | 
| 414 |  | 
| 415 | /*! | 
| 416 |     \qmlproperty url FolderListModel::folder | 
| 417 |  | 
| 418 |     The \a folder property holds a URL for the folder that the model | 
| 419 |     currently provides. | 
| 420 |  | 
| 421 |     The value must be a \c file: or \c qrc: URL, or a relative URL. | 
| 422 |  | 
| 423 |     The default value is an invalid URL. | 
| 424 | */ | 
| 425 | QUrl QQuickFolderListModel::folder() const | 
| 426 | { | 
| 427 |     Q_D(const QQuickFolderListModel); | 
| 428 |     return d->currentDir; | 
| 429 | } | 
| 430 |  | 
| 431 | void QQuickFolderListModel::setFolder(const QUrl &folder) | 
| 432 | { | 
| 433 |     Q_D(QQuickFolderListModel); | 
| 434 |  | 
| 435 |     if (folder == d->currentDir) | 
| 436 |         return; | 
| 437 |  | 
| 438 |     QString resolvedPath = QQuickFolderListModelPrivate::resolvePath(path: folder); | 
| 439 |  | 
| 440 |     beginResetModel(); | 
| 441 |  | 
| 442 |     //Remove the old path for the file system watcher | 
| 443 |     if (!d->currentDir.isEmpty()) | 
| 444 |         d->fileInfoThread.removePath(path: d->currentDir.path()); | 
| 445 |  | 
| 446 |     d->currentDir = folder; | 
| 447 |  | 
| 448 |     QFileInfo info(resolvedPath); | 
| 449 |     if (!info.exists() || !info.isDir()) { | 
| 450 |         d->data.clear(); | 
| 451 |         endResetModel(); | 
| 452 |         emit rowCountChanged(); | 
| 453 |         if (d->status != QQuickFolderListModel::Null) { | 
| 454 |             d->status = QQuickFolderListModel::Null; | 
| 455 |             emit statusChanged(); | 
| 456 |         } | 
| 457 |         return; | 
| 458 |     } | 
| 459 |  | 
| 460 |     d->fileInfoThread.setPath(resolvedPath); | 
| 461 | } | 
| 462 |  | 
| 463 |  | 
| 464 | /*! | 
| 465 |    \qmlproperty url FolderListModel::rootFolder | 
| 466 |  | 
| 467 |    When this property is set, the given folder will | 
| 468 |    be treated as the root in the file system, so that | 
| 469 |    you can only traverse subfolders within it. | 
| 470 | */ | 
| 471 | QUrl QQuickFolderListModel::rootFolder() const | 
| 472 | { | 
| 473 |     Q_D(const QQuickFolderListModel); | 
| 474 |     return d->rootDir; | 
| 475 | } | 
| 476 |  | 
| 477 | void QQuickFolderListModel::setRootFolder(const QUrl &path) | 
| 478 | { | 
| 479 |     Q_D(QQuickFolderListModel); | 
| 480 |  | 
| 481 |     if (path.isEmpty()) | 
| 482 |         return; | 
| 483 |  | 
| 484 |     QString resolvedPath = QQuickFolderListModelPrivate::resolvePath(path); | 
| 485 |  | 
| 486 |     QFileInfo info(resolvedPath); | 
| 487 |     if (!info.exists() || !info.isDir()) | 
| 488 |         return; | 
| 489 |  | 
| 490 |     d->fileInfoThread.setRootPath(resolvedPath); | 
| 491 |     d->rootDir = path; | 
| 492 | } | 
| 493 |  | 
| 494 |  | 
| 495 | /*! | 
| 496 |     \qmlproperty url FolderListModel::parentFolder | 
| 497 |  | 
| 498 |     Returns the URL of the parent of the current \l folder. | 
| 499 | */ | 
| 500 | QUrl QQuickFolderListModel::parentFolder() const | 
| 501 | { | 
| 502 |     Q_D(const QQuickFolderListModel); | 
| 503 |  | 
| 504 |     QString localFile = d->currentDir.toLocalFile(); | 
| 505 |     if (!localFile.isEmpty()) { | 
| 506 |         QDir dir(localFile); | 
| 507 |         if (dir.isRoot() || !dir.cdUp()) | 
| 508 |             return QUrl(); | 
| 509 |         localFile = dir.path(); | 
| 510 |     } else { | 
| 511 |         const QString path = d->currentDir.path(); | 
| 512 |         const int pos = path.lastIndexOf(c: QLatin1Char('/')); | 
| 513 |         if (pos <= 0) | 
| 514 |             return QUrl(); | 
| 515 |         localFile = path.left(n: pos); | 
| 516 |     } | 
| 517 |     return QUrl::fromLocalFile(localfile: localFile); | 
| 518 | } | 
| 519 |  | 
| 520 | /*! | 
| 521 |     \qmlproperty list<string> FolderListModel::nameFilters | 
| 522 |  | 
| 523 |     The \a nameFilters property contains a list of file name filters. | 
| 524 |     The filters may include the ? and * wildcards. | 
| 525 |  | 
| 526 |     The example below filters on PNG and JPEG files: | 
| 527 |  | 
| 528 |     \qml | 
| 529 |     FolderListModel { | 
| 530 |         nameFilters: [ "*.png", "*.jpg" ] | 
| 531 |     } | 
| 532 |     \endqml | 
| 533 |  | 
| 534 |     \note Directories are not excluded by filters. | 
| 535 | */ | 
| 536 | QStringList QQuickFolderListModel::nameFilters() const | 
| 537 | { | 
| 538 |     Q_D(const QQuickFolderListModel); | 
| 539 |     return d->nameFilters; | 
| 540 | } | 
| 541 |  | 
| 542 | void QQuickFolderListModel::setNameFilters(const QStringList &filters) | 
| 543 | { | 
| 544 |     Q_D(QQuickFolderListModel); | 
| 545 |     if (d->nameFilters == filters) | 
| 546 |         return; | 
| 547 |     d->fileInfoThread.setNameFilters(filters); | 
| 548 |     d->nameFilters = filters; | 
| 549 | } | 
| 550 |  | 
| 551 | void QQuickFolderListModel::classBegin() | 
| 552 | { | 
| 553 | } | 
| 554 |  | 
| 555 | void QQuickFolderListModel::componentComplete() | 
| 556 | { | 
| 557 |     Q_D(QQuickFolderListModel); | 
| 558 |     QString localPath = QQmlFile::urlToLocalFileOrQrc(d->currentDir); | 
| 559 |     if (localPath.isEmpty() || !QDir(localPath).exists()) | 
| 560 |         setFolder(QUrl::fromLocalFile(localfile: QDir::currentPath())); | 
| 561 |     d->fileInfoThread.start(QThread::LowPriority); | 
| 562 | } | 
| 563 |  | 
| 564 | /*! | 
| 565 |     \qmlproperty enumeration FolderListModel::sortField | 
| 566 |  | 
| 567 |     The \a sortField property contains field to use for sorting.  sortField | 
| 568 |     may be one of: | 
| 569 |     \list | 
| 570 |     \li Unsorted - no sorting is applied. | 
| 571 |     \li Name - sort by filename | 
| 572 |     \li Time - sort by time modified | 
| 573 |     \li Size - sort by file size | 
| 574 |     \li Type - sort by file type (extension) | 
| 575 |     \endlist | 
| 576 |  | 
| 577 |     \sa sortReversed | 
| 578 | */ | 
| 579 | QQuickFolderListModel::SortField QQuickFolderListModel::sortField() const | 
| 580 | { | 
| 581 |     Q_D(const QQuickFolderListModel); | 
| 582 |     return d->sortField; | 
| 583 | } | 
| 584 |  | 
| 585 | void QQuickFolderListModel::setSortField(SortField field) | 
| 586 | { | 
| 587 |     Q_D(QQuickFolderListModel); | 
| 588 |     if (field != d->sortField) { | 
| 589 |         d->sortField = field; | 
| 590 |         d->updateSorting(); | 
| 591 |     } | 
| 592 | } | 
| 593 |  | 
| 594 | int QQuickFolderListModel::roleFromString(const QString &roleName) const | 
| 595 | { | 
| 596 |     Q_D(const QQuickFolderListModel); | 
| 597 |     return d->roleNames.key(avalue: roleName.toLatin1(), defaultValue: -1); | 
| 598 | } | 
| 599 |  | 
| 600 | /*! | 
| 601 |     \qmlproperty bool FolderListModel::sortReversed | 
| 602 |  | 
| 603 |     If set to true, reverses the sort order.  The default is false. | 
| 604 |  | 
| 605 |     \sa sortField | 
| 606 | */ | 
| 607 | bool QQuickFolderListModel::sortReversed() const | 
| 608 | { | 
| 609 |     Q_D(const QQuickFolderListModel); | 
| 610 |     return d->sortReversed; | 
| 611 | } | 
| 612 |  | 
| 613 | void QQuickFolderListModel::setSortReversed(bool rev) | 
| 614 | { | 
| 615 |     Q_D(QQuickFolderListModel); | 
| 616 |  | 
| 617 |     if (rev != d->sortReversed) { | 
| 618 |         d->sortReversed = rev; | 
| 619 |         d->updateSorting(); | 
| 620 |     } | 
| 621 | } | 
| 622 |  | 
| 623 | /*! | 
| 624 |     \qmlmethod bool FolderListModel::isFolder(int index) | 
| 625 |  | 
| 626 |     Returns true if the entry \a index is a folder; otherwise | 
| 627 |     returns false. | 
| 628 | */ | 
| 629 | bool QQuickFolderListModel::isFolder(int index) const | 
| 630 | { | 
| 631 |     if (index != -1) { | 
| 632 |         QModelIndex idx = createIndex(arow: index, acolumn: 0); | 
| 633 |         if (idx.isValid()) { | 
| 634 |             QVariant var = data(index: idx, role: FileIsDirRole); | 
| 635 |             if (var.isValid()) | 
| 636 |                 return var.toBool(); | 
| 637 |         } | 
| 638 |     } | 
| 639 |     return false; | 
| 640 | } | 
| 641 |  | 
| 642 | /*! | 
| 643 |     \qmlproperty bool FolderListModel::showFiles | 
| 644 |     \since 5.2 | 
| 645 |  | 
| 646 |     If true, files are included in the model; otherwise only directories | 
| 647 |     are included. | 
| 648 |  | 
| 649 |     By default, this property is true. | 
| 650 |  | 
| 651 |     \sa showDirs | 
| 652 | */ | 
| 653 | bool QQuickFolderListModel::showFiles() const | 
| 654 | { | 
| 655 |     Q_D(const QQuickFolderListModel); | 
| 656 |     return d->showFiles; | 
| 657 | } | 
| 658 |  | 
| 659 | void QQuickFolderListModel::setShowFiles(bool on) | 
| 660 | { | 
| 661 |     Q_D(QQuickFolderListModel); | 
| 662 |  | 
| 663 |     d->fileInfoThread.setShowFiles(on); | 
| 664 |     d->showFiles = on; | 
| 665 | } | 
| 666 |  | 
| 667 | /*! | 
| 668 |     \qmlproperty bool FolderListModel::showDirs | 
| 669 |  | 
| 670 |     If true, directories are included in the model; otherwise only files | 
| 671 |     are included. | 
| 672 |  | 
| 673 |     By default, this property is true. | 
| 674 |  | 
| 675 |     Note that the nameFilters are not applied to directories. | 
| 676 |  | 
| 677 |     \sa showDotAndDotDot | 
| 678 | */ | 
| 679 | bool QQuickFolderListModel::showDirs() const | 
| 680 | { | 
| 681 |     Q_D(const QQuickFolderListModel); | 
| 682 |     return d->showDirs; | 
| 683 | } | 
| 684 |  | 
| 685 | void  QQuickFolderListModel::setShowDirs(bool on) | 
| 686 | { | 
| 687 |     Q_D(QQuickFolderListModel); | 
| 688 |  | 
| 689 |     d->fileInfoThread.setShowDirs(on); | 
| 690 |     d->showDirs = on; | 
| 691 | } | 
| 692 |  | 
| 693 | /*! | 
| 694 |     \qmlproperty bool FolderListModel::showDirsFirst | 
| 695 |  | 
| 696 |     If true, if directories are included in the model they will | 
| 697 |     always be shown first, then the files. | 
| 698 |  | 
| 699 |     By default, this property is false. | 
| 700 |  | 
| 701 | */ | 
| 702 | bool QQuickFolderListModel::showDirsFirst() const | 
| 703 | { | 
| 704 |     Q_D(const QQuickFolderListModel); | 
| 705 |     return d->showDirsFirst; | 
| 706 | } | 
| 707 |  | 
| 708 | void  QQuickFolderListModel::setShowDirsFirst(bool on) | 
| 709 | { | 
| 710 |     Q_D(QQuickFolderListModel); | 
| 711 |  | 
| 712 |     d->fileInfoThread.setShowDirsFirst(on); | 
| 713 |     d->showDirsFirst = on; | 
| 714 | } | 
| 715 |  | 
| 716 |  | 
| 717 | /*! | 
| 718 |     \qmlproperty bool FolderListModel::showDotAndDotDot | 
| 719 |  | 
| 720 |     If true, the "." and ".." directories are included in the model; otherwise | 
| 721 |     they are excluded. | 
| 722 |  | 
| 723 |     By default, this property is false. | 
| 724 |  | 
| 725 |     \sa showDirs | 
| 726 | */ | 
| 727 | bool QQuickFolderListModel::showDotAndDotDot() const | 
| 728 | { | 
| 729 |     Q_D(const QQuickFolderListModel); | 
| 730 |     return d->showDotAndDotDot; | 
| 731 | } | 
| 732 |  | 
| 733 | void  QQuickFolderListModel::setShowDotAndDotDot(bool on) | 
| 734 | { | 
| 735 |     Q_D(QQuickFolderListModel); | 
| 736 |  | 
| 737 |     if (on != d->showDotAndDotDot) { | 
| 738 |         d->fileInfoThread.setShowDotAndDotDot(on); | 
| 739 |         d->showDotAndDotDot = on; | 
| 740 |     } | 
| 741 | } | 
| 742 |  | 
| 743 |  | 
| 744 | /*! | 
| 745 |     \qmlproperty bool FolderListModel::showHidden | 
| 746 |     \since 5.2 | 
| 747 |  | 
| 748 |     If true, hidden files and directories are included in the model; otherwise | 
| 749 |     they are excluded. | 
| 750 |  | 
| 751 |     By default, this property is false. | 
| 752 | */ | 
| 753 | bool QQuickFolderListModel::showHidden() const | 
| 754 | { | 
| 755 |     Q_D(const QQuickFolderListModel); | 
| 756 |     return d->showHidden; | 
| 757 | } | 
| 758 |  | 
| 759 | void QQuickFolderListModel::setShowHidden(bool on) | 
| 760 | { | 
| 761 |     Q_D(QQuickFolderListModel); | 
| 762 |  | 
| 763 |     if (on != d->showHidden) { | 
| 764 |         d->fileInfoThread.setShowHidden(on); | 
| 765 |         d->showHidden = on; | 
| 766 |     } | 
| 767 | } | 
| 768 |  | 
| 769 | /*! | 
| 770 |     \qmlproperty bool FolderListModel::showOnlyReadable | 
| 771 |  | 
| 772 |     If true, only readable files and directories are shown; otherwise all files | 
| 773 |     and directories are shown. | 
| 774 |  | 
| 775 |     By default, this property is false. | 
| 776 |  | 
| 777 |     \sa showDirs | 
| 778 | */ | 
| 779 | bool QQuickFolderListModel::showOnlyReadable() const | 
| 780 | { | 
| 781 |     Q_D(const QQuickFolderListModel); | 
| 782 |     return d->showOnlyReadable; | 
| 783 | } | 
| 784 |  | 
| 785 | void QQuickFolderListModel::setShowOnlyReadable(bool on) | 
| 786 | { | 
| 787 |     Q_D(QQuickFolderListModel); | 
| 788 |  | 
| 789 |     if (on != d->showOnlyReadable) { | 
| 790 |         d->fileInfoThread.setShowOnlyReadable(on); | 
| 791 |         d->showOnlyReadable = on; | 
| 792 |     } | 
| 793 | } | 
| 794 |  | 
| 795 | /*! | 
| 796 |  * \qmlproperty bool FolderListModel::caseSensitive | 
| 797 |  * \since 5.7 | 
| 798 |  * | 
| 799 |  * Use case sensitive pattern matching. | 
| 800 |  * | 
| 801 |  * By default, this property is true. | 
| 802 |  * | 
| 803 |  */ | 
| 804 | bool QQuickFolderListModel::caseSensitive() const | 
| 805 | { | 
| 806 |     Q_D(const QQuickFolderListModel); | 
| 807 |     return d->caseSensitive; | 
| 808 | } | 
| 809 |  | 
| 810 | void QQuickFolderListModel::setCaseSensitive(bool on) | 
| 811 | { | 
| 812 |     Q_D(QQuickFolderListModel); | 
| 813 |  | 
| 814 |     if (on != d->caseSensitive) { | 
| 815 |         d->fileInfoThread.setCaseSensitive(on); | 
| 816 |         d->caseSensitive = on; | 
| 817 |     } | 
| 818 | } | 
| 819 |  | 
| 820 | /*! | 
| 821 |     \qmlproperty enumeration FolderListModel::status | 
| 822 |     \since 5.11 | 
| 823 |  | 
| 824 |     This property holds the status of folder reading.  It can be one of: | 
| 825 |     \list | 
| 826 |     \li FolderListModel.Null - no \a folder has been set | 
| 827 |     \li FolderListModel.Ready - the folder has been loaded | 
| 828 |     \li FolderListModel.Loading - the folder is currently being loaded | 
| 829 |     \endlist | 
| 830 |  | 
| 831 |     Use this status to provide an update or respond to the status change in some way. | 
| 832 |     For example, you could: | 
| 833 |  | 
| 834 |     \list | 
| 835 |     \li Trigger a state change: | 
| 836 |     \qml | 
| 837 |         State { name: 'loaded'; when: folderModel.status == FolderListModel.Ready } | 
| 838 |     \endqml | 
| 839 |  | 
| 840 |     \li Implement an \c onStatusChanged signal handler: | 
| 841 |     \qml | 
| 842 |         FolderListModel { | 
| 843 |             id: folderModel | 
| 844 |             onStatusChanged: if (folderModel.status == FolderListModel.Ready) console.log('Loaded') | 
| 845 |         } | 
| 846 |     \endqml | 
| 847 |  | 
| 848 |     \li Bind to the status value: | 
| 849 |     \qml | 
| 850 |         Text { text: folderModel.status == FolderListModel.Ready ? 'Loaded' : 'Not loaded' } | 
| 851 |     \endqml | 
| 852 |     \endlist | 
| 853 | */ | 
| 854 | QQuickFolderListModel::Status QQuickFolderListModel::status() const | 
| 855 | { | 
| 856 |     Q_D(const QQuickFolderListModel); | 
| 857 |     return d->status; | 
| 858 | } | 
| 859 |  | 
| 860 | /*! | 
| 861 |     \qmlproperty bool FolderListModel::sortCaseSensitive | 
| 862 |     \since 5.12 | 
| 863 |  | 
| 864 |     If set to \c true, the sort is case sensitive. This property is \c true by default. | 
| 865 | */ | 
| 866 |  | 
| 867 | bool QQuickFolderListModel::sortCaseSensitive() const | 
| 868 | { | 
| 869 |     Q_D(const QQuickFolderListModel); | 
| 870 |     return d->sortCaseSensitive; | 
| 871 | } | 
| 872 |  | 
| 873 | void QQuickFolderListModel::setSortCaseSensitive(bool on) | 
| 874 | { | 
| 875 |     Q_D(QQuickFolderListModel); | 
| 876 |  | 
| 877 |     if (on != d->sortCaseSensitive) { | 
| 878 |         d->sortCaseSensitive = on; | 
| 879 |         d->updateSorting(); | 
| 880 |     } | 
| 881 | } | 
| 882 |  | 
| 883 | /*! | 
| 884 |     \qmlmethod var FolderListModel::get(int index, string property) | 
| 885 |  | 
| 886 |     Returns the folder \a property for the given \a index. The following properties | 
| 887 |     are available: | 
| 888 |  | 
| 889 |     \list | 
| 890 |         \li \c fileName | 
| 891 |         \li \c filePath | 
| 892 |         \li \c fileURL (since Qt 5.2; deprecated since Qt 5.15) | 
| 893 |         \li \c fileUrl (since Qt 5.15) | 
| 894 |         \li \c fileBaseName | 
| 895 |         \li \c fileSuffix | 
| 896 |         \li \c fileSize | 
| 897 |         \li \c fileModified | 
| 898 |         \li \c fileAccessed | 
| 899 |         \li \c fileIsDir | 
| 900 |     \endlist | 
| 901 | */ | 
| 902 | QVariant QQuickFolderListModel::get(int idx, const QString &property) const | 
| 903 | { | 
| 904 |     int role = roleFromString(roleName: property); | 
| 905 |     if (role >= 0 && idx >= 0) | 
| 906 |         return data(index: index(row: idx, 0), role); | 
| 907 |     else | 
| 908 |         return QVariant(); | 
| 909 | } | 
| 910 |  | 
| 911 | /*! | 
| 912 |     \qmlmethod int FolderListModel::indexOf(url file) | 
| 913 |     \since 5.6 | 
| 914 |  | 
| 915 |     Returns the index of the given \a file URL if the model contains it, | 
| 916 |     or -1 if not. | 
| 917 | */ | 
| 918 | int QQuickFolderListModel::indexOf(const QUrl &file) const | 
| 919 | { | 
| 920 |     Q_D(const QQuickFolderListModel); | 
| 921 |     FileProperty toFind(QFileInfo(file.toLocalFile())); | 
| 922 |     return d->data.indexOf(t: toFind); | 
| 923 | } | 
| 924 |  | 
| 925 | #include "moc_qquickfolderlistmodel.cpp" | 
| 926 |  | 
| 927 | //![code] | 
| 928 | QT_END_NAMESPACE | 
| 929 |  |