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
=== added directory 'folderlistmodel'
=== added file 'folderlistmodel/README'
--- folderlistmodel/README 1970-01-01 00:00:00 +0000
+++ folderlistmodel/README 2013-06-01 17:20:36 +0000
@@ -0,0 +1,6 @@
1Building and installing
2=======================
3
4qmake && make
5sudo make install
6
07
=== added file 'folderlistmodel/dirmodel.cpp'
--- folderlistmodel/dirmodel.cpp 1970-01-01 00:00:00 +0000
+++ folderlistmodel/dirmodel.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,1005 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include <errno.h>
33#include <string.h>
34#include "dirmodel.h"
35#include "ioworkerthread.h"
36#include "filesystemaction.h"
37
38#include <QDirIterator>
39#include <QDir>
40#include <QDebug>
41#include <QDateTime>
42#include <QFileIconProvider>
43#include <QUrl>
44#include <QDesktopServices>
45
46#if defined(REGRESSION_TEST_FOLDERLISTMODEL) || QT_VERSION >= 0x050000
47# include <QMimeType>
48# include <QMimeDatabase>
49#endif
50
51#define IS_VALID_ROW(row) (row >=0 && row < mDirectoryContents.count())
52#define WARN_ROW_OUT_OF_RANGE(row) qWarning() << Q_FUNC_INFO << "row" << row << "Out of bounds access"
53
54
55Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread)
56
57namespace {
58 QHash<QByteArray, int> roleMapping;
59}
60
61
62
63
64static bool fileCompareExists(const QFileInfo &a, const QFileInfo &b)
65{
66 if (a.isDir() && !b.isDir())
67 return true;
68
69 if (b.isDir() && !a.isDir())
70 return false;
71
72 bool ret = QString::localeAwareCompare(a.absoluteFilePath(), b.absoluteFilePath()) < 0;
73#if DEBUG_MESSAGES
74 qDebug() << Q_FUNC_INFO << ret << a.absoluteFilePath() << b.absoluteFilePath();
75#endif
76 return ret;
77}
78
79static bool fileCompareAscending(const QFileInfo &a, const QFileInfo &b)
80{
81 if (a.isDir() && !b.isDir())
82 return true;
83
84 if (b.isDir() && !a.isDir())
85 return false;
86
87 return QString::localeAwareCompare(a.fileName(), b.fileName()) < 0;
88}
89
90
91static bool fileCompareDescending(const QFileInfo &a, const QFileInfo &b)
92{
93 if (a.isDir() && !b.isDir())
94 return true;
95
96 if (b.isDir() && !a.isDir())
97 return false;
98
99 return QString::localeAwareCompare(a.fileName(), b.fileName()) > 0;
100}
101
102static bool dateCompareDescending(const QFileInfo &a, const QFileInfo &b)
103{
104 if (a.isDir() && !b.isDir())
105 return true;
106
107 if (b.isDir() && !a.isDir())
108 return false;
109
110 return a.lastModified() > b.lastModified();
111}
112
113static bool dateCompareAscending(const QFileInfo &a, const QFileInfo &b)
114{
115 if (a.isDir() && !b.isDir())
116 return true;
117
118 if (b.isDir() && !a.isDir())
119 return false;
120
121 return a.lastModified() < b.lastModified();
122}
123
124/*!
125 * Sort was originally done in \ref onItemsAdded() and that code is now in \ref addItem(),
126 * the reason to keep doing sort and do not let QDir does it is that when adding new items
127 * by \ref mkdir() or \paste() it is not necessary to call refresh() to load the entire directory
128 * to organize it items again. New items order/position are organized by \ref addItem()
129 *
130 */
131static CompareFunction availableCompareFunctions[2][2] =
132{
133 {fileCompareAscending, fileCompareDescending}
134 ,{dateCompareAscending, dateCompareDescending}
135};
136
137
138
139
140class DirListWorker : public IORequest
141{
142 Q_OBJECT
143public:
144 DirListWorker(const QString &pathName, QDir::Filter filter)
145 : mPathName(pathName)
146 , mFilter(filter)
147 { }
148
149 void run()
150 {
151#if DEBUG_MESSAGES
152 qDebug() << Q_FUNC_INFO << "Running on: " << QThread::currentThreadId();
153#endif
154
155 QDir tmpDir = QDir(mPathName, QString(), QDir::NoSort, mFilter);
156 QDirIterator it(tmpDir);
157 QVector<QFileInfo> directoryContents;
158
159 while (it.hasNext()) {
160 it.next();
161
162 directoryContents.append(it.fileInfo());
163 if (directoryContents.count() >= 50) {
164 emit itemsAdded(directoryContents);
165
166 // clear() would force a deallocation, micro-optimization
167 directoryContents.erase(directoryContents.begin(), directoryContents.end());
168 }
169 }
170
171 // last batch
172 emit itemsAdded(directoryContents);
173 emit workerFinished();
174 }
175
176signals:
177 void itemsAdded(const QVector<QFileInfo> &files);
178 void workerFinished();
179
180private:
181 QString mPathName;
182 QDir::Filter mFilter;
183};
184
185DirModel::DirModel(QObject *parent)
186 : QAbstractListModel(parent)
187 , mShowDirectories(true)
188 , mAwaitingResults(false)
189 , mShowHiddenFiles(false)
190 , mSortBy(SortByName)
191 , mSortOrder(SortAscending)
192 , mCompareFunction(0)
193 , m_fsAction(new FileSystemAction(this) )
194{
195 mNameFilters = QStringList() << "*";
196
197#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
198 // There's no setRoleNames in Qt5.
199 setRoleNames(buildRoleNames());
200#else
201 // In Qt5, the roleNames() is virtual and will work just fine.
202#endif
203
204 connect(m_fsAction, SIGNAL(progress(int,int,int)),
205 this, SIGNAL(progress(int,int,int)));
206
207 connect(m_fsAction, SIGNAL(added(QFileInfo)),
208 this, SLOT(onItemAdded(QFileInfo)));
209
210 connect(m_fsAction, SIGNAL(added(QString)),
211 this, SLOT(onItemAdded(QString)));
212
213 connect(m_fsAction, SIGNAL(removed(QFileInfo)),
214 this, SLOT(onItemRemoved(QFileInfo)));
215
216 connect(m_fsAction, SIGNAL(removed(QString)),
217 this, SLOT(onItemRemoved(QString)));
218
219 connect(m_fsAction, SIGNAL(error(QString,QString)),
220 this, SIGNAL(error(QString,QString)));
221
222 connect(this, SIGNAL(pathChanged(QString)),
223 m_fsAction, SLOT(pathChanged(QString)));
224
225 connect(m_fsAction, SIGNAL(clipboardChanged()),
226 this, SIGNAL(clipboardChanged()));
227
228 setCompareAndReorder();
229}
230
231DirModel::~DirModel()
232{
233}
234
235#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
236// roleNames has changed between Qt4 and Qt5. In Qt5 it is a virtual
237 // function and setRoleNames should not be used.
238QHash<int, QByteArray> DirModel::roleNames() const
239{
240 static QHash<int, QByteArray> roles;
241 if (roles.isEmpty()) {
242 roles = buildRoleNames();
243 }
244
245 return roles;
246}
247#endif
248
249QHash<int, QByteArray> DirModel::buildRoleNames() const
250{
251 QHash<int, QByteArray> roles;
252 roles.insert(FileNameRole, QByteArray("fileName"));
253 roles.insert(CreationDateRole, QByteArray("creationDate"));
254 roles.insert(ModifiedDateRole, QByteArray("modifiedDate"));
255 roles.insert(FileSizeRole, QByteArray("fileSize"));
256 roles.insert(IconSourceRole, QByteArray("iconSource"));
257 roles.insert(FilePathRole, QByteArray("filePath"));
258 roles.insert(IsDirRole, QByteArray("isDir"));
259 roles.insert(IsFileRole, QByteArray("isFile"));
260 roles.insert(IsReadableRole, QByteArray("isReadable"));
261 roles.insert(IsWritableRole, QByteArray("isWritable"));
262 roles.insert(IsExecutableRole, QByteArray("isExecutable"));
263
264 // populate reverse mapping
265 if (roleMapping.isEmpty()) {
266 QHash<int, QByteArray>::ConstIterator it = roles.constBegin();
267 for (;it != roles.constEnd(); ++it)
268 roleMapping.insert(it.value(), it.key());
269
270 // make sure we cover all roles
271 // Q_ASSERT(roles.count() == IsFileRole - FileNameRole);
272 }
273
274 return roles;
275}
276
277QVariant DirModel::data(int row, const QByteArray &stringRole) const
278{
279 QHash<QByteArray, int>::ConstIterator it = roleMapping.constFind(stringRole);
280
281 if (it == roleMapping.constEnd())
282 return QVariant();
283
284 return data(index(row, 0), *it);
285}
286
287QVariant DirModel::data(const QModelIndex &index, int role) const
288{
289#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
290 if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::DecorationRole) )
291 {
292 return QVariant();
293 }
294 if (role == Qt::DecorationRole)
295 {
296 if (index.column() == 0)
297 {
298 QMimeDatabase database;
299 QIcon icon;
300 QMimeType mime = database.mimeTypeForFile(mDirectoryContents.at(index.row()));
301 if (mime.isValid()) {
302 icon = QIcon::fromTheme(mime.iconName());
303 }
304 if (icon.isNull()) {
305 icon = QFileIconProvider().icon(mDirectoryContents.at(index.row()));
306 }
307 return icon;
308 }
309 return QVariant();
310 }
311 role = FileNameRole + index.column();
312#else
313 if (role < FileNameRole || role > IsExecutableRole) {
314 qWarning() << Q_FUNC_INFO << "Got an out of range role: " << role;
315 return QVariant();
316 }
317
318 if (index.row() < 0 || index.row() >= mDirectoryContents.count()) {
319 qWarning() << "Attempted to access out of range row: " << index.row();
320 return QVariant();
321 }
322
323 if (index.column() != 0)
324 return QVariant();
325#endif
326
327 const QFileInfo &fi = mDirectoryContents.at(index.row());
328
329 switch (role) {
330 case FileNameRole:
331 return fi.fileName();
332 case CreationDateRole:
333 return fi.created();
334 case ModifiedDateRole:
335 return fi.lastModified();
336 case FileSizeRole: {
337 if (fi.isDir())
338 {
339 return dirItems(fi);
340 }
341 return fileSize(fi.size());
342 }
343 case IconSourceRole: {
344 const QString &fileName = fi.fileName();
345
346 if (fi.isDir())
347 return QLatin1String("image://theme/icon-m-common-directory");
348
349 if (fileName.endsWith(QLatin1String(".jpg"), Qt::CaseInsensitive) ||
350 fileName.endsWith(QLatin1String(".png"), Qt::CaseInsensitive)) {
351 return QLatin1String("image://nemoThumbnail/") + fi.filePath();
352 }
353
354 return "image://theme/icon-m-content-document";
355 }
356 case FilePathRole:
357 return fi.filePath();
358 case IsDirRole:
359 return fi.isDir();
360 case IsFileRole:
361 return !fi.isDir();
362 case IsReadableRole:
363 return fi.isReadable();
364 case IsWritableRole:
365 return fi.isWritable();
366 case IsExecutableRole:
367 return fi.isExecutable();
368 default:
369#if !defined(REGRESSION_TEST_FOLDERLISTMODEL)
370 // this should not happen, ever
371 Q_ASSERT(false);
372 qWarning() << Q_FUNC_INFO << "Got an unknown role: " << role;
373#endif
374 return QVariant();
375 }
376}
377
378void DirModel::setPath(const QString &pathName)
379{
380 if (pathName.isEmpty())
381 return;
382
383 if (mAwaitingResults) {
384 // TODO: handle the case where pathName != our current path, cancel old
385 // request, start a new one
386 qDebug() << Q_FUNC_INFO << "Ignoring path change request, request already running";
387 return;
388 }
389
390 mAwaitingResults = true;
391 emit awaitingResultsChanged();
392#if DEBUG_MESSAGES
393 qDebug() << Q_FUNC_INFO << "Changing to " << pathName << " on " << QThread::currentThreadId();
394#endif
395 beginResetModel();
396 mDirectoryContents.clear();
397 endResetModel();
398
399 QDir::Filter dirFilter = currentDirFilter();
400 // TODO: we need to set a spinner active before we start getting results from DirListWorker
401 DirListWorker *dlw = new DirListWorker(pathName, dirFilter);
402 connect(dlw, SIGNAL(itemsAdded(QVector<QFileInfo>)), SLOT(onItemsAdded(QVector<QFileInfo>)));
403 connect(dlw, SIGNAL(workerFinished()), SLOT(onResultsFetched()));
404 ioWorkerThread()->addRequest(dlw);
405
406 mCurrentDir = pathName;
407 emit pathChanged(pathName);
408}
409
410
411void DirModel::onResultsFetched() {
412 if (mAwaitingResults) {
413#if DEBUG_MESSAGES
414 qDebug() << Q_FUNC_INFO << "No longer awaiting results";
415#endif
416 mAwaitingResults = false;
417 emit awaitingResultsChanged();
418 }
419}
420
421void DirModel::onItemsAdded(const QVector<QFileInfo> &newFiles)
422{
423#if DEBUG_MESSAGES
424 qDebug() << Q_FUNC_INFO << "Got new files: " << newFiles.count();
425#endif
426
427 foreach (const QFileInfo &fi, newFiles) {
428
429 bool doAdd = true;
430 foreach (const QString &nameFilter, mNameFilters) {
431 // TODO: using QRegExp for wildcard matching is slow
432 QRegExp re(nameFilter, Qt::CaseInsensitive, QRegExp::Wildcard);
433 if (!re.exactMatch(fi.fileName())) {
434 doAdd = false;
435 break;
436 }
437 }
438
439 if (!doAdd)
440 continue;
441
442 addItem(fi);
443 }
444}
445
446void DirModel::rm(const QStringList &paths)
447{
448 m_fsAction->remove(paths);
449}
450
451bool DirModel::rename(int row, const QString &newName)
452{
453#if DEBUG_MESSAGES
454 qDebug() << Q_FUNC_INFO << "Renaming " << row << " to " << newName;
455#endif
456
457 if (!IS_VALID_ROW(row)) {
458 WARN_ROW_OUT_OF_RANGE(row);
459 return false;
460 }
461
462 const QFileInfo &fi = mDirectoryContents.at(row);
463 QString newFullFilename(fi.absolutePath() + QDir::separator() + newName);
464
465 //QFile::rename() works for File and Dir
466 QFile f(fi.absoluteFilePath());
467 bool retval = f.rename(newFullFilename);
468 if (!retval)
469 {
470 qDebug() << Q_FUNC_INFO << "Rename returned error code: " << f.error() << f.errorString();
471 emit(QObject::tr("Rename error"), f.errorString());
472 }
473 else
474 {
475 mDirectoryContents[row] = QFileInfo(newFullFilename);
476 QModelIndex idx = createIndex(row,0);
477 emit dataChanged(idx, idx);
478 }
479 return retval;
480}
481
482void DirModel::mkdir(const QString &newDir)
483{
484 QDir dir(mCurrentDir);
485 bool retval = dir.mkdir(newDir);
486 if (!retval) {
487 const char *errorStr = strerror(errno);
488 qDebug() << Q_FUNC_INFO << "Error creating new directory: " << errno << " (" << errorStr << ")";
489 emit error(QObject::tr("Error creating new folder"), errorStr);
490 } else {
491 onItemAdded(dir.filePath(newDir));
492 }
493}
494
495bool DirModel::showDirectories() const
496{
497 return mShowDirectories;
498}
499
500void DirModel::setShowDirectories(bool showDirectories)
501{
502 mShowDirectories = showDirectories;
503 refresh();
504 emit showDirectoriesChanged();
505}
506
507QStringList DirModel::nameFilters() const
508{
509 return mNameFilters;
510}
511
512void DirModel::setNameFilters(const QStringList &nameFilters)
513{
514 mNameFilters = nameFilters;
515 refresh();
516 emit nameFiltersChanged();
517}
518
519bool DirModel::awaitingResults() const
520{
521 return mAwaitingResults;
522}
523
524
525QString DirModel::parentPath() const
526{
527 QDir dir(mCurrentDir);
528 if (dir.isRoot()) {
529 qDebug() << Q_FUNC_INFO << "already at root";
530 return mCurrentDir;
531 }
532
533 bool success = dir.cdUp();
534 if (!success) {
535 qWarning() << Q_FUNC_INFO << "Failed to to go to parent of " << mCurrentDir;
536 return mCurrentDir;
537 }
538 qDebug() << Q_FUNC_INFO << "returning" << dir.absolutePath();
539 return dir.absolutePath();
540}
541
542QString DirModel::homePath() const
543{
544 return QDir::homePath();
545}
546
547#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
548 QVariant DirModel::headerData(int section, Qt::Orientation orientation, int role) const
549 {
550 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
551 {
552 QVariant ret;
553 QHash<int, QByteArray> roles = this->roleNames();
554 section += FileNameRole;
555 if (roles.contains(section))
556 {
557 QString header= QString(roles.value(section));
558 ret = header;
559 }
560 return ret;
561 }
562 return QAbstractItemModel::headerData(section, orientation, role);
563 }
564#endif
565
566
567void DirModel::goHome()
568{
569 setPath(QDir::homePath());
570}
571
572
573bool DirModel::cdUp()
574{
575 int ret = false;
576 if (!mCurrentDir.isEmpty()) // we are in any dir
577 {
578 QDir current(mCurrentDir);
579 if (current.cdUp())
580 {
581 setPath(current.absolutePath());
582 ret = true;
583 }
584 }
585 return ret;
586}
587
588
589void DirModel::removeIndex(int row)
590{
591 if (IS_VALID_ROW(row))
592 {
593 const QFileInfo &fi = mDirectoryContents.at(row);
594 QStringList list(fi.absoluteFilePath());
595 this->rm(list);
596 }
597 else
598 {
599 WARN_ROW_OUT_OF_RANGE(row);
600 }
601}
602
603void DirModel::removePaths(const QStringList& items)
604{
605 this->rm(items);
606}
607
608void DirModel::copyIndex(int row)
609{
610 if (IS_VALID_ROW(row))
611 {
612 const QFileInfo &fi = mDirectoryContents.at(row);
613 QStringList list(fi.absoluteFilePath());
614 this->copyPaths(list);
615 }
616 else
617 {
618 WARN_ROW_OUT_OF_RANGE(row);
619 }
620}
621
622void DirModel::copyPaths(const QStringList &items)
623{
624 m_fsAction->copy(items);
625}
626
627
628void DirModel::cutIndex(int row)
629{
630 if (IS_VALID_ROW(row))
631 {
632 const QFileInfo &fi = mDirectoryContents.at(row);
633 QStringList list(fi.absoluteFilePath());
634 m_fsAction->cut(list);
635 }
636 else
637 {
638 WARN_ROW_OUT_OF_RANGE(row);
639 }
640}
641
642
643void DirModel::cutPaths(const QStringList &items)
644{
645 m_fsAction->cut(items);
646}
647
648
649void DirModel::paste()
650{
651 m_fsAction->paste();
652}
653
654
655bool DirModel::cdIntoIndex(int row)
656{
657 bool ret = false;
658 if (IS_VALID_ROW(row))
659 {
660 ret = cdInto(mDirectoryContents.at(row));
661 }
662 else
663 {
664 WARN_ROW_OUT_OF_RANGE(row);
665 }
666 return ret;
667}
668
669
670bool DirModel::cdIntoPath(const QString &filename)
671{
672 QFileInfo fi(filename);
673 if (fi.isRelative())
674 {
675 fi.setFile(mCurrentDir, filename);
676 }
677 return cdInto(fi);
678}
679
680
681bool DirModel::cdInto(const QFileInfo &fi)
682{
683 bool ret = false;
684 if (fi.exists() && fi.isDir() && fi.isReadable())
685 {
686 QDir childDir(mCurrentDir);
687 if ( childDir.cd(fi.fileName()) )
688 {
689 setPath(childDir.absolutePath());
690 ret = true;
691 }
692 }
693 return ret;
694}
695
696/*!
697 * \brief DirModel::onItemRemoved()
698 * \param pathname full pathname of removed file
699 */
700void DirModel::onItemRemoved(const QString &pathname)
701{
702 QFileInfo info(pathname);
703 onItemRemoved(info);
704}
705
706
707void DirModel::onItemRemoved(const QFileInfo &fi)
708{
709 int row = rowOfItem(fi);
710 if (row >= 0)
711 {
712 beginRemoveRows(QModelIndex(), row, row);
713 mDirectoryContents.remove(row,1);
714 endRemoveRows();
715 }
716}
717
718/*!
719 * \brief DirModel::onItemAdded()
720 * \param pathname full pathname of the added file
721 */
722void DirModel::onItemAdded(const QString &pathname)
723{
724 QFileInfo info(pathname);
725 onItemAdded(info);
726}
727
728
729void DirModel::onItemAdded(const QFileInfo &fi)
730{
731 int newRow = addItem(fi);
732 emit insertedRow(newRow);
733}
734
735/*!
736 * \brief DirModel::addItem() adds an item into the model
737 * This code was moved from onItemsAdded(const QVector<QFileInfo> &newFiles),
738 * the reason is: this code now is used for \ref mkdir() and for \ref paste() operations
739 * that inserts new items
740 * \param fi
741 * \return the index where it was inserted, it can be used in the view
742 * \sa insertedRow()
743 */
744int DirModel::addItem(const QFileInfo &fi)
745{
746 QVector<QFileInfo>::Iterator it = qLowerBound(mDirectoryContents.begin(),
747 mDirectoryContents.end(),
748 fi,
749 mCompareFunction);
750 int idx = mDirectoryContents.count();
751
752 if (it == mDirectoryContents.end()) {
753 beginInsertRows(QModelIndex(), mDirectoryContents.count(), mDirectoryContents.count());
754 mDirectoryContents.append(fi);
755 endInsertRows();
756 } else {
757 idx = it - mDirectoryContents.begin();
758 beginInsertRows(QModelIndex(), idx, idx);
759 mDirectoryContents.insert(it, fi);
760 endInsertRows();
761 }
762 return idx;
763}
764
765
766
767void DirModel::cancelAction()
768{
769 m_fsAction->cancel();
770}
771
772
773QString DirModel::fileSize(qint64 size) const
774{
775 struct UnitSizes
776 {
777 qint64 bytes;
778 const char *name;
779 };
780
781 static UnitSizes m_unitBytes[5] =
782 {
783 { 1, "Bytes" }
784 ,{1024, "KB"}
785 // got it from http://wiki.answers.com/Q/How_many_bytes_are_in_a_megabyte
786 ,{1000 * 1000, "MB"}
787 ,{1000 * m_unitBytes[2].bytes, "GB"}
788 ,{1000 * m_unitBytes[3].bytes, "TB"}
789 };
790
791 QString ret;
792 int unit = sizeof(m_unitBytes)/sizeof(m_unitBytes[0]);
793 while( unit-- > 1 && size < m_unitBytes[unit].bytes );
794 if (unit > 0 )
795 {
796 ret.sprintf("%0.1f %s", (float)size/m_unitBytes[unit].bytes,
797 m_unitBytes[unit].name);
798 }
799 else
800 {
801 ret.sprintf("%ld %s", (long int)size, m_unitBytes[0].name);
802 }
803 return ret;
804}
805
806
807
808bool DirModel::getShowHiddenFiles() const
809{
810 return mShowHiddenFiles;
811}
812
813
814void DirModel::setShowHiddenFiles(bool show)
815{
816 if (show != mShowHiddenFiles)
817 {
818 mShowHiddenFiles = show;
819 refresh();
820 emit showHiddenFilesChanged();
821 }
822}
823
824
825void DirModel::toggleShowDirectories()
826{
827 setShowDirectories(!mShowDirectories);
828}
829
830
831void DirModel::toggleShowHiddenFiles()
832{
833 setShowHiddenFiles(!mShowHiddenFiles);
834}
835
836
837DirModel::SortBy
838DirModel::getSortBy() const
839{
840 return mSortBy;
841}
842
843
844void DirModel::setSortBy(SortBy field)
845{
846 if (field != mSortBy)
847 {
848 mSortBy = field;
849 setCompareAndReorder();
850 emit sortByChanged();
851 }
852}
853
854
855DirModel::SortOrder
856DirModel::getSortOrder() const
857{
858 return mSortOrder;
859}
860
861void DirModel::setSortOrder(SortOrder order)
862{
863 if ( order != mSortOrder )
864 {
865 mSortOrder = order;
866 setCompareAndReorder();
867 emit sortOrderChanged();
868 }
869}
870
871
872void DirModel::toggleSortOrder()
873{
874 SortOrder order = static_cast<SortOrder> (mSortOrder ^ 1);
875 setSortOrder(order);
876}
877
878
879void DirModel::toggleSortBy()
880{
881 SortBy by = static_cast<SortBy> (mSortBy ^ 1);
882 setSortBy(by);
883}
884
885/*!
886 * \brief DirModel::setCompareAndReorder() called when SortOrder or SortBy change
887 *
888 * It does not reload items from disk, just reorganize items from \a mDirectoryContents array
889 */
890void DirModel::setCompareAndReorder()
891{
892 mCompareFunction = availableCompareFunctions[mSortBy][mSortOrder];
893 if (mDirectoryContents.count() > 0 && !mAwaitingResults )
894 {
895 QVector<QFileInfo> tmpDirectoryContents = mDirectoryContents;
896 beginResetModel();
897 mDirectoryContents.clear();
898 endResetModel();
899 for(int counter=0; counter < tmpDirectoryContents.count(); counter++)
900 {
901 addItem(tmpDirectoryContents.at(counter));
902 }
903 }
904}
905
906
907int DirModel::getClipboardUrlsCounter() const
908{
909 return m_fsAction->clipboardLocalUrlsConunter();
910}
911
912
913int DirModel::rowOfItem(const QFileInfo& fi)
914{
915 QVector<QFileInfo>::Iterator it = qBinaryFind(mDirectoryContents.begin(),
916 mDirectoryContents.end(),
917 fi,
918 fileCompareExists);
919 int row;
920 if (it == mDirectoryContents.end())
921 {
922 row = -1;
923 }
924 else
925 {
926 row = it - mDirectoryContents.begin();
927 }
928 return row;
929}
930
931
932QDir::Filter DirModel::currentDirFilter() const
933{
934 int filter = QDir::AllEntries | QDir::NoDotAndDotDot ;
935 if (!mShowDirectories)
936 {
937 filter &= ~QDir::AllDirs;
938 filter &= ~QDir::Dirs;
939 }
940 if (mShowHiddenFiles)
941 {
942 filter |= QDir::Hidden;
943 }
944 QDir::Filter dirFilter = static_cast<QDir::Filter>(filter);
945 return dirFilter;
946}
947
948QString DirModel::dirItems(const QFileInfo& fi) const
949{
950 int counter = 0;
951 QDir d(fi.absoluteFilePath(), QString(), QDir::NoSort, currentDirFilter());
952 counter = d.count();
953 if (counter < 0)
954 {
955 counter = 0;
956 }
957 QString ret (QString::number(counter) + QLatin1Char(' '));
958 ret += QObject::tr("items");
959 return ret;
960}
961
962
963bool DirModel::openIndex(int row)
964{
965 bool ret = false;
966 if (IS_VALID_ROW(row))
967 {
968 ret = openItem(mDirectoryContents.at(row));
969 }
970 else
971 {
972 WARN_ROW_OUT_OF_RANGE(row);
973 }
974 return ret;
975}
976
977bool DirModel::openPath(const QString &filename)
978{
979 QFileInfo fi(filename);
980 if (fi.isRelative())
981 {
982 fi.setFile(mCurrentDir, filename);
983 }
984 return openItem(fi);
985}
986
987bool DirModel::openItem(const QFileInfo &fi)
988{
989 bool ret = false;
990 if (fi.exists())
991 {
992 if (fi.isDir())
993 {
994 ret = cdInto(fi);
995 }
996 else
997 {
998 ret = QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absoluteFilePath()));
999 }
1000 }
1001 return ret;
1002}
1003
1004// for dirlistworker
1005#include "dirmodel.moc"
01006
=== added file 'folderlistmodel/dirmodel.h'
--- folderlistmodel/dirmodel.h 1970-01-01 00:00:00 +0000
+++ folderlistmodel/dirmodel.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,328 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef DIRMODEL_H
33#define DIRMODEL_H
34
35#include <QAbstractListModel>
36#include <QFileInfo>
37#include <QVector>
38#include <QStringList>
39#include <QDir>
40
41#include "iorequest.h"
42
43class FileSystemAction;
44typedef bool (*CompareFunction)(const QFileInfo &a, const QFileInfo &b);
45
46class DirModel : public QAbstractListModel
47{
48 Q_OBJECT
49public:
50 enum Roles {
51 FileNameRole = Qt::UserRole,
52 CreationDateRole,
53 ModifiedDateRole,
54 FileSizeRole,
55 IconSourceRole,
56 FilePathRole,
57 IsDirRole,
58 IsFileRole,
59 IsReadableRole,
60 IsWritableRole,
61 IsExecutableRole
62 };
63
64public:
65 explicit DirModel(QObject *parent = 0);
66 ~DirModel();
67
68 int rowCount(const QModelIndex &index = QModelIndex()) const
69 {
70 if (index.parent() != QModelIndex())
71 return 0;
72 return mDirectoryContents.count();
73 }
74
75 // TODO: this won't be safe if the model can change under the holder of the row
76 Q_INVOKABLE QVariant data(int row, const QByteArray &stringRole) const;
77
78 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
79
80 Q_INVOKABLE void refresh()
81 {
82 // just some syntactical sugar really
83 setPath(path());
84 }
85
86 Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
87 inline QString path() const { return mCurrentDir; }
88 void setPath(const QString &pathName);
89
90 Q_PROPERTY(bool awaitingResults READ awaitingResults NOTIFY awaitingResultsChanged)
91 bool awaitingResults() const;
92
93 Q_INVOKABLE void rm(const QStringList &paths);
94
95 Q_INVOKABLE bool rename(int row, const QString &newName);
96
97 Q_INVOKABLE void mkdir(const QString &newdir);
98
99 Q_PROPERTY(bool showDirectories READ showDirectories WRITE setShowDirectories NOTIFY showDirectoriesChanged)
100 bool showDirectories() const;
101
102 Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
103 QStringList nameFilters() const;
104 void setNameFilters(const QStringList &nameFilters);
105
106public slots:
107 void onItemsAdded(const QVector<QFileInfo> &newFiles);
108 void onResultsFetched();
109
110signals:
111 void awaitingResultsChanged();
112 void nameFiltersChanged();
113 void showDirectoriesChanged();
114 void pathChanged(const QString& newPath);
115 void error(const QString &errorTitle, const QString &errorMessage);
116
117private:
118 QHash<int, QByteArray> buildRoleNames() const;
119#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
120 // In Qt5, the roleNames() is virtual and will work just fine. On qt4 setRoleNames must be used with buildRoleNames.
121 QHash<int, QByteArray> roleNames() const;
122#endif
123
124 QStringList mNameFilters;
125 bool mShowDirectories;
126 bool mAwaitingResults;
127 QString mCurrentDir;
128 QVector<QFileInfo> mDirectoryContents;
129
130public:
131 //[0] new stuff Ubuntu File Manager
132#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
133 //make this work with tables
134 virtual int columnCount(const QModelIndex &) const
135 {
136 return IsExecutableRole - FileNameRole + 1;
137 }
138 virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
139#endif
140
141 Q_PROPERTY(QString parentPath READ parentPath NOTIFY pathChanged)
142 QString parentPath() const;
143
144 Q_PROPERTY(bool showHiddenFiles READ getShowHiddenFiles WRITE setShowHiddenFiles NOTIFY showHiddenFilesChanged)
145 bool getShowHiddenFiles() const;
146
147 Q_ENUMS(SortBy)
148 enum SortBy
149 {
150 SortByName,
151 SortByDate
152 };
153 Q_PROPERTY(SortBy sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged)
154 SortBy getSortBy() const;
155
156 Q_ENUMS(SortOrder)
157 enum SortOrder
158 {
159 SortAscending = Qt::AscendingOrder,
160 SortDescending = Qt::DescendingOrder
161 };
162 Q_PROPERTY(SortOrder sortOrder READ getSortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
163 SortOrder getSortOrder() const;
164
165 Q_PROPERTY(int clipboardUrlsCounter READ getClipboardUrlsCounter NOTIFY clipboardChanged)
166 int getClipboardUrlsCounter() const;
167
168 Q_INVOKABLE QString homePath() const;
169
170 /*!
171 * \brief Tries to make the directory pointed by row as the current to be browsed
172 * \return true if row points to a directory and the directory is readble, false otherwise
173 */
174 Q_INVOKABLE bool cdIntoIndex(int row);
175
176 Q_INVOKABLE bool cdIntoPath(const QString& filename);
177 /*!
178 * \brief copyIndex() puts the item pointed by \a row (dir or file) into the clipboard
179 * \param row points to the item file or directory
180 */
181 Q_INVOKABLE void copyIndex(int row);
182
183 /*!
184 * \brief copyPaths(const QStringList& urls) several items (dirs or files) into the clipboard
185 * \param items fullpathnames or names only
186 */
187 Q_INVOKABLE void copyPaths(const QStringList& items);
188
189 /*!
190 * \brief cutIndex() puts the item into the clipboard as \ref copy(),
191 * mark the item to be removed after \ref paste()
192 * \param row points to the item file or directory
193 */
194 Q_INVOKABLE void cutIndex(int row);
195
196 /*!
197 * \brief cut() puts several items (dirs or files) into the clipboard as \ref copy(),
198 * mark the item to be removed after \ref paste()
199 * \param items fullpathnames or names only
200 */
201 Q_INVOKABLE void cutPaths(const QStringList& items);
202
203 /*!
204 * \brief removeIndex(); remove a item file or directory
205 *
206 * I gets the item indicated by \row and calls \ref rm()
207 *
208 * \param row points to the item to b e removed
209 * \return true if it was possible to remove the item
210 */
211 Q_INVOKABLE void removeIndex(int row);
212
213 /*!
214 * Just calls \ref rm()
215 */
216 Q_INVOKABLE void removePaths(const QStringList& items);
217
218 /*!
219 * Tries to open a file using a suitable application, if the index points to a directory
220 * it goes into it using \ref cdIntoIndex() or \ref cdIntoPath()
221 *
222 * \note Qt uses Qt QDesktopServices::openUrl()
223 */
224
225 Q_INVOKABLE bool openIndex(int row);
226 /*!
227 * Same as \ref openIndex() but using a file name instead of index
228 *
229 * \sa \ref cdIntoPath()
230 */
231 Q_INVOKABLE bool openPath(const QString& filename);
232
233public slots:
234 /*!
235 * \brief goHome() goes to user home dir
236 * Go to user home dir, we may have a tab for places or something like that
237 */
238 void goHome();
239
240 /*!
241 * \brief cdUp() sets the parent directory as current directory
242 *
243 * It can work as a back function if there is no user input path
244 * \return true if it was possible to change to parent dir, otherwise false
245 */
246 bool cdUp();
247
248 /*!
249 * \brief paste() copy item(s) from \ref copy() and \ref paste() into the current directory
250 *
251 * If the operation was \ref cut(), then remove the original item
252 */
253 void paste();
254
255 /*!
256 * \brief cancelAction() any copy/cut/remove can be cancelled
257 */
258 void cancelAction();
259
260 void setShowDirectories(bool showDirectories);
261 void setShowHiddenFiles(bool show);
262 void setSortBy(SortBy field);
263 void setSortOrder(SortOrder order);
264
265 void toggleShowDirectories();
266 void toggleShowHiddenFiles();
267 void toggleSortOrder();
268 void toggleSortBy();
269
270signals:
271 /*!
272 * \brief insertedItem()
273 *
274 * It happens when a new file is inserted in an existent view,
275 * for example from \ref mkdir() or \ref paste()
276 *
277 * It can be used to make the new row visible to the user doing a scroll to
278 */
279 void insertedRow(int row);
280 /*!
281 * \brief progress()
282 * Sends status about recursive and multi-items remove/move/copy
283 *
284 * \param curItem current item being handled
285 * \param totalItems total of items including recursive directories content
286 * \param percent a percent done
287 */
288 void progress(int curItem, int totalItems, int percent);
289
290 void showHiddenFilesChanged();
291 void sortByChanged();
292 void sortOrderChanged();
293
294 void clipboardChanged();
295
296private slots:
297 void onItemRemoved(const QString&);
298 void onItemRemoved(const QFileInfo&);
299 void onItemAdded(const QString&);
300 void onItemAdded(const QFileInfo&);
301
302private:
303 int addItem(const QFileInfo& fi);
304 void setCompareAndReorder();
305 int rowOfItem(const QFileInfo& fi);
306 QDir::Filter currentDirFilter() const;
307 QString dirItems(const QFileInfo& fi) const;
308 bool cdInto(const QFileInfo& fi);
309 bool openItem(const QFileInfo& fi);
310
311private:
312 bool mShowHiddenFiles;
313 SortBy mSortBy;
314 SortOrder mSortOrder;
315 CompareFunction mCompareFunction;
316
317#if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests
318public:
319#else
320private:
321#endif
322 FileSystemAction * m_fsAction; //!< it does file system recursive remove/copy/move
323 QString fileSize(qint64 size) const;
324//[0]
325};
326
327
328#endif // DIRMODEL_H
0329
=== added file 'folderlistmodel/filesystemaction.cpp'
--- folderlistmodel/filesystemaction.cpp 1970-01-01 00:00:00 +0000
+++ folderlistmodel/filesystemaction.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,1389 @@
1/**************************************************************************
2 *
3 * Copyright 2013 Canonical Ltd.
4 * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com>
5 *
6 * You may use this file under the terms of the BSD license as follows:
7 *
8 * "Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Nemo Mobile nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
32 *
33 * File: filesystemaction.cpp
34 * Date: 3/13/2013
35 */
36
37#include "filesystemaction.h"
38#include <sys/statvfs.h>
39#include <errno.h>
40
41#include <QDirIterator>
42#include <QDebug>
43#include <QTimer>
44#include <QMimeData>
45#include <QClipboard>
46#include <QApplication>
47#include <QUrl>
48#include <QFileInfo>
49#include <QDir>
50#include <QThread>
51#include <QTemporaryFile>
52
53#define STEP_FILES 5 // number of the files to work on a step, when this number is reached a signal is emitted
54
55#define SHOULD_EMIT_PROGRESS_SIGNAL(action) (1)
56
57#define COMMON_SIZE_ITEM 120
58
59RemoveNotifier FileSystemAction::m_removeNotifier;
60
61static QLatin1String GNOME_COPIED_MIME_TYPE ("x-special/gnome-copied-files");
62static QLatin1String KDE_CUT_MIME_TYPE ("application/x-kde-cutselection");
63
64
65
66class DirModelMimeData : public QMimeData
67{
68public:
69 enum ClipBoardDataOwner
70 {
71 Nobody, // might have failed
72 Application,
73 MySelf
74 };
75
76 explicit DirModelMimeData();
77 ~DirModelMimeData();
78 virtual QStringList formats() const { return m_formats; }
79 virtual bool hasFormat ( const QString & mimeType ) const;
80public:
81 ClipBoardDataOwner setIntoClipboard(const QStringList& files,
82 const QString &path,
83 ClipboardOperation operation);
84 const QMimeData *clipboardMimeData();
85 QStringList localUrls(ClipboardOperation& operation);
86private:
87 static QList<QUrl> gnomeUrls(const QMimeData *mime, ClipboardOperation& operation);
88 ClipboardOperation clipBoardOperation();
89 bool fillClipboard(const QStringList& files, const QString &path, ClipboardOperation operation);
90private:
91 QStringList m_formats;
92 const QMimeData * m_appMime;
93 QByteArray gnomeData;
94 QList<QUrl> urls;
95 static DirModelMimeData* m_globalMimeData; //!< some mobile devices do not use X, they may not have clipboard
96 static int instances;
97};
98
99
100int DirModelMimeData::instances = 0;
101DirModelMimeData* DirModelMimeData::m_globalMimeData = 0;
102
103void FileSystemAction::CopyFile::clear()
104{
105 bytesWritten = 0;
106 if (source) delete source;
107 if (target) delete target;
108 source = 0;
109 target = 0;
110}
111
112bool DirModelMimeData::hasFormat ( const QString & mimeType ) const
113{
114 bool ret = false;
115 if ( mimeType == KDE_CUT_MIME_TYPE )
116 {
117 ret = true;
118 }
119 else
120 {
121 ret = m_formats.contains(mimeType);
122 }
123 return ret;
124}
125
126//===============================================================================================
127/*!
128 * \brief DirModelMimeData::DirModelMimeData
129 */
130DirModelMimeData::DirModelMimeData() :
131 QMimeData()
132 , m_appMime(0)
133{
134 m_formats.append("text/uri-list");
135 m_formats.append(GNOME_COPIED_MIME_TYPE);
136 m_formats.append("text/plain");
137 m_formats.append("COMPOUND_TEXT");
138 m_formats.append("TARGETS");
139 m_formats.append("MULTIPLE");
140 m_formats.append("TIMESTAMP");
141 m_formats.append("SAVE_TARGETS");
142
143 ++instances;
144#if DEBUG_MESSAGES
145 qDebug() << Q_FUNC_INFO << this << "instances" << instances;
146#endif
147}
148
149
150
151
152DirModelMimeData::~DirModelMimeData()
153{
154 --instances;
155#if DEBUG_MESSAGES
156 qDebug() << Q_FUNC_INFO << this << "instances" << instances
157 << "m_globalMimeData" << m_globalMimeData;
158#endif
159 if (instances == 1 && m_globalMimeData)
160 {
161 DirModelMimeData * tmp = m_globalMimeData;
162 m_globalMimeData = 0;
163 delete tmp;
164 }
165}
166
167//===============================================================================================
168/*!
169 * \brief DirModelMimeData::gnomeUrls
170 * \param mime
171 * \param operation
172 * \return
173 */
174QList<QUrl>
175DirModelMimeData::gnomeUrls(const QMimeData * mime,
176 ClipboardOperation& operation)
177{
178 QList<QUrl> urls;
179 if (mime->hasFormat(GNOME_COPIED_MIME_TYPE))
180 {
181 QByteArray bytes = mime->data(GNOME_COPIED_MIME_TYPE);
182 QList<QString> d = QString(bytes).split(QLatin1String("\r\n"),
183 QString::SkipEmptyParts);
184 for (int counter= 0; counter < d.count(); counter++)
185 {
186 if (counter==0)
187 {
188 QStringList couple = d.at(0).split(QLatin1Char('\n'));
189 urls.append(couple[1]);
190 if (couple[0] == QLatin1String("cut")) {
191 operation = ClipboardCut;
192 }
193 else {
194 operation = ClipboardCopy;
195 }
196 }
197 else {
198 urls.append(d.at(counter));
199 }
200 }
201 }
202 return urls;
203}
204
205//===============================================================================================
206/*!
207 * \brief DirModelMimeData::clipBoardOperation()
208 * \param mime
209 * \return
210 */
211ClipboardOperation DirModelMimeData::clipBoardOperation()
212{
213 ClipboardOperation op = ClipboardCopy;
214 m_appMime = clipboardMimeData();
215 if (m_appMime)
216 {
217 //first check for GNOME clipboard format, op comes with Copy/Cut
218 if (gnomeUrls(m_appMime, op).count() == 0)
219 { // there is no gnome format, tries KDE format
220 QStringList formats = m_appMime->formats();
221 int f = formats.count();
222 while(f--)
223 {
224 const QString &mi = formats.at(f);
225 if(mi.startsWith(QLatin1String("application/x-kde")) )
226 {
227 if (mi.contains(QLatin1String("cut")))
228 {
229 op = ClipboardCut;
230 break;
231 }
232 }
233 }
234 }
235 }
236 return op;
237}
238
239
240//===============================================================================================
241/*!
242 * \brief DirModelMimeData::setIntoClipboard
243 *
244 * Try to put data in the global cliboard
245 *
246 * \note:
247 * On mobile devices clipboard might not work, in this case a local Clipboard is simulated
248 *
249 * \param files
250 * \param path
251 * \param isCut
252 * \return who is owner of clipboard data
253 */
254DirModelMimeData::ClipBoardDataOwner
255DirModelMimeData::setIntoClipboard(const QStringList &files, const QString& path, ClipboardOperation operation)
256{
257 DirModelMimeData::ClipBoardDataOwner ret = Nobody;
258 QClipboard *clipboard = QApplication::clipboard();
259 if (clipboard)
260 {
261 ret = Application;
262 DirModelMimeData *mime = m_globalMimeData ? m_globalMimeData
263 : new DirModelMimeData();
264 if (mime->fillClipboard(files, path, operation))
265 {
266 clipboard->setMimeData(mime);
267 const QMimeData *data = clipboard->mimeData();
268 //it looks like some mobile devices does not have X
269 //in this case we simulate our own clipboard
270 if (!data && !m_globalMimeData)
271 {
272 m_globalMimeData = mime;
273 }
274#if DEBUG_MESSAGES
275 qDebug() << Q_FUNC_INFO << "mime" << mime << "clipboard->mimeData()" << data
276 << "m_ownClipboardMimeData" << m_globalMimeData;
277#endif
278 }
279 else
280 if (m_globalMimeData != mime)
281 {
282 delete mime;
283 }
284 //check if it is necessary to send notification about Clipboard changed
285 if (m_globalMimeData)
286 {
287 ret = MySelf;
288 }
289 }
290 return ret;
291}
292
293
294bool DirModelMimeData::fillClipboard(const QStringList& files, const QString &path, ClipboardOperation operation)
295{
296 bool ret = false;
297 int index = m_formats.indexOf(KDE_CUT_MIME_TYPE);
298 if (index != -1 && operation != ClipboardCut)
299 {
300 m_formats.removeAt(index);
301 }
302 else
303 if (operation == ClipboardCut)
304 {
305 m_formats.append(KDE_CUT_MIME_TYPE);
306 }
307
308 urls.clear();
309 QFileInfo fi;
310 gnomeData.clear();
311 gnomeData += operation == ClipboardCut ?
312 QLatin1String("cut\n") :
313 QLatin1String("copy\n");
314 for(int counter = 0; counter < files.count(); counter++)
315 {
316 const QString& item = files.at(counter);
317 fi.setFile(item);
318 if (!fi.isAbsolute())
319 {
320 fi.setFile(path + QDir::separator() + item);
321 }
322 if (fi.exists())
323 {
324 QUrl item = QUrl::fromLocalFile(fi.absoluteFilePath());
325 urls.append(item);
326 gnomeData += item.toEncoded() + QLatin1String("\r\n");
327 }
328 else
329 {
330 // emit error( QObject::tr("Item does not exist"), item);
331 urls.clear();
332 break;
333 }
334 }
335 if (urls.count() > 0)
336 {
337 setData(GNOME_COPIED_MIME_TYPE, gnomeData);
338 setUrls(urls);
339 ret = true;
340 }
341 return ret;
342}
343
344//===============================================================================================
345/*!
346 * \brief DirModelMimeData::clipboardMimeData
347 * \return
348 */
349const QMimeData *DirModelMimeData::clipboardMimeData()
350{
351 const QMimeData *ret = 0;
352 QClipboard *clipboard = QApplication::clipboard();
353 if (m_globalMimeData)
354 {
355 ret = m_globalMimeData;
356 }
357 else
358 if (clipboard)
359 {
360 ret = clipboard->mimeData();
361 }
362#if DEBUG_MESSAGES
363 qDebug() << Q_FUNC_INFO << "clipboard" << clipboard
364 << "m_ownClipboardMimeData" << m_globalMimeData
365 << "clipboard->mimeData()" << ret;
366#endif
367 return ret;
368}
369
370//===============================================================================================
371/*!
372 * \brief DirModelMimeData::localUrls
373 * \return
374 */
375QStringList
376DirModelMimeData::localUrls(ClipboardOperation& operation)
377{
378 m_appMime = clipboardMimeData();
379 QStringList paths;
380 //it may have external urls
381 if (m_appMime)
382 {
383 QList<QUrl> urls;
384 if (m_appMime->hasUrls())
385 {
386 urls = m_appMime->urls();
387 operation = clipBoardOperation();
388 }
389 else
390 {
391 urls = gnomeUrls(m_appMime, operation);
392 }
393 for (int counter=0; counter < urls.count(); counter++)
394 {
395 if (urls.at(counter).toString().startsWith(QLatin1String("file://")))
396 {
397 paths.append(urls.at(counter).toLocalFile());
398 }
399 }
400 }
401#if DEBUG_MESSAGES
402 qDebug() << Q_FUNC_INFO << paths;
403#endif
404 return paths;
405}
406
407/*!
408 * \brief RemoveNotifier::RemoveNotifier
409 * \param parent
410 */
411RemoveNotifier::RemoveNotifier(QObject *parent) :
412 QObject(parent)
413{
414}
415
416//===============================================================================================
417/*!
418 * \brief RemoveNotifier::notifyRemoved
419 * \param fi
420 */
421void RemoveNotifier::notifyRemoved(const QFileInfo &fi)
422{
423#if DEBUG_MESSAGES
424 qDebug() << Q_FUNC_INFO << "emit removed(QFileInfo)" << fi.absoluteFilePath();
425#endif
426 emit removed(fi);
427}
428
429//===============================================================================================
430/*!
431 * \brief RemoveNotifier::notifyRemoved
432 * \param item
433 */
434void RemoveNotifier::notifyRemoved(const QString &item)
435{
436#if DEBUG_MESSAGES
437 qDebug() << Q_FUNC_INFO << "emit removed(QString)" << item;
438#endif
439 emit removed(item);
440}
441
442
443//===============================================================================================
444/*!
445 * \brief FileSystemAction::FileSystemAction
446 * \param parent
447 */
448FileSystemAction::FileSystemAction(QObject *parent) :
449 QObject(parent)
450 , m_curAction(0)
451 , m_cancelCurrentAction(false)
452 , m_busy(false)
453 , m_mimeData ( new DirModelMimeData() )
454 , m_clipboardModifiedByOther(false)
455{
456 //as m_removeNotifier is static it will send signals to all instances of
457 //the model
458 connect(&m_removeNotifier, SIGNAL(removed(QFileInfo)),
459 this, SIGNAL(removed(QFileInfo)));
460
461 connect(&m_removeNotifier, SIGNAL(removed(QString)),
462 this, SIGNAL(removed(QString)));
463
464 QClipboard *clipboard = QApplication::clipboard();
465
466 connect(clipboard, SIGNAL(dataChanged()), this, SIGNAL(clipboardChanged()));
467 connect(clipboard, SIGNAL(dataChanged()), this, SLOT(clipboardHasChanged()));
468}
469
470//===============================================================================================
471/*!
472 * \brief FileSystemAction::~FileSystemAction
473 */
474FileSystemAction::~FileSystemAction()
475{
476 delete m_mimeData;
477}
478
479//===============================================================================================
480/*!
481 * \brief FileSystemAction::remove
482 * \param paths
483 */
484void FileSystemAction::remove(const QStringList &paths)
485{
486 createAndProcessAction(ActionRemove, paths, NoClipboard);
487}
488
489//===============================================================================================
490/*!
491 * \brief FileSystemAction::createAction
492 * \param type
493 * \param origBase
494 * \return
495 */
496FileSystemAction::Action* FileSystemAction::createAction(ActionType type, int origBase)
497{
498 Action * action = new Action();
499 action->type = type;
500 action->baseOrigSize = origBase;
501 action->targetPath = m_path;
502 action->totalItems = 0;
503 action->currItem = 0;
504 action->currEntry = 0;
505 action->totalBytes = 0;
506 action->bytesWritten = 0;
507 action->done = false;
508
509 return action;
510}
511
512//===============================================================================================
513/*!
514 * \brief FileSystemAction::addEntry
515 * \param action
516 * \param pathname
517 */
518void FileSystemAction::addEntry(Action* action, const QString& pathname)
519{
520#if DEBUG_MESSAGES
521 qDebug() << Q_FUNC_INFO << pathname;
522#endif
523 QFileInfo info(pathname);
524 if (!info.isAbsolute())
525 {
526 info.setFile(action->targetPath, pathname);
527 }
528 if (!info.exists())
529 {
530 emit error(QObject::tr("File or Directory does not exist"),
531 pathname + QObject::tr(" does not exist")
532 );
533 return;
534 }
535 ActionEntry * entry = new ActionEntry();
536 QFileInfo item;
537 //ActionMove will perform a rename, so no Directory expanding is necessary
538 if (action->type != ActionMove && info.isDir() && !info.isSymLink())
539 {
540 QDirIterator it(info.absoluteFilePath(),
541 QDir::AllEntries | QDir::System |
542 QDir::NoDotAndDotDot | QDir::Hidden,
543 QDirIterator::Subdirectories);
544 while (it.hasNext() && !it.next().isEmpty())
545 {
546 item = it.fileInfo();
547 entry->reversedOrder.prepend(it.fileInfo());
548 if (item.isFile() && !item.isDir() && !item.isSymLink())
549 {
550 action->totalBytes += item.size();
551 }
552 else
553 {
554 action->totalBytes += COMMON_SIZE_ITEM;
555 }
556 }
557 }
558 //this is the item being handled
559 entry->reversedOrder.append(info);
560
561 // verify if the destination item already exists
562 if (action->type == ActionCopy || action->type == ActionMove ||
563 action->type == ActionHardMoveCopy)
564 {
565 QFileInfo destination(targetFom(info.absoluteFilePath()));
566 entry->alreadyExists = destination.exists();
567 }
568
569 action->totalItems += entry->reversedOrder.count();
570 if (info.isFile() && !info.isDir() && !info.isSymLink())
571 {
572 action->totalBytes += info.size();
573 }
574 else
575 {
576 action->totalBytes += COMMON_SIZE_ITEM;
577 }
578 action->entries.append(entry);
579}
580
581//===============================================================================================
582/*!
583 * \brief FileSystemAction::processAction
584 */
585void FileSystemAction::processAction()
586{
587 if (m_curAction)
588 {
589 //it will be ActionHardMoveRemove only when switched from ActionHardMoveCopy
590 //in this case the move is done in two steps COPY and REMOVE
591 if (m_curAction->type != ActionHardMoveCopy)
592 {
593 delete m_curAction;
594 m_curAction = 0;
595 }
596 }
597 if (!m_curAction && m_queuedActions.count())
598 {
599 m_curAction = m_queuedActions.at(0);
600 m_queuedActions.remove(0,1);
601 }
602 if (m_curAction)
603 {
604 m_busy = true;
605 m_cancelCurrentAction = false;
606 m_errorMsg.clear();
607 m_errorTitle.clear();
608 scheduleSlot(SLOT(processActionEntry()));
609 if (SHOULD_EMIT_PROGRESS_SIGNAL(m_curAction))
610 {
611 emit progress(0,m_curAction->totalItems, 0);
612 }
613 }
614 else
615 {
616 m_busy = false;
617 }
618}
619
620
621//===============================================================================================
622/*!
623 * \brief FileSystemAction::processActionEntry
624 */
625void FileSystemAction::processActionEntry()
626{
627#if DEBUG_MESSAGES
628 qDebug() << Q_FUNC_INFO;
629#endif
630
631 ActionEntry * curEntry = static_cast<ActionEntry*>
632 ( m_curAction->entries.at(m_curAction->currEntry) );
633
634#if defined(SIMULATE_LONG_ACTION)
635 {
636 unsigned int delay = SIMULATE_LONG_ACTION;
637 if (delay == 1)
638 {
639 delay = 100; //each (10 * STEP_FILES) files will waits a second
640 QThread::currentThread()->wait(delay);
641 }
642 }
643#endif
644 if (!m_cancelCurrentAction)
645 {
646 switch(m_curAction->type)
647 {
648 case ActionRemove:
649 case ActionHardMoveRemove:
650 removeEntry(curEntry);
651 endActionEntry();
652 break;
653 case ActionCopy:
654 case ActionHardMoveCopy:
655 processCopyEntry(); // specially: this is a slot
656 break;
657 case ActionMove:
658 moveEntry(curEntry);
659 endActionEntry();
660 break;
661 }
662 }
663}
664
665//===============================================================================================
666/*!
667 * \brief FileSystemAction::endActionEntry
668 */
669void FileSystemAction::endActionEntry()
670{
671#if DEBUG_MESSAGES
672 qDebug() << Q_FUNC_INFO;
673#endif
674 ActionEntry * curEntry = static_cast<ActionEntry*>
675 ( m_curAction->entries.at(m_curAction->currEntry) );
676
677 // first of all check for any error or a cancel issued by the user
678 if (m_cancelCurrentAction)
679 {
680 if (!m_errorTitle.isEmpty())
681 {
682 emit error(m_errorTitle, m_errorMsg);
683 }
684 //it may have other actions to do
685 scheduleSlot(SLOT(processAction()));
686 return;
687 }
688 // check if the current entry has finished
689 // if so Views need to receive the notification about that
690 if (curEntry->currItem == curEntry->reversedOrder.count())
691 {
692 const QFileInfo & mainItem = curEntry->reversedOrder.at(curEntry->currItem -1);
693 if (m_curAction->type == ActionRemove || m_curAction->type == ActionMove ||
694 m_curAction->type == ActionHardMoveRemove)
695 {
696 m_removeNotifier.notifyRemoved(mainItem); // notify all instances
697 }
698 if (m_curAction->type == ActionCopy || m_curAction->type == ActionMove ||
699 m_curAction->type == ActionHardMoveCopy)
700 {
701 QString addedItem = targetFom(mainItem.absoluteFilePath());
702 if (curEntry->alreadyExists)
703 {
704 m_removeNotifier.notifyRemoved(addedItem);
705 }
706 emit added(addedItem);
707 }
708 m_curAction->currEntry++;
709 //check if is doing a hard move and the copy part has finished
710 //if so switch the action to remove
711 if (m_curAction->type == ActionHardMoveCopy &&
712 m_curAction->currEntry == m_curAction->entries.count() )
713 {
714 m_curAction->type = ActionHardMoveRemove;
715 m_curAction->currEntry = 0;
716 int entryCounter = m_curAction->entries.count();
717 ActionEntry * entry;
718 while (entryCounter--)
719 {
720 entry = m_curAction->entries.at(entryCounter);
721 entry->currItem = 0;
722 entry->currStep = 0;
723 }
724 }
725 }
726 if (curEntry->currStep == STEP_FILES)
727 {
728 curEntry->currStep = 0;
729 }
730
731 int percent = notifyProgress();
732 //Check if the current action has finished or cancelled
733 if (m_cancelCurrentAction ||
734 m_curAction->currEntry == m_curAction->entries.count())
735 {
736 if (!m_cancelCurrentAction)
737 {
738 endCurrentAction();
739 if (percent < 100)
740 {
741 notifyProgress(100);
742 }
743 }
744 //it may have other actions to do
745 scheduleSlot(SLOT(processAction()));
746 }
747 else
748 {
749 //keep working on current Action maybe more entries
750 scheduleSlot(SLOT(processActionEntry()));
751 }
752}
753
754//===============================================================================================
755/*!
756 * \brief FileSystemAction::cancel
757 */
758void FileSystemAction::cancel()
759{
760 m_cancelCurrentAction = true;
761}
762
763//===============================================================================================
764/*!
765 * \brief FileSystemAction::removeEntry
766 * \param entry
767 */
768void FileSystemAction::removeEntry(ActionEntry *entry)
769{
770 QDir dir;
771 //do one step at least
772 for(; !m_cancelCurrentAction &&
773 entry->currStep < STEP_FILES &&
774 m_curAction->currItem < m_curAction->totalItems &&
775 entry->currItem < entry->reversedOrder.count()
776 ; entry->currStep++, m_curAction->currItem++, entry->currItem++
777 )
778
779 {
780 const QFileInfo &fi = entry->reversedOrder.at(entry->currItem);
781 if (fi.isDir() && !fi.isSymLink())
782 {
783 m_cancelCurrentAction = !dir.rmdir(fi.absoluteFilePath());
784 }
785 else
786 {
787 m_cancelCurrentAction = !QFile::remove(fi.absoluteFilePath());
788 }
789#if DEBUG_REMOVE
790 qDebug() << "remove ret=" << !m_cancelCurrentAction << fi.absoluteFilePath();
791#endif
792 if (m_cancelCurrentAction)
793 {
794 m_errorTitle = QObject::tr("Could not remove the item ") +
795 fi.absoluteFilePath();
796 m_errorMsg = ::strerror(errno);
797 }
798 }
799}
800
801//===============================================================================================
802/*!
803 * \brief FileSystemAction::copyEntry
804 * \param entry
805 */
806void FileSystemAction::processCopyEntry()
807{
808#if DEBUG_MESSAGES
809 qDebug() << Q_FUNC_INFO;
810#endif
811
812 ActionEntry * entry = static_cast<ActionEntry*>
813 ( m_curAction->entries.at(m_curAction->currEntry) );
814
815 /*
816 * This flag will be true when processCopySingleFile() has put any slot in the execution queue
817 * it will work to stop the loop.
818 * Later processCopyEntry() will be called again to continue working
819 */
820 bool scheduleAnySlot = false;
821
822 for(; !m_cancelCurrentAction && !scheduleAnySlot &&
823 entry->currStep < STEP_FILES &&
824 m_curAction->currItem < m_curAction->totalItems &&
825 entry->currItem < entry->reversedOrder.count()
826 ; entry->currStep++, entry->currItem++
827 )
828
829 {
830 const QFileInfo &fi = entry->reversedOrder.at(entry->currItem);
831 QString orig = fi.absoluteFilePath();
832 QString target = targetFom(orig);
833 QString path(target);
834 // do this here to allow progress send right item number, copySingleFile will emit progress()
835 m_curAction->currItem++;
836
837 if (fi.isFile() || fi.isSymLink())
838 {
839 QFileInfo t(target);
840 path = t.path();
841 }
842 QDir d(path);
843 if (!d.exists() && !d.mkpath(path))
844 {
845 m_cancelCurrentAction = true;
846 m_errorTitle = QObject::tr("Could not create the directory");
847 m_errorMsg = path;
848 }
849 else
850 if (fi.isSymLink())
851 {
852 m_cancelCurrentAction = ! copySymLink(target,fi);
853 if (m_cancelCurrentAction)
854 {
855 m_errorTitle = QObject::tr("Could not create link to");
856 m_errorMsg = target;
857 }
858 m_curAction->bytesWritten += COMMON_SIZE_ITEM;
859 }
860 else
861 if (fi.isDir())
862 {
863 m_cancelCurrentAction = !
864 QFile(target).setPermissions(fi.permissions());
865 if (m_cancelCurrentAction)
866 {
867 m_errorTitle = QObject::tr("Could not set permissions to dir");
868 m_errorMsg = target;
869 }
870 m_curAction->bytesWritten += COMMON_SIZE_ITEM;
871 }
872 else
873 if (fi.isFile())
874 {
875 m_curAction->copyFile.clear();
876 m_curAction->copyFile.source = new QFile(orig);
877 if (!m_curAction->copyFile.source->open(QFile::ReadOnly))
878 {
879 m_cancelCurrentAction = true;
880 m_errorTitle = QObject::tr("Could not open file");
881 m_errorMsg = orig;
882 }
883 m_curAction->copyFile.target = new QTemporaryFile();
884 if (! m_curAction->copyFile.target->open())
885 {
886 m_cancelCurrentAction = true;
887 m_errorTitle = QObject::tr("Could not create temporary file");
888 m_errorMsg = m_curAction->copyFile.target->fileName();
889 }
890 m_curAction->copyFile.targetName = target;
891 scheduleAnySlot = processCopySingleFile();
892 }
893 }//for
894
895 //no copy going on
896 if (!scheduleAnySlot)
897 {
898 endActionEntry();
899 }
900}
901
902//===============================================================================================
903/*!
904 * \brief FileSystemAction::moveEntry
905 * \param entry
906 */
907void FileSystemAction::moveEntry(ActionEntry *entry)
908{
909 QFile file;
910
911 for(; !m_cancelCurrentAction &&
912 entry->currStep < STEP_FILES &&
913 m_curAction->currItem < m_curAction->totalItems &&
914 entry->currItem < entry->reversedOrder.count()
915 ; entry->currStep++, m_curAction->currItem++, entry->currItem++
916 )
917
918 {
919 const QFileInfo &fi = entry->reversedOrder.at(entry->currItem);
920 file.setFileName(fi.absoluteFilePath());
921 QString target = targetFom(fi.absoluteFilePath());
922 if (!file.rename(target))
923 {
924 m_cancelCurrentAction = true;
925 m_errorTitle = QObject::tr("Could not move the directory/file ") + target;
926 m_errorMsg = ::strerror(errno);
927 }
928 }//for
929}
930
931//===============================================================================================
932/*!
933 * \brief FileSystemAction::pathChanged
934 * \param path
935 */
936void FileSystemAction::pathChanged(const QString &path)
937{
938 m_path = path;
939}
940
941//===============================================================================================
942/*!
943 * \brief FileSystemAction::copy
944 * \param pathnames
945 */
946void FileSystemAction::copy(const QStringList &pathnames)
947{
948#if DEBUG_MESSAGES
949 qDebug() << Q_FUNC_INFO << pathnames;
950#endif
951 DirModelMimeData::ClipBoardDataOwner owner =
952 m_mimeData->setIntoClipboard(pathnames, m_path, ClipboardCopy);
953 if (owner == DirModelMimeData::MySelf )
954 {
955 emit clipboardChanged();
956 }
957}
958
959//===============================================================================================
960/*!
961 * \brief FileSystemAction::cut
962 * \param pathnames
963 */
964void FileSystemAction::cut(const QStringList &pathnames)
965{
966#if DEBUG_MESSAGES
967 qDebug() << Q_FUNC_INFO << pathnames;
968#endif
969 DirModelMimeData::ClipBoardDataOwner owner =
970 m_mimeData->setIntoClipboard(pathnames, m_path, ClipboardCut);
971 if (owner == DirModelMimeData::MySelf )
972 {
973 emit clipboardChanged();
974 }
975}
976
977//===============================================================================================
978/*!
979 * \brief FileSystemAction::paste
980 */
981void FileSystemAction::paste()
982{
983 ClipboardOperation operation;
984 QStringList paths = m_mimeData->localUrls(operation);
985#if DEBUG_MESSAGES
986 qDebug() << Q_FUNC_INFO << paths;
987#endif
988 if (paths.count())
989 {
990 if (QFileInfo(m_path).absoluteFilePath() == QFileInfo(paths.at(0)).absolutePath())
991 {
992 emit error(tr("Cannot paste"),
993 tr("origin and destination folder are the same"));
994 return;
995 }
996 ActionType actionType = ActionCopy; // start with Copy and check for Cut
997 if (operation == ClipboardCut)
998 {
999 //so far it always returns true since on Linux it is possible to rename
1000 // between different file systems
1001 if ( moveUsingSameFileSystem(paths.at(0)) ) {
1002 actionType = ActionMove;
1003 } else {
1004 actionType = ActionHardMoveCopy; // first step
1005 }
1006 }
1007 createAndProcessAction(actionType, paths, operation);
1008 }
1009}
1010
1011//===============================================================================================
1012/*!
1013 * \brief FileSystemAction::createAndProcessAction
1014 * \param actionType
1015 * \param paths
1016 * \param operation
1017 */
1018void FileSystemAction::createAndProcessAction(ActionType actionType, const QStringList& paths, ClipboardOperation operation)
1019{
1020#if DEBUG_MESSAGES
1021 qDebug() << Q_FUNC_INFO << paths;
1022#endif
1023 Action *myAction = 0;
1024 int origPathLen = 0;
1025 myAction = createAction(actionType, origPathLen);
1026 myAction->operation = operation;
1027 myAction->origPath = QFileInfo(paths.at(0)).absolutePath();
1028 myAction->baseOrigSize = myAction->origPath.length();
1029 Action * saveAction = m_curAction;
1030 m_curAction = myAction;
1031 for (int counter=0; counter < paths.count(); counter++)
1032 {
1033 //targetFom() uses m_curAction and is called inside addEntry()
1034 addEntry(myAction, paths.at(counter));
1035 }
1036 m_curAction = saveAction;
1037 if (actionType == ActionHardMoveCopy)
1038 {
1039 myAction->totalItems *= 2; //duplicate this
1040 myAction->totalBytes *= 2;
1041 }
1042 if (operation == ClipboardCut)
1043 {
1044 //this must still be false when cut finishes to change the clipboard to the target
1045 m_clipboardModifiedByOther = false;
1046 }
1047 m_queuedActions.append(myAction);
1048 if (!m_busy)
1049 {
1050 processAction();
1051 }
1052}
1053
1054//===============================================================================================
1055/*!
1056 * \brief FileSystemAction::targetFom() makes a destination full pathname from \a origItem
1057 * \param origItem full pathname from a item intended to be copied or moved into current path
1058 * \return full pathname of target
1059 */
1060QString FileSystemAction::targetFom(const QString& origItem)
1061{
1062 QString target(m_curAction->targetPath + origItem.mid(m_curAction->baseOrigSize));
1063 return target;
1064}
1065
1066//===============================================================================================
1067/*!
1068 * \brief FileSystemAction::moveUsingSameFileSystem() Checks if the item being moved to
1069 * current m_path belongs to the same File System
1070 *
1071 * \param itemToMovePathname first item being moved from a paste operation
1072 *
1073 * \return true if the item being moved to the current m_path belongs to the same file system as m_path
1074 */
1075bool FileSystemAction::moveUsingSameFileSystem(const QString& itemToMovePathname)
1076{
1077#if 0 //disabled since on Linux it looks like renaming between different file systems works
1078 unsigned long targetFsId = 0xffff;
1079 unsigned long originFsId = 0xfffe;
1080 struct statvfs vfs;
1081
1082 if ( ::statvfs(m_path.toLatin1().constData(), &vfs) == 0 )
1083 {
1084 targetFsId = vfs.f_fsid;
1085 }
1086 if ( ::statvfs(itemToMovePathname.toLatin1().constData(), &vfs) == 0)
1087 {
1088 originFsId = vfs.f_fsid;
1089 }
1090 return targetFsId == originFsId;
1091#else
1092 Q_UNUSED(itemToMovePathname);
1093 return true;
1094#endif
1095}
1096
1097//=======================================================
1098/*!
1099 * \brief FileSystemAction::clipboardLocalUrlsConunter
1100 * \return
1101 */
1102int FileSystemAction::clipboardLocalUrlsConunter()
1103{
1104 ClipboardOperation operation;
1105 return m_mimeData->localUrls(operation).count();
1106}
1107
1108//================================================================================
1109/*!
1110 * \brief FileSystemAction::endCurrentAction() finishes an Action
1111 *
1112 * If a Paste was made from a Cut operation, items pasted become avaialable in the clipboard
1113 * as from Copy source operation, so items can be now Pasted again, but with no source removal
1114 *
1115 * It checks for \a m_clipboardModifiedByOther that idenftifies if the clipboard was modified during the
1116 * operation maybe by another application.
1117 */
1118void FileSystemAction::endCurrentAction()
1119{
1120 if ( m_curAction->origPath != m_curAction->targetPath &&
1121 m_curAction->operation == ClipboardCut &&
1122 !m_clipboardModifiedByOther )
1123 {
1124 QStringList items;
1125 const ActionEntry *entry;
1126 int last;
1127 for(int e = 0; e < m_curAction->entries.count(); e++)
1128 {
1129 entry = m_curAction->entries.at(e);
1130 last = entry->reversedOrder.count() -1;
1131 QString item(targetFom(entry->reversedOrder.at(last).absoluteFilePath()));
1132 items.append(item);
1133 }
1134 if (items.count())
1135 {
1136 QString targetPath = m_curAction->targetPath;
1137 //it is not necessary to handle own clipboard here
1138 m_mimeData->setIntoClipboard(items, targetPath, ClipboardCopy);
1139 }
1140 }
1141}
1142
1143//================================================================================
1144/*!
1145 * \brief FileSystemAction::copySingleFile() do a single file copy
1146 *
1147 * Several write operations are required to copy big files, each operation writes (STEP_FILES * 4k) bytes.
1148 * After a write operation if more operations are required to copy the whole file,
1149 * a progress() signal is emitted and a new write operation is scheduled to happen in the next loop interaction.
1150 *
1151 * \return true if scheduled to another slot either processCopyEntry() or itself; false if not.
1152 */
1153bool FileSystemAction::processCopySingleFile()
1154{
1155#if DEBUG_MESSAGES
1156 qDebug() << Q_FUNC_INFO;
1157#endif
1158 char block[4096];
1159 int step = 0;
1160 bool copySingleFileDone = false;
1161 bool scheduleAnySlot = true;
1162 int startBytes = m_curAction->copyFile.bytesWritten;
1163
1164 while( m_curAction->copyFile.source &&
1165 !m_curAction->copyFile.source->atEnd() &&
1166 !m_cancelCurrentAction &&
1167 m_curAction->copyFile.bytesWritten < m_curAction->copyFile.source->size() &&
1168 step++ < STEP_FILES
1169 )
1170 {
1171 qint64 in = m_curAction->copyFile.source->read(block, sizeof(block));
1172 if (in > 0)
1173 {
1174 if(in != m_curAction->copyFile.target->write(block, in))
1175 {
1176 m_curAction->copyFile.source->close();
1177 m_curAction->copyFile.target->close();
1178 m_cancelCurrentAction = true;
1179 m_errorTitle = QObject::tr("Write error in ")
1180 + m_curAction->copyFile.targetName,
1181 m_errorMsg = ::strerror(errno);
1182 break;
1183 }
1184 m_curAction->bytesWritten += in;
1185 m_curAction->copyFile.bytesWritten += in;
1186 }
1187 else
1188 if (in < 0)
1189 {
1190 m_cancelCurrentAction = true;
1191 m_errorTitle = QObject::tr("Read error in ")
1192 + m_curAction->copyFile.source->fileName();
1193 m_errorMsg = ::strerror(errno);
1194 break;
1195 }
1196 }// end write loop
1197
1198 // write loop finished, the copy might be finished
1199 if (!m_cancelCurrentAction
1200 && m_curAction->copyFile.source
1201 && m_curAction->copyFile.bytesWritten == m_curAction->copyFile.source->size()
1202 && m_curAction->copyFile.source->isOpen()
1203 )
1204 {
1205 m_curAction->copyFile.source->close();
1206 m_curAction->copyFile.target->close();
1207 m_curAction->copyFile.target->setAutoRemove(false);
1208 m_cancelCurrentAction = !m_curAction->copyFile.target->setPermissions(
1209 m_curAction->copyFile.source->permissions());
1210 if (m_cancelCurrentAction)
1211 {
1212 m_errorTitle = QObject::tr("Set permissions error in ")
1213 + m_curAction->copyFile.targetName,
1214 m_errorMsg = ::strerror(errno);
1215 }
1216 else
1217 {
1218 QFile testExistTarget(m_curAction->copyFile.targetName);
1219 if (testExistTarget.exists())
1220 {
1221 if ((m_cancelCurrentAction = ! testExistTarget.remove()))
1222 {
1223 m_errorTitle = QObject::tr("Could not remove original file ")
1224 + m_curAction->copyFile.targetName,
1225 m_errorMsg = ::strerror(errno);
1226 }
1227 }
1228 if (!m_cancelCurrentAction)
1229 {
1230 m_cancelCurrentAction = ! m_curAction->copyFile.target->
1231 rename(m_curAction->copyFile.targetName);
1232 if (m_cancelCurrentAction)
1233 {
1234 m_errorTitle = QObject::tr("Rename error: renaming to ")
1235 + m_curAction->copyFile.targetName,
1236 m_errorMsg = ::strerror(errno);
1237 }
1238 else
1239 {
1240 copySingleFileDone = true;
1241 }
1242 }
1243 }
1244 }
1245
1246 if (m_cancelCurrentAction)
1247 {
1248 if (m_curAction->copyFile.target)
1249 {
1250 m_curAction->copyFile.target->setAutoRemove(true);
1251 }
1252 m_curAction->copyFile.clear();
1253 endActionEntry();
1254 }
1255 else
1256 {
1257 notifyProgress();
1258 if (copySingleFileDone)
1259 {
1260 m_curAction->copyFile.clear();
1261 //whem the whole copy could be done just in one call
1262 //do not schedule to call copyEntry()
1263 if (startBytes > 0)
1264 {
1265 //the whole took more than one call to copySingleFile()
1266 scheduleSlot(SLOT(processCopyEntry()));
1267 }
1268 else
1269 { //return normally to entry loop
1270 scheduleAnySlot = false;
1271 }
1272 }
1273 else
1274 {
1275 scheduleSlot(SLOT(processCopySingleFile()));
1276 }
1277 }
1278
1279 return scheduleAnySlot;
1280}
1281
1282
1283//================================================================================
1284/*!
1285 * \brief FileSystemAction::percentWorkDone() Compute the percent of work done
1286 *
1287 * Copy operations are based on bytes written while remove/move operations are based on items number
1288 *
1289 * \return the percent of work done
1290 */
1291int FileSystemAction::percentWorkDone()
1292{
1293 int percent = 0;
1294 if (m_curAction->type != ActionCopy && m_curAction->type != ActionHardMoveCopy)
1295 {
1296 percent = (m_curAction->currItem * 100) / m_curAction->totalItems;
1297 }
1298 else
1299 {
1300 percent = (m_curAction->bytesWritten * 100) / m_curAction->totalBytes ;
1301 }
1302 if (percent > 100)
1303 {
1304 percent = 100;
1305 }
1306 return percent;
1307}
1308
1309
1310//================================================================================
1311/*!
1312 * \brief FileSystemAction::notifyProgress() Notify the progress signal
1313 *
1314 * \return the percent of work done
1315 */
1316int FileSystemAction::notifyProgress(int forcePercent)
1317{
1318 int percent = forcePercent > 0 ? forcePercent : percentWorkDone();
1319 if (percent == 0)
1320 {
1321 percent = 1;
1322 }
1323 if (SHOULD_EMIT_PROGRESS_SIGNAL(m_curAction) && !m_curAction->done)
1324 {
1325 if (m_curAction->type == ActionHardMoveCopy ||
1326 m_curAction->type ==ActionHardMoveRemove)
1327 {
1328 emit progress(m_curAction->currItem/2, m_curAction->totalItems/2, percent);
1329 }
1330 else
1331 {
1332 emit progress(m_curAction->currItem, m_curAction->totalItems, percent);
1333 }
1334 if (percent == 100 && m_curAction->currItem == m_curAction->totalItems)
1335 {
1336 m_curAction->done = true;
1337 }
1338 }
1339 return percent;
1340}
1341
1342//================================================================================
1343/*!
1344 * \brief FileSystemAction::copySymLink() creates the \a target as a link according to \a orig
1345 * \param target full pathname of the file to be created
1346 * \param orig original file, it carries the link that \a target will point to
1347 * \return true if it could create, else if not
1348 */
1349bool FileSystemAction::copySymLink(const QString &target, const QFileInfo &orig)
1350{
1351 QString link(orig.symLinkTarget());
1352 QFileInfo linkFile(link);
1353 if (linkFile.isAbsolute() && linkFile.absolutePath() == orig.absolutePath())
1354 {
1355 link = linkFile.fileName();
1356 }
1357#if QT_VERSION <= 0x040704
1358 QString current = QDir::currentPath();
1359 QDir::setCurrent(linkFile.absolutePath());
1360 bool ret = QFile::link(link, target);
1361 QDir::setCurrent(current);
1362#else
1363 bool ret = QFile::link(link, target);
1364#endif
1365#if DEBUG_MESSAGES
1366 qDebug() << "FileSystemAction::copySymLink" << ret << target << link;
1367#endif
1368 return ret;
1369}
1370
1371//================================================================================
1372void FileSystemAction::scheduleSlot(const char *slot)
1373{
1374#if DEBUG_MESSAGES
1375 qDebug() << "FileSystemAction::scheduleSlot()" << slot;
1376#endif
1377 QTimer::singleShot(0, this, slot);
1378}
1379
1380//================================================================================
1381/*!
1382 * \brief FileSystemAction::clipboardHasChanged() used to identify if the clipboard changed during a Cut operation
1383 *
1384 * \sa \ref endCurrentAction()
1385 */
1386void FileSystemAction::clipboardHasChanged()
1387{
1388 m_clipboardModifiedByOther = true;
1389}
01390
=== added file 'folderlistmodel/filesystemaction.h'
--- folderlistmodel/filesystemaction.h 1970-01-01 00:00:00 +0000
+++ folderlistmodel/filesystemaction.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,212 @@
1/**************************************************************************
2 *
3 * Copyright 2013 Canonical Ltd.
4 * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com>
5 *
6 * You may use this file under the terms of the BSD license as follows:
7 *
8 * "Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Nemo Mobile nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
32 *
33 * File: filesystemaction.h
34 * Date: 3/13/2013
35 */
36
37#ifndef FILESYSTEMACTION_H
38#define FILESYSTEMACTION_H
39
40
41#include <QObject>
42#include <QFileInfo>
43#include <QVector>
44
45class DirModelMimeData;
46class RemoveNotifier;
47class QFile;
48class QTemporaryFile;
49
50enum ClipboardOperation
51{
52 NoClipboard, ClipboardCopy, ClipboardCut
53};
54
55/*!
56 * \brief The FileSystemAction class
57 *
58 *
59 */
60class FileSystemAction : public QObject
61{
62 Q_OBJECT
63public:
64 explicit FileSystemAction(QObject *parent = 0);
65 ~FileSystemAction();
66public slots:
67 void cancel();
68 void remove(const QStringList & filePaths);
69 int clipboardLocalUrlsConunter();
70
71signals:
72 void error(const QString& errorTitle, const QString &errorMessage);
73 void removed(const QString& item); //must be sent to all Model instances
74 void removed(const QFileInfo&);
75 void added(const QString& );
76 void added(const QFileInfo& );
77 void progress(int curItem, int totalItems, int percent);
78 void clipboardChanged();
79
80public slots:
81 void pathChanged(const QString& path);
82 void paste();
83 void cut(const QStringList& );
84 void copy(const QStringList&);
85
86private slots:
87 void processAction();
88 void processActionEntry();
89 void processCopyEntry();
90 bool processCopySingleFile();
91 void clipboardHasChanged();
92
93#if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests
94 public:
95#else
96 private:
97#endif
98 enum ActionType
99 {
100 ActionRemove,
101 ActionCopy,
102 ActionMove,
103 ActionHardMoveCopy,
104 ActionHardMoveRemove
105 };
106 void createAndProcessAction(ActionType actionType, const QStringList& paths,
107 ClipboardOperation operation=NoClipboard);
108
109private:
110
111 struct CopyFile
112 {
113 public:
114 CopyFile() : bytesWritten(0), source(0), target(0) {}
115 ~CopyFile() { clear(); }
116 void clear();
117
118 qint64 bytesWritten; // set 0 when reach bytesToNotify, notify progress
119 QFile * source;
120 QTemporaryFile * target;
121 QString targetName;
122 };
123
124 /*!
125 An ActionEntry represents a high level item as a File or a Directory which an Action is required
126
127 For directories \a reversedOrder keeps all children
128 */
129 struct ActionEntry
130 {
131 public:
132 ActionEntry(): currStep(0),currItem(0),alreadyExists(false), newName(0) {}
133 ~ActionEntry()
134 {
135 reversedOrder.clear();
136 if (newName) { delete newName; }
137 }
138 QList<QFileInfo> reversedOrder; //!< last item must be the item from the list
139 int currStep;
140 int currItem;
141 bool alreadyExists;
142 QString * newName; //TODO: allow to rename an existent file when it already exists
143 };
144
145 struct Action
146 {
147 public:
148 ~Action() {qDeleteAll(entries); entries.clear(); copyFile.clear();}
149 ActionType type;
150 QList<ActionEntry*> entries;
151 int totalItems;
152 int currItem;
153 int baseOrigSize;
154 QString origPath;
155 QString targetPath;
156 quint64 totalBytes;
157 quint64 bytesWritten;
158 int currEntry;
159 ClipboardOperation operation;
160 CopyFile copyFile;
161 bool done;
162 };
163
164 QVector<Action*> m_queuedActions; //!< work always at item 0, after finishing taking item 0 out
165 Action * m_curAction;
166 bool m_cancelCurrentAction;
167 bool m_busy;
168 static RemoveNotifier m_removeNotifier;
169 QString m_path;
170 DirModelMimeData * m_mimeData;
171 QString m_errorTitle;
172 QString m_errorMsg;
173 bool m_clipboardModifiedByOther;
174
175private:
176 Action * createAction(ActionType, int origBase = 0);
177 void addEntry(Action* action, const QString &pathname);
178 void removeEntry(ActionEntry *);
179 void moveEntry(ActionEntry *entry);
180 bool moveUsingSameFileSystem(const QString& itemToMovePathname);
181 QString targetFom(const QString& origItem);
182 void endCurrentAction();
183 int percentWorkDone();
184 int notifyProgress(int forcePercent = 0);
185 void endActionEntry();
186 bool copySymLink(const QString& target, const QFileInfo& orig);
187 void scheduleSlot(const char *slot);
188};
189
190
191/*!
192 * \brief The RemoveNotifier is a utility class for \ref FileSystemAction to send
193 * notifications about removed files/dir
194 *
195 * This class must have a unique instance to notify all instances of \ref FileSystemAction and \ref DirModel
196 */
197class RemoveNotifier : public QObject
198{
199 Q_OBJECT
200
201 friend class FileSystemAction;
202private:
203 explicit RemoveNotifier(QObject *parent = 0);
204 void notifyRemoved(const QString& item);
205 void notifyRemoved(const QFileInfo& fi);
206
207signals:
208 void removed(const QString& item);
209 void removed(const QFileInfo&);
210};
211
212#endif // FILESYSTEMACTION_H
0213
=== added file 'folderlistmodel/folderlistmodel.pri'
--- folderlistmodel/folderlistmodel.pri 1970-01-01 00:00:00 +0000
+++ folderlistmodel/folderlistmodel.pri 2013-06-01 17:20:36 +0000
@@ -0,0 +1,26 @@
1SOURCES += $$PWD/dirmodel.cpp \
2 $$PWD/iorequest.cpp \
3 $$PWD/iorequestworker.cpp \
4 $$PWD/ioworkerthread.cpp \
5 $$PWD/filesystemaction.cpp \
6
7
8
9
10HEADERS += $$PWD/dirmodel.h \
11 $$PWD/iorequest.h \
12 $$PWD/iorequestworker.h \
13 $$PWD/ioworkerthread.h \
14 $$PWD/filesystemaction.h \
15
16
17
18INCLUDEPATH += $$PWD
19
20greaterThan(QT_MAJOR_VERSION, 4) {
21 QT += qml
22}
23else {
24 QT += declarative
25}
26
027
=== added file 'folderlistmodel/folderlistmodel.pro'
--- folderlistmodel/folderlistmodel.pro 1970-01-01 00:00:00 +0000
+++ folderlistmodel/folderlistmodel.pro 2013-06-01 17:20:36 +0000
@@ -0,0 +1,39 @@
1TARGET = nemofolderlistmodel
2
3PLUGIN_IMPORT_PATH = org/nemomobile/folderlistmodel
4PLUGIN_URI = org.nemomobile.folderlistmodel
5
6# plugin.h and plugin.cpp use URI from PLUGIN_URI instead of hard coded
7DEFINES += PLUGIN_URI=$$PLUGIN_URI
8
9#core: sources + headers, separated here to use in regression test project
10include (folderlistmodel.pri)
11
12# Input
13SOURCES += plugin.cpp
14HEADERS += plugin.h
15
16## QApplication::clipboard() needs gui
17QT += gui
18greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
19
20exists(../plugin.pri) {
21 include(../plugin.pri)
22}
23else {
24 TEMPLATE = lib
25 CONFIG += qt plugin hide_symbols
26 greaterThan(QT_MAJOR_VERSION, 4) {
27 QT += qml
28 }
29 else {
30 QT += declarative
31 }
32 target.path = $$[QT_INSTALL_QML]/$$PLUGIN_IMPORT_PATH
33 INSTALLS += target
34 qmldir.files += $$PWD/qmldir
35 qmldir.path += $$[QT_INSTALL_QML]/$$$$PLUGIN_IMPORT_PATH
36 INSTALLS += qmldir
37}
38
39
040
=== added file 'folderlistmodel/iorequest.cpp'
--- folderlistmodel/iorequest.cpp 1970-01-01 00:00:00 +0000
+++ folderlistmodel/iorequest.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include "iorequest.h"
33
34IORequest::IORequest() : QObject()
35{
36}
037
=== added file 'folderlistmodel/iorequest.h'
--- folderlistmodel/iorequest.h 1970-01-01 00:00:00 +0000
+++ folderlistmodel/iorequest.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef IOREQUEST_H
33#define IOREQUEST_H
34
35#include <QObject>
36
37class IORequest : public QObject
38{
39 Q_OBJECT
40public:
41 explicit IORequest();
42
43public:
44 virtual void run() = 0;
45
46private:
47 // hide this because IORequest should *NOT* be parented directly
48 using QObject::setParent;
49};
50
51#endif // IOREQUEST_H
052
=== added file 'folderlistmodel/iorequestworker.cpp'
--- folderlistmodel/iorequestworker.cpp 1970-01-01 00:00:00 +0000
+++ folderlistmodel/iorequestworker.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,94 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include "iorequestworker.h"
33#include "iorequest.h"
34
35#include <QMutexLocker>
36#include <QDebug>
37
38/*!
39 Lives on an IOWorkerThread.
40
41 Responsible for running IORequest jobs on the thread instance, and
42 disposing of their resources once they are done.
43 */
44IORequestWorker::IORequestWorker()
45 : QThread()
46 , mTimeToQuit(false)
47{
48}
49
50void IORequestWorker::addRequest(IORequest *request)
51{
52 request->moveToThread(this);
53
54 // TODO: queue requests so we run the most important one first
55 QMutexLocker lock(&mMutex);
56 mRequests.append(request);
57
58 // wake run()
59 mWaitCondition.wakeOne();
60}
61
62void IORequestWorker::run()
63{
64 forever {
65 QMutexLocker lock(&mMutex);
66
67 if (mTimeToQuit)
68 return;
69
70 if (mRequests.empty())
71 mWaitCondition.wait(&mMutex);
72
73 while (!mRequests.isEmpty()) {
74 IORequest *request = mRequests.takeFirst();
75
76 lock.unlock();
77
78 request->run();
79 request->deleteLater();
80
81 lock.relock();
82 }
83 }
84}
85
86void IORequestWorker::exit()
87{
88#if DEBUG_MESSAGES
89 qDebug() << Q_FUNC_INFO << "Quitting";
90#endif
91 QMutexLocker lock(&mMutex);
92 mTimeToQuit = true;
93 mWaitCondition.wakeOne();
94}
095
=== added file 'folderlistmodel/iorequestworker.h'
--- folderlistmodel/iorequestworker.h 1970-01-01 00:00:00 +0000
+++ folderlistmodel/iorequestworker.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,61 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef IOREQUESTWORKER_H
33#define IOREQUESTWORKER_H
34
35#include <QObject>
36#include <QThread>
37#include <QMutex>
38#include <QWaitCondition>
39
40#include "iorequest.h"
41
42class IORequestWorker : public QThread
43{
44 Q_OBJECT
45public:
46 explicit IORequestWorker();
47
48 void addRequest(IORequest *request);
49
50 void run();
51
52 void exit();
53
54private:
55 QMutex mMutex;
56 QWaitCondition mWaitCondition;
57 QList<IORequest *> mRequests;
58 bool mTimeToQuit;
59};
60
61#endif // IOREQUESTWORKER_H
062
=== added file 'folderlistmodel/ioworkerthread.cpp'
--- folderlistmodel/ioworkerthread.cpp 1970-01-01 00:00:00 +0000
+++ folderlistmodel/ioworkerthread.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include "ioworkerthread.h"
33
34
35/*!
36 Hosts a thread, lives on the main thread.
37
38 Responsible for relaying interaction between the main thread and an IOWorkerThread.
39 */
40IOWorkerThread::IOWorkerThread(QObject *parent) :
41 QObject(parent)
42{
43 mWorker.start(QThread::IdlePriority);
44}
45
46/*!
47 Destroys an IOWorkerThread instance.
48 */
49IOWorkerThread::~IOWorkerThread()
50{
51 mWorker.exit();
52 mWorker.wait();
53}
54
55/*!
56 Attempts an asynchronous attempt to start a \a request.
57
58 If the request may be run, it is queued, and true is returned, otherwise, false.
59 */
60bool IOWorkerThread::addRequest(IORequest *request)
61{
62 mWorker.addRequest(request);
63 return true;
64}
065
=== added file 'folderlistmodel/ioworkerthread.h'
--- folderlistmodel/ioworkerthread.h 1970-01-01 00:00:00 +0000
+++ folderlistmodel/ioworkerthread.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,52 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef IOWORKERTHREAD_H
33#define IOWORKERTHREAD_H
34
35#include <QObject>
36#include <QThread>
37
38#include "iorequestworker.h"
39
40class IOWorkerThread : public QObject
41{
42 Q_OBJECT
43public:
44 explicit IOWorkerThread(QObject *parent = 0);
45 virtual ~IOWorkerThread();
46 bool addRequest(IORequest *request);
47
48private:
49 IORequestWorker mWorker;
50};
51
52#endif // IOWORKERTHREAD_H
053
=== added file 'folderlistmodel/plugin.cpp'
--- folderlistmodel/plugin.cpp 1970-01-01 00:00:00 +0000
+++ folderlistmodel/plugin.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include <QVector>
33#include <QFileInfo>
34
35#include "plugin.h"
36
37NemoFolderListModelPlugin::NemoFolderListModelPlugin() { }
38
39NemoFolderListModelPlugin::~NemoFolderListModelPlugin() { }
40
41void NemoFolderListModelPlugin::initializeEngine(QmlEngine *engine, const char *uri)
42{
43 Q_UNUSED(engine)
44 Q_ASSERT(uri == QLatin1String(QUOTES(PLUGIN_URI)));
45}
46
47void NemoFolderListModelPlugin::registerTypes(const char *uri)
48{
49 Q_ASSERT(uri == QLatin1String(QUOTES(PLUGIN_URI)));
50 qRegisterMetaType<QVector<QFileInfo> >();
51 qmlRegisterType<DirModel>(uri, 1, 0, "FolderListModel");
52}
53
054
=== added file 'folderlistmodel/plugin.h'
--- folderlistmodel/plugin.h 1970-01-01 00:00:00 +0000
+++ folderlistmodel/plugin.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,84 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef NEMO_QML_PLUGINS_FOLDERLISTMODEL
33#define NEMO_QML_PLUGINS_FOLDERLISTMODEL
34
35#include <QtGlobal>
36#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
37#include <QtDeclarative>
38#include <QDeclarativeEngine>
39#include <QDeclarativeExtensionPlugin>
40#include <QVector>
41#include <QFileInfo>
42
43#define PLUGIN_CLASS_EXPORT
44#define PLUGIN_CLASS_EXTERNAL_EXPORT Q_EXPORT_PLUGIN2(nemofolderlistmodel, NemoFolderListModelPlugin);
45#define PLUGIN_CLASS_EXTEND
46typedef QDeclarativeExtensionPlugin QmlPluginParent;
47typedef QDeclarativeEngine QmlEngine;
48Q_DECLARE_METATYPE(QVector<QFileInfo>)
49
50#else
51#include <QQmlComponent>
52#include <QQmlEngine>
53#include <QQmlContext>
54#include <QQmlExtensionPlugin>
55
56#define PLUGIN_CLASS_EXPORT Q_DECL_EXPORT
57#define PLUGIN_CLASS_EXTERNAL_EXPORT
58#define PLUGIN_CLASS_EXTEND \
59 Q_OBJECT \
60 Q_PLUGIN_METADATA(IID "org.nemomobile.folderlistmodel")
61typedef QQmlExtensionPlugin QmlPluginParent;
62typedef QQmlEngine QmlEngine;
63#endif
64
65#include "dirmodel.h"
66
67#define QUOTES(x) #x
68
69
70class PLUGIN_CLASS_EXPORT NemoFolderListModelPlugin : public QmlPluginParent
71{
72 PLUGIN_CLASS_EXTEND
73
74public:
75 NemoFolderListModelPlugin();
76 virtual ~NemoFolderListModelPlugin();
77
78 void initializeEngine(QmlEngine *engine, const char *uri);
79 void registerTypes(const char *uri);
80};
81
82PLUGIN_CLASS_EXTERNAL_EXPORT
83
84#endif // NEMO_QML_PLUGINS_FOLDERLISTMODEL
085
=== added file 'folderlistmodel/qmldir'
--- folderlistmodel/qmldir 1970-01-01 00:00:00 +0000
+++ folderlistmodel/qmldir 2013-06-01 17:20:36 +0000
@@ -0,0 +1,1 @@
1plugin nemofolderlistmodel
02
=== added directory 'nemo-folderlistmodel'
=== added file 'nemo-folderlistmodel/dirmodel.cpp'
--- nemo-folderlistmodel/dirmodel.cpp 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/dirmodel.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,385 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include <QDirIterator>
33#include <QDir>
34#include <QDebug>
35#include <QDateTime>
36#include <QUrl>
37
38#include <errno.h>
39#include <string.h>
40
41#include "dirmodel.h"
42#include "ioworkerthread.h"
43
44Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread);
45
46class DirListWorker : public IORequest
47{
48 Q_OBJECT
49public:
50 DirListWorker(const QString &pathName)
51 : mPathName(pathName)
52 { }
53
54 void run()
55 {
56 qDebug() << Q_FUNC_INFO << "Running on: " << QThread::currentThreadId();
57
58 QDir tmpDir = QDir(mPathName);
59 QDirIterator it(tmpDir);
60 QVector<QFileInfo> directoryContents;
61
62 while (it.hasNext()) {
63 it.next();
64
65 // skip hidden files
66 if (it.fileName()[0] == QLatin1Char('.'))
67 continue;
68
69 directoryContents.append(it.fileInfo());
70 if (directoryContents.count() >= 50) {
71 emit itemsAdded(directoryContents);
72
73 // clear() would force a deallocation, micro-optimisation
74 directoryContents.erase(directoryContents.begin(), directoryContents.end());
75 }
76 }
77
78 // last batch
79 emit itemsAdded(directoryContents);
80
81 //std::sort(directoryContents.begin(), directoryContents.end(), DirModel::fileCompare);
82 }
83
84signals:
85 void itemsAdded(const QVector<QFileInfo> &files);
86
87private:
88 QString mPathName;
89};
90
91DirModel::DirModel(QObject *parent)
92 : QAbstractListModel(parent)
93 , mAwaitingResults(false)
94 , mShowDirectories(true)
95{
96 mNameFilters = QStringList() << "*";
97
98 QHash<int, QByteArray> roles = roleNames();
99 roles.insert(FileNameRole, QByteArray("fileName"));
100 roles.insert(CreationDateRole, QByteArray("creationDate"));
101 roles.insert(ModifiedDateRole, QByteArray("modifiedDate"));
102 roles.insert(FileSizeRole, QByteArray("fileSize"));
103 roles.insert(IconSourceRole, QByteArray("iconSource"));
104 roles.insert(FilePathRole, QByteArray("filePath"));
105 roles.insert(IsDirRole, QByteArray("isDir"));
106 roles.insert(IsFileRole, QByteArray("isFile"));
107 roles.insert(IsReadableRole, QByteArray("isReadable"));
108 roles.insert(IsWritableRole, QByteArray("isWritable"));
109 roles.insert(IsExecutableRole, QByteArray("isExecutable"));
110 setRoleNames(roles);
111
112 // populate reverse mapping
113 QHash<int, QByteArray>::ConstIterator it = roles.constBegin();
114 for (;it != roles.constEnd(); ++it)
115 mRoleMapping.insert(it.value(), it.key());
116
117 // make sure we cover all roles
118// Q_ASSERT(roles.count() == IsFileRole - FileNameRole);
119}
120
121QVariant DirModel::data(int row, const QByteArray &stringRole) const
122{
123 QHash<QByteArray, int>::ConstIterator it = mRoleMapping.constFind(stringRole);
124
125 if (it == mRoleMapping.constEnd())
126 return QVariant();
127
128 return data(index(row, 0), *it);
129}
130
131QVariant DirModel::data(const QModelIndex &index, int role) const
132{
133 if (role < FileNameRole || role > IsExecutableRole) {
134 qWarning() << Q_FUNC_INFO << "Got an out of range role: " << role;
135 return QVariant();
136 }
137
138 if (index.row() < 0 || index.row() >= mDirectoryContents.count()) {
139 qWarning() << "Attempted to access out of range row: " << index.row();
140 return QVariant();
141 }
142
143 if (index.column() != 0)
144 return QVariant();
145
146 const QFileInfo &fi = mDirectoryContents.at(index.row());
147
148 switch (role) {
149 case FileNameRole:
150 return fi.fileName();
151 case CreationDateRole:
152 return fi.created();
153 case ModifiedDateRole:
154 return fi.lastModified();
155 case FileSizeRole: {
156 qint64 kb = fi.size() / 1024;
157 if (kb < 1)
158 return QString::number(fi.size()) + " bytes";
159 else if (kb < 1024)
160 return QString::number(kb) + " kb";
161
162 kb /= 1024;
163 return QString::number(kb) + "mb";
164 }
165 case IconSourceRole: {
166 const QString &fileName = fi.fileName();
167
168 if (fi.isDir())
169 return "image://theme/icon-m-common-directory";
170
171 if (fileName.endsWith(".jpg", Qt::CaseInsensitive) ||
172 fileName.endsWith(".png", Qt::CaseInsensitive)) {
173 return "image://nemoThumbnail/" + fi.filePath();
174 }
175
176 return "image://theme/icon-m-content-document";
177 }
178 case FilePathRole:
179 return fi.filePath();
180 case IsDirRole:
181 return fi.isDir();
182 case IsFileRole:
183 return !fi.isDir();
184 case IsReadableRole:
185 return fi.isReadable();
186 case IsWritableRole:
187 return fi.isWritable();
188 case IsExecutableRole:
189 return fi.isExecutable();
190 default:
191 // this should not happen, ever
192 Q_ASSERT(false);
193 qWarning() << Q_FUNC_INFO << "Got an unknown role: " << role;
194 return QVariant();
195 }
196}
197
198void DirModel::setPath(const QString &pathName)
199{
200 if (pathName.isEmpty())
201 return;
202
203 if (mAwaitingResults) {
204 // TODO: handle the case where pathName != our current path, cancel old
205 // request, start a new one
206 qDebug() << Q_FUNC_INFO << "Ignoring path change request, request already running";
207 return;
208 }
209
210 mAwaitingResults = true;
211 emit awaitingResultsChanged();
212 qDebug() << Q_FUNC_INFO << "Changing to " << pathName << " on " << QThread::currentThreadId();
213
214 beginResetModel();
215 mDirectoryContents.clear();
216 endResetModel();
217
218 // TODO: we need to set a spinner active before we start getting results from DirListWorker
219 DirListWorker *dlw = new DirListWorker(pathName);
220 connect(dlw, SIGNAL(itemsAdded(QVector<QFileInfo>)), SLOT(onItemsAdded(QVector<QFileInfo>)));
221 ioWorkerThread()->addRequest(dlw);
222
223 mCurrentDir = pathName;
224 emit pathChanged();
225}
226
227static bool fileCompare(const QFileInfo &a, const QFileInfo &b)
228{
229 if (a.isDir() && !b.isDir())
230 return true;
231
232 if (b.isDir() && !a.isDir())
233 return false;
234
235 return QString::localeAwareCompare(a.fileName(), b.fileName()) < 0;
236}
237
238void DirModel::onItemsAdded(const QVector<QFileInfo> &newFiles)
239{
240 qDebug() << Q_FUNC_INFO << "Got new files: " << newFiles.count();
241
242 if (mAwaitingResults) {
243 qDebug() << Q_FUNC_INFO << "No longer awaiting results";
244 mAwaitingResults = false;
245 emit awaitingResultsChanged();
246 }
247
248 foreach (const QFileInfo &fi, newFiles) {
249 if (!mShowDirectories && fi.isDir())
250 continue;
251
252 bool doAdd = true;
253 foreach (const QString &nameFilter, mNameFilters) {
254 // TODO: using QRegExp for wildcard matching is slow
255 QRegExp re(nameFilter, Qt::CaseInsensitive, QRegExp::Wildcard);
256 if (!re.exactMatch(fi.fileName())) {
257 doAdd = false;
258 break;
259 }
260 }
261
262 if (!doAdd)
263 continue;
264
265 QVector<QFileInfo>::Iterator it = qLowerBound(mDirectoryContents.begin(),
266 mDirectoryContents.end(),
267 fi,
268 fileCompare);
269
270 if (it == mDirectoryContents.end()) {
271 beginInsertRows(QModelIndex(), mDirectoryContents.count(), mDirectoryContents.count());
272 mDirectoryContents.append(fi);
273 endInsertRows();
274 } else {
275 int idx = it - mDirectoryContents.begin();
276 beginInsertRows(QModelIndex(), idx, idx);
277 mDirectoryContents.insert(it, fi);
278 endInsertRows();
279 }
280 }
281}
282
283void DirModel::rm(const QStringList &paths)
284{
285 // TODO: handle directory deletions?
286 bool error = false;
287
288 foreach (const QString &path, paths) {
289 error |= QFile::remove(path);
290
291 if (error) {
292 qWarning() << Q_FUNC_INFO << "Failed to remove " << path;
293 error = false;
294 }
295 }
296
297 // TODO: just remove removed items; don't reload the entire model
298 refresh();
299}
300
301bool DirModel::rename(int row, const QString &newName)
302{
303 qDebug() << Q_FUNC_INFO << "Renaming " << row << " to " << newName;
304 Q_ASSERT(row >= 0 && row < mDirectoryContents.count());
305 if (row < 0 || row >= mDirectoryContents.count()) {
306 qWarning() << Q_FUNC_INFO << "Out of bounds access";
307 return false;
308 }
309
310 const QFileInfo &fi = mDirectoryContents.at(row);
311
312 if (!fi.isDir()) {
313 QFile f(fi.absoluteFilePath());
314 bool retval = f.rename(fi.absolutePath() + QDir::separator() + newName);
315
316 if (!retval)
317 qDebug() << Q_FUNC_INFO << "Rename returned error code: " << f.error() << f.errorString();
318 else
319 refresh();
320 // TODO: just change the affected item... ^^
321
322 return retval;
323 } else {
324 QDir d(fi.absoluteFilePath());
325 bool retval = d.rename(fi.absoluteFilePath(), fi.absolutePath() + QDir::separator() + newName);
326
327 // QDir has no way to detect what went wrong. woohoo!
328
329 // TODO: just change the affected item...
330 refresh();
331
332 return retval;
333 }
334
335 // unreachable (we hope)
336 Q_ASSERT(false);
337 return false;
338}
339
340void DirModel::mkdir(const QString &newDir)
341{
342 qDebug() << Q_FUNC_INFO << "Creating new folder " << newDir << " to " << mCurrentDir;
343
344 QDir dir(mCurrentDir);
345 bool retval = dir.mkdir(newDir);
346 if (!retval) {
347 const char *errorStr = strerror(errno);
348 qDebug() << Q_FUNC_INFO << "Error creating new directory: " << errno << " (" << errorStr << ")";
349 emit error("Error creating new folder", errorStr);
350 } else {
351 refresh();
352 }
353}
354
355bool DirModel::showDirectories() const
356{
357 return mShowDirectories;
358}
359
360void DirModel::setShowDirectories(bool showDirectories)
361{
362 mShowDirectories = showDirectories;
363 refresh();
364 emit showDirectoriesChanged();
365}
366
367QStringList DirModel::nameFilters() const
368{
369 return mNameFilters;
370}
371
372void DirModel::setNameFilters(const QStringList &nameFilters)
373{
374 mNameFilters = nameFilters;
375 refresh();
376 emit nameFiltersChanged();
377}
378
379bool DirModel::awaitingResults() const
380{
381 return mAwaitingResults;
382}
383
384// for dirlistworker
385#include "dirmodel.moc"
0386
=== added file 'nemo-folderlistmodel/dirmodel.h'
--- nemo-folderlistmodel/dirmodel.h 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/dirmodel.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,124 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef DIRMODEL_H
33#define DIRMODEL_H
34
35#include <QAbstractListModel>
36#include <QFileInfo>
37#include <QVector>
38#include <QStringList>
39
40#include "iorequest.h"
41
42class DirModel : public QAbstractListModel
43{
44 Q_OBJECT
45
46 enum Roles {
47 FileNameRole = Qt::UserRole,
48 CreationDateRole,
49 ModifiedDateRole,
50 FileSizeRole,
51 IconSourceRole,
52 FilePathRole,
53 IsDirRole,
54 IsFileRole,
55 IsReadableRole,
56 IsWritableRole,
57 IsExecutableRole
58 };
59
60public:
61 DirModel(QObject *parent = 0);
62
63 int rowCount(const QModelIndex &index) const
64 {
65 if (index.parent() != QModelIndex())
66 return 0;
67
68 return mDirectoryContents.count();
69 }
70
71 // TODO: this won't be safe if the model can change under the holder of the row
72 Q_INVOKABLE QVariant data(int row, const QByteArray &stringRole) const;
73
74 QVariant data(const QModelIndex &index, int role) const;
75
76 Q_INVOKABLE void refresh()
77 {
78 // just some syntactical sugar really
79 setPath(path());
80 }
81
82 Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged);
83 inline QString path() const { return mCurrentDir; }
84
85 Q_PROPERTY(bool awaitingResults READ awaitingResults NOTIFY awaitingResultsChanged);
86 bool awaitingResults() const;
87
88 void setPath(const QString &pathName);
89
90 Q_INVOKABLE void rm(const QStringList &paths);
91
92 Q_INVOKABLE bool rename(int row, const QString &newName);
93
94 Q_INVOKABLE void mkdir(const QString &newdir);
95
96 Q_PROPERTY(bool showDirectories READ showDirectories WRITE setShowDirectories NOTIFY showDirectoriesChanged)
97 bool showDirectories() const;
98 void setShowDirectories(bool showDirectories);
99
100 Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
101 QStringList nameFilters() const;
102 void setNameFilters(const QStringList &nameFilters);
103
104public slots:
105 void onItemsAdded(const QVector<QFileInfo> &newFiles);
106
107signals:
108 void awaitingResultsChanged();
109 void nameFiltersChanged();
110 void showDirectoriesChanged();
111 void pathChanged();
112 void error(const QString &errorTitle, const QString &errorMessage);
113
114private:
115 QStringList mNameFilters;
116 bool mShowDirectories;
117 bool mAwaitingResults;
118 QString mCurrentDir;
119 QVector<QFileInfo> mDirectoryContents;
120 QHash<QByteArray, int> mRoleMapping;
121};
122
123
124#endif // DIRMODEL_H
0125
=== added file 'nemo-folderlistmodel/folderlistmodel.pro'
--- nemo-folderlistmodel/folderlistmodel.pro 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/folderlistmodel.pro 2013-06-01 17:20:36 +0000
@@ -0,0 +1,16 @@
1TARGET = nemofolderlistmodel
2PLUGIN_IMPORT_PATH = org/nemomobile/folderlistmodel
3
4SOURCES += plugin.cpp \
5 dirmodel.cpp \
6 iorequest.cpp \
7 iorequestworker.cpp \
8 ioworkerthread.cpp
9
10HEADERS += plugin.h \
11 dirmodel.h \
12 iorequest.h \
13 iorequestworker.h \
14 ioworkerthread.h
15
16include(../plugin.pri)
017
=== added file 'nemo-folderlistmodel/iorequest.cpp'
--- nemo-folderlistmodel/iorequest.cpp 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/iorequest.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include "iorequest.h"
33
34IORequest::IORequest() : QObject()
35{
36}
037
=== added file 'nemo-folderlistmodel/iorequest.h'
--- nemo-folderlistmodel/iorequest.h 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/iorequest.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef IOREQUEST_H
33#define IOREQUEST_H
34
35#include <QObject>
36
37class IORequest : public QObject
38{
39 Q_OBJECT
40public:
41 explicit IORequest();
42
43public:
44 virtual void run() = 0;
45
46private:
47 // hide this because IORequest should *NOT* be parented directly
48 using QObject::setParent;
49};
50
51#endif // IOREQUEST_H
052
=== added file 'nemo-folderlistmodel/iorequestworker.cpp'
--- nemo-folderlistmodel/iorequestworker.cpp 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/iorequestworker.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,92 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include <QMutexLocker>
33#include <QDebug>
34
35#include "iorequestworker.h"
36#include "iorequest.h"
37
38/*!
39 Lives on an IOWorkerThread.
40
41 Responsible for running IORequest jobs on the thread instance, and
42 disposing of their resources once they are done.
43 */
44IORequestWorker::IORequestWorker()
45 : QThread()
46 , mTimeToQuit(false)
47{
48}
49
50void IORequestWorker::addRequest(IORequest *request)
51{
52 request->moveToThread(this);
53
54 // TODO: queue requests so we run the most important one first
55 QMutexLocker lock(&mMutex);
56 mRequests.append(request);
57
58 // wake run()
59 mWaitCondition.wakeOne();
60}
61
62void IORequestWorker::run()
63{
64 forever {
65 QMutexLocker lock(&mMutex);
66
67 if (mTimeToQuit)
68 return;
69
70 if (mRequests.empty())
71 mWaitCondition.wait(&mMutex);
72
73 while (!mRequests.isEmpty()) {
74 IORequest *request = mRequests.takeFirst();
75
76 lock.unlock();
77
78 request->run();
79 request->deleteLater();
80
81 lock.relock();
82 }
83 }
84}
85
86void IORequestWorker::exit()
87{
88 qDebug() << Q_FUNC_INFO << "Quitting";
89 QMutexLocker lock(&mMutex);
90 mTimeToQuit = true;
91 mWaitCondition.wakeOne();
92}
093
=== added file 'nemo-folderlistmodel/iorequestworker.h'
--- nemo-folderlistmodel/iorequestworker.h 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/iorequestworker.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,61 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef IOREQUESTWORKER_H
33#define IOREQUESTWORKER_H
34
35#include <QObject>
36#include <QThread>
37#include <QMutex>
38#include <QWaitCondition>
39
40#include "iorequest.h"
41
42class IORequestWorker : public QThread
43{
44 Q_OBJECT
45public:
46 explicit IORequestWorker();
47
48 void addRequest(IORequest *request);
49
50 void run();
51
52 void exit();
53
54private:
55 QMutex mMutex;
56 QWaitCondition mWaitCondition;
57 QList<IORequest *> mRequests;
58 bool mTimeToQuit;
59};
60
61#endif // IOREQUESTWORKER_H
062
=== added file 'nemo-folderlistmodel/ioworkerthread.cpp'
--- nemo-folderlistmodel/ioworkerthread.cpp 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/ioworkerthread.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include "ioworkerthread.h"
33
34
35/*!
36 Hosts a thread, lives on the main thread.
37
38 Responsible for relaying interaction between the main thread and an IOWorkerThread.
39 */
40IOWorkerThread::IOWorkerThread(QObject *parent) :
41 QObject(parent)
42{
43 mWorker.start(QThread::IdlePriority);
44}
45
46/*!
47 Destroys an IOWorkerThread instance.
48 */
49IOWorkerThread::~IOWorkerThread()
50{
51 mWorker.exit();
52 mWorker.wait();
53}
54
55/*!
56 Attempts an asynchronous attempt to start a \a request.
57
58 If the request may be run, it is queued, and true is returned, otherwise, false.
59 */
60bool IOWorkerThread::addRequest(IORequest *request)
61{
62 mWorker.addRequest(request);
63 return true;
64}
065
=== added file 'nemo-folderlistmodel/ioworkerthread.h'
--- nemo-folderlistmodel/ioworkerthread.h 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/ioworkerthread.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,52 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef IOWORKERTHREAD_H
33#define IOWORKERTHREAD_H
34
35#include <QObject>
36#include <QThread>
37
38#include "iorequestworker.h"
39
40class IOWorkerThread : public QObject
41{
42 Q_OBJECT
43public:
44 explicit IOWorkerThread(QObject *parent = 0);
45 virtual ~IOWorkerThread();
46 bool addRequest(IORequest *request);
47
48private:
49 IORequestWorker mWorker;
50};
51
52#endif // IOWORKERTHREAD_H
053
=== added file 'nemo-folderlistmodel/plugin.cpp'
--- nemo-folderlistmodel/plugin.cpp 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/plugin.cpp 2013-06-01 17:20:36 +0000
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#include <QVector>
33#include <QFileInfo>
34
35#include "plugin.h"
36
37NemoFolderListModelPlugin::NemoFolderListModelPlugin() { }
38
39NemoFolderListModelPlugin::~NemoFolderListModelPlugin() { }
40
41void NemoFolderListModelPlugin::initializeEngine(QmlEngine *engine, const char *uri)
42{
43 Q_UNUSED(engine)
44 Q_ASSERT(uri == QLatin1String("org.nemomobile.folderlistmodel"));
45}
46
47void NemoFolderListModelPlugin::registerTypes(const char *uri)
48{
49 Q_ASSERT(uri == QLatin1String("org.nemomobile.folderlistmodel"));
50 qRegisterMetaType<QVector<QFileInfo> >();
51 qmlRegisterType<DirModel>(uri, 1, 0, "FolderListModel");
52}
53
054
=== added file 'nemo-folderlistmodel/plugin.h'
--- nemo-folderlistmodel/plugin.h 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/plugin.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,82 @@
1/*
2 * Copyright (C) 2012 Robin Burchell <robin+nemo@viroteck.net>
3 *
4 * You may use this file under the terms of the BSD license as follows:
5 *
6 * "Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Nemo Mobile nor the names of its contributors
16 * may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
30 */
31
32#ifndef NEMO_QML_PLUGINS_FOLDERLISTMODEL
33#define NEMO_QML_PLUGINS_FOLDERLISTMODEL
34
35#include <QtGlobal>
36
37#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
38#include <QtDeclarative>
39#include <QDeclarativeEngine>
40#include <QDeclarativeExtensionPlugin>
41#include <QVector>
42#include <QFileInfo>
43
44#define PLUGIN_CLASS_EXPORT
45#define PLUGIN_CLASS_EXTERNAL_EXPORT Q_EXPORT_PLUGIN2(nemofolderlistmodel, NemoFolderListModelPlugin);
46#define PLUGIN_CLASS_EXTEND
47typedef QDeclarativeExtensionPlugin QmlPluginParent;
48typedef QDeclarativeEngine QmlEngine;
49Q_DECLARE_METATYPE(QVector<QFileInfo>)
50
51#else
52#include <QQmlComponent>
53#include <QQmlEngine>
54#include <QQmlContext>
55#include <QQmlExtensionPlugin>
56
57#define PLUGIN_CLASS_EXPORT Q_DECL_EXPORT
58#define PLUGIN_CLASS_EXTERNAL_EXPORT
59#define PLUGIN_CLASS_EXTEND \
60 Q_OBJECT \
61 Q_PLUGIN_METADATA(IID "org.nemomobile.folderlistmodel")
62typedef QQmlExtensionPlugin QmlPluginParent;
63typedef QQmlEngine QmlEngine;
64#endif
65
66#include "dirmodel.h"
67
68class PLUGIN_CLASS_EXPORT NemoFolderListModelPlugin : public QmlPluginParent
69{
70 PLUGIN_CLASS_EXTEND
71
72public:
73 NemoFolderListModelPlugin();
74 virtual ~NemoFolderListModelPlugin();
75
76 void initializeEngine(QmlEngine *engine, const char *uri);
77 void registerTypes(const char *uri);
78};
79
80PLUGIN_CLASS_EXTERNAL_EXPORT
81
82#endif // NEMO_QML_PLUGINS_FOLDERLISTMODEL
083
=== added file 'nemo-folderlistmodel/qmldir'
--- nemo-folderlistmodel/qmldir 1970-01-01 00:00:00 +0000
+++ nemo-folderlistmodel/qmldir 2013-06-01 17:20:36 +0000
@@ -0,0 +1,1 @@
1plugin nemofolderlistmodel
02
=== added directory 'test_folderlistmodel'
=== added directory 'test_folderlistmodel/regression'
=== added file 'test_folderlistmodel/regression/media_asx.h'
--- test_folderlistmodel/regression/media_asx.h 1970-01-01 00:00:00 +0000
+++ test_folderlistmodel/regression/media_asx.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,21 @@
1const unsigned char media_asx[] = {
2 0x3c, 0x61, 0x73, 0x78, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
3 0x3d, 0x22, 0x33, 0x2e, 0x30, 0x22, 0x3e, 0x0d, 0x0a, 0x3c, 0x65, 0x6e,
4 0x74, 0x72, 0x79, 0x3e, 0x0d, 0x0a, 0x3c, 0x72, 0x65, 0x66, 0x20, 0x68,
5 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
6 0x72, 0x65, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x61, 0x62, 0x61, 0x63, 0x61,
7 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77,
8 0x61, 0x79, 0x2f, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e,
9 0x61, 0x73, 0x70, 0x3f, 0x73, 0x63, 0x3d, 0x77, 0x74, 0x72, 0x78, 0x2d,
10 0x66, 0x6d, 0x22, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x65, 0x6e,
11 0x74, 0x72, 0x79, 0x3e, 0x0d, 0x0a, 0x3c, 0x65, 0x6e, 0x74, 0x72, 0x79,
12 0x3e, 0x0d, 0x0a, 0x3c, 0x72, 0x65, 0x66, 0x20, 0x68, 0x72, 0x65, 0x66,
13 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6d, 0x65, 0x64,
14 0x69, 0x61, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x61, 0x64, 0x73,
15 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x64,
16 0x61, 0x74, 0x61, 0x2f, 0x72, 0x65, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61,
17 0x73, 0x78, 0x2f, 0x57, 0x54, 0x52, 0x58, 0x2e, 0x61, 0x73, 0x78, 0x22,
18 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x65, 0x6e, 0x74, 0x72, 0x79,
19 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x61, 0x73, 0x78, 0x3e, 0x0d, 0x0a
20};
21qint64 media_asx_len = 215;
022
=== added file 'test_folderlistmodel/regression/media_xspf.h'
--- test_folderlistmodel/regression/media_xspf.h 1970-01-01 00:00:00 +0000
+++ test_folderlistmodel/regression/media_xspf.h 2013-06-01 17:20:36 +0000
@@ -0,0 +1,135 @@
1const unsigned char media_xspf[] = {
2 0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
3 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f,
4 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x22,
5 0x3f, 0x3e, 0x0a, 0x3c, 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74,
6 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x22,
7 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70,
8 0x3a, 0x2f, 0x2f, 0x78, 0x73, 0x70, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
9 0x6e, 0x73, 0x2f, 0x30, 0x2f, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73,
10 0x3a, 0x76, 0x6c, 0x63, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
11 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61,
12 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x76, 0x6c, 0x63, 0x2f, 0x70, 0x6c,
13 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x6e, 0x73, 0x2f, 0x30, 0x2f,
14 0x22, 0x3e, 0x0a, 0x09, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x4c,
15 0x69, 0x73, 0x74, 0x61, 0x20, 0x64, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72,
16 0x6f, 0x64, 0x75, 0xc3, 0xa7, 0xc3, 0xa3, 0x6f, 0x3c, 0x2f, 0x74, 0x69,
17 0x74, 0x6c, 0x65, 0x3e, 0x0a, 0x09, 0x3c, 0x74, 0x72, 0x61, 0x63, 0x6b,
18 0x4c, 0x69, 0x73, 0x74, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
19 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74,
20 0x72, 0x61, 0x63, 0x6b, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
21 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
22 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x4c, 0x69, 0x61, 0x6e, 0xc3,
23 0xa7, 0x61, 0x2f, 0x45, 0x41, 0x45, 0x20, 0x70, 0x61, 0x72, 0x61, 0x20,
24 0x61, 0x20, 0x53, 0x6f, 0x63, 0x69, 0x65, 0x64, 0x61, 0x64, 0x65, 0x3c,
25 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
26 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
27 0x20, 0x20, 0x3c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
28 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f, 0x6d, 0x6e, 0x74, 0x2f,
29 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x61, 0x75, 0x6c, 0x61, 0x73,
30 0x2f, 0x45, 0x41, 0x45, 0x2f, 0x31, 0x31, 0x35, 0x25, 0x32, 0x30, 0x50,
31 0x72, 0x6f, 0x70, 0x61, 0x67, 0x61, 0x63, 0x61, 0x6f, 0x5f, 0x64, 0x6f,
32 0x5f, 0x45, 0x73, 0x70, 0x69, 0x72, 0x69, 0x74, 0x69, 0x73, 0x6d, 0x6f,
33 0x2f, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x73, 0x2f, 0x4f, 0x25, 0x32, 0x30,
34 0x71, 0x75, 0x65, 0x25, 0x32, 0x30, 0x65, 0x25, 0x32, 0x30, 0x61, 0x25,
35 0x32, 0x30, 0x45, 0x41, 0x45, 0x25, 0x32, 0x30, 0x31, 0x2e, 0x6d, 0x70,
36 0x34, 0x3c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
37 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
38 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
39 0x20, 0x3c, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20,
40 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3d,
41 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
42 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67,
43 0x2f, 0x76, 0x6c, 0x63, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73,
44 0x74, 0x2f, 0x30, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
45 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
46 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
47 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x69, 0x64, 0x3e, 0x30, 0x3c,
48 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x69, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20,
49 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
50 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76,
51 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x73, 0x74,
52 0x61, 0x72, 0x74, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x3d, 0x34, 0x35, 0x3c,
53 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
54 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
55 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
56 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f,
57 0x6e, 0x3e, 0x73, 0x74, 0x6f, 0x70, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x3d,
58 0x36, 0x39, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69,
59 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
60 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
61 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70,
62 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72,
63 0x65, 0x65, 0x6e, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74,
64 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
65 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
66 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f,
67 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65,
68 0x3d, 0x35, 0x30, 0x30, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70,
69 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
70 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
71 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x65, 0x78, 0x74, 0x65,
72 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
73 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
74 0x2f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x74,
75 0x72, 0x61, 0x63, 0x6b, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
76 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
77 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x48, 0x69, 0x73, 0x74, 0x6f,
78 0x72, 0x69, 0x61, 0x20, 0x64, 0x6f, 0x20, 0x45, 0x73, 0x70, 0x69, 0x72,
79 0x69, 0x74, 0x69, 0x73, 0x6d, 0x6f, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c,
80 0x65, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
81 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x6f,
82 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x66, 0x69, 0x6c, 0x65, 0x3a,
83 0x2f, 0x2f, 0x2f, 0x6d, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75,
84 0x70, 0x2f, 0x61, 0x75, 0x6c, 0x61, 0x73, 0x2f, 0x45, 0x41, 0x45, 0x2f,
85 0x31, 0x31, 0x35, 0x25, 0x32, 0x30, 0x50, 0x72, 0x6f, 0x70, 0x61, 0x67,
86 0x61, 0x63, 0x61, 0x6f, 0x5f, 0x64, 0x6f, 0x5f, 0x45, 0x73, 0x70, 0x69,
87 0x72, 0x69, 0x74, 0x69, 0x73, 0x6d, 0x6f, 0x2f, 0x76, 0x69, 0x64, 0x65,
88 0x6f, 0x73, 0x2f, 0x4f, 0x25, 0x32, 0x30, 0x71, 0x75, 0x65, 0x25, 0x32,
89 0x30, 0x65, 0x25, 0x32, 0x30, 0x61, 0x25, 0x32, 0x30, 0x45, 0x41, 0x45,
90 0x25, 0x32, 0x30, 0x31, 0x2e, 0x6d, 0x70, 0x34, 0x3c, 0x2f, 0x6c, 0x6f,
91 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c,
92 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70,
93 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x68,
94 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69,
95 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x76,
96 0x6c, 0x63, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74, 0x2f,
97 0x30, 0x22, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x76, 0x6c, 0x63,
98 0x3a, 0x69, 0x64, 0x3e, 0x31, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x69,
99 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
100 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
101 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74,
102 0x69, 0x6f, 0x6e, 0x3e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x2d, 0x74, 0x69,
103 0x6d, 0x65, 0x3d, 0x31, 0x39, 0x37, 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a,
104 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
105 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
106 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x76, 0x6c,
107 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x73, 0x74, 0x6f,
108 0x70, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x3d, 0x32, 0x36, 0x37, 0x3c, 0x2f,
109 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a,
110 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
111 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
112 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
113 0x3e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x3c,
114 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
115 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
116 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
117 0x20, 0x20, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f,
118 0x6e, 0x3e, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x3d, 0x35, 0x30, 0x30,
119 0x3c, 0x2f, 0x76, 0x6c, 0x63, 0x3a, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
120 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e,
121 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x74, 0x72,
122 0x61, 0x63, 0x6b, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x74, 0x72, 0x61, 0x63,
123 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x65, 0x78, 0x74,
124 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69,
125 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70,
126 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f,
127 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x76, 0x6c, 0x63, 0x2f,
128 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x30, 0x22, 0x3e,
129 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x76, 0x6c, 0x63, 0x3a, 0x69, 0x74, 0x65,
130 0x6d, 0x20, 0x74, 0x69, 0x64, 0x3d, 0x22, 0x30, 0x22, 0x20, 0x2f, 0x3e,
131 0x0a, 0x09, 0x3c, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
132 0x6e, 0x3e, 0x0a, 0x3c, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73,
133 0x74, 0x3e, 0x0a
134};
135qint64 media_xspf_len = 1575;
0136
=== added directory 'test_folderlistmodel/regression/mimetypes'
=== added file 'test_folderlistmodel/regression/mimetypes/LICENSE.LGPL'
--- test_folderlistmodel/regression/mimetypes/LICENSE.LGPL 1970-01-01 00:00:00 +0000
+++ test_folderlistmodel/regression/mimetypes/LICENSE.LGPL 2013-06-01 17:20:36 +0000
@@ -0,0 +1,504 @@
1 GNU LESSER GENERAL PUBLIC LICENSE
2 Version 2.1, February 1999
3
4 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9[This is the first released version of the Lesser GPL. It also counts
10 as the successor of the GNU Library Public License, version 2, hence
11 the version number 2.1.]
12
13 Preamble
14
15 The licenses for most software are designed to take away your
16freedom to share and change it. By contrast, the GNU General Public
17Licenses are intended to guarantee your freedom to share and change
18free software--to make sure the software is free for all its users.
19
20 This license, the Lesser General Public License, applies to some
21specially designated software packages--typically libraries--of the
22Free Software Foundation and other authors who decide to use it. You
23can use it too, but we suggest you first think carefully about whether
24this license or the ordinary General Public License is the better
25strategy to use in any particular case, based on the explanations below.
26
27 When we speak of free software, we are referring to freedom of use,
28not price. Our General Public Licenses are designed to make sure that
29you have the freedom to distribute copies of free software (and charge
30for this service if you wish); that you receive source code or can get
31it if you want it; that you can change the software and use pieces of
32it in new free programs; and that you are informed that you can do
33these things.
34
35 To protect your rights, we need to make restrictions that forbid
36distributors to deny you these rights or to ask you to surrender these
37rights. These restrictions translate to certain responsibilities for
38you if you distribute copies of the library or if you modify it.
39
40 For example, if you distribute copies of the library, whether gratis
41or for a fee, you must give the recipients all the rights that we gave
42you. You must make sure that they, too, receive or can get the source
43code. If you link other code with the library, you must provide
44complete object files to the recipients, so that they can relink them
45with the library after making changes to the library and recompiling
46it. And you must show them these terms so they know their rights.
47
48 We protect your rights with a two-step method: (1) we copyright the
49library, and (2) we offer you this license, which gives you legal
50permission to copy, distribute and/or modify the library.
51
52 To protect each distributor, we want to make it very clear that
53there is no warranty for the free library. Also, if the library is
54modified by someone else and passed on, the recipients should know
55that what they have is not the original version, so that the original
56author's reputation will not be affected by problems that might be
57introduced by others.
58
059
60 Finally, software patents pose a constant threat to the existence of
61any free program. We wish to make sure that a company cannot
62effectively restrict the users of a free program by obtaining a
63restrictive license from a patent holder. Therefore, we insist that
64any patent license obtained for a version of the library must be
65consistent with the full freedom of use specified in this license.
66
67 Most GNU software, including some libraries, is covered by the
68ordinary GNU General Public License. This license, the GNU Lesser
69General Public License, applies to certain designated libraries, and
70is quite different from the ordinary General Public License. We use
71this license for certain libraries in order to permit linking those
72libraries into non-free programs.
73
74 When a program is linked with a library, whether statically or using
75a shared library, the combination of the two is legally speaking a
76combined work, a derivative of the original library. The ordinary
77General Public License therefore permits such linking only if the
78entire combination fits its criteria of freedom. The Lesser General
79Public License permits more lax criteria for linking other code with
80the library.
81
82 We call this license the "Lesser" General Public License because it
83does Less to protect the user's freedom than the ordinary General
84Public License. It also provides other free software developers Less
85of an advantage over competing non-free programs. These disadvantages
86are the reason we use the ordinary General Public License for many
87libraries. However, the Lesser license provides advantages in certain
88special circumstances.
89
90 For example, on rare occasions, there may be a special need to
91encourage the widest possible use of a certain library, so that it becomes
92a de-facto standard. To achieve this, non-free programs must be
93allowed to use the library. A more frequent case is that a free
94library does the same job as widely used non-free libraries. In this
95case, there is little to gain by limiting the free library to free
96software only, so we use the Lesser General Public License.
97
98 In other cases, permission to use a particular library in non-free
99programs enables a greater number of people to use a large body of
100free software. For example, permission to use the GNU C Library in
101non-free programs enables many more people to use the whole GNU
102operating system, as well as its variant, the GNU/Linux operating
103system.
104
105 Although the Lesser General Public License is Less protective of the
106users' freedom, it does ensure that the user of a program that is
107linked with the Library has the freedom and the wherewithal to run
108that program using a modified version of the Library.
109
110 The precise terms and conditions for copying, distribution and
111modification follow. Pay close attention to the difference between a
112"work based on the library" and a "work that uses the library". The
113former contains code derived from the library, whereas the latter must
114be combined with the library in order to run.
115
1116
117 GNU LESSER GENERAL PUBLIC LICENSE
118 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
119
120 0. This License Agreement applies to any software library or other
121program which contains a notice placed by the copyright holder or
122other authorized party saying it may be distributed under the terms of
123this Lesser General Public License (also called "this License").
124Each licensee is addressed as "you".
125
126 A "library" means a collection of software functions and/or data
127prepared so as to be conveniently linked with application programs
128(which use some of those functions and data) to form executables.
129
130 The "Library", below, refers to any such software library or work
131which has been distributed under these terms. A "work based on the
132Library" means either the Library or any derivative work under
133copyright law: that is to say, a work containing the Library or a
134portion of it, either verbatim or with modifications and/or translated
135straightforwardly into another language. (Hereinafter, translation is
136included without limitation in the term "modification".)
137
138 "Source code" for a work means the preferred form of the work for
139making modifications to it. For a library, complete source code means
140all the source code for all modules it contains, plus any associated
141interface definition files, plus the scripts used to control compilation
142and installation of the library.
143
144 Activities other than copying, distribution and modification are not
145covered by this License; they are outside its scope. The act of
146running a program using the Library is not restricted, and output from
147such a program is covered only if its contents constitute a work based
148on the Library (independent of the use of the Library in a tool for
149writing it). Whether that is true depends on what the Library does
150and what the program that uses the Library does.
151
152 1. You may copy and distribute verbatim copies of the Library's
153complete source code as you receive it, in any medium, provided that
154you conspicuously and appropriately publish on each copy an
155appropriate copyright notice and disclaimer of warranty; keep intact
156all the notices that refer to this License and to the absence of any
157warranty; and distribute a copy of this License along with the
158Library.
159
160 You may charge a fee for the physical act of transferring a copy,
161and you may at your option offer warranty protection in exchange for a
162fee.
163
2164
165 2. You may modify your copy or copies of the Library or any portion
166of it, thus forming a work based on the Library, and copy and
167distribute 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