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