Merge lp:~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre5-final into lp:ubuntu-filemanager-app

Proposed by Carlos Jose Mazieri
Status: Merged
Approved by: Carlos Jose Mazieri
Approved revision: 177
Merged at revision: 184
Proposed branch: lp:~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre5-final
Merge into: lp:ubuntu-filemanager-app
Prerequisite: lp:~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre4
Diff against target: 1653 lines (+1185/-84)
16 files modified
src/plugin/folderlistmodel/CMakeLists.txt (+7/-1)
src/plugin/folderlistmodel/dirmodel.cpp (+7/-1)
src/plugin/folderlistmodel/dirmodel.h (+5/-0)
src/plugin/folderlistmodel/folderlistmodel.pri (+11/-6)
src/plugin/folderlistmodel/iorequest.cpp (+137/-31)
src/plugin/folderlistmodel/iorequest.h (+42/-5)
src/plugin/folderlistmodel/locationsfactory.cpp (+4/-2)
src/plugin/folderlistmodel/trash/qtrashdir.cpp (+14/-14)
src/plugin/folderlistmodel/trash/qtrashdir.h (+3/-14)
src/plugin/folderlistmodel/trash/qtrashutilinfo.cpp (+153/-0)
src/plugin/folderlistmodel/trash/qtrashutilinfo.h (+82/-0)
src/plugin/folderlistmodel/trash/trashiteminfo.cpp (+147/-0)
src/plugin/folderlistmodel/trash/trashiteminfo.h (+58/-0)
src/plugin/folderlistmodel/trash/trashlocation.cpp (+260/-0)
src/plugin/folderlistmodel/trash/trashlocation.h (+55/-0)
src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp (+200/-10)
To merge this branch: bzr merge lp:~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre5-final
Reviewer Review Type Date Requested Status
Carlos Jose Mazieri Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+218062@code.launchpad.net

Commit message

it is the last part of https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/app-devel/+merge/216409 in fact the branches should be equals.

Description of the change

Introduces Trash, Trash browsing by providing TrashLocation class.
  * Add equivalent Disk Loader/Comparing classes for Trash in iorequest.h/iorequest.cpp
  * Add TrashLocation object into LocationsFactory
  * Trash browsing: DirModel::goTrash()
  * fileCompareExists() changed to use absolute path since Trash can have more than an item with same name
    belonging to different sources.

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
Alan Pope 🍺🐧🐱 πŸ¦„ (popey) wrote :

I've asked Michael Spencer to take a look at this and the other related branches and review. If he has difficulty with that I've asked him to get back to me so we can find another reviewer.

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

> I've asked Michael Spencer to take a look at this and the other related
> branches and review. If he has difficulty with that I've asked him to get back
> to me so we can find another reviewer.

These 5 branches code enable Trash browsing only.

I have also Trash Operations done: "move to Trash", "restore from Trash" and "empty Trash".

I am thinking about proposing these changes which completes Trash support in some more separated branches.

Please let me know if I should wait for a reviewer.

174. By Carlos Jose Mazieri

added m_currentPaths to TrashLocation, the reason is TrashLocation::startExternalFsWatcher() can activated any time.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
175. By Carlos Jose Mazieri

added virtual destrcutor to classes:
  IORequestLoader
  DirListWorker
  TrashListWorker
  ExternalFileSystemChangesWorker
  ExternalFileSystemTrashChangesWorker

changed TrashLocation destructor to virtual

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Arto Jalkanen (ajalkane) wrote :

I did a cursory glance through the code. I only found a little comment snippet that should be clarified:

928 + // move extra data here when exist, avoid extra data than DirItemInfo

I guess that should read "extra data _other_ than DirItemInfo" ?

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

extra data means: data members defined only in inherited classes not in base class DirItemInfo.
The operator= works for the case "BaseObject = BaseObject" and "InheritedObject = BaseObject"

But data can be lost in the case "BaseObject = InheritedObject"

Perhaps I can change to:

// move inherited class data members here when exist, avoid data members outside base class DirItemInfo

Revision history for this message
Arto Jalkanen (ajalkane) wrote :

Perhaps "copy data specific to this class here, do not unnecessarily copy data that is handled by parent's assignment operator".

Anyway the exact wording doesn't matter so much, the original comment was just grammatically off enough to be a bit confusing. Move is anyway wrong word here as far as I understand, as it makes a copy assignment (ie. the original data is not lost, as would be the case in move).

176. By Carlos Jose Mazieri

improved comments in TrashItemInfo::operator=(const DirItemInfo &other), disabled code not used so far.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
177. By Carlos Jose Mazieri

fixed type error stoptExternalFsWatcher() to stopExternalFsWatcher()

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 :

revision 176 improves comments stated in https://code.launchpad.net/~carlos-mazieri/ubuntu-filemanager-app/app-devel-pre5-final/+merge/218062/comments/525128

revision 177 fixes a type error, so it is OK now.

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

