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

Proposed by Carlos Jose Mazieri
Status: Merged
Approved by: Carlos Jose Mazieri
Approved revision: 63
Merged at revision: 48
Proposed branch: lp:~carlos-mazieri/ubuntu-filemanager-app/model
Merge into: lp:ubuntu-filemanager-app/plugin
Diff against target: 3582 lines (+2441/-386)
27 files modified
folderlistmodel/diriteminfo.cpp (+50/-69)
folderlistmodel/diriteminfo.h (+47/-5)
folderlistmodel/dirmodel.cpp (+151/-158)
folderlistmodel/dirmodel.h (+20/-24)
folderlistmodel/disk/disklocation.cpp (+222/-0)
folderlistmodel/disk/disklocation.h (+81/-0)
folderlistmodel/externalfswatcher.cpp (+35/-18)
folderlistmodel/externalfswatcher.h (+11/-6)
folderlistmodel/filecompare.cpp (+2/-3)
folderlistmodel/folderlistmodel.pri (+16/-2)
folderlistmodel/iorequest.cpp (+139/-36)
folderlistmodel/iorequest.h (+76/-15)
folderlistmodel/location.cpp (+140/-0)
folderlistmodel/location.h (+132/-0)
folderlistmodel/locationsfactory.cpp (+183/-0)
folderlistmodel/locationsfactory.h (+133/-0)
folderlistmodel/locationurl.cpp (+34/-0)
folderlistmodel/locationurl.h (+40/-0)
folderlistmodel/trash/qtrashdir.cpp (+21/-18)
folderlistmodel/trash/qtrashdir.h (+3/-14)
folderlistmodel/trash/qtrashutilinfo.cpp (+87/-0)
folderlistmodel/trash/qtrashutilinfo.h (+57/-0)
folderlistmodel/trash/trashiteminfo.cpp (+141/-0)
folderlistmodel/trash/trashiteminfo.h (+58/-0)
folderlistmodel/trash/trashlocation.cpp (+255/-0)
folderlistmodel/trash/trashlocation.h (+54/-0)
test_folderlistmodel/regression/tst_folderlistmodel.cpp (+253/-18)
To merge this branch: bzr merge lp:~carlos-mazieri/ubuntu-filemanager-app/model
Reviewer Review Type Date Requested Status
Carlos Jose Mazieri Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+212319@code.launchpad.net

Commit message

File Manager UI will requires changes from this point.

Description of the change

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.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Carlos Jose Mazieri (carlos-mazieri) wrote :

Due to there were no comments from anyone else, I have to approve it myself.

review: Approve
Revision history for this message
David Planella (dpm) wrote :

Carlos, could you check this MP as well?
https://code.launchpad.net/~dpm/ubuntu-filemanager-app/include-plugin/+merge/213368

It'd be good if we could land that and do any new changes in there

On Sat, Apr 5, 2014 at 3:20 PM, <email address hidden> wrote:

> The proposal to merge lp:~carlos-mazieri/ubuntu-filemanager-app/model into
> lp:ubuntu-filemanager-app/plugin has been updated.
>
> Status: Approved => Merged
>
> For more details, see:
>
> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+merge/212319
> --
>
> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+merge/212319
> Your team Ubuntu File Manager Developers is subscribed to branch
> lp:ubuntu-filemanager-app/plugin.
>

Revision history for this message
Carlos Jose Mazieri (carlos-mazieri) wrote :

David,

Sure, I will take a look on that.

Carlos

On 4/7/14, David Planella <email address hidden> wrote:
> Carlos, could you check this MP as well?
> https://code.launchpad.net/~dpm/ubuntu-filemanager-app/include-plugin/+merge/213368
>
> It'd be good if we could land that and do any new changes in there
>
>
> On Sat, Apr 5, 2014 at 3:20 PM, <email address hidden> wrote:
>
>> The proposal to merge lp:~carlos-mazieri/ubuntu-filemanager-app/model
>> into
>> lp:ubuntu-filemanager-app/plugin has been updated.
>>
>> Status: Approved => Merged
>>
>> For more details, see:
>>
>> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+merge/212319
>> --
>>
>> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+merge/212319
>> Your team Ubuntu File Manager Developers is subscribed to branch
>> lp:ubuntu-filemanager-app/plugin.
>>
>
> --
> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+merge/212319
> You are the owner of lp:~carlos-mazieri/ubuntu-filemanager-app/model.
>

Revision history for this message
Carlos Jose Mazieri (carlos-mazieri) wrote :

David,

The Status from this MP says "Work in progress",
What do you expect me to do in this MP?

Carlos

On Monday 07 April 2014 18:36:25 you wrote:
> David,
>
> Sure, I will take a look on that.
>
> Carlos
>
> On 4/7/14, David Planella <email address hidden> wrote:
> > Carlos, could you check this MP as well?
> > https://code.launchpad.net/~dpm/ubuntu-filemanager-app/include-plugin/+mer
> > ge/213368
> >
> > It'd be good if we could land that and do any new changes in there
> >
> > On Sat, Apr 5, 2014 at 3:20 PM, <email address hidden> wrote:
> >> The proposal to merge lp:~carlos-mazieri/ubuntu-filemanager-app/model
> >> into
> >> lp:ubuntu-filemanager-app/plugin has been updated.
> >>
> >> Status: Approved => Merged
> >>
> >> For more details, see:
> >>
> >> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+
> >> merge/212319 --
> >>
> >> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+
> >> merge/212319 Your team Ubuntu File Manager Developers is subscribed to
> >> branch
> >> lp:ubuntu-filemanager-app/plugin.
> >
> > --
> > https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+m
> > erge/212319 You are the owner of
> > lp:~carlos-mazieri/ubuntu-filemanager-app/model.

Revision history for this message
David Planella (dpm) wrote :

Hi Carlos,

I think it should be ready for review now after the latest changes. Let me
change the status to Needs Review, and if you could do a review of the MP,
that'd be awesome.

Thanks!

On Tue, Apr 8, 2014 at 1:24 AM, Carlos Jose Mazieri <
<email address hidden>> wrote:

