Merge lp:~carlos-mazieri/ubuntu-filemanager-app/model into lp:ubuntu-filemanager-app

Proposed by Carlos Jose Mazieri
Status: Rejected
Rejected by: Michael Hall
Proposed branch: lp:~carlos-mazieri/ubuntu-filemanager-app/model
Merge into: lp:ubuntu-filemanager-app
Diff against target: 48088 lines (+47602/-0)
94 files modified
folderlistmodel/README (+6/-0)
folderlistmodel/dirmodel.cpp (+1005/-0)
folderlistmodel/dirmodel.h (+328/-0)
folderlistmodel/filesystemaction.cpp (+1389/-0)
folderlistmodel/filesystemaction.h (+212/-0)
folderlistmodel/folderlistmodel.pri (+26/-0)
folderlistmodel/folderlistmodel.pro (+39/-0)
folderlistmodel/iorequest.cpp (+36/-0)
folderlistmodel/iorequest.h (+51/-0)
folderlistmodel/iorequestworker.cpp (+94/-0)
folderlistmodel/iorequestworker.h (+61/-0)
folderlistmodel/ioworkerthread.cpp (+64/-0)
folderlistmodel/ioworkerthread.h (+52/-0)
folderlistmodel/plugin.cpp (+53/-0)
folderlistmodel/plugin.h (+84/-0)
folderlistmodel/qmldir (+1/-0)
nemo-folderlistmodel/dirmodel.cpp (+385/-0)
nemo-folderlistmodel/dirmodel.h (+124/-0)
nemo-folderlistmodel/folderlistmodel.pro (+16/-0)
nemo-folderlistmodel/iorequest.cpp (+36/-0)
nemo-folderlistmodel/iorequest.h (+51/-0)
nemo-folderlistmodel/iorequestworker.cpp (+92/-0)
nemo-folderlistmodel/iorequestworker.h (+61/-0)
nemo-folderlistmodel/ioworkerthread.cpp (+64/-0)
nemo-folderlistmodel/ioworkerthread.h (+52/-0)
nemo-folderlistmodel/plugin.cpp (+53/-0)
nemo-folderlistmodel/plugin.h (+82/-0)
nemo-folderlistmodel/qmldir (+1/-0)
test_folderlistmodel/regression/media_asx.h (+21/-0)
test_folderlistmodel/regression/media_xspf.h (+135/-0)
test_folderlistmodel/regression/mimetypes/LICENSE.LGPL (+504/-0)
test_folderlistmodel/regression/mimetypes/TODO.txt (+8/-0)
test_folderlistmodel/regression/mimetypes/include/QtMimeTypes/QMimeDatabase (+1/-0)
test_folderlistmodel/regression/mimetypes/include/QtMimeTypes/QMimeMagicRule (+1/-0)
test_folderlistmodel/regression/mimetypes/include/QtMimeTypes/QMimeType (+1/-0)
test_folderlistmodel/regression/mimetypes/include/QtMimeTypes/QtMimeTypes.pro (+17/-0)
test_folderlistmodel/regression/mimetypes/include/QtMimeTypes/qmimedatabase.h (+1/-0)
test_folderlistmodel/regression/mimetypes/include/QtMimeTypes/qmimemagicrule.h (+1/-0)
test_folderlistmodel/regression/mimetypes/include/QtMimeTypes/qmimetype.h (+1/-0)
test_folderlistmodel/regression/mimetypes/include/include.pro (+4/-0)
test_folderlistmodel/regression/mimetypes/mimetypes-nolibs.pri (+11/-0)
test_folderlistmodel/regression/mimetypes/mimetypes-src.pri (+26/-0)
test_folderlistmodel/regression/mimetypes/qtmimetypes.pro (+23/-0)
test_folderlistmodel/regression/mimetypes/src/imports/imports.pro (+3/-0)
test_folderlistmodel/regression/mimetypes/src/imports/mimetypes/mimetypes.cpp (+69/-0)
test_folderlistmodel/regression/mimetypes/src/imports/mimetypes/mimetypes.pro (+43/-0)
test_folderlistmodel/regression/mimetypes/src/imports/mimetypes/plugins.qmltypes (+59/-0)
test_folderlistmodel/regression/mimetypes/src/imports/mimetypes/qdeclarativemimedatabase.cpp (+320/-0)
test_folderlistmodel/regression/mimetypes/src/imports/mimetypes/qdeclarativemimedatabase_p.h (+98/-0)
test_folderlistmodel/regression/mimetypes/src/imports/mimetypes/qdeclarativemimetype.cpp (+683/-0)
test_folderlistmodel/regression/mimetypes/src/imports/mimetypes/qdeclarativemimetype_p.h (+155/-0)
test_folderlistmodel/regression/mimetypes/src/imports/mimetypes/qmldir (+1/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/inqt5/qstandardpaths.cpp (+275/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/inqt5/qstandardpaths.h (+106/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/inqt5/qstandardpaths_mac.cpp (+173/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/inqt5/qstandardpaths_unix.cpp (+258/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/inqt5/qstandardpaths_win.cpp (+218/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/mime/packages/freedesktop.org.xml (+31966/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/mimetypes.pro (+72/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/mimetypes.qrc (+5/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmime_global.h (+32/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimedatabase.cpp (+615/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimedatabase.h (+114/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimedatabase_p.h (+89/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimeglobpattern.cpp (+240/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimeglobpattern_p.h (+146/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimemagicrule.cpp (+387/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimemagicrule_p.h (+89/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimemagicrulematcher.cpp (+107/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimemagicrulematcher_p.h (+78/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimeprovider.cpp (+835/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimeprovider_p.h (+165/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimetype.cpp (+482/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimetype.h (+120/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimetype_p.h (+114/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimetypeparser.cpp (+341/-0)
test_folderlistmodel/regression/mimetypes/src/mimetypes/qmimetypeparser_p.h (+118/-0)
test_folderlistmodel/regression/mimetypes/src/src.pro (+3/-0)
test_folderlistmodel/regression/regression_folderlilstmodel.pro (+30/-0)
test_folderlistmodel/regression/sound_7200_amr.h (+87/-0)
test_folderlistmodel/regression/sound_mp3.h (+700/-0)
test_folderlistmodel/regression/tempfiles.cpp (+177/-0)
test_folderlistmodel/regression/tempfiles.h (+90/-0)
test_folderlistmodel/regression/testonly_pdf.h (+641/-0)
test_folderlistmodel/regression/tst_folderlistmodel.cpp (+1304/-0)
test_folderlistmodel/results/DesktopQt4.74.txt (+47/-0)
test_folderlistmodel/results/DesktopQt5.0.txt (+53/-0)
test_folderlistmodel/results/NemoEmulatorQ8.43.txt (+36/-0)
test_folderlistmodel/results/openFiles.Readme.txt (+7/-0)
test_folderlistmodel/simpleUI/main.cpp (+32/-0)
test_folderlistmodel/simpleUI/simplelist.cpp (+256/-0)
test_folderlistmodel/simpleUI/simplelist.h (+72/-0)
test_folderlistmodel/simpleUI/simplelist.ui (+183/-0)
test_folderlistmodel/simpleUI/simpleui.pro (+35/-0)
To merge this branch: bzr merge lp:~carlos-mazieri/ubuntu-filemanager-app/model
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Needs Fixing
Arto Jalkanen Disapprove
Review via email: mp+166863@code.launchpad.net

Commit message

Description of the change

It contains the fix for bug #1180956.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :

FAILED: Continuous integration, rev:20
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+merge/166863/+edit-commit-message

http://91.189.93.125:8080/job/ubuntu-filemanager-app-ci/5/
Executed test runs:
    SUCCESS: http://91.189.93.125:8080/job/ubuntu-filemanager-app-quantal-amd64-ci/2
    SUCCESS: http://91.189.93.125:8080/job/ubuntu-filemanager-app-raring-amd64-ci/5

Click here to trigger a rebuild:
http://91.189.93.125:8080/job/ubuntu-filemanager-app-ci/5/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Arto Jalkanen (ajalkane) wrote :

Hi,

you've committed to the wrong branch. This is for the QML application. The correct branch for plugin changes are in lp:ubuntu-filemanager-app/plugin

review: Disapprove
21. By Carlos Jose Mazieri

fixed refresh view signals when a pate operation is made and items already exist.
In this case as the existent item is removed both signals: "removed" and "added" items are sent.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :

FAILED: Continuous integration, rev:21
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+merge/166863/+edit-commit-message

http://91.189.93.125:8080/job/ubuntu-filemanager-app-ci/6/
Executed test runs:
    SUCCESS: http://91.189.93.125:8080/job/ubuntu-filemanager-app-quantal-amd64-ci/3
    SUCCESS: http://91.189.93.125:8080/job/ubuntu-filemanager-app-raring-amd64-ci/6

Click here to trigger a rebuild:
http://91.189.93.125:8080/job/ubuntu-filemanager-app-ci/6/rebuild

review: Needs Fixing (continuous-integration)

Unmerged revisions

66. By Carlos Jose Mazieri

remade C++ UI

65. By Carlos Jose Mazieri

added moveToTrash, removeFromTrash, restoreFromTrash and emptyTrash facilities.
Test View remade to use selection.

64. By Carlos Jose Mazieri

Preparation for Move/Restore to/from Trash and Undo Actions:
 * Some information from Action data structure were moved into ActionEntry data structure.
 * Actions used to have "targetPath" saying all items (ActionEntry items) were copied/moved into a unique path.
   Now having ActionEntry more indenpendent allows to move/copy items to different paths inside an Action.
   This is required for Restore items from Trash.

63. By Carlos Jose Mazieri

Redesign:
    * Created Location class which represents a URL supported in the File Manager
      - DiskLocation represents any url/path like file:/// or normal /
      - TrashLocation represents any url/path like trash:///
      - There will be a SmbLocation for samba/cifs network sharing
    * Browsing items (IOReuest/IOWorkerThread) moved into the Location
    * External File system watcher handling was moved into DiskLocation class
    * Navigation into child folders and up to parent folder were delegated to the Location
    * Created LocationsFactory class which keeps the supported Locations, it provides a URL
      parser that sets the current Location.
Trash:
    * implemented browsing: missing carry orignal item properties
    * implemented a specific External File system watcher for trash
    * missing Move/Restore to/from Trash (NOT YET IMPLEMENTED)

OBS:
     * due to current File Manager UI typing method both: "file:" and "trash:" are supported.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'folderlistmodel'
2=== added file 'folderlistmodel/README'
3--- folderlistmodel/README 1970-01-01 00:00:00 +0000
4+++ folderlistmodel/README 2013-06-01 17:20:36 +0000
5@@ -0,0 +1,6 @@
6+Building and installing
7+=======================
8+
9+qmake && make
10+sudo make install
11+
12
13=== added file 'folderlistmodel/dirmodel.cpp'
14--- folderlistmodel/dirmodel.cpp 1970-01-01 00:00:00 +0000
15+++ folderlistmodel/dirmodel.cpp 2013-06-01 17:20:36 +0000
16@@ -0,0 +1,1005 @@
17+/*
18+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
19+ *
20+ * You may use this file under the terms of the BSD license as follows:
21+ *
22+ * "Redistribution and use in source and binary forms, with or without
23+ * modification, are permitted provided that the following conditions are
24+ * met:
25+ * * Redistributions of source code must retain the above copyright
26+ * notice, this list of conditions and the following disclaimer.
27+ * * Redistributions in binary form must reproduce the above copyright
28+ * notice, this list of conditions and the following disclaimer in
29+ * the documentation and/or other materials provided with the
30+ * distribution.
31+ * * Neither the name of Nemo Mobile nor the names of its contributors
32+ * may be used to endorse or promote products derived from this
33+ * software without specific prior written permission.
34+ *
35+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46+ */
47+
48+#include <errno.h>
49+#include <string.h>
50+#include "dirmodel.h"
51+#include "ioworkerthread.h"
52+#include "filesystemaction.h"
53+
54+#include <QDirIterator>
55+#include <QDir>
56+#include <QDebug>
57+#include <QDateTime>
58+#include <QFileIconProvider>
59+#include <QUrl>
60+#include <QDesktopServices>
61+
62+#if defined(REGRESSION_TEST_FOLDERLISTMODEL) || QT_VERSION >= 0x050000
63+# include <QMimeType>
64+# include <QMimeDatabase>
65+#endif
66+
67+#define IS_VALID_ROW(row) (row >=0 && row < mDirectoryContents.count())
68+#define WARN_ROW_OUT_OF_RANGE(row) qWarning() << Q_FUNC_INFO << "row" << row << "Out of bounds access"
69+
70+
71+Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread)
72+
73+namespace {
74+ QHash<QByteArray, int> roleMapping;
75+}
76+
77+
78+
79+
80+static bool fileCompareExists(const QFileInfo &a, const QFileInfo &b)
81+{
82+ if (a.isDir() && !b.isDir())
83+ return true;
84+
85+ if (b.isDir() && !a.isDir())
86+ return false;
87+
88+ bool ret = QString::localeAwareCompare(a.absoluteFilePath(), b.absoluteFilePath()) < 0;
89+#if DEBUG_MESSAGES
90+ qDebug() << Q_FUNC_INFO << ret << a.absoluteFilePath() << b.absoluteFilePath();
91+#endif
92+ return ret;
93+}
94+
95+static bool fileCompareAscending(const QFileInfo &a, const QFileInfo &b)
96+{
97+ if (a.isDir() && !b.isDir())
98+ return true;
99+
100+ if (b.isDir() && !a.isDir())
101+ return false;
102+
103+ return QString::localeAwareCompare(a.fileName(), b.fileName()) < 0;
104+}
105+
106+
107+static bool fileCompareDescending(const QFileInfo &a, const QFileInfo &b)
108+{
109+ if (a.isDir() && !b.isDir())
110+ return true;
111+
112+ if (b.isDir() && !a.isDir())
113+ return false;
114+
115+ return QString::localeAwareCompare(a.fileName(), b.fileName()) > 0;
116+}
117+
118+static bool dateCompareDescending(const QFileInfo &a, const QFileInfo &b)
119+{
120+ if (a.isDir() && !b.isDir())
121+ return true;
122+
123+ if (b.isDir() && !a.isDir())
124+ return false;
125+
126+ return a.lastModified() > b.lastModified();
127+}
128+
129+static bool dateCompareAscending(const QFileInfo &a, const QFileInfo &b)
130+{
131+ if (a.isDir() && !b.isDir())
132+ return true;
133+
134+ if (b.isDir() && !a.isDir())
135+ return false;
136+
137+ return a.lastModified() < b.lastModified();
138+}
139+
140+/*!
141+ * Sort was originally done in \ref onItemsAdded() and that code is now in \ref addItem(),
142+ * the reason to keep doing sort and do not let QDir does it is that when adding new items
143+ * by \ref mkdir() or \paste() it is not necessary to call refresh() to load the entire directory
144+ * to organize it items again. New items order/position are organized by \ref addItem()
145+ *
146+ */
147+static CompareFunction availableCompareFunctions[2][2] =
148+{
149+ {fileCompareAscending, fileCompareDescending}
150+ ,{dateCompareAscending, dateCompareDescending}
151+};
152+
153+
154+
155+
156+class DirListWorker : public IORequest
157+{
158+ Q_OBJECT
159+public:
160+ DirListWorker(const QString &pathName, QDir::Filter filter)
161+ : mPathName(pathName)
162+ , mFilter(filter)
163+ { }
164+
165+ void run()
166+ {
167+#if DEBUG_MESSAGES
168+ qDebug() << Q_FUNC_INFO << "Running on: " << QThread::currentThreadId();
169+#endif
170+
171+ QDir tmpDir = QDir(mPathName, QString(), QDir::NoSort, mFilter);
172+ QDirIterator it(tmpDir);
173+ QVector<QFileInfo> directoryContents;
174+
175+ while (it.hasNext()) {
176+ it.next();
177+
178+ directoryContents.append(it.fileInfo());
179+ if (directoryContents.count() >= 50) {
180+ emit itemsAdded(directoryContents);
181+
182+ // clear() would force a deallocation, micro-optimization
183+ directoryContents.erase(directoryContents.begin(), directoryContents.end());
184+ }
185+ }
186+
187+ // last batch
188+ emit itemsAdded(directoryContents);
189+ emit workerFinished();
190+ }
191+
192+signals:
193+ void itemsAdded(const QVector<QFileInfo> &files);
194+ void workerFinished();
195+
196+private:
197+ QString mPathName;
198+ QDir::Filter mFilter;
199+};
200+
201+DirModel::DirModel(QObject *parent)
202+ : QAbstractListModel(parent)
203+ , mShowDirectories(true)
204+ , mAwaitingResults(false)
205+ , mShowHiddenFiles(false)
206+ , mSortBy(SortByName)
207+ , mSortOrder(SortAscending)
208+ , mCompareFunction(0)
209+ , m_fsAction(new FileSystemAction(this) )
210+{
211+ mNameFilters = QStringList() << "*";
212+
213+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
214+ // There's no setRoleNames in Qt5.
215+ setRoleNames(buildRoleNames());
216+#else
217+ // In Qt5, the roleNames() is virtual and will work just fine.
218+#endif
219+
220+ connect(m_fsAction, SIGNAL(progress(int,int,int)),
221+ this, SIGNAL(progress(int,int,int)));
222+
223+ connect(m_fsAction, SIGNAL(added(QFileInfo)),
224+ this, SLOT(onItemAdded(QFileInfo)));
225+
226+ connect(m_fsAction, SIGNAL(added(QString)),
227+ this, SLOT(onItemAdded(QString)));
228+
229+ connect(m_fsAction, SIGNAL(removed(QFileInfo)),
230+ this, SLOT(onItemRemoved(QFileInfo)));
231+
232+ connect(m_fsAction, SIGNAL(removed(QString)),
233+ this, SLOT(onItemRemoved(QString)));
234+
235+ connect(m_fsAction, SIGNAL(error(QString,QString)),
236+ this, SIGNAL(error(QString,QString)));
237+
238+ connect(this, SIGNAL(pathChanged(QString)),
239+ m_fsAction, SLOT(pathChanged(QString)));
240+
241+ connect(m_fsAction, SIGNAL(clipboardChanged()),
242+ this, SIGNAL(clipboardChanged()));
243+
244+ setCompareAndReorder();
245+}
246+
247+DirModel::~DirModel()
248+{
249+}
250+
251+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
252+// roleNames has changed between Qt4 and Qt5. In Qt5 it is a virtual
253+ // function and setRoleNames should not be used.
254+QHash<int, QByteArray> DirModel::roleNames() const
255+{
256+ static QHash<int, QByteArray> roles;
257+ if (roles.isEmpty()) {
258+ roles = buildRoleNames();
259+ }
260+
261+ return roles;
262+}
263+#endif
264+
265+QHash<int, QByteArray> DirModel::buildRoleNames() const
266+{
267+ QHash<int, QByteArray> roles;
268+ roles.insert(FileNameRole, QByteArray("fileName"));
269+ roles.insert(CreationDateRole, QByteArray("creationDate"));
270+ roles.insert(ModifiedDateRole, QByteArray("modifiedDate"));
271+ roles.insert(FileSizeRole, QByteArray("fileSize"));
272+ roles.insert(IconSourceRole, QByteArray("iconSource"));
273+ roles.insert(FilePathRole, QByteArray("filePath"));
274+ roles.insert(IsDirRole, QByteArray("isDir"));
275+ roles.insert(IsFileRole, QByteArray("isFile"));
276+ roles.insert(IsReadableRole, QByteArray("isReadable"));
277+ roles.insert(IsWritableRole, QByteArray("isWritable"));
278+ roles.insert(IsExecutableRole, QByteArray("isExecutable"));
279+
280+ // populate reverse mapping
281+ if (roleMapping.isEmpty()) {
282+ QHash<int, QByteArray>::ConstIterator it = roles.constBegin();
283+ for (;it != roles.constEnd(); ++it)
284+ roleMapping.insert(it.value(), it.key());
285+
286+ // make sure we cover all roles
287+ // Q_ASSERT(roles.count() == IsFileRole - FileNameRole);
288+ }
289+
290+ return roles;
291+}
292+
293+QVariant DirModel::data(int row, const QByteArray &stringRole) const
294+{
295+ QHash<QByteArray, int>::ConstIterator it = roleMapping.constFind(stringRole);
296+
297+ if (it == roleMapping.constEnd())
298+ return QVariant();
299+
300+ return data(index(row, 0), *it);
301+}
302+
303+QVariant DirModel::data(const QModelIndex &index, int role) const
304+{
305+#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
306+ if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::DecorationRole) )
307+ {
308+ return QVariant();
309+ }
310+ if (role == Qt::DecorationRole)
311+ {
312+ if (index.column() == 0)
313+ {
314+ QMimeDatabase database;
315+ QIcon icon;
316+ QMimeType mime = database.mimeTypeForFile(mDirectoryContents.at(index.row()));
317+ if (mime.isValid()) {
318+ icon = QIcon::fromTheme(mime.iconName());
319+ }
320+ if (icon.isNull()) {
321+ icon = QFileIconProvider().icon(mDirectoryContents.at(index.row()));
322+ }
323+ return icon;
324+ }
325+ return QVariant();
326+ }
327+ role = FileNameRole + index.column();
328+#else
329+ if (role < FileNameRole || role > IsExecutableRole) {
330+ qWarning() << Q_FUNC_INFO << "Got an out of range role: " << role;
331+ return QVariant();
332+ }
333+
334+ if (index.row() < 0 || index.row() >= mDirectoryContents.count()) {
335+ qWarning() << "Attempted to access out of range row: " << index.row();
336+ return QVariant();
337+ }
338+
339+ if (index.column() != 0)
340+ return QVariant();
341+#endif
342+
343+ const QFileInfo &fi = mDirectoryContents.at(index.row());
344+
345+ switch (role) {
346+ case FileNameRole:
347+ return fi.fileName();
348+ case CreationDateRole:
349+ return fi.created();
350+ case ModifiedDateRole:
351+ return fi.lastModified();
352+ case FileSizeRole: {
353+ if (fi.isDir())
354+ {
355+ return dirItems(fi);
356+ }
357+ return fileSize(fi.size());
358+ }
359+ case IconSourceRole: {
360+ const QString &fileName = fi.fileName();
361+
362+ if (fi.isDir())
363+ return QLatin1String("image://theme/icon-m-common-directory");
364+
365+ if (fileName.endsWith(QLatin1String(".jpg"), Qt::CaseInsensitive) ||
366+ fileName.endsWith(QLatin1String(".png"), Qt::CaseInsensitive)) {
367+ return QLatin1String("image://nemoThumbnail/") + fi.filePath();
368+ }
369+
370+ return "image://theme/icon-m-content-document";
371+ }
372+ case FilePathRole:
373+ return fi.filePath();
374+ case IsDirRole:
375+ return fi.isDir();
376+ case IsFileRole:
377+ return !fi.isDir();
378+ case IsReadableRole:
379+ return fi.isReadable();
380+ case IsWritableRole:
381+ return fi.isWritable();
382+ case IsExecutableRole:
383+ return fi.isExecutable();
384+ default:
385+#if !defined(REGRESSION_TEST_FOLDERLISTMODEL)
386+ // this should not happen, ever
387+ Q_ASSERT(false);
388+ qWarning() << Q_FUNC_INFO << "Got an unknown role: " << role;
389+#endif
390+ return QVariant();
391+ }
392+}
393+
394+void DirModel::setPath(const QString &pathName)
395+{
396+ if (pathName.isEmpty())
397+ return;
398+
399+ if (mAwaitingResults) {
400+ // TODO: handle the case where pathName != our current path, cancel old
401+ // request, start a new one
402+ qDebug() << Q_FUNC_INFO << "Ignoring path change request, request already running";
403+ return;
404+ }
405+
406+ mAwaitingResults = true;
407+ emit awaitingResultsChanged();
408+#if DEBUG_MESSAGES
409+ qDebug() << Q_FUNC_INFO << "Changing to " << pathName << " on " << QThread::currentThreadId();
410+#endif
411+ beginResetModel();
412+ mDirectoryContents.clear();
413+ endResetModel();
414+
415+ QDir::Filter dirFilter = currentDirFilter();
416+ // TODO: we need to set a spinner active before we start getting results from DirListWorker
417+ DirListWorker *dlw = new DirListWorker(pathName, dirFilter);
418+ connect(dlw, SIGNAL(itemsAdded(QVector<QFileInfo>)), SLOT(onItemsAdded(QVector<QFileInfo>)));
419+ connect(dlw, SIGNAL(workerFinished()), SLOT(onResultsFetched()));
420+ ioWorkerThread()->addRequest(dlw);
421+
422+ mCurrentDir = pathName;
423+ emit pathChanged(pathName);
424+}
425+
426+
427+void DirModel::onResultsFetched() {
428+ if (mAwaitingResults) {
429+#if DEBUG_MESSAGES
430+ qDebug() << Q_FUNC_INFO << "No longer awaiting results";
431+#endif
432+ mAwaitingResults = false;
433+ emit awaitingResultsChanged();
434+ }
435+}
436+
437+void DirModel::onItemsAdded(const QVector<QFileInfo> &newFiles)
438+{
439+#if DEBUG_MESSAGES
440+ qDebug() << Q_FUNC_INFO << "Got new files: " << newFiles.count();
441+#endif
442+
443+ foreach (const QFileInfo &fi, newFiles) {
444+
445+ bool doAdd = true;
446+ foreach (const QString &nameFilter, mNameFilters) {
447+ // TODO: using QRegExp for wildcard matching is slow
448+ QRegExp re(nameFilter, Qt::CaseInsensitive, QRegExp::Wildcard);
449+ if (!re.exactMatch(fi.fileName())) {
450+ doAdd = false;
451+ break;
452+ }
453+ }
454+
455+ if (!doAdd)
456+ continue;
457+
458+ addItem(fi);
459+ }
460+}
461+
462+void DirModel::rm(const QStringList &paths)
463+{
464+ m_fsAction->remove(paths);
465+}
466+
467+bool DirModel::rename(int row, const QString &newName)
468+{
469+#if DEBUG_MESSAGES
470+ qDebug() << Q_FUNC_INFO << "Renaming " << row << " to " << newName;
471+#endif
472+
473+ if (!IS_VALID_ROW(row)) {
474+ WARN_ROW_OUT_OF_RANGE(row);
475+ return false;
476+ }
477+
478+ const QFileInfo &fi = mDirectoryContents.at(row);
479+ QString newFullFilename(fi.absolutePath() + QDir::separator() + newName);
480+
481+ //QFile::rename() works for File and Dir
482+ QFile f(fi.absoluteFilePath());
483+ bool retval = f.rename(newFullFilename);
484+ if (!retval)
485+ {
486+ qDebug() << Q_FUNC_INFO << "Rename returned error code: " << f.error() << f.errorString();
487+ emit(QObject::tr("Rename error"), f.errorString());
488+ }
489+ else
490+ {
491+ mDirectoryContents[row] = QFileInfo(newFullFilename);
492+ QModelIndex idx = createIndex(row,0);
493+ emit dataChanged(idx, idx);
494+ }
495+ return retval;
496+}
497+
498+void DirModel::mkdir(const QString &newDir)
499+{
500+ QDir dir(mCurrentDir);
501+ bool retval = dir.mkdir(newDir);
502+ if (!retval) {
503+ const char *errorStr = strerror(errno);
504+ qDebug() << Q_FUNC_INFO << "Error creating new directory: " << errno << " (" << errorStr << ")";
505+ emit error(QObject::tr("Error creating new folder"), errorStr);
506+ } else {
507+ onItemAdded(dir.filePath(newDir));
508+ }
509+}
510+
511+bool DirModel::showDirectories() const
512+{
513+ return mShowDirectories;
514+}
515+
516+void DirModel::setShowDirectories(bool showDirectories)
517+{
518+ mShowDirectories = showDirectories;
519+ refresh();
520+ emit showDirectoriesChanged();
521+}
522+
523+QStringList DirModel::nameFilters() const
524+{
525+ return mNameFilters;
526+}
527+
528+void DirModel::setNameFilters(const QStringList &nameFilters)
529+{
530+ mNameFilters = nameFilters;
531+ refresh();
532+ emit nameFiltersChanged();
533+}
534+
535+bool DirModel::awaitingResults() const
536+{
537+ return mAwaitingResults;
538+}
539+
540+
541+QString DirModel::parentPath() const
542+{
543+ QDir dir(mCurrentDir);
544+ if (dir.isRoot()) {
545+ qDebug() << Q_FUNC_INFO << "already at root";
546+ return mCurrentDir;
547+ }
548+
549+ bool success = dir.cdUp();
550+ if (!success) {
551+ qWarning() << Q_FUNC_INFO << "Failed to to go to parent of " << mCurrentDir;
552+ return mCurrentDir;
553+ }
554+ qDebug() << Q_FUNC_INFO << "returning" << dir.absolutePath();
555+ return dir.absolutePath();
556+}
557+
558+QString DirModel::homePath() const
559+{
560+ return QDir::homePath();
561+}
562+
563+#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
564+ QVariant DirModel::headerData(int section, Qt::Orientation orientation, int role) const
565+ {
566+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
567+ {
568+ QVariant ret;
569+ QHash<int, QByteArray> roles = this->roleNames();
570+ section += FileNameRole;
571+ if (roles.contains(section))
572+ {
573+ QString header= QString(roles.value(section));
574+ ret = header;
575+ }
576+ return ret;
577+ }
578+ return QAbstractItemModel::headerData(section, orientation, role);
579+ }
580+#endif
581+
582+
583+void DirModel::goHome()
584+{
585+ setPath(QDir::homePath());
586+}
587+
588+
589+bool DirModel::cdUp()
590+{
591+ int ret = false;
592+ if (!mCurrentDir.isEmpty()) // we are in any dir
593+ {
594+ QDir current(mCurrentDir);
595+ if (current.cdUp())
596+ {
597+ setPath(current.absolutePath());
598+ ret = true;
599+ }
600+ }
601+ return ret;
602+}
603+
604+
605+void DirModel::removeIndex(int row)
606+{
607+ if (IS_VALID_ROW(row))
608+ {
609+ const QFileInfo &fi = mDirectoryContents.at(row);
610+ QStringList list(fi.absoluteFilePath());
611+ this->rm(list);
612+ }
613+ else
614+ {
615+ WARN_ROW_OUT_OF_RANGE(row);
616+ }
617+}
618+
619+void DirModel::removePaths(const QStringList& items)
620+{
621+ this->rm(items);
622+}
623+
624+void DirModel::copyIndex(int row)
625+{
626+ if (IS_VALID_ROW(row))
627+ {
628+ const QFileInfo &fi = mDirectoryContents.at(row);
629+ QStringList list(fi.absoluteFilePath());
630+ this->copyPaths(list);
631+ }
632+ else
633+ {
634+ WARN_ROW_OUT_OF_RANGE(row);
635+ }
636+}
637+
638+void DirModel::copyPaths(const QStringList &items)
639+{
640+ m_fsAction->copy(items);
641+}
642+
643+
644+void DirModel::cutIndex(int row)
645+{
646+ if (IS_VALID_ROW(row))
647+ {
648+ const QFileInfo &fi = mDirectoryContents.at(row);
649+ QStringList list(fi.absoluteFilePath());
650+ m_fsAction->cut(list);
651+ }
652+ else
653+ {
654+ WARN_ROW_OUT_OF_RANGE(row);
655+ }
656+}
657+
658+
659+void DirModel::cutPaths(const QStringList &items)
660+{
661+ m_fsAction->cut(items);
662+}
663+
664+
665+void DirModel::paste()
666+{
667+ m_fsAction->paste();
668+}
669+
670+
671+bool DirModel::cdIntoIndex(int row)
672+{
673+ bool ret = false;
674+ if (IS_VALID_ROW(row))
675+ {
676+ ret = cdInto(mDirectoryContents.at(row));
677+ }
678+ else
679+ {
680+ WARN_ROW_OUT_OF_RANGE(row);
681+ }
682+ return ret;
683+}
684+
685+
686+bool DirModel::cdIntoPath(const QString &filename)
687+{
688+ QFileInfo fi(filename);
689+ if (fi.isRelative())
690+ {
691+ fi.setFile(mCurrentDir, filename);
692+ }
693+ return cdInto(fi);
694+}
695+
696+
697+bool DirModel::cdInto(const QFileInfo &fi)
698+{
699+ bool ret = false;
700+ if (fi.exists() && fi.isDir() && fi.isReadable())
701+ {
702+ QDir childDir(mCurrentDir);
703+ if ( childDir.cd(fi.fileName()) )
704+ {
705+ setPath(childDir.absolutePath());
706+ ret = true;
707+ }
708+ }
709+ return ret;
710+}
711+
712+/*!
713+ * \brief DirModel::onItemRemoved()
714+ * \param pathname full pathname of removed file
715+ */
716+void DirModel::onItemRemoved(const QString &pathname)
717+{
718+ QFileInfo info(pathname);
719+ onItemRemoved(info);
720+}
721+
722+
723+void DirModel::onItemRemoved(const QFileInfo &fi)
724+{
725+ int row = rowOfItem(fi);
726+ if (row >= 0)
727+ {
728+ beginRemoveRows(QModelIndex(), row, row);
729+ mDirectoryContents.remove(row,1);
730+ endRemoveRows();
731+ }
732+}
733+
734+/*!
735+ * \brief DirModel::onItemAdded()
736+ * \param pathname full pathname of the added file
737+ */
738+void DirModel::onItemAdded(const QString &pathname)
739+{
740+ QFileInfo info(pathname);
741+ onItemAdded(info);
742+}
743+
744+
745+void DirModel::onItemAdded(const QFileInfo &fi)
746+{
747+ int newRow = addItem(fi);
748+ emit insertedRow(newRow);
749+}
750+
751+/*!
752+ * \brief DirModel::addItem() adds an item into the model
753+ * This code was moved from onItemsAdded(const QVector<QFileInfo> &newFiles),
754+ * the reason is: this code now is used for \ref mkdir() and for \ref paste() operations
755+ * that inserts new items
756+ * \param fi
757+ * \return the index where it was inserted, it can be used in the view
758+ * \sa insertedRow()
759+ */
760+int DirModel::addItem(const QFileInfo &fi)
761+{
762+ QVector<QFileInfo>::Iterator it = qLowerBound(mDirectoryContents.begin(),
763+ mDirectoryContents.end(),
764+ fi,
765+ mCompareFunction);
766+ int idx = mDirectoryContents.count();
767+
768+ if (it == mDirectoryContents.end()) {
769+ beginInsertRows(QModelIndex(), mDirectoryContents.count(), mDirectoryContents.count());
770+ mDirectoryContents.append(fi);
771+ endInsertRows();
772+ } else {
773+ idx = it - mDirectoryContents.begin();
774+ beginInsertRows(QModelIndex(), idx, idx);
775+ mDirectoryContents.insert(it, fi);
776+ endInsertRows();
777+ }
778+ return idx;
779+}
780+
781+
782+
783+void DirModel::cancelAction()
784+{
785+ m_fsAction->cancel();
786+}
787+
788+
789+QString DirModel::fileSize(qint64 size) const
790+{
791+ struct UnitSizes
792+ {
793+ qint64 bytes;
794+ const char *name;
795+ };
796+
797+ static UnitSizes m_unitBytes[5] =
798+ {
799+ { 1, "Bytes" }
800+ ,{1024, "KB"}
801+ // got it from http://wiki.answers.com/Q/How_many_bytes_are_in_a_megabyte
802+ ,{1000 * 1000, "MB"}
803+ ,{1000 * m_unitBytes[2].bytes, "GB"}
804+ ,{1000 * m_unitBytes[3].bytes, "TB"}
805+ };
806+
807+ QString ret;
808+ int unit = sizeof(m_unitBytes)/sizeof(m_unitBytes[0]);
809+ while( unit-- > 1 && size < m_unitBytes[unit].bytes );
810+ if (unit > 0 )
811+ {
812+ ret.sprintf("%0.1f %s", (float)size/m_unitBytes[unit].bytes,
813+ m_unitBytes[unit].name);
814+ }
815+ else
816+ {
817+ ret.sprintf("%ld %s", (long int)size, m_unitBytes[0].name);
818+ }
819+ return ret;
820+}
821+
822+
823+
824+bool DirModel::getShowHiddenFiles() const
825+{
826+ return mShowHiddenFiles;
827+}
828+
829+
830+void DirModel::setShowHiddenFiles(bool show)
831+{
832+ if (show != mShowHiddenFiles)
833+ {
834+ mShowHiddenFiles = show;
835+ refresh();
836+ emit showHiddenFilesChanged();
837+ }
838+}
839+
840+
841+void DirModel::toggleShowDirectories()
842+{
843+ setShowDirectories(!mShowDirectories);
844+}
845+
846+
847+void DirModel::toggleShowHiddenFiles()
848+{
849+ setShowHiddenFiles(!mShowHiddenFiles);
850+}
851+
852+
853+DirModel::SortBy
854+DirModel::getSortBy() const
855+{
856+ return mSortBy;
857+}
858+
859+
860+void DirModel::setSortBy(SortBy field)
861+{
862+ if (field != mSortBy)
863+ {
864+ mSortBy = field;
865+ setCompareAndReorder();
866+ emit sortByChanged();
867+ }
868+}
869+
870+
871+DirModel::SortOrder
872+DirModel::getSortOrder() const
873+{
874+ return mSortOrder;
875+}
876+
877+void DirModel::setSortOrder(SortOrder order)
878+{
879+ if ( order != mSortOrder )
880+ {
881+ mSortOrder = order;
882+ setCompareAndReorder();
883+ emit sortOrderChanged();
884+ }
885+}
886+
887+
888+void DirModel::toggleSortOrder()
889+{
890+ SortOrder order = static_cast<SortOrder> (mSortOrder ^ 1);
891+ setSortOrder(order);
892+}
893+
894+
895+void DirModel::toggleSortBy()
896+{
897+ SortBy by = static_cast<SortBy> (mSortBy ^ 1);
898+ setSortBy(by);
899+}
900+
901+/*!
902+ * \brief DirModel::setCompareAndReorder() called when SortOrder or SortBy change
903+ *
904+ * It does not reload items from disk, just reorganize items from \a mDirectoryContents array
905+ */
906+void DirModel::setCompareAndReorder()
907+{
908+ mCompareFunction = availableCompareFunctions[mSortBy][mSortOrder];
909+ if (mDirectoryContents.count() > 0 && !mAwaitingResults )
910+ {
911+ QVector<QFileInfo> tmpDirectoryContents = mDirectoryContents;
912+ beginResetModel();
913+ mDirectoryContents.clear();
914+ endResetModel();
915+ for(int counter=0; counter < tmpDirectoryContents.count(); counter++)
916+ {
917+ addItem(tmpDirectoryContents.at(counter));
918+ }
919+ }
920+}
921+
922+
923+int DirModel::getClipboardUrlsCounter() const
924+{
925+ return m_fsAction->clipboardLocalUrlsConunter();
926+}
927+
928+
929+int DirModel::rowOfItem(const QFileInfo& fi)
930+{
931+ QVector<QFileInfo>::Iterator it = qBinaryFind(mDirectoryContents.begin(),
932+ mDirectoryContents.end(),
933+ fi,
934+ fileCompareExists);
935+ int row;
936+ if (it == mDirectoryContents.end())
937+ {
938+ row = -1;
939+ }
940+ else
941+ {
942+ row = it - mDirectoryContents.begin();
943+ }
944+ return row;
945+}
946+
947+
948+QDir::Filter DirModel::currentDirFilter() const
949+{
950+ int filter = QDir::AllEntries | QDir::NoDotAndDotDot ;
951+ if (!mShowDirectories)
952+ {
953+ filter &= ~QDir::AllDirs;
954+ filter &= ~QDir::Dirs;
955+ }
956+ if (mShowHiddenFiles)
957+ {
958+ filter |= QDir::Hidden;
959+ }
960+ QDir::Filter dirFilter = static_cast<QDir::Filter>(filter);
961+ return dirFilter;
962+}
963+
964+QString DirModel::dirItems(const QFileInfo& fi) const
965+{
966+ int counter = 0;
967+ QDir d(fi.absoluteFilePath(), QString(), QDir::NoSort, currentDirFilter());
968+ counter = d.count();
969+ if (counter < 0)
970+ {
971+ counter = 0;
972+ }
973+ QString ret (QString::number(counter) + QLatin1Char(' '));
974+ ret += QObject::tr("items");
975+ return ret;
976+}
977+
978+
979+bool DirModel::openIndex(int row)
980+{
981+ bool ret = false;
982+ if (IS_VALID_ROW(row))
983+ {
984+ ret = openItem(mDirectoryContents.at(row));
985+ }
986+ else
987+ {
988+ WARN_ROW_OUT_OF_RANGE(row);
989+ }
990+ return ret;
991+}
992+
993+bool DirModel::openPath(const QString &filename)
994+{
995+ QFileInfo fi(filename);
996+ if (fi.isRelative())
997+ {
998+ fi.setFile(mCurrentDir, filename);
999+ }
1000+ return openItem(fi);
1001+}
1002+
1003+bool DirModel::openItem(const QFileInfo &fi)
1004+{
1005+ bool ret = false;
1006+ if (fi.exists())
1007+ {
1008+ if (fi.isDir())
1009+ {
1010+ ret = cdInto(fi);
1011+ }
1012+ else
1013+ {
1014+ ret = QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absoluteFilePath()));
1015+ }
1016+ }
1017+ return ret;
1018+}
1019+
1020+// for dirlistworker
1021+#include "dirmodel.moc"
1022
1023=== added file 'folderlistmodel/dirmodel.h'
1024--- folderlistmodel/dirmodel.h 1970-01-01 00:00:00 +0000
1025+++ folderlistmodel/dirmodel.h 2013-06-01 17:20:36 +0000
1026@@ -0,0 +1,328 @@
1027+/*
1028+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
1029+ *
1030+ * You may use this file under the terms of the BSD license as follows:
1031+ *
1032+ * "Redistribution and use in source and binary forms, with or without
1033+ * modification, are permitted provided that the following conditions are
1034+ * met:
1035+ * * Redistributions of source code must retain the above copyright
1036+ * notice, this list of conditions and the following disclaimer.
1037+ * * Redistributions in binary form must reproduce the above copyright
1038+ * notice, this list of conditions and the following disclaimer in
1039+ * the documentation and/or other materials provided with the
1040+ * distribution.
1041+ * * Neither the name of Nemo Mobile nor the names of its contributors
1042+ * may be used to endorse or promote products derived from this
1043+ * software without specific prior written permission.
1044+ *
1045+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1046+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1047+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1048+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1049+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1050+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1051+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1052+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1053+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1054+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1055+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
1056+ */
1057+
1058+#ifndef DIRMODEL_H
1059+#define DIRMODEL_H
1060+
1061+#include <QAbstractListModel>
1062+#include <QFileInfo>
1063+#include <QVector>
1064+#include <QStringList>
1065+#include <QDir>
1066+
1067+#include "iorequest.h"
1068+
1069+class FileSystemAction;
1070+typedef bool (*CompareFunction)(const QFileInfo &a, const QFileInfo &b);
1071+
1072+class DirModel : public QAbstractListModel
1073+{
1074+ Q_OBJECT
1075+public:
1076+ enum Roles {
1077+ FileNameRole = Qt::UserRole,
1078+ CreationDateRole,
1079+ ModifiedDateRole,
1080+ FileSizeRole,
1081+ IconSourceRole,
1082+ FilePathRole,
1083+ IsDirRole,
1084+ IsFileRole,
1085+ IsReadableRole,
1086+ IsWritableRole,
1087+ IsExecutableRole
1088+ };
1089+
1090+public:
1091+ explicit DirModel(QObject *parent = 0);
1092+ ~DirModel();
1093+
1094+ int rowCount(const QModelIndex &index = QModelIndex()) const
1095+ {
1096+ if (index.parent() != QModelIndex())
1097+ return 0;
1098+ return mDirectoryContents.count();
1099+ }
1100+
1101+ // TODO: this won't be safe if the model can change under the holder of the row
1102+ Q_INVOKABLE QVariant data(int row, const QByteArray &stringRole) const;
1103+
1104+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
1105+
1106+ Q_INVOKABLE void refresh()
1107+ {
1108+ // just some syntactical sugar really
1109+ setPath(path());
1110+ }
1111+
1112+ Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
1113+ inline QString path() const { return mCurrentDir; }
1114+ void setPath(const QString &pathName);
1115+
1116+ Q_PROPERTY(bool awaitingResults READ awaitingResults NOTIFY awaitingResultsChanged)
1117+ bool awaitingResults() const;
1118+
1119+ Q_INVOKABLE void rm(const QStringList &paths);
1120+
1121+ Q_INVOKABLE bool rename(int row, const QString &newName);
1122+
1123+ Q_INVOKABLE void mkdir(const QString &newdir);
1124+
1125+ Q_PROPERTY(bool showDirectories READ showDirectories WRITE setShowDirectories NOTIFY showDirectoriesChanged)
1126+ bool showDirectories() const;
1127+
1128+ Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
1129+ QStringList nameFilters() const;
1130+ void setNameFilters(const QStringList &nameFilters);
1131+
1132+public slots:
1133+ void onItemsAdded(const QVector<QFileInfo> &newFiles);
1134+ void onResultsFetched();
1135+
1136+signals:
1137+ void awaitingResultsChanged();
1138+ void nameFiltersChanged();
1139+ void showDirectoriesChanged();
1140+ void pathChanged(const QString& newPath);
1141+ void error(const QString &errorTitle, const QString &errorMessage);
1142+
1143+private:
1144+ QHash<int, QByteArray> buildRoleNames() const;
1145+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
1146+ // In Qt5, the roleNames() is virtual and will work just fine. On qt4 setRoleNames must be used with buildRoleNames.
1147+ QHash<int, QByteArray> roleNames() const;
1148+#endif
1149+
1150+ QStringList mNameFilters;
1151+ bool mShowDirectories;
1152+ bool mAwaitingResults;
1153+ QString mCurrentDir;
1154+ QVector<QFileInfo> mDirectoryContents;
1155+
1156+public:
1157+ //[0] new stuff Ubuntu File Manager
1158+#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
1159+ //make this work with tables
1160+ virtual int columnCount(const QModelIndex &) const
1161+ {
1162+ return IsExecutableRole - FileNameRole + 1;
1163+ }
1164+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
1165+#endif
1166+
1167+ Q_PROPERTY(QString parentPath READ parentPath NOTIFY pathChanged)
1168+ QString parentPath() const;
1169+
1170+ Q_PROPERTY(bool showHiddenFiles READ getShowHiddenFiles WRITE setShowHiddenFiles NOTIFY showHiddenFilesChanged)
1171+ bool getShowHiddenFiles() const;
1172+
1173+ Q_ENUMS(SortBy)
1174+ enum SortBy
1175+ {
1176+ SortByName,
1177+ SortByDate
1178+ };
1179+ Q_PROPERTY(SortBy sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged)
1180+ SortBy getSortBy() const;
1181+
1182+ Q_ENUMS(SortOrder)
1183+ enum SortOrder
1184+ {
1185+ SortAscending = Qt::AscendingOrder,
1186+ SortDescending = Qt::DescendingOrder
1187+ };
1188+ Q_PROPERTY(SortOrder sortOrder READ getSortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
1189+ SortOrder getSortOrder() const;
1190+
1191+ Q_PROPERTY(int clipboardUrlsCounter READ getClipboardUrlsCounter NOTIFY clipboardChanged)
1192+ int getClipboardUrlsCounter() const;
1193+
1194+ Q_INVOKABLE QString homePath() const;
1195+
1196+ /*!
1197+ * \brief Tries to make the directory pointed by row as the current to be browsed
1198+ * \return true if row points to a directory and the directory is readble, false otherwise
1199+ */
1200+ Q_INVOKABLE bool cdIntoIndex(int row);
1201+
1202+ Q_INVOKABLE bool cdIntoPath(const QString& filename);
1203+ /*!
1204+ * \brief copyIndex() puts the item pointed by \a row (dir or file) into the clipboard
1205+ * \param row points to the item file or directory
1206+ */
1207+ Q_INVOKABLE void copyIndex(int row);
1208+
1209+ /*!
1210+ * \brief copyPaths(const QStringList& urls) several items (dirs or files) into the clipboard
1211+ * \param items fullpathnames or names only
1212+ */
1213+ Q_INVOKABLE void copyPaths(const QStringList& items);
1214+
1215+ /*!
1216+ * \brief cutIndex() puts the item into the clipboard as \ref copy(),
1217+ * mark the item to be removed after \ref paste()
1218+ * \param row points to the item file or directory
1219+ */
1220+ Q_INVOKABLE void cutIndex(int row);
1221+
1222+ /*!
1223+ * \brief cut() puts several items (dirs or files) into the clipboard as \ref copy(),
1224+ * mark the item to be removed after \ref paste()
1225+ * \param items fullpathnames or names only
1226+ */
1227+ Q_INVOKABLE void cutPaths(const QStringList& items);
1228+
1229+ /*!
1230+ * \brief removeIndex(); remove a item file or directory
1231+ *
1232+ * I gets the item indicated by \row and calls \ref rm()
1233+ *
1234+ * \param row points to the item to b e removed
1235+ * \return true if it was possible to remove the item
1236+ */
1237+ Q_INVOKABLE void removeIndex(int row);
1238+
1239+ /*!
1240+ * Just calls \ref rm()
1241+ */
1242+ Q_INVOKABLE void removePaths(const QStringList& items);
1243+
1244+ /*!
1245+ * Tries to open a file using a suitable application, if the index points to a directory
1246+ * it goes into it using \ref cdIntoIndex() or \ref cdIntoPath()
1247+ *
1248+ * \note Qt uses Qt QDesktopServices::openUrl()
1249+ */
1250+
1251+ Q_INVOKABLE bool openIndex(int row);
1252+ /*!
1253+ * Same as \ref openIndex() but using a file name instead of index
1254+ *
1255+ * \sa \ref cdIntoPath()
1256+ */
1257+ Q_INVOKABLE bool openPath(const QString& filename);
1258+
1259+public slots:
1260+ /*!
1261+ * \brief goHome() goes to user home dir
1262+ * Go to user home dir, we may have a tab for places or something like that
1263+ */
1264+ void goHome();
1265+
1266+ /*!
1267+ * \brief cdUp() sets the parent directory as current directory
1268+ *
1269+ * It can work as a back function if there is no user input path
1270+ * \return true if it was possible to change to parent dir, otherwise false
1271+ */
1272+ bool cdUp();
1273+
1274+ /*!
1275+ * \brief paste() copy item(s) from \ref copy() and \ref paste() into the current directory
1276+ *
1277+ * If the operation was \ref cut(), then remove the original item
1278+ */
1279+ void paste();
1280+
1281+ /*!
1282+ * \brief cancelAction() any copy/cut/remove can be cancelled
1283+ */
1284+ void cancelAction();
1285+
1286+ void setShowDirectories(bool showDirectories);
1287+ void setShowHiddenFiles(bool show);
1288+ void setSortBy(SortBy field);
1289+ void setSortOrder(SortOrder order);
1290+
1291+ void toggleShowDirectories();
1292+ void toggleShowHiddenFiles();
1293+ void toggleSortOrder();
1294+ void toggleSortBy();
1295+
1296+signals:
1297+ /*!
1298+ * \brief insertedItem()
1299+ *
1300+ * It happens when a new file is inserted in an existent view,
1301+ * for example from \ref mkdir() or \ref paste()
1302+ *
1303+ * It can be used to make the new row visible to the user doing a scroll to
1304+ */
1305+ void insertedRow(int row);
1306+ /*!
1307+ * \brief progress()
1308+ * Sends status about recursive and multi-items remove/move/copy
1309+ *
1310+ * \param curItem current item being handled
1311+ * \param totalItems total of items including recursive directories content
1312+ * \param percent a percent done
1313+ */
1314+ void progress(int curItem, int totalItems, int percent);
1315+
1316+ void showHiddenFilesChanged();
1317+ void sortByChanged();
1318+ void sortOrderChanged();
1319+
1320+ void clipboardChanged();
1321+
1322+private slots:
1323+ void onItemRemoved(const QString&);
1324+ void onItemRemoved(const QFileInfo&);
1325+ void onItemAdded(const QString&);
1326+ void onItemAdded(const QFileInfo&);
1327+
1328+private:
1329+ int addItem(const QFileInfo& fi);
1330+ void setCompareAndReorder();
1331+ int rowOfItem(const QFileInfo& fi);
1332+ QDir::Filter currentDirFilter() const;
1333+ QString dirItems(const QFileInfo& fi) const;
1334+ bool cdInto(const QFileInfo& fi);
1335+ bool openItem(const QFileInfo& fi);
1336+
1337+private:
1338+ bool mShowHiddenFiles;
1339+ SortBy mSortBy;
1340+ SortOrder mSortOrder;
1341+ CompareFunction mCompareFunction;
1342+
1343+#if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests
1344+public:
1345+#else
1346+private:
1347+#endif
1348+ FileSystemAction * m_fsAction; //!< it does file system recursive remove/copy/move
1349+ QString fileSize(qint64 size) const;
1350+//[0]
1351+};
1352+
1353+
1354+#endif // DIRMODEL_H
1355
1356=== added file 'folderlistmodel/filesystemaction.cpp'
1357--- folderlistmodel/filesystemaction.cpp 1970-01-01 00:00:00 +0000
1358+++ folderlistmodel/filesystemaction.cpp 2013-06-01 17:20:36 +0000
1359@@ -0,0 +1,1389 @@
1360+/**************************************************************************
1361+ *
1362+ * Copyright 2013 Canonical Ltd.
1363+ * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com>
1364+ *
1365+ * You may use this file under the terms of the BSD license as follows:
1366+ *
1367+ * "Redistribution and use in source and binary forms, with or without
1368+ * modification, are permitted provided that the following conditions are
1369+ * met:
1370+ * * Redistributions of source code must retain the above copyright
1371+ * notice, this list of conditions and the following disclaimer.
1372+ * * Redistributions in binary form must reproduce the above copyright
1373+ * notice, this list of conditions and the following disclaimer in
1374+ * the documentation and/or other materials provided with the
1375+ * distribution.
1376+ * * Neither the name of Nemo Mobile nor the names of its contributors
1377+ * may be used to endorse or promote products derived from this
1378+ * software without specific prior written permission.
1379+ *
1380+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1381+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1382+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1383+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1384+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1385+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1386+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1387+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1388+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1389+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1390+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
1391+ *
1392+ * File: filesystemaction.cpp
1393+ * Date: 3/13/2013
1394+ */
1395+
1396+#include "filesystemaction.h"
1397+#include <sys/statvfs.h>
1398+#include <errno.h>
1399+
1400+#include <QDirIterator>
1401+#include <QDebug>
1402+#include <QTimer>
1403+#include <QMimeData>
1404+#include <QClipboard>
1405+#include <QApplication>
1406+#include <QUrl>
1407+#include <QFileInfo>
1408+#include <QDir>
1409+#include <QThread>
1410+#include <QTemporaryFile>
1411+
1412+#define STEP_FILES 5 // number of the files to work on a step, when this number is reached a signal is emitted
1413+
1414+#define SHOULD_EMIT_PROGRESS_SIGNAL(action) (1)
1415+
1416+#define COMMON_SIZE_ITEM 120
1417+
1418+RemoveNotifier FileSystemAction::m_removeNotifier;
1419+
1420+static QLatin1String GNOME_COPIED_MIME_TYPE ("x-special/gnome-copied-files");
1421+static QLatin1String KDE_CUT_MIME_TYPE ("application/x-kde-cutselection");
1422+
1423+
1424+
1425+class DirModelMimeData : public QMimeData
1426+{
1427+public:
1428+ enum ClipBoardDataOwner
1429+ {
1430+ Nobody, // might have failed
1431+ Application,
1432+ MySelf
1433+ };
1434+
1435+ explicit DirModelMimeData();
1436+ ~DirModelMimeData();
1437+ virtual QStringList formats() const { return m_formats; }
1438+ virtual bool hasFormat ( const QString & mimeType ) const;
1439+public:
1440+ ClipBoardDataOwner setIntoClipboard(const QStringList& files,
1441+ const QString &path,
1442+ ClipboardOperation operation);
1443+ const QMimeData *clipboardMimeData();
1444+ QStringList localUrls(ClipboardOperation& operation);
1445+private:
1446+ static QList<QUrl> gnomeUrls(const QMimeData *mime, ClipboardOperation& operation);
1447+ ClipboardOperation clipBoardOperation();
1448+ bool fillClipboard(const QStringList& files, const QString &path, ClipboardOperation operation);
1449+private:
1450+ QStringList m_formats;
1451+ const QMimeData * m_appMime;
1452+ QByteArray gnomeData;
1453+ QList<QUrl> urls;
1454+ static DirModelMimeData* m_globalMimeData; //!< some mobile devices do not use X, they may not have clipboard
1455+ static int instances;
1456+};
1457+
1458+
1459+int DirModelMimeData::instances = 0;
1460+DirModelMimeData* DirModelMimeData::m_globalMimeData = 0;
1461+
1462+void FileSystemAction::CopyFile::clear()
1463+{
1464+ bytesWritten = 0;
1465+ if (source) delete source;
1466+ if (target) delete target;
1467+ source = 0;
1468+ target = 0;
1469+}
1470+
1471+bool DirModelMimeData::hasFormat ( const QString & mimeType ) const
1472+{
1473+ bool ret = false;
1474+ if ( mimeType == KDE_CUT_MIME_TYPE )
1475+ {
1476+ ret = true;
1477+ }
1478+ else
1479+ {
1480+ ret = m_formats.contains(mimeType);
1481+ }
1482+ return ret;
1483+}
1484+
1485+//===============================================================================================
1486+/*!
1487+ * \brief DirModelMimeData::DirModelMimeData
1488+ */
1489+DirModelMimeData::DirModelMimeData() :
1490+ QMimeData()
1491+ , m_appMime(0)
1492+{
1493+ m_formats.append("text/uri-list");
1494+ m_formats.append(GNOME_COPIED_MIME_TYPE);
1495+ m_formats.append("text/plain");
1496+ m_formats.append("COMPOUND_TEXT");
1497+ m_formats.append("TARGETS");
1498+ m_formats.append("MULTIPLE");
1499+ m_formats.append("TIMESTAMP");
1500+ m_formats.append("SAVE_TARGETS");
1501+
1502+ ++instances;
1503+#if DEBUG_MESSAGES
1504+ qDebug() << Q_FUNC_INFO << this << "instances" << instances;
1505+#endif
1506+}
1507+
1508+
1509+
1510+
1511+DirModelMimeData::~DirModelMimeData()
1512+{
1513+ --instances;
1514+#if DEBUG_MESSAGES
1515+ qDebug() << Q_FUNC_INFO << this << "instances" << instances
1516+ << "m_globalMimeData" << m_globalMimeData;
1517+#endif
1518+ if (instances == 1 && m_globalMimeData)
1519+ {
1520+ DirModelMimeData * tmp = m_globalMimeData;
1521+ m_globalMimeData = 0;
1522+ delete tmp;
1523+ }
1524+}
1525+
1526+//===============================================================================================
1527+/*!
1528+ * \brief DirModelMimeData::gnomeUrls
1529+ * \param mime
1530+ * \param operation
1531+ * \return
1532+ */
1533+QList<QUrl>
1534+DirModelMimeData::gnomeUrls(const QMimeData * mime,
1535+ ClipboardOperation& operation)
1536+{
1537+ QList<QUrl> urls;
1538+ if (mime->hasFormat(GNOME_COPIED_MIME_TYPE))
1539+ {
1540+ QByteArray bytes = mime->data(GNOME_COPIED_MIME_TYPE);
1541+ QList<QString> d = QString(bytes).split(QLatin1String("\r\n"),
1542+ QString::SkipEmptyParts);
1543+ for (int counter= 0; counter < d.count(); counter++)
1544+ {
1545+ if (counter==0)
1546+ {
1547+ QStringList couple = d.at(0).split(QLatin1Char('\n'));
1548+ urls.append(couple[1]);
1549+ if (couple[0] == QLatin1String("cut")) {
1550+ operation = ClipboardCut;
1551+ }
1552+ else {
1553+ operation = ClipboardCopy;
1554+ }
1555+ }
1556+ else {
1557+ urls.append(d.at(counter));
1558+ }
1559+ }
1560+ }
1561+ return urls;
1562+}
1563+
1564+//===============================================================================================
1565+/*!
1566+ * \brief DirModelMimeData::clipBoardOperation()
1567+ * \param mime
1568+ * \return
1569+ */
1570+ClipboardOperation DirModelMimeData::clipBoardOperation()
1571+{
1572+ ClipboardOperation op = ClipboardCopy;
1573+ m_appMime = clipboardMimeData();
1574+ if (m_appMime)
1575+ {
1576+ //first check for GNOME clipboard format, op comes with Copy/Cut
1577+ if (gnomeUrls(m_appMime, op).count() == 0)
1578+ { // there is no gnome format, tries KDE format
1579+ QStringList formats = m_appMime->formats();
1580+ int f = formats.count();
1581+ while(f--)
1582+ {
1583+ const QString &mi = formats.at(f);
1584+ if(mi.startsWith(QLatin1String("application/x-kde")) )
1585+ {
1586+ if (mi.contains(QLatin1String("cut")))
1587+ {
1588+ op = ClipboardCut;
1589+ break;
1590+ }
1591+ }
1592+ }
1593+ }
1594+ }
1595+ return op;
1596+}
1597+
1598+
1599+//===============================================================================================
1600+/*!
1601+ * \brief DirModelMimeData::setIntoClipboard
1602+ *
1603+ * Try to put data in the global cliboard
1604+ *
1605+ * \note:
1606+ * On mobile devices clipboard might not work, in this case a local Clipboard is simulated
1607+ *
1608+ * \param files
1609+ * \param path
1610+ * \param isCut
1611+ * \return who is owner of clipboard data
1612+ */
1613+DirModelMimeData::ClipBoardDataOwner
1614+DirModelMimeData::setIntoClipboard(const QStringList &files, const QString& path, ClipboardOperation operation)
1615+{
1616+ DirModelMimeData::ClipBoardDataOwner ret = Nobody;
1617+ QClipboard *clipboard = QApplication::clipboard();
1618+ if (clipboard)
1619+ {
1620+ ret = Application;
1621+ DirModelMimeData *mime = m_globalMimeData ? m_globalMimeData
1622+ : new DirModelMimeData();
1623+ if (mime->fillClipboard(files, path, operation))
1624+ {
1625+ clipboard->setMimeData(mime);
1626+ const QMimeData *data = clipboard->mimeData();
1627+ //it looks like some mobile devices does not have X
1628+ //in this case we simulate our own clipboard
1629+ if (!data && !m_globalMimeData)
1630+ {
1631+ m_globalMimeData = mime;
1632+ }
1633+#if DEBUG_MESSAGES
1634+ qDebug() << Q_FUNC_INFO << "mime" << mime << "clipboard->mimeData()" << data
1635+ << "m_ownClipboardMimeData" << m_globalMimeData;
1636+#endif
1637+ }
1638+ else
1639+ if (m_globalMimeData != mime)
1640+ {
1641+ delete mime;
1642+ }
1643+ //check if it is necessary to send notification about Clipboard changed
1644+ if (m_globalMimeData)
1645+ {
1646+ ret = MySelf;
1647+ }
1648+ }
1649+ return ret;
1650+}
1651+
1652+
1653+bool DirModelMimeData::fillClipboard(const QStringList& files, const QString &path, ClipboardOperation operation)
1654+{
1655+ bool ret = false;
1656+ int index = m_formats.indexOf(KDE_CUT_MIME_TYPE);
1657+ if (index != -1 && operation != ClipboardCut)
1658+ {
1659+ m_formats.removeAt(index);
1660+ }
1661+ else
1662+ if (operation == ClipboardCut)
1663+ {
1664+ m_formats.append(KDE_CUT_MIME_TYPE);
1665+ }
1666+
1667+ urls.clear();
1668+ QFileInfo fi;
1669+ gnomeData.clear();
1670+ gnomeData += operation == ClipboardCut ?
1671+ QLatin1String("cut\n") :
1672+ QLatin1String("copy\n");
1673+ for(int counter = 0; counter < files.count(); counter++)
1674+ {
1675+ const QString& item = files.at(counter);
1676+ fi.setFile(item);
1677+ if (!fi.isAbsolute())
1678+ {
1679+ fi.setFile(path + QDir::separator() + item);
1680+ }
1681+ if (fi.exists())
1682+ {
1683+ QUrl item = QUrl::fromLocalFile(fi.absoluteFilePath());
1684+ urls.append(item);
1685+ gnomeData += item.toEncoded() + QLatin1String("\r\n");
1686+ }
1687+ else
1688+ {
1689+ // emit error( QObject::tr("Item does not exist"), item);
1690+ urls.clear();
1691+ break;
1692+ }
1693+ }
1694+ if (urls.count() > 0)
1695+ {
1696+ setData(GNOME_COPIED_MIME_TYPE, gnomeData);
1697+ setUrls(urls);
1698+ ret = true;
1699+ }
1700+ return ret;
1701+}
1702+
1703+//===============================================================================================
1704+/*!
1705+ * \brief DirModelMimeData::clipboardMimeData
1706+ * \return
1707+ */
1708+const QMimeData *DirModelMimeData::clipboardMimeData()
1709+{
1710+ const QMimeData *ret = 0;
1711+ QClipboard *clipboard = QApplication::clipboard();
1712+ if (m_globalMimeData)
1713+ {
1714+ ret = m_globalMimeData;
1715+ }
1716+ else
1717+ if (clipboard)
1718+ {
1719+ ret = clipboard->mimeData();
1720+ }
1721+#if DEBUG_MESSAGES
1722+ qDebug() << Q_FUNC_INFO << "clipboard" << clipboard
1723+ << "m_ownClipboardMimeData" << m_globalMimeData
1724+ << "clipboard->mimeData()" << ret;
1725+#endif
1726+ return ret;
1727+}
1728+
1729+//===============================================================================================
1730+/*!
1731+ * \brief DirModelMimeData::localUrls
1732+ * \return
1733+ */
1734+QStringList
1735+DirModelMimeData::localUrls(ClipboardOperation& operation)
1736+{
1737+ m_appMime = clipboardMimeData();
1738+ QStringList paths;
1739+ //it may have external urls
1740+ if (m_appMime)
1741+ {
1742+ QList<QUrl> urls;
1743+ if (m_appMime->hasUrls())
1744+ {
1745+ urls = m_appMime->urls();
1746+ operation = clipBoardOperation();
1747+ }
1748+ else
1749+ {
1750+ urls = gnomeUrls(m_appMime, operation);
1751+ }
1752+ for (int counter=0; counter < urls.count(); counter++)
1753+ {
1754+ if (urls.at(counter).toString().startsWith(QLatin1String("file://")))
1755+ {
1756+ paths.append(urls.at(counter).toLocalFile());
1757+ }
1758+ }
1759+ }
1760+#if DEBUG_MESSAGES
1761+ qDebug() << Q_FUNC_INFO << paths;
1762+#endif
1763+ return paths;
1764+}
1765+
1766+/*!
1767+ * \brief RemoveNotifier::RemoveNotifier
1768+ * \param parent
1769+ */
1770+RemoveNotifier::RemoveNotifier(QObject *parent) :
1771+ QObject(parent)
1772+{
1773+}
1774+
1775+//===============================================================================================
1776+/*!
1777+ * \brief RemoveNotifier::notifyRemoved
1778+ * \param fi
1779+ */
1780+void RemoveNotifier::notifyRemoved(const QFileInfo &fi)
1781+{
1782+#if DEBUG_MESSAGES
1783+ qDebug() << Q_FUNC_INFO << "emit removed(QFileInfo)" << fi.absoluteFilePath();
1784+#endif
1785+ emit removed(fi);
1786+}
1787+
1788+//===============================================================================================
1789+/*!
1790+ * \brief RemoveNotifier::notifyRemoved
1791+ * \param item
1792+ */
1793+void RemoveNotifier::notifyRemoved(const QString &item)
1794+{
1795+#if DEBUG_MESSAGES
1796+ qDebug() << Q_FUNC_INFO << "emit removed(QString)" << item;
1797+#endif
1798+ emit removed(item);
1799+}
1800+
1801+
1802+//===============================================================================================
1803+/*!
1804+ * \brief FileSystemAction::FileSystemAction
1805+ * \param parent
1806+ */
1807+FileSystemAction::FileSystemAction(QObject *parent) :
1808+ QObject(parent)
1809+ , m_curAction(0)
1810+ , m_cancelCurrentAction(false)
1811+ , m_busy(false)
1812+ , m_mimeData ( new DirModelMimeData() )
1813+ , m_clipboardModifiedByOther(false)
1814+{
1815+ //as m_removeNotifier is static it will send signals to all instances of
1816+ //the model
1817+ connect(&m_removeNotifier, SIGNAL(removed(QFileInfo)),
1818+ this, SIGNAL(removed(QFileInfo)));
1819+
1820+ connect(&m_removeNotifier, SIGNAL(removed(QString)),
1821+ this, SIGNAL(removed(QString)));
1822+
1823+ QClipboard *clipboard = QApplication::clipboard();
1824+
1825+ connect(clipboard, SIGNAL(dataChanged()), this, SIGNAL(clipboardChanged()));
1826+ connect(clipboard, SIGNAL(dataChanged()), this, SLOT(clipboardHasChanged()));
1827+}
1828+
1829+//===============================================================================================
1830+/*!
1831+ * \brief FileSystemAction::~FileSystemAction
1832+ */
1833+FileSystemAction::~FileSystemAction()
1834+{
1835+ delete m_mimeData;
1836+}
1837+
1838+//===============================================================================================
1839+/*!
1840+ * \brief FileSystemAction::remove
1841+ * \param paths
1842+ */
1843+void FileSystemAction::remove(const QStringList &paths)
1844+{
1845+ createAndProcessAction(ActionRemove, paths, NoClipboard);
1846+}
1847+
1848+//===============================================================================================
1849+/*!
1850+ * \brief FileSystemAction::createAction
1851+ * \param type
1852+ * \param origBase
1853+ * \return
1854+ */
1855+FileSystemAction::Action* FileSystemAction::createAction(ActionType type, int origBase)
1856+{
1857+ Action * action = new Action();
1858+ action->type = type;
1859+ action->baseOrigSize = origBase;
1860+ action->targetPath = m_path;
1861+ action->totalItems = 0;
1862+ action->currItem = 0;
1863+ action->currEntry = 0;
1864+ action->totalBytes = 0;
1865+ action->bytesWritten = 0;
1866+ action->done = false;
1867+
1868+ return action;
1869+}
1870+
1871+//===============================================================================================
1872+/*!
1873+ * \brief FileSystemAction::addEntry
1874+ * \param action
1875+ * \param pathname
1876+ */
1877+void FileSystemAction::addEntry(Action* action, const QString& pathname)
1878+{
1879+#if DEBUG_MESSAGES
1880+ qDebug() << Q_FUNC_INFO << pathname;
1881+#endif
1882+ QFileInfo info(pathname);
1883+ if (!info.isAbsolute())
1884+ {
1885+ info.setFile(action->targetPath, pathname);
1886+ }
1887+ if (!info.exists())
1888+ {
1889+ emit error(QObject::tr("File or Directory does not exist"),
1890+ pathname + QObject::tr(" does not exist")
1891+ );
1892+ return;
1893+ }
1894+ ActionEntry * entry = new ActionEntry();
1895+ QFileInfo item;
1896+ //ActionMove will perform a rename, so no Directory expanding is necessary
1897+ if (action->type != ActionMove && info.isDir() && !info.isSymLink())
1898+ {
1899+ QDirIterator it(info.absoluteFilePath(),
1900+ QDir::AllEntries | QDir::System |
1901+ QDir::NoDotAndDotDot | QDir::Hidden,
1902+ QDirIterator::Subdirectories);
1903+ while (it.hasNext() && !it.next().isEmpty())
1904+ {
1905+ item = it.fileInfo();
1906+ entry->reversedOrder.prepend(it.fileInfo());
1907+ if (item.isFile() && !item.isDir() && !item.isSymLink())
1908+ {
1909+ action->totalBytes += item.size();
1910+ }
1911+ else
1912+ {
1913+ action->totalBytes += COMMON_SIZE_ITEM;
1914+ }
1915+ }
1916+ }
1917+ //this is the item being handled
1918+ entry->reversedOrder.append(info);
1919+
1920+ // verify if the destination item already exists
1921+ if (action->type == ActionCopy || action->type == ActionMove ||
1922+ action->type == ActionHardMoveCopy)
1923+ {
1924+ QFileInfo destination(targetFom(info.absoluteFilePath()));
1925+ entry->alreadyExists = destination.exists();
1926+ }
1927+
1928+ action->totalItems += entry->reversedOrder.count();
1929+ if (info.isFile() && !info.isDir() && !info.isSymLink())
1930+ {
1931+ action->totalBytes += info.size();
1932+ }
1933+ else
1934+ {
1935+ action->totalBytes += COMMON_SIZE_ITEM;
1936+ }
1937+ action->entries.append(entry);
1938+}
1939+
1940+//===============================================================================================
1941+/*!
1942+ * \brief FileSystemAction::processAction
1943+ */
1944+void FileSystemAction::processAction()
1945+{
1946+ if (m_curAction)
1947+ {
1948+ //it will be ActionHardMoveRemove only when switched from ActionHardMoveCopy
1949+ //in this case the move is done in two steps COPY and REMOVE
1950+ if (m_curAction->type != ActionHardMoveCopy)
1951+ {
1952+ delete m_curAction;
1953+ m_curAction = 0;
1954+ }
1955+ }
1956+ if (!m_curAction && m_queuedActions.count())
1957+ {
1958+ m_curAction = m_queuedActions.at(0);
1959+ m_queuedActions.remove(0,1);
1960+ }
1961+ if (m_curAction)
1962+ {
1963+ m_busy = true;
1964+ m_cancelCurrentAction = false;
1965+ m_errorMsg.clear();
1966+ m_errorTitle.clear();
1967+ scheduleSlot(SLOT(processActionEntry()));
1968+ if (SHOULD_EMIT_PROGRESS_SIGNAL(m_curAction))
1969+ {
1970+ emit progress(0,m_curAction->totalItems, 0);
1971+ }
1972+ }
1973+ else
1974+ {
1975+ m_busy = false;
1976+ }
1977+}
1978+
1979+
1980+//===============================================================================================
1981+/*!
1982+ * \brief FileSystemAction::processActionEntry
1983+ */
1984+void FileSystemAction::processActionEntry()
1985+{
1986+#if DEBUG_MESSAGES
1987+ qDebug() << Q_FUNC_INFO;
1988+#endif
1989+
1990+ ActionEntry * curEntry = static_cast<ActionEntry*>
1991+ ( m_curAction->entries.at(m_curAction->currEntry) );
1992+
1993+#if defined(SIMULATE_LONG_ACTION)
1994+ {
1995+ unsigned int delay = SIMULATE_LONG_ACTION;
1996+ if (delay == 1)
1997+ {
1998+ delay = 100; //each (10 * STEP_FILES) files will waits a second
1999+ QThread::currentThread()->wait(delay);
2000+ }
2001+ }
2002+#endif
2003+ if (!m_cancelCurrentAction)
2004+ {
2005+ switch(m_curAction->type)
2006+ {
2007+ case ActionRemove:
2008+ case ActionHardMoveRemove:
2009+ removeEntry(curEntry);
2010+ endActionEntry();
2011+ break;
2012+ case ActionCopy:
2013+ case ActionHardMoveCopy:
2014+ processCopyEntry(); // specially: this is a slot
2015+ break;
2016+ case ActionMove:
2017+ moveEntry(curEntry);
2018+ endActionEntry();
2019+ break;
2020+ }
2021+ }
2022+}
2023+
2024+//===============================================================================================
2025+/*!
2026+ * \brief FileSystemAction::endActionEntry
2027+ */
2028+void FileSystemAction::endActionEntry()
2029+{
2030+#if DEBUG_MESSAGES
2031+ qDebug() << Q_FUNC_INFO;
2032+#endif
2033+ ActionEntry * curEntry = static_cast<ActionEntry*>
2034+ ( m_curAction->entries.at(m_curAction->currEntry) );
2035+
2036+ // first of all check for any error or a cancel issued by the user
2037+ if (m_cancelCurrentAction)
2038+ {
2039+ if (!m_errorTitle.isEmpty())
2040+ {
2041+ emit error(m_errorTitle, m_errorMsg);
2042+ }
2043+ //it may have other actions to do
2044+ scheduleSlot(SLOT(processAction()));
2045+ return;
2046+ }
2047+ // check if the current entry has finished
2048+ // if so Views need to receive the notification about that
2049+ if (curEntry->currItem == curEntry->reversedOrder.count())
2050+ {
2051+ const QFileInfo & mainItem = curEntry->reversedOrder.at(curEntry->currItem -1);
2052+ if (m_curAction->type == ActionRemove || m_curAction->type == ActionMove ||
2053+ m_curAction->type == ActionHardMoveRemove)
2054+ {
2055+ m_removeNotifier.notifyRemoved(mainItem); // notify all instances
2056+ }
2057+ if (m_curAction->type == ActionCopy || m_curAction->type == ActionMove ||
2058+ m_curAction->type == ActionHardMoveCopy)
2059+ {
2060+ QString addedItem = targetFom(mainItem.absoluteFilePath());
2061+ if (curEntry->alreadyExists)
2062+ {
2063+ m_removeNotifier.notifyRemoved(addedItem);
2064+ }
2065+ emit added(addedItem);
2066+ }
2067+ m_curAction->currEntry++;
2068+ //check if is doing a hard move and the copy part has finished
2069+ //if so switch the action to remove
2070+ if (m_curAction->type == ActionHardMoveCopy &&
2071+ m_curAction->currEntry == m_curAction->entries.count() )
2072+ {
2073+ m_curAction->type = ActionHardMoveRemove;
2074+ m_curAction->currEntry = 0;
2075+ int entryCounter = m_curAction->entries.count();
2076+ ActionEntry * entry;
2077+ while (entryCounter--)
2078+ {
2079+ entry = m_curAction->entries.at(entryCounter);
2080+ entry->currItem = 0;
2081+ entry->currStep = 0;
2082+ }
2083+ }
2084+ }
2085+ if (curEntry->currStep == STEP_FILES)
2086+ {
2087+ curEntry->currStep = 0;
2088+ }
2089+
2090+ int percent = notifyProgress();
2091+ //Check if the current action has finished or cancelled
2092+ if (m_cancelCurrentAction ||
2093+ m_curAction->currEntry == m_curAction->entries.count())
2094+ {
2095+ if (!m_cancelCurrentAction)
2096+ {
2097+ endCurrentAction();
2098+ if (percent < 100)
2099+ {
2100+ notifyProgress(100);
2101+ }
2102+ }
2103+ //it may have other actions to do
2104+ scheduleSlot(SLOT(processAction()));
2105+ }
2106+ else
2107+ {
2108+ //keep working on current Action maybe more entries
2109+ scheduleSlot(SLOT(processActionEntry()));
2110+ }
2111+}
2112+
2113+//===============================================================================================
2114+/*!
2115+ * \brief FileSystemAction::cancel
2116+ */
2117+void FileSystemAction::cancel()
2118+{
2119+ m_cancelCurrentAction = true;
2120+}
2121+
2122+//===============================================================================================
2123+/*!
2124+ * \brief FileSystemAction::removeEntry
2125+ * \param entry
2126+ */
2127+void FileSystemAction::removeEntry(ActionEntry *entry)
2128+{
2129+ QDir dir;
2130+ //do one step at least
2131+ for(; !m_cancelCurrentAction &&
2132+ entry->currStep < STEP_FILES &&
2133+ m_curAction->currItem < m_curAction->totalItems &&
2134+ entry->currItem < entry->reversedOrder.count()
2135+ ; entry->currStep++, m_curAction->currItem++, entry->currItem++
2136+ )
2137+
2138+ {
2139+ const QFileInfo &fi = entry->reversedOrder.at(entry->currItem);
2140+ if (fi.isDir() && !fi.isSymLink())
2141+ {
2142+ m_cancelCurrentAction = !dir.rmdir(fi.absoluteFilePath());
2143+ }
2144+ else
2145+ {
2146+ m_cancelCurrentAction = !QFile::remove(fi.absoluteFilePath());
2147+ }
2148+#if DEBUG_REMOVE
2149+ qDebug() << "remove ret=" << !m_cancelCurrentAction << fi.absoluteFilePath();
2150+#endif
2151+ if (m_cancelCurrentAction)
2152+ {
2153+ m_errorTitle = QObject::tr("Could not remove the item ") +
2154+ fi.absoluteFilePath();
2155+ m_errorMsg = ::strerror(errno);
2156+ }
2157+ }
2158+}
2159+
2160+//===============================================================================================
2161+/*!
2162+ * \brief FileSystemAction::copyEntry
2163+ * \param entry
2164+ */
2165+void FileSystemAction::processCopyEntry()
2166+{
2167+#if DEBUG_MESSAGES
2168+ qDebug() << Q_FUNC_INFO;
2169+#endif
2170+
2171+ ActionEntry * entry = static_cast<ActionEntry*>
2172+ ( m_curAction->entries.at(m_curAction->currEntry) );
2173+
2174+ /*
2175+ * This flag will be true when processCopySingleFile() has put any slot in the execution queue
2176+ * it will work to stop the loop.
2177+ * Later processCopyEntry() will be called again to continue working
2178+ */
2179+ bool scheduleAnySlot = false;
2180+
2181+ for(; !m_cancelCurrentAction && !scheduleAnySlot &&
2182+ entry->currStep < STEP_FILES &&
2183+ m_curAction->currItem < m_curAction->totalItems &&
2184+ entry->currItem < entry->reversedOrder.count()
2185+ ; entry->currStep++, entry->currItem++
2186+ )
2187+
2188+ {
2189+ const QFileInfo &fi = entry->reversedOrder.at(entry->currItem);
2190+ QString orig = fi.absoluteFilePath();
2191+ QString target = targetFom(orig);
2192+ QString path(target);
2193+ // do this here to allow progress send right item number, copySingleFile will emit progress()
2194+ m_curAction->currItem++;
2195+
2196+ if (fi.isFile() || fi.isSymLink())
2197+ {
2198+ QFileInfo t(target);
2199+ path = t.path();
2200+ }
2201+ QDir d(path);
2202+ if (!d.exists() && !d.mkpath(path))
2203+ {
2204+ m_cancelCurrentAction = true;
2205+ m_errorTitle = QObject::tr("Could not create the directory");
2206+ m_errorMsg = path;
2207+ }
2208+ else
2209+ if (fi.isSymLink())
2210+ {
2211+ m_cancelCurrentAction = ! copySymLink(target,fi);
2212+ if (m_cancelCurrentAction)
2213+ {
2214+ m_errorTitle = QObject::tr("Could not create link to");
2215+ m_errorMsg = target;
2216+ }
2217+ m_curAction->bytesWritten += COMMON_SIZE_ITEM;
2218+ }
2219+ else
2220+ if (fi.isDir())
2221+ {
2222+ m_cancelCurrentAction = !
2223+ QFile(target).setPermissions(fi.permissions());
2224+ if (m_cancelCurrentAction)
2225+ {
2226+ m_errorTitle = QObject::tr("Could not set permissions to dir");
2227+ m_errorMsg = target;
2228+ }
2229+ m_curAction->bytesWritten += COMMON_SIZE_ITEM;
2230+ }
2231+ else
2232+ if (fi.isFile())
2233+ {
2234+ m_curAction->copyFile.clear();
2235+ m_curAction->copyFile.source = new QFile(orig);
2236+ if (!m_curAction->copyFile.source->open(QFile::ReadOnly))
2237+ {
2238+ m_cancelCurrentAction = true;
2239+ m_errorTitle = QObject::tr("Could not open file");
2240+ m_errorMsg = orig;
2241+ }
2242+ m_curAction->copyFile.target = new QTemporaryFile();
2243+ if (! m_curAction->copyFile.target->open())
2244+ {
2245+ m_cancelCurrentAction = true;
2246+ m_errorTitle = QObject::tr("Could not create temporary file");
2247+ m_errorMsg = m_curAction->copyFile.target->fileName();
2248+ }
2249+ m_curAction->copyFile.targetName = target;
2250+ scheduleAnySlot = processCopySingleFile();
2251+ }
2252+ }//for
2253+
2254+ //no copy going on
2255+ if (!scheduleAnySlot)
2256+ {
2257+ endActionEntry();
2258+ }
2259+}
2260+
2261+//===============================================================================================
2262+/*!
2263+ * \brief FileSystemAction::moveEntry
2264+ * \param entry
2265+ */
2266+void FileSystemAction::moveEntry(ActionEntry *entry)
2267+{
2268+ QFile file;
2269+
2270+ for(; !m_cancelCurrentAction &&
2271+ entry->currStep < STEP_FILES &&
2272+ m_curAction->currItem < m_curAction->totalItems &&
2273+ entry->currItem < entry->reversedOrder.count()
2274+ ; entry->currStep++, m_curAction->currItem++, entry->currItem++
2275+ )
2276+
2277+ {
2278+ const QFileInfo &fi = entry->reversedOrder.at(entry->currItem);
2279+ file.setFileName(fi.absoluteFilePath());
2280+ QString target = targetFom(fi.absoluteFilePath());
2281+ if (!file.rename(target))
2282+ {
2283+ m_cancelCurrentAction = true;
2284+ m_errorTitle = QObject::tr("Could not move the directory/file ") + target;
2285+ m_errorMsg = ::strerror(errno);
2286+ }
2287+ }//for
2288+}
2289+
2290+//===============================================================================================
2291+/*!
2292+ * \brief FileSystemAction::pathChanged
2293+ * \param path
2294+ */
2295+void FileSystemAction::pathChanged(const QString &path)
2296+{
2297+ m_path = path;
2298+}
2299+
2300+//===============================================================================================
2301+/*!
2302+ * \brief FileSystemAction::copy
2303+ * \param pathnames
2304+ */
2305+void FileSystemAction::copy(const QStringList &pathnames)
2306+{
2307+#if DEBUG_MESSAGES
2308+ qDebug() << Q_FUNC_INFO << pathnames;
2309+#endif
2310+ DirModelMimeData::ClipBoardDataOwner owner =
2311+ m_mimeData->setIntoClipboard(pathnames, m_path, ClipboardCopy);
2312+ if (owner == DirModelMimeData::MySelf )
2313+ {
2314+ emit clipboardChanged();
2315+ }
2316+}
2317+
2318+//===============================================================================================
2319+/*!
2320+ * \brief FileSystemAction::cut
2321+ * \param pathnames
2322+ */
2323+void FileSystemAction::cut(const QStringList &pathnames)
2324+{
2325+#if DEBUG_MESSAGES
2326+ qDebug() << Q_FUNC_INFO << pathnames;
2327+#endif
2328+ DirModelMimeData::ClipBoardDataOwner owner =
2329+ m_mimeData->setIntoClipboard(pathnames, m_path, ClipboardCut);
2330+ if (owner == DirModelMimeData::MySelf )
2331+ {
2332+ emit clipboardChanged();
2333+ }
2334+}
2335+
2336+//===============================================================================================
2337+/*!
2338+ * \brief FileSystemAction::paste
2339+ */
2340+void FileSystemAction::paste()
2341+{
2342+ ClipboardOperation operation;
2343+ QStringList paths = m_mimeData->localUrls(operation);
2344+#if DEBUG_MESSAGES
2345+ qDebug() << Q_FUNC_INFO << paths;
2346+#endif
2347+ if (paths.count())
2348+ {
2349+ if (QFileInfo(m_path).absoluteFilePath() == QFileInfo(paths.at(0)).absolutePath())
2350+ {
2351+ emit error(tr("Cannot paste"),
2352+ tr("origin and destination folder are the same"));
2353+ return;
2354+ }
2355+ ActionType actionType = ActionCopy; // start with Copy and check for Cut
2356+ if (operation == ClipboardCut)
2357+ {
2358+ //so far it always returns true since on Linux it is possible to rename
2359+ // between different file systems
2360+ if ( moveUsingSameFileSystem(paths.at(0)) ) {
2361+ actionType = ActionMove;
2362+ } else {
2363+ actionType = ActionHardMoveCopy; // first step
2364+ }
2365+ }
2366+ createAndProcessAction(actionType, paths, operation);
2367+ }
2368+}
2369+
2370+//===============================================================================================
2371+/*!
2372+ * \brief FileSystemAction::createAndProcessAction
2373+ * \param actionType
2374+ * \param paths
2375+ * \param operation
2376+ */
2377+void FileSystemAction::createAndProcessAction(ActionType actionType, const QStringList& paths, ClipboardOperation operation)
2378+{
2379+#if DEBUG_MESSAGES
2380+ qDebug() << Q_FUNC_INFO << paths;
2381+#endif
2382+ Action *myAction = 0;
2383+ int origPathLen = 0;
2384+ myAction = createAction(actionType, origPathLen);
2385+ myAction->operation = operation;
2386+ myAction->origPath = QFileInfo(paths.at(0)).absolutePath();
2387+ myAction->baseOrigSize = myAction->origPath.length();
2388+ Action * saveAction = m_curAction;
2389+ m_curAction = myAction;
2390+ for (int counter=0; counter < paths.count(); counter++)
2391+ {
2392+ //targetFom() uses m_curAction and is called inside addEntry()
2393+ addEntry(myAction, paths.at(counter));
2394+ }
2395+ m_curAction = saveAction;
2396+ if (actionType == ActionHardMoveCopy)
2397+ {
2398+ myAction->totalItems *= 2; //duplicate this
2399+ myAction->totalBytes *= 2;
2400+ }
2401+ if (operation == ClipboardCut)
2402+ {
2403+ //this must still be false when cut finishes to change the clipboard to the target
2404+ m_clipboardModifiedByOther = false;
2405+ }
2406+ m_queuedActions.append(myAction);
2407+ if (!m_busy)
2408+ {
2409+ processAction();
2410+ }
2411+}
2412+
2413+//===============================================================================================
2414+/*!
2415+ * \brief FileSystemAction::targetFom() makes a destination full pathname from \a origItem
2416+ * \param origItem full pathname from a item intended to be copied or moved into current path
2417+ * \return full pathname of target
2418+ */
2419+QString FileSystemAction::targetFom(const QString& origItem)
2420+{
2421+ QString target(m_curAction->targetPath + origItem.mid(m_curAction->baseOrigSize));
2422+ return target;
2423+}
2424+
2425+//===============================================================================================
2426+/*!
2427+ * \brief FileSystemAction::moveUsingSameFileSystem() Checks if the item being moved to
2428+ * current m_path belongs to the same File System
2429+ *
2430+ * \param itemToMovePathname first item being moved from a paste operation
2431+ *
2432+ * \return true if the item being moved to the current m_path belongs to the same file system as m_path
2433+ */
2434+bool FileSystemAction::moveUsingSameFileSystem(const QString& itemToMovePathname)
2435+{
2436+#if 0 //disabled since on Linux it looks like renaming between different file systems works
2437+ unsigned long targetFsId = 0xffff;
2438+ unsigned long originFsId = 0xfffe;
2439+ struct statvfs vfs;
2440+
2441+ if ( ::statvfs(m_path.toLatin1().constData(), &vfs) == 0 )
2442+ {
2443+ targetFsId = vfs.f_fsid;
2444+ }
2445+ if ( ::statvfs(itemToMovePathname.toLatin1().constData(), &vfs) == 0)
2446+ {
2447+ originFsId = vfs.f_fsid;
2448+ }
2449+ return targetFsId == originFsId;
2450+#else
2451+ Q_UNUSED(itemToMovePathname);
2452+ return true;
2453+#endif
2454+}
2455+
2456+//=======================================================
2457+/*!
2458+ * \brief FileSystemAction::clipboardLocalUrlsConunter
2459+ * \return
2460+ */
2461+int FileSystemAction::clipboardLocalUrlsConunter()
2462+{
2463+ ClipboardOperation operation;
2464+ return m_mimeData->localUrls(operation).count();
2465+}
2466+
2467+//================================================================================
2468+/*!
2469+ * \brief FileSystemAction::endCurrentAction() finishes an Action
2470+ *
2471+ * If a Paste was made from a Cut operation, items pasted become avaialable in the clipboard
2472+ * as from Copy source operation, so items can be now Pasted again, but with no source removal
2473+ *
2474+ * It checks for \a m_clipboardModifiedByOther that idenftifies if the clipboard was modified during the
2475+ * operation maybe by another application.
2476+ */
2477+void FileSystemAction::endCurrentAction()
2478+{
2479+ if ( m_curAction->origPath != m_curAction->targetPath &&
2480+ m_curAction->operation == ClipboardCut &&
2481+ !m_clipboardModifiedByOther )
2482+ {
2483+ QStringList items;
2484+ const ActionEntry *entry;
2485+ int last;
2486+ for(int e = 0; e < m_curAction->entries.count(); e++)
2487+ {
2488+ entry = m_curAction->entries.at(e);
2489+ last = entry->reversedOrder.count() -1;
2490+ QString item(targetFom(entry->reversedOrder.at(last).absoluteFilePath()));
2491+ items.append(item);
2492+ }
2493+ if (items.count())
2494+ {
2495+ QString targetPath = m_curAction->targetPath;
2496+ //it is not necessary to handle own clipboard here
2497+ m_mimeData->setIntoClipboard(items, targetPath, ClipboardCopy);
2498+ }
2499+ }
2500+}
2501+
2502+//================================================================================
2503+/*!
2504+ * \brief FileSystemAction::copySingleFile() do a single file copy
2505+ *
2506+ * Several write operations are required to copy big files, each operation writes (STEP_FILES * 4k) bytes.
2507+ * After a write operation if more operations are required to copy the whole file,
2508+ * a progress() signal is emitted and a new write operation is scheduled to happen in the next loop interaction.
2509+ *
2510+ * \return true if scheduled to another slot either processCopyEntry() or itself; false if not.
2511+ */
2512+bool FileSystemAction::processCopySingleFile()
2513+{
2514+#if DEBUG_MESSAGES
2515+ qDebug() << Q_FUNC_INFO;
2516+#endif
2517+ char block[4096];
2518+ int step = 0;
2519+ bool copySingleFileDone = false;
2520+ bool scheduleAnySlot = true;
2521+ int startBytes = m_curAction->copyFile.bytesWritten;
2522+
2523+ while( m_curAction->copyFile.source &&
2524+ !m_curAction->copyFile.source->atEnd() &&
2525+ !m_cancelCurrentAction &&
2526+ m_curAction->copyFile.bytesWritten < m_curAction->copyFile.source->size() &&
2527+ step++ < STEP_FILES
2528+ )
2529+ {
2530+ qint64 in = m_curAction->copyFile.source->read(block, sizeof(block));
2531+ if (in > 0)
2532+ {
2533+ if(in != m_curAction->copyFile.target->write(block, in))
2534+ {
2535+ m_curAction->copyFile.source->close();
2536+ m_curAction->copyFile.target->close();
2537+ m_cancelCurrentAction = true;
2538+ m_errorTitle = QObject::tr("Write error in ")
2539+ + m_curAction->copyFile.targetName,
2540+ m_errorMsg = ::strerror(errno);
2541+ break;
2542+ }
2543+ m_curAction->bytesWritten += in;
2544+ m_curAction->copyFile.bytesWritten += in;
2545+ }
2546+ else
2547+ if (in < 0)
2548+ {
2549+ m_cancelCurrentAction = true;
2550+ m_errorTitle = QObject::tr("Read error in ")
2551+ + m_curAction->copyFile.source->fileName();
2552+ m_errorMsg = ::strerror(errno);
2553+ break;
2554+ }
2555+ }// end write loop
2556+
2557+ // write loop finished, the copy might be finished
2558+ if (!m_cancelCurrentAction
2559+ && m_curAction->copyFile.source
2560+ && m_curAction->copyFile.bytesWritten == m_curAction->copyFile.source->size()
2561+ && m_curAction->copyFile.source->isOpen()
2562+ )
2563+ {
2564+ m_curAction->copyFile.source->close();
2565+ m_curAction->copyFile.target->close();
2566+ m_curAction->copyFile.target->setAutoRemove(false);
2567+ m_cancelCurrentAction = !m_curAction->copyFile.target->setPermissions(
2568+ m_curAction->copyFile.source->permissions());
2569+ if (m_cancelCurrentAction)
2570+ {
2571+ m_errorTitle = QObject::tr("Set permissions error in ")
2572+ + m_curAction->copyFile.targetName,
2573+ m_errorMsg = ::strerror(errno);
2574+ }
2575+ else
2576+ {
2577+ QFile testExistTarget(m_curAction->copyFile.targetName);
2578+ if (testExistTarget.exists())
2579+ {
2580+ if ((m_cancelCurrentAction = ! testExistTarget.remove()))
2581+ {
2582+ m_errorTitle = QObject::tr("Could not remove original file ")
2583+ + m_curAction->copyFile.targetName,
2584+ m_errorMsg = ::strerror(errno);
2585+ }
2586+ }
2587+ if (!m_cancelCurrentAction)
2588+ {
2589+ m_cancelCurrentAction = ! m_curAction->copyFile.target->
2590+ rename(m_curAction->copyFile.targetName);
2591+ if (m_cancelCurrentAction)
2592+ {
2593+ m_errorTitle = QObject::tr("Rename error: renaming to ")
2594+ + m_curAction->copyFile.targetName,
2595+ m_errorMsg = ::strerror(errno);
2596+ }
2597+ else
2598+ {
2599+ copySingleFileDone = true;
2600+ }
2601+ }
2602+ }
2603+ }
2604+
2605+ if (m_cancelCurrentAction)
2606+ {
2607+ if (m_curAction->copyFile.target)
2608+ {
2609+ m_curAction->copyFile.target->setAutoRemove(true);
2610+ }
2611+ m_curAction->copyFile.clear();
2612+ endActionEntry();
2613+ }
2614+ else
2615+ {
2616+ notifyProgress();
2617+ if (copySingleFileDone)
2618+ {
2619+ m_curAction->copyFile.clear();
2620+ //whem the whole copy could be done just in one call
2621+ //do not schedule to call copyEntry()
2622+ if (startBytes > 0)
2623+ {
2624+ //the whole took more than one call to copySingleFile()
2625+ scheduleSlot(SLOT(processCopyEntry()));
2626+ }
2627+ else
2628+ { //return normally to entry loop
2629+ scheduleAnySlot = false;
2630+ }
2631+ }
2632+ else
2633+ {
2634+ scheduleSlot(SLOT(processCopySingleFile()));
2635+ }
2636+ }
2637+
2638+ return scheduleAnySlot;
2639+}
2640+
2641+
2642+//================================================================================
2643+/*!
2644+ * \brief FileSystemAction::percentWorkDone() Compute the percent of work done
2645+ *
2646+ * Copy operations are based on bytes written while remove/move operations are based on items number
2647+ *
2648+ * \return the percent of work done
2649+ */
2650+int FileSystemAction::percentWorkDone()
2651+{
2652+ int percent = 0;
2653+ if (m_curAction->type != ActionCopy && m_curAction->type != ActionHardMoveCopy)
2654+ {
2655+ percent = (m_curAction->currItem * 100) / m_curAction->totalItems;
2656+ }
2657+ else
2658+ {
2659+ percent = (m_curAction->bytesWritten * 100) / m_curAction->totalBytes ;
2660+ }
2661+ if (percent > 100)
2662+ {
2663+ percent = 100;
2664+ }
2665+ return percent;
2666+}
2667+
2668+
2669+//================================================================================
2670+/*!
2671+ * \brief FileSystemAction::notifyProgress() Notify the progress signal
2672+ *
2673+ * \return the percent of work done
2674+ */
2675+int FileSystemAction::notifyProgress(int forcePercent)
2676+{
2677+ int percent = forcePercent > 0 ? forcePercent : percentWorkDone();
2678+ if (percent == 0)
2679+ {
2680+ percent = 1;
2681+ }
2682+ if (SHOULD_EMIT_PROGRESS_SIGNAL(m_curAction) && !m_curAction->done)
2683+ {
2684+ if (m_curAction->type == ActionHardMoveCopy ||
2685+ m_curAction->type ==ActionHardMoveRemove)
2686+ {
2687+ emit progress(m_curAction->currItem/2, m_curAction->totalItems/2, percent);
2688+ }
2689+ else
2690+ {
2691+ emit progress(m_curAction->currItem, m_curAction->totalItems, percent);
2692+ }
2693+ if (percent == 100 && m_curAction->currItem == m_curAction->totalItems)
2694+ {
2695+ m_curAction->done = true;
2696+ }
2697+ }
2698+ return percent;
2699+}
2700+
2701+//================================================================================
2702+/*!
2703+ * \brief FileSystemAction::copySymLink() creates the \a target as a link according to \a orig
2704+ * \param target full pathname of the file to be created
2705+ * \param orig original file, it carries the link that \a target will point to
2706+ * \return true if it could create, else if not
2707+ */
2708+bool FileSystemAction::copySymLink(const QString &target, const QFileInfo &orig)
2709+{
2710+ QString link(orig.symLinkTarget());
2711+ QFileInfo linkFile(link);
2712+ if (linkFile.isAbsolute() && linkFile.absolutePath() == orig.absolutePath())
2713+ {
2714+ link = linkFile.fileName();
2715+ }
2716+#if QT_VERSION <= 0x040704
2717+ QString current = QDir::currentPath();
2718+ QDir::setCurrent(linkFile.absolutePath());
2719+ bool ret = QFile::link(link, target);
2720+ QDir::setCurrent(current);
2721+#else
2722+ bool ret = QFile::link(link, target);
2723+#endif
2724+#if DEBUG_MESSAGES
2725+ qDebug() << "FileSystemAction::copySymLink" << ret << target << link;
2726+#endif
2727+ return ret;
2728+}
2729+
2730+//================================================================================
2731+void FileSystemAction::scheduleSlot(const char *slot)
2732+{
2733+#if DEBUG_MESSAGES
2734+ qDebug() << "FileSystemAction::scheduleSlot()" << slot;
2735+#endif
2736+ QTimer::singleShot(0, this, slot);
2737+}
2738+
2739+//================================================================================
2740+/*!
2741+ * \brief FileSystemAction::clipboardHasChanged() used to identify if the clipboard changed during a Cut operation
2742+ *
2743+ * \sa \ref endCurrentAction()
2744+ */
2745+void FileSystemAction::clipboardHasChanged()
2746+{
2747+ m_clipboardModifiedByOther = true;
2748+}
2749
2750=== added file 'folderlistmodel/filesystemaction.h'
2751--- folderlistmodel/filesystemaction.h 1970-01-01 00:00:00 +0000
2752+++ folderlistmodel/filesystemaction.h 2013-06-01 17:20:36 +0000
2753@@ -0,0 +1,212 @@
2754+/**************************************************************************
2755+ *
2756+ * Copyright 2013 Canonical Ltd.
2757+ * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com>
2758+ *
2759+ * You may use this file under the terms of the BSD license as follows:
2760+ *
2761+ * "Redistribution and use in source and binary forms, with or without
2762+ * modification, are permitted provided that the following conditions are
2763+ * met:
2764+ * * Redistributions of source code must retain the above copyright
2765+ * notice, this list of conditions and the following disclaimer.
2766+ * * Redistributions in binary form must reproduce the above copyright
2767+ * notice, this list of conditions and the following disclaimer in
2768+ * the documentation and/or other materials provided with the
2769+ * distribution.
2770+ * * Neither the name of Nemo Mobile nor the names of its contributors
2771+ * may be used to endorse or promote products derived from this
2772+ * software without specific prior written permission.
2773+ *
2774+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2775+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2776+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2777+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2778+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2779+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2780+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2781+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2782+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2783+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2784+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
2785+ *
2786+ * File: filesystemaction.h
2787+ * Date: 3/13/2013
2788+ */
2789+
2790+#ifndef FILESYSTEMACTION_H
2791+#define FILESYSTEMACTION_H
2792+
2793+
2794+#include <QObject>
2795+#include <QFileInfo>
2796+#include <QVector>
2797+
2798+class DirModelMimeData;
2799+class RemoveNotifier;
2800+class QFile;
2801+class QTemporaryFile;
2802+
2803+enum ClipboardOperation
2804+{
2805+ NoClipboard, ClipboardCopy, ClipboardCut
2806+};
2807+
2808+/*!
2809+ * \brief The FileSystemAction class
2810+ *
2811+ *
2812+ */
2813+class FileSystemAction : public QObject
2814+{
2815+ Q_OBJECT
2816+public:
2817+ explicit FileSystemAction(QObject *parent = 0);
2818+ ~FileSystemAction();
2819+public slots:
2820+ void cancel();
2821+ void remove(const QStringList & filePaths);
2822+ int clipboardLocalUrlsConunter();
2823+
2824+signals:
2825+ void error(const QString& errorTitle, const QString &errorMessage);
2826+ void removed(const QString& item); //must be sent to all Model instances
2827+ void removed(const QFileInfo&);
2828+ void added(const QString& );
2829+ void added(const QFileInfo& );
2830+ void progress(int curItem, int totalItems, int percent);
2831+ void clipboardChanged();
2832+
2833+public slots:
2834+ void pathChanged(const QString& path);
2835+ void paste();
2836+ void cut(const QStringList& );
2837+ void copy(const QStringList&);
2838+
2839+private slots:
2840+ void processAction();
2841+ void processActionEntry();
2842+ void processCopyEntry();
2843+ bool processCopySingleFile();
2844+ void clipboardHasChanged();
2845+
2846+#if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests
2847+ public:
2848+#else
2849+ private:
2850+#endif
2851+ enum ActionType
2852+ {
2853+ ActionRemove,
2854+ ActionCopy,
2855+ ActionMove,
2856+ ActionHardMoveCopy,
2857+ ActionHardMoveRemove
2858+ };
2859+ void createAndProcessAction(ActionType actionType, const QStringList& paths,
2860+ ClipboardOperation operation=NoClipboard);
2861+
2862+private:
2863+
2864+ struct CopyFile
2865+ {
2866+ public:
2867+ CopyFile() : bytesWritten(0), source(0), target(0) {}
2868+ ~CopyFile() { clear(); }
2869+ void clear();
2870+
2871+ qint64 bytesWritten; // set 0 when reach bytesToNotify, notify progress
2872+ QFile * source;
2873+ QTemporaryFile * target;
2874+ QString targetName;
2875+ };
2876+
2877+ /*!
2878+ An ActionEntry represents a high level item as a File or a Directory which an Action is required
2879+
2880+ For directories \a reversedOrder keeps all children
2881+ */
2882+ struct ActionEntry
2883+ {
2884+ public:
2885+ ActionEntry(): currStep(0),currItem(0),alreadyExists(false), newName(0) {}
2886+ ~ActionEntry()
2887+ {
2888+ reversedOrder.clear();
2889+ if (newName) { delete newName; }
2890+ }
2891+ QList<QFileInfo> reversedOrder; //!< last item must be the item from the list
2892+ int currStep;
2893+ int currItem;
2894+ bool alreadyExists;
2895+ QString * newName; //TODO: allow to rename an existent file when it already exists
2896+ };
2897+
2898+ struct Action
2899+ {
2900+ public:
2901+ ~Action() {qDeleteAll(entries); entries.clear(); copyFile.clear();}
2902+ ActionType type;
2903+ QList<ActionEntry*> entries;
2904+ int totalItems;
2905+ int currItem;
2906+ int baseOrigSize;
2907+ QString origPath;
2908+ QString targetPath;
2909+ quint64 totalBytes;
2910+ quint64 bytesWritten;
2911+ int currEntry;
2912+ ClipboardOperation operation;
2913+ CopyFile copyFile;
2914+ bool done;
2915+ };
2916+
2917+ QVector<Action*> m_queuedActions; //!< work always at item 0, after finishing taking item 0 out
2918+ Action * m_curAction;
2919+ bool m_cancelCurrentAction;
2920+ bool m_busy;
2921+ static RemoveNotifier m_removeNotifier;
2922+ QString m_path;
2923+ DirModelMimeData * m_mimeData;
2924+ QString m_errorTitle;
2925+ QString m_errorMsg;
2926+ bool m_clipboardModifiedByOther;
2927+
2928+private:
2929+ Action * createAction(ActionType, int origBase = 0);
2930+ void addEntry(Action* action, const QString &pathname);
2931+ void removeEntry(ActionEntry *);
2932+ void moveEntry(ActionEntry *entry);
2933+ bool moveUsingSameFileSystem(const QString& itemToMovePathname);
2934+ QString targetFom(const QString& origItem);
2935+ void endCurrentAction();
2936+ int percentWorkDone();
2937+ int notifyProgress(int forcePercent = 0);
2938+ void endActionEntry();
2939+ bool copySymLink(const QString& target, const QFileInfo& orig);
2940+ void scheduleSlot(const char *slot);
2941+};
2942+
2943+
2944+/*!
2945+ * \brief The RemoveNotifier is a utility class for \ref FileSystemAction to send
2946+ * notifications about removed files/dir
2947+ *
2948+ * This class must have a unique instance to notify all instances of \ref FileSystemAction and \ref DirModel
2949+ */
2950+class RemoveNotifier : public QObject
2951+{
2952+ Q_OBJECT
2953+
2954+ friend class FileSystemAction;
2955+private:
2956+ explicit RemoveNotifier(QObject *parent = 0);
2957+ void notifyRemoved(const QString& item);
2958+ void notifyRemoved(const QFileInfo& fi);
2959+
2960+signals:
2961+ void removed(const QString& item);
2962+ void removed(const QFileInfo&);
2963+};
2964+
2965+#endif // FILESYSTEMACTION_H
2966
2967=== added file 'folderlistmodel/folderlistmodel.pri'
2968--- folderlistmodel/folderlistmodel.pri 1970-01-01 00:00:00 +0000
2969+++ folderlistmodel/folderlistmodel.pri 2013-06-01 17:20:36 +0000
2970@@ -0,0 +1,26 @@
2971+SOURCES += $$PWD/dirmodel.cpp \
2972+ $$PWD/iorequest.cpp \
2973+ $$PWD/iorequestworker.cpp \
2974+ $$PWD/ioworkerthread.cpp \
2975+ $$PWD/filesystemaction.cpp \
2976+
2977+
2978+
2979+
2980+HEADERS += $$PWD/dirmodel.h \
2981+ $$PWD/iorequest.h \
2982+ $$PWD/iorequestworker.h \
2983+ $$PWD/ioworkerthread.h \
2984+ $$PWD/filesystemaction.h \
2985+
2986+
2987+
2988+INCLUDEPATH += $$PWD
2989+
2990+greaterThan(QT_MAJOR_VERSION, 4) {
2991+ QT += qml
2992+}
2993+else {
2994+ QT += declarative
2995+}
2996+
2997
2998=== added file 'folderlistmodel/folderlistmodel.pro'
2999--- folderlistmodel/folderlistmodel.pro 1970-01-01 00:00:00 +0000
3000+++ folderlistmodel/folderlistmodel.pro 2013-06-01 17:20:36 +0000
3001@@ -0,0 +1,39 @@
3002+TARGET = nemofolderlistmodel
3003+
3004+PLUGIN_IMPORT_PATH = org/nemomobile/folderlistmodel
3005+PLUGIN_URI = org.nemomobile.folderlistmodel
3006+
3007+# plugin.h and plugin.cpp use URI from PLUGIN_URI instead of hard coded
3008+DEFINES += PLUGIN_URI=$$PLUGIN_URI
3009+
3010+#core: sources + headers, separated here to use in regression test project
3011+include (folderlistmodel.pri)
3012+
3013+# Input
3014+SOURCES += plugin.cpp
3015+HEADERS += plugin.h
3016+
3017+## QApplication::clipboard() needs gui
3018+QT += gui
3019+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
3020+
3021+exists(../plugin.pri) {
3022+ include(../plugin.pri)
3023+}
3024+else {
3025+ TEMPLATE = lib
3026+ CONFIG += qt plugin hide_symbols
3027+ greaterThan(QT_MAJOR_VERSION, 4) {
3028+ QT += qml
3029+ }
3030+ else {
3031+ QT += declarative
3032+ }
3033+ target.path = $$[QT_INSTALL_QML]/$$PLUGIN_IMPORT_PATH
3034+ INSTALLS += target
3035+ qmldir.files += $$PWD/qmldir
3036+ qmldir.path += $$[QT_INSTALL_QML]/$$$$PLUGIN_IMPORT_PATH
3037+ INSTALLS += qmldir
3038+}
3039+
3040+
3041
3042=== added file 'folderlistmodel/iorequest.cpp'
3043--- folderlistmodel/iorequest.cpp 1970-01-01 00:00:00 +0000
3044+++ folderlistmodel/iorequest.cpp 2013-06-01 17:20:36 +0000
3045@@ -0,0 +1,36 @@
3046+/*
3047+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3048+ *
3049+ * You may use this file under the terms of the BSD license as follows:
3050+ *
3051+ * "Redistribution and use in source and binary forms, with or without
3052+ * modification, are permitted provided that the following conditions are
3053+ * met:
3054+ * * Redistributions of source code must retain the above copyright
3055+ * notice, this list of conditions and the following disclaimer.
3056+ * * Redistributions in binary form must reproduce the above copyright
3057+ * notice, this list of conditions and the following disclaimer in
3058+ * the documentation and/or other materials provided with the
3059+ * distribution.
3060+ * * Neither the name of Nemo Mobile nor the names of its contributors
3061+ * may be used to endorse or promote products derived from this
3062+ * software without specific prior written permission.
3063+ *
3064+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3065+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3066+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3067+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3068+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3069+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3070+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3071+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3072+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3073+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3074+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3075+ */
3076+
3077+#include "iorequest.h"
3078+
3079+IORequest::IORequest() : QObject()
3080+{
3081+}
3082
3083=== added file 'folderlistmodel/iorequest.h'
3084--- folderlistmodel/iorequest.h 1970-01-01 00:00:00 +0000
3085+++ folderlistmodel/iorequest.h 2013-06-01 17:20:36 +0000
3086@@ -0,0 +1,51 @@
3087+/*
3088+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3089+ *
3090+ * You may use this file under the terms of the BSD license as follows:
3091+ *
3092+ * "Redistribution and use in source and binary forms, with or without
3093+ * modification, are permitted provided that the following conditions are
3094+ * met:
3095+ * * Redistributions of source code must retain the above copyright
3096+ * notice, this list of conditions and the following disclaimer.
3097+ * * Redistributions in binary form must reproduce the above copyright
3098+ * notice, this list of conditions and the following disclaimer in
3099+ * the documentation and/or other materials provided with the
3100+ * distribution.
3101+ * * Neither the name of Nemo Mobile nor the names of its contributors
3102+ * may be used to endorse or promote products derived from this
3103+ * software without specific prior written permission.
3104+ *
3105+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3106+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3107+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3108+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3109+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3110+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3111+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3112+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3113+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3114+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3115+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3116+ */
3117+
3118+#ifndef IOREQUEST_H
3119+#define IOREQUEST_H
3120+
3121+#include <QObject>
3122+
3123+class IORequest : public QObject
3124+{
3125+ Q_OBJECT
3126+public:
3127+ explicit IORequest();
3128+
3129+public:
3130+ virtual void run() = 0;
3131+
3132+private:
3133+ // hide this because IORequest should *NOT* be parented directly
3134+ using QObject::setParent;
3135+};
3136+
3137+#endif // IOREQUEST_H
3138
3139=== added file 'folderlistmodel/iorequestworker.cpp'
3140--- folderlistmodel/iorequestworker.cpp 1970-01-01 00:00:00 +0000
3141+++ folderlistmodel/iorequestworker.cpp 2013-06-01 17:20:36 +0000
3142@@ -0,0 +1,94 @@
3143+/*
3144+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3145+ *
3146+ * You may use this file under the terms of the BSD license as follows:
3147+ *
3148+ * "Redistribution and use in source and binary forms, with or without
3149+ * modification, are permitted provided that the following conditions are
3150+ * met:
3151+ * * Redistributions of source code must retain the above copyright
3152+ * notice, this list of conditions and the following disclaimer.
3153+ * * Redistributions in binary form must reproduce the above copyright
3154+ * notice, this list of conditions and the following disclaimer in
3155+ * the documentation and/or other materials provided with the
3156+ * distribution.
3157+ * * Neither the name of Nemo Mobile nor the names of its contributors
3158+ * may be used to endorse or promote products derived from this
3159+ * software without specific prior written permission.
3160+ *
3161+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3162+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3163+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3164+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3165+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3166+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3167+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3168+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3169+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3170+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3171+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3172+ */
3173+
3174+#include "iorequestworker.h"
3175+#include "iorequest.h"
3176+
3177+#include <QMutexLocker>
3178+#include <QDebug>
3179+
3180+/*!
3181+ Lives on an IOWorkerThread.
3182+
3183+ Responsible for running IORequest jobs on the thread instance, and
3184+ disposing of their resources once they are done.
3185+ */
3186+IORequestWorker::IORequestWorker()
3187+ : QThread()
3188+ , mTimeToQuit(false)
3189+{
3190+}
3191+
3192+void IORequestWorker::addRequest(IORequest *request)
3193+{
3194+ request->moveToThread(this);
3195+
3196+ // TODO: queue requests so we run the most important one first
3197+ QMutexLocker lock(&mMutex);
3198+ mRequests.append(request);
3199+
3200+ // wake run()
3201+ mWaitCondition.wakeOne();
3202+}
3203+
3204+void IORequestWorker::run()
3205+{
3206+ forever {
3207+ QMutexLocker lock(&mMutex);
3208+
3209+ if (mTimeToQuit)
3210+ return;
3211+
3212+ if (mRequests.empty())
3213+ mWaitCondition.wait(&mMutex);
3214+
3215+ while (!mRequests.isEmpty()) {
3216+ IORequest *request = mRequests.takeFirst();
3217+
3218+ lock.unlock();
3219+
3220+ request->run();
3221+ request->deleteLater();
3222+
3223+ lock.relock();
3224+ }
3225+ }
3226+}
3227+
3228+void IORequestWorker::exit()
3229+{
3230+#if DEBUG_MESSAGES
3231+ qDebug() << Q_FUNC_INFO << "Quitting";
3232+#endif
3233+ QMutexLocker lock(&mMutex);
3234+ mTimeToQuit = true;
3235+ mWaitCondition.wakeOne();
3236+}
3237
3238=== added file 'folderlistmodel/iorequestworker.h'
3239--- folderlistmodel/iorequestworker.h 1970-01-01 00:00:00 +0000
3240+++ folderlistmodel/iorequestworker.h 2013-06-01 17:20:36 +0000
3241@@ -0,0 +1,61 @@
3242+/*
3243+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3244+ *
3245+ * You may use this file under the terms of the BSD license as follows:
3246+ *
3247+ * "Redistribution and use in source and binary forms, with or without
3248+ * modification, are permitted provided that the following conditions are
3249+ * met:
3250+ * * Redistributions of source code must retain the above copyright
3251+ * notice, this list of conditions and the following disclaimer.
3252+ * * Redistributions in binary form must reproduce the above copyright
3253+ * notice, this list of conditions and the following disclaimer in
3254+ * the documentation and/or other materials provided with the
3255+ * distribution.
3256+ * * Neither the name of Nemo Mobile nor the names of its contributors
3257+ * may be used to endorse or promote products derived from this
3258+ * software without specific prior written permission.
3259+ *
3260+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3261+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3262+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3263+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3264+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3265+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3266+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3267+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3268+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3269+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3270+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3271+ */
3272+
3273+#ifndef IOREQUESTWORKER_H
3274+#define IOREQUESTWORKER_H
3275+
3276+#include <QObject>
3277+#include <QThread>
3278+#include <QMutex>
3279+#include <QWaitCondition>
3280+
3281+#include "iorequest.h"
3282+
3283+class IORequestWorker : public QThread
3284+{
3285+ Q_OBJECT
3286+public:
3287+ explicit IORequestWorker();
3288+
3289+ void addRequest(IORequest *request);
3290+
3291+ void run();
3292+
3293+ void exit();
3294+
3295+private:
3296+ QMutex mMutex;
3297+ QWaitCondition mWaitCondition;
3298+ QList<IORequest *> mRequests;
3299+ bool mTimeToQuit;
3300+};
3301+
3302+#endif // IOREQUESTWORKER_H
3303
3304=== added file 'folderlistmodel/ioworkerthread.cpp'
3305--- folderlistmodel/ioworkerthread.cpp 1970-01-01 00:00:00 +0000
3306+++ folderlistmodel/ioworkerthread.cpp 2013-06-01 17:20:36 +0000
3307@@ -0,0 +1,64 @@
3308+/*
3309+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3310+ *
3311+ * You may use this file under the terms of the BSD license as follows:
3312+ *
3313+ * "Redistribution and use in source and binary forms, with or without
3314+ * modification, are permitted provided that the following conditions are
3315+ * met:
3316+ * * Redistributions of source code must retain the above copyright
3317+ * notice, this list of conditions and the following disclaimer.
3318+ * * Redistributions in binary form must reproduce the above copyright
3319+ * notice, this list of conditions and the following disclaimer in
3320+ * the documentation and/or other materials provided with the
3321+ * distribution.
3322+ * * Neither the name of Nemo Mobile nor the names of its contributors
3323+ * may be used to endorse or promote products derived from this
3324+ * software without specific prior written permission.
3325+ *
3326+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3327+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3328+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3329+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3330+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3331+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3332+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3333+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3334+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3335+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3336+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3337+ */
3338+
3339+#include "ioworkerthread.h"
3340+
3341+
3342+/*!
3343+ Hosts a thread, lives on the main thread.
3344+
3345+ Responsible for relaying interaction between the main thread and an IOWorkerThread.
3346+ */
3347+IOWorkerThread::IOWorkerThread(QObject *parent) :
3348+ QObject(parent)
3349+{
3350+ mWorker.start(QThread::IdlePriority);
3351+}
3352+
3353+/*!
3354+ Destroys an IOWorkerThread instance.
3355+ */
3356+IOWorkerThread::~IOWorkerThread()
3357+{
3358+ mWorker.exit();
3359+ mWorker.wait();
3360+}
3361+
3362+/*!
3363+ Attempts an asynchronous attempt to start a \a request.
3364+
3365+ If the request may be run, it is queued, and true is returned, otherwise, false.
3366+ */
3367+bool IOWorkerThread::addRequest(IORequest *request)
3368+{
3369+ mWorker.addRequest(request);
3370+ return true;
3371+}
3372
3373=== added file 'folderlistmodel/ioworkerthread.h'
3374--- folderlistmodel/ioworkerthread.h 1970-01-01 00:00:00 +0000
3375+++ folderlistmodel/ioworkerthread.h 2013-06-01 17:20:36 +0000
3376@@ -0,0 +1,52 @@
3377+/*
3378+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3379+ *
3380+ * You may use this file under the terms of the BSD license as follows:
3381+ *
3382+ * "Redistribution and use in source and binary forms, with or without
3383+ * modification, are permitted provided that the following conditions are
3384+ * met:
3385+ * * Redistributions of source code must retain the above copyright
3386+ * notice, this list of conditions and the following disclaimer.
3387+ * * Redistributions in binary form must reproduce the above copyright
3388+ * notice, this list of conditions and the following disclaimer in
3389+ * the documentation and/or other materials provided with the
3390+ * distribution.
3391+ * * Neither the name of Nemo Mobile nor the names of its contributors
3392+ * may be used to endorse or promote products derived from this
3393+ * software without specific prior written permission.
3394+ *
3395+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3396+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3397+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3398+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3399+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3400+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3401+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3402+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3403+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3404+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3405+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3406+ */
3407+
3408+#ifndef IOWORKERTHREAD_H
3409+#define IOWORKERTHREAD_H
3410+
3411+#include <QObject>
3412+#include <QThread>
3413+
3414+#include "iorequestworker.h"
3415+
3416+class IOWorkerThread : public QObject
3417+{
3418+ Q_OBJECT
3419+public:
3420+ explicit IOWorkerThread(QObject *parent = 0);
3421+ virtual ~IOWorkerThread();
3422+ bool addRequest(IORequest *request);
3423+
3424+private:
3425+ IORequestWorker mWorker;
3426+};
3427+
3428+#endif // IOWORKERTHREAD_H
3429
3430=== added file 'folderlistmodel/plugin.cpp'
3431--- folderlistmodel/plugin.cpp 1970-01-01 00:00:00 +0000
3432+++ folderlistmodel/plugin.cpp 2013-06-01 17:20:36 +0000
3433@@ -0,0 +1,53 @@
3434+/*
3435+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3436+ *
3437+ * You may use this file under the terms of the BSD license as follows:
3438+ *
3439+ * "Redistribution and use in source and binary forms, with or without
3440+ * modification, are permitted provided that the following conditions are
3441+ * met:
3442+ * * Redistributions of source code must retain the above copyright
3443+ * notice, this list of conditions and the following disclaimer.
3444+ * * Redistributions in binary form must reproduce the above copyright
3445+ * notice, this list of conditions and the following disclaimer in
3446+ * the documentation and/or other materials provided with the
3447+ * distribution.
3448+ * * Neither the name of Nemo Mobile nor the names of its contributors
3449+ * may be used to endorse or promote products derived from this
3450+ * software without specific prior written permission.
3451+ *
3452+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3453+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3454+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3455+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3456+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3457+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3458+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3459+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3460+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3461+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3462+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3463+ */
3464+
3465+#include <QVector>
3466+#include <QFileInfo>
3467+
3468+#include "plugin.h"
3469+
3470+NemoFolderListModelPlugin::NemoFolderListModelPlugin() { }
3471+
3472+NemoFolderListModelPlugin::~NemoFolderListModelPlugin() { }
3473+
3474+void NemoFolderListModelPlugin::initializeEngine(QmlEngine *engine, const char *uri)
3475+{
3476+ Q_UNUSED(engine)
3477+ Q_ASSERT(uri == QLatin1String(QUOTES(PLUGIN_URI)));
3478+}
3479+
3480+void NemoFolderListModelPlugin::registerTypes(const char *uri)
3481+{
3482+ Q_ASSERT(uri == QLatin1String(QUOTES(PLUGIN_URI)));
3483+ qRegisterMetaType<QVector<QFileInfo> >();
3484+ qmlRegisterType<DirModel>(uri, 1, 0, "FolderListModel");
3485+}
3486+
3487
3488=== added file 'folderlistmodel/plugin.h'
3489--- folderlistmodel/plugin.h 1970-01-01 00:00:00 +0000
3490+++ folderlistmodel/plugin.h 2013-06-01 17:20:36 +0000
3491@@ -0,0 +1,84 @@
3492+/*
3493+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3494+ *
3495+ * You may use this file under the terms of the BSD license as follows:
3496+ *
3497+ * "Redistribution and use in source and binary forms, with or without
3498+ * modification, are permitted provided that the following conditions are
3499+ * met:
3500+ * * Redistributions of source code must retain the above copyright
3501+ * notice, this list of conditions and the following disclaimer.
3502+ * * Redistributions in binary form must reproduce the above copyright
3503+ * notice, this list of conditions and the following disclaimer in
3504+ * the documentation and/or other materials provided with the
3505+ * distribution.
3506+ * * Neither the name of Nemo Mobile nor the names of its contributors
3507+ * may be used to endorse or promote products derived from this
3508+ * software without specific prior written permission.
3509+ *
3510+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3511+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3512+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3513+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3514+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3515+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3516+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3517+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3518+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3519+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3520+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3521+ */
3522+
3523+#ifndef NEMO_QML_PLUGINS_FOLDERLISTMODEL
3524+#define NEMO_QML_PLUGINS_FOLDERLISTMODEL
3525+
3526+#include <QtGlobal>
3527+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
3528+#include <QtDeclarative>
3529+#include <QDeclarativeEngine>
3530+#include <QDeclarativeExtensionPlugin>
3531+#include <QVector>
3532+#include <QFileInfo>
3533+
3534+#define PLUGIN_CLASS_EXPORT
3535+#define PLUGIN_CLASS_EXTERNAL_EXPORT Q_EXPORT_PLUGIN2(nemofolderlistmodel, NemoFolderListModelPlugin);
3536+#define PLUGIN_CLASS_EXTEND
3537+typedef QDeclarativeExtensionPlugin QmlPluginParent;
3538+typedef QDeclarativeEngine QmlEngine;
3539+Q_DECLARE_METATYPE(QVector<QFileInfo>)
3540+
3541+#else
3542+#include <QQmlComponent>
3543+#include <QQmlEngine>
3544+#include <QQmlContext>
3545+#include <QQmlExtensionPlugin>
3546+
3547+#define PLUGIN_CLASS_EXPORT Q_DECL_EXPORT
3548+#define PLUGIN_CLASS_EXTERNAL_EXPORT
3549+#define PLUGIN_CLASS_EXTEND \
3550+ Q_OBJECT \
3551+ Q_PLUGIN_METADATA(IID "org.nemomobile.folderlistmodel")
3552+typedef QQmlExtensionPlugin QmlPluginParent;
3553+typedef QQmlEngine QmlEngine;
3554+#endif
3555+
3556+#include "dirmodel.h"
3557+
3558+#define QUOTES(x) #x
3559+
3560+
3561+class PLUGIN_CLASS_EXPORT NemoFolderListModelPlugin : public QmlPluginParent
3562+{
3563+ PLUGIN_CLASS_EXTEND
3564+
3565+public:
3566+ NemoFolderListModelPlugin();
3567+ virtual ~NemoFolderListModelPlugin();
3568+
3569+ void initializeEngine(QmlEngine *engine, const char *uri);
3570+ void registerTypes(const char *uri);
3571+};
3572+
3573+PLUGIN_CLASS_EXTERNAL_EXPORT
3574+
3575+#endif // NEMO_QML_PLUGINS_FOLDERLISTMODEL
3576
3577=== added file 'folderlistmodel/qmldir'
3578--- folderlistmodel/qmldir 1970-01-01 00:00:00 +0000
3579+++ folderlistmodel/qmldir 2013-06-01 17:20:36 +0000
3580@@ -0,0 +1,1 @@
3581+plugin nemofolderlistmodel
3582
3583=== added directory 'nemo-folderlistmodel'
3584=== added file 'nemo-folderlistmodel/dirmodel.cpp'
3585--- nemo-folderlistmodel/dirmodel.cpp 1970-01-01 00:00:00 +0000
3586+++ nemo-folderlistmodel/dirmodel.cpp 2013-06-01 17:20:36 +0000
3587@@ -0,0 +1,385 @@
3588+/*
3589+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3590+ *
3591+ * You may use this file under the terms of the BSD license as follows:
3592+ *
3593+ * "Redistribution and use in source and binary forms, with or without
3594+ * modification, are permitted provided that the following conditions are
3595+ * met:
3596+ * * Redistributions of source code must retain the above copyright
3597+ * notice, this list of conditions and the following disclaimer.
3598+ * * Redistributions in binary form must reproduce the above copyright
3599+ * notice, this list of conditions and the following disclaimer in
3600+ * the documentation and/or other materials provided with the
3601+ * distribution.
3602+ * * Neither the name of Nemo Mobile nor the names of its contributors
3603+ * may be used to endorse or promote products derived from this
3604+ * software without specific prior written permission.
3605+ *
3606+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3607+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3608+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3609+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3610+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3611+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3612+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3613+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3614+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3615+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3616+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
3617+ */
3618+
3619+#include <QDirIterator>
3620+#include <QDir>
3621+#include <QDebug>
3622+#include <QDateTime>
3623+#include <QUrl>
3624+
3625+#include <errno.h>
3626+#include <string.h>
3627+
3628+#include "dirmodel.h"
3629+#include "ioworkerthread.h"
3630+
3631+Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread);
3632+
3633+class DirListWorker : public IORequest
3634+{
3635+ Q_OBJECT
3636+public:
3637+ DirListWorker(const QString &pathName)
3638+ : mPathName(pathName)
3639+ { }
3640+
3641+ void run()
3642+ {
3643+ qDebug() << Q_FUNC_INFO << "Running on: " << QThread::currentThreadId();
3644+
3645+ QDir tmpDir = QDir(mPathName);
3646+ QDirIterator it(tmpDir);
3647+ QVector<QFileInfo> directoryContents;
3648+
3649+ while (it.hasNext()) {
3650+ it.next();
3651+
3652+ // skip hidden files
3653+ if (it.fileName()[0] == QLatin1Char('.'))
3654+ continue;
3655+
3656+ directoryContents.append(it.fileInfo());
3657+ if (directoryContents.count() >= 50) {
3658+ emit itemsAdded(directoryContents);
3659+
3660+ // clear() would force a deallocation, micro-optimisation
3661+ directoryContents.erase(directoryContents.begin(), directoryContents.end());
3662+ }
3663+ }
3664+
3665+ // last batch
3666+ emit itemsAdded(directoryContents);
3667+
3668+ //std::sort(directoryContents.begin(), directoryContents.end(), DirModel::fileCompare);
3669+ }
3670+
3671+signals:
3672+ void itemsAdded(const QVector<QFileInfo> &files);
3673+
3674+private:
3675+ QString mPathName;
3676+};
3677+
3678+DirModel::DirModel(QObject *parent)
3679+ : QAbstractListModel(parent)
3680+ , mAwaitingResults(false)
3681+ , mShowDirectories(true)
3682+{
3683+ mNameFilters = QStringList() << "*";
3684+
3685+ QHash<int, QByteArray> roles = roleNames();
3686+ roles.insert(FileNameRole, QByteArray("fileName"));
3687+ roles.insert(CreationDateRole, QByteArray("creationDate"));
3688+ roles.insert(ModifiedDateRole, QByteArray("modifiedDate"));
3689+ roles.insert(FileSizeRole, QByteArray("fileSize"));
3690+ roles.insert(IconSourceRole, QByteArray("iconSource"));
3691+ roles.insert(FilePathRole, QByteArray("filePath"));
3692+ roles.insert(IsDirRole, QByteArray("isDir"));
3693+ roles.insert(IsFileRole, QByteArray("isFile"));
3694+ roles.insert(IsReadableRole, QByteArray("isReadable"));
3695+ roles.insert(IsWritableRole, QByteArray("isWritable"));
3696+ roles.insert(IsExecutableRole, QByteArray("isExecutable"));
3697+ setRoleNames(roles);
3698+
3699+ // populate reverse mapping
3700+ QHash<int, QByteArray>::ConstIterator it = roles.constBegin();
3701+ for (;it != roles.constEnd(); ++it)
3702+ mRoleMapping.insert(it.value(), it.key());
3703+
3704+ // make sure we cover all roles
3705+// Q_ASSERT(roles.count() == IsFileRole - FileNameRole);
3706+}
3707+
3708+QVariant DirModel::data(int row, const QByteArray &stringRole) const
3709+{
3710+ QHash<QByteArray, int>::ConstIterator it = mRoleMapping.constFind(stringRole);
3711+
3712+ if (it == mRoleMapping.constEnd())
3713+ return QVariant();
3714+
3715+ return data(index(row, 0), *it);
3716+}
3717+
3718+QVariant DirModel::data(const QModelIndex &index, int role) const
3719+{
3720+ if (role < FileNameRole || role > IsExecutableRole) {
3721+ qWarning() << Q_FUNC_INFO << "Got an out of range role: " << role;
3722+ return QVariant();
3723+ }
3724+
3725+ if (index.row() < 0 || index.row() >= mDirectoryContents.count()) {
3726+ qWarning() << "Attempted to access out of range row: " << index.row();
3727+ return QVariant();
3728+ }
3729+
3730+ if (index.column() != 0)
3731+ return QVariant();
3732+
3733+ const QFileInfo &fi = mDirectoryContents.at(index.row());
3734+
3735+ switch (role) {
3736+ case FileNameRole:
3737+ return fi.fileName();
3738+ case CreationDateRole:
3739+ return fi.created();
3740+ case ModifiedDateRole:
3741+ return fi.lastModified();
3742+ case FileSizeRole: {
3743+ qint64 kb = fi.size() / 1024;
3744+ if (kb < 1)
3745+ return QString::number(fi.size()) + " bytes";
3746+ else if (kb < 1024)
3747+ return QString::number(kb) + " kb";
3748+
3749+ kb /= 1024;
3750+ return QString::number(kb) + "mb";
3751+ }
3752+ case IconSourceRole: {
3753+ const QString &fileName = fi.fileName();
3754+
3755+ if (fi.isDir())
3756+ return "image://theme/icon-m-common-directory";
3757+
3758+ if (fileName.endsWith(".jpg", Qt::CaseInsensitive) ||
3759+ fileName.endsWith(".png", Qt::CaseInsensitive)) {
3760+ return "image://nemoThumbnail/" + fi.filePath();
3761+ }
3762+
3763+ return "image://theme/icon-m-content-document";
3764+ }
3765+ case FilePathRole:
3766+ return fi.filePath();
3767+ case IsDirRole:
3768+ return fi.isDir();
3769+ case IsFileRole:
3770+ return !fi.isDir();
3771+ case IsReadableRole:
3772+ return fi.isReadable();
3773+ case IsWritableRole:
3774+ return fi.isWritable();
3775+ case IsExecutableRole:
3776+ return fi.isExecutable();
3777+ default:
3778+ // this should not happen, ever
3779+ Q_ASSERT(false);
3780+ qWarning() << Q_FUNC_INFO << "Got an unknown role: " << role;
3781+ return QVariant();
3782+ }
3783+}
3784+
3785+void DirModel::setPath(const QString &pathName)
3786+{
3787+ if (pathName.isEmpty())
3788+ return;
3789+
3790+ if (mAwaitingResults) {
3791+ // TODO: handle the case where pathName != our current path, cancel old
3792+ // request, start a new one
3793+ qDebug() << Q_FUNC_INFO << "Ignoring path change request, request already running";
3794+ return;
3795+ }
3796+
3797+ mAwaitingResults = true;
3798+ emit awaitingResultsChanged();
3799+ qDebug() << Q_FUNC_INFO << "Changing to " << pathName << " on " << QThread::currentThreadId();
3800+
3801+ beginResetModel();
3802+ mDirectoryContents.clear();
3803+ endResetModel();
3804+
3805+ // TODO: we need to set a spinner active before we start getting results from DirListWorker
3806+ DirListWorker *dlw = new DirListWorker(pathName);
3807+ connect(dlw, SIGNAL(itemsAdded(QVector<QFileInfo>)), SLOT(onItemsAdded(QVector<QFileInfo>)));
3808+ ioWorkerThread()->addRequest(dlw);
3809+
3810+ mCurrentDir = pathName;
3811+ emit pathChanged();
3812+}
3813+
3814+static bool fileCompare(const QFileInfo &a, const QFileInfo &b)
3815+{
3816+ if (a.isDir() && !b.isDir())
3817+ return true;
3818+
3819+ if (b.isDir() && !a.isDir())
3820+ return false;
3821+
3822+ return QString::localeAwareCompare(a.fileName(), b.fileName()) < 0;
3823+}
3824+
3825+void DirModel::onItemsAdded(const QVector<QFileInfo> &newFiles)
3826+{
3827+ qDebug() << Q_FUNC_INFO << "Got new files: " << newFiles.count();
3828+
3829+ if (mAwaitingResults) {
3830+ qDebug() << Q_FUNC_INFO << "No longer awaiting results";
3831+ mAwaitingResults = false;
3832+ emit awaitingResultsChanged();
3833+ }
3834+
3835+ foreach (const QFileInfo &fi, newFiles) {
3836+ if (!mShowDirectories && fi.isDir())
3837+ continue;
3838+
3839+ bool doAdd = true;
3840+ foreach (const QString &nameFilter, mNameFilters) {
3841+ // TODO: using QRegExp for wildcard matching is slow
3842+ QRegExp re(nameFilter, Qt::CaseInsensitive, QRegExp::Wildcard);
3843+ if (!re.exactMatch(fi.fileName())) {
3844+ doAdd = false;
3845+ break;
3846+ }
3847+ }
3848+
3849+ if (!doAdd)
3850+ continue;
3851+
3852+ QVector<QFileInfo>::Iterator it = qLowerBound(mDirectoryContents.begin(),
3853+ mDirectoryContents.end(),
3854+ fi,
3855+ fileCompare);
3856+
3857+ if (it == mDirectoryContents.end()) {
3858+ beginInsertRows(QModelIndex(), mDirectoryContents.count(), mDirectoryContents.count());
3859+ mDirectoryContents.append(fi);
3860+ endInsertRows();
3861+ } else {
3862+ int idx = it - mDirectoryContents.begin();
3863+ beginInsertRows(QModelIndex(), idx, idx);
3864+ mDirectoryContents.insert(it, fi);
3865+ endInsertRows();
3866+ }
3867+ }
3868+}
3869+
3870+void DirModel::rm(const QStringList &paths)
3871+{
3872+ // TODO: handle directory deletions?
3873+ bool error = false;
3874+
3875+ foreach (const QString &path, paths) {
3876+ error |= QFile::remove(path);
3877+
3878+ if (error) {
3879+ qWarning() << Q_FUNC_INFO << "Failed to remove " << path;
3880+ error = false;
3881+ }
3882+ }
3883+
3884+ // TODO: just remove removed items; don't reload the entire model
3885+ refresh();
3886+}
3887+
3888+bool DirModel::rename(int row, const QString &newName)
3889+{
3890+ qDebug() << Q_FUNC_INFO << "Renaming " << row << " to " << newName;
3891+ Q_ASSERT(row >= 0 && row < mDirectoryContents.count());
3892+ if (row < 0 || row >= mDirectoryContents.count()) {
3893+ qWarning() << Q_FUNC_INFO << "Out of bounds access";
3894+ return false;
3895+ }
3896+
3897+ const QFileInfo &fi = mDirectoryContents.at(row);
3898+
3899+ if (!fi.isDir()) {
3900+ QFile f(fi.absoluteFilePath());
3901+ bool retval = f.rename(fi.absolutePath() + QDir::separator() + newName);
3902+
3903+ if (!retval)
3904+ qDebug() << Q_FUNC_INFO << "Rename returned error code: " << f.error() << f.errorString();
3905+ else
3906+ refresh();
3907+ // TODO: just change the affected item... ^^
3908+
3909+ return retval;
3910+ } else {
3911+ QDir d(fi.absoluteFilePath());
3912+ bool retval = d.rename(fi.absoluteFilePath(), fi.absolutePath() + QDir::separator() + newName);
3913+
3914+ // QDir has no way to detect what went wrong. woohoo!
3915+
3916+ // TODO: just change the affected item...
3917+ refresh();
3918+
3919+ return retval;
3920+ }
3921+
3922+ // unreachable (we hope)
3923+ Q_ASSERT(false);
3924+ return false;
3925+}
3926+
3927+void DirModel::mkdir(const QString &newDir)
3928+{
3929+ qDebug() << Q_FUNC_INFO << "Creating new folder " << newDir << " to " << mCurrentDir;
3930+
3931+ QDir dir(mCurrentDir);
3932+ bool retval = dir.mkdir(newDir);
3933+ if (!retval) {
3934+ const char *errorStr = strerror(errno);
3935+ qDebug() << Q_FUNC_INFO << "Error creating new directory: " << errno << " (" << errorStr << ")";
3936+ emit error("Error creating new folder", errorStr);
3937+ } else {
3938+ refresh();
3939+ }
3940+}
3941+
3942+bool DirModel::showDirectories() const
3943+{
3944+ return mShowDirectories;
3945+}
3946+
3947+void DirModel::setShowDirectories(bool showDirectories)
3948+{
3949+ mShowDirectories = showDirectories;
3950+ refresh();
3951+ emit showDirectoriesChanged();
3952+}
3953+
3954+QStringList DirModel::nameFilters() const
3955+{
3956+ return mNameFilters;
3957+}
3958+
3959+void DirModel::setNameFilters(const QStringList &nameFilters)
3960+{
3961+ mNameFilters = nameFilters;
3962+ refresh();
3963+ emit nameFiltersChanged();
3964+}
3965+
3966+bool DirModel::awaitingResults() const
3967+{
3968+ return mAwaitingResults;
3969+}
3970+
3971+// for dirlistworker
3972+#include "dirmodel.moc"
3973
3974=== added file 'nemo-folderlistmodel/dirmodel.h'
3975--- nemo-folderlistmodel/dirmodel.h 1970-01-01 00:00:00 +0000
3976+++ nemo-folderlistmodel/dirmodel.h 2013-06-01 17:20:36 +0000
3977@@ -0,0 +1,124 @@
3978+/*
3979+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3980+ *
3981+ * You may use this file under the terms of the BSD license as follows:
3982+ *
3983+ * "Redistribution and use in source and binary forms, with or without
3984+ * modification, are permitted provided that the following conditions are
3985+ * met:
3986+ * * Redistributions of source code must retain the above copyright
3987+ * notice, this list of conditions and the following disclaimer.
3988+ * * Redistributions in binary form must reproduce the above copyright
3989+ * notice, this list of conditions and the following disclaimer in
3990+ * the documentation and/or other materials provided with the
3991+ * distribution.
3992+ * * Neither the name of Nemo Mobile nor the names of its contributors
3993+ * may be used to endorse or promote products derived from this
3994+ * software without specific prior written permission.
3995+ *
3996+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3997+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3998+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3999+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4000+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4001+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4002+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4003+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4004+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4005+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4006+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4007+ */
4008+
4009+#ifndef DIRMODEL_H
4010+#define DIRMODEL_H
4011+
4012+#include <QAbstractListModel>
4013+#include <QFileInfo>
4014+#include <QVector>
4015+#include <QStringList>
4016+
4017+#include "iorequest.h"
4018+
4019+class DirModel : public QAbstractListModel
4020+{
4021+ Q_OBJECT
4022+
4023+ enum Roles {
4024+ FileNameRole = Qt::UserRole,
4025+ CreationDateRole,
4026+ ModifiedDateRole,
4027+ FileSizeRole,
4028+ IconSourceRole,
4029+ FilePathRole,
4030+ IsDirRole,
4031+ IsFileRole,
4032+ IsReadableRole,
4033+ IsWritableRole,
4034+ IsExecutableRole
4035+ };
4036+
4037+public:
4038+ DirModel(QObject *parent = 0);
4039+
4040+ int rowCount(const QModelIndex &index) const
4041+ {
4042+ if (index.parent() != QModelIndex())
4043+ return 0;
4044+
4045+ return mDirectoryContents.count();
4046+ }
4047+
4048+ // TODO: this won't be safe if the model can change under the holder of the row
4049+ Q_INVOKABLE QVariant data(int row, const QByteArray &stringRole) const;
4050+
4051+ QVariant data(const QModelIndex &index, int role) const;
4052+
4053+ Q_INVOKABLE void refresh()
4054+ {
4055+ // just some syntactical sugar really
4056+ setPath(path());
4057+ }
4058+
4059+ Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged);
4060+ inline QString path() const { return mCurrentDir; }
4061+
4062+ Q_PROPERTY(bool awaitingResults READ awaitingResults NOTIFY awaitingResultsChanged);
4063+ bool awaitingResults() const;
4064+
4065+ void setPath(const QString &pathName);
4066+
4067+ Q_INVOKABLE void rm(const QStringList &paths);
4068+
4069+ Q_INVOKABLE bool rename(int row, const QString &newName);
4070+
4071+ Q_INVOKABLE void mkdir(const QString &newdir);
4072+
4073+ Q_PROPERTY(bool showDirectories READ showDirectories WRITE setShowDirectories NOTIFY showDirectoriesChanged)
4074+ bool showDirectories() const;
4075+ void setShowDirectories(bool showDirectories);
4076+
4077+ Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
4078+ QStringList nameFilters() const;
4079+ void setNameFilters(const QStringList &nameFilters);
4080+
4081+public slots:
4082+ void onItemsAdded(const QVector<QFileInfo> &newFiles);
4083+
4084+signals:
4085+ void awaitingResultsChanged();
4086+ void nameFiltersChanged();
4087+ void showDirectoriesChanged();
4088+ void pathChanged();
4089+ void error(const QString &errorTitle, const QString &errorMessage);
4090+
4091+private:
4092+ QStringList mNameFilters;
4093+ bool mShowDirectories;
4094+ bool mAwaitingResults;
4095+ QString mCurrentDir;
4096+ QVector<QFileInfo> mDirectoryContents;
4097+ QHash<QByteArray, int> mRoleMapping;
4098+};
4099+
4100+
4101+#endif // DIRMODEL_H
4102
4103=== added file 'nemo-folderlistmodel/folderlistmodel.pro'
4104--- nemo-folderlistmodel/folderlistmodel.pro 1970-01-01 00:00:00 +0000
4105+++ nemo-folderlistmodel/folderlistmodel.pro 2013-06-01 17:20:36 +0000
4106@@ -0,0 +1,16 @@
4107+TARGET = nemofolderlistmodel
4108+PLUGIN_IMPORT_PATH = org/nemomobile/folderlistmodel
4109+
4110+SOURCES += plugin.cpp \
4111+ dirmodel.cpp \
4112+ iorequest.cpp \
4113+ iorequestworker.cpp \
4114+ ioworkerthread.cpp
4115+
4116+HEADERS += plugin.h \
4117+ dirmodel.h \
4118+ iorequest.h \
4119+ iorequestworker.h \
4120+ ioworkerthread.h
4121+
4122+include(../plugin.pri)
4123
4124=== added file 'nemo-folderlistmodel/iorequest.cpp'
4125--- nemo-folderlistmodel/iorequest.cpp 1970-01-01 00:00:00 +0000
4126+++ nemo-folderlistmodel/iorequest.cpp 2013-06-01 17:20:36 +0000
4127@@ -0,0 +1,36 @@
4128+/*
4129+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
4130+ *
4131+ * You may use this file under the terms of the BSD license as follows:
4132+ *
4133+ * "Redistribution and use in source and binary forms, with or without
4134+ * modification, are permitted provided that the following conditions are
4135+ * met:
4136+ * * Redistributions of source code must retain the above copyright
4137+ * notice, this list of conditions and the following disclaimer.
4138+ * * Redistributions in binary form must reproduce the above copyright
4139+ * notice, this list of conditions and the following disclaimer in
4140+ * the documentation and/or other materials provided with the
4141+ * distribution.
4142+ * * Neither the name of Nemo Mobile nor the names of its contributors
4143+ * may be used to endorse or promote products derived from this
4144+ * software without specific prior written permission.
4145+ *
4146+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4147+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4148+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4149+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4150+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4151+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4152+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4153+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4154+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4155+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4156+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4157+ */
4158+
4159+#include "iorequest.h"
4160+
4161+IORequest::IORequest() : QObject()
4162+{
4163+}
4164
4165=== added file 'nemo-folderlistmodel/iorequest.h'
4166--- nemo-folderlistmodel/iorequest.h 1970-01-01 00:00:00 +0000
4167+++ nemo-folderlistmodel/iorequest.h 2013-06-01 17:20:36 +0000
4168@@ -0,0 +1,51 @@
4169+/*
4170+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
4171+ *
4172+ * You may use this file under the terms of the BSD license as follows:
4173+ *
4174+ * "Redistribution and use in source and binary forms, with or without
4175+ * modification, are permitted provided that the following conditions are
4176+ * met:
4177+ * * Redistributions of source code must retain the above copyright
4178+ * notice, this list of conditions and the following disclaimer.
4179+ * * Redistributions in binary form must reproduce the above copyright
4180+ * notice, this list of conditions and the following disclaimer in
4181+ * the documentation and/or other materials provided with the
4182+ * distribution.
4183+ * * Neither the name of Nemo Mobile nor the names of its contributors
4184+ * may be used to endorse or promote products derived from this
4185+ * software without specific prior written permission.
4186+ *
4187+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4188+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4189+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4190+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4191+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4192+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4193+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4194+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4195+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4196+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4197+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4198+ */
4199+
4200+#ifndef IOREQUEST_H
4201+#define IOREQUEST_H
4202+
4203+#include <QObject>
4204+
4205+class IORequest : public QObject
4206+{
4207+ Q_OBJECT
4208+public:
4209+ explicit IORequest();
4210+
4211+public:
4212+ virtual void run() = 0;
4213+
4214+private:
4215+ // hide this because IORequest should *NOT* be parented directly
4216+ using QObject::setParent;
4217+};
4218+
4219+#endif // IOREQUEST_H
4220
4221=== added file 'nemo-folderlistmodel/iorequestworker.cpp'
4222--- nemo-folderlistmodel/iorequestworker.cpp 1970-01-01 00:00:00 +0000
4223+++ nemo-folderlistmodel/iorequestworker.cpp 2013-06-01 17:20:36 +0000
4224@@ -0,0 +1,92 @@
4225+/*
4226+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
4227+ *
4228+ * You may use this file under the terms of the BSD license as follows:
4229+ *
4230+ * "Redistribution and use in source and binary forms, with or without
4231+ * modification, are permitted provided that the following conditions are
4232+ * met:
4233+ * * Redistributions of source code must retain the above copyright
4234+ * notice, this list of conditions and the following disclaimer.
4235+ * * Redistributions in binary form must reproduce the above copyright
4236+ * notice, this list of conditions and the following disclaimer in
4237+ * the documentation and/or other materials provided with the
4238+ * distribution.
4239+ * * Neither the name of Nemo Mobile nor the names of its contributors
4240+ * may be used to endorse or promote products derived from this
4241+ * software without specific prior written permission.
4242+ *
4243+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4244+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4245+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4246+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4247+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4248+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4249+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4250+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4251+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4252+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4253+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4254+ */
4255+
4256+#include <QMutexLocker>
4257+#include <QDebug>
4258+
4259+#include "iorequestworker.h"
4260+#include "iorequest.h"
4261+
4262+/*!
4263+ Lives on an IOWorkerThread.
4264+
4265+ Responsible for running IORequest jobs on the thread instance, and
4266+ disposing of their resources once they are done.
4267+ */
4268+IORequestWorker::IORequestWorker()
4269+ : QThread()
4270+ , mTimeToQuit(false)
4271+{
4272+}
4273+
4274+void IORequestWorker::addRequest(IORequest *request)
4275+{
4276+ request->moveToThread(this);
4277+
4278+ // TODO: queue requests so we run the most important one first
4279+ QMutexLocker lock(&mMutex);
4280+ mRequests.append(request);
4281+
4282+ // wake run()
4283+ mWaitCondition.wakeOne();
4284+}
4285+
4286+void IORequestWorker::run()
4287+{
4288+ forever {
4289+ QMutexLocker lock(&mMutex);
4290+
4291+ if (mTimeToQuit)
4292+ return;
4293+
4294+ if (mRequests.empty())
4295+ mWaitCondition.wait(&mMutex);
4296+
4297+ while (!mRequests.isEmpty()) {
4298+ IORequest *request = mRequests.takeFirst();
4299+
4300+ lock.unlock();
4301+
4302+ request->run();
4303+ request->deleteLater();
4304+
4305+ lock.relock();
4306+ }
4307+ }
4308+}
4309+
4310+void IORequestWorker::exit()
4311+{
4312+ qDebug() << Q_FUNC_INFO << "Quitting";
4313+ QMutexLocker lock(&mMutex);
4314+ mTimeToQuit = true;
4315+ mWaitCondition.wakeOne();
4316+}
4317
4318=== added file 'nemo-folderlistmodel/iorequestworker.h'
4319--- nemo-folderlistmodel/iorequestworker.h 1970-01-01 00:00:00 +0000
4320+++ nemo-folderlistmodel/iorequestworker.h 2013-06-01 17:20:36 +0000
4321@@ -0,0 +1,61 @@
4322+/*
4323+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
4324+ *
4325+ * You may use this file under the terms of the BSD license as follows:
4326+ *
4327+ * "Redistribution and use in source and binary forms, with or without
4328+ * modification, are permitted provided that the following conditions are
4329+ * met:
4330+ * * Redistributions of source code must retain the above copyright
4331+ * notice, this list of conditions and the following disclaimer.
4332+ * * Redistributions in binary form must reproduce the above copyright
4333+ * notice, this list of conditions and the following disclaimer in
4334+ * the documentation and/or other materials provided with the
4335+ * distribution.
4336+ * * Neither the name of Nemo Mobile nor the names of its contributors
4337+ * may be used to endorse or promote products derived from this
4338+ * software without specific prior written permission.
4339+ *
4340+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4341+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4342+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4343+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4344+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4345+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4346+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4347+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4348+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4349+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4350+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4351+ */
4352+
4353+#ifndef IOREQUESTWORKER_H
4354+#define IOREQUESTWORKER_H
4355+
4356+#include <QObject>
4357+#include <QThread>
4358+#include <QMutex>
4359+#include <QWaitCondition>
4360+
4361+#include "iorequest.h"
4362+
4363+class IORequestWorker : public QThread
4364+{
4365+ Q_OBJECT
4366+public:
4367+ explicit IORequestWorker();
4368+
4369+ void addRequest(IORequest *request);
4370+
4371+ void run();
4372+
4373+ void exit();
4374+
4375+private:
4376+ QMutex mMutex;
4377+ QWaitCondition mWaitCondition;
4378+ QList<IORequest *> mRequests;
4379+ bool mTimeToQuit;
4380+};
4381+
4382+#endif // IOREQUESTWORKER_H
4383
4384=== added file 'nemo-folderlistmodel/ioworkerthread.cpp'
4385--- nemo-folderlistmodel/ioworkerthread.cpp 1970-01-01 00:00:00 +0000
4386+++ nemo-folderlistmodel/ioworkerthread.cpp 2013-06-01 17:20:36 +0000
4387@@ -0,0 +1,64 @@
4388+/*
4389+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
4390+ *
4391+ * You may use this file under the terms of the BSD license as follows:
4392+ *
4393+ * "Redistribution and use in source and binary forms, with or without
4394+ * modification, are permitted provided that the following conditions are
4395+ * met:
4396+ * * Redistributions of source code must retain the above copyright
4397+ * notice, this list of conditions and the following disclaimer.
4398+ * * Redistributions in binary form must reproduce the above copyright
4399+ * notice, this list of conditions and the following disclaimer in
4400+ * the documentation and/or other materials provided with the
4401+ * distribution.
4402+ * * Neither the name of Nemo Mobile nor the names of its contributors
4403+ * may be used to endorse or promote products derived from this
4404+ * software without specific prior written permission.
4405+ *
4406+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4407+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4408+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4409+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4410+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4411+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4412+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4413+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4414+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4415+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4416+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4417+ */
4418+
4419+#include "ioworkerthread.h"
4420+
4421+
4422+/*!
4423+ Hosts a thread, lives on the main thread.
4424+
4425+ Responsible for relaying interaction between the main thread and an IOWorkerThread.
4426+ */
4427+IOWorkerThread::IOWorkerThread(QObject *parent) :
4428+ QObject(parent)
4429+{
4430+ mWorker.start(QThread::IdlePriority);
4431+}
4432+
4433+/*!
4434+ Destroys an IOWorkerThread instance.
4435+ */
4436+IOWorkerThread::~IOWorkerThread()
4437+{
4438+ mWorker.exit();
4439+ mWorker.wait();
4440+}
4441+
4442+/*!
4443+ Attempts an asynchronous attempt to start a \a request.
4444+
4445+ If the request may be run, it is queued, and true is returned, otherwise, false.
4446+ */
4447+bool IOWorkerThread::addRequest(IORequest *request)
4448+{
4449+ mWorker.addRequest(request);
4450+ return true;
4451+}
4452
4453=== added file 'nemo-folderlistmodel/ioworkerthread.h'
4454--- nemo-folderlistmodel/ioworkerthread.h 1970-01-01 00:00:00 +0000
4455+++ nemo-folderlistmodel/ioworkerthread.h 2013-06-01 17:20:36 +0000
4456@@ -0,0 +1,52 @@
4457+/*
4458+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
4459+ *
4460+ * You may use this file under the terms of the BSD license as follows:
4461+ *
4462+ * "Redistribution and use in source and binary forms, with or without
4463+ * modification, are permitted provided that the following conditions are
4464+ * met:
4465+ * * Redistributions of source code must retain the above copyright
4466+ * notice, this list of conditions and the following disclaimer.
4467+ * * Redistributions in binary form must reproduce the above copyright
4468+ * notice, this list of conditions and the following disclaimer in
4469+ * the documentation and/or other materials provided with the
4470+ * distribution.
4471+ * * Neither the name of Nemo Mobile nor the names of its contributors
4472+ * may be used to endorse or promote products derived from this
4473+ * software without specific prior written permission.
4474+ *
4475+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4476+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4477+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4478+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4479+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4480+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4481+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4482+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4483+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4484+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4485+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4486+ */
4487+
4488+#ifndef IOWORKERTHREAD_H
4489+#define IOWORKERTHREAD_H
4490+
4491+#include <QObject>
4492+#include <QThread>
4493+
4494+#include "iorequestworker.h"
4495+
4496+class IOWorkerThread : public QObject
4497+{
4498+ Q_OBJECT
4499+public:
4500+ explicit IOWorkerThread(QObject *parent = 0);
4501+ virtual ~IOWorkerThread();
4502+ bool addRequest(IORequest *request);
4503+
4504+private:
4505+ IORequestWorker mWorker;
4506+};
4507+
4508+#endif // IOWORKERTHREAD_H
4509
4510=== added file 'nemo-folderlistmodel/plugin.cpp'
4511--- nemo-folderlistmodel/plugin.cpp 1970-01-01 00:00:00 +0000
4512+++ nemo-folderlistmodel/plugin.cpp 2013-06-01 17:20:36 +0000
4513@@ -0,0 +1,53 @@
4514+/*
4515+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
4516+ *
4517+ * You may use this file under the terms of the BSD license as follows:
4518+ *
4519+ * "Redistribution and use in source and binary forms, with or without
4520+ * modification, are permitted provided that the following conditions are
4521+ * met:
4522+ * * Redistributions of source code must retain the above copyright
4523+ * notice, this list of conditions and the following disclaimer.
4524+ * * Redistributions in binary form must reproduce the above copyright
4525+ * notice, this list of conditions and the following disclaimer in
4526+ * the documentation and/or other materials provided with the
4527+ * distribution.
4528+ * * Neither the name of Nemo Mobile nor the names of its contributors
4529+ * may be used to endorse or promote products derived from this
4530+ * software without specific prior written permission.
4531+ *
4532+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4533+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4534+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4535+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4536+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4537+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4538+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4539+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4540+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4541+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4542+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4543+ */
4544+
4545+#include <QVector>
4546+#include <QFileInfo>
4547+
4548+#include "plugin.h"
4549+
4550+NemoFolderListModelPlugin::NemoFolderListModelPlugin() { }
4551+
4552+NemoFolderListModelPlugin::~NemoFolderListModelPlugin() { }
4553+
4554+void NemoFolderListModelPlugin::initializeEngine(QmlEngine *engine, const char *uri)
4555+{
4556+ Q_UNUSED(engine)
4557+ Q_ASSERT(uri == QLatin1String("org.nemomobile.folderlistmodel"));
4558+}
4559+
4560+void NemoFolderListModelPlugin::registerTypes(const char *uri)
4561+{
4562+ Q_ASSERT(uri == QLatin1String("org.nemomobile.folderlistmodel"));
4563+ qRegisterMetaType<QVector<QFileInfo> >();
4564+ qmlRegisterType<DirModel>(uri, 1, 0, "FolderListModel");
4565+}
4566+
4567
4568=== added file 'nemo-folderlistmodel/plugin.h'
4569--- nemo-folderlistmodel/plugin.h 1970-01-01 00:00:00 +0000
4570+++ nemo-folderlistmodel/plugin.h 2013-06-01 17:20:36 +0000
4571@@ -0,0 +1,82 @@
4572+/*
4573+ * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
4574+ *
4575+ * You may use this file under the terms of the BSD license as follows:
4576+ *
4577+ * "Redistribution and use in source and binary forms, with or without
4578+ * modification, are permitted provided that the following conditions are
4579+ * met:
4580+ * * Redistributions of source code must retain the above copyright
4581+ * notice, this list of conditions and the following disclaimer.
4582+ * * Redistributions in binary form must reproduce the above copyright
4583+ * notice, this list of conditions and the following disclaimer in
4584+ * the documentation and/or other materials provided with the
4585+ * distribution.
4586+ * * Neither the name of Nemo Mobile nor the names of its contributors
4587+ * may be used to endorse or promote products derived from this
4588+ * software without specific prior written permission.
4589+ *
4590+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4591+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4592+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4593+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4594+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4595+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4596+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4597+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4598+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4599+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4600+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
4601+ */
4602+
4603+#ifndef NEMO_QML_PLUGINS_FOLDERLISTMODEL
4604+#define NEMO_QML_PLUGINS_FOLDERLISTMODEL
4605+
4606+#include <QtGlobal>
4607+
4608+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
4609+#include <QtDeclarative>
4610+#include <QDeclarativeEngine>
4611+#include <QDeclarativeExtensionPlugin>
4612+#include <QVector>
4613+#include <QFileInfo>
4614+
4615+#define PLUGIN_CLASS_EXPORT
4616+#define PLUGIN_CLASS_EXTERNAL_EXPORT Q_EXPORT_PLUGIN2(nemofolderlistmodel, NemoFolderListModelPlugin);
4617+#define PLUGIN_CLASS_EXTEND
4618+typedef QDeclarativeExtensionPlugin QmlPluginParent;
4619+typedef QDeclarativeEngine QmlEngine;
4620+Q_DECLARE_METATYPE(QVector<QFileInfo>)
4621+
4622+#else
4623+#include <QQmlComponent>
4624+#include <QQmlEngine>
4625+#include <QQmlContext>
4626+#include <QQmlExtensionPlugin>
4627+
4628+#define PLUGIN_CLASS_EXPORT Q_DECL_EXPORT
4629+#define PLUGIN_CLASS_EXTERNAL_EXPORT
4630+#define PLUGIN_CLASS_EXTEND \
4631+ Q_OBJECT \
4632+ Q_PLUGIN_METADATA(IID "org.nemomobile.folderlistmodel")
4633+typedef QQmlExtensionPlugin QmlPluginParent;
4634+typedef QQmlEngine QmlEngine;
4635+#endif
4636+
4637+#include "dirmodel.h"
4638+
4639+class PLUGIN_CLASS_EXPORT NemoFolderListModelPlugin : public QmlPluginParent
4640+{
4641+ PLUGIN_CLASS_EXTEND
4642+
4643+public:
4644+ NemoFolderListModelPlugin();
4645+ virtual ~NemoFolderListModelPlugin();
4646+
4647+ void initializeEngine(QmlEngine *engine, const char *uri);
4648+ void registerTypes(const char *uri);
4649+};
4650+
4651+PLUGIN_CLASS_EXTERNAL_EXPORT
4652+
4653+#endif // NEMO_QML_PLUGINS_FOLDERLISTMODEL
4654
4655=== added file 'nemo-folderlistmodel/qmldir'
4656--- nemo-folderlistmodel/qmldir 1970-01-01 00:00:00 +0000
4657+++ nemo-folderlistmodel/qmldir 2013-06-01 17:20:36 +0000
4658@@ -0,0 +1,1 @@
4659+plugin nemofolderlistmodel
4660
4661=== added directory 'test_folderlistmodel'
4662=== added directory 'test_folderlistmodel/regression'
4663=== added file 'test_folderlistmodel/regression/media_asx.h'
4664--- test_folderlistmodel/regression/media_asx.h 1970-01-01 00:00:00 +0000
4665+++ test_folderlistmodel/regression/media_asx.h 2013-06-01 17:20:36 +0000
4666@@ -0,0 +1,21 @@
4667+const unsigned char media_asx[] = {
4668+ 0x3c, 0x61, 0x73, 0x78, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
4669+ 0x3d, 0x22, 0x33, 0x2e, 0x30, 0x22, 0x3e, 0x0d, 0x0a, 0x3c, 0x65, 0x6e,
4670+ 0x74, 0x72, 0x79, 0x3e, 0x0d, 0x0a, 0x3c, 0x72, 0x65, 0x66, 0x20, 0x68,
4671+ 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
4672+ 0x72, 0x65, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x61, 0x62, 0x61, 0x63, 0x61,
4673+ 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77,
4674+ 0x61, 0x79, 0x2f, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e,
4675+ 0x61, 0x73, 0x70, 0x3f, 0x73, 0x63, 0x3d, 0x77, 0x74, 0x72, 0x78, 0x2d,
4676+ 0x66, 0x6d, 0x22, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x65, 0x6e,
4677+ 0x74, 0x72, 0x79, 0x3e, 0x0d, 0x0a, 0x3c, 0x65, 0x6e, 0x74, 0x72, 0x79,
4678+ 0x3e, 0x0d, 0x0a, 0x3c, 0x72, 0x65, 0x66, 0x20, 0x68, 0x72, 0x65, 0x66,
4679+ 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6d, 0x65, 0x64,
4680+ 0x69, 0x61, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x61, 0x64, 0x73,
4681+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x64,
4682+ 0x61, 0x74, 0x61, 0x2f, 0x72, 0x65, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61,
4683+ 0x73, 0x78, 0x2f, 0x57, 0x54, 0x52, 0x58, 0x2e, 0x61, 0x73, 0x78, 0x22,
4684+ 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x79,
4685+ 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x61, 0x73, 0x78, 0x3e, 0x0d, 0x0a
4686+};
4687+qint64 media_asx_len = 215;
4688
4689=== added file 'test_folderlistmodel/regression/media_xspf.h'
4690--- test_folderlistmodel/regression/media_xspf.h 1970-01-01 00:00:00 +0000
4691+++ test_folderlistmodel/regression/media_xspf.h 2013-06-01 17:20:36 +0000
4692@@ -0,0 +1,135 @@
4693+const unsigned char media_xspf[] = {
4694+ 0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
4695+ 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f,
4696+ 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x22,
4697+ 0x3f, 0x3e, 0x0a, 0x3c, 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74,
4698+ 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x22,
4699+ 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70,
4700+ 0x3a, 0x2f, 0x2f, 0x78, 0x73, 0x70, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
4701+ 0x6e, 0x73, 0x2f, 0x30, 0x2f, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73,
4702+ 0x3a, 0x76, 0x6c, 0x63, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
4703+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61,
4704+ 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x76, 0x6c, 0x63, 0x2f, 0x70, 0x6c,
4705+ 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x6e, 0x73, 0x2f, 0x30, 0x2f,
4706+ 0x22, 0x3e, 0x0a, 0x09, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x4c,
4707+ 0x69, 0x73, 0x74, 0x61, 0x20, 0x64, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72,
4708+ 0x6f, 0x64, 0x75, 0xc3, 0xa7, 0xc3, 0xa3, 0x6f, 0x3c, 0x2f, 0x74, 0x69,
4709+ 0x74, 0x6c, 0x65, 0x3e, 0x0a, 0x09, 0x3c, 0x74, 0x72, 0x61, 0x63, 0x6b,
4710+ 0x4c, 0x69, 0x73, 0x74, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4711+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74,
4712+ 0x72, 0x61, 0x63, 0x6b, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4713+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4714+ 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x4c, 0x69, 0x61, 0x6e, 0xc3,
4715+ 0xa7, 0x61, 0x2f, 0x45, 0x41, 0x45, 0x20, 0x70, 0x61, 0x72, 0x61, 0x20,
4716+ 0x61, 0x20, 0x53, 0x6f, 0x63, 0x69, 0x65, 0x64, 0x61, 0x64, 0x65, 0x3c,
4717+ 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
4718+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4719+ 0x20, 0x20, 0x3c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
4720+ 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f, 0x6d, 0x6e, 0x74, 0x2f,
4721+ 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x61, 0x75, 0x6c, 0x61, 0x73,
4722+ 0x2f, 0x45, 0x41, 0x45, 0x2f, 0x31, 0x31, 0x35, 0x25, 0x32, 0x30, 0x50,
4723+ 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x63, 0x61, 0x6f, 0x5f, 0x64, 0x6f,
4724+ 0x5f, 0x45, 0x73, 0x70, 0x69, 0x72, 0x69, 0x74, 0x69, 0x73, 0x6d, 0x6f,
4725+ 0x2f, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x73, 0x2f, 0x4f, 0x25, 0x32, 0x30,
4726+ 0x71, 0x75, 0x65, 0x25, 0x32, 0x30, 0x65, 0x25, 0x32, 0x30, 0x61, 0x25,
4727+ 0x32, 0x30, 0x45, 0x41, 0x45, 0x25, 0x32, 0x30, 0x31, 0x2e, 0x6d, 0x70,
4728+ 0x34, 0x3c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
4729+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4730+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4731+ 0x20, 0x3c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20,
4732+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3d,
4733+ 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
4734+ 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67,
4735+ 0x2f, 0x76, 0x6c, 0x63, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73,
4736+ 0x74, 0x2f, 0x30, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4737+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4738+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4739+ 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x69, 0x64, 0x3e, 0x30, 0x3c,
4740+ 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x69, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20,
4741+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4742+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76,
4743+ 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x73, 0x74,
4744+ 0x61, 0x72, 0x74, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x3d, 0x34, 0x35, 0x3c,
4745+ 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
4746+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4747+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4748+ 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f,
4749+ 0x6e, 0x3e, 0x73, 0x74, 0x6f, 0x70, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x3d,
4750+ 0x36, 0x39, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69,
4751+ 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4752+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4753+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70,
4754+ 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72,
4755+ 0x65, 0x65, 0x6e, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74,
4756+ 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4757+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4758+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f,
4759+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65,
4760+ 0x3d, 0x35, 0x30, 0x30, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70,
4761+ 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4762+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4763+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x65, 0x78, 0x74, 0x65,
4764+ 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
4765+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
4766+ 0x2f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x74,
4767+ 0x72, 0x61, 0x63, 0x6b, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4768+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4769+ 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x48, 0x69, 0x73, 0x74, 0x6f,
4770+ 0x72, 0x69, 0x61, 0x20, 0x64, 0x6f, 0x20, 0x45, 0x73, 0x70, 0x69, 0x72,
4771+ 0x69, 0x74, 0x69, 0x73, 0x6d, 0x6f, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c,
4772+ 0x65, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4773+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x6f,
4774+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x66, 0x69, 0x6c, 0x65, 0x3a,
4775+ 0x2f, 0x2f, 0x2f, 0x6d, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75,
4776+ 0x70, 0x2f, 0x61, 0x75, 0x6c, 0x61, 0x73, 0x2f, 0x45, 0x41, 0x45, 0x2f,
4777+ 0x31, 0x31, 0x35, 0x25, 0x32, 0x30, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67,
4778+ 0x61, 0x63, 0x61, 0x6f, 0x5f, 0x64, 0x6f, 0x5f, 0x45, 0x73, 0x70, 0x69,
4779+ 0x72, 0x69, 0x74, 0x69, 0x73, 0x6d, 0x6f, 0x2f, 0x76, 0x69, 0x64, 0x65,
4780+ 0x6f, 0x73, 0x2f, 0x4f, 0x25, 0x32, 0x30, 0x71, 0x75, 0x65, 0x25, 0x32,
4781+ 0x30, 0x65, 0x25, 0x32, 0x30, 0x61, 0x25, 0x32, 0x30, 0x45, 0x41, 0x45,
4782+ 0x25, 0x32, 0x30, 0x31, 0x2e, 0x6d, 0x70, 0x34, 0x3c, 0x2f, 0x6c, 0x6f,
4783+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c,
4784+ 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70,
4785+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x68,
4786+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69,
4787+ 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x76,
4788+ 0x6c, 0x63, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74, 0x2f,
4789+ 0x30, 0x22, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x76, 0x6c, 0x63,
4790+ 0x3a, 0x69, 0x64, 0x3e, 0x31, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x69,
4791+ 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4792+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4793+ 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74,
4794+ 0x69, 0x6f, 0x6e, 0x3e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x2d, 0x74, 0x69,
4795+ 0x6d, 0x65, 0x3d, 0x31, 0x39, 0x37, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a,
4796+ 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
4797+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4798+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76, 0x6c,
4799+ 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x73, 0x74, 0x6f,
4800+ 0x70, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x3d, 0x32, 0x36, 0x37, 0x3c, 0x2f,
4801+ 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a,
4802+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4803+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4804+ 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
4805+ 0x3e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x3c,
4806+ 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
4807+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4808+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4809+ 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f,
4810+ 0x6e, 0x3e, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x3d, 0x35, 0x30, 0x30,
4811+ 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
4812+ 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e,
4813+ 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x74, 0x72,
4814+ 0x61, 0x63, 0x6b, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x74, 0x72, 0x61, 0x63,
4815+ 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x65, 0x78, 0x74,
4816+ 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69,
4817+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70,
4818+ 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f,
4819+ 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x76, 0x6c, 0x63, 0x2f,
4820+ 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x30, 0x22, 0x3e,
4821+ 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x69, 0x74, 0x65,
4822+ 0x6d, 0x20, 0x74, 0x69, 0x64, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x2f, 0x3e,
4823+ 0x0a, 0x09, 0x3c, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
4824+ 0x6e, 0x3e, 0x0a, 0x3c, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73,
4825+ 0x74, 0x3e, 0x0a
4826+};
4827+qint64 media_xspf_len = 1575;
4828
4829=== added directory 'test_folderlistmodel/regression/mimetypes'
4830=== added file 'test_folderlistmodel/regression/mimetypes/LICENSE.LGPL'
4831--- test_folderlistmodel/regression/mimetypes/LICENSE.LGPL 1970-01-01 00:00:00 +0000
4832+++ test_folderlistmodel/regression/mimetypes/LICENSE.LGPL 2013-06-01 17:20:36 +0000
4833@@ -0,0 +1,504 @@
4834+ GNU LESSER GENERAL PUBLIC LICENSE
4835+ Version 2.1, February 1999
4836+
4837+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
4838+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
4839+ Everyone is permitted to copy and distribute verbatim copies
4840+ of this license document, but changing it is not allowed.
4841+
4842+[This is the first released version of the Lesser GPL. It also counts
4843+ as the successor of the GNU Library Public License, version 2, hence
4844+ the version number 2.1.]
4845+
4846+ Preamble
4847+
4848+ The licenses for most software are designed to take away your
4849+freedom to share and change it. By contrast, the GNU General Public
4850+Licenses are intended to guarantee your freedom to share and change
4851+free software--to make sure the software is free for all its users.
4852+
4853+ This license, the Lesser General Public License, applies to some
4854+specially designated software packages--typically libraries--of the
4855+Free Software Foundation and other authors who decide to use it. You
4856+can use it too, but we suggest you first think carefully about whether
4857+this license or the ordinary General Public License is the better
4858+strategy to use in any particular case, based on the explanations below.
4859+
4860+ When we speak of free software, we are referring to freedom of use,
4861+not price. Our General Public Licenses are designed to make sure that
4862+you have the freedom to distribute copies of free software (and charge
4863+for this service if you wish); that you receive source code or can get
4864+it if you want it; that you can change the software and use pieces of
4865+it in new free programs; and that you are informed that you can do
4866+these things.
4867+
4868+ To protect your rights, we need to make restrictions that forbid
4869+distributors to deny you these rights or to ask you to surrender these
4870+rights. These restrictions translate to certain responsibilities for
4871+you if you distribute copies of the library or if you modify it.
4872+
4873+ For example, if you distribute copies of the library, whether gratis
4874+or for a fee, you must give the recipients all the rights that we gave
4875+you. You must make sure that they, too, receive or can get the source
4876+code. If you link other code with the library, you must provide
4877+complete object files to the recipients, so that they can relink them
4878+with the library after making changes to the library and recompiling
4879+it. And you must show them these terms so they know their rights.
4880+
4881+ We protect your rights with a two-step method: (1) we copyright the
4882+library, and (2) we offer you this license, which gives you legal
4883+permission to copy, distribute and/or modify the library.
4884+
4885+ To protect each distributor, we want to make it very clear that
4886+there is no warranty for the free library. Also, if the library is
4887+modified by someone else and passed on, the recipients should know
4888+that what they have is not the original version, so that the original
4889+author's reputation will not be affected by problems that might be
4890+introduced by others.
4891+
4892
4893+ Finally, software patents pose a constant threat to the existence of
4894+any free program. We wish to make sure that a company cannot
4895+effectively restrict the users of a free program by obtaining a
4896+restrictive license from a patent holder. Therefore, we insist that
4897+any patent license obtained for a version of the library must be
4898+consistent with the full freedom of use specified in this license.
4899+
4900+ Most GNU software, including some libraries, is covered by the
4901+ordinary GNU General Public License. This license, the GNU Lesser
4902+General Public License, applies to certain designated libraries, and
4903+is quite different from the ordinary General Public License. We use
4904+this license for certain libraries in order to permit linking those
4905+libraries into non-free programs.
4906+
4907+ When a program is linked with a library, whether statically or using
4908+a shared library, the combination of the two is legally speaking a
4909+combined work, a derivative of the original library. The ordinary
4910+General Public License therefore permits such linking only if the
4911+entire combination fits its criteria of freedom. The Lesser General
4912+Public License permits more lax criteria for linking other code with
4913+the library.
4914+
4915+ We call this license the "Lesser" General Public License because it
4916+does Less to protect the user's freedom than the ordinary General
4917+Public License. It also provides other free software developers Less
4918+of an advantage over competing non-free programs. These disadvantages
4919+are the reason we use the ordinary General Public License for many
4920+libraries. However, the Lesser license provides advantages in certain
4921+special circumstances.
4922+
4923+ For example, on rare occasions, there may be a special need to
4924+encourage the widest possible use of a certain library, so that it becomes
4925+a de-facto standard. To achieve this, non-free programs must be
4926+allowed to use the library. A more frequent case is that a free
4927+library does the same job as widely used non-free libraries. In this
4928+case, there is little to gain by limiting the free library to free
4929+software only, so we use the Lesser General Public License.
4930+
4931+ In other cases, permission to use a particular library in non-free
4932+programs enables a greater number of people to use a large body of
4933+free software. For example, permission to use the GNU C Library in
4934+non-free programs enables many more people to use the whole GNU
4935+operating system, as well as its variant, the GNU/Linux operating
4936+system.
4937+
4938+ Although the Lesser General Public License is Less protective of the
4939+users' freedom, it does ensure that the user of a program that is
4940+linked with the Library has the freedom and the wherewithal to run
4941+that program using a modified version of the Library.
4942+
4943+ The precise terms and conditions for copying, distribution and
4944+modification follow. Pay close attention to the difference between a
4945+"work based on the library" and a "work that uses the library". The
4946+former contains code derived from the library, whereas the latter must
4947+be combined with the library in order to run.
4948+
4949
4950+ GNU LESSER GENERAL PUBLIC LICENSE
4951+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
4952+
4953+ 0. This License Agreement applies to any software library or other
4954+program which contains a notice placed by the copyright holder or
4955+other authorized party saying it may be distributed under the terms of
4956+this Lesser General Public License (also called "this License").
4957+Each licensee is addressed as "you".
4958+
4959+ A "library" means a collection of software functions and/or data
4960+prepared so as to be conveniently linked with application programs
4961+(which use some of those functions and data) to form executables.
4962+
4963+ The "Library", below, refers to any such software library or work
4964+which has been distributed under these terms. A "work based on the
4965+Library" means either the Library or any derivative work under
4966+copyright law: that is to say, a work containing the Library or a
4967+portion of it, either verbatim or with modifications and/or translated
4968+straightforwardly into another language. (Hereinafter, translation is
4969+included without limitation in the term "modification".)
4970+
4971+ "Source code" for a work means the preferred form of the work for
4972+making modifications to it. For a library, complete source code means
4973+all the source code for all modules it contains, plus any associated
4974+interface definition files, plus the scripts used to control compilation
4975+and installation of the library.
4976+
4977+ Activities other than copying, distribution and modification are not
4978+covered by this License; they are outside its scope. The act of
4979+running a program using the Library is not restricted, and output from
4980+such a program is covered only if its contents constitute a work based
4981+on the Library (independent of the use of the Library in a tool for
4982+writing it). Whether that is true depends on what the Library does
4983+and what the program that uses the Library does.
4984+
4985+ 1. You may copy and distribute verbatim copies of the Library's
4986+complete source code as you receive it, in any medium, provided that
4987+you conspicuously and appropriately publish on each copy an
4988+appropriate copyright notice and disclaimer of warranty; keep intact
4989+all the notices that refer to this License and to the absence of any
4990+warranty; and distribute a copy of this License along with the
4991+Library.
4992+
4993+ You may charge a fee for the physical act of transferring a copy,
4994+and you may at your option offer warranty protection in exchange for a
4995+fee.
4996+
4997
4998+ 2. You may modify your copy or copies of the Library or any portion
4999+of it, thus forming a work based on the Library, and copy and
5000+distribute such modifications or work under the terms of Section 1
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches