Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / imports / folderlistmodel / qdeclarativefolderlistmodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 //![code]
43 #include "qdeclarativefolderlistmodel.h"
44 #include <QDirModel>
45 #include <QDebug>
46 #include <qdeclarativecontext.h>
47
48 #ifndef QT_NO_DIRMODEL
49
50 QT_BEGIN_NAMESPACE
51
52 class QDeclarativeFolderListModelPrivate
53 {
54 public:
55     QDeclarativeFolderListModelPrivate()
56         : sortField(QDeclarativeFolderListModel::Name), sortReversed(false), count(0), showDirs(true), showDots(false), showOnlyReadable(false), insideRefresh(false) {
57         nameFilters << QLatin1String("*");
58     }
59
60     void updateSorting() {
61         QDir::SortFlags flags = 0;
62         switch(sortField) {
63         case QDeclarativeFolderListModel::Unsorted:
64             flags |= QDir::Unsorted;
65             break;
66         case QDeclarativeFolderListModel::Name:
67             flags |= QDir::Name;
68             break;
69         case QDeclarativeFolderListModel::Time:
70             flags |= QDir::Time;
71             break;
72         case QDeclarativeFolderListModel::Size:
73             flags |= QDir::Size;
74             break;
75         case QDeclarativeFolderListModel::Type:
76             flags |= QDir::Type;
77             break;
78         }
79
80         if (sortReversed)
81             flags |= QDir::Reversed;
82
83         model.setSorting(flags);
84     }
85
86     QDirModel model;
87     QUrl folder;
88     QStringList nameFilters;
89     QModelIndex folderIndex;
90     QDeclarativeFolderListModel::SortField sortField;
91     bool sortReversed;
92     int count;
93     bool showDirs;
94     bool showDots;
95     bool showOnlyReadable;
96     bool insideRefresh;
97 };
98
99 /*!
100     \qmlclass FolderListModel QDeclarativeFolderListModel
101     \ingroup qml-working-with-data
102     \brief The FolderListModel provides a model of the contents of a file system folder.
103
104     FolderListModel provides access to information about the contents of a folder
105     in the local file system, exposing a list of files to views and other data components.
106
107     \note This type is made available by importing the \c Qt.labs.folderlistmodel module.
108     \e{Elements in the Qt.labs module are not guaranteed to remain compatible
109     in future versions.}
110
111     \bold{import Qt.labs.folderlistmodel 1.0}
112
113     The \l folder property specifies the folder to access. Information about the
114     files and directories in the folder is supplied via the model's interface.
115     Components access names and paths via the following roles:
116
117     \list
118     \o fileName
119     \o filePath
120     \endlist
121
122     Additionally a file entry can be differentiated from a folder entry via the
123     isFolder() method.
124
125     \section1 Filtering
126
127     Various properties can be set to filter the number of files and directories
128     exposed by the model.
129
130     The \l nameFilters property can be set to contain a list of wildcard filters
131     that are applied to names of files and directories, causing only those that
132     match the filters to be exposed.
133
134     Directories can be included or excluded using the \l showDirs property, and
135     navigation directories can also be excluded by setting the \l showDotAndDotDot
136     property to false.
137
138     It is sometimes useful to limit the files and directories exposed to those
139     that the user can access. The \l showOnlyReadable property can be set to
140     enable this feature.
141
142     \section1 Example Usage
143
144     The following example shows a FolderListModel being used to provide a list
145     of QML files in a \l ListView:
146
147     \snippet doc/src/snippets/declarative/folderlistmodel.qml 0
148
149     \section1 Path Separators
150
151     Qt uses "/" as a universal directory separator in the same way that "/" is
152     used as a path separator in URLs. If you always use "/" as a directory
153     separator, Qt will translate your paths to conform to the underlying
154     operating system.
155
156     \sa {QML Data Models}
157 */
158
159 QDeclarativeFolderListModel::QDeclarativeFolderListModel(QObject *parent)
160     : QAbstractListModel(parent)
161 {
162     QHash<int, QByteArray> roles;
163     roles[FileNameRole] = "fileName";
164     roles[FilePathRole] = "filePath";
165     setRoleNames(roles);
166
167     d = new QDeclarativeFolderListModelPrivate;
168     d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot);
169     connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int))
170             , this, SLOT(inserted(const QModelIndex&,int,int)));
171     connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int))
172             , this, SLOT(removed(const QModelIndex&,int,int)));
173     connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))
174             , this, SLOT(handleDataChanged(const QModelIndex&,const QModelIndex&)));
175     connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh()));
176     connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh()));
177 }
178
179 QDeclarativeFolderListModel::~QDeclarativeFolderListModel()
180 {
181     delete d;
182 }
183
184 QVariant QDeclarativeFolderListModel::data(const QModelIndex &index, int role) const
185 {
186     QVariant rv;
187     QModelIndex modelIndex = d->model.index(index.row(), 0, d->folderIndex);
188     if (modelIndex.isValid()) {
189         if (role == FileNameRole)
190             rv = d->model.data(modelIndex, QDirModel::FileNameRole).toString();
191         else if (role == FilePathRole)
192             rv = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString());
193     }
194     return rv;
195 }
196
197 /*!
198     \qmlproperty int FolderListModel::count
199
200     Returns the number of items in the current folder that match the
201     filter criteria.
202 */
203 int QDeclarativeFolderListModel::rowCount(const QModelIndex &parent) const
204 {
205     Q_UNUSED(parent);
206     return d->count;
207 }
208
209 /*!
210     \qmlproperty string FolderListModel::folder
211
212     The \a folder property holds a URL for the folder that the model is
213     currently providing.
214
215     The value is a URL expressed as a string, and must be a \c file: or \c qrc:
216     URL, or a relative URL.
217
218     By default, the value is an invalid URL.
219 */
220 QUrl QDeclarativeFolderListModel::folder() const
221 {
222     return d->folder;
223 }
224
225 void QDeclarativeFolderListModel::setFolder(const QUrl &folder)
226 {
227     if (folder == d->folder)
228         return;
229
230     QModelIndex index = d->model.index(folder.toLocalFile()); // This can modify the filtering rules.
231     if ((index.isValid() && d->model.isDir(index)) || folder.toLocalFile().isEmpty()) {
232         d->folder = folder;
233         QMetaObject::invokeMethod(this, "resetFiltering", Qt::QueuedConnection); // resetFiltering will invoke refresh().
234         emit folderChanged();
235     }
236 }
237
238 void QDeclarativeFolderListModel::resetFiltering()
239 {
240     // ensure that we reset the filtering rules, because the QDirModel::index()
241     // function isn't quite as const as it claims to be.
242     QDir::Filters filt = d->model.filter();
243
244     if (d->showDirs)
245         filt |= (QDir::AllDirs | QDir::Drives);
246     else
247         filt &= ~(QDir::AllDirs | QDir::Drives);
248
249     if (d->showDots)
250         filt &= ~QDir::NoDotAndDotDot;
251     else
252         filt |= QDir::NoDotAndDotDot;
253
254     if (d->showOnlyReadable)
255         filt |= QDir::Readable;
256     else
257         filt &= ~QDir::Readable;
258
259     d->model.setFilter(filt); // this causes a refresh().
260 }
261
262 /*!
263     \qmlproperty url FolderListModel::parentFolder
264
265     Returns the URL of the parent of of the current \l folder.
266 */
267 QUrl QDeclarativeFolderListModel::parentFolder() const
268 {
269     QString localFile = d->folder.toLocalFile();
270     if (!localFile.isEmpty()) {
271         QDir dir(localFile);
272 #if defined(Q_OS_WIN)
273         if (dir.isRoot())
274             dir.setPath("");
275         else
276 #endif
277             dir.cdUp();
278         localFile = dir.path();
279     } else {
280         int pos = d->folder.path().lastIndexOf(QLatin1Char('/'));
281         if (pos == -1)
282             return QUrl();
283         localFile = d->folder.path().left(pos);
284     }
285     return QUrl::fromLocalFile(localFile);
286 }
287
288 /*!
289     \qmlproperty list<string> FolderListModel::nameFilters
290
291     The \a nameFilters property contains a list of file name filters.
292     The filters may include the ? and * wildcards.
293
294     The example below filters on PNG and JPEG files:
295
296     \qml
297     FolderListModel {
298         nameFilters: [ "*.png", "*.jpg" ]
299     }
300     \endqml
301
302     \note Directories are not excluded by filters.
303 */
304 QStringList QDeclarativeFolderListModel::nameFilters() const
305 {
306     return d->nameFilters;
307 }
308
309 void QDeclarativeFolderListModel::setNameFilters(const QStringList &filters)
310 {
311     d->nameFilters = filters;
312     d->model.setNameFilters(d->nameFilters);
313 }
314
315 void QDeclarativeFolderListModel::classBegin()
316 {
317 }
318
319 void QDeclarativeFolderListModel::componentComplete()
320 {
321     if (!d->folder.isValid() || d->folder.toLocalFile().isEmpty() || !QDir().exists(d->folder.toLocalFile()))
322         setFolder(QUrl(QLatin1String("file://")+QDir::currentPath()));
323
324     if (!d->folderIndex.isValid())
325         QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection);
326 }
327
328 /*!
329     \qmlproperty enumeration FolderListModel::sortField
330
331     The \a sortField property contains field to use for sorting.  sortField
332     may be one of:
333     \list
334     \o Unsorted - no sorting is applied.  The order is system default.
335     \o Name - sort by filename
336     \o Time - sort by time modified
337     \o Size - sort by file size
338     \o Type - sort by file type (extension)
339     \endlist
340
341     \sa sortReversed
342 */
343 QDeclarativeFolderListModel::SortField QDeclarativeFolderListModel::sortField() const
344 {
345     return d->sortField;
346 }
347
348 void QDeclarativeFolderListModel::setSortField(SortField field)
349 {
350     if (field != d->sortField) {
351         d->sortField = field;
352         d->updateSorting();
353     }
354 }
355
356 /*!
357     \qmlproperty bool FolderListModel::sortReversed
358
359     If set to true, reverses the sort order.  The default is false.
360
361     \sa sortField
362 */
363 bool QDeclarativeFolderListModel::sortReversed() const
364 {
365     return d->sortReversed;
366 }
367
368 void QDeclarativeFolderListModel::setSortReversed(bool rev)
369 {
370     if (rev != d->sortReversed) {
371         d->sortReversed = rev;
372         d->updateSorting();
373     }
374 }
375
376 /*!
377     \qmlmethod bool FolderListModel::isFolder(int index)
378
379     Returns true if the entry \a index is a folder; otherwise
380     returns false.
381 */
382 bool QDeclarativeFolderListModel::isFolder(int index) const
383 {
384     if (index != -1) {
385         QModelIndex idx = d->model.index(index, 0, d->folderIndex);
386         if (idx.isValid())
387             return d->model.isDir(idx);
388     }
389     return false;
390 }
391
392 void QDeclarativeFolderListModel::refresh()
393 {
394     if (d->insideRefresh)
395         return;
396     d->insideRefresh = true;
397
398     d->folderIndex = QModelIndex();
399     if (d->count) {
400         emit beginRemoveRows(QModelIndex(), 0, d->count-1);
401         d->count = 0;
402         emit endRemoveRows();
403     }
404
405     d->folderIndex = d->model.index(d->folder.toLocalFile());
406     int newcount = d->model.rowCount(d->folderIndex);
407     if (newcount) {
408         emit beginInsertRows(QModelIndex(), 0, newcount-1);
409         d->count = newcount;
410         emit endInsertRows();
411     }
412
413     d->insideRefresh = false; // finished refreshing.
414 }
415
416 void QDeclarativeFolderListModel::inserted(const QModelIndex &index, int start, int end)
417 {
418     if (index == d->folderIndex) {
419         emit beginInsertRows(QModelIndex(), start, end);
420         d->count = d->model.rowCount(d->folderIndex);
421         emit endInsertRows();
422     }
423 }
424
425 void QDeclarativeFolderListModel::removed(const QModelIndex &index, int start, int end)
426 {
427     if (index == d->folderIndex) {
428         emit beginRemoveRows(QModelIndex(), start, end);
429         d->count = d->model.rowCount(d->folderIndex);
430         emit endRemoveRows();
431     }
432 }
433
434 void QDeclarativeFolderListModel::handleDataChanged(const QModelIndex &start, const QModelIndex &end)
435 {
436     if (start.parent() == d->folderIndex)
437         emit dataChanged(index(start.row(),0), index(end.row(),0));
438 }
439
440 /*!
441     \qmlproperty bool FolderListModel::showDirs
442
443     If true, directories are included in the model; otherwise only files
444     are included.
445
446     By default, this property is true.
447
448     Note that the nameFilters are not applied to directories.
449
450     \sa showDotAndDotDot
451 */
452 bool QDeclarativeFolderListModel::showDirs() const
453 {
454     return d->model.filter() & QDir::AllDirs;
455 }
456
457 void  QDeclarativeFolderListModel::setShowDirs(bool on)
458 {
459     if (!(d->model.filter() & QDir::AllDirs) == !on)
460         return;
461     if (on) {
462         d->showDirs = true;
463         d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives);
464     } else {
465         d->showDirs = false;
466         d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives));
467     }
468 }
469
470 /*!
471     \qmlproperty bool FolderListModel::showDotAndDotDot
472
473     If true, the "." and ".." directories are included in the model; otherwise
474     they are excluded.
475
476     By default, this property is false.
477
478     \sa showDirs
479 */
480 bool QDeclarativeFolderListModel::showDotAndDotDot() const
481 {
482     return !(d->model.filter() & QDir::NoDotAndDotDot);
483 }
484
485 void  QDeclarativeFolderListModel::setShowDotAndDotDot(bool on)
486 {
487     if (!(d->model.filter() & QDir::NoDotAndDotDot) == on)
488         return;
489     if (on) {
490         d->showDots = true;
491         d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot);
492     } else {
493         d->showDots = false;
494         d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot);
495     }
496 }
497
498 /*!
499     \qmlproperty bool FolderListModel::showOnlyReadable
500
501     If true, only readable files and directories are shown; otherwise all files
502     and directories are shown.
503
504     By default, this property is false.
505
506     \sa showDirs
507 */
508 bool QDeclarativeFolderListModel::showOnlyReadable() const
509 {
510     return d->model.filter() & QDir::Readable;
511 }
512
513 void QDeclarativeFolderListModel::setShowOnlyReadable(bool on)
514 {
515     if (!(d->model.filter() & QDir::Readable) == !on)
516         return;
517     if (on) {
518         d->showOnlyReadable = true;
519         d->model.setFilter(d->model.filter() | QDir::Readable);
520     } else {
521         d->showOnlyReadable = false;
522         d->model.setFilter(d->model.filter() & ~QDir::Readable);
523     }
524 }
525
526 //![code]
527 QT_END_NAMESPACE
528
529 #endif // QT_NO_DIRMODEL