I am approving this myself to get it ready to receive other changes already done.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/plugin/folderlistmodel/CMakeLists.txt'
2--- src/plugin/folderlistmodel/CMakeLists.txt 2014-05-02 10:42:48 +0000
3+++ src/plugin/folderlistmodel/CMakeLists.txt 2014-05-17 11:47:42 +0000
4@@ -43,7 +43,13 @@
5 disk/disklocation.cpp
6 disk/disklocation.h
7 trash/qtrashdir.cpp
8- trash/qtrashdir.h
9+ trash/qtrashdir.h
10+ trash/qtrashutilinfo.cpp
11+ trash/qtrashutilinfo.h
12+ trash/trashiteminfo.cpp
13+ trash/trashiteminfo.h
14+ trash/trashlocation.cpp
15+ trash/trashlocation.h
16 )
17
18 add_library(nemofolderlistmodel MODULE
19
20=== modified file 'src/plugin/folderlistmodel/dirmodel.cpp'
21--- src/plugin/folderlistmodel/dirmodel.cpp 2014-05-15 23:27:42 +0000
22+++ src/plugin/folderlistmodel/dirmodel.cpp 2014-05-17 11:47:42 +0000
23@@ -207,7 +207,6 @@
24
25
26
27-
28 QHash<int, QByteArray> DirModel::buildRoleNames() const
29 {
30 QHash<int, QByteArray> roles;
31@@ -395,6 +394,7 @@
32 return QVariant();
33 }
34
35+
36 void DirModel::setPath(const QString &pathName)
37 {
38 if (pathName.isEmpty())
39@@ -663,6 +663,12 @@
40 }
41
42
43+void DirModel::goTrash()
44+{
45+ setPath(LocationUrl::TrashRootURL);
46+}
47+
48+
49 bool DirModel::cdUp()
50 {
51 int ret = mCurLocation && mCurLocation->becomeParent();
52
53=== modified file 'src/plugin/folderlistmodel/dirmodel.h'
54--- src/plugin/folderlistmodel/dirmodel.h 2014-05-02 10:42:48 +0000
55+++ src/plugin/folderlistmodel/dirmodel.h 2014-05-17 11:47:42 +0000
56@@ -297,6 +297,11 @@
57 void goHome();
58
59 /*!
60+ * \brief goTrash() goes to logical folder trash:///
61+ */
62+ void goTrash();
63+
64+ /*!
65 * \brief cdUp() sets the parent directory as current directory
66 *
67 * It can work as a back function if there is no user input path
68
69=== modified file 'src/plugin/folderlistmodel/folderlistmodel.pri'
70--- src/plugin/folderlistmodel/folderlistmodel.pri 2014-05-02 10:42:48 +0000
71+++ src/plugin/folderlistmodel/folderlistmodel.pri 2014-05-17 11:47:42 +0000
72@@ -9,12 +9,14 @@
73 $$PWD/fmutil.cpp \
74 $$PWD/dirselection.cpp \
75 $$PWD/diriteminfo.cpp \
76- $$PWD/trash/qtrashdir.cpp \
77+ $$PWD/trash/qtrashdir.cpp \
78+ $$PWD/trash/trashiteminfo.cpp \
79 $$PWD/location.cpp \
80 $$PWD/locationsfactory.cpp \
81- $$PWD/disk/disklocation.cpp \
82+ $$PWD/disk/disklocation.cpp \
83+ $$PWD/trash/trashlocation.cpp \
84 $$PWD/locationurl.cpp \
85-
86+ $$PWD/trash/qtrashutilinfo.cpp
87
88
89 HEADERS += $$PWD/dirmodel.h \
90@@ -29,11 +31,14 @@
91 $$PWD/dirselection.h \
92 $$PWD/diritemabstractlistmodel.h \
93 $$PWD/diriteminfo.h \
94- $$PWD/trash/qtrashdir.h \
95+ $$PWD/trash/qtrashdir.h \
96+ $$PWD/trash/trashiteminfo.h \
97 $$PWD/location.h \
98 $$PWD/locationsfactory.h \
99- $$PWD/disk/disklocation.h \
100- $$PWD/locationurl.h \
101+ $$PWD/disk/disklocation.h \
102+ $$PWD/trash/trashlocation.h \
103+ $$PWD/locationurl.h \
104+ $$PWD/trash/qtrashutilinfo.h
105
106
107 INCLUDEPATH += $$PWD $$PWD/trash $$PWD/disk
108
109=== modified file 'src/plugin/folderlistmodel/iorequest.cpp'
110--- src/plugin/folderlistmodel/iorequest.cpp 2014-05-02 08:29:53 +0000
111+++ src/plugin/folderlistmodel/iorequest.cpp 2014-05-17 11:47:42 +0000
112@@ -30,7 +30,9 @@
113 */
114
115 #include "iorequest.h"
116+#include "qtrashutilinfo.h"
117 #include "diriteminfo.h"
118+#include "trashiteminfo.h"
119
120 #include <QDirIterator>
121 #include <QDebug>
122@@ -44,6 +46,11 @@
123 {
124 }
125
126+IORequest::~IORequest()
127+{
128+
129+}
130+
131 IORequest::RequestType IORequest::type() const
132 {
133 return m_type;
134@@ -59,33 +66,32 @@
135 , mFilter(filter)
136 , mIsRecursive(isRecursive)
137 {
138-
139-}
140-
141-//-----------------------------------------------------------------------------------------------
142-DirListWorker::DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive)
143- : IORequestLoader(pathName, filter, isRecursive)
144-{
145-
146-}
147-
148-
149-void DirListWorker::run()
150-{
151-#if DEBUG_MESSAGES
152- qDebug() << Q_FUNC_INFO << "Running on: " << QThread::currentThreadId();
153-#endif
154-
155- DirItemInfoList directoryContents = getContents();
156-
157- // last batch
158- emit itemsAdded(directoryContents);
159- emit workerFinished();
160+}
161+
162+IORequestLoader::IORequestLoader(const QString& trashRootDir,
163+ const QString &pathName,
164+ QDir::Filter filter,
165+ bool isRecursive)
166+ : IORequest()
167+ , mLoaderType(TrashLoader)
168+ , mPathName(pathName)
169+ , mFilter(filter)
170+ , mIsRecursive(isRecursive)
171+ , mTtrashRootDir(trashRootDir)
172+{
173+
174+}
175+
176+IORequestLoader::~IORequestLoader()
177+{
178+
179 }
180
181 DirItemInfoList IORequestLoader::getContents()
182 {
183- return getNormalContent();
184+ return mLoaderType == NormalLoader ?
185+ getNormalContent() :
186+ getTrashContent();
187 }
188
189 DirItemInfoList IORequestLoader::getNormalContent()
190@@ -123,17 +129,87 @@
191 directoryContents.erase(directoryContents.begin(), directoryContents.end());
192 }
193 }
194-
195 return directoryContents;
196 }
197
198+DirItemInfoList IORequestLoader::getTrashContent()
199+{
200+ DirItemInfoList directoryContents;
201+ QTrashUtilInfo trashInfo;
202+ QDir tmpDir = QDir(mPathName, QString(), QDir::NoSort, mFilter);
203+ bool isTopLevel = QFileInfo(mPathName).absolutePath() == mTtrashRootDir;
204+ QDirIterator it(tmpDir);
205+ while (it.hasNext())
206+ {
207+ it.next();
208+ trashInfo.setInfo(mTtrashRootDir, it.fileInfo().absoluteFilePath());
209+ if (!isTopLevel || (isTopLevel && trashInfo.existsInfoFile() && trashInfo.existsFile()) )
210+ {
211+ //TODO read the trashinfo file and set it into a display field
212+ // the display field can be a string the usally points to absoluteFilePath()
213+ // it would be used only in the DirModel::data()
214+ TrashItemInfo item(QTrashUtilInfo::filesTrashDir(mTtrashRootDir),
215+ it.fileInfo().absoluteFilePath());
216+ directoryContents.append(item);
217+ }
218+ }
219+ return directoryContents;
220+}
221+
222+
223+//-----------------------------------------------------------------------------------------------
224+DirListWorker::DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive)
225+ : IORequestLoader(pathName, filter, isRecursive)
226+{
227+
228+}
229+
230+
231+DirListWorker::DirListWorker(const QString& trashRootDir, const QString &pathName, QDir::Filter filter, const bool isRecursive)
232+ : IORequestLoader(trashRootDir, pathName, filter, isRecursive)
233+{
234+
235+}
236+
237+DirListWorker::~DirListWorker()
238+{
239+
240+}
241+
242+void DirListWorker::run()
243+{
244+#if DEBUG_MESSAGES
245+ qDebug() << Q_FUNC_INFO << "Running on: " << QThread::currentThreadId();
246+#endif
247+
248+ DirItemInfoList directoryContents = getContents();
249+
250+ // last batch
251+ emit itemsAdded(directoryContents);
252+ emit workerFinished();
253+}
254+
255+
256+
257+
258+//-------------------------------------------------------------------------------------
259+TrashListWorker::TrashListWorker(const QString& trashRoot, const QString &path, QDir::Filter filter)
260+ : DirListWorker(trashRoot, path, filter, false)
261+{
262+ mLoaderType = TrashLoader;
263+}
264+
265+TrashListWorker::~TrashListWorker()
266+{
267+
268+}
269
270 //---------------------------------------------------------------------------------------------------------
271 ExternalFileSystemChangesWorker::ExternalFileSystemChangesWorker(const DirItemInfoList &content,
272 const QString &pathName,
273 QDir::Filter filter,
274 const bool isRecursive)
275- : DirListWorker(pathName, filter, isRecursive)
276+ : IORequestLoader(pathName, filter, isRecursive)
277
278 {
279 m_type = DirListExternalFSChanges;
280@@ -145,14 +221,11 @@
281 }
282
283
284-void ExternalFileSystemChangesWorker::run()
285+ExternalFileSystemChangesWorker::~ExternalFileSystemChangesWorker()
286 {
287- DirItemInfoList directoryContents = getContents();
288- int remainingitemsCounter = compareItems(directoryContents);
289- emit finished(remainingitemsCounter);
290+
291 }
292
293-
294 int ExternalFileSystemChangesWorker::compareItems(const DirItemInfoList& contentNew)
295 {
296 int addedCounter=0;
297@@ -207,4 +280,37 @@
298 return counter;
299 }
300
301-
302+void ExternalFileSystemChangesWorker::run()
303+{
304+ DirItemInfoList directoryContents = getContents();
305+ int remainingitemsCounter = compareItems(directoryContents);
306+ emit finished(remainingitemsCounter);
307+}
308+
309+
310+//---------------------------------------------------------------------
311+ExternalFileSystemTrashChangesWorker::ExternalFileSystemTrashChangesWorker(const QStringList &pathNames,
312+ const DirItemInfoList &list,
313+ QDir::Filter filter)
314+ : ExternalFileSystemChangesWorker(list, pathNames.at(0), filter, false)
315+ , m_pathList(pathNames)
316+{
317+ mLoaderType = TrashLoader;
318+}
319+
320+ExternalFileSystemTrashChangesWorker::~ExternalFileSystemTrashChangesWorker()
321+{
322+
323+}
324+
325+void ExternalFileSystemTrashChangesWorker::run()
326+{
327+ DirItemInfoList directoryContents;
328+ for(int counter = 0; counter < m_pathList.count(); counter++)
329+ {
330+ mPathName = QTrashUtilInfo::filesTrashDir(m_pathList.at(counter));
331+ directoryContents += getContents();
332+ }
333+ int remainingitemsCounter = compareItems(directoryContents);
334+ emit finished(remainingitemsCounter);
335+}
336
337=== modified file 'src/plugin/folderlistmodel/iorequest.h'
338--- src/plugin/folderlistmodel/iorequest.h 2014-05-02 08:29:53 +0000
339+++ src/plugin/folderlistmodel/iorequest.h 2014-05-17 11:47:42 +0000
340@@ -42,6 +42,7 @@
341 Q_OBJECT
342 public:
343 explicit IORequest();
344+ virtual ~IORequest();
345
346 public:
347 enum RequestType
348@@ -75,21 +76,29 @@
349 IORequestLoader( const QString &pathName,
350 QDir::Filter filter,
351 bool isRecursive
352- );
353+ );
354+ IORequestLoader( const QString& trashRootDir,
355+ const QString &pathName,
356+ QDir::Filter filter,
357+ bool isRecursive
358+ );
359+ virtual ~IORequestLoader();
360 DirItemInfoList getContents();
361
362 signals:
363 void itemsAdded(const DirItemInfoList &files);
364
365 private:
366- DirItemInfoList getNormalContent();
367+ DirItemInfoList getNormalContent();
368+ DirItemInfoList getTrashContent();
369 DirItemInfoList add(const QString &pathName, QDir::Filter filter,
370 bool isRecursive, DirItemInfoList directoryContents);
371 protected:
372 LoaderType mLoaderType;
373 QString mPathName;
374 QDir::Filter mFilter;
375- bool mIsRecursive;
376+ bool mIsRecursive;
377+ QString mTtrashRootDir;
378 };
379
380
381@@ -99,7 +108,9 @@
382 {
383 Q_OBJECT
384 public:
385- explicit DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive);
386+ explicit DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive);
387+ explicit DirListWorker(const QString& trashRootDir, const QString &pathName, QDir::Filter filter, const bool isRecursive);
388+ virtual ~DirListWorker();
389 void run();
390 protected:
391 signals:
392@@ -108,7 +119,19 @@
393 };
394
395
396-class ExternalFileSystemChangesWorker : public DirListWorker
397+
398+
399+class TrashListWorker : public DirListWorker
400+{
401+ Q_OBJECT
402+public:
403+ explicit TrashListWorker(const QString &trashRoot, const QString& path, QDir::Filter filter);
404+ virtual ~TrashListWorker();
405+};
406+
407+
408+
409+class ExternalFileSystemChangesWorker : public IORequestLoader
410 {
411 Q_OBJECT
412 public:
413@@ -116,6 +139,7 @@
414 const QString &pathName,
415 QDir::Filter filter,
416 const bool isRecursive);
417+ virtual ~ExternalFileSystemChangesWorker();
418 void run();
419
420 protected:
421@@ -132,6 +156,19 @@
422
423
424
425+class ExternalFileSystemTrashChangesWorker : public ExternalFileSystemChangesWorker
426+{
427+ Q_OBJECT
428+
429+public:
430+ ExternalFileSystemTrashChangesWorker(const QStringList& pathNames,
431+ const DirItemInfoList& list,
432+ QDir::Filter filter);
433+ virtual ~ExternalFileSystemTrashChangesWorker();
434+ void run();
435+private:
436+ QStringList m_pathList;
437+};
438
439
440
441
442=== modified file 'src/plugin/folderlistmodel/locationsfactory.cpp'
443--- src/plugin/folderlistmodel/locationsfactory.cpp 2014-05-14 22:51:47 +0000
444+++ src/plugin/folderlistmodel/locationsfactory.cpp 2014-05-17 11:47:42 +0000
445@@ -24,7 +24,8 @@
446 #include "location.h"
447 #include "locationurl.h"
448 #include "disklocation.h"
449-
450+#include "trashlocation.h"
451+#include "trashiteminfo.h"
452
453 #include <QDir>
454 #include <QDebug>
455@@ -36,7 +37,8 @@
456 , m_curLoc(0)
457 , m_lastValidFileInfo(0)
458 {
459- m_locations.append(new DiskLocation(LocalDisk));
460+ m_locations.append(new DiskLocation(LocalDisk));
461+ m_locations.append(new TrashLocation(TrashDisk));
462 }
463
464
465
466=== modified file 'src/plugin/folderlistmodel/trash/qtrashdir.cpp'
467--- src/plugin/folderlistmodel/trash/qtrashdir.cpp 2014-02-15 15:18:24 +0000
468+++ src/plugin/folderlistmodel/trash/qtrashdir.cpp 2014-05-17 11:47:42 +0000
469@@ -20,6 +20,7 @@
470 */
471
472 #include "qtrashdir.h"
473+#include "qtrashutilinfo.h"
474
475 #include <QFileInfo>
476 #include <QDir>
477@@ -39,6 +40,7 @@
478
479 }
480
481+
482 bool QTrashDir::validate(const QString &trashDir, bool create) const
483 {
484 bool ret = false;
485@@ -49,8 +51,8 @@
486 }
487 if (checkUserDirPermissions(trashDir))
488 {
489- QString files(filesTrashDir(trashDir));
490- QString info(infoTrashDir(trashDir));
491+ QString files(QTrashUtilInfo::filesTrashDir(trashDir));
492+ QString info(QTrashUtilInfo::infoTrashDir(trashDir));
493 if ( (checkUserDirPermissions(files) || (create && createUserDir(files))) &&
494 (checkUserDirPermissions(info) || (create && createUserDir(info)))
495 )
496@@ -170,18 +172,6 @@
497 }
498
499
500-QString QTrashDir::filesTrashDir(const QString &trashDir) const
501-{
502- QString filesDir(trashDir + QDir::separator() + QLatin1String("files"));
503- return filesDir;
504-}
505-
506-
507-QString QTrashDir::infoTrashDir(const QString &trashDir) const
508-{
509- QString infoDir(trashDir + QDir::separator() + QLatin1String("info"));
510- return infoDir;
511-}
512
513
514 /*!
515@@ -333,3 +323,13 @@
516 }
517 return trashDir;
518 }
519+
520+
521+bool QTrashDir::suitableTrash(const QString &fullPathName, QTrashUtilInfo &fullInfo) const
522+{
523+ fullInfo.setInfo(suitableTrash(fullPathName), fullPathName);
524+ return fullInfo.isValid();
525+}
526+
527+
528+
529
530=== modified file 'src/plugin/folderlistmodel/trash/qtrashdir.h'
531--- src/plugin/folderlistmodel/trash/qtrashdir.h 2014-02-15 15:18:24 +0000
532+++ src/plugin/folderlistmodel/trash/qtrashdir.h 2014-05-17 11:47:42 +0000
533@@ -24,7 +24,7 @@
534
535 #include <QStringList>
536 #include <QDateTime>
537-
538+struct QTrashUtilInfo;
539
540 /*!
541 * \brief The QTrashDir class is a Qt implementation of the Trash Directories specification
542@@ -93,19 +93,8 @@
543 */
544 QString suitableTrash(const QString &fullPathName) const;
545
546- /*!
547- * \brief filesTrashDir() gets the "files" directory under Trash Dir
548- * \param trashDir
549- * \return trashDir/files
550- */
551- QString filesTrashDir(const QString& trashDir) const;
552+ bool suitableTrash(const QString &fullPathName, QTrashUtilInfo& fullInfo) const;
553
554- /*!
555- * \brief infoTrashDir() gets gets the "info" directory under Trash Dir
556- * \param trashDir
557- * \return trashDir/info
558- */
559- QString infoTrashDir(const QString& trashDir) const;
560
561 private:
562 bool validate(const QString& trashDir, bool create=false) const;
563@@ -120,7 +109,7 @@
564
565 private:
566 uint m_userId;
567- #if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests
568+#if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests
569 friend class TestDirModel;
570 #endif
571 };
572
573=== added file 'src/plugin/folderlistmodel/trash/qtrashutilinfo.cpp'
574--- src/plugin/folderlistmodel/trash/qtrashutilinfo.cpp 1970-01-01 00:00:00 +0000
575+++ src/plugin/folderlistmodel/trash/qtrashutilinfo.cpp 2014-05-17 11:47:42 +0000
576@@ -0,0 +1,153 @@
577+/**************************************************************************
578+ *
579+ * Copyright 2014 Canonical Ltd.
580+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
581+ *
582+ * This program is free software; you can redistribute it and/or modify
583+ * it under the terms of the GNU Lesser General Public License as published by
584+ * the Free Software Foundation; version 3.
585+ *
586+ * This program is distributed in the hope that it will be useful,
587+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
588+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
589+ * GNU Lesser General Public License for more details.
590+ *
591+ * You should have received a copy of the GNU Lesser General Public License
592+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
593+ *
594+ * File: qtrashutilinfo.cpp
595+ * Date: 16/03/2014
596+ */
597+
598+#include "qtrashutilinfo.h"
599+
600+#include <QDir>
601+#include <QSettings>
602+#include <QDateTime>
603+
604+QLatin1String filesDirString("files");
605+QLatin1String infoDirString("info");
606+
607+void QTrashUtilInfo::clear()
608+{
609+ trashRoot.clear();
610+ filesDir.clear();
611+ absFile.clear();
612+ infoDir.clear();
613+ absInfo.clear();
614+ valid = false;
615+}
616+
617+
618+QString QTrashUtilInfo::filesTrashDir(const QString &trashDir)
619+{
620+ QString filesDir(trashDir + QDir::separator() + filesDirString);
621+ return filesDir;
622+}
623+
624+
625+QString QTrashUtilInfo::infoTrashDir(const QString &trashDir)
626+{
627+ QString infoDir(trashDir + QDir::separator() + infoDirString);
628+ return infoDir;
629+}
630+
631+
632+void QTrashUtilInfo::setInfoFromTrashItem(const QString &absTrashItem)
633+{
634+ valid = false;
635+ QFileInfo item(absTrashItem);
636+ if (item.absolutePath().endsWith(filesDirString))
637+ {
638+ QFileInfo filesUnderRoot(item.absolutePath());
639+ QTrashUtilInfo::setInfo(filesUnderRoot.absolutePath(), absTrashItem);
640+ }
641+ else
642+ {
643+ clear();
644+ }
645+}
646+
647+
648+void QTrashUtilInfo::setInfo(const QString& trashRootDir, const QString& filename)
649+{
650+ valid = !trashRootDir.isEmpty();
651+ if (valid)
652+ {
653+ QFileInfo f(filename);
654+ trashRoot = trashRootDir;
655+ filesDir = filesTrashDir(trashRootDir);
656+ absFile = filesDir + QDir::separator() + f.fileName();
657+ infoDir = infoTrashDir(trashRootDir) ;
658+ absInfo = infoDir + QDir::separator() + f.fileName() +
659+ QLatin1String(".trashinfo");
660+ }
661+ else
662+ {
663+ clear();
664+ }
665+}
666+
667+
668+bool QTrashUtilInfo::isValid()
669+{
670+ return valid;
671+}
672+
673+
674+bool QTrashUtilInfo::existsFile()
675+{
676+ return QFileInfo(absFile).exists();
677+}
678+
679+
680+bool QTrashUtilInfo::existsInfoFile()
681+{
682+ return QFileInfo(absInfo).exists();
683+}
684+
685+
686+QString QTrashUtilInfo::getOriginalPathName()
687+{
688+ QString path;
689+ if (isValid())
690+ {
691+ QSettings inff(absInfo, QSettings::IniFormat);
692+ inff.beginGroup(QLatin1String("Trash Info"));
693+ QFileInfo f (inff.value(QLatin1String("Path")).toString());
694+ //Path contains the full pathname
695+ path = f.absoluteFilePath();
696+ }
697+ return path;
698+}
699+
700+
701+bool QTrashUtilInfo::createTrashInfoFile(const QString& orignalPathname)
702+{
703+ bool ret = isValid();
704+ if (ret)
705+ {
706+ QByteArray content("[Trash Info]\nPath=");
707+ content += orignalPathname + QLatin1Char('\n');
708+ content += "DeletionDate=";
709+ content += QDateTime::currentDateTime().toString(Qt::ISODate) + QLatin1Char('\n');
710+ QFile f(absInfo);
711+ ret = f.open(QFile::WriteOnly | QFile::Truncate) &&
712+ f.write(content) == content.size();
713+ f.close();
714+ }
715+ return ret;
716+}
717+
718+
719+
720+bool QTrashUtilInfo::removeTrashInfoFile()
721+{
722+ QFile infoFile(absInfo);
723+ bool ret = false;
724+ if (valid && infoFile.exists())
725+ {
726+ ret = infoFile.remove();
727+ }
728+ return ret;
729+}
730
731=== added file 'src/plugin/folderlistmodel/trash/qtrashutilinfo.h'
732--- src/plugin/folderlistmodel/trash/qtrashutilinfo.h 1970-01-01 00:00:00 +0000
733+++ src/plugin/folderlistmodel/trash/qtrashutilinfo.h 2014-05-17 11:47:42 +0000
734@@ -0,0 +1,82 @@
735+/**************************************************************************
736+ *
737+ * Copyright 2014 Canonical Ltd.
738+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
739+ *
740+ * This program is free software; you can redistribute it and/or modify
741+ * it under the terms of the GNU Lesser General Public License as published by
742+ * the Free Software Foundation; version 3.
743+ *
744+ * This program is distributed in the hope that it will be useful,
745+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
746+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
747+ * GNU Lesser General Public License for more details.
748+ *
749+ * You should have received a copy of the GNU Lesser General Public License
750+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
751+ *
752+ * File: qtrashutilinfo.h
753+ * Date: 16/03/2014
754+ */
755+
756+#ifndef QTRASHUTILINFO_H
757+#define QTRASHUTILINFO_H
758+
759+#include <QString>
760+
761+
762+/*!
763+ * \brief The QTrashUtilInfo struct just provides helper functions and information using a file structure like
764+ *
765+ * Trash/
766+ * files/ info/
767+ * item item.trashinfo
768+ */
769+struct QTrashUtilInfo
770+{
771+public:
772+ /*!
773+ * \brief setInfo() build the whole Trash information
774+ * \param trashRootDir the root Trash Dir usually a folder "Trash"
775+ * \param filename the item, it can be either a relative file name or a full path name
776+ */
777+ void setInfo(const QString& trashRootDir, const QString& filename);
778+
779+ /*!
780+ * \brief setInfoFromTrashItem() build the whole Trash information from the absolute path name from a trash item
781+ * \param absTrashItem the full path, something like <TrashRoot>/files/item
782+ *
783+ * The item pointed by \a absTrashItem does not need to exist
784+ */
785+ void setInfoFromTrashItem(const QString& absTrashItem);
786+ void clear();
787+ bool existsInfoFile();
788+ bool existsFile();
789+ bool isValid();
790+ QString getOriginalPathName();
791+ bool createTrashInfoFile(const QString& orignalPathname);
792+ bool removeTrashInfoFile();
793+
794+ /*!
795+ * \brief filesTrashDir() gets the "files" directory under Trash Dir
796+ * \param trashDir
797+ * \return trashDir/files
798+ */
799+ static QString filesTrashDir(const QString& trashDir);
800+
801+ /*!
802+ * \brief infoTrashDir() gets gets the "info" directory under Trash Dir
803+ * \param trashDir
804+ * \return trashDir/info
805+ */
806+ static QString infoTrashDir(const QString& trashDir);
807+
808+ QString trashRoot; // root
809+ QString filesDir; // root/files
810+ QString absFile; // root/files/item
811+ QString infoDir; // root/info
812+ QString absInfo; // root/info/item.trashinfo
813+ bool valid;
814+};
815+
816+#endif // QTRASHUTILINFO_H
817
818=== added file 'src/plugin/folderlistmodel/trash/trashiteminfo.cpp'
819--- src/plugin/folderlistmodel/trash/trashiteminfo.cpp 1970-01-01 00:00:00 +0000
820+++ src/plugin/folderlistmodel/trash/trashiteminfo.cpp 2014-05-17 11:47:42 +0000
821@@ -0,0 +1,147 @@
822+/**************************************************************************
823+ *
824+ * Copyright 2014 Canonical Ltd.
825+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
826+ *
827+ * This program is free software; you can redistribute it and/or modify
828+ * it under the terms of the GNU Lesser General Public License as published by
829+ * the Free Software Foundation; version 3.
830+ *
831+ * This program is distributed in the hope that it will be useful,
832+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
833+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
834+ * GNU Lesser General Public License for more details.
835+ *
836+ * You should have received a copy of the GNU Lesser General Public License
837+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
838+ *
839+ * File: trashiteminfo.cpp
840+ * Date: 05/03/2014
841+ */
842+
843+#include "trashiteminfo.h"
844+#include "locationurl.h"
845+
846+
847+TrashItemInfo::TrashItemInfo(const QString &urlPath)
848+ : DirItemInfo()
849+{
850+ d_ptr->_path = urlPath;
851+ d_ptr->_isLocal = true;
852+ d_ptr->_normalizedPath = urlPath;
853+ if (urlPath == LocationUrl::TrashRootURL)
854+ {
855+ setRoot();
856+ }
857+}
858+
859+
860+TrashItemInfo::TrashItemInfo(const TrashItemInfo &other)
861+ : DirItemInfo(other)
862+{
863+}
864+
865+
866+TrashItemInfo::TrashItemInfo(const QString& trashPath, const QString &urlPath)
867+ : DirItemInfo(urlPath)
868+{
869+ init(trashPath);
870+}
871+
872+
873+void TrashItemInfo::setRoot()
874+{
875+ d_ptr->_isValid = true;
876+ d_ptr->_isRoot = true;
877+ d_ptr->_isDir = true;
878+ d_ptr->_isReadable = true;
879+ d_ptr->_isExecutable = true;
880+ d_ptr->_exists = true;
881+ d_ptr->_fileName.clear();
882+}
883+
884+
885+void TrashItemInfo::init(const QString& trashPath)
886+{
887+ if (trashPath == absoluteFilePath())
888+ {
889+ d_ptr->_path = trashPath;
890+ setRoot();
891+ }
892+ else
893+ {
894+ if (!d_ptr->_path.startsWith(trashPath))
895+ {
896+ d_ptr->_isValid = false;
897+ }
898+ }
899+ QString abs(d_ptr->_path);
900+ d_ptr->_normalizedPath = abs.replace(0,trashPath.length()+1, LocationUrl::TrashRootURL);
901+}
902+
903+
904+TrashItemInfo& TrashItemInfo::operator=(const DirItemInfo &other)
905+{
906+ DirItemInfo::operator = (other);
907+ //the following code is disabled because TrashItemInfo does not define any data member
908+ //but it is kept for the case any specific data member be necessary in the future
909+ //and it is also kept to warn that doing so would cause a bug
910+#if 0
911+ const TrashItemInfo *isTrash = dynamic_cast<const TrashItemInfo*> (&other);
912+ if (isTrash)
913+ {
914+ //copy data specific to this class here,
915+ //do not unnecessarily copy data that is handled by parent's assignment operator
916+ }
917+#endif
918+ return *this;
919+}
920+
921+
922+TrashItemInfo& TrashItemInfo::operator=(const TrashItemInfo &other)
923+{
924+ DirItemInfo::operator = (other);
925+ return *this;
926+}
927+
928+
929+/*!
930+ * \brief TrashItemInfo::getTrashDir()
931+ *
932+ * Lets suppose a directory in the trash named DIR:
933+ * absFilePath() = /home/user/.local/share/Trash/files/DIR
934+ * normalizedFilePath() = trash:///DIR
935+ *
936+ * The trash dir is /home/user/.local/share/Trash/files
937+ *
938+ * \return The trash dir
939+ */
940+QString TrashItemInfo::getTrashDir() const
941+{
942+ QString trashDir;
943+ QString norm(urlPath());
944+ if ( norm.length() > LocationUrl::TrashRootURL.length()
945+ && norm.startsWith(LocationUrl::TrashRootURL)
946+ )
947+ {
948+ QStringRef trashItemRef(norm.midRef(LocationUrl::TrashRootURL.length()));
949+ QString abs(absoluteFilePath());
950+ int length = abs.lastIndexOf(trashItemRef);
951+ if (length > 0)
952+ {
953+ trashDir = abs.left(length-1);
954+ }
955+ }
956+ return trashDir;
957+}
958+
959+
960+QString TrashItemInfo::getRootTrashDir() const
961+{
962+ QString ret = getTrashDir();
963+ if (!isRoot())
964+ {
965+ ret = QFileInfo(ret).absolutePath();
966+ }
967+ return ret;
968+}
969
970=== added file 'src/plugin/folderlistmodel/trash/trashiteminfo.h'
971--- src/plugin/folderlistmodel/trash/trashiteminfo.h 1970-01-01 00:00:00 +0000
972+++ src/plugin/folderlistmodel/trash/trashiteminfo.h 2014-05-17 11:47:42 +0000
973@@ -0,0 +1,58 @@
974+/**************************************************************************
975+ *
976+ * Copyright 2014 Canonical Ltd.
977+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
978+ *
979+ * This program is free software; you can redistribute it and/or modify
980+ * it under the terms of the GNU Lesser General Public License as published by
981+ * the Free Software Foundation; version 3.
982+ *
983+ * This program is distributed in the hope that it will be useful,
984+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
985+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
986+ * GNU Lesser General Public License for more details.
987+ *
988+ * You should have received a copy of the GNU Lesser General Public License
989+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
990+ *
991+ * File: trashiteminfo.h
992+ * Date: 05/03/2014
993+ */
994+
995+#ifndef TRASHITEMINFO_H
996+#define TRASHITEMINFO_H
997+
998+#include "diriteminfo.h"
999+
1000+
1001+/*!
1002+ * \brief The TrashItemInfo class provides a QFileInfo like information for files in Trash
1003+ *
1004+ * Basically it differs from DirItemInfo in the field \a d_ptr->_normalizedPath, it must store the
1005+ * url like trash:///Item, while the field d_ptr->_path stores the current path in the file system as usual.
1006+ *
1007+ * So suppose a Item in the trash:
1008+ * \li \ref absoluteFilePath() returns like /home/user/.local/share/Trash/files/Item
1009+ * \li \ref urlPath() returns trash:///Item
1010+ * \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
1011+ *
1012+ * The constructor \ref TrashItemInfo(const QString& urlPath) is used only to store the logical root trash folder trash:///
1013+ */
1014+class TrashItemInfo : public DirItemInfo
1015+{
1016+public:
1017+ TrashItemInfo(const QString& urlPath);
1018+ TrashItemInfo(const QString& trashPath, const QString& urlPath);
1019+ TrashItemInfo(const TrashItemInfo &other);
1020+public:
1021+ virtual TrashItemInfo& operator=(const DirItemInfo &other);
1022+ virtual TrashItemInfo& operator=(const TrashItemInfo &other);
1023+public:
1024+ QString getTrashDir() const;
1025+ QString getRootTrashDir() const;
1026+private:
1027+ void setRoot();
1028+ void init(const QString& trashPath);
1029+};
1030+
1031+#endif // TRASHITEMINFO_H
1032
1033=== added file 'src/plugin/folderlistmodel/trash/trashlocation.cpp'
1034--- src/plugin/folderlistmodel/trash/trashlocation.cpp 1970-01-01 00:00:00 +0000
1035+++ src/plugin/folderlistmodel/trash/trashlocation.cpp 2014-05-17 11:47:42 +0000
1036@@ -0,0 +1,260 @@
1037+/**************************************************************************
1038+ *
1039+ * Copyright 2014 Canonical Ltd.
1040+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1041+ *
1042+ * This program is free software; you can redistribute it and/or modify
1043+ * it under the terms of the GNU Lesser General Public License as published by
1044+ * the Free Software Foundation; version 3.
1045+ *
1046+ * This program is distributed in the hope that it will be useful,
1047+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1048+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1049+ * GNU Lesser General Public License for more details.
1050+ *
1051+ * You should have received a copy of the GNU Lesser General Public License
1052+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1053+ *
1054+ * File: trashlocation.cpp
1055+ * Date: 08/03/2014
1056+ */
1057+
1058+#include "iorequest.h"
1059+#include "ioworkerthread.h"
1060+#include "trashlocation.h"
1061+#include "trashiteminfo.h"
1062+#include "qtrashutilinfo.h"
1063+#include "locationurl.h"
1064+#include "externalfswatcher.h"
1065+
1066+#include <QDebug>
1067+
1068+TrashLocation::TrashLocation(int type, QObject *parent) :
1069+ DiskLocation(type, parent)
1070+ ,QTrashDir()
1071+
1072+{
1073+}
1074+
1075+TrashLocation::~TrashLocation()
1076+{
1077+
1078+}
1079+
1080+bool TrashLocation::becomeParent()
1081+{
1082+
1083+ bool ret = false;
1084+ TrashItemInfo *trashInfo = static_cast<TrashItemInfo*> (m_info);
1085+ if (trashInfo && !trashInfo->isRoot())
1086+ {
1087+ QString trashDir = trashInfo->getTrashDir();
1088+ if (!trashDir.isEmpty())
1089+ {
1090+ TrashItemInfo *other = new TrashItemInfo(trashDir, trashInfo->absolutePath());
1091+ if (other->isValid() && other->isDir())
1092+ {
1093+ delete m_info;
1094+ m_info = other;
1095+ ret = true;
1096+ }
1097+ else
1098+ {
1099+ delete other;
1100+ }
1101+ }
1102+ }
1103+ return ret;
1104+}
1105+
1106+
1107+DirItemInfo * TrashLocation::validateUrlPath(const QString& urlPath)
1108+{
1109+ TrashItemInfo *item = 0;
1110+ QString myPath(urlPath);
1111+
1112+ //first void any relative path when is root
1113+ if (m_info && m_info->isRoot() && myPath.startsWith(QLatin1String("..")))
1114+ {
1115+ return item;
1116+ }
1117+
1118+ int firstSlash = -1;
1119+
1120+ // handle relative paths to the current
1121+ if (!myPath.startsWith(LocationUrl::TrashRootURL) && m_info)
1122+ {
1123+ QFileInfo f;
1124+ f.setFile(m_info->absoluteFilePath(), myPath);
1125+ if (f.exists() && f.isDir())
1126+ {
1127+ TrashItemInfo *trashItem = static_cast<TrashItemInfo*> (m_info);
1128+ item = new TrashItemInfo(trashItem->getTrashDir(), f.canonicalFilePath());
1129+#if DEBUG_MESSAGES
1130+ qDebug() << Q_FUNC_INFO << "cur path:" << m_info->absoluteFilePath()
1131+ << " new path:" << item->absoluteFilePath()
1132+ << "url:" << item->urlPath();
1133+#endif
1134+ }
1135+ else
1136+ {
1137+ myPath = LocationUrl::TrashRootURL + urlPath;
1138+ }
1139+ }
1140+ else
1141+ {
1142+ item = new TrashItemInfo(myPath);
1143+ if (!item->isRoot())
1144+ {
1145+ delete item;
1146+ item = 0;
1147+ }
1148+ }
1149+
1150+ //Not Relative, handle absolute path but it is not root
1151+ if (item == 0)
1152+ {
1153+ QString absTrashItem;
1154+ QString trashItemFromRoot = myPath.mid(LocationUrl::TrashRootURL.size());
1155+ foreach(const QString& trashRoot, allTrashes())
1156+ {
1157+ //this is the full path of the item, it does not mean it is a Trash top level item
1158+ //example: trash:///Dir1/Dir2/Dir3 may be in /home/user/.local/share/Trash//Dir1/Dir2/Dir3
1159+ absTrashItem = QTrashUtilInfo::filesTrashDir(trashRoot) + QDir::separator() + trashItemFromRoot;
1160+ const QFileInfo info(absTrashItem);
1161+ if (info.exists())
1162+ {
1163+ //check top level trash item
1164+ firstSlash = trashItemFromRoot.indexOf(QDir::separator());
1165+ QString toplevelDir = firstSlash != -1 ? trashItemFromRoot.left(firstSlash)
1166+ : trashItemFromRoot;
1167+
1168+ QTrashUtilInfo topLevelTrashDirInfo;
1169+ topLevelTrashDirInfo.setInfo(trashRoot, toplevelDir);
1170+#if DEBUG_MESSAGES
1171+ qDebug() << Q_FUNC_INFO
1172+ << topLevelTrashDirInfo.absFile << "exists" << topLevelTrashDirInfo.existsFile()
1173+ << topLevelTrashDirInfo.absInfo << "exists" << topLevelTrashDirInfo.existsInfoFile();
1174+#endif
1175+ //check if a .trashinfo file for toplevel dir exists
1176+ if (topLevelTrashDirInfo.existsInfoFile())
1177+ {
1178+ item = new TrashItemInfo(QTrashUtilInfo::filesTrashDir(trashRoot), absTrashItem);
1179+ break;
1180+ }
1181+ }
1182+ }
1183+ }
1184+
1185+ if (item)
1186+ {
1187+ if (!item->isValid() || !item->isContentReadable())
1188+ {
1189+ delete item;
1190+ item = 0;
1191+ }
1192+ else
1193+ {
1194+ if (firstSlash != -1)
1195+ {
1196+ // TODO get the trashinfo information and carry into the item
1197+ }
1198+ }
1199+ }
1200+ return item;
1201+}
1202+
1203+
1204+
1205+
1206+void TrashLocation::refreshInfo()
1207+{
1208+ if (m_info && !m_info->isRoot())
1209+ {
1210+ TrashItemInfo *trashItem = static_cast<TrashItemInfo*>(m_info);
1211+ TrashItemInfo *item = new TrashItemInfo(trashItem->getTrashDir(), trashItem->absoluteFilePath());
1212+ delete m_info;
1213+ m_info = item;
1214+ }
1215+}
1216+
1217+
1218+void TrashLocation::startExternalFsWatcher()
1219+{
1220+ //TODO implement a Watcher for this
1221+ //modify the existent watcher to work having a list of paths
1222+ if (m_usingExternalWatcher && m_extWatcher == 0 && isRoot())
1223+ {
1224+ m_extWatcher = new ExternalFSWatcher(this);
1225+ m_extWatcher->setIntervalToNotifyChanges(EX_FS_WATCHER_TIMER_INTERVAL);
1226+ m_extWatcher->setCurrentPaths(m_currentPaths);
1227+
1228+ connect(m_extWatcher, SIGNAL(pathModified(QString)),
1229+ this, SIGNAL(extWatcherPathChanged(QString)));
1230+ }
1231+}
1232+
1233+
1234+void TrashLocation::fetchItems(QDir::Filter dirFilter, bool recursive)
1235+{
1236+ Q_UNUSED(recursive)
1237+ if (!m_info->isRoot()) //any item under the logical trash folder
1238+ {
1239+ //sub items inside Trash do not need external watcher, they will never be updated
1240+ stopExternalFsWatcher();
1241+ TrashItemInfo *trashItem = static_cast<TrashItemInfo*> (m_info);
1242+ TrashListWorker *dlw = new TrashListWorker(trashItem->getRootTrashDir(),
1243+ trashItem->absoluteFilePath(),
1244+ dirFilter);
1245+ addTrashFetchRequest(dlw);
1246+ }
1247+ else
1248+ {
1249+ m_currentPaths = allTrashes();
1250+ startExternalFsWatcher();
1251+
1252+ //the trash a is logical folder, its content can be composed by more than one physical folder
1253+ foreach (const QString& trashRootDir, m_currentPaths)
1254+ {
1255+ TrashListWorker *dlw = new TrashListWorker(trashRootDir,
1256+ QTrashUtilInfo::filesTrashDir(trashRootDir),
1257+ dirFilter);
1258+ addTrashFetchRequest(dlw);
1259+ }
1260+ }
1261+}
1262+
1263+
1264+void TrashLocation::addTrashFetchRequest(TrashListWorker *workerObject)
1265+{
1266+ connect(workerObject, SIGNAL(itemsAdded(DirItemInfoList)),
1267+ this, SIGNAL(itemsAdded(DirItemInfoList)));
1268+ //it differs from DiskLocation
1269+ connect(workerObject, SIGNAL(workerFinished()),
1270+ this, SIGNAL(itemsFetched()));
1271+ workerThread()->addRequest(workerObject);
1272+}
1273+
1274+
1275+
1276+void TrashLocation::fetchExternalChanges(const QString& urlPath,
1277+ const DirItemInfoList& list,
1278+ QDir::Filter dirFilter)
1279+{
1280+ Q_UNUSED(urlPath);
1281+ if (m_extWatcher)
1282+ {
1283+ ExternalFileSystemTrashChangesWorker * extFsWorker =
1284+ new ExternalFileSystemTrashChangesWorker( m_extWatcher->pathsWatched(),
1285+ list,
1286+ dirFilter
1287+ );
1288+ addExternalFsWorkerRequest(extFsWorker);
1289+ }
1290+}
1291+
1292+
1293+void TrashLocation::startWorking()
1294+{
1295+ // do nothing, the startExternalFsWatcher() is called in fetchItems()
1296+}
1297
1298=== added file 'src/plugin/folderlistmodel/trash/trashlocation.h'
1299--- src/plugin/folderlistmodel/trash/trashlocation.h 1970-01-01 00:00:00 +0000
1300+++ src/plugin/folderlistmodel/trash/trashlocation.h 2014-05-17 11:47:42 +0000
1301@@ -0,0 +1,55 @@
1302+/**************************************************************************
1303+ *
1304+ * Copyright 2014 Canonical Ltd.
1305+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1306+ *
1307+ * This program is free software; you can redistribute it and/or modify
1308+ * it under the terms of the GNU Lesser General Public License as published by
1309+ * the Free Software Foundation; version 3.
1310+ *
1311+ * This program is distributed in the hope that it will be useful,
1312+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1314+ * GNU Lesser General Public License for more details.
1315+ *
1316+ * You should have received a copy of the GNU Lesser General Public License
1317+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1318+ *
1319+ * File: trashlocation.h
1320+ * Date: 08/03/2014
1321+ */
1322+
1323+#ifndef TRASHLOCATION_H
1324+#define TRASHLOCATION_H
1325+
1326+#include "disk/disklocation.h"
1327+#include "trash/qtrashdir.h"
1328+
1329+class TrashListWorker;
1330+
1331+class TrashLocation : public DiskLocation, public QTrashDir
1332+{
1333+ Q_OBJECT
1334+public:
1335+ explicit TrashLocation(int type, QObject *parent=0);
1336+ virtual ~TrashLocation();
1337+ virtual bool becomeParent();
1338+ virtual void refreshInfo();
1339+ virtual void fetchItems(QDir::Filter dirFilter, bool recursive=0);
1340+ virtual void fetchExternalChanges(const QString& urlPath,
1341+ const DirItemInfoList& list,
1342+ QDir::Filter dirFilter) ;
1343+
1344+ virtual void startWorking();
1345+ virtual void startExternalFsWatcher();
1346+
1347+ virtual DirItemInfo *validateUrlPath(const QString& urlPath);
1348+
1349+private:
1350+ void addTrashFetchRequest(TrashListWorker *workerObject);
1351+
1352+private:
1353+ QStringList m_currentPaths; //!< also used in the startExternalFsWatcher(), it can br activated any time
1354+};
1355+
1356+#endif // TRASHLOCATION_H
1357
1358=== modified file 'src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp'
1359--- src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp 2014-05-02 10:42:48 +0000
1360+++ src/plugin/test_folderlistmodel/regression/tst_folderlistmodel.cpp 2014-05-17 11:47:42 +0000
1361@@ -8,6 +8,7 @@
1362 #include "locationurl.h"
1363 #include "locationsfactory.h"
1364 #include "disklocation.h"
1365+#include "qtrashutilinfo.h"
1366
1367 #if defined(Q_OS_UNIX)
1368 #include <stdio.h>
1369@@ -147,10 +148,11 @@
1370 void modelSelectionItemsRange();
1371
1372 void trashDiretories();
1373+
1374 void locationFactory();
1375
1376-
1377 private:
1378+ bool createTempHomeTrashDir(const QString& existentDir);
1379 void initDeepDirs();
1380 void cleanDeepDirs();
1381 void initModels();
1382@@ -1415,16 +1417,114 @@
1383 QCOMPARE(ret, true);
1384 QCOMPARE(m_currentPath, m_deepDir_01->path());
1385 QCOMPARE(m_dirModel_01->rowCount(), 1);
1386+ QCOMPARE(m_receivedErrorSignal, false);
1387
1388 ret = m_dirModel_01->openPath(QLatin1String(".."));
1389 QTest::qWait(TIME_TO_REFRESH_DIR);
1390 QCOMPARE(ret, true);
1391 QCOMPARE(m_currentPath, QDir::tempPath());
1392+ QCOMPARE(m_receivedErrorSignal, false);
1393
1394 ret = m_dirModel_01->openPath(orig);
1395 QTest::qWait(TIME_TO_REFRESH_DIR);
1396 QCOMPARE(ret, true);
1397 QCOMPARE(m_currentPath, m_deepDir_01->path());
1398+ QCOMPARE(m_receivedErrorSignal, false);
1399+
1400+ // trash --------------------------------------
1401+ TempFiles files;
1402+ QCOMPARE(files.addSubDirLevel(m_deepDir_01->path()), true);
1403+
1404+ createTempHomeTrashDir(m_deepDir_01->path());
1405+
1406+ QTrashDir tempTrash;
1407+ QCOMPARE(files.addSubDirLevel(tempTrash.homeTrash()), true);
1408+ QCOMPARE(files.addSubDirLevel(QTrashUtilInfo::filesTrashDir(tempTrash.homeTrash())), true);
1409+
1410+ QString level1("Level1");
1411+ QCOMPARE(files.addSubDirLevel(level1), true);
1412+
1413+ QTrashUtilInfo trashInfo;
1414+ trashInfo.setInfo(tempTrash.homeTrash(), level1);
1415+ QCOMPARE(trashInfo.existsFile() , true);
1416+ QFile infoFile(trashInfo.absInfo);
1417+ QCOMPARE(infoFile.open(QFile::WriteOnly), true);
1418+ infoFile.close();
1419+
1420+ //check if "Level1" is valid item under trash
1421+ QCOMPARE(trashInfo.existsInfoFile() , true);
1422+
1423+ QString level2("level2");
1424+ QString level3("level3");
1425+
1426+ QCOMPARE(files.addSubDirLevel(level2), true);
1427+ QCOMPARE(files.addSubDirLevel(level3), true);
1428+
1429+ files.create(1);
1430+
1431+ // using trash:///
1432+ ret = m_dirModel_01->openPath(LocationUrl::TrashRootURL);
1433+ QTest::qWait(TIME_TO_REFRESH_DIR);
1434+ QCOMPARE(ret, true);
1435+ QCOMPARE(m_currentPath, LocationUrl::TrashRootURL);
1436+ QCOMPARE(m_receivedErrorSignal, false);
1437+
1438+ // using relative "Level1"
1439+ ret = m_dirModel_01->openPath(level1);
1440+ QTest::qWait(TIME_TO_REFRESH_DIR);
1441+ QCOMPARE(ret, true);
1442+ QCOMPARE(m_currentPath, QString(LocationUrl::TrashRootURL + level1) );
1443+ QCOMPARE(m_receivedErrorSignal, false);
1444+
1445+ //using trash:///Level1/Level2/Level3
1446+ QString deep(LocationUrl::TrashRootURL + level1 + QDir::separator() + level2 + QDir::separator() + level3);
1447+ ret = m_dirModel_01->openPath(deep);
1448+ QTest::qWait(TIME_TO_REFRESH_DIR);
1449+ QCOMPARE(ret, true);
1450+ QCOMPARE(m_receivedErrorSignal, false);
1451+
1452+ //using ../ to go up into Level2
1453+ ret = m_dirModel_01->openPath("../");
1454+ QTest::qWait(TIME_TO_REFRESH_DIR);
1455+ QCOMPARE(ret, true);
1456+ QCOMPARE(m_receivedErrorSignal, false);
1457+
1458+ //using .. to go up into Level1
1459+ ret = m_dirModel_01->openPath("..");
1460+ QTest::qWait(TIME_TO_REFRESH_DIR);
1461+ QCOMPARE(ret, true);
1462+ QCOMPARE(m_receivedErrorSignal, false);
1463+
1464+ //back to trash:///
1465+ ret = m_dirModel_01->openPath("..");
1466+ QTest::qWait(TIME_TO_REFRESH_DIR);
1467+ QCOMPARE(ret, true);
1468+ QCOMPARE(m_currentPath, LocationUrl::TrashRootURL);
1469+ QCOMPARE(m_receivedErrorSignal, false);
1470+
1471+ //now it must fail
1472+ ret = m_dirModel_01->openPath("..");
1473+ QTest::qWait(TIME_TO_REFRESH_DIR);
1474+ QCOMPARE(ret, false);
1475+ QCOMPARE(m_receivedErrorSignal, false);
1476+
1477+ ret = m_dirModel_01->openPath("file:///");
1478+ QTest::qWait(TIME_TO_REFRESH_DIR);
1479+ QCOMPARE(ret, true);
1480+ QCOMPARE(m_currentPath, QDir::rootPath());
1481+ QCOMPARE(m_receivedErrorSignal, false);
1482+
1483+ ret = m_dirModel_01->openPath("file://");
1484+ QTest::qWait(TIME_TO_REFRESH_DIR);
1485+ QCOMPARE(ret, true);
1486+ QCOMPARE(m_currentPath, QDir::rootPath());
1487+ QCOMPARE(m_receivedErrorSignal, false);
1488+
1489+ ret = m_dirModel_01->openPath("file:/");
1490+ QTest::qWait(TIME_TO_REFRESH_DIR);
1491+ QCOMPARE(ret, true);
1492+ QCOMPARE(m_currentPath, QDir::rootPath());
1493+ QCOMPARE(m_receivedErrorSignal, false);
1494 }
1495
1496
1497@@ -2314,9 +2414,9 @@
1498 QCOMPARE(trash.checkUserDirPermissions(trashDir), true);
1499
1500 //create files in Trash
1501- QCOMPARE(trash.createUserDir(trash.filesTrashDir(trashDir)), true);
1502+ QCOMPARE(trash.createUserDir(QTrashUtilInfo::filesTrashDir(trashDir)), true);
1503 //create info in Trash
1504- QCOMPARE(trash.createUserDir(trash.infoTrashDir(trashDir)), true);
1505+ QCOMPARE(trash.createUserDir(QTrashUtilInfo::infoTrashDir(trashDir)), true);
1506 //test validate Trash Dir(), now it MUST pass
1507 QCOMPARE(trash.validate(trashDir, false), true);
1508
1509@@ -2333,16 +2433,18 @@
1510 QString xdgTrash("xdg_Trash");
1511 m_deepDir_02 = new DeepDir(xdgTrash,0);
1512
1513+ if (::qgetenv("XDG_DATA_HOME").size() == 0)
1514+ {
1515+ QString myTrash(QDir::homePath() + "/.local/share/Trash");
1516+ QCOMPARE(trash.homeTrash(), myTrash);
1517+ }
1518+
1519 //test XDG Home Trash
1520 ::setenv("XDG_DATA_HOME", m_deepDir_02->path().toLatin1().constData(), true );
1521-
1522 QString xdgTrashDir(trash.homeTrash());
1523 QCOMPARE(trash.validate(xdgTrashDir, false), true);
1524 QCOMPARE(trash.homeTrash() , xdgTrashDir);
1525
1526- ::setenv("XDG_DATA_HOME", "\0", true );
1527- QCOMPARE(trash.homeTrash() , QDir::homePath() + "/.local/share/Trash");
1528-
1529 QCOMPARE(trash.getMountPoint(QDir::rootPath()), QDir::rootPath());
1530
1531 QStringList mountedPoints = trash.mountedPoints();
1532@@ -2398,12 +2500,46 @@
1533 void TestDirModel::locationFactory()
1534 {
1535 LocationsFactory factoryLocations(this);
1536- const Location *location = 0;
1537+ const Location *location = 0;
1538+
1539+ QString validTrashURL(LocationUrl::TrashRootURL);
1540
1541 //Due to current File Manager UI typing method both: "file:" and "trash:" are supported
1542 // location = factoryLocations.setNewPath("trash:");
1543 // QVERIFY(location == 0);
1544
1545+ location = factoryLocations.setNewPath("trash:/");
1546+ QVERIFY(location);
1547+ QVERIFY(location->type() == LocationsFactory::TrashDisk);
1548+ QCOMPARE(location->info()->absoluteFilePath(), validTrashURL);
1549+ QCOMPARE(location->urlPath(), validTrashURL);
1550+ QCOMPARE(location->isRoot(), true);
1551+
1552+ location = factoryLocations.setNewPath("trash://");
1553+ QVERIFY(location);
1554+ QVERIFY(location->type() == LocationsFactory::TrashDisk);
1555+ QCOMPARE(location->info()->absoluteFilePath(), validTrashURL);
1556+ QCOMPARE(location->urlPath(), validTrashURL);
1557+ QCOMPARE(location->isRoot(), true);
1558+
1559+ location = factoryLocations.setNewPath("trash:///");
1560+ QVERIFY(location);
1561+ QVERIFY(location->type() == LocationsFactory::TrashDisk);
1562+ QCOMPARE(location->info()->absoluteFilePath(), validTrashURL);
1563+ QCOMPARE(location->urlPath(), validTrashURL);
1564+ QCOMPARE(location->isRoot(), true);
1565+
1566+ location = factoryLocations.setNewPath("trash://////");
1567+ QVERIFY(location);
1568+ QVERIFY(location->type() == LocationsFactory::TrashDisk);
1569+ QCOMPARE(location->info()->absoluteFilePath(), validTrashURL);
1570+ QCOMPARE(location->urlPath(), validTrashURL);
1571+ QCOMPARE(location->isRoot(), true);
1572+
1573+ QString myDir("___myDir_must_NOT_EXIST___");
1574+ location = factoryLocations.setNewPath(QString("trash:/") + myDir);
1575+ QVERIFY(location == 0);
1576+
1577 location = factoryLocations.setNewPath("file://////");
1578 QVERIFY(location);
1579 QVERIFY(location->type() == LocationsFactory::LocalDisk);
1580@@ -2430,10 +2566,49 @@
1581 QVERIFY(location->type() == LocationsFactory::LocalDisk);
1582 QCOMPARE(location->info()->absoluteFilePath(), QLatin1String("/bin"));
1583 QCOMPARE(location->urlPath(), QLatin1String("/bin"));
1584- QCOMPARE(location->isRoot(), false);
1585+ QCOMPARE(location->isRoot(), false);
1586+
1587+ QTrashDir trash;
1588+ QString dirName("trashDirectory");
1589+ m_deepDir_01 = new DeepDir(dirName,0);
1590+
1591+ //create a Trash to have
1592+
1593+ ::setenv("XDG_DATA_HOME", m_deepDir_01->path().toLatin1().constData(), true );
1594+ QString xdgTrashDir(trash.homeTrash());
1595+ QCOMPARE(trash.validate(xdgTrashDir, true), true);
1596+ QCOMPARE(trash.homeTrash() , xdgTrashDir);
1597+
1598+ QString trash3("trash:///Dir1/Dir2/Dir3");
1599+ QString trash2("trash:///Dir1/Dir2");
1600+ QString trash1("trash:///Dir1");
1601+
1602+ QCOMPARE(QDir().mkpath(QTrashUtilInfo::filesTrashDir(xdgTrashDir) + "/Dir1/Dir2/Dir3"), true);
1603+
1604+
1605+ //create a empty .trashinfo file to validate the Trash
1606+ QFile trashinfo (QTrashUtilInfo::infoTrashDir(xdgTrashDir) + "/Dir1.trashinfo");
1607+ QCOMPARE(trashinfo.open(QFile::WriteOnly), true);
1608+ trashinfo.close();
1609+
1610+ location = factoryLocations.setNewPath(trash3);
1611+ Location * myLocation = const_cast<Location*> (location);
1612+ QCOMPARE(myLocation->becomeParent(), true);
1613+ QCOMPARE(location->urlPath(), trash2);
1614+ QCOMPARE(location->isRoot(), false);
1615+
1616+ location = factoryLocations.setNewPath(trash2);
1617+ myLocation = const_cast<Location*> (location);
1618+ QCOMPARE(myLocation->becomeParent(), true);
1619+ QCOMPARE(location->urlPath(), trash1);
1620+ QCOMPARE(location->isRoot(), false);
1621+
1622+ myLocation = const_cast<Location*> (location);
1623+ QCOMPARE(myLocation->becomeParent(), true);
1624+ QCOMPARE(location->urlPath(), LocationUrl::TrashRootURL);
1625+ QCOMPARE(location->isRoot(), true);
1626 }
1627
1628-
1629 int main(int argc, char *argv[])
1630 {
1631 QApplication app(argc, argv);
1632@@ -2489,6 +2664,21 @@
1633 return ret;
1634 }
1635
1636+
1637+bool TestDirModel::createTempHomeTrashDir(const QString& existentDir)
1638+{
1639+ QDir d(existentDir);
1640+ bool ret = false;
1641+ if (existentDir.startsWith(QDir::tempPath()) && (d.exists() || d.mkpath(existentDir)))
1642+ {
1643+ QTrashDir trash;
1644+ ::setenv("XDG_DATA_HOME", existentDir.toLatin1().constData(), true );
1645+ QString xdgTrashDir(trash.homeTrash());
1646+ ret = trash.validate(xdgTrashDir, true);
1647+ }
1648+ return ret;
1649+}
1650+
1651 #if defined(Q_OS_UNIX)
1652 /*!
1653 * \brief updateAndSetModificationTime()

Subscribers

People subscribed via source and target branches