> David,
>
> The Status from this MP says "Work in progress",
> What do you expect me to do in this MP?
>
> Carlos
>
> On Monday 07 April 2014 18:36:25 you wrote:
> > David,
> >
> > Sure, I will take a look on that.
> >
> > Carlos
> >
> > On 4/7/14, David Planella <email address hidden> wrote:
> > > Carlos, could you check this MP as well?
> > >
> https://code.launchpad.net/~dpm/ubuntu-filemanager-app/include-plugin/+mer
> > > ge/213368
> > >
> > > It'd be good if we could land that and do any new changes in there
> > >
> > > On Sat, Apr 5, 2014 at 3:20 PM, <email address hidden> wrote:
> > >> The proposal to merge lp:~carlos-mazieri/ubuntu-filemanager-app/model
> > >> into
> > >> lp:ubuntu-filemanager-app/plugin has been updated.
> > >>
> > >> Status: Approved => Merged
> > >>
> > >> For more details, see:
> > >>
> > >>
> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+
> > >> merge/212319 --
> > >>
> > >>
> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+
> > >> merge/212319 Your team Ubuntu File Manager Developers is subscribed to
> > >> branch
> > >> lp:ubuntu-filemanager-app/plugin.
> > >
> > > --
> > >
> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+m
> > > erge/212319 You are the owner of
> > > lp:~carlos-mazieri/ubuntu-filemanager-app/model.
>
>
> --
>
> https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/model/+merge/212319
> Your team Ubuntu File Manager Developers is subscribed to branch
> lp:ubuntu-filemanager-app/plugin.
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'folderlistmodel/diriteminfo.cpp'
2--- folderlistmodel/diriteminfo.cpp 2014-02-07 13:22:44 +0000
3+++ folderlistmodel/diriteminfo.cpp 2014-03-23 13:46:13 +0000
4@@ -22,45 +22,6 @@
5 #include "diriteminfo.h"
6
7
8-
9-
10-#include <QUrl>
11-#include <QDir>
12-
13-
14-class DirItemInfoPrivate : public QSharedData
15-{
16-public:
17- DirItemInfoPrivate();
18- DirItemInfoPrivate(const DirItemInfoPrivate& other);
19- DirItemInfoPrivate(const QFileInfo& fi);
20- void setFileInfo(const QFileInfo&);
21-
22-public:
23- bool _isValid :1;
24- bool _isLocal :1;
25- bool _isRemote :1;
26- bool _isSelected :1;
27- bool _isAbsolute :1;
28- bool _exists :1;
29- bool _isFile :1;
30- bool _isDir :1;
31- bool _isSymLink :1;
32- bool _isRoot :1;
33- bool _isReadable :1;
34- bool _isWritable :1;
35- bool _isExecutable:1;
36- QFile::Permissions _permissions;
37- qint64 _size;
38- QDateTime _created;
39- QDateTime _lastModified;
40- QDateTime _lastRead;
41- QString _path;
42- QString _fileName;
43- static QMimeDatabase mimeDatabase;
44-};
45-
46-
47 QMimeDatabase DirItemInfoPrivate::mimeDatabase;
48
49
50@@ -128,22 +89,23 @@
51 }
52 else
53 {
54- _path = fi.absolutePath();
55- _fileName = fi.fileName();
56- _isAbsolute = fi.isAbsolute();
57- _exists = fi.exists();
58- _isDir = fi.isDir();
59- _isFile = fi.isFile();
60- _isSymLink = fi.isSymLink();
61- _isRoot = fi.isRoot();
62- _isReadable = fi.isReadable();
63- _isWritable = fi.isWritable();
64- _isExecutable = fi.isExecutable();
65- _permissions = fi.permissions();
66- _size = fi.size();
67- _created = fi.created();
68- _lastRead = fi.lastRead();
69- _lastModified = fi.lastModified();
70+ _path = fi.absolutePath();
71+ _normalizedPath = _path;
72+ _fileName = fi.fileName();
73+ _isAbsolute = fi.isAbsolute();
74+ _exists = fi.exists();
75+ _isDir = fi.isDir();
76+ _isFile = fi.isFile();
77+ _isSymLink = fi.isSymLink();
78+ _isRoot = fi.isRoot();
79+ _isReadable = fi.isReadable();
80+ _isWritable = fi.isWritable();
81+ _isExecutable = fi.isExecutable();
82+ _permissions = fi.permissions();
83+ _size = fi.size();
84+ _created = fi.created();
85+ _lastRead = fi.lastRead();
86+ _lastModified = fi.lastModified();
87 }
88 }
89
90@@ -168,8 +130,8 @@
91
92
93
94-DirItemInfo::DirItemInfo(const QString& urlOrPath):
95- d_ptr( new DirItemInfoPrivate(QFileInfo(urlOrPath)) )
96+DirItemInfo::DirItemInfo(const QString& filePath):
97+ d_ptr( new DirItemInfoPrivate(QFileInfo(filePath)) )
98 {
99
100 }
101@@ -219,21 +181,14 @@
102 return d_ptr->_exists;
103 }
104
105+
106+
107 QString DirItemInfo::filePath() const
108 {
109- QString filepath;
110- if (!d_ptr->_path.isEmpty())
111- {
112- filepath = d_ptr->_path;
113- if (d_ptr->_path != QDir::rootPath())
114- {
115- filepath += QDir::separator();
116- }
117- }
118- filepath += d_ptr->_fileName;
119- return filepath;
120+ return filePathFrom(d_ptr->_path);
121 }
122
123+
124 QString DirItemInfo::fileName() const
125 {
126 return d_ptr->_fileName;
127@@ -251,7 +206,12 @@
128
129 bool DirItemInfo::isReadable() const
130 {
131- return d_ptr->_isReadable;
132+ bool readable = d_ptr->_isReadable;
133+ if (isDir() && !isSymLink())
134+ {
135+ readable &= isExecutable();
136+ }
137+ return readable;
138 }
139
140 bool DirItemInfo::isWritable() const
141@@ -343,3 +303,24 @@
142 return d_ptr->mimeDatabase.mimeTypeForFile(diskFileInfo());
143 }
144
145+
146+QString DirItemInfo::urlPath() const
147+{
148+ return filePathFrom(d_ptr->_normalizedPath);
149+}
150+
151+
152+QString DirItemInfo::filePathFrom(const QString& p) const
153+{
154+ QString filepath;
155+ if (!p.isEmpty())
156+ {
157+ filepath = p;
158+ if (!p.endsWith(QDir::separator()) && !d_ptr->_fileName.isEmpty())
159+ {
160+ filepath += QDir::separator();
161+ }
162+ }
163+ filepath += d_ptr->_fileName;
164+ return filepath;
165+}
166
167=== modified file 'folderlistmodel/diriteminfo.h'
168--- folderlistmodel/diriteminfo.h 2014-02-07 13:22:44 +0000
169+++ folderlistmodel/diriteminfo.h 2014-03-23 13:46:13 +0000
170@@ -27,7 +27,7 @@
171 #include <QFileInfo>
172 #include <QSharedData>
173 #include <QDateTime>
174-
175+#include <QDir>
176 #include <QMimeType>
177 #include <QMimeDatabase>
178
179@@ -46,9 +46,10 @@
180 {
181 public:
182 DirItemInfo();
183- DirItemInfo(const QString& urlOrPath);
184- DirItemInfo(const QFileInfo&);
185+ DirItemInfo(const QString& filePath);
186 DirItemInfo(const DirItemInfo& other);
187+ DirItemInfo(const QFileInfo& fi);
188+
189
190 virtual ~DirItemInfo();
191
192@@ -74,7 +75,7 @@
193 inline void swap(DirItemInfo &other)
194 { qSwap(d_ptr, other.d_ptr); }
195
196- inline DirItemInfo& operator=(const DirItemInfo &other)
197+ virtual inline DirItemInfo& operator=(const DirItemInfo &other)
198 { swap(*(const_cast<DirItemInfo*>(&other))); return *this; }
199
200 virtual bool exists() const;
201@@ -82,7 +83,8 @@
202 virtual QString fileName() const;
203 virtual QString path() const;
204 virtual QString absolutePath() const;
205- virtual QString absoluteFilePath() const;
206+ virtual QString absoluteFilePath() const;
207+ virtual QString urlPath() const;
208 virtual bool isReadable() const;
209 virtual bool isWritable() const;
210 virtual bool isExecutable() const;
211@@ -110,6 +112,8 @@
212 virtual bool permission(QFile::Permissions permissions) const;
213 #endif
214
215+protected:
216+ QString filePathFrom(const QString& path) const;
217
218 protected:
219 QSharedDataPointer<DirItemInfoPrivate> d_ptr;
220@@ -120,4 +124,42 @@
221 Q_DECLARE_SHARED(DirItemInfo)
222 Q_DECLARE_METATYPE(DirItemInfo)
223
224+
225+
226+
227+class DirItemInfoPrivate : public QSharedData
228+{
229+public:
230+ DirItemInfoPrivate();
231+ DirItemInfoPrivate(const DirItemInfoPrivate& other);
232+ DirItemInfoPrivate(const QFileInfo& fi);
233+ void setFileInfo(const QFileInfo&);
234+
235+public:
236+ bool _isValid :1;
237+ bool _isLocal :1;
238+ bool _isRemote :1;
239+ bool _isSelected :1;
240+ bool _isAbsolute :1;
241+ bool _exists :1;
242+ bool _isFile :1;
243+ bool _isDir :1;
244+ bool _isSymLink :1;
245+ bool _isRoot :1;
246+ bool _isReadable :1;
247+ bool _isWritable :1;
248+ bool _isExecutable:1;
249+ QFile::Permissions _permissions;
250+ qint64 _size;
251+ QDateTime _created;
252+ QDateTime _lastModified;
253+ QDateTime _lastRead;
254+ QString _path;
255+ QString _fileName;
256+ QString _normalizedPath;
257+ static QMimeDatabase mimeDatabase;
258+};
259+
260+
261+
262 #endif // DIRITEMINFO_H
263
264=== modified file 'folderlistmodel/dirmodel.cpp'
265--- folderlistmodel/dirmodel.cpp 2014-03-03 17:19:49 +0000
266+++ folderlistmodel/dirmodel.cpp 2014-03-23 13:46:13 +0000
267@@ -31,12 +31,13 @@
268
269 #include "dirselection.h"
270 #include "dirmodel.h"
271-#include "iorequest.h"
272-#include "ioworkerthread.h"
273 #include "filesystemaction.h"
274-#include "externalfswatcher.h"
275 #include "clipboard.h"
276 #include "fmutil.h"
277+#include "locationsfactory.h"
278+#include "location.h"
279+#include "locationurl.h"
280+#include "disk/disklocation.h"
281
282
283 #ifndef DO_NOT_USE_TAG_LIB
284@@ -75,7 +76,6 @@
285 #define IS_FILE_MANAGER_IDLE() (!mAwaitingResults)
286
287
288-Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread)
289
290 namespace {
291 QHash<QByteArray, int> roleMapping;
292@@ -108,9 +108,11 @@
293 , mSortBy(SortByName)
294 , mSortOrder(SortAscending)
295 , mCompareFunction(0)
296- , mExtFSWatcher(0)
297- , mClipboard(new Clipboard(this))
298- , m_fsAction(new FileSystemAction(this) )
299+ , mExtFSWatcher(false)
300+ , mClipboard(new Clipboard(this))
301+ , mLocationFactory(new LocationsFactory(this))
302+ , mCurLocation(0)
303+ , m_fsAction(new FileSystemAction(this) )
304 {
305 mNameFilters = QStringList() << "*";
306
307@@ -155,13 +157,40 @@
308 {
309 FMUtil::setThemeName();
310 }
311+
312+ foreach (const Location* l, mLocationFactory->availableLocations())
313+ {
314+ connect(l, SIGNAL(itemsAdded(DirItemInfoList)),
315+ this, SLOT(onItemsAdded(DirItemInfoList)));
316+
317+ connect(l, SIGNAL(itemsFetched()),
318+ this, SLOT(onItemsFetched()));
319+
320+ connect(l, SIGNAL(extWatcherItemAdded(DirItemInfo)),
321+ this, SLOT(onItemAddedOutsideFm(DirItemInfo)));
322+
323+ connect(l, SIGNAL(extWatcherItemRemoved(DirItemInfo)),
324+ this, SLOT(onItemRemovedOutSideFm(DirItemInfo)));
325+
326+ connect(l, SIGNAL(extWatcherItemChanged(DirItemInfo)),
327+ this, SLOT(onItemChangedOutSideFm(DirItemInfo)));
328+
329+ connect(l, SIGNAL(extWatcherChangesFetched(int)),
330+ this, SLOT(onExternalFsWorkerFinished(int)));
331+
332+ connect(l, SIGNAL(extWatcherPathChanged(QString)),
333+ this, SLOT(onThereAreExternalChanges(QString)));
334+
335+ connect(this, SIGNAL(enabledExternalFSWatcherChanged(bool)),
336+ l, SLOT(setUsingExternalWatcher(bool)));
337+ }
338 }
339
340
341
342 DirModel::~DirModel()
343 {
344- stoptExternalFsWatcher();
345+
346 }
347
348
349@@ -178,7 +207,6 @@
350
351
352
353-
354 QHash<int, QByteArray> DirModel::buildRoleNames() const
355 {
356 QHash<int, QByteArray> roles;
357@@ -366,43 +394,54 @@
358 return QVariant();
359 }
360
361+
362 void DirModel::setPath(const QString &pathName)
363 {
364 if (pathName.isEmpty())
365 return;
366
367- if (!canReadDir(pathName))
368- {
369- emit error(tr("cannot read path"), pathName);
370- return;
371- }
372-
373- if (mAwaitingResults) {
374+ if (mAwaitingResults) {
375 // TODO: handle the case where pathName != our current path, cancel old
376 // request, start a new one
377- qDebug() << Q_FUNC_INFO << this << "Ignoring path change request, request already running";
378- return;
379- }
380-
381+ qDebug() << Q_FUNC_INFO << this << "Ignoring path change request, request already running in" << pathName;
382+ return;
383+ }
384+
385+ const Location *location = mLocationFactory->setNewPath(pathName);
386+ if (location == 0)
387+ {
388+ emit error(tr("path or url may not exist or cannot be read"), pathName);
389+ qDebug() << Q_FUNC_INFO << this << "path or url may not exist or cannot be read:" << pathName;
390+ return;
391+ }
392+
393+ mCurLocation = const_cast<Location*> (location);
394+ setPathFromCurrentLocation();
395+}
396+
397+/*!
398+ * \brief DirModel::setPathFromCurrentLocation() changes current Path using current Location
399+ *
400+ * Used in \ref cdUp() and \ref cdIntoIndex()
401+ */
402+void DirModel::setPathFromCurrentLocation()
403+{
404 mAwaitingResults = true;
405 emit awaitingResultsChanged();
406 #if DEBUG_MESSAGES
407- qDebug() << Q_FUNC_INFO << this << "Changing to " << pathName << " on " << QThread::currentThreadId();
408+ qDebug() << Q_FUNC_INFO << this << "Changing to " << mCurLocation->urlPath();
409 #endif
410
411 clear();
412
413- DirListWorker *dlw = createWorkerRequest(IORequest::DirList, pathName);
414- connect(dlw, SIGNAL(itemsAdded(DirItemInfoList)), SLOT(onItemsAdded(DirItemInfoList)));
415- connect(dlw, SIGNAL(workerFinished()), SLOT(onResultsFetched()));
416- ioWorkerThread()->addRequest(dlw);
417+ mCurLocation->fetchItems(currentDirFilter(), mIsRecursive);
418
419- mCurrentDir = pathName;
420- emit pathChanged(pathName);
421+ mCurrentDir = mCurLocation->urlPath();
422+ emit pathChanged(mCurLocation->urlPath());
423 }
424
425
426-void DirModel::onResultsFetched() {
427+void DirModel::onItemsFetched() {
428 if (mAwaitingResults) {
429 #if DEBUG_MESSAGES
430 qDebug() << Q_FUNC_INFO << this << "No longer awaiting results";
431@@ -588,22 +627,33 @@
432 }
433
434 #if defined(REGRESSION_TEST_FOLDERLISTMODEL)
435- QVariant DirModel::headerData(int section, Qt::Orientation orientation, int role) const
436- {
437- if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
438- {
439- QVariant ret;
440- QHash<int, QByteArray> roles = this->roleNames();
441- section += FileNameRole;
442- if (roles.contains(section))
443- {
444- QString header= QString(roles.value(section));
445- ret = header;
446- }
447- return ret;
448- }
449- return QAbstractItemModel::headerData(section, orientation, role);
450- }
451+int DirModel::columnCount(const QModelIndex &parent) const
452+{
453+ Q_UNUSED(parent);
454+ return TrackCoverRole - FileNameRole + 1;
455+}
456+QVariant DirModel::headerData(int section, Qt::Orientation orientation, int role) const
457+{
458+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
459+ {
460+ QVariant ret;
461+ QHash<int, QByteArray> roles = this->roleNames();
462+ section += FileNameRole;
463+ if (roles.contains(section))
464+ {
465+ QString header= QString(roles.value(section));
466+ ret = header;
467+ }
468+ return ret;
469+ }
470+ return QAbstractItemModel::headerData(section, orientation, role);
471+}
472+ExternalFSWatcher * DirModel::getExternalFSWatcher() const
473+{
474+ const Location *l = mLocationFactory->availableLocations().at(LocationsFactory::LocalDisk);
475+ const DiskLocation *disk = static_cast<const DiskLocation*> (l);
476+ return disk->getExternalFSWatcher();
477+}
478 #endif
479
480
481@@ -613,17 +663,18 @@
482 }
483
484
485+void DirModel::goTrash()
486+{
487+ setPath(LocationUrl::TrashRootURL);
488+}
489+
490+
491 bool DirModel::cdUp()
492 {
493- int ret = false;
494- if (!mCurrentDir.isEmpty()) // we are in any dir
495+ int ret = mCurLocation && mCurLocation->becomeParent();
496+ if (ret)
497 {
498- QDir current(mCurrentDir);
499- if (current.cdUp())
500- {
501- setPath(current.absolutePath());
502- ret = true;
503- }
504+ setPathFromCurrentLocation();
505 }
506 return ret;
507 }
508@@ -707,9 +758,13 @@
509 bool DirModel::cdIntoIndex(int row)
510 {
511 bool ret = false;
512- if (IS_VALID_ROW(row))
513+ if (IS_VALID_ROW(row) &&
514+ mDirectoryContents.at(row).isDir() &&
515+ mDirectoryContents.at(row).isReadable())
516 {
517- ret = cdInto(mDirectoryContents.at(row));
518+ mCurLocation->setFromInfoItem(mDirectoryContents.at(row));
519+ setPathFromCurrentLocation();
520+ ret = true;
521 }
522 else
523 {
524@@ -1085,7 +1140,14 @@
525 bool ret = false;
526 if (IS_VALID_ROW(row))
527 {
528- ret = openItem(mDirectoryContents.at(row));
529+ if (mDirectoryContents.at(row).isDir())
530+ {
531+ ret = cdIntoIndex(row);
532+ }
533+ else
534+ {
535+ ret = openItem(mDirectoryContents.at(row));
536+ }
537 }
538 else
539 {
540@@ -1096,8 +1158,28 @@
541
542 bool DirModel::openPath(const QString &filename)
543 {
544- DirItemInfo fi(setParentIfRelative(filename));
545- return openItem(fi);
546+ bool ret = false;
547+ //first void any relative path when is root
548+ if ( !(mCurLocation && mCurLocation->isRoot() && filename.startsWith(QLatin1String(".."))) )
549+ {
550+ const Location *location = mLocationFactory->setNewPath(filename);
551+ if (location)
552+ {
553+ mCurLocation = const_cast<Location*> (location);
554+ setPathFromCurrentLocation();
555+ ret = true;
556+ }
557+ else
558+ {
559+ const DirItemInfo *item = mLocationFactory->lastValidFileInfo();
560+ // DirItemInfo fi(setParentIfRelative(filename));
561+ if (item && item->isFile())
562+ {
563+ ret = openItem(*item);
564+ }
565+ }
566+ }
567+ return ret;
568 }
569
570 /*!
571@@ -1126,103 +1208,21 @@
572 return ret;
573 }
574
575-/*!
576- * \brief DirModel::createWorkerRequest() create a request for IORequestWorker
577- * \param requestType the common IORequest::DirList to fill a directory content
578- * or IORequest::DirAutoRefresh that will verify any external File System modification
579- * \param pathName the path to get content
580- * \return the thread object
581- */
582-DirListWorker * DirModel::createWorkerRequest(IORequest::RequestType requestType,
583- const QString& pathName)
584-{
585- DirListWorker * reqThread = 0;
586- QDir::Filter dirFilter = currentDirFilter();
587- if (requestType == IORequest::DirList)
588- {
589- // TODO: we need to set a spinner active before we start getting results from DirListWorker
590- reqThread = new DirListWorker(pathName, dirFilter, mIsRecursive);
591- }
592- else
593- {
594- reqThread = new ExternalFileSystemChangesWorker(mDirectoryContents,
595- pathName,
596- dirFilter, mIsRecursive);
597- }
598- return reqThread;
599-}
600-
601-
602-
603-/*!
604- * \brief DirModel::startExternalFsWatcher() starts the External File System Watcher
605- */
606-void DirModel::startExternalFsWatcher()
607-{
608-#if DEBUG_EXT_FS_WATCHER
609- qDebug() << "[extFsWorker]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
610- << Q_FUNC_INFO << this;
611-
612-#endif
613- if (!mExtFSWatcher)
614- {
615- mExtFSWatcher = new ExternalFSWatcher(this);
616- mExtFSWatcher->setIntervalToNotifyChanges(EX_FS_WATCHER_TIMER_INTERVAL);
617- connect(this, SIGNAL(pathChanged(QString)),
618- mExtFSWatcher, SLOT(setCurrentPath(QString)));
619-
620- connect(mExtFSWatcher, SIGNAL(pathModified()),
621- this, SLOT(onThereAreExternalChanges()));
622-
623- //setCurrentPath() checks for empty paths
624- mExtFSWatcher->setCurrentPath(mCurrentDir);
625- }
626-}
627-
628-
629-
630-/*!
631- * \brief DirModel::stoptExternalFsWatcher stops the External File System Watcher
632- */
633-void DirModel::stoptExternalFsWatcher()
634-{
635-#if DEBUG_EXT_FS_WATCHER
636- qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
637- << Q_FUNC_INFO << this;
638-#endif
639- if (mExtFSWatcher)
640- {
641- delete mExtFSWatcher;
642- mExtFSWatcher = 0;
643- }
644-}
645-
646-
647-void DirModel::onThereAreExternalChanges()
648+
649+
650+
651+
652+void DirModel::onThereAreExternalChanges(const QString& pathModifiedOutside)
653 {
654 if ( IS_FILE_MANAGER_IDLE() )
655 {
656 #if DEBUG_EXT_FS_WATCHER
657 qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
658- << Q_FUNC_INFO << this << "File System modified";
659+ << Q_FUNC_INFO << this << "File System modified in" << pathModifiedOutside;
660 #endif
661- DirListWorker *w =
662- createWorkerRequest(IORequest::DirListExternalFSChanges,
663- mCurrentDir
664- );
665- ExternalFileSystemChangesWorker *extFsWorker =
666- static_cast<ExternalFileSystemChangesWorker*> (w);
667-
668- connect(extFsWorker, SIGNAL(added(DirItemInfo)),
669- this, SLOT(onItemAddedOutsideFm(DirItemInfo)));
670- connect(extFsWorker, SIGNAL(removed(DirItemInfo)),
671- this, SLOT(onItemRemovedOutSideFm(DirItemInfo)));
672- connect(extFsWorker, SIGNAL(changed(DirItemInfo)),
673- this, SLOT(onItemChangedOutSideFm(DirItemInfo)));
674- connect(extFsWorker, SIGNAL(finished(int)),
675- this, SLOT(onExternalFsWorkerFinished(int)));
676-
677- ioWorkerThread()->addRequest(extFsWorker);
678+ mCurLocation->fetchExternalChanges(pathModifiedOutside,
679+ mDirectoryContents,
680+ currentDirFilter());
681 }
682 #if DEBUG_EXT_FS_WATCHER
683 else
684@@ -1322,7 +1322,7 @@
685 */
686 bool DirModel::getEnabledExternalFSWatcher() const
687 {
688- return mExtFSWatcher ? true : false;
689+ return mExtFSWatcher;
690 }
691
692
693@@ -1331,15 +1331,8 @@
694 * \param enable
695 */
696 void DirModel::setEnabledExternalFSWatcher(bool enable)
697-{
698- if(enable)
699- {
700- startExternalFsWatcher();
701- }
702- else
703- {
704- stoptExternalFsWatcher();
705- }
706+{
707+ emit enabledExternalFSWatcherChanged(enable);
708 }
709
710
711
712=== modified file 'folderlistmodel/dirmodel.h'
713--- folderlistmodel/dirmodel.h 2014-02-07 13:22:44 +0000
714+++ folderlistmodel/dirmodel.h 2014-03-23 13:46:13 +0000
715@@ -42,17 +42,11 @@
716 #include "diriteminfo.h"
717
718 class FileSystemAction;
719-class ExternalFSWatcher;
720 class Clipboard;
721 class DirSelection;
722-
723-/*!
724- * When the External File System Wathcer is enabled,
725- * this is the interval used to check if there has been any change in the current path
726- *
727- * \sa setEnabledExternalFSWatcher()
728- */
729-#define EX_FS_WATCHER_TIMER_INTERVAL 900
730+class LocationsFactory;
731+class Location;
732+class ExternalFSWatcher;
733
734 class DirModel : public DirItemAbstractListModel
735 {
736@@ -150,7 +144,7 @@
737
738 public slots:
739 void onItemsAdded(const DirItemInfoList &newFiles);
740- void onResultsFetched();
741+ void onItemsFetched();
742
743 signals:
744 void awaitingResultsChanged();
745@@ -206,7 +200,7 @@
746 Q_PROPERTY(int clipboardUrlsCounter READ getClipboardUrlsCounter NOTIFY clipboardChanged)
747 int getClipboardUrlsCounter() const;
748
749- Q_PROPERTY(bool enableExternalFSWatcher READ getEnabledExternalFSWatcher WRITE setEnabledExternalFSWatcher)
750+ Q_PROPERTY(bool enableExternalFSWatcher READ getEnabledExternalFSWatcher WRITE setEnabledExternalFSWatcher NOTIFY enabledExternalFSWatcherChanged)
751 bool getEnabledExternalFSWatcher() const;
752
753 Q_INVOKABLE QString homePath() const;
754@@ -303,6 +297,11 @@
755 void goHome();
756
757 /*!
758+ * \brief goTrash() goes to logical folder trash:///
759+ */
760+ void goTrash();
761+
762+ /*!
763 * \brief cdUp() sets the parent directory as current directory
764 *
765 * It can work as a back function if there is no user input path
766@@ -360,8 +359,8 @@
767 void showHiddenFilesChanged();
768 void sortByChanged();
769 void sortOrderChanged();
770-
771 void clipboardChanged();
772+ void enabledExternalFSWatcherChanged(bool);
773
774 private slots:
775 void onItemRemoved(const QString&);
776@@ -377,12 +376,11 @@
777 QDir::Filter currentDirFilter() const;
778 QString dirItems(const DirItemInfo& fi) const;
779 bool cdInto(const DirItemInfo& fi);
780- bool openItem(const DirItemInfo& fi);
781- DirListWorker * createWorkerRequest(IORequest::RequestType requestType,
782- const QString& pathName);
783+ bool openItem(const DirItemInfo& fi);
784 bool canReadDir(const QFileInfo& d) const;
785 bool canReadFile(const QFileInfo& f) const;
786 QFileInfo setParentIfRelative(const QString &fileOrDir) const;
787+ void setPathFromCurrentLocation();
788
789 private:
790 void startExternalFsWatcher();
791@@ -392,7 +390,7 @@
792 void onItemAddedOutsideFm(const DirItemInfo&fi);
793 void onItemRemovedOutSideFm(const DirItemInfo&);
794 void onItemChangedOutSideFm(const DirItemInfo&fi);
795- void onThereAreExternalChanges();
796+ void onThereAreExternalChanges(const QString &);
797 void onExternalFsWorkerFinished(int);
798
799
800@@ -401,9 +399,11 @@
801 SortBy mSortBy;
802 SortOrder mSortOrder;
803 CompareFunction mCompareFunction;
804- ExternalFSWatcher* mExtFSWatcher;
805+ bool mExtFSWatcher;
806 Clipboard * mClipboard;
807 DirSelection * mSelection;
808+ LocationsFactory * mLocationFactory;
809+ Location * mCurLocation;
810
811
812 private:
813@@ -414,13 +414,9 @@
814 #endif
815 //[0]
816
817-#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
818- //make this work with tables
819- virtual int columnCount(const QModelIndex &parent = QModelIndex()) const
820- {
821- Q_UNUSED(parent);
822- return TrackCoverRole - FileNameRole + 1;
823- }
824+#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
825+ ExternalFSWatcher * getExternalFSWatcher() const;
826+ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
827 virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
828 friend class TestDirModel;
829 #endif
830
831=== added directory 'folderlistmodel/disk'
832=== added file 'folderlistmodel/disk/disklocation.cpp'
833--- folderlistmodel/disk/disklocation.cpp 1970-01-01 00:00:00 +0000
834+++ folderlistmodel/disk/disklocation.cpp 2014-03-23 13:46:13 +0000
835@@ -0,0 +1,222 @@
836+/**************************************************************************
837+ *
838+ * Copyright 2014 Canonical Ltd.
839+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
840+ *
841+ * This program is free software; you can redistribute it and/or modify
842+ * it under the terms of the GNU Lesser General Public License as published by
843+ * the Free Software Foundation; version 3.
844+ *
845+ * This program is distributed in the hope that it will be useful,
846+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
847+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
848+ * GNU Lesser General Public License for more details.
849+ *
850+ * You should have received a copy of the GNU Lesser General Public License
851+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
852+ *
853+ * File: disklocation.cpp
854+ * Date: 08/03/2014
855+ */
856+
857+#include "disklocation.h"
858+#include "iorequest.h"
859+#include "ioworkerthread.h"
860+#include "externalfswatcher.h"
861+
862+#include <QDebug>
863+
864+#if defined(DEBUG_EXT_FS_WATCHER)
865+# define DEBUG_WATCHER() qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") \
866+ << Q_FUNC_INFO << this
867+#else
868+# define DEBUG_WATCHER() /**/
869+#endif
870+
871+DiskLocation::DiskLocation(int type, QObject *parent)
872+ : Location(type, parent)
873+ , m_extWatcher(0)
874+{
875+}
876+
877+
878+DiskLocation::~ DiskLocation()
879+{
880+ stoptExternalFsWatcher();
881+}
882+
883+
884+void DiskLocation::fetchItems(QDir::Filter dirFilter, bool recursive)
885+{
886+ DirListWorker *dlw = new DirListWorker(m_info->absoluteFilePath(), dirFilter, recursive);
887+ connect(dlw, SIGNAL(itemsAdded(DirItemInfoList)),
888+ this, SIGNAL(itemsAdded(DirItemInfoList)));
889+ connect(dlw, SIGNAL(workerFinished()),
890+ this, SLOT(onItemsFetched()));
891+ workerThread()->addRequest(dlw);
892+}
893+
894+
895+bool DiskLocation::becomeParent()
896+{
897+ bool ret = false;
898+ if (m_info && !m_info->isRoot())
899+ {
900+ DirItemInfo *other = new DirItemInfo(m_info->absolutePath());
901+ if (other->isValid())
902+ {
903+ delete m_info;
904+ m_info = other;
905+ ret = true;
906+ }
907+ else
908+ {
909+ delete other;
910+ }
911+ }
912+ return ret;
913+}
914+
915+
916+void DiskLocation::refreshInfo()
917+{
918+ if (m_info)
919+ {
920+ DirItemInfo *item = new DirItemInfo(m_info->absoluteFilePath());
921+ delete m_info;
922+ m_info = item;
923+ }
924+}
925+
926+
927+/*!
928+ * \brief DiskLocation::stoptExternalFsWatcher stops the External File System Watcher
929+ */
930+void DiskLocation::stoptExternalFsWatcher()
931+{
932+ if (m_extWatcher)
933+ {
934+ DEBUG_WATCHER();
935+ delete m_extWatcher;
936+ m_extWatcher = 0;
937+ }
938+}
939+
940+
941+/*!
942+ * \brief DiskLocation::startExternalFsWatcher() starts the External File System Watcher
943+ */
944+void DiskLocation::startExternalFsWatcher()
945+{
946+ if (m_extWatcher == 0)
947+ {
948+ DEBUG_WATCHER();
949+ m_extWatcher = new ExternalFSWatcher(this);
950+ m_extWatcher->setIntervalToNotifyChanges(EX_FS_WATCHER_TIMER_INTERVAL);
951+
952+ connect(m_extWatcher, SIGNAL(pathModified(QString)),
953+ this, SIGNAL(extWatcherPathChanged(QString)));
954+ if (m_info)
955+ { //setCurrentPath() checks for empty paths
956+ m_extWatcher->setCurrentPath(m_info->absoluteFilePath());
957+ }
958+ }
959+}
960+
961+
962+void DiskLocation::onItemsFetched()
963+{
964+ if (m_extWatcher)
965+ {
966+ m_extWatcher->setCurrentPath(m_info->absoluteFilePath());
967+ }
968+ emit itemsFetched();
969+}
970+
971+
972+void DiskLocation::startWorking()
973+{
974+ if (m_usingExternalWatcher)
975+ {
976+ startExternalFsWatcher();
977+ }
978+}
979+
980+
981+void DiskLocation::stopWorking()
982+{
983+ stoptExternalFsWatcher();
984+}
985+
986+
987+void DiskLocation::fetchExternalChanges(const QString &path,
988+ const DirItemInfoList &list,
989+ QDir::Filter dirFilter)
990+{
991+ ExternalFileSystemChangesWorker *extFsWorker =
992+ new ExternalFileSystemChangesWorker(list,
993+ path,
994+ dirFilter, false);
995+ addExternalFsWorkerRequest(extFsWorker);
996+
997+
998+}
999+
1000+void DiskLocation::addExternalFsWorkerRequest(ExternalFileSystemChangesWorker *extFsWorker)
1001+{
1002+ connect(extFsWorker, SIGNAL(added(DirItemInfo)),
1003+ this, SIGNAL(extWatcherItemAdded(DirItemInfo)));
1004+
1005+ connect(extFsWorker, SIGNAL(removed(DirItemInfo)),
1006+ this, SIGNAL(extWatcherItemRemoved(DirItemInfo)));
1007+
1008+ connect(extFsWorker, SIGNAL(changed(DirItemInfo)),
1009+ this, SIGNAL(extWatcherItemChanged(DirItemInfo)));
1010+
1011+ connect(extFsWorker, SIGNAL(finished(int)),
1012+ this, SIGNAL(extWatcherChangesFetched(int)));
1013+
1014+ workerThread()->addRequest(extFsWorker);
1015+}
1016+
1017+
1018+ExternalFSWatcher * DiskLocation::getExternalFSWatcher() const
1019+{
1020+ return m_extWatcher;
1021+}
1022+
1023+
1024+void DiskLocation::setUsingExternalWatcher(bool use)
1025+{
1026+ Location::setUsingExternalWatcher(use);
1027+ if (m_usingExternalWatcher)
1028+ {
1029+ startExternalFsWatcher();
1030+ }
1031+ else
1032+ {
1033+ stoptExternalFsWatcher();
1034+ }
1035+}
1036+
1037+
1038+DirItemInfo * DiskLocation::validateUrlPath(const QString& uPath)
1039+{
1040+ QString myPath(uPath);
1041+ QFileInfo tmpUrl(uPath);
1042+ if (tmpUrl.isRelative() && m_info)
1043+ {
1044+ tmpUrl.setFile(m_info->absoluteFilePath(), uPath);
1045+ myPath = tmpUrl.absoluteFilePath();
1046+ }
1047+#if DEBUG_MESSAGES
1048+ qDebug() << Q_FUNC_INFO << "path:" << myPath;
1049+#endif
1050+ DirItemInfo * item = new DirItemInfo(myPath);
1051+ if (!item->isValid() || !item->exists() || !item->isReadable())
1052+ {
1053+ delete item;
1054+ item = 0;
1055+ }
1056+ return item;
1057+}
1058
1059=== added file 'folderlistmodel/disk/disklocation.h'
1060--- folderlistmodel/disk/disklocation.h 1970-01-01 00:00:00 +0000
1061+++ folderlistmodel/disk/disklocation.h 2014-03-23 13:46:13 +0000
1062@@ -0,0 +1,81 @@
1063+/**************************************************************************
1064+ *
1065+ * Copyright 2014 Canonical Ltd.
1066+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1067+ *
1068+ * This program is free software; you can redistribute it and/or modify
1069+ * it under the terms of the GNU Lesser General Public License as published by
1070+ * the Free Software Foundation; version 3.
1071+ *
1072+ * This program is distributed in the hope that it will be useful,
1073+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1074+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1075+ * GNU Lesser General Public License for more details.
1076+ *
1077+ * You should have received a copy of the GNU Lesser General Public License
1078+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1079+ *
1080+ * File: disklocation.h
1081+ * Date: 08/03/2014
1082+ */
1083+
1084+#ifndef DISKLOCATION_H
1085+#define DISKLOCATION_H
1086+
1087+#include "location.h"
1088+#include <QList>
1089+
1090+/*!
1091+ * When the External File System Wathcer is enabled,
1092+ * this is the interval used to check if there has been any change in the current path
1093+ *
1094+ * \sa setEnabledExternalFSWatcher()
1095+ */
1096+#define EX_FS_WATCHER_TIMER_INTERVAL 900
1097+
1098+
1099+class ExternalFSWatcher;
1100+class ExternalFileSystemChangesWorker;
1101+
1102+/*!
1103+ * \brief The DiskLocation class extends \ref Location for Local Disk and provides a External File System watcher
1104+ */
1105+class DiskLocation : public Location
1106+{
1107+ Q_OBJECT
1108+public:
1109+ explicit DiskLocation(int type, QObject *parent=0);
1110+ ~DiskLocation();
1111+
1112+ ExternalFSWatcher * getExternalFSWatcher() const;
1113+
1114+ virtual void fetchItems(QDir::Filter dirFilter, bool recursive = false) ;
1115+ virtual void fetchExternalChanges(const QString& urlPath,
1116+ const DirItemInfoList& list,
1117+ QDir::Filter dirFilter) ;
1118+ virtual bool becomeParent();
1119+ virtual void refreshInfo();
1120+
1121+ virtual void startExternalFsWatcher();
1122+ virtual void stoptExternalFsWatcher();
1123+
1124+ virtual void startWorking();
1125+ virtual void stopWorking();
1126+
1127+ virtual DirItemInfo *validateUrlPath(const QString& urlPath);
1128+
1129+protected:
1130+ void addExternalFsWorkerRequest(ExternalFileSystemChangesWorker *);
1131+
1132+public slots:
1133+ virtual void setUsingExternalWatcher(bool use);
1134+
1135+protected slots:
1136+ void onItemsFetched();
1137+
1138+protected:
1139+ ExternalFSWatcher * m_extWatcher ;
1140+
1141+};
1142+
1143+#endif // DISKLOCATION_H
1144
1145=== modified file 'folderlistmodel/externalfswatcher.cpp'
1146--- folderlistmodel/externalfswatcher.cpp 2013-11-17 14:27:10 +0000
1147+++ folderlistmodel/externalfswatcher.cpp 2014-03-23 13:46:13 +0000
1148@@ -40,6 +40,7 @@
1149 QFileSystemWatcher(parent)
1150 , m_waitingEmitCounter(0)
1151 , m_msWaitTime(DEFAULT_NOTICATION_PERIOD)
1152+ , m_lastChangedIndex(0)
1153 {
1154 connect(this, SIGNAL(directoryChanged(QString)),
1155 this, SLOT(slotDirChanged(QString)));
1156@@ -49,31 +50,45 @@
1157 void ExternalFSWatcher::setCurrentPath(const QString &curPath)
1158 {
1159 if (!curPath.isEmpty())
1160+ {
1161+ if (m_setPath.count() == 1 && m_setPath.at(0) != curPath)
1162+ {
1163+ m_setPath.removeFirst();
1164+ }
1165+ if (m_setPath.count() == 0)
1166+ {
1167+ m_setPath.append(curPath);
1168+ QFileSystemWatcher::addPath(curPath);
1169+ }
1170+ }
1171+ DEBUG_FSWATCHER();
1172+}
1173+
1174+
1175+void ExternalFSWatcher::setCurrentPaths(const QStringList &paths)
1176+{
1177+ QStringList myPaths(paths);
1178+ ::qSort(myPaths);
1179+ QStringList existentPaths = QFileSystemWatcher::directories();
1180+ if (existentPaths.count() > 0)
1181 {
1182- if (m_setPath != curPath)
1183- {
1184- if (!m_setPath.isEmpty())
1185- {
1186- removePath(m_setPath);
1187- }
1188- m_setPath = curPath;
1189- addPath(m_setPath);
1190- }
1191+ QFileSystemWatcher::removePaths(existentPaths);
1192 }
1193- DEBUG_FSWATCHER();
1194+ m_setPath = myPaths;
1195+ QFileSystemWatcher::addPaths(paths);
1196 }
1197
1198
1199 void ExternalFSWatcher::slotDirChanged(const QString &dir)
1200 {
1201 DEBUG_FSWATCHER();
1202- if ( (m_setPath == dir)
1203- && ( m_waitingEmitCounter == 0 || m_setPath != m_changedPath )
1204+ if ( ((m_lastChangedIndex = m_setPath.indexOf(dir)) != -1)
1205+ && ( m_waitingEmitCounter == 0 || dir != m_changedPath )
1206 )
1207 {
1208- removePath(m_setPath);
1209+ removePath(m_setPath.at(m_lastChangedIndex));
1210 ++m_waitingEmitCounter;
1211- m_changedPath = m_setPath;
1212+ m_changedPath = dir;
1213 QTimer::singleShot(m_msWaitTime, this, SLOT(slotFireChanges()));
1214 }
1215 }
1216@@ -87,12 +102,14 @@
1217 */
1218 void ExternalFSWatcher::slotFireChanges()
1219 {
1220- if (--m_waitingEmitCounter == 0)
1221+ if ( --m_waitingEmitCounter == 0
1222+ && m_lastChangedIndex != -1
1223+ && m_lastChangedIndex < m_setPath.count() )
1224 {
1225- addPath(m_setPath);
1226- if (m_setPath == m_changedPath)
1227+ addPath(m_setPath.at(m_lastChangedIndex));
1228+ if (m_setPath.at(m_lastChangedIndex) == m_changedPath)
1229 {
1230- emit pathModified();
1231+ emit pathModified(m_changedPath);
1232 #if DEBUG_EXT_FS_WATCHER
1233 DEBUG_FSWATCHER() << "emit pathModified()";
1234 #endif
1235
1236=== modified file 'folderlistmodel/externalfswatcher.h'
1237--- folderlistmodel/externalfswatcher.h 2013-10-20 16:58:41 +0000
1238+++ folderlistmodel/externalfswatcher.h 2014-03-23 13:46:13 +0000
1239@@ -23,6 +23,7 @@
1240 #define EXTERNALFSWATCHER_H
1241
1242 #include <QFileSystemWatcher>
1243+#include <QStringList>
1244
1245 #define DEFAULT_NOTICATION_PERIOD 500
1246
1247@@ -47,11 +48,14 @@
1248 explicit ExternalFSWatcher(QObject *parent = 0);
1249 int getIntervalToNotifyChanges() const;
1250
1251+ inline const QStringList& pathsWatched() const { return m_setPath;}
1252+
1253 signals:
1254- void pathModified();
1255+ void pathModified(const QString& path);
1256
1257- public slots:
1258+public slots:
1259 void setCurrentPath(const QString& curPath);
1260+ void setCurrentPaths(const QStringList& paths);
1261 void setIntervalToNotifyChanges(int ms);
1262
1263 private slots:
1264@@ -59,10 +63,11 @@
1265 void slotFireChanges();
1266
1267 private:
1268- QString m_setPath;
1269- QString m_changedPath;
1270- unsigned m_waitingEmitCounter;
1271- int m_msWaitTime;
1272+ QStringList m_setPath;
1273+ QString m_changedPath;
1274+ unsigned m_waitingEmitCounter;
1275+ int m_msWaitTime;
1276+ int m_lastChangedIndex;
1277 };
1278
1279 #endif // EXTERNALFSWATCHER_H
1280
1281=== modified file 'folderlistmodel/filecompare.cpp'
1282--- folderlistmodel/filecompare.cpp 2014-02-05 15:31:44 +0000
1283+++ folderlistmodel/filecompare.cpp 2014-03-23 13:46:13 +0000
1284@@ -50,11 +50,10 @@
1285 if (b.isDir() && !a.isDir())
1286 return false;
1287
1288- bool ret = QString::localeAwareCompare(a.fileName(), b.fileName()) < 0;
1289+ bool ret = QString::localeAwareCompare(a.absoluteFilePath(), b.absoluteFilePath()) < 0;
1290 #if DEBUG_MESSAGES
1291- qDebug() << Q_FUNC_INFO << ret << a.fileName() << b.fileName();
1292+ qDebug() << Q_FUNC_INFO << ret << a.absoluteFilePath() << b.absoluteFilePath();
1293 #endif
1294-
1295 return ret;
1296 }
1297
1298
1299=== modified file 'folderlistmodel/folderlistmodel.pri'
1300--- folderlistmodel/folderlistmodel.pri 2014-02-10 23:41:50 +0000
1301+++ folderlistmodel/folderlistmodel.pri 2014-03-23 13:46:13 +0000
1302@@ -9,7 +9,14 @@
1303 $$PWD/fmutil.cpp \
1304 $$PWD/dirselection.cpp \
1305 $$PWD/diriteminfo.cpp \
1306- $$PWD/trash/qtrashdir.cpp
1307+ $$PWD/trash/qtrashdir.cpp \
1308+ $$PWD/trash/trashiteminfo.cpp \
1309+ $$PWD/location.cpp \
1310+ $$PWD/locationsfactory.cpp \
1311+ $$PWD/disk/disklocation.cpp \
1312+ $$PWD/trash/trashlocation.cpp \
1313+ $$PWD/locationurl.cpp \
1314+ $$PWD/trash/qtrashutilinfo.cpp
1315
1316
1317 HEADERS += $$PWD/dirmodel.h \
1318@@ -24,7 +31,14 @@
1319 $$PWD/dirselection.h \
1320 $$PWD/diritemabstractlistmodel.h \
1321 $$PWD/diriteminfo.h \
1322- $$PWD/trash/qtrashdir.h
1323+ $$PWD/trash/qtrashdir.h \
1324+ $$PWD/trash/trashiteminfo.h \
1325+ $$PWD/location.h \
1326+ $$PWD/locationsfactory.h \
1327+ $$PWD/disk/disklocation.h \
1328+ $$PWD/trash/trashlocation.h \
1329+ $$PWD/locationurl.h \
1330+ $$PWD/trash/qtrashutilinfo.h
1331
1332
1333 INCLUDEPATH += $$PWD $$PWD/trash
1334
1335=== modified file 'folderlistmodel/iorequest.cpp'
1336--- folderlistmodel/iorequest.cpp 2014-02-05 15:31:44 +0000
1337+++ folderlistmodel/iorequest.cpp 2014-03-23 13:46:13 +0000
1338@@ -30,6 +30,9 @@
1339 */
1340
1341 #include "iorequest.h"
1342+#include "qtrashutilinfo.h"
1343+#include "diriteminfo.h"
1344+#include "trashiteminfo.h"
1345
1346 #include <QDirIterator>
1347 #include <QDebug>
1348@@ -48,31 +51,40 @@
1349 return m_type;
1350 }
1351
1352-
1353-DirListWorker::DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive)
1354- : mPathName(pathName)
1355- , mFilter(filter)
1356- , mIsRecursive(isRecursive)
1357-{
1358-
1359-}
1360-
1361-
1362-void DirListWorker::run()
1363-{
1364-#if DEBUG_MESSAGES
1365- qDebug() << Q_FUNC_INFO << "Running on: " << QThread::currentThreadId();
1366-#endif
1367-
1368- DirItemInfoList directoryContents = getContents();
1369-
1370- // last batch
1371- emit itemsAdded(directoryContents);
1372- emit workerFinished();
1373-}
1374-
1375-
1376-DirItemInfoList DirListWorker::getContents()
1377+//----------------------------------------------------------------------------------
1378+IORequestLoader::IORequestLoader(const QString &pathName,
1379+ QDir::Filter filter,
1380+ bool isRecursive)
1381+ : IORequest()
1382+ , mLoaderType(NormalLoader)
1383+ , mPathName(pathName)
1384+ , mFilter(filter)
1385+ , mIsRecursive(isRecursive)
1386+{
1387+}
1388+
1389+IORequestLoader::IORequestLoader(const QString& trashRootDir,
1390+ const QString &pathName,
1391+ QDir::Filter filter,
1392+ bool isRecursive)
1393+ : IORequest()
1394+ , mLoaderType(TrashLoader)
1395+ , mPathName(pathName)
1396+ , mFilter(filter)
1397+ , mIsRecursive(isRecursive)
1398+ , mTtrashRootDir(trashRootDir)
1399+{
1400+
1401+}
1402+
1403+DirItemInfoList IORequestLoader::getContents()
1404+{
1405+ return mLoaderType == NormalLoader ?
1406+ getNormalContent() :
1407+ getTrashContent();
1408+}
1409+
1410+DirItemInfoList IORequestLoader::getNormalContent()
1411 {
1412 #if DEBUG_EXT_FS_WATCHER
1413 qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
1414@@ -83,10 +95,9 @@
1415 return directoryContents;
1416 }
1417
1418-
1419-DirItemInfoList DirListWorker::add(const QString &pathName,
1420+DirItemInfoList IORequestLoader::add(const QString &pathName,
1421 QDir::Filter filter,
1422- const bool isRecursive,
1423+ bool isRecursive,
1424 DirItemInfoList directoryContents)
1425 {
1426 QDir tmpDir = QDir(pathName, QString(), QDir::NoSort, filter);
1427@@ -108,17 +119,79 @@
1428 directoryContents.erase(directoryContents.begin(), directoryContents.end());
1429 }
1430 }
1431-
1432 return directoryContents;
1433 }
1434
1435+DirItemInfoList IORequestLoader::getTrashContent()
1436+{
1437+ DirItemInfoList directoryContents;
1438+ QTrashUtilInfo trashInfo;
1439+ QDir tmpDir = QDir(mPathName, QString(), QDir::NoSort, mFilter);
1440+ bool isTopLevel = QFileInfo(mPathName).absolutePath() == mTtrashRootDir;
1441+ QDirIterator it(tmpDir);
1442+ while (it.hasNext())
1443+ {
1444+ it.next();
1445+ trashInfo.setInfo(mTtrashRootDir, it.fileInfo().absoluteFilePath());
1446+ if (!isTopLevel || (isTopLevel && trashInfo.existsInfoFile() && trashInfo.existsFile()) )
1447+ {
1448+ //TODO read the trashinfo file and set it into a display field
1449+ // the display field can be a string the usally points to absoluteFilePath()
1450+ // it would be used only in the DirModel::data()
1451+ TrashItemInfo item(QTrashUtilInfo::filesTrashDir(mTtrashRootDir),
1452+ it.fileInfo().absoluteFilePath());
1453+ directoryContents.append(item);
1454+ }
1455+ }
1456+ return directoryContents;
1457+}
1458+
1459+
1460+//-----------------------------------------------------------------------------------------------
1461+DirListWorker::DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive)
1462+ : IORequestLoader(pathName, filter, isRecursive)
1463+{
1464+
1465+}
1466+
1467+
1468+DirListWorker::DirListWorker(const QString& trashRootDir, const QString &pathName, QDir::Filter filter, const bool isRecursive)
1469+ : IORequestLoader(trashRootDir, pathName, filter, isRecursive)
1470+{
1471+
1472+}
1473+
1474+
1475+void DirListWorker::run()
1476+{
1477+#if DEBUG_MESSAGES
1478+ qDebug() << Q_FUNC_INFO << "Running on: " << QThread::currentThreadId();
1479+#endif
1480+
1481+ DirItemInfoList directoryContents = getContents();
1482+
1483+ // last batch
1484+ emit itemsAdded(directoryContents);
1485+ emit workerFinished();
1486+}
1487+
1488+
1489+
1490+
1491+//-------------------------------------------------------------------------------------
1492+TrashListWorker::TrashListWorker(const QString& trashRoot, const QString &path, QDir::Filter filter)
1493+ : DirListWorker(trashRoot, path, filter, false)
1494+{
1495+ mLoaderType = TrashLoader;
1496+}
1497+
1498
1499 //---------------------------------------------------------------------------------------------------------
1500 ExternalFileSystemChangesWorker::ExternalFileSystemChangesWorker(const DirItemInfoList &content,
1501 const QString &pathName,
1502 QDir::Filter filter,
1503 const bool isRecursive)
1504- : DirListWorker(pathName, filter, isRecursive)
1505+ : IORequestLoader(pathName, filter, isRecursive)
1506
1507 {
1508 m_type = DirListExternalFSChanges;
1509@@ -130,24 +203,23 @@
1510 }
1511
1512
1513-void ExternalFileSystemChangesWorker::run()
1514+int ExternalFileSystemChangesWorker::compareItems(const DirItemInfoList& contentNew)
1515 {
1516- DirItemInfoList directoryContents = getContents();
1517 int addedCounter=0;
1518 int removedCounter=0;
1519 #if DEBUG_EXT_FS_WATCHER
1520 qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
1521 << Q_FUNC_INFO
1522 << "m_curContent.count():" << m_curContent.count()
1523- << "directoryContents.count():" << directoryContents.count();
1524+ << "contentNew.count():" << contentNew.count();
1525 #endif
1526- int counter = directoryContents.count();
1527+ int counter = contentNew.count();
1528 if (counter > 0)
1529 {
1530 int tmpCounter = counter;
1531 while (tmpCounter--)
1532 {
1533- const DirItemInfo& originalItem = directoryContents.at(tmpCounter);
1534+ const DirItemInfo& originalItem = contentNew.at(tmpCounter);
1535 const DirItemInfo existItem = m_curContent.value(originalItem.absoluteFilePath());
1536 if ( existItem.exists() )
1537 {
1538@@ -181,5 +253,36 @@
1539 << "addedCounter:" << addedCounter
1540 << "removedCounter:" << removedCounter;
1541 #endif
1542- emit finished(counter);
1543+
1544+ return counter;
1545+}
1546+
1547+void ExternalFileSystemChangesWorker::run()
1548+{
1549+ DirItemInfoList directoryContents = getContents();
1550+ int remainingitemsCounter = compareItems(directoryContents);
1551+ emit finished(remainingitemsCounter);
1552+}
1553+
1554+
1555+//---------------------------------------------------------------------
1556+ExternalFileSystemTrashChangesWorker::ExternalFileSystemTrashChangesWorker(const QStringList &pathNames,
1557+ const DirItemInfoList &list,
1558+ QDir::Filter filter)
1559+ : ExternalFileSystemChangesWorker(list, pathNames.at(0), filter, false)
1560+ , m_pathList(pathNames)
1561+{
1562+ mLoaderType = TrashLoader;
1563+}
1564+
1565+void ExternalFileSystemTrashChangesWorker::run()
1566+{
1567+ DirItemInfoList directoryContents;
1568+ for(int counter = 0; counter < m_pathList.count(); counter++)
1569+ {
1570+ mPathName = QTrashUtilInfo::filesTrashDir(m_pathList.at(counter));
1571+ directoryContents += getContents();
1572+ }
1573+ int remainingitemsCounter = compareItems(directoryContents);
1574+ emit finished(remainingitemsCounter);
1575 }
1576
1577=== modified file 'folderlistmodel/iorequest.h'
1578--- folderlistmodel/iorequest.h 2014-02-05 15:31:44 +0000
1579+++ folderlistmodel/iorequest.h 2014-03-23 13:46:13 +0000
1580@@ -62,31 +62,72 @@
1581
1582
1583
1584-class DirListWorker : public IORequest
1585+class IORequestLoader : public IORequest
1586 {
1587- Q_OBJECT
1588+ Q_OBJECT
1589 public:
1590- explicit DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive);
1591- void run();
1592+ enum LoaderType
1593+ {
1594+ NormalLoader,
1595+ TrashLoader
1596+ };
1597+
1598+ IORequestLoader( const QString &pathName,
1599+ QDir::Filter filter,
1600+ bool isRecursive
1601+ );
1602+ IORequestLoader( const QString& trashRootDir,
1603+ const QString &pathName,
1604+ QDir::Filter filter,
1605+ bool isRecursive
1606+ );
1607+ DirItemInfoList getContents();
1608+
1609 signals:
1610 void itemsAdded(const DirItemInfoList &files);
1611- void workerFinished();
1612-
1613-protected:
1614- DirItemInfoList getContents();
1615
1616 private:
1617+ DirItemInfoList getNormalContent();
1618+ DirItemInfoList getTrashContent();
1619 DirItemInfoList add(const QString &pathName, QDir::Filter filter,
1620- const bool isRecursive, DirItemInfoList directoryContents);
1621-private:
1622+ bool isRecursive, DirItemInfoList directoryContents);
1623+protected:
1624+ LoaderType mLoaderType;
1625 QString mPathName;
1626 QDir::Filter mFilter;
1627 bool mIsRecursive;
1628-};
1629-
1630-
1631-
1632-class ExternalFileSystemChangesWorker : public DirListWorker
1633+ QString mTtrashRootDir;
1634+};
1635+
1636+
1637+
1638+
1639+class DirListWorker : public IORequestLoader
1640+{
1641+ Q_OBJECT
1642+public:
1643+ explicit DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive);
1644+ explicit DirListWorker(const QString& trashRootDir, const QString &pathName, QDir::Filter filter, const bool isRecursive);
1645+ void run();
1646+protected:
1647+signals:
1648+ void workerFinished();
1649+
1650+};
1651+
1652+
1653+
1654+
1655+class TrashListWorker : public DirListWorker
1656+{
1657+ Q_OBJECT
1658+public:
1659+ explicit TrashListWorker(const QString &trashRoot, const QString& path, QDir::Filter filter);
1660+};
1661+
1662+
1663+
1664+class ExternalFileSystemChangesWorker : public IORequestLoader
1665 {
1666 Q_OBJECT
1667 public:
1668@@ -95,6 +136,10 @@
1669 QDir::Filter filter,
1670 const bool isRecursive);
1671 void run();
1672+
1673+protected:
1674+ int compareItems(const DirItemInfoList& contentNew);
1675+
1676 signals:
1677 void removed(const DirItemInfo&);
1678 void changed(const DirItemInfo&);
1679@@ -106,4 +151,20 @@
1680
1681
1682
1683+class ExternalFileSystemTrashChangesWorker : public ExternalFileSystemChangesWorker
1684+{
1685+ Q_OBJECT
1686+
1687+public:
1688+ ExternalFileSystemTrashChangesWorker(const QStringList& pathNames,
1689+ const DirItemInfoList& list,
1690+ QDir::Filter filter);
1691+
1692+ void run();
1693+private:
1694+ QStringList m_pathList;
1695+};
1696+
1697+
1698+
1699 #endif // IOREQUEST_H
1700
1701=== added file 'folderlistmodel/location.cpp'
1702--- folderlistmodel/location.cpp 1970-01-01 00:00:00 +0000
1703+++ folderlistmodel/location.cpp 2014-03-23 13:46:13 +0000
1704@@ -0,0 +1,140 @@
1705+/**************************************************************************
1706+ *
1707+ * Copyright 2014 Canonical Ltd.
1708+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1709+ *
1710+ * This program is free software; you can redistribute it and/or modify
1711+ * it under the terms of the GNU Lesser General Public License as published by
1712+ * the Free Software Foundation; version 3.
1713+ *
1714+ * This program is distributed in the hope that it will be useful,
1715+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1716+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1717+ * GNU Lesser General Public License for more details.
1718+ *
1719+ * You should have received a copy of the GNU Lesser General Public License
1720+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1721+ *
1722+ * File: location.cpp
1723+ * Date: 08/03/2014
1724+ */
1725+/**************************************************************************
1726+ *
1727+ * Copyright 2014 Canonical Ltd.
1728+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1729+ *
1730+ * This program is free software; you can redistribute it and/or modify
1731+ * it under the terms of the GNU Lesser General Public License as published by
1732+ * the Free Software Foundation; version 3.
1733+ *
1734+ * This program is distributed in the hope that it will be useful,
1735+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1736+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1737+ * GNU Lesser General Public License for more details.
1738+ *
1739+ * You should have received a copy of the GNU Lesser General Public License
1740+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1741+ *
1742+ * File: locations.cpp
1743+ * Date: 04/03/2014
1744+ */
1745+
1746+#include "location.h"
1747+#include "ioworkerthread.h"
1748+
1749+Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread)
1750+
1751+
1752+Location::Location(int type, QObject *parent)
1753+ : QObject(parent)
1754+ , m_info(0)
1755+ , m_type(type)
1756+ , m_usingExternalWatcher(false)
1757+{
1758+
1759+}
1760+
1761+Location::~Location()
1762+{
1763+ if (m_info)
1764+ {
1765+ delete m_info;
1766+ m_info = 0;
1767+ }
1768+}
1769+
1770+
1771+bool Location::isRoot() const
1772+{
1773+ return m_info->isRoot();
1774+}
1775+
1776+
1777+bool Location::isWritable() const
1778+{
1779+ return m_info->isWritable();
1780+}
1781+
1782+
1783+bool Location::isReadable() const
1784+{
1785+ return m_info->isReadable();
1786+}
1787+
1788+void Location::setFromInfoItem(const DirItemInfo &itemInfo)
1789+{
1790+ setFromInfoItem (new DirItemInfo(itemInfo));
1791+}
1792+
1793+void Location::setFromInfoItem(const DirItemInfo *itemInfo)
1794+{
1795+ if (m_info)
1796+ {
1797+ delete m_info;
1798+ }
1799+ m_info = const_cast<DirItemInfo*> (itemInfo);
1800+}
1801+
1802+
1803+QString Location::urlPath() const
1804+{
1805+ return m_info->urlPath();
1806+}
1807+
1808+
1809+void Location::startWorking()
1810+{
1811+
1812+}
1813+
1814+void Location::stopWorking()
1815+{
1816+
1817+}
1818+
1819+bool Location::becomeParent()
1820+{
1821+ return false;
1822+}
1823+
1824+IOWorkerThread * Location::workerThread() const
1825+{
1826+ return ioWorkerThread();
1827+}
1828+
1829+
1830+//providing an empty method
1831+void Location::fetchExternalChanges(const QString &path,
1832+ const DirItemInfoList &list,
1833+ QDir::Filter dirFilter)
1834+{
1835+ Q_UNUSED(path);
1836+ Q_UNUSED(list);
1837+ Q_UNUSED(dirFilter);
1838+}
1839+
1840+
1841+void Location::setUsingExternalWatcher(bool use)
1842+{
1843+ m_usingExternalWatcher = use;
1844+}
1845
1846=== added file 'folderlistmodel/location.h'
1847--- folderlistmodel/location.h 1970-01-01 00:00:00 +0000
1848+++ folderlistmodel/location.h 2014-03-23 13:46:13 +0000
1849@@ -0,0 +1,132 @@
1850+/**************************************************************************
1851+ *
1852+ * Copyright 2014 Canonical Ltd.
1853+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1854+ *
1855+ * This program is free software; you can redistribute it and/or modify
1856+ * it under the terms of the GNU Lesser General Public License as published by
1857+ * the Free Software Foundation; version 3.
1858+ *
1859+ * This program is distributed in the hope that it will be useful,
1860+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1861+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1862+ * GNU Lesser General Public License for more details.
1863+ *
1864+ * You should have received a copy of the GNU Lesser General Public License
1865+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1866+ *
1867+ * File: location.h
1868+ * Date: 08/03/2014
1869+ */
1870+
1871+#ifndef LOCATION_H
1872+#define LOCATION_H
1873+
1874+#include "diriteminfo.h"
1875+
1876+#include <QObject>
1877+
1878+class IOWorkerThread;
1879+
1880+/*!
1881+ * \brief The Location class represents any location (full path) where there are items to browse: directories, shares, from Disk and from Network.
1882+ *
1883+ * It is an abstract class the must be inherited for specific Location handling as example: \ref DiskLocation and \ref TrashLocation
1884+ *
1885+ * The location must be able to:
1886+ * \li provide the browsing for the location in \ref fetchItems()
1887+ * \li become itself its parent in \ref becomeParent() it will allow easy \ref DirModel::cdUp()
1888+ * \li refresh its information in \ref refreshInfo()
1889+ * \li validate its location (creates a valid DirItemInfo object or any descendent) from a url string
1890+ *
1891+ * The \ref startWorking() is called by \ref LocationsFactory just before this location becomes the current in the File Manager
1892+ * In the same way the \ref stopWorking() is called by \ref LocationsFactory just before this location no longer be the current in the File Manager
1893+ */
1894+class Location : public QObject
1895+{
1896+ Q_OBJECT
1897+public:
1898+ explicit Location( int type, QObject *parent=0);
1899+ ~Location();
1900+
1901+ IOWorkerThread * workerThread() const;
1902+
1903+signals:
1904+ void itemsAdded(const DirItemInfoList &files);
1905+ void itemsFetched();
1906+ void extWatcherPathChanged(const QString&);
1907+ void extWatcherItemRemoved(const DirItemInfo&);
1908+ void extWatcherItemChanged(const DirItemInfo&);
1909+ void extWatcherItemAdded(const DirItemInfo&);
1910+ void extWatcherChangesFetched(int);
1911+
1912+public slots:
1913+ virtual void setUsingExternalWatcher(bool use);
1914+
1915+public: //pure functions
1916+ /*!
1917+ * \brief fetchItems() gets the content of the Location
1918+ *
1919+ * \param dirFilter current Filter
1920+ * \param recursive should get the content all sub dirs or not, (hardly ever it is true)
1921+ */
1922+ virtual void fetchItems(QDir::Filter dirFilter, bool recursive=0) = 0;
1923+
1924+ /*!
1925+ * \brief refreshInfo() It must refresh the DirItemInfo
1926+ *
1927+ * It can be used for example after receiving the signal about external disk file system changes
1928+ * due to the current path permissions might have changed.
1929+ */
1930+ virtual void refreshInfo() = 0;
1931+
1932+ /*!
1933+ * \brief becomeParent() The current path location becomes the parent Location
1934+ *
1935+ * When \ref isRoot() returns false the current path location becomes the parent path location
1936+ * in order to make it the current.
1937+ * It acts like a cdUp, but without fetching items; then calling \ref fetchItems() may get contents.
1938+ *
1939+ * \note It must take care of deleting \ref m_info when creating a new DirItemInfo/TrashItemInfo etc.
1940+ *
1941+ * \return true if it is possible to do like a cdUp.
1942+ */
1943+ virtual bool becomeParent() = 0;
1944+
1945+ /*!
1946+ * \brief validateUrlPath() Validates the urlPath (file or Directory) and creates a new Obeject from this path
1947+ *
1948+ * If urlPath is a valid Directory it can be used later to set a new Location.
1949+ *
1950+ * \param urlPath
1951+ * \return a valid pointer to DirItemInfo object or NULL indicating something wrong with the path
1952+ */
1953+ virtual DirItemInfo * validateUrlPath(const QString& urlPath) = 0;
1954+
1955+public:
1956+ virtual void fetchExternalChanges(const QString& urlPath,
1957+ const DirItemInfoList& list,
1958+ QDir::Filter dirFilter) ;
1959+ virtual void setFromInfoItem(const DirItemInfo &itemInfo);
1960+ virtual void setFromInfoItem(const DirItemInfo *itemInfo);
1961+ virtual bool isRoot() const;
1962+ virtual bool isWritable() const;
1963+ virtual bool isReadable() const;
1964+ virtual QString urlPath() const;
1965+ virtual void startWorking();
1966+ virtual void stopWorking();
1967+
1968+ inline const DirItemInfo* info() const { return m_info; }
1969+ inline int type() const { return m_type; }
1970+
1971+protected:
1972+ DirItemInfo * m_info;
1973+ int m_type;
1974+ bool m_usingExternalWatcher;
1975+
1976+#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
1977+ friend class TestDirModel;
1978+#endif
1979+
1980+};
1981+#endif // LOCATION_H
1982
1983=== added file 'folderlistmodel/locationsfactory.cpp'
1984--- folderlistmodel/locationsfactory.cpp 1970-01-01 00:00:00 +0000
1985+++ folderlistmodel/locationsfactory.cpp 2014-03-23 13:46:13 +0000
1986@@ -0,0 +1,183 @@
1987+/**************************************************************************
1988+ *
1989+ * Copyright 2014 Canonical Ltd.
1990+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1991+ *
1992+ * This program is free software; you can redistribute it and/or modify
1993+ * it under the terms of the GNU Lesser General Public License as published by
1994+ * the Free Software Foundation; version 3.
1995+ *
1996+ * This program is distributed in the hope that it will be useful,
1997+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1998+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1999+ * GNU Lesser General Public License for more details.
2000+ *
2001+ * You should have received a copy of the GNU Lesser General Public License
2002+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2003+ *
2004+ * File: locationsfactory.cpp
2005+ * Date: 05/03/2014
2006+ */
2007+
2008+#include "diriteminfo.h"
2009+#include "locationsfactory.h"
2010+#include "location.h"
2011+#include "locationurl.h"
2012+#include "disk/disklocation.h"
2013+#include "trash/trashlocation.h"
2014+#include "trashiteminfo.h"
2015+
2016+#include <QDir>
2017+#include <QDebug>
2018+
2019+
2020+
2021+LocationsFactory::LocationsFactory(QObject *parent)
2022+ : QObject(parent)
2023+ , m_curLoc(0)
2024+ , m_lastValidFileInfo(0)
2025+{
2026+ m_locations.append(new DiskLocation(LocalDisk));
2027+ m_locations.append(new TrashLocation(TrashDisk));
2028+}
2029+
2030+
2031+LocationsFactory::~LocationsFactory()
2032+{
2033+ ::qDeleteAll(m_locations);
2034+ m_locations.clear();
2035+}
2036+
2037+
2038+/*!
2039+ * \brief LocationsFactory::parse() identifies what main location that path/url refers to
2040+ * \param path it is supposed to be always a full path like: file:///myDir /myDir trash:/// trash:///myDir
2041+ * \return
2042+ */
2043+
2044+const Location * LocationsFactory::parse(const QString& uPath)
2045+{
2046+ int index = -1;
2047+ int type = -1;
2048+ Location * location = 0;
2049+ if ( (index = uPath.indexOf(QChar(':'))) != -1 )
2050+ {
2051+#if defined(Q_OS_WIN)
2052+#else
2053+#if defined(Q_OS_UNIX)
2054+ if (uPath.startsWith(LocationUrl::TrashRootURL.midRef(0,6)))
2055+ {
2056+ type = TrashDisk;
2057+ m_tmpPath = LocationUrl::TrashRootURL + stringAfterSlahes(uPath, index+1);
2058+ }
2059+ else
2060+#endif //Q_OS_UNIX
2061+#endif //Q_OS_UNIX
2062+ if (uPath.startsWith(LocationUrl::DiskRootURL.midRef(0,5)))
2063+ {
2064+ type = LocalDisk;
2065+ m_tmpPath = QDir::rootPath() + stringAfterSlahes(uPath, index+1);
2066+ }
2067+ }
2068+ else
2069+ {
2070+ m_tmpPath = stringAfterSlahes(uPath, -1);
2071+ type = LocalDisk;
2072+ if (!m_tmpPath.startsWith(QDir::rootPath()) && m_curLoc)
2073+ {
2074+ //it can be any, check current location
2075+ type = m_curLoc->type();
2076+ }
2077+ }
2078+ if (!m_tmpPath.isEmpty() && type != -1)
2079+ {
2080+ location = m_locations.at(type);
2081+ }
2082+#if DEBUG_MESSAGES
2083+ qDebug() << Q_FUNC_INFO << "input path:" << uPath << "location result:" << location;
2084+#endif
2085+ return location;
2086+}
2087+
2088+
2089+const Location * LocationsFactory::setNewPath(const QString& uPath)
2090+{
2091+ storeValidFileInfo(0);
2092+ Location *location = const_cast<Location*> (parse(uPath));
2093+ if (location)
2094+ {
2095+ const DirItemInfo *item = location->validateUrlPath(m_tmpPath);
2096+ if (item)
2097+ {
2098+ //isReadable() must already carry execution permission
2099+ if (item->isValid() && item->isDir() && item->isReadable())
2100+ {
2101+ location->setFromInfoItem(item);
2102+ if (location != m_curLoc)
2103+ {
2104+ if (m_curLoc)
2105+ {
2106+ m_curLoc->stopWorking();
2107+ }
2108+ emit locationChanged(m_curLoc, location);
2109+ location->startWorking();
2110+ m_curLoc = location;
2111+ }
2112+ }
2113+ else
2114+ {
2115+ storeValidFileInfo(item);
2116+ }
2117+ }
2118+ else
2119+ { // not valid
2120+ location = 0;
2121+ }
2122+ }
2123+#if DEBUG_MESSAGES
2124+ qDebug() << Q_FUNC_INFO << "input path:" << uPath << "location result:" << location;
2125+#endif
2126+ return location;
2127+}
2128+
2129+
2130+QString LocationsFactory::stringAfterSlahes(const QString &url, int firstSlashIndex) const
2131+{
2132+ QString ret;
2133+ if (firstSlashIndex >=0)
2134+ {
2135+ while ( firstSlashIndex < url.length() && url.at(firstSlashIndex) == QDir::separator())
2136+ {
2137+ ++firstSlashIndex;
2138+ }
2139+ if (firstSlashIndex < url.length())
2140+ {
2141+ ret = url.mid(firstSlashIndex);
2142+ }
2143+ }
2144+ else
2145+ {
2146+ ret = url;
2147+ firstSlashIndex = 0;
2148+ }
2149+ //replace any double slashes by just one
2150+ for(int charCounter = ret.size() -1; charCounter > 0; --charCounter)
2151+ {
2152+ if (ret.at(charCounter) == QDir::separator() &&
2153+ ret.at(charCounter-1) == QDir::separator())
2154+ {
2155+ ret.remove(charCounter,1);
2156+ }
2157+ }
2158+ return ret;
2159+}
2160+
2161+
2162+void LocationsFactory::storeValidFileInfo(const DirItemInfo *item)
2163+{
2164+ if (m_lastValidFileInfo)
2165+ {
2166+ delete m_lastValidFileInfo;
2167+ }
2168+ m_lastValidFileInfo = item;
2169+}
2170
2171=== added file 'folderlistmodel/locationsfactory.h'
2172--- folderlistmodel/locationsfactory.h 1970-01-01 00:00:00 +0000
2173+++ folderlistmodel/locationsfactory.h 2014-03-23 13:46:13 +0000
2174@@ -0,0 +1,133 @@
2175+/**************************************************************************
2176+ *
2177+ * Copyright 2014 Canonical Ltd.
2178+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
2179+ *
2180+ * This program is free software; you can redistribute it and/or modify
2181+ * it under the terms of the GNU Lesser General Public License as published by
2182+ * the Free Software Foundation; version 3.
2183+ *
2184+ * This program is distributed in the hope that it will be useful,
2185+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2186+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2187+ * GNU Lesser General Public License for more details.
2188+ *
2189+ * You should have received a copy of the GNU Lesser General Public License
2190+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2191+ *
2192+ * File: locationsfactory.h
2193+ * Date: 05/03/2014
2194+ */
2195+
2196+#ifndef LOCATIONSFACTORY_H
2197+#define LOCATIONSFACTORY_H
2198+
2199+#include <QObject>
2200+#include <QList>
2201+
2202+
2203+class Location;
2204+class DirItemInfo;
2205+
2206+/*!
2207+ * \brief The LocationsFactory class represents the set of main
2208+ * URL locations the File Manager supports.
2209+ *
2210+ * It is basically devided into main groups:
2211+ * \li Disk: \ref LocalDisk and \ref TrashDisk
2212+ * \li Net: \ref NetSambaShare and NetFishShare
2213+ *
2214+ * smb:// browses workgroup
2215+ *
2216+ * Location parser: \ref parser()
2217+ * \li \\workkgroup becomes smb://workgroup
2218+ * \li \\ becomes smb://
2219+ * \li trash:/ and trash:// becomes trash:///
2220+ * \li fish:/ and fish:// becomes fish:///
2221+ * \li file:/ , file:// and file:/// becomes /
2222+ *
2223+ * \note Due to current File Manager UI typing method both: "file:" and "trash:" are supported
2224+ */
2225+class LocationsFactory : public QObject
2226+{
2227+ Q_OBJECT
2228+public:
2229+ explicit LocationsFactory(QObject *parent = 0);
2230+ ~LocationsFactory();
2231+
2232+ Q_ENUMS(Locations)
2233+ enum Locations
2234+ {
2235+ LocalDisk, //<! any mounted file system
2236+ TrashDisk //<! special trash location in the disk
2237+#if 0
2238+ NetSambaShare //<! SAMBA or CIFS shares
2239+ NetFishShare //<! FISH protocol over ssh that provides file sharing
2240+#endif
2241+ };
2242+
2243+ /*!
2244+ * \brief parse() Just parses (does not set/change the current location) according to \a urlPath
2245+ * \param urlPath urlPath the url like: file:///Item trash:///item /item, it MUST point to a valid Directory
2246+ * \return The location which supports the \a urlPath
2247+ */
2248+ const Location * parse(const QString& urlPath);
2249+
2250+ /*!
2251+ * \brief setNewPath() Sets a new path, it can be in the current location or on another location
2252+ *
2253+ * When the location changes, the signal \ref locationChanged() is fired.
2254+ *
2255+ * \param urlPath the url like: file:///Item trash:///item /item, it MUST point to a valid Directory
2256+ * \return the location that supports the urlPath or NULL when \a urlPath is NOT a valid url or it is not a valid Directory
2257+ *
2258+ * \sa \ref parse() \ref location()
2259+ */
2260+ const Location * setNewPath(const QString& urlPath);
2261+
2262+ /*!
2263+ * \brief location()
2264+ * \return The current location
2265+ */
2266+ const Location * location() const { return m_curLoc; }
2267+
2268+ /*!
2269+ * \brief availableLocations()
2270+ * \return
2271+ */
2272+ const QList<Location*>&
2273+ availableLocations() const { return m_locations; }
2274+
2275+ /*!
2276+ * \brief lastValidFileInfo()
2277+ *
2278+ * When calling setNewPath(file_path) using a path to a File instead of a Directory
2279+ * the setNewPath() is not able to set a new path (current location or other), however it uses
2280+ * Location::validateUrlPath() which validates the path for files also, then this valid DirItemInfo object
2281+ * is saved using \ref storeValidFileInfo() for further use.
2282+ *
2283+ * \return The last valid DirItemInfo parsed which is not a Directory
2284+ */
2285+ const DirItemInfo* lastValidFileInfo() const { return m_lastValidFileInfo; }
2286+
2287+ void storeValidFileInfo(const DirItemInfo *item);
2288+
2289+signals:
2290+ void locationChanged(const Location *old, const Location *current);
2291+
2292+private:
2293+ QString stringAfterSlahes(const QString& url, int firstSlashIndex) const;
2294+
2295+private:
2296+ Location * m_curLoc;
2297+ QList<Location*> m_locations;
2298+ QString m_tmpPath;
2299+ const DirItemInfo * m_lastValidFileInfo;
2300+
2301+#if defined(REGRESSION_TEST_FOLDERLISTMODEL)
2302+ friend class TestDirModel;
2303+#endif
2304+
2305+};
2306+
2307+#endif // LOCATIONSFACTORY_H
2308
2309=== added file 'folderlistmodel/locationurl.cpp'
2310--- folderlistmodel/locationurl.cpp 1970-01-01 00:00:00 +0000
2311+++ folderlistmodel/locationurl.cpp 2014-03-23 13:46:13 +0000
2312@@ -0,0 +1,34 @@
2313+/**************************************************************************
2314+ *
2315+ * Copyright 2014 Canonical Ltd.
2316+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
2317+ *
2318+ * This program is free software; you can redistribute it and/or modify
2319+ * it under the terms of the GNU Lesser General Public License as published by
2320+ * the Free Software Foundation; version 3.
2321+ *
2322+ * This program is distributed in the hope that it will be useful,
2323+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2324+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2325+ * GNU Lesser General Public License for more details.
2326+ *
2327+ * You should have received a copy of the GNU Lesser General Public License
2328+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2329+ *
2330+ * File: locationurl.cpp
2331+ * Date: 11/03/2014
2332+ */
2333+
2334+#include "locationurl.h"
2335+
2336+const QString LocationUrl::TrashRootURL("trash:///");
2337+const QString LocationUrl::DiskRootURL("file:///");
2338+#if 0
2339+QString LocationURL::SmbURL("smb://");
2340+QString LocationURL::FishURL("fish:///");
2341+#endif
2342+
2343+
2344+LocationUrl::LocationUrl()
2345+{
2346+}
2347
2348=== added file 'folderlistmodel/locationurl.h'
2349--- folderlistmodel/locationurl.h 1970-01-01 00:00:00 +0000
2350+++ folderlistmodel/locationurl.h 2014-03-23 13:46:13 +0000
2351@@ -0,0 +1,40 @@
2352+/**************************************************************************
2353+ *
2354+ * Copyright 2014 Canonical Ltd.
2355+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
2356+ *
2357+ * This program is free software; you can redistribute it and/or modify
2358+ * it under the terms of the GNU Lesser General Public License as published by
2359+ * the Free Software Foundation; version 3.
2360+ *
2361+ * This program is distributed in the hope that it will be useful,
2362+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2363+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2364+ * GNU Lesser General Public License for more details.
2365+ *
2366+ * You should have received a copy of the GNU Lesser General Public License
2367+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2368+ *
2369+ * File: locationurl.h
2370+ * Date: 11/03/2014
2371+ */
2372+
2373+#ifndef LOCATIONURL_H
2374+#define LOCATIONURL_H
2375+
2376+#include <QString>
2377+
2378+class LocationUrl
2379+{
2380+public:
2381+ static const QString DiskRootURL;
2382+ static const QString TrashRootURL;
2383+#if 0
2384+ static const QString SmbURL;
2385+ static const QString FishURL;
2386+#endif
2387+private:
2388+ LocationUrl();
2389+};
2390+
2391+#endif // LOCATIONURL_H
2392
2393=== modified file 'folderlistmodel/trash/qtrashdir.cpp'
2394--- folderlistmodel/trash/qtrashdir.cpp 2014-02-15 15:18:24 +0000
2395+++ folderlistmodel/trash/qtrashdir.cpp 2014-03-23 13:46:13 +0000
2396@@ -20,6 +20,7 @@
2397 */
2398
2399 #include "qtrashdir.h"
2400+#include "qtrashutilinfo.h"
2401
2402 #include <QFileInfo>
2403 #include <QDir>
2404@@ -34,10 +35,6 @@
2405 #endif
2406
2407
2408-QTrashDir::QTrashDir() : m_userId(::getuid())
2409-{
2410-
2411-}
2412
2413 bool QTrashDir::validate(const QString &trashDir, bool create) const
2414 {
2415@@ -49,8 +46,8 @@
2416 }
2417 if (checkUserDirPermissions(trashDir))
2418 {
2419- QString files(filesTrashDir(trashDir));
2420- QString info(infoTrashDir(trashDir));
2421+ QString files(QTrashUtilInfo::filesTrashDir(trashDir));
2422+ QString info(QTrashUtilInfo::infoTrashDir(trashDir));
2423 if ( (checkUserDirPermissions(files) || (create && createUserDir(files))) &&
2424 (checkUserDirPermissions(info) || (create && createUserDir(info)))
2425 )
2426@@ -170,18 +167,6 @@
2427 }
2428
2429
2430-QString QTrashDir::filesTrashDir(const QString &trashDir) const
2431-{
2432- QString filesDir(trashDir + QDir::separator() + QLatin1String("files"));
2433- return filesDir;
2434-}
2435-
2436-
2437-QString QTrashDir::infoTrashDir(const QString &trashDir) const
2438-{
2439- QString infoDir(trashDir + QDir::separator() + QLatin1String("info"));
2440- return infoDir;
2441-}
2442
2443
2444 /*!
2445@@ -333,3 +318,21 @@
2446 }
2447 return trashDir;
2448 }
2449+
2450+
2451+bool QTrashDir:: suitableTrash(const QString &fullPathName, QTrashUtilInfo &fullInfo) const
2452+{
2453+ fullInfo.setInfo(suitableTrash(fullPathName), fullPathName);
2454+ return fullInfo.isValid();
2455+}
2456+
2457+
2458+
2459+
2460+
2461+QTrashDir::QTrashDir() : m_userId(::getuid())
2462+{
2463+
2464+}
2465+
2466+
2467
2468=== modified file 'folderlistmodel/trash/qtrashdir.h'
2469--- folderlistmodel/trash/qtrashdir.h 2014-02-15 15:18:24 +0000
2470+++ folderlistmodel/trash/qtrashdir.h 2014-03-23 13:46:13 +0000
2471@@ -24,7 +24,7 @@
2472
2473 #include <QStringList>
2474 #include <QDateTime>
2475-
2476+struct QTrashUtilInfo;
2477
2478 /*!
2479 * \brief The QTrashDir class is a Qt implementation of the Trash Directories specification
2480@@ -93,19 +93,8 @@
2481 */
2482 QString suitableTrash(const QString &fullPathName) const;
2483
2484- /*!
2485- * \brief filesTrashDir() gets the "files" directory under Trash Dir
2486- * \param trashDir
2487- * \return trashDir/files
2488- */
2489- QString filesTrashDir(const QString& trashDir) const;
2490+ bool suitableTrash(const QString &fullPathName, QTrashUtilInfo& fullInfo) const;
2491
2492- /*!
2493- * \brief infoTrashDir() gets gets the "info" directory under Trash Dir
2494- * \param trashDir
2495- * \return trashDir/info
2496- */
2497- QString infoTrashDir(const QString& trashDir) const;
2498
2499 private:
2500 bool validate(const QString& trashDir, bool create=false) const;
2501@@ -120,7 +109,7 @@
2502
2503 private:
2504 uint m_userId;
2505- #if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests
2506+#if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests
2507 friend class TestDirModel;
2508 #endif
2509 };
2510
2511=== added file 'folderlistmodel/trash/qtrashutilinfo.cpp'
2512--- folderlistmodel/trash/qtrashutilinfo.cpp 1970-01-01 00:00:00 +0000
2513+++ folderlistmodel/trash/qtrashutilinfo.cpp 2014-03-23 13:46:13 +0000
2514@@ -0,0 +1,87 @@
2515+/**************************************************************************
2516+ *
2517+ * Copyright 2014 Canonical Ltd.
2518+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
2519+ *
2520+ * This program is free software; you can redistribute it and/or modify
2521+ * it under the terms of the GNU Lesser General Public License as published by
2522+ * the Free Software Foundation; version 3.
2523+ *
2524+ * This program is distributed in the hope that it will be useful,
2525+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2526+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2527+ * GNU Lesser General Public License for more details.
2528+ *
2529+ * You should have received a copy of the GNU Lesser General Public License
2530+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2531+ *
2532+ * File: qtrashutilinfo.cpp
2533+ * Date: 16/03/2014
2534+ */
2535+
2536+#include "qtrashutilinfo.h"
2537+
2538+#include <QDir>
2539+
2540+
2541+void QTrashUtilInfo::clear()
2542+{
2543+ trashRoot.clear();
2544+ filesDir.clear();
2545+ absFile.clear();
2546+ infoDir.clear();
2547+ absInfo.clear();
2548+ valid = false;
2549+}
2550+
2551+
2552+QString QTrashUtilInfo::filesTrashDir(const QString &trashDir)
2553+{
2554+ QString filesDir(trashDir + QDir::separator() + QLatin1String("files"));
2555+ return filesDir;
2556+}
2557+
2558+
2559+QString QTrashUtilInfo::infoTrashDir(const QString &trashDir)
2560+{
2561+ QString infoDir(trashDir + QDir::separator() + QLatin1String("info"));
2562+ return infoDir;
2563+}
2564+
2565+
2566+void QTrashUtilInfo:: setInfo(const QString& trashDir, const QString& filename)
2567+{
2568+ valid = !trashDir.isEmpty();
2569+ if (valid)
2570+ {
2571+ QFileInfo f(filename);
2572+ trashRoot = trashDir;
2573+ filesDir = filesTrashDir(trashDir);
2574+ absFile = filesDir + QDir::separator() + f.fileName();
2575+ infoDir = infoTrashDir(trashDir) ;
2576+ absInfo = infoDir + QDir::separator() + f.fileName() +
2577+ QLatin1String(".trashinfo");
2578+ }
2579+ else
2580+ {
2581+ clear();
2582+ }
2583+}
2584+
2585+
2586+bool QTrashUtilInfo::isValid()
2587+{
2588+ return valid;
2589+}
2590+
2591+
2592+bool QTrashUtilInfo::existsFile()
2593+{
2594+ return QFileInfo(absFile).exists();
2595+}
2596+
2597+
2598+bool QTrashUtilInfo::existsInfoFile()
2599+{
2600+ return QFileInfo(absInfo).exists();
2601+}
2602
2603=== added file 'folderlistmodel/trash/qtrashutilinfo.h'
2604--- folderlistmodel/trash/qtrashutilinfo.h 1970-01-01 00:00:00 +0000
2605+++ folderlistmodel/trash/qtrashutilinfo.h 2014-03-23 13:46:13 +0000
2606@@ -0,0 +1,57 @@
2607+/**************************************************************************
2608+ *
2609+ * Copyright 2014 Canonical Ltd.
2610+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
2611+ *
2612+ * This program is free software; you can redistribute it and/or modify
2613+ * it under the terms of the GNU Lesser General Public License as published by
2614+ * the Free Software Foundation; version 3.
2615+ *
2616+ * This program is distributed in the hope that it will be useful,
2617+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2618+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2619+ * GNU Lesser General Public License for more details.
2620+ *
2621+ * You should have received a copy of the GNU Lesser General Public License
2622+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2623+ *
2624+ * File: qtrashutilinfo.h
2625+ * Date: 16/03/2014
2626+ */
2627+
2628+#ifndef QTRASHUTILINFO_H
2629+#define QTRASHUTILINFO_H
2630+
2631+#include <QString>
2632+
2633+struct QTrashUtilInfo
2634+{
2635+public:
2636+ void setInfo(const QString& trashDir, const QString& filename);
2637+ void clear();
2638+ bool existsInfoFile();
2639+ bool existsFile();
2640+ bool isValid();
2641+ /*!
2642+ * \brief filesTrashDir() gets the "files" directory under Trash Dir
2643+ * \param trashDir
2644+ * \return trashDir/files
2645+ */
2646+ static QString filesTrashDir(const QString& trashDir);
2647+
2648+ /*!
2649+ * \brief infoTrashDir() gets gets the "info" directory under Trash Dir
2650+ * \param trashDir
2651+ * \return trashDir/info
2652+ */
2653+ static QString infoTrashDir(const QString& trashDir);
2654+
2655+ QString trashRoot; // root
2656+ QString filesDir; // root/files
2657+ QString absFile; // root/files/item
2658+ QString infoDir; // root/info
2659+ QString absInfo; // root/info/item.trashinfo
2660+ bool valid;
2661+};
2662+
2663+#endif // QTRASHUTILINFO_H
2664
2665=== added file 'folderlistmodel/trash/trashiteminfo.cpp'
2666--- folderlistmodel/trash/trashiteminfo.cpp 1970-01-01 00:00:00 +0000
2667+++ folderlistmodel/trash/trashiteminfo.cpp 2014-03-23 13:46:13 +0000
2668@@ -0,0 +1,141 @@
2669+/**************************************************************************
2670+ *
2671+ * Copyright 2014 Canonical Ltd.
2672+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
2673+ *
2674+ * This program is free software; you can redistribute it and/or modify
2675+ * it under the terms of the GNU Lesser General Public License as published by
2676+ * the Free Software Foundation; version 3.
2677+ *
2678+ * This program is distributed in the hope that it will be useful,
2679+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2680+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2681+ * GNU Lesser General Public License for more details.
2682+ *
2683+ * You should have received a copy of the GNU Lesser General Public License
2684+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2685+ *
2686+ * File: trashiteminfo.cpp
2687+ * Date: 05/03/2014
2688+ */
2689+
2690+#include "trashiteminfo.h"
2691+#include "locationurl.h"
2692+
2693+
2694+TrashItemInfo::TrashItemInfo(const QString &urlPath)
2695+ : DirItemInfo()
2696+{
2697+ d_ptr->_path = urlPath;
2698+ d_ptr->_isLocal = true;
2699+ d_ptr->_normalizedPath = urlPath;
2700+ if (urlPath == LocationUrl::TrashRootURL)
2701+ {
2702+ setRoot();
2703+ }
2704+}
2705+
2706+
2707+TrashItemInfo::TrashItemInfo(const TrashItemInfo &other)
2708+ : DirItemInfo(other)
2709+{
2710+}
2711+
2712+
2713+TrashItemInfo::TrashItemInfo(const QString& trashPath, const QString &urlPath)
2714+ : DirItemInfo(urlPath)
2715+{
2716+ init(trashPath);
2717+}
2718+
2719+
2720+void TrashItemInfo::setRoot()
2721+{
2722+ d_ptr->_isValid = true;
2723+ d_ptr->_isRoot = true;
2724+ d_ptr->_isDir = true;
2725+ d_ptr->_isReadable = true;
2726+ d_ptr->_isExecutable = true;
2727+ d_ptr->_exists = true;
2728+ d_ptr->_fileName.clear();
2729+}
2730+
2731+
2732+void TrashItemInfo::init(const QString& trashPath)
2733+{
2734+ if (trashPath == absoluteFilePath())
2735+ {
2736+ d_ptr->_path = trashPath;
2737+ setRoot();
2738+ }
2739+ else
2740+ {
2741+ if (!d_ptr->_path.startsWith(trashPath))
2742+ {
2743+ d_ptr->_isValid = false;
2744+ }
2745+ }
2746+ QString abs(d_ptr->_path);
2747+ d_ptr->_normalizedPath = abs.replace(0,trashPath.length()+1, LocationUrl::TrashRootURL);
2748+}
2749+
2750+
2751+TrashItemInfo& TrashItemInfo::operator=(const DirItemInfo &other)
2752+{
2753+ DirItemInfo::operator = (other);
2754+ const TrashItemInfo *isTrash = dynamic_cast<const TrashItemInfo*> (&other);
2755+ if (isTrash)
2756+ {
2757+ // move extra data here when exist, avoid extra data than DirItemInfo
2758+ }
2759+ return *this;
2760+}
2761+
2762+
2763+TrashItemInfo& TrashItemInfo::operator=(const TrashItemInfo &other)
2764+{
2765+ DirItemInfo::operator = (other);
2766+ return *this;
2767+}
2768+
2769+
2770+/*!
2771+ * \brief TrashItemInfo::getTrashDir()
2772+ *
2773+ * Lets suppose a directory in the trash named DIR:
2774+ * absFilePath() = /home/user/.local/share/Trash/files/DIR
2775+ * normalizedFilePath() = trash:///DIR
2776+ *
2777+ * The trash dir is /home/user/.local/share/Trash/files
2778+ *
2779+ * \return The trash dir
2780+ */
2781+QString TrashItemInfo::getTrashDir() const
2782+{
2783+ QString trashDir;
2784+ QString norm(urlPath());
2785+ if ( norm.length() > LocationUrl::TrashRootURL.length()
2786+ && norm.startsWith(LocationUrl::TrashRootURL)
2787+ )
2788+ {
2789+ QStringRef trashItemRef(norm.midRef(LocationUrl::TrashRootURL.length()));
2790+ QString abs(absoluteFilePath());
2791+ int length = abs.lastIndexOf(trashItemRef);
2792+ if (length > 0)
2793+ {
2794+ trashDir = abs.left(length-1);
2795+ }
2796+ }
2797+ return trashDir;
2798+}
2799+
2800+
2801+QString TrashItemInfo::getRootTrashDir() const
2802+{
2803+ QString ret = getTrashDir();
2804+ if (!isRoot())
2805+ {
2806+ ret = QFileInfo(ret).absolutePath();
2807+ }
2808+ return ret;
2809+}
2810
2811=== added file 'folderlistmodel/trash/trashiteminfo.h'
2812--- folderlistmodel/trash/trashiteminfo.h 1970-01-01 00:00:00 +0000
2813+++ folderlistmodel/trash/trashiteminfo.h 2014-03-23 13:46:13 +0000
2814@@ -0,0 +1,58 @@
2815+/**************************************************************************
2816+ *
2817+ * Copyright 2014 Canonical Ltd.
2818+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
2819+ *
2820+ * This program is free software; you can redistribute it and/or modify
2821+ * it under the terms of the GNU Lesser General Public License as published by
2822+ * the Free Software Foundation; version 3.
2823+ *
2824+ * This program is distributed in the hope that it will be useful,
2825+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2826+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2827+ * GNU Lesser General Public License for more details.
2828+ *
2829+ * You should have received a copy of the GNU Lesser General Public License
2830+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2831+ *
2832+ * File: trashiteminfo.h
2833+ * Date: 05/03/2014
2834+ */
2835+
2836+#ifndef TRASHITEMINFO_H
2837+#define TRASHITEMINFO_H
2838+
2839+#include "diriteminfo.h"
2840+
2841+
2842+/*!
2843+ * \brief The TrashItemInfo class provides a QFileInfo like information for files in Trash
2844+ *
2845+ * Basically it differs from DirItemInfo in the field \a d_ptr->_normalizedPath, it must store the
2846+ * url like trash:///Item, while the field d_ptr->_path stores the current path in the file system as usual.
2847+ *
2848+ * So suppose a Item in the trash:
2849+ * \li \ref absoluteFilePath() returns like /home/user/.local/share/Trash/files/Item
2850+ * \li \ref urlPath() returns trash:///Item
2851+ * \li \ref getTrashDir() does a right-to-left comparing in order to find out the Trash Dir, in this case /home/user/.local/share/Trash/files
2852+ *
2853+ * The constructor \ref TrashItemInfo(const QString& urlPath) is used only to store the logical root trash folder trash:///
2854+ */
2855+class TrashItemInfo : public DirItemInfo
2856+{
2857+public:
2858+ TrashItemInfo(const QString& urlPath);
2859+ TrashItemInfo(const QString& trashPath, const QString& urlPath);
2860+ TrashItemInfo(const TrashItemInfo &other);
2861+public:
2862+ virtual TrashItemInfo& operator=(const DirItemInfo &other);
2863+ virtual TrashItemInfo& operator=(const TrashItemInfo &other);
2864+public:
2865+ QString getTrashDir() const;
2866+ QString getRootTrashDir() const;
2867+private:
2868+ void setRoot();
2869+ void init(const QString& trashPath);
2870+};
2871+
2872+#endif // TRASHITEMINFO_H
2873
2874=== added file 'folderlistmodel/trash/trashlocation.cpp'
2875--- folderlistmodel/trash/trashlocation.cpp 1970-01-01 00:00:00 +0000
2876+++ folderlistmodel/trash/trashlocation.cpp 2014-03-23 13:46:13 +0000
2877@@ -0,0 +1,255 @@
2878+/**************************************************************************
2879+ *
2880+ * Copyright 2014 Canonical Ltd.
2881+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
2882+ *
2883+ * This program is free software; you can redistribute it and/or modify
2884+ * it under the terms of the GNU Lesser General Public License as published by
2885+ * the Free Software Foundation; version 3.
2886+ *
2887+ * This program is distributed in the hope that it will be useful,
2888+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2889+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2890+ * GNU Lesser General Public License for more details.
2891+ *
2892+ * You should have received a copy of the GNU Lesser General Public License
2893+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2894+ *
2895+ * File: trashlocation.cpp
2896+ * Date: 08/03/2014
2897+ */
2898+
2899+#include "iorequest.h"
2900+#include "ioworkerthread.h"
2901+#include "trashlocation.h"
2902+#include "trashiteminfo.h"
2903+#include "qtrashutilinfo.h"
2904+#include "locationurl.h"
2905+#include "externalfswatcher.h"
2906+
2907+#include <QDebug>
2908+
2909+TrashLocation::TrashLocation(int type, QObject *parent) :
2910+ DiskLocation(type, parent)
2911+ ,QTrashDir()
2912+
2913+{
2914+}
2915+
2916+
2917+bool TrashLocation::becomeParent()
2918+{
2919+
2920+ bool ret = false;
2921+ TrashItemInfo *trashInfo = static_cast<TrashItemInfo*> (m_info);
2922+ if (trashInfo && !trashInfo->isRoot())
2923+ {
2924+ QString trashDir = trashInfo->getTrashDir();
2925+ if (!trashDir.isEmpty())
2926+ {
2927+ TrashItemInfo *other = new TrashItemInfo(trashDir, trashInfo->absolutePath());
2928+ if (other->isValid() && other->isDir())
2929+ {
2930+ delete m_info;
2931+ m_info = other;
2932+ ret = true;
2933+ }
2934+ else
2935+ {
2936+ delete other;
2937+ }
2938+ }
2939+ }
2940+ return ret;
2941+}
2942+
2943+
2944+DirItemInfo * TrashLocation::validateUrlPath(const QString& urlPath)
2945+{
2946+ TrashItemInfo *item = 0;
2947+ QString myPath(urlPath);
2948+
2949+ //first void any relative path when is root
2950+ if (m_info && m_info->isRoot() && myPath.startsWith(QLatin1String("..")))
2951+ {
2952+ return item;
2953+ }
2954+
2955+ int firstSlash = -1;
2956+
2957+ // handle relative paths to the current
2958+ if (!myPath.startsWith(LocationUrl::TrashRootURL) && m_info)
2959+ {
2960+ QFileInfo f;
2961+ f.setFile(m_info->absoluteFilePath(), myPath);
2962+ if (f.exists() && f.isDir())
2963+ {
2964+ TrashItemInfo *trashItem = static_cast<TrashItemInfo*> (m_info);
2965+ item = new TrashItemInfo(trashItem->getTrashDir(), f.canonicalFilePath());
2966+#if DEBUG_MESSAGES
2967+ qDebug() << Q_FUNC_INFO << "cur path:" << m_info->absoluteFilePath()
2968+ << " new path:" << item->absoluteFilePath()
2969+ << "url:" << item->urlPath();
2970+#endif
2971+ }
2972+ else
2973+ {
2974+ myPath = LocationUrl::TrashRootURL + urlPath;
2975+ }
2976+ }
2977+ else
2978+ {
2979+ item = new TrashItemInfo(myPath);
2980+ if (!item->isRoot())
2981+ {
2982+ delete item;
2983+ item = 0;
2984+ }
2985+ }
2986+
2987+ //Not Relative, handle absolute path but it is not root
2988+ if (item == 0)
2989+ {
2990+ QString absTrashItem;
2991+ QString trashItemFromRoot = myPath.mid(LocationUrl::TrashRootURL.size());
2992+ foreach(const QString& trashRoot, allTrashes())
2993+ {
2994+ //this is the full path of the item, it does not mean it is a Trash top level item
2995+ //example: trash:///Dir1/Dir2/Dir3 may be in /home/user/.local/share/Trash//Dir1/Dir2/Dir3
2996+ absTrashItem = QTrashUtilInfo::filesTrashDir(trashRoot) + QDir::separator() + trashItemFromRoot;
2997+ const QFileInfo info(absTrashItem);
2998+ if (info.exists())
2999+ {
3000+ //check top level trash item
3001+ firstSlash = trashItemFromRoot.indexOf(QDir::separator());
3002+ QString toplevelDir = firstSlash != -1 ? trashItemFromRoot.left(firstSlash)
3003+ : trashItemFromRoot;
3004+
3005+ QTrashUtilInfo topLevelTrashDirInfo;
3006+ topLevelTrashDirInfo.setInfo(trashRoot, toplevelDir);
3007+#if DEBUG_MESSAGES
3008+ qDebug() << Q_FUNC_INFO
3009+ << topLevelTrashDirInfo.absFile << "exists" << topLevelTrashDirInfo.existsFile()
3010+ << topLevelTrashDirInfo.absInfo << "exists" << topLevelTrashDirInfo.existsInfoFile();
3011+#endif
3012+ //check if a .trashinfo file for toplevel dir exists
3013+ if (topLevelTrashDirInfo.existsInfoFile())
3014+ {
3015+ item = new TrashItemInfo(QTrashUtilInfo::filesTrashDir(trashRoot), absTrashItem);
3016+ break;
3017+ }
3018+ }
3019+ }
3020+ }
3021+
3022+ if (item)
3023+ {
3024+ if (!item->isValid() || !item->isReadable())
3025+ {
3026+ delete item;
3027+ item = 0;
3028+ }
3029+ else
3030+ {
3031+ if (firstSlash != -1)
3032+ {
3033+ // TODO get the trashinfo information and carry into the item
3034+ }
3035+ }
3036+ }
3037+ return item;
3038+}
3039+
3040+
3041+
3042+
3043+void TrashLocation::refreshInfo()
3044+{
3045+ if (m_info && !m_info->isRoot())
3046+ {
3047+ TrashItemInfo *trashItem = static_cast<TrashItemInfo*>(m_info);
3048+ TrashItemInfo *item = new TrashItemInfo(trashItem->getTrashDir(), trashItem->absoluteFilePath());
3049+ delete m_info;
3050+ m_info = item;
3051+ }
3052+}
3053+
3054+
3055+void TrashLocation::startExternalFsWatcher()
3056+{
3057+ //TODO implement a Watcher for this
3058+ //modify the existent watcher to work having a list of paths
3059+ if (m_extWatcher == 0)
3060+ {
3061+ m_extWatcher = new ExternalFSWatcher(this);
3062+ m_extWatcher->setIntervalToNotifyChanges(EX_FS_WATCHER_TIMER_INTERVAL);
3063+
3064+ connect(m_extWatcher, SIGNAL(pathModified(QString)),
3065+ this, SIGNAL(extWatcherPathChanged(QString)));
3066+ }
3067+}
3068+
3069+
3070+void TrashLocation::fetchItems(QDir::Filter dirFilter, bool recursive)
3071+{
3072+ Q_UNUSED(recursive)
3073+ if (!m_info->isRoot()) //any item under the logical trash folder
3074+ {
3075+ //sub items inside Trash do not need external watcher, they will never be updated
3076+ stoptExternalFsWatcher();
3077+ TrashItemInfo *trashItem = static_cast<TrashItemInfo*> (m_info);
3078+ TrashListWorker *dlw = new TrashListWorker(trashItem->getRootTrashDir(),
3079+ trashItem->absoluteFilePath(),
3080+ dirFilter);
3081+ addTrashFetchRequest(dlw);
3082+ }
3083+ else
3084+ {
3085+ QStringList trashes = allTrashes();
3086+ startExternalFsWatcher();
3087+ m_extWatcher->setCurrentPaths(trashes);
3088+ //the trash a is logical folder, its content can be composed by more than one physical folder
3089+ foreach (const QString& trashRootDir, trashes)
3090+ {
3091+ TrashListWorker *dlw = new TrashListWorker(trashRootDir,
3092+ QTrashUtilInfo::filesTrashDir(trashRootDir),
3093+ dirFilter);
3094+ addTrashFetchRequest(dlw);
3095+ }
3096+ }
3097+}
3098+
3099+
3100+void TrashLocation::addTrashFetchRequest(TrashListWorker *workerObject)
3101+{
3102+ connect(workerObject, SIGNAL(itemsAdded(DirItemInfoList)),
3103+ this, SIGNAL(itemsAdded(DirItemInfoList)));
3104+ //it differs from DiskLocation
3105+ connect(workerObject, SIGNAL(workerFinished()),
3106+ this, SIGNAL(itemsFetched()));
3107+ workerThread()->addRequest(workerObject);
3108+}
3109+
3110+
3111+
3112+void TrashLocation::fetchExternalChanges(const QString& urlPath,
3113+ const DirItemInfoList& list,
3114+ QDir::Filter dirFilter)
3115+{
3116+ Q_UNUSED(urlPath);
3117+ if (m_extWatcher)
3118+ {
3119+ ExternalFileSystemTrashChangesWorker * extFsWorker =
3120+ new ExternalFileSystemTrashChangesWorker( m_extWatcher->pathsWatched(),
3121+ list,
3122+ dirFilter
3123+ );
3124+ addExternalFsWorkerRequest(extFsWorker);
3125+ }
3126+}
3127+
3128+
3129+void TrashLocation::startWorking()
3130+{
3131+ // do nothing, the startExternalFsWatcher() is called in fetchItems()
3132+}
3133
3134=== added file 'folderlistmodel/trash/trashlocation.h'
3135--- folderlistmodel/trash/trashlocation.h 1970-01-01 00:00:00 +0000
3136+++ folderlistmodel/trash/trashlocation.h 2014-03-23 13:46:13 +0000
3137@@ -0,0 +1,54 @@
3138+/**************************************************************************
3139+ *
3140+ * Copyright 2014 Canonical Ltd.
3141+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
3142+ *
3143+ * This program is free software; you can redistribute it and/or modify
3144+ * it under the terms of the GNU Lesser General Public License as published by
3145+ * the Free Software Foundation; version 3.
3146+ *
3147+ * This program is distributed in the hope that it will be useful,
3148+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3149+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3150+ * GNU Lesser General Public License for more details.
3151+ *
3152+ * You should have received a copy of the GNU Lesser General Public License
3153+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3154+ *
3155+ * File: trashlocation.h
3156+ * Date: 08/03/2014
3157+ */
3158+
3159+#ifndef TRASHLOCATION_H
3160+#define TRASHLOCATION_H
3161+
3162+#include "disk/disklocation.h"
3163+#include "trash/qtrashdir.h"
3164+
3165+class TrashListWorker;
3166+
3167+class TrashLocation : public DiskLocation, public QTrashDir
3168+{
3169+ Q_OBJECT
3170+public:
3171+ explicit TrashLocation(int type, QObject *parent=0);
3172+ virtual bool becomeParent();
3173+ virtual void refreshInfo();
3174+ virtual void fetchItems(QDir::Filter dirFilter, bool recursive=0);
3175+ virtual void fetchExternalChanges(const QString& urlPath,
3176+ const DirItemInfoList& list,
3177+ QDir::Filter dirFilter) ;
3178+
3179+ virtual void startWorking();
3180+ virtual void startExternalFsWatcher();
3181+
3182+ virtual DirItemInfo *validateUrlPath(const QString& urlPath);
3183+
3184+private:
3185+ void addTrashFetchRequest(TrashListWorker *workerObject);
3186+
3187+public slots:
3188+
3189+};
3190+
3191+#endif // TRASHLOCATION_H
3192
3193=== modified file 'test_folderlistmodel/regression/tst_folderlistmodel.cpp'
3194--- test_folderlistmodel/regression/tst_folderlistmodel.cpp 2014-03-03 17:19:49 +0000
3195+++ test_folderlistmodel/regression/tst_folderlistmodel.cpp 2014-03-23 13:46:13 +0000
3196@@ -4,6 +4,11 @@
3197 #include "externalfswatcher.h"
3198 #include "dirselection.h"
3199 #include "trash/qtrashdir.h"
3200+#include "location.h"
3201+#include "locationurl.h"
3202+#include "locationsfactory.h"
3203+#include "disk/disklocation.h"
3204+#include "qtrashutilinfo.h"
3205
3206 #if defined(Q_OS_UNIX)
3207 #include <stdio.h>
3208@@ -77,7 +82,7 @@
3209 void cancel(int index, int, int percent);
3210 void slotclipboardChanged();
3211 void slotError(QString title, QString message);
3212- void slotExtFsWatcherPathModified() { ++m_extFSWatcherPathModifiedCounter; }
3213+ void slotExtFsWatcherPathModified(const QString&) { ++m_extFSWatcherPathModifiedCounter; }
3214 void slotSelectionChanged(int counter) { m_selectedItemsCounter = counter; }
3215 void slotSelectionModeChanged(int m) { m_selectionMode = m;}
3216
3217@@ -144,7 +149,10 @@
3218
3219 void trashDiretories();
3220
3221+ void locationFactory();
3222+
3223 private:
3224+ bool createTempHomeTrashDir(const QString& existentDir);
3225 void initDeepDirs();
3226 void cleanDeepDirs();
3227 void initModels();
3228@@ -1409,16 +1417,114 @@
3229 QCOMPARE(ret, true);
3230 QCOMPARE(m_currentPath, m_deepDir_01->path());
3231 QCOMPARE(m_dirModel_01->rowCount(), 1);
3232+ QCOMPARE(m_receivedErrorSignal, false);
3233
3234 ret = m_dirModel_01->openPath(QLatin1String(".."));
3235 QTest::qWait(TIME_TO_REFRESH_DIR);
3236 QCOMPARE(ret, true);
3237 QCOMPARE(m_currentPath, QDir::tempPath());
3238+ QCOMPARE(m_receivedErrorSignal, false);
3239
3240 ret = m_dirModel_01->openPath(orig);
3241 QTest::qWait(TIME_TO_REFRESH_DIR);
3242 QCOMPARE(ret, true);
3243 QCOMPARE(m_currentPath, m_deepDir_01->path());
3244+ QCOMPARE(m_receivedErrorSignal, false);
3245+
3246+ // trash --------------------------------------
3247+ TempFiles files;
3248+ QCOMPARE(files.addSubDirLevel(m_deepDir_01->path()), true);
3249+
3250+ createTempHomeTrashDir(m_deepDir_01->path());
3251+
3252+ QTrashDir tempTrash;
3253+ QCOMPARE(files.addSubDirLevel(tempTrash.homeTrash()), true);
3254+ QCOMPARE(files.addSubDirLevel(QTrashUtilInfo::filesTrashDir(tempTrash.homeTrash())), true);
3255+
3256+ QString level1("Level1");
3257+ QCOMPARE(files.addSubDirLevel(level1), true);
3258+
3259+ QTrashUtilInfo trashInfo;
3260+ trashInfo.setInfo(tempTrash.homeTrash(), level1);
3261+ QCOMPARE(trashInfo.existsFile() , true);
3262+ QFile infoFile(trashInfo.absInfo);
3263+ QCOMPARE(infoFile.open(QFile::WriteOnly), true);
3264+ infoFile.close();
3265+
3266+ //check if "Level1" is valid item under trash
3267+ QCOMPARE(trashInfo.existsInfoFile() , true);
3268+
3269+ QString level2("level2");
3270+ QString level3("level3");
3271+
3272+ QCOMPARE(files.addSubDirLevel(level2), true);
3273+ QCOMPARE(files.addSubDirLevel(level3), true);
3274+
3275+ files.create(1);
3276+
3277+ // using trash:///
3278+ ret = m_dirModel_01->openPath(LocationUrl::TrashRootURL);
3279+ QTest::qWait(TIME_TO_REFRESH_DIR);
3280+ QCOMPARE(ret, true);
3281+ QCOMPARE(m_currentPath, LocationUrl::TrashRootURL);
3282+ QCOMPARE(m_receivedErrorSignal, false);
3283+
3284+ // using relative "Level1"
3285+ ret = m_dirModel_01->openPath(level1);
3286+ QTest::qWait(TIME_TO_REFRESH_DIR);
3287+ QCOMPARE(ret, true);
3288+ QCOMPARE(m_currentPath, QString(LocationUrl::TrashRootURL + level1) );
3289+ QCOMPARE(m_receivedErrorSignal, false);
3290+
3291+ //using trash:///Level1/Level2/Level3
3292+ QString deep(LocationUrl::TrashRootURL + level1 + QDir::separator() + level2 + QDir::separator() + level3);
3293+ ret = m_dirModel_01->openPath(deep);
3294+ QTest::qWait(TIME_TO_REFRESH_DIR);
3295+ QCOMPARE(ret, true);
3296+ QCOMPARE(m_receivedErrorSignal, false);
3297+
3298+ //using ../ to go up into Level2
3299+ ret = m_dirModel_01->openPath("../");
3300+ QTest::qWait(TIME_TO_REFRESH_DIR);
3301+ QCOMPARE(ret, true);
3302+ QCOMPARE(m_receivedErrorSignal, false);
3303+
3304+ //using .. to go up into Level1
3305+ ret = m_dirModel_01->openPath("..");
3306+ QTest::qWait(TIME_TO_REFRESH_DIR);
3307+ QCOMPARE(ret, true);
3308+ QCOMPARE(m_receivedErrorSignal, false);
3309+
3310+ //back to trash:///
3311+ ret = m_dirModel_01->openPath("..");
3312+ QTest::qWait(TIME_TO_REFRESH_DIR);
3313+ QCOMPARE(ret, true);
3314+ QCOMPARE(m_currentPath, LocationUrl::TrashRootURL);
3315+ QCOMPARE(m_receivedErrorSignal, false);
3316+
3317+ //now it must fail
3318+ ret = m_dirModel_01->openPath("..");
3319+ QTest::qWait(TIME_TO_REFRESH_DIR);
3320+ QCOMPARE(ret, false);
3321+ QCOMPARE(m_receivedErrorSignal, false);
3322+
3323+ ret = m_dirModel_01->openPath("file:///");
3324+ QTest::qWait(TIME_TO_REFRESH_DIR);
3325+ QCOMPARE(ret, true);
3326+ QCOMPARE(m_currentPath, QDir::rootPath());
3327+ QCOMPARE(m_receivedErrorSignal, false);
3328+
3329+ ret = m_dirModel_01->openPath("file://");
3330+ QTest::qWait(TIME_TO_REFRESH_DIR);
3331+ QCOMPARE(ret, true);
3332+ QCOMPARE(m_currentPath, QDir::rootPath());
3333+ QCOMPARE(m_receivedErrorSignal, false);
3334+
3335+ ret = m_dirModel_01->openPath("file:/");
3336+ QTest::qWait(TIME_TO_REFRESH_DIR);
3337+ QCOMPARE(ret, true);
3338+ QCOMPARE(m_currentPath, QDir::rootPath());
3339+ QCOMPARE(m_receivedErrorSignal, false);
3340 }
3341
3342
3343@@ -1859,8 +1965,8 @@
3344 void TestDirModel::extFsWatcherChangePathManyTimesModifyAllPathsLessLast()
3345 {
3346 ExternalFSWatcher watcher;
3347- connect(&watcher, SIGNAL(pathModified()),
3348- this, SLOT(slotExtFsWatcherPathModified()));
3349+ connect(&watcher, SIGNAL(pathModified(QString)),
3350+ this, SLOT(slotExtFsWatcherPathModified(QString)));
3351
3352 const int items = 150;
3353 QVector<DeepDir *> deepDirs;
3354@@ -1896,8 +2002,8 @@
3355 void TestDirModel::extFsWatcherChangePathManyTimesModifyManyTimes()
3356 {
3357 ExternalFSWatcher watcher;
3358- connect(&watcher, SIGNAL(pathModified()),
3359- this, SLOT(slotExtFsWatcherPathModified()));
3360+ connect(&watcher, SIGNAL(pathModified(QString)),
3361+ this, SLOT(slotExtFsWatcherPathModified(QString)));
3362
3363 const int items = 50;
3364 QVector<DeepDir *> deepDirs;
3365@@ -1930,8 +2036,8 @@
3366 void TestDirModel::extFsWatcherModifySamePathManyTimesWithInInterval()
3367 {
3368 ExternalFSWatcher watcher;
3369- connect(&watcher, SIGNAL(pathModified()),
3370- this, SLOT(slotExtFsWatcherPathModified()));
3371+ connect(&watcher, SIGNAL(pathModified(QString)),
3372+ this, SLOT(slotExtFsWatcherPathModified(QString)));
3373
3374 QString dirName("extFsWatcher_expects_just_one_signal");
3375 m_deepDir_01 = new DeepDir(dirName,0);
3376@@ -1957,8 +2063,8 @@
3377 void TestDirModel::extFsWatcherSetPathAndModifyManyTimesWithInInterval()
3378 {
3379 ExternalFSWatcher watcher;
3380- connect(&watcher, SIGNAL(pathModified()),
3381- this, SLOT(slotExtFsWatcherPathModified()));
3382+ connect(&watcher, SIGNAL(pathModified(QString)),
3383+ this, SLOT(slotExtFsWatcherPathModified(QString)));
3384
3385 QList<DeepDir *> deepDirs;
3386
3387@@ -1995,8 +2101,8 @@
3388 {
3389 bool updateAndSetModificationTime(const QString& filename, QDateTime& desiredTime);
3390
3391- connect( m_dirModel_01->mExtFSWatcher, SIGNAL(pathModified()),
3392- this, SLOT(slotExtFsWatcherPathModified()));
3393+ connect( m_dirModel_01->getExternalFSWatcher(), SIGNAL(pathModified(QString)),
3394+ this, SLOT(slotExtFsWatcherPathModified(QString)));
3395
3396 QString dirName("extFsWatcher_generate_fileswithsameTimeStamp");
3397 m_deepDir_01 = new DeepDir(dirName,0);
3398@@ -2029,7 +2135,7 @@
3399 QFileInfo firstFile(firstPathName);
3400 QCOMPARE(firstFile.lastModified(), timeStamp);
3401
3402- const int maxWait = m_dirModel_01->mExtFSWatcher->getIntervalToNotifyChanges() + 10;
3403+ const int maxWait = m_dirModel_01->getExternalFSWatcher()->getIntervalToNotifyChanges() + 10;
3404 int counter = 0;
3405
3406 //make sure ExternalFSWatcher has not notified any change
3407@@ -2308,9 +2414,9 @@
3408 QCOMPARE(trash.checkUserDirPermissions(trashDir), true);
3409
3410 //create files in Trash
3411- QCOMPARE(trash.createUserDir(trash.filesTrashDir(trashDir)), true);
3412+ QCOMPARE(trash.createUserDir(QTrashUtilInfo::filesTrashDir(trashDir)), true);
3413 //create info in Trash
3414- QCOMPARE(trash.createUserDir(trash.infoTrashDir(trashDir)), true);
3415+ QCOMPARE(trash.createUserDir(QTrashUtilInfo::infoTrashDir(trashDir)), true);
3416 //test validate Trash Dir(), now it MUST pass
3417 QCOMPARE(trash.validate(trashDir, false), true);
3418
3419@@ -2327,16 +2433,18 @@
3420 QString xdgTrash("xdg_Trash");
3421 m_deepDir_02 = new DeepDir(xdgTrash,0);
3422
3423+ if (::qgetenv("XDG_DATA_HOME").size() == 0)
3424+ {
3425+ QString myTrash(QDir::homePath() + "/.local/share/Trash");
3426+ QCOMPARE(trash.homeTrash(), myTrash);
3427+ }
3428+
3429 //test XDG Home Trash
3430 ::setenv("XDG_DATA_HOME", m_deepDir_02->path().toLatin1().constData(), true );
3431-
3432 QString xdgTrashDir(trash.homeTrash());
3433 QCOMPARE(trash.validate(xdgTrashDir, false), true);
3434 QCOMPARE(trash.homeTrash() , xdgTrashDir);
3435
3436- ::setenv("XDG_DATA_HOME", "\0", true );
3437- QCOMPARE(trash.homeTrash() , QDir::homePath() + "/.local/share/Trash");
3438-
3439 QCOMPARE(trash.getMountPoint(QDir::rootPath()), QDir::rootPath());
3440
3441 QStringList mountedPoints = trash.mountedPoints();
3442@@ -2389,6 +2497,118 @@
3443 }
3444
3445
3446+void TestDirModel::locationFactory()
3447+{
3448+ LocationsFactory factoryLocations(this);
3449+ const Location *location = 0;
3450+
3451+ QString validTrashURL(LocationUrl::TrashRootURL);
3452+
3453+ //Due to current File Manager UI typing method both: "file:" and "trash:" are supported
3454+ // location = factoryLocations.setNewPath("trash:");
3455+ // QVERIFY(location == 0);
3456+
3457+ location = factoryLocations.setNewPath("trash:/");
3458+ QVERIFY(location);
3459+ QVERIFY(location->type() == LocationsFactory::TrashDisk);
3460+ QCOMPARE(location->info()->absoluteFilePath(), validTrashURL);
3461+ QCOMPARE(location->urlPath(), validTrashURL);
3462+ QCOMPARE(location->isRoot(), true);
3463+
3464+ location = factoryLocations.setNewPath("trash://");
3465+ QVERIFY(location);
3466+ QVERIFY(location->type() == LocationsFactory::TrashDisk);
3467+ QCOMPARE(location->info()->absoluteFilePath(), validTrashURL);
3468+ QCOMPARE(location->urlPath(), validTrashURL);
3469+ QCOMPARE(location->isRoot(), true);
3470+
3471+ location = factoryLocations.setNewPath("trash:///");
3472+ QVERIFY(location);
3473+ QVERIFY(location->type() == LocationsFactory::TrashDisk);
3474+ QCOMPARE(location->info()->absoluteFilePath(), validTrashURL);
3475+ QCOMPARE(location->urlPath(), validTrashURL);
3476+ QCOMPARE(location->isRoot(), true);
3477+
3478+ location = factoryLocations.setNewPath("trash://////");
3479+ QVERIFY(location);
3480+ QVERIFY(location->type() == LocationsFactory::TrashDisk);
3481+ QCOMPARE(location->info()->absoluteFilePath(), validTrashURL);
3482+ QCOMPARE(location->urlPath(), validTrashURL);
3483+ QCOMPARE(location->isRoot(), true);
3484+
3485+ QString myDir("___myDir_must_NOT_EXIST___");
3486+ location = factoryLocations.setNewPath(QString("trash:/") + myDir);
3487+ QVERIFY(location == 0);
3488+
3489+ location = factoryLocations.setNewPath("file://////");
3490+ QVERIFY(location);
3491+ QVERIFY(location->type() == LocationsFactory::LocalDisk);
3492+ QCOMPARE(location->info()->absoluteFilePath(), QDir::rootPath());
3493+ QCOMPARE(location->urlPath(), QDir::rootPath());
3494+ QCOMPARE(location->isRoot(), true);
3495+
3496+ location = factoryLocations.setNewPath("/");
3497+ QVERIFY(location);
3498+ QVERIFY(location->type() == LocationsFactory::LocalDisk);
3499+ QCOMPARE(location->info()->absoluteFilePath(), QDir::rootPath());
3500+ QCOMPARE(location->urlPath(), QDir::rootPath());
3501+ QCOMPARE(location->isRoot(), true);
3502+
3503+ location = factoryLocations.setNewPath("//");
3504+ QVERIFY(location);
3505+ QVERIFY(location->type() == LocationsFactory::LocalDisk);
3506+ QCOMPARE(location->info()->absoluteFilePath(), QDir::rootPath());
3507+ QCOMPARE(location->urlPath(), QDir::rootPath());
3508+ QCOMPARE(location->isRoot(), true);
3509+
3510+ location = factoryLocations.setNewPath("//bin");
3511+ QVERIFY(location);
3512+ QVERIFY(location->type() == LocationsFactory::LocalDisk);
3513+ QCOMPARE(location->info()->absoluteFilePath(), QLatin1String("/bin"));
3514+ QCOMPARE(location->urlPath(), QLatin1String("/bin"));
3515+ QCOMPARE(location->isRoot(), false);
3516+
3517+ QTrashDir trash;
3518+ QString dirName("trashDirectory");
3519+ m_deepDir_01 = new DeepDir(dirName,0);
3520+
3521+ //create a Trash to have
3522+
3523+ ::setenv("XDG_DATA_HOME", m_deepDir_01->path().toLatin1().constData(), true );
3524+ QString xdgTrashDir(trash.homeTrash());
3525+ QCOMPARE(trash.validate(xdgTrashDir, true), true);
3526+ QCOMPARE(trash.homeTrash() , xdgTrashDir);
3527+
3528+ QString trash3("trash:///Dir1/Dir2/Dir3");
3529+ QString trash2("trash:///Dir1/Dir2");
3530+ QString trash1("trash:///Dir1");
3531+
3532+ QCOMPARE(QDir().mkpath(QTrashUtilInfo::filesTrashDir(xdgTrashDir) + "/Dir1/Dir2/Dir3"), true);
3533+
3534+
3535+ //create a empty .trashinfo file to validate the Trash
3536+ QFile trashinfo (QTrashUtilInfo::infoTrashDir(xdgTrashDir) + "/Dir1.trashinfo");
3537+ QCOMPARE(trashinfo.open(QFile::WriteOnly), true);
3538+ trashinfo.close();
3539+
3540+ location = factoryLocations.setNewPath(trash3);
3541+ Location * myLocation = const_cast<Location*> (location);
3542+ QCOMPARE(myLocation->becomeParent(), true);
3543+ QCOMPARE(location->urlPath(), trash2);
3544+ QCOMPARE(location->isRoot(), false);
3545+
3546+ location = factoryLocations.setNewPath(trash2);
3547+ myLocation = const_cast<Location*> (location);
3548+ QCOMPARE(myLocation->becomeParent(), true);
3549+ QCOMPARE(location->urlPath(), trash1);
3550+ QCOMPARE(location->isRoot(), false);
3551+
3552+ myLocation = const_cast<Location*> (location);
3553+ QCOMPARE(myLocation->becomeParent(), true);
3554+ QCOMPARE(location->urlPath(), LocationUrl::TrashRootURL);
3555+ QCOMPARE(location->isRoot(), true);
3556+}
3557+
3558 int main(int argc, char *argv[])
3559 {
3560 QApplication app(argc, argv);
3561@@ -2444,6 +2664,21 @@
3562 return ret;
3563 }
3564
3565+
3566+bool TestDirModel::createTempHomeTrashDir(const QString& existentDir)
3567+{
3568+ QDir d(existentDir);
3569+ bool ret = false;
3570+ if (existentDir.startsWith(QDir::tempPath()) && (d.exists() || d.mkpath(existentDir)))
3571+ {
3572+ QTrashDir trash;
3573+ ::setenv("XDG_DATA_HOME", existentDir.toLatin1().constData(), true );
3574+ QString xdgTrashDir(trash.homeTrash());
3575+ ret = trash.validate(xdgTrashDir, true);
3576+ }
3577+ return ret;
3578+}
3579+
3580 #if defined(Q_OS_UNIX)
3581 /*!
3582 * \brief updateAndSetModificationTime()

Subscribers

People subscribed via source and target branches