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