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: 46
Merged at revision: 39
Proposed branch: lp:~carlos-mazieri/ubuntu-filemanager-app/model
Merge into: lp:ubuntu-filemanager-app/plugin
Diff against target: 2020 lines (+637/-412)
13 files modified
folderlistmodel/dirmodel.cpp (+100/-117)
folderlistmodel/dirmodel.h (+14/-15)
folderlistmodel/externalfswatcher.cpp (+114/-0)
folderlistmodel/externalfswatcher.h (+68/-0)
folderlistmodel/filesystemaction.cpp (+64/-93)
folderlistmodel/filesystemaction.h (+3/-4)
folderlistmodel/folderlistmodel.pri (+2/-0)
folderlistmodel/iorequest.cpp (+39/-30)
folderlistmodel/iorequest.h (+1/-2)
folderlistmodel/iorequestworker.cpp (+4/-44)
folderlistmodel/iorequestworker.h (+0/-3)
test_folderlistmodel/regression/regression_folderlilstmodel.pro (+2/-0)
test_folderlistmodel/regression/tst_folderlistmodel.cpp (+226/-104)
To merge this branch: bzr merge lp:~carlos-mazieri/ubuntu-filemanager-app/model
Reviewer Review Type Date Requested Status
Carlos Jose Mazieri Approve
Victor Thompson (community) Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+195968@code.launchpad.net

Commit message

The auto-refresh feature which watches for external modifications in the file system is now using QFileSystemWatcher which was extended by ExternalFSWatcher class in externalfswatcher.h

Description of the change

The auto-refresh feature which watches for external modifications in the file system is now using QFileSystemWatcher which was extended by ExternalFSWatcher class in externalfswatcher.h. The logic now is more simple.
The refresh time interval is 900 milliseconds.

The old mechanism used: comparing current path modification times, might fail when there are files modified in the same time stamp.

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
Victor Thompson (vthompson) wrote :

I tested the external modification functionality and ran the regression suite and everything looks good. If the modification time issue was a consistent failure, consider adding a unit test for this situation.

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

Victor, Thanks for testing this.

I notice "the modification time issue" sometimes running the test case watchExternalChanges() with different values for EX_FS_WATCHER_TIMER_INTERVAL which is defined in dirmodel.h

The old logic used to check current directory modification time, the problem could happen if next modification time happened in the same time stamp as the last notification, in this case there were no differecence between time stamps used to compare in order to indentify changes in the file system.

I think that QFileSystemWatcher watches directory file descriptor updates based on "select" or similar system call which must avoid this kind of problem.

Right now, related tests cases are:
    void watchExternalChanges();
    void extFsWatcherChangePathManyTimesModifyAllPathsLessLast();
    void extFsWatcherModifySamePathManyTimesWithInInterval();
    void extFsWatcherSetPathAndModifyManyTimesWithInInterval();
    void extFsWatcherChangePathManyTimesModifyManyTimes();

I can add that test case, thanks for this suggestion.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'folderlistmodel/dirmodel.cpp'
2--- folderlistmodel/dirmodel.cpp 2013-10-06 14:49:04 +0000
3+++ folderlistmodel/dirmodel.cpp 2013-11-20 14:23:19 +0000
4@@ -33,6 +33,7 @@
5 #include "iorequest.h"
6 #include "ioworkerthread.h"
7 #include "filesystemaction.h"
8+#include "externalfswatcher.h"
9
10 #ifndef DO_NOT_USE_TAG_LIB
11 #include <taglib/attachedpictureframe.h>
12@@ -58,10 +59,8 @@
13 #endif
14
15 #define IS_VALID_ROW(row) (row >=0 && row < mDirectoryContents.count())
16-#define WARN_ROW_OUT_OF_RANGE(row) qWarning() << Q_FUNC_INFO << "row" << row << "Out of bounds access"
17+#define WARN_ROW_OUT_OF_RANGE(row) qWarning() << Q_FUNC_INFO << this << "row:" << row << "Out of bounds access"
18
19-#define NO_EXT_FS_WATCHER_TIMER -1
20-#define IS_EXT_FS_WATCHER_TIMER_ACTIVE() (mExternalFSWatcherTimer != NO_EXT_FS_WATCHER_TIMER)
21 #define IS_FILE_MANAGER_IDLE() (!mAwaitingResults)
22
23
24@@ -97,10 +96,8 @@
25 , mShowHiddenFiles(false)
26 , mSortBy(SortByName)
27 , mSortOrder(SortAscending)
28- , mCompareFunction(0)
29- , mExternalFSWatcherTimer(NO_EXT_FS_WATCHER_TIMER)
30- , mEnableExternalFSWatcher(false)
31- , mLastModifiedCurrentPath(QDateTime::currentDateTime())
32+ , mCompareFunction(0)
33+ , mExtFSWatcher(0)
34 , m_fsAction(new FileSystemAction(this) )
35 {
36 mNameFilters = QStringList() << "*";
37@@ -127,6 +124,9 @@
38 connect(m_fsAction, SIGNAL(removed(QString)),
39 this, SLOT(onItemRemoved(QString)));
40
41+ connect(m_fsAction, SIGNAL(removedThenAdded(QFileInfo)),
42+ this, SLOT(onItemChangedOutSideFm(QFileInfo)));
43+
44 connect(m_fsAction, SIGNAL(error(QString,QString)),
45 this, SIGNAL(error(QString,QString)));
46
47@@ -229,7 +229,7 @@
48 role = FileNameRole + index.column();
49 #else
50 if (role < FileNameRole || role > TrackCoverRole) {
51- qWarning() << Q_FUNC_INFO << "Got an out of range role: " << role;
52+ qWarning() << Q_FUNC_INFO << this << "Got an out of range role: " << role;
53 return QVariant();
54 }
55
56@@ -304,7 +304,7 @@
57 #if !defined(REGRESSION_TEST_FOLDERLISTMODEL)
58 // this should not happen, ever
59 Q_ASSERT(false);
60- qWarning() << Q_FUNC_INFO << "Got an unknown role: " << role;
61+ qWarning() << Q_FUNC_INFO << this << "Got an unknown role: " << role;
62 #endif
63 break;
64 }
65@@ -326,29 +326,17 @@
66 if (mAwaitingResults) {
67 // TODO: handle the case where pathName != our current path, cancel old
68 // request, start a new one
69- qDebug() << Q_FUNC_INFO << "Ignoring path change request, request already running";
70+ qDebug() << Q_FUNC_INFO << this << "Ignoring path change request, request already running";
71 return;
72 }
73
74-#if DEBUG_EXT_FS_WATCHER
75- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
76- << Q_FUNC_INFO
77- << "changing current path to:" << pathName;
78-#endif
79-
80- /*
81- * if active the External File System Watcher is stopped
82- */
83- stoptExternalFsWatcher();
84-
85 mAwaitingResults = true;
86 emit awaitingResultsChanged();
87 #if DEBUG_MESSAGES
88- qDebug() << Q_FUNC_INFO << "Changing to " << pathName << " on " << QThread::currentThreadId();
89+ qDebug() << Q_FUNC_INFO << this << "Changing to " << pathName << " on " << QThread::currentThreadId();
90 #endif
91- beginResetModel();
92- mDirectoryContents.clear();
93- endResetModel();
94+
95+ clear();
96
97 DirListWorker *dlw = createWorkerRequest(IORequest::DirList, pathName);
98 connect(dlw, SIGNAL(itemsAdded(QVector<QFileInfo>)), SLOT(onItemsAdded(QVector<QFileInfo>)));
99@@ -356,14 +344,14 @@
100 ioWorkerThread()->addRequest(dlw);
101
102 mCurrentDir = pathName;
103- emit pathChanged(pathName);
104+ emit pathChanged(pathName);
105 }
106
107
108 void DirModel::onResultsFetched() {
109 if (mAwaitingResults) {
110 #if DEBUG_MESSAGES
111- qDebug() << Q_FUNC_INFO << "No longer awaiting results";
112+ qDebug() << Q_FUNC_INFO << this << "No longer awaiting results";
113 #endif
114 mAwaitingResults = false;
115 emit awaitingResultsChanged();
116@@ -373,7 +361,7 @@
117 void DirModel::onItemsAdded(const QVector<QFileInfo> &newFiles)
118 {
119 #if DEBUG_MESSAGES
120- qDebug() << Q_FUNC_INFO << "Got new files: " << newFiles.count();
121+ qDebug() << Q_FUNC_INFO << this << "Got new files: " << newFiles.count();
122 #endif
123
124 foreach (const QFileInfo &fi, newFiles) {
125@@ -403,7 +391,7 @@
126 bool DirModel::rename(int row, const QString &newName)
127 {
128 #if DEBUG_MESSAGES
129- qDebug() << Q_FUNC_INFO << "Renaming " << row << " to " << newName;
130+ qDebug() << Q_FUNC_INFO << this << "Renaming " << row << " to " << newName;
131 #endif
132
133 if (!IS_VALID_ROW(row)) {
134@@ -419,7 +407,7 @@
135 bool retval = f.rename(newFullFilename);
136 if (!retval)
137 {
138- qDebug() << Q_FUNC_INFO << "Rename returned error code: " << f.error() << f.errorString();
139+ qDebug() << Q_FUNC_INFO << this << "Rename returned error code: " << f.error() << f.errorString();
140 emit(QObject::tr("Rename error"), f.errorString());
141 }
142 else
143@@ -437,7 +425,7 @@
144 bool retval = dir.mkdir(newDir);
145 if (!retval) {
146 const char *errorStr = strerror(errno);
147- qDebug() << Q_FUNC_INFO << "Error creating new directory: " << errno << " (" << errorStr << ")";
148+ qDebug() << Q_FUNC_INFO << this << "Error creating new directory: " << errno << " (" << errorStr << ")";
149 emit error(QObject::tr("Error creating new folder"), errorStr);
150 } else {
151 onItemAdded(dir.filePath(newDir));
152@@ -514,16 +502,16 @@
153 {
154 QDir dir(mCurrentDir);
155 if (dir.isRoot()) {
156- qDebug() << Q_FUNC_INFO << "already at root";
157+ qDebug() << Q_FUNC_INFO << this << "already at root";
158 return mCurrentDir;
159 }
160
161 bool success = dir.cdUp();
162 if (!success) {
163- qWarning() << Q_FUNC_INFO << "Failed to to go to parent of " << mCurrentDir;
164+ qWarning() << Q_FUNC_INFO << this << "Failed to to go to parent of " << mCurrentDir;
165 return mCurrentDir;
166 }
167- qDebug() << Q_FUNC_INFO << "returning" << dir.absolutePath();
168+ qDebug() << Q_FUNC_INFO << this << "returning" << dir.absolutePath();
169 return dir.absolutePath();
170 }
171
172@@ -703,8 +691,11 @@
173 void DirModel::onItemRemoved(const QFileInfo &fi)
174 {
175 int row = rowOfItem(fi);
176-#if DEBUG_MESSAGES
177- qDebug() << Q_FUNC_INFO << "row" << row;
178+#if DEBUG_MESSAGES || DEBUG_EXT_FS_WATCHER
179+ qDebug() << Q_FUNC_INFO << this
180+ << "row" << row
181+ << "name" << fi.absoluteFilePath()
182+ << "removed[True|False]:" << (row >= 0);
183 #endif
184 if (row >= 0)
185 {
186@@ -750,7 +741,7 @@
187 int idx = mDirectoryContents.count();
188
189 if (it == mDirectoryContents.end()) {
190- beginInsertRows(QModelIndex(), mDirectoryContents.count(), mDirectoryContents.count());
191+ beginInsertRows(QModelIndex(), idx, idx);
192 mDirectoryContents.append(fi);
193 endInsertRows();
194 } else {
195@@ -1043,108 +1034,87 @@
196 reqThread = new ExternalFileSystemChangesWorker(mDirectoryContents,
197 pathName,
198 dirFilter, mIsRecursive);
199- }
200- connect(reqThread, SIGNAL(fetchingContents(QDateTime)),
201- this, SLOT(onFetchingContents(QDateTime)));
202+ }
203 return reqThread;
204 }
205
206
207-/*!
208- * \brief DirModel::onFetchingContents() slot that is called before any fetch directory operation
209- *
210- * It can be called in two situations:
211- * \li 1. When a user change the current directory, then new content needs be fetched
212- * in this case the timer should be inactive
213- * \li 2. When the external File System Watcher is active and was requested to get the contents
214- * in order to compare and then notify changes. In this case the timer should be already active
215- *
216- * \sa startExternalFsWatcher(), stoptExternalFsWatcher()
217- */
218-void DirModel::onFetchingContents(QDateTime lastModifiedPath)
219-{
220- mLastModifiedCurrentPath = lastModifiedPath;
221- if (mEnableExternalFSWatcher)
222- {
223- startExternalFsWatcher();
224-#if DEBUG_EXT_FS_WATCHER
225- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
226- << Q_FUNC_INFO
227- << "setting modified path" << mLastModifiedCurrentPath.toString("hh:mm:ss.zzz");
228-#endif
229- }
230-}
231-
232
233 /*!
234 * \brief DirModel::startExternalFsWatcher() starts the External File System Watcher
235 */
236 void DirModel::startExternalFsWatcher()
237 {
238- if (!IS_EXT_FS_WATCHER_TIMER_ACTIVE() && mEnableExternalFSWatcher)
239- {
240- mExternalFSWatcherTimer = startTimer(EX_FS_WATCHER_TIMER_INTERVAL);
241 #if DEBUG_EXT_FS_WATCHER
242- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
243- << Q_FUNC_INFO << "timerID" << mExternalFSWatcherTimer;
244+ qDebug() << "[extFsWorker]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
245+ << Q_FUNC_INFO << this;
246
247 #endif
248-
249+ if (!mExtFSWatcher)
250+ {
251+ mExtFSWatcher = new ExternalFSWatcher(this);
252+ mExtFSWatcher->setIntervalToNotifyChanges(EX_FS_WATCHER_TIMER_INTERVAL);
253+ connect(this, SIGNAL(pathChanged(QString)),
254+ mExtFSWatcher, SLOT(setCurrentPath(QString)));
255+
256+ connect(mExtFSWatcher, SIGNAL(pathModified()),
257+ this, SLOT(onThereAreExternalChanges()));
258+
259+ //setCurrentPath() checks for empty paths
260+ mExtFSWatcher->setCurrentPath(mCurrentDir);
261 }
262 }
263
264
265
266 /*!
267- * \brief DirModel::stoptExternalFsWatcher() stops the External File System Watcher
268+ * \brief DirModel::stoptExternalFsWatcher stops the External File System Watcher
269 */
270 void DirModel::stoptExternalFsWatcher()
271 {
272 #if DEBUG_EXT_FS_WATCHER
273- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
274- << Q_FUNC_INFO;
275+ qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
276+ << Q_FUNC_INFO << this;
277 #endif
278- if (IS_EXT_FS_WATCHER_TIMER_ACTIVE())
279+ if (mExtFSWatcher)
280 {
281- killTimer(mExternalFSWatcherTimer);
282- mExternalFSWatcherTimer = NO_EXT_FS_WATCHER_TIMER;
283+ delete mExtFSWatcher;
284+ mExtFSWatcher = 0;
285 }
286 }
287
288
289-void DirModel::timerEvent(QTimerEvent *)
290+void DirModel::onThereAreExternalChanges()
291 {
292- if ( mEnableExternalFSWatcher
293- && IS_FILE_MANAGER_IDLE()
294- && mLastModifiedCurrentPath < curPathModifiedDate() )
295+ if ( IS_FILE_MANAGER_IDLE() )
296 {
297 #if DEBUG_EXT_FS_WATCHER
298- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
299- << Q_FUNC_INFO << "File System modified";
300+ qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
301+ << Q_FUNC_INFO << this << "File System modified";
302 #endif
303 DirListWorker *w =
304 createWorkerRequest(IORequest::DirListExternalFSChanges,
305 mCurrentDir
306 );
307- ExternalFileSystemChangesWorker *fsWatcher =
308+ ExternalFileSystemChangesWorker *extFsWorker =
309 static_cast<ExternalFileSystemChangesWorker*> (w);
310
311- connect(fsWatcher, SIGNAL(added(QFileInfo)),
312+ connect(extFsWorker, SIGNAL(added(QFileInfo)),
313 this, SLOT(onItemAddedOutsideFm(QFileInfo)));
314- connect(fsWatcher, SIGNAL(removed(QFileInfo)),
315+ connect(extFsWorker, SIGNAL(removed(QFileInfo)),
316 this, SLOT(onItemRemovedOutSideFm(QFileInfo)));
317- connect(fsWatcher, SIGNAL(changed(QFileInfo)),
318+ connect(extFsWorker, SIGNAL(changed(QFileInfo)),
319 this, SLOT(onItemChangedOutSideFm(QFileInfo)));
320- connect(fsWatcher, SIGNAL(finished()),
321- this, SLOT(onExternalFsWatcherFinihed()));
322+ connect(extFsWorker, SIGNAL(finished(int)),
323+ this, SLOT(onExternalFsWorkerFinished(int)));
324
325- ioWorkerThread()->addRequest(fsWatcher);
326+ ioWorkerThread()->addRequest(extFsWorker);
327 }
328 #if DEBUG_EXT_FS_WATCHER
329 else
330 {
331- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
332- << Q_FUNC_INFO << "nothing to do";
333+ qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
334+ << Q_FUNC_INFO << this << "Busy, nothing to do";
335 }
336 #endif
337 }
338@@ -1155,18 +1125,24 @@
339 */
340 void DirModel::onItemAddedOutsideFm(const QFileInfo &fi)
341 {
342- if (mEnableExternalFSWatcher && IS_FILE_MANAGER_IDLE())
343+#if DEBUG_EXT_FS_WATCHER
344+ int before = rowCount();
345+#endif
346+ if (IS_FILE_MANAGER_IDLE())
347 {
348 int row = rowOfItem(fi);
349 if (row == -1)
350 {
351-#if DEBUG_EXT_FS_WATCHER
352- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
353- << Q_FUNC_INFO << "added" << fi.absoluteFilePath();
354-#endif
355 onItemAdded(fi);
356 }
357 }
358+#if DEBUG_EXT_FS_WATCHER
359+ qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
360+ << Q_FUNC_INFO << this
361+ << "counterBefore:" << before
362+ << "added" << fi.absoluteFilePath()
363+ << "counterAfter:" << rowCount();
364+#endif
365 }
366
367 /*!
368@@ -1178,11 +1154,11 @@
369 */
370 void DirModel::onItemRemovedOutSideFm(const QFileInfo &fi)
371 {
372- if (mEnableExternalFSWatcher && IS_FILE_MANAGER_IDLE())
373+ if (IS_FILE_MANAGER_IDLE())
374 {
375 #if DEBUG_EXT_FS_WATCHER
376- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
377- << Q_FUNC_INFO << "removed" << fi.absoluteFilePath();
378+ qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
379+ << Q_FUNC_INFO << this << "removed" << fi.absoluteFilePath();
380 #endif
381 onItemRemoved(fi);
382 }
383@@ -1195,12 +1171,12 @@
384 */
385 void DirModel::onItemChangedOutSideFm(const QFileInfo &fi)
386 {
387- if (mEnableExternalFSWatcher && IS_FILE_MANAGER_IDLE())
388+ if (IS_FILE_MANAGER_IDLE())
389 {
390 int row = rowOfItem(fi);
391 #if DEBUG_EXT_FS_WATCHER
392- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
393- << Q_FUNC_INFO << "changed" << fi.absoluteFilePath()
394+ qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
395+ << Q_FUNC_INFO << this << "changed" << fi.absoluteFilePath()
396 << "from row" << row;
397 #endif
398 if (row >= 0)
399@@ -1222,24 +1198,29 @@
400 /*!
401 * \brief DirModel::onExternalFsWatcherFinihed()
402 */
403-void DirModel::onExternalFsWatcherFinihed()
404+void DirModel::onExternalFsWorkerFinished(int currentDirCounter)
405 {
406- mLastModifiedCurrentPath = curPathModifiedDate();
407+
408 #if DEBUG_EXT_FS_WATCHER
409- qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
410- << Q_FUNC_INFO
411- << "path modfied" << mLastModifiedCurrentPath.toString("hh:mm:ss.zzz");
412+ qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
413+ << Q_FUNC_INFO << this
414+ << "currentDirCounter:" << currentDirCounter;
415+
416 #endif
417+ if (currentDirCounter == 0 && IS_FILE_MANAGER_IDLE())
418+ {
419+ clear();
420+ }
421 }
422
423
424 /*!
425- * \brief DirModel::getEnabledExternalFSWatcher()
426+ * \brief DirModel:getEnabledExternalFSWatcher()
427 * \return true if the External File System Watcher is enabled
428 */
429 bool DirModel::getEnabledExternalFSWatcher() const
430 {
431- return mEnableExternalFSWatcher;
432+ return mExtFSWatcher ? true : false;
433 }
434
435
436@@ -1249,14 +1230,9 @@
437 */
438 void DirModel::setEnabledExternalFSWatcher(bool enable)
439 {
440- mEnableExternalFSWatcher = enable;
441- if (enable)
442+ if(enable)
443 {
444- //if a directory is already and the timer is not acive, start the timer
445- if (canReadDir(mCurrentDir))
446- {
447- startExternalFsWatcher();
448- }
449+ startExternalFsWatcher();
450 }
451 else
452 {
453@@ -1396,6 +1372,13 @@
454 }
455
456
457+void DirModel::clear()
458+{
459+ beginResetModel();
460+ mDirectoryContents.clear();
461+ endResetModel();
462+}
463+
464
465 #ifndef DO_NOT_USE_TAG_LIB
466 QVariant DirModel::getAudioMetaData(const QFileInfo& fi, int role) const
467
468=== modified file 'folderlistmodel/dirmodel.h'
469--- folderlistmodel/dirmodel.h 2013-10-06 14:49:04 +0000
470+++ folderlistmodel/dirmodel.h 2013-11-20 14:23:19 +0000
471@@ -43,6 +43,7 @@
472 #include "filecompare.h"
473
474 class FileSystemAction;
475+class ExternalFSWatcher;
476
477 /*!
478 * When the External File System Wathcer is enabled,
479@@ -50,7 +51,7 @@
480 *
481 * \sa setEnabledExternalFSWatcher()
482 */
483-#define EX_FS_WATCHER_TIMER_INTERVAL 3100
484+#define EX_FS_WATCHER_TIMER_INTERVAL 900
485
486 class DirModel : public QAbstractListModel
487 {
488@@ -104,7 +105,7 @@
489 Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
490 inline QString path() const { return mCurrentDir; }
491 void setPath(const QString &pathName);
492-
493+
494 Q_INVOKABLE QDateTime curPathAccessedDate() const;
495 Q_INVOKABLE QDateTime curPathCreatedDate() const;
496 Q_INVOKABLE QDateTime curPathModifiedDate() const;
497@@ -112,7 +113,6 @@
498 Q_INVOKABLE QString curPathCreatedDateLocaleShort() const;
499 Q_INVOKABLE QString curPathModifiedDateLocaleShort() const;
500 Q_INVOKABLE bool curPathIsWritable() const;
501-
502
503 Q_PROPERTY(bool awaitingResults READ awaitingResults NOTIFY awaitingResultsChanged)
504 bool awaitingResults() const;
505@@ -373,28 +373,27 @@
506 const QString& pathName);
507 bool canReadDir(const QFileInfo& d) const;
508 bool canReadFile(const QFileInfo& f) const;
509- QFileInfo setParentIfRelative(const QString &fileOrDir) const;
510+ QFileInfo setParentIfRelative(const QString &fileOrDir) const;
511
512 private:
513 void startExternalFsWatcher();
514 void stoptExternalFsWatcher();
515+ void clear();
516 private slots:
517- void onFetchingContents(QDateTime);
518 void onItemAddedOutsideFm(const QFileInfo&fi);
519 void onItemRemovedOutSideFm(const QFileInfo&);
520 void onItemChangedOutSideFm(const QFileInfo&fi);
521- void onExternalFsWatcherFinihed();
522-protected:
523- virtual void timerEvent(QTimerEvent *);
524+ void onThereAreExternalChanges();
525+ void onExternalFsWorkerFinished(int);
526+
527
528 private:
529- bool mShowHiddenFiles;
530- SortBy mSortBy;
531- SortOrder mSortOrder;
532- CompareFunction mCompareFunction;
533- int mExternalFSWatcherTimer;
534- bool mEnableExternalFSWatcher;
535- QDateTime mLastModifiedCurrentPath;
536+ bool mShowHiddenFiles;
537+ SortBy mSortBy;
538+ SortOrder mSortOrder;
539+ CompareFunction mCompareFunction;
540+ ExternalFSWatcher* mExtFSWatcher;
541+
542
543 private:
544 FileSystemAction * m_fsAction; //!< it does file system recursive remove/copy/move
545
546=== added file 'folderlistmodel/externalfswatcher.cpp'
547--- folderlistmodel/externalfswatcher.cpp 1970-01-01 00:00:00 +0000
548+++ folderlistmodel/externalfswatcher.cpp 2013-11-20 14:23:19 +0000
549@@ -0,0 +1,114 @@
550+/**************************************************************************
551+ *
552+ * Copyright 2013 Canonical Ltd.
553+ * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com>
554+ *
555+ * This program is free software; you can redistribute it and/or modify
556+ * it under the terms of the GNU Lesser General Public License as published by
557+ * the Free Software Foundation; version 3.
558+ *
559+ * This program is distributed in the hope that it will be useful,
560+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
561+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
562+ * GNU Lesser General Public License for more details.
563+ *
564+ * You should have received a copy of the GNU Lesser General Public License
565+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
566+ *
567+ * File: externalfswatcher.cpp
568+ * Date: 9/14/2013
569+ */
570+
571+#include "externalfswatcher.h"
572+
573+#include <QTimer>
574+#include <QDateTime>
575+#include <QDebug>
576+
577+#if DEBUG_EXT_FS_WATCHER
578+# define DEBUG_FSWATCHER() \
579+ qDebug() << "[extFsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") \
580+ << Q_FUNC_INFO << "m_setPath:" << m_setPath \
581+ << "m_changedPath:" << m_changedPath \
582+ << "m_waitingEmit:" << m_waitingEmitCounter
583+#else
584+# define DEBUG_FSWATCHER() /**/
585+#endif //
586+
587+
588+ExternalFSWatcher::ExternalFSWatcher(QObject *parent) :
589+ QFileSystemWatcher(parent)
590+ , m_waitingEmitCounter(0)
591+ , m_msWaitTime(DEFAULT_NOTICATION_PERIOD)
592+{
593+ connect(this, SIGNAL(directoryChanged(QString)),
594+ this, SLOT(slotDirChanged(QString)));
595+}
596+
597+
598+void ExternalFSWatcher::setCurrentPath(const QString &curPath)
599+{
600+ if (!curPath.isEmpty())
601+ {
602+ if (m_setPath != curPath)
603+ {
604+ if (!m_setPath.isEmpty())
605+ {
606+ removePath(m_setPath);
607+ }
608+ m_setPath = curPath;
609+ addPath(m_setPath);
610+ }
611+ }
612+ DEBUG_FSWATCHER();
613+}
614+
615+
616+void ExternalFSWatcher::slotDirChanged(const QString &dir)
617+{
618+ DEBUG_FSWATCHER();
619+ if ( (m_setPath == dir)
620+ && ( m_waitingEmitCounter == 0 || m_setPath != m_changedPath )
621+ )
622+ {
623+ removePath(m_setPath);
624+ ++m_waitingEmitCounter;
625+ m_changedPath = m_setPath;
626+ QTimer::singleShot(m_msWaitTime, this, SLOT(slotFireChanges()));
627+ }
628+}
629+
630+
631+/*!
632+ * \brief ExternalFSWatcher::slotFireChanges() emits \ref pathModified() only when it is sure
633+ * that the current path was changed.
634+ *
635+ * A change for the current path (the last current) MUST be notified at least once.
636+ */
637+void ExternalFSWatcher::slotFireChanges()
638+{
639+ if (--m_waitingEmitCounter == 0)
640+ {
641+ addPath(m_setPath);
642+ if (m_setPath == m_changedPath)
643+ {
644+ emit pathModified();
645+#if DEBUG_EXT_FS_WATCHER
646+ DEBUG_FSWATCHER() << "emit pathModified()";
647+#endif
648+ }
649+ }
650+}
651+
652+
653+
654+void ExternalFSWatcher::setIntervalToNotifyChanges(int ms)
655+{
656+ m_msWaitTime = ms;
657+}
658+
659+
660+int ExternalFSWatcher::getIntervalToNotifyChanges() const
661+{
662+ return m_msWaitTime;
663+}
664
665=== added file 'folderlistmodel/externalfswatcher.h'
666--- folderlistmodel/externalfswatcher.h 1970-01-01 00:00:00 +0000
667+++ folderlistmodel/externalfswatcher.h 2013-11-20 14:23:19 +0000
668@@ -0,0 +1,68 @@
669+/**************************************************************************
670+ *
671+ * Copyright 2013 Canonical Ltd.
672+ * Copyright 2013 Carlos J Mazieri <carlos.mazieri@gmail.com>
673+ *
674+ * This program is free software; you can redistribute it and/or modify
675+ * it under the terms of the GNU Lesser General Public License as published by
676+ * the Free Software Foundation; version 3.
677+ *
678+ * This program is distributed in the hope that it will be useful,
679+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
680+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
681+ * GNU Lesser General Public License for more details.
682+ *
683+ * You should have received a copy of the GNU Lesser General Public License
684+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
685+ *
686+ * File: externalfswatcher.h
687+ * Date: 9/14/2013
688+ */
689+
690+#ifndef EXTERNALFSWATCHER_H
691+#define EXTERNALFSWATCHER_H
692+
693+#include <QFileSystemWatcher>
694+
695+#define DEFAULT_NOTICATION_PERIOD 500
696+
697+
698+/*!
699+ * \brief The ExternalFSWatcher class notifies the owner when the File System when the current path \a m_setPath has changed
700+ * emitting pathModified() signal.
701+ *
702+ * The current path \a m_setPath is set by using the slot \ref setCurrentPath()
703+ *
704+ * The idea of this class is to minimize notifications as the current path can change quickly.
705+ * A notification will occur if it was requested for a path and this path is still the current at the moment
706+ * of the notification.
707+ *
708+ * Once it detects a change it will wait \ref getIntervalToNotifyChanges() milliseconds to notify that change.
709+ * At this moment it checks if no \ref setCurrentPath() has been called during this time and then notifies that change.
710+ */
711+class ExternalFSWatcher : public QFileSystemWatcher
712+{
713+ Q_OBJECT
714+public:
715+ explicit ExternalFSWatcher(QObject *parent = 0);
716+ int getIntervalToNotifyChanges() const;
717+
718+signals:
719+ void pathModified();
720+
721+ public slots:
722+ void setCurrentPath(const QString& curPath);
723+ void setIntervalToNotifyChanges(int ms);
724+
725+private slots:
726+ void slotDirChanged(const QString&);
727+ void slotFireChanges();
728+
729+ private:
730+ QString m_setPath;
731+ QString m_changedPath;
732+ unsigned m_waitingEmitCounter;
733+ int m_msWaitTime;
734+};
735+
736+#endif // EXTERNALFSWATCHER_H
737
738=== modified file 'folderlistmodel/filesystemaction.cpp'
739--- folderlistmodel/filesystemaction.cpp 2013-10-31 23:49:07 +0000
740+++ folderlistmodel/filesystemaction.cpp 2013-11-20 14:23:19 +0000
741@@ -68,13 +68,11 @@
742
743 #define COMMON_SIZE_ITEM 120
744
745-RemoveNotifier FileSystemAction::m_removeNotifier;
746
747 static QLatin1String GNOME_COPIED_MIME_TYPE ("x-special/gnome-copied-files");
748 static QLatin1String KDE_CUT_MIME_TYPE ("application/x-kde-cutselection");
749
750
751-
752 class DirModelMimeData : public QMimeData
753 {
754 public:
755@@ -414,41 +412,6 @@
756 return paths;
757 }
758
759-/*!
760- * \brief RemoveNotifier::RemoveNotifier
761- * \param parent
762- */
763-RemoveNotifier::RemoveNotifier(QObject *parent) :
764- QObject(parent)
765-{
766-}
767-
768-//===============================================================================================
769-/*!
770- * \brief RemoveNotifier::notifyRemoved
771- * \param fi
772- */
773-void RemoveNotifier::notifyRemoved(const QFileInfo &fi)
774-{
775-#if DEBUG_MESSAGES
776- qDebug() << Q_FUNC_INFO << "emit removed(QFileInfo)" << fi.absoluteFilePath();
777-#endif
778- emit removed(fi);
779-}
780-
781-//===============================================================================================
782-/*!
783- * \brief RemoveNotifier::notifyRemoved
784- * \param item
785- */
786-void RemoveNotifier::notifyRemoved(const QString &item)
787-{
788-#if DEBUG_MESSAGES
789- qDebug() << Q_FUNC_INFO << "emit removed(QString)" << item;
790-#endif
791- emit removed(item);
792-}
793-
794
795 //===============================================================================================
796 /*!
797@@ -463,14 +426,6 @@
798 , m_mimeData ( new DirModelMimeData() )
799 , m_clipboardModifiedByOther(false)
800 {
801- //as m_removeNotifier is static it will send signals to all instances of
802- //the model
803- connect(&m_removeNotifier, SIGNAL(removed(QFileInfo)),
804- this, SIGNAL(removed(QFileInfo)));
805-
806- connect(&m_removeNotifier, SIGNAL(removed(QString)),
807- this, SIGNAL(removed(QString)));
808-
809 QClipboard *clipboard = QApplication::clipboard();
810
811 connect(clipboard, SIGNAL(dataChanged()), this, SIGNAL(clipboardChanged()));
812@@ -543,10 +498,10 @@
813 {
814 emit error(QObject::tr("File or Directory does not exist"),
815 pathname + QObject::tr(" does not exist")
816- );
817+ );
818 return;
819 }
820- ActionEntry * entry = new ActionEntry();
821+ ActionEntry * entry = new ActionEntry();
822 //this is the item being handled
823 entry->reversedOrder.append(info);
824 // verify if the destination item already exists
825@@ -563,11 +518,11 @@
826 QDirIterator it(info.absoluteFilePath(),
827 QDir::AllEntries | QDir::System |
828 QDir::NoDotAndDotDot | QDir::Hidden,
829- QDirIterator::Subdirectories);
830+ QDirIterator::Subdirectories);
831 while (it.hasNext() && !it.next().isEmpty())
832- {
833- entry->reversedOrder.prepend(it.fileInfo());
834- }
835+ {
836+ entry->reversedOrder.prepend(it.fileInfo());
837+ }
838 }
839 //set steps and total bytes considering all items in the Entry
840 int counter = entry->reversedOrder.count();
841@@ -575,7 +530,7 @@
842 int sizeSteps = 0;
843 int bufferSize = (COPY_BUFFER_SIZE * STEP_FILES);
844 while (counter--)
845- {
846+ {
847 const QFileInfo & item = entry->reversedOrder.at(counter);
848 size = (item.isFile() && !item.isDir() && !item.isSymLink()) ?
849 item.size() : COMMON_SIZE_ITEM;
850@@ -587,11 +542,11 @@
851 if ( !(size % bufferSize) )
852 {
853 --sizeSteps;
854- }
855+ }
856 action->steps += sizeSteps ;
857- }
858 }
859 }
860+ }
861 //set final steps for the Entry based on Items number
862 int entrySteps = entry->reversedOrder.count() / STEP_FILES;
863 if ( entry->reversedOrder.count() % STEP_FILES) entrySteps++;
864@@ -723,17 +678,33 @@
865 if (m_curAction->type == ActionRemove || m_curAction->type == ActionMove ||
866 m_curAction->type == ActionHardMoveRemove)
867 {
868- m_removeNotifier.notifyRemoved(mainItem); // notify all instances
869+ emit removed(mainItem);
870 }
871 if (m_curAction->type == ActionCopy || m_curAction->type == ActionMove ||
872- m_curAction->type == ActionHardMoveCopy)
873+ m_curAction->type == ActionHardMoveCopy)
874 {
875+ bool toAdd = true;
876 QString addedItem = targetFom(mainItem.absoluteFilePath(), m_curAction);
877 if (curEntry->alreadyExists)
878 {
879- m_removeNotifier.notifyRemoved(addedItem);
880- }
881- emit added(addedItem);
882+ //if an item already exists, even we remove the original item and then add
883+ //the same item again (maybe a new content),
884+ //BUT: we want to notify it as a change to NOT give a chance to External File System Watcher
885+ //to get it during the time it is (removed + added)
886+ if (m_curAction->type == ActionHardMoveCopy)
887+ {
888+ emit removed(addedItem);
889+ }
890+ else
891+ { //ActionCopy ActionMove
892+ emit removedThenAdded(QFileInfo(addedItem));
893+ toAdd = false;
894+ }
895+ }
896+ if(toAdd)
897+ {
898+ emit added(addedItem);
899+ }
900 }
901 m_curAction->currEntryIndex++;
902 //check if is doing a hard move and the copy part has finished
903@@ -1051,29 +1022,29 @@
904 void FileSystemAction::paste()
905 {
906 ClipboardOperation operation;
907- QStringList paths = m_mimeData->localUrls(operation);
908+ QStringList paths = m_mimeData->localUrls(operation);
909 #if DEBUG_MESSAGES
910 qDebug() << Q_FUNC_INFO << paths;
911 #endif
912 if (paths.count())
913- {
914+ {
915 ActionType actionType = ActionCopy; // start with Copy and check for Cut
916 if (operation == ClipboardCut)
917 {
918 //we allow Copy to backup items, but Cut must Fail
919- if (QFileInfo(m_path).absoluteFilePath() == QFileInfo(paths.at(0)).absolutePath())
920- {
921- emit error(tr("Cannot paste"),
922- tr("origin and destination folder are the same"));
923- return;
924- }
925- //so far it always returns true since on Linux it is possible to rename
926- // between different file systems
927- if ( moveUsingSameFileSystem(paths.at(0)) ) {
928- actionType = ActionMove;
929- } else {
930- actionType = ActionHardMoveCopy; // first step
931- }
932+ if (QFileInfo(m_path).absoluteFilePath() == QFileInfo(paths.at(0)).absolutePath())
933+ {
934+ emit error(tr("Cannot paste"),
935+ tr("origin and destination folder are the same"));
936+ return;
937+ }
938+ //so far it always returns true since on Linux it is possible to rename
939+ // between different file systems
940+ if ( moveUsingSameFileSystem(paths.at(0)) ) {
941+ actionType = ActionMove;
942+ } else {
943+ actionType = ActionHardMoveCopy; // first step
944+ }
945 }
946 createAndProcessAction(actionType, paths, operation);
947 }
948@@ -1096,17 +1067,17 @@
949 myAction = createAction(actionType, origPathLen);
950 myAction->operation = operation;
951 myAction->origPath = QFileInfo(paths.at(0)).absolutePath();
952- myAction->baseOrigSize = myAction->origPath.length();
953+ myAction->baseOrigSize = myAction->origPath.length();
954 for (int counter=0; counter < paths.count(); counter++)
955- {
956+ {
957 addEntry(myAction, paths.at(counter));
958 }
959 if (myAction->totalItems > 0)
960 {
961- if (actionType == ActionHardMoveCopy)
962- {
963- myAction->totalItems *= 2; //duplicate this
964- }
965+ if (actionType == ActionHardMoveCopy)
966+ {
967+ myAction->totalItems *= 2; //duplicate this
968+ }
969 /*
970 if (actionType == ActionHardMoveCopy || actionType == ActionCopy)
971 {
972@@ -1115,17 +1086,17 @@
973 myAction->steps += myAction->totalBytes / (COPY_BUFFER_SIZE * STEP_FILES);
974 }
975 */
976- if (operation == ClipboardCut)
977- {
978- //this must still be false when cut finishes to change the clipboard to the target
979- m_clipboardModifiedByOther = false;
980- }
981- m_queuedActions.append(myAction);
982- if (!m_busy)
983- {
984- processAction();
985- }
986- }
987+ if (operation == ClipboardCut)
988+ {
989+ //this must still be false when cut finishes to change the clipboard to the target
990+ m_clipboardModifiedByOther = false;
991+ }
992+ m_queuedActions.append(myAction);
993+ if (!m_busy)
994+ {
995+ processAction();
996+ }
997+}
998 else
999 { // no items were added into the Action, maybe items were removed
1000 //addEntry() emits error() signal when items do not exist
1001@@ -1144,7 +1115,7 @@
1002 * \return full pathname of target
1003 */
1004 QString FileSystemAction::targetFom(const QString& origItem, const Action* const action)
1005-{
1006+{
1007 QString destinationUnderTarget(origItem.mid(action->baseOrigSize));
1008 if (action->currEntry && action->currEntry->newName)
1009 {
1010@@ -1354,7 +1325,7 @@
1011 endActionEntry();
1012 }
1013 else
1014- {
1015+ {
1016 if (copySingleFileDone)
1017 {
1018 m_curAction->copyFile.clear();
1019
1020=== modified file 'folderlistmodel/filesystemaction.h'
1021--- folderlistmodel/filesystemaction.h 2013-08-18 12:19:36 +0000
1022+++ folderlistmodel/filesystemaction.h 2013-11-20 14:23:19 +0000
1023@@ -43,7 +43,6 @@
1024 #include <QVector>
1025
1026 class DirModelMimeData;
1027-class RemoveNotifier;
1028 class QFile;
1029 class QTemporaryFile;
1030
1031@@ -104,7 +103,7 @@
1032
1033 public slots:
1034 void cancel();
1035- void remove(const QStringList& filePaths);
1036+ void remove(const QStringList & filePaths);
1037 void pathChanged(const QString& path);
1038 void paste();
1039 void cut(const QStringList&);
1040@@ -116,6 +115,7 @@
1041 void removed(const QFileInfo&);
1042 void added(const QString& );
1043 void added(const QFileInfo& );
1044+ void removedThenAdded(const QFileInfo&);
1045 void progress(int curItem, int totalItems, int percent);
1046 void clipboardChanged();
1047
1048@@ -201,8 +201,7 @@
1049 QVector<Action*> m_queuedActions; //!< work always at item 0, after finishing taking item 0 out
1050 Action * m_curAction;
1051 bool m_cancelCurrentAction;
1052- bool m_busy;
1053- static RemoveNotifier m_removeNotifier;
1054+ bool m_busy;
1055 QString m_path;
1056 DirModelMimeData * m_mimeData;
1057 QString m_errorTitle;
1058
1059=== modified file 'folderlistmodel/folderlistmodel.pri'
1060--- folderlistmodel/folderlistmodel.pri 2013-10-31 23:49:07 +0000
1061+++ folderlistmodel/folderlistmodel.pri 2013-11-20 14:23:19 +0000
1062@@ -4,6 +4,7 @@
1063 $$PWD/ioworkerthread.cpp \
1064 $$PWD/filesystemaction.cpp \
1065 $$PWD/filecompare.cpp \
1066+ $$PWD/externalfswatcher.cpp
1067
1068
1069
1070@@ -14,6 +15,7 @@
1071 $$PWD/ioworkerthread.h \
1072 $$PWD/filesystemaction.h \
1073 $$PWD/filecompare.h \
1074+ $$PWD/externalfswatcher.h
1075
1076
1077
1078
1079=== modified file 'folderlistmodel/iorequest.cpp'
1080--- folderlistmodel/iorequest.cpp 2013-10-31 23:49:07 +0000
1081+++ folderlistmodel/iorequest.cpp 2013-11-20 14:23:19 +0000
1082@@ -75,10 +75,9 @@
1083 {
1084 #if DEBUG_EXT_FS_WATCHER
1085 qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
1086- << Q_FUNC_INFO;
1087+ << Q_FUNC_INFO;
1088 #endif
1089- QVector<QFileInfo> directoryContents;
1090- emit fetchingContents(QFileInfo(mPathName).lastModified());
1091+ QVector<QFileInfo> directoryContents;
1092 directoryContents = add(mPathName, mFilter, mIsRecursive, directoryContents);
1093 return directoryContents;
1094 }
1095@@ -132,42 +131,52 @@
1096 void ExternalFileSystemChangesWorker::run()
1097 {
1098 QVector<QFileInfo> directoryContents = getContents();
1099+ int addedCounter=0;
1100+ int removedCounter=0;
1101 #if DEBUG_EXT_FS_WATCHER
1102 qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
1103- << Q_FUNC_INFO << "checking added and changed files";
1104+ << Q_FUNC_INFO
1105+ << "m_curContent.count():" << m_curContent.count()
1106+ << "directoryContents.count():" << directoryContents.count();
1107 #endif
1108 int counter = directoryContents.count();
1109- while (counter--)
1110+ if (counter > 0)
1111 {
1112- const QFileInfo& originalItem = directoryContents.at(counter);
1113- const QFileInfo existItem = m_curContent.value(originalItem.absoluteFilePath());
1114- if ( existItem.exists() )
1115- {
1116- //it may have changed
1117- if ( originalItem.size() != existItem.size()
1118- || originalItem.lastModified() != existItem.lastModified()
1119- || originalItem.permissions() != existItem.permissions()
1120- )
1121- {
1122- emit changed(originalItem);
1123- }
1124- //remove this item
1125- m_curContent.remove(originalItem.absoluteFilePath());
1126+ while (counter--)
1127+ {
1128+ const QFileInfo& originalItem = directoryContents.at(counter);
1129+ const QFileInfo existItem = m_curContent.value(originalItem.absoluteFilePath());
1130+ if ( existItem.exists() )
1131+ {
1132+ //it may have changed
1133+ if ( originalItem.size() != existItem.size()
1134+ || originalItem.lastModified() != existItem.lastModified()
1135+ || originalItem.permissions() != existItem.permissions()
1136+ )
1137+ {
1138+ emit changed(originalItem);
1139+ }
1140+ //remove this item
1141+ m_curContent.remove(originalItem.absoluteFilePath());
1142+ }
1143+ else // originalItem was added
1144+ {
1145+ emit added(originalItem);
1146+ ++addedCounter;
1147+ }
1148 }
1149- else // originalItem was added
1150- {
1151- emit added(originalItem);
1152+
1153+ QHash<QString, QFileInfo>::iterator i = m_curContent.begin();
1154+ for ( ; i != m_curContent.end(); ++removedCounter, ++i )
1155+ {
1156+ emit removed(i.value());
1157 }
1158 }
1159 #if DEBUG_EXT_FS_WATCHER
1160 qDebug() << "[exfsWatcher]" << QDateTime::currentDateTime().toString("hh:mm:ss.zzz")
1161- << Q_FUNC_INFO << "checking for removed files";
1162+ << Q_FUNC_INFO
1163+ << "addedCounter:" << addedCounter
1164+ << "removedCounter:" << removedCounter;
1165 #endif
1166- QHash<QString, QFileInfo>::iterator i = m_curContent.begin();
1167- while ( i != m_curContent.end() )
1168- {
1169- emit removed(i.value());
1170- ++i;
1171- }
1172- emit finished();
1173+ emit finished(counter);
1174 }
1175
1176=== modified file 'folderlistmodel/iorequest.h'
1177--- folderlistmodel/iorequest.h 2013-07-06 15:13:48 +0000
1178+++ folderlistmodel/iorequest.h 2013-11-20 14:23:19 +0000
1179@@ -70,7 +70,6 @@
1180 explicit DirListWorker(const QString &pathName, QDir::Filter filter, const bool isRecursive);
1181 void run();
1182 signals:
1183- void fetchingContents(QDateTime);
1184 void itemsAdded(const QVector<QFileInfo> &files);
1185 void workerFinished();
1186
1187@@ -101,7 +100,7 @@
1188 void removed(const QFileInfo&);
1189 void changed(const QFileInfo&);
1190 void added(const QFileInfo& );
1191- void finished();
1192+ void finished(int);
1193 private:
1194 QHash<QString, QFileInfo> m_curContent; //!< using hash because the vector can be in any order
1195 };
1196
1197=== modified file 'folderlistmodel/iorequestworker.cpp'
1198--- folderlistmodel/iorequestworker.cpp 2013-07-06 14:55:25 +0000
1199+++ folderlistmodel/iorequestworker.cpp 2013-11-20 14:23:19 +0000
1200@@ -76,35 +76,11 @@
1201 if (mRequests.empty())
1202 mWaitCondition.wait(&mMutex);
1203
1204- int counter = 0;
1205- while (!mRequests.isEmpty())
1206- {
1207- /* If there are more than one thread in the queue and there is at least one
1208- * of the type Auto Refresh, do:
1209- * 1. if all threads are type Auto Refresh (leave just one) it might not happen but we check it here
1210- * 2. if there is at least one type DirList, remove all type Auto Refresh, the user might have changed
1211- * the current dir when the Auto Refresh was already in the queue
1212- */
1213- if ( (counter=mRequests.count()) > 1)
1214- {
1215- int autoRefreshCounter = 0;
1216- for(int aux=0; aux < counter; aux++)
1217- {
1218- if (mRequests.at(aux)->type() == IORequest::DirListExternalFSChanges)
1219- {
1220- autoRefreshCounter++;
1221- }
1222- }
1223- if (autoRefreshCounter)
1224- {
1225- removeAutoRefreshThread( (autoRefreshCounter == counter)
1226- ? counter -1
1227- : autoRefreshCounter
1228- );
1229- }
1230- }
1231- IORequest *request = mRequests.takeFirst();
1232+ while (!mRequests.isEmpty()) {
1233+ IORequest *request = mRequests.takeFirst();
1234+
1235 lock.unlock();
1236+
1237 request->run();
1238 request->deleteLater();
1239 lock.relock();
1240@@ -122,19 +98,3 @@
1241 mTimeToQuit = true;
1242 mWaitCondition.wakeOne();
1243 }
1244-
1245-
1246-
1247-void IORequestWorker::removeAutoRefreshThread(int toRemoveCounter)
1248-{
1249- int counter = mRequests.count();
1250- while(counter-- && toRemoveCounter)
1251- {
1252- if (mRequests.at(counter)->type() == IORequest::DirListExternalFSChanges)
1253- {
1254- --toRemoveCounter;
1255- IORequest *request = mRequests.takeAt(counter);
1256- delete request;
1257- }
1258- }
1259-}
1260
1261=== modified file 'folderlistmodel/iorequestworker.h'
1262--- folderlistmodel/iorequestworker.h 2013-06-29 20:36:26 +0000
1263+++ folderlistmodel/iorequestworker.h 2013-11-20 14:23:19 +0000
1264@@ -52,9 +52,6 @@
1265 void exit();
1266
1267 private:
1268- void removeAutoRefreshThread(int toRemoveCounter);
1269-
1270-private:
1271 QMutex mMutex;
1272 QWaitCondition mWaitCondition;
1273 QList<IORequest *> mRequests;
1274
1275=== modified file 'test_folderlistmodel/regression/regression_folderlilstmodel.pro'
1276--- test_folderlistmodel/regression/regression_folderlilstmodel.pro 2013-08-24 18:30:29 +0000
1277+++ test_folderlistmodel/regression/regression_folderlilstmodel.pro 2013-11-20 14:23:19 +0000
1278@@ -26,3 +26,5 @@
1279
1280 # DEFINES += DEBUG_REMOVE
1281
1282+#DEFINES += DEBUG_EXT_FS_WATCHER
1283+
1284
1285=== modified file 'test_folderlistmodel/regression/tst_folderlistmodel.cpp'
1286--- test_folderlistmodel/regression/tst_folderlistmodel.cpp 2013-11-02 12:21:29 +0000
1287+++ test_folderlistmodel/regression/tst_folderlistmodel.cpp 2013-11-20 14:23:19 +0000
1288@@ -1,6 +1,7 @@
1289 #include "filesystemaction.h"
1290 #include "dirmodel.h"
1291 #include "tempfiles.h"
1292+#include "externalfswatcher.h"
1293 #include <stdio.h>
1294
1295 #ifndef DO_NOT_USE_TAG_LIB
1296@@ -72,6 +73,7 @@
1297 void cancel(int index, int, int percent);
1298 void slotclipboardChanged();
1299 void slotError(QString title, QString message);
1300+ void slotExtFsWatcherPathModified() { ++m_extFSWatcherPathModifiedCounter; }
1301
1302 private Q_SLOTS:
1303 void initTestCase(); //before all tests
1304@@ -117,6 +119,10 @@
1305 void existsFileAndCanReadFile();
1306 void pathProperties();
1307 void watchExternalChanges();
1308+ void extFsWatcherChangePathManyTimesModifyAllPathsLessLast(); // no notification
1309+ void extFsWatcherModifySamePathManyTimesWithInInterval(); // just one notification
1310+ void extFsWatcherSetPathAndModifyManyTimesWithInInterval();// just one notification
1311+ void extFsWatcherChangePathManyTimesModifyManyTimes(); // many notifications
1312
1313 //define TEST_OPENFILES to test QDesktopServices::openUrl() for some files
1314 #if defined(TEST_OPENFILES)
1315@@ -167,6 +173,7 @@
1316 QFileIconProvider m_provider;
1317 QString m_currentPath;
1318 QString m_fileToRemoveInProgressSignal;
1319+ int m_extFSWatcherPathModifiedCounter;
1320
1321 };
1322
1323@@ -357,6 +364,29 @@
1324 void TestDirModel::initModels()
1325 {
1326 cleanModels();
1327+ m_dirModel_01 = new DirModel();
1328+ m_dirModel_02 = new DirModel();
1329+
1330+ connect(m_dirModel_01->m_fsAction, SIGNAL(added(QString)),
1331+ this, SLOT(slotFileAdded(QString)) );
1332+ connect(m_dirModel_01->m_fsAction, SIGNAL(removed(QString)),
1333+ this, SLOT(slotFileRemoved(QString)) );
1334+ connect(m_dirModel_01->m_fsAction, SIGNAL(added(QFileInfo)),
1335+ this, SLOT(slotFileAdded(QFileInfo)));
1336+ connect(m_dirModel_01->m_fsAction, SIGNAL(removed(QFileInfo)),
1337+ this, SLOT(slotFileRemoved(QFileInfo)));
1338+
1339+ connect(m_dirModel_02->m_fsAction, SIGNAL(added(QString)),
1340+ this, SLOT(slotFileAdded(QString)) );
1341+ connect(m_dirModel_02->m_fsAction, SIGNAL(removed(QString)),
1342+ this, SLOT(slotFileRemoved(QString)) );
1343+ connect(m_dirModel_02->m_fsAction, SIGNAL(added(QFileInfo)),
1344+ this, SLOT(slotFileAdded(QFileInfo)));
1345+ connect(m_dirModel_02->m_fsAction, SIGNAL(removed(QFileInfo)),
1346+ this, SLOT(slotFileRemoved(QFileInfo)));
1347+
1348+ m_dirModel_01->setEnabledExternalFSWatcher(true);
1349+ m_dirModel_02->setEnabledExternalFSWatcher(true);
1350 }
1351
1352
1353@@ -396,6 +426,7 @@
1354 m_receivedErrorSignal = false;
1355 m_progressNotificationsCounter = 0;
1356 m_visibleProgressMessages = false;
1357+ m_extFSWatcherPathModifiedCounter = 0;
1358 }
1359
1360
1361@@ -415,6 +446,7 @@
1362 m_fileToRemoveInProgressSignal.clear();
1363 m_progressNotificationsCounter = 0;
1364 m_visibleProgressMessages = false;
1365+ m_extFSWatcherPathModifiedCounter = 0;
1366 }
1367
1368
1369@@ -504,7 +536,6 @@
1370 m_deepDir_01 = new DeepDir("modelRemoveRecursiveDirByIndex", level);
1371 QCOMPARE( QFileInfo(m_deepDir_01->path()).exists(), true);
1372
1373- m_dirModel_01 = new DirModel();
1374 m_dirModel_01->setPath(m_deepDir_01->path());
1375 QTest::qWait(TIME_TO_REFRESH_DIR);
1376
1377@@ -535,7 +566,6 @@
1378 files.create(1);
1379 items.append(files.lastPath());
1380
1381- m_dirModel_01 = new DirModel();
1382 connect(m_dirModel_01, SIGNAL(progress(int,int,int)),
1383 this, SLOT(progress(int,int,int)));
1384 m_dirModel_01->setPath(m_deepDir_01->path());
1385@@ -563,7 +593,6 @@
1386 files.create(4);
1387 QCOMPARE(files.howManyExist(), filesToCreate);
1388
1389- m_dirModel_01 = new DirModel();
1390 m_dirModel_01->setPath(files.lastPath());
1391 QTest::qWait(TIME_TO_REFRESH_DIR);
1392
1393@@ -583,8 +612,7 @@
1394 {
1395 QString orig("modelCopyDirToAnotherModel_orig");
1396
1397- m_deepDir_01 = new DeepDir(orig, 1);
1398- m_dirModel_01 = new DirModel();
1399+ m_deepDir_01 = new DeepDir(orig, 1);
1400 m_dirModel_01->setPath(m_deepDir_01->path());
1401 connect(m_dirModel_01, SIGNAL(clipboardChanged()),
1402 this, SLOT(slotclipboardChanged()));
1403@@ -593,7 +621,6 @@
1404
1405 QString target("modelCopyDirToAnotherModel_target");
1406 m_deepDir_02 = new DeepDir(target, 0);
1407- m_dirModel_02 = new DirModel();
1408 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1409 this, SLOT(progress(int,int,int)));
1410 m_dirModel_02->setPath(m_deepDir_02->path());
1411@@ -621,8 +648,7 @@
1412 {
1413 QString orig("modelCopyManyItemstoAnotherModel_orig");
1414
1415- m_deepDir_01 = new DeepDir(orig, 5);
1416- m_dirModel_01 = new DirModel();
1417+ m_deepDir_01 = new DeepDir(orig, 5);
1418 connect(m_dirModel_01, SIGNAL(clipboardChanged()),
1419 this, SLOT(slotclipboardChanged()));
1420 const int filesCreated = 10;
1421@@ -650,8 +676,7 @@
1422 QCOMPARE(m_dirModel_01->rowCount(), itemsCreated);
1423
1424 QString target("modelCopyManyItemstoAnotherModel_target");
1425- m_deepDir_02 = new DeepDir(target, 0);
1426- m_dirModel_02 = new DirModel();
1427+ m_deepDir_02 = new DeepDir(target, 0);
1428 m_dirModel_02->setPath(m_deepDir_02->path());
1429 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1430 this, SLOT(progress(int,int,int)));
1431@@ -690,15 +715,12 @@
1432 empty.addSubDirLevel(orig);
1433 empty.touch(itemsCreated);
1434
1435-
1436- m_dirModel_01 = new DirModel();
1437 m_dirModel_01->setPath(m_deepDir_01->path());
1438 QTest::qWait(TIME_TO_REFRESH_DIR);
1439 QCOMPARE(m_dirModel_01->rowCount(), itemsCreated);
1440
1441 QString target("modelCopyTwoEmptyFiles_target");
1442 m_deepDir_02 = new DeepDir(target, 0);
1443- m_dirModel_02 = new DirModel();
1444 m_dirModel_02->setPath(m_deepDir_02->path());
1445 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1446 this, SLOT(progress(int,int,int)));
1447@@ -730,14 +752,12 @@
1448 tempFile.addSubDirLevel(orig);
1449 tempFile.create();
1450
1451- m_dirModel_01 = new DirModel();
1452 m_dirModel_01->setPath(m_deepDir_01->path());
1453 QTest::qWait(TIME_TO_REFRESH_DIR);
1454 QCOMPARE(m_dirModel_01->rowCount(), 1);
1455
1456 QString target("modelCopyFileAndRemoveBeforePaste_target");
1457- m_deepDir_02 = new DeepDir(target, 0);
1458- m_dirModel_02 = new DirModel();
1459+ m_deepDir_02 = new DeepDir(target, 0);
1460 m_dirModel_02->setPath(m_deepDir_02->path());
1461 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1462 this, SLOT(progress(int,int,int)));
1463@@ -769,14 +789,12 @@
1464 tempFile.addSubDirLevel(orig);
1465 tempFile.create();
1466
1467- m_dirModel_01 = new DirModel();
1468 m_dirModel_01->setPath(m_deepDir_01->path());
1469 QTest::qWait(TIME_TO_REFRESH_DIR);
1470 QCOMPARE(m_dirModel_01->rowCount(), 1);
1471
1472 QString target("modelCopyPasteFileAndRemoveWhenFirstProgressSignalArrives_target");
1473 m_deepDir_02 = new DeepDir(target, 0);
1474- m_dirModel_02 = new DirModel();
1475 m_dirModel_02->setPath(m_deepDir_02->path());
1476 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1477 this, SLOT(slotRemoveFileWhenProgressArrive(int,int,int)));
1478@@ -800,8 +818,7 @@
1479 {
1480 QString orig("modelCutManyItemsPasteIntoAnotherModel_orig");
1481
1482- m_deepDir_01 = new DeepDir(orig, 5);
1483- m_dirModel_01 = new DirModel();
1484+ m_deepDir_01 = new DeepDir(orig, 5);
1485 connect(m_dirModel_01, SIGNAL(clipboardChanged()),
1486 this, SLOT(slotclipboardChanged()));
1487 const int filesCreated = 10;
1488@@ -815,8 +832,7 @@
1489 QCOMPARE(m_dirModel_01->rowCount(), itemsCreated);
1490
1491 QString target("modelCutManyItemsPasteIntoAnotherModel_target");
1492- m_deepDir_02 = new DeepDir(target, 0);
1493- m_dirModel_02 = new DirModel();
1494+ m_deepDir_02 = new DeepDir(target, 0);
1495 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1496 this, SLOT(progress(int,int,int)));
1497 connect(m_dirModel_02, SIGNAL(error(QString,QString)),
1498@@ -832,7 +848,7 @@
1499
1500 m_dirModel_01->cutPaths(allFiles);
1501 m_visibleProgressMessages = true;
1502- m_dirModel_02->paste();
1503+ m_dirModel_02->paste();
1504 int steps = m_dirModel_02->getProgressCounter();
1505 QTest::qWait(TIME_TO_PROCESS);
1506
1507@@ -847,7 +863,7 @@
1508 QString orig("fsActionMoveItemsForcingCopyAndThenRemove_orig");
1509
1510 m_deepDir_01 = new DeepDir(orig, 1);
1511- m_dirModel_01 = new DirModel();
1512+
1513 const int filesCreated = 4;
1514 const int itemsCreated = filesCreated +1;
1515
1516@@ -860,12 +876,10 @@
1517
1518 QString target("fsActionMoveItemsForcingCopyAndThenRemove_target");
1519 m_deepDir_02 = new DeepDir(target, 0);
1520- m_dirModel_02 = new DirModel();
1521+
1522 m_dirModel_02->setPath(m_deepDir_02->path());
1523 QTest::qWait(TIME_TO_REFRESH_DIR);
1524
1525- connect(m_dirModel_02->m_fsAction, SIGNAL(added(QString)),
1526- this, SLOT(slotFileAdded(QString)));
1527 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1528 this, SLOT(progress(int,int,int)));
1529
1530@@ -894,7 +908,6 @@
1531 m_deepDir_01 = new DeepDir("modelCancelRemoveAction", level);
1532 QCOMPARE( QFileInfo(m_deepDir_01->path()).exists(), true);
1533
1534- m_dirModel_01 = new DirModel();
1535 m_dirModel_01->setPath(m_deepDir_01->path());
1536 QTest::qWait(TIME_TO_REFRESH_DIR);
1537
1538@@ -915,9 +928,7 @@
1539 }
1540
1541 void TestDirModel::modelTestFileSize()
1542-{
1543- m_dirModel_01 = new DirModel();
1544-
1545+{
1546 QCOMPARE(m_dirModel_01->fileSize(0), QString("0 Bytes"));
1547 QCOMPARE(m_dirModel_01->fileSize(1023), QString("1023 Bytes"));
1548 QCOMPARE(m_dirModel_01->fileSize(1024), QString("1.0 kB"));
1549@@ -935,7 +946,6 @@
1550 m_deepDir_01 = new DeepDir("modelRemoveDirWithHiddenFilesAndLinks", level);
1551 QCOMPARE( QFileInfo(m_deepDir_01->path()).exists(), true);
1552
1553- m_dirModel_01 = new DirModel();
1554 m_dirModel_01->setShowHiddenFiles(true);
1555 m_dirModel_01->setPath(m_deepDir_01->path());
1556 QTest::qWait(TIME_TO_REFRESH_DIR);
1557@@ -995,14 +1005,13 @@
1558 }
1559 big.close();
1560
1561- m_dirModel_01 = new DirModel();
1562 m_dirModel_01->setPath(m_deepDir_01->path());
1563 QTest::qWait(TIME_TO_REFRESH_DIR);
1564 QCOMPARE(m_dirModel_01->rowCount(), 1);
1565
1566 QString target("modelCancelCopyAction_target");
1567 m_deepDir_02 = new DeepDir(target, 0);
1568- m_dirModel_02 = new DirModel();
1569+
1570 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1571 this, SLOT(progress(int,int,int)));
1572 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1573@@ -1034,7 +1043,6 @@
1574 QVERIFY(files.count() > 0);
1575 QCOMPARE(createLink(files.at(0).absoluteFilePath(), QLatin1String("link_to_file")), true);
1576
1577- m_dirModel_01 = new DirModel();
1578 m_dirModel_01->setPath(m_deepDir_01->path());
1579 QTest::qWait(TIME_TO_REFRESH_DIR);
1580 QCOMPARE(m_dirModel_01->rowCount(), 2);
1581@@ -1042,7 +1050,6 @@
1582
1583 QString target("modelCopyFileAndDirectoryLinks_target");
1584 m_deepDir_02 = new DeepDir(target, 0);
1585- m_dirModel_02 = new DirModel();
1586 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1587 this, SLOT(progress(int,int,int)));
1588
1589@@ -1085,7 +1092,6 @@
1590 info_before[counter] = QFileInfo(created_files.at(counter));
1591 }
1592
1593- m_dirModel_01 = new DirModel();
1594 m_dirModel_01->setPath(files.lastPath());
1595 connect(m_dirModel_01, SIGNAL(error(QString,QString)),
1596 this, SLOT(slotError(QString,QString)));
1597@@ -1125,7 +1131,6 @@
1598 QStringList created_files(files.createdList());
1599 QCOMPARE(created_files.count(), files_to_create);
1600
1601- m_dirModel_01 = new DirModel();
1602 m_dirModel_01->setPath(files.lastPath());
1603
1604 QTest::qWait(TIME_TO_REFRESH_DIR);
1605@@ -1133,7 +1138,6 @@
1606 created_files.append(m_deepDir_01->firstLevel());
1607
1608 m_dirModel_01->copyPaths(created_files);
1609- m_dirModel_02 = new DirModel();
1610 connect(m_dirModel_02, SIGNAL(error(QString,QString)),
1611 this, SLOT(slotError(QString,QString)));
1612
1613@@ -1174,7 +1178,6 @@
1614 DeepDir t2(target2,0);
1615 DeepDir t3(target3,0);
1616
1617- m_dirModel_01 = new DirModel();
1618 m_dirModel_01->setPath(m_deepDir_01->path());
1619 QTest::qWait(TIME_TO_REFRESH_DIR);
1620 QCOMPARE(items.count(), m_dirModel_01->rowCount());
1621@@ -1229,10 +1232,9 @@
1622 DeepDir t2(target2,0);
1623 DeepDir t3(target3,0);
1624
1625- m_dirModel_01 = new DirModel();
1626 m_dirModel_01->setPath(m_deepDir_01->path());
1627 QTest::qWait(TIME_TO_REFRESH_DIR);
1628- QCOMPARE(items.count(), m_dirModel_01->rowCount());
1629+ QCOMPARE(items.count(), m_dirModel_01->rowCount());
1630 m_dirModel_01->cutPaths(items);
1631
1632 DirModel model1;
1633@@ -1266,7 +1268,6 @@
1634 {
1635 QString orig("modelCopyPasteAndPasteAgain_orig");
1636 m_deepDir_01 = new DeepDir(orig, 1);
1637- m_dirModel_01 = new DirModel();
1638 connect(m_dirModel_01, SIGNAL(error(QString,QString)),
1639 this, SLOT(slotError(QString,QString)));
1640
1641@@ -1277,25 +1278,10 @@
1642
1643 QString target("modelCopyPasteAndPasteAgain_target");
1644 m_deepDir_02 = new DeepDir(target, 0);
1645- m_dirModel_02 = new DirModel();
1646 connect(m_dirModel_02, SIGNAL(error(QString,QString)),
1647 this, SLOT(slotError(QString,QString)));
1648
1649- m_dirModel_02->setPath(m_deepDir_02->path());
1650- connect(m_dirModel_02->m_fsAction, SIGNAL(added(QFileInfo)),
1651- this, SLOT(slotFileAdded(QFileInfo)));
1652- connect(m_dirModel_02->m_fsAction, SIGNAL(added(QString)),
1653- this, SLOT(slotFileAdded(QString)));
1654-
1655-#if 0 /* it is not necessary to connect this signal because it is already handled
1656- * by fsAction member, since the RemoveNotifier is static, the signal is emitted to
1657- * fsAction even it is not being used here
1658- */
1659- connect(m_dirModel_02->m_fsAction, SIGNAL(removed(QFileInfo)),
1660- this, SLOT(slotFileRemoved(QFileInfo)));
1661- connect(m_dirModel_02->m_fsAction, SIGNAL(removed(QString)),
1662- this, SLOT(slotFileRemoved(QString)));
1663-#endif
1664+ m_dirModel_02->setPath(m_deepDir_02->path());
1665 QTest::qWait(TIME_TO_REFRESH_DIR);
1666 QCOMPARE(m_dirModel_02->rowCount(), 0);
1667
1668@@ -1313,9 +1299,10 @@
1669
1670 QCOMPARE(compareDirectories(m_deepDir_01->path(), m_deepDir_02->path()), true);
1671 QCOMPARE(m_receivedErrorSignal, false);
1672- //same item was removed from view and added again
1673- QCOMPARE(m_filesRemoved.count(), 1);
1674- QCOMPARE(m_filesAdded.count(), 2);
1675+
1676+ //when items already exist, changed signal is emitted
1677+ QCOMPARE(m_filesRemoved.count(), 0);
1678+ QCOMPARE(m_filesAdded.count(), 1);
1679 }
1680
1681
1682@@ -1327,20 +1314,20 @@
1683 TempFiles tempFiles_01;
1684 TempFiles tempDir_01;
1685
1686- const int createCounter = 8;
1687+ const int createCounterTopLevel = 8;
1688+ const int createCounterSubLevel = 2;
1689
1690 tempFiles_01.addSubDirLevel(orig);
1691- tempFiles_01.create(createCounter - 1);
1692+ tempFiles_01.create(createCounterTopLevel);
1693 tempDir_01.addSubDirLevel(orig);
1694 tempDir_01.addSubDirLevel(moreOneLevel);
1695 tempDir_01.create(2);
1696
1697- m_dirModel_01 = new DirModel();
1698 connect(m_dirModel_01, SIGNAL(error(QString,QString)),
1699 this, SLOT(slotError(QString,QString)));
1700 m_dirModel_01->setPath(tempFiles_01.lastPath());
1701 QTest::qWait(TIME_TO_REFRESH_DIR);
1702- QCOMPARE(m_dirModel_01->rowCount(), createCounter);
1703+ QCOMPARE(m_dirModel_01->rowCount(), createCounterTopLevel+1); //those created top level plus the subfolder
1704
1705 QString target("modelCutPasteIntoExistentItems_target");
1706 m_deepDir_02 = new DeepDir(target, 0);
1707@@ -1348,25 +1335,21 @@
1708 TempFiles tempDir_02;
1709
1710 tempFiles_02.addSubDirLevel(target);
1711- tempFiles_02.create(createCounter -1);
1712+ tempFiles_02.create(createCounterTopLevel);
1713 tempDir_02.addSubDirLevel(target);
1714 tempDir_02.addSubDirLevel(moreOneLevel);
1715- tempDir_02.create(2);
1716- m_dirModel_02 = new DirModel();
1717+ tempDir_02.create(createCounterSubLevel);
1718+
1719 connect(m_dirModel_02, SIGNAL(error(QString,QString)),
1720 this, SLOT(slotError(QString,QString)));
1721 connect(m_dirModel_02, SIGNAL(progress(int,int,int)),
1722 this, SLOT(progress(int,int,int)));
1723 m_dirModel_02->setPath(tempFiles_02.lastPath());
1724 QTest::qWait(TIME_TO_REFRESH_DIR);
1725- QCOMPARE(m_dirModel_02->rowCount(), createCounter);
1726-
1727- connect(m_dirModel_02->m_fsAction, SIGNAL(added(QFileInfo)),
1728- this, SLOT(slotFileAdded(QFileInfo)));
1729- connect(m_dirModel_02->m_fsAction, SIGNAL(added(QString)),
1730- this, SLOT(slotFileAdded(QString)));
1731-
1732- //both directories have the same content
1733+
1734+ QCOMPARE(m_dirModel_02->rowCount(), createCounterTopLevel+1); //those created top level plus the subfolder
1735+
1736+ //both directories have the same content
1737 QCOMPARE(compareDirectories(tempFiles_01.lastPath(), tempFiles_02.lastPath()), true);
1738
1739 //cut from first Model
1740@@ -1378,10 +1361,10 @@
1741 QTest::qWait(TIME_TO_PROCESS *2);
1742
1743 QCOMPARE(m_receivedErrorSignal, false);
1744- // same item removed from model_01 (cut) and from model_02 because it already exists there
1745- // for temp directory removed() signal is also emitted, so there is one more
1746- QCOMPARE(m_filesRemoved.count(), createCounter *2 + 1);
1747- QCOMPARE(m_filesAdded.count(), createCounter );
1748+
1749+ QCOMPARE(m_filesRemoved.count(), createCounterTopLevel + createCounterSubLevel);
1750+ //when items being copied from COPY or renamed from CUT already exist, they are not added
1751+ QCOMPARE(m_filesAdded.count(), 0 );
1752 }
1753
1754
1755@@ -1389,7 +1372,7 @@
1756 {
1757 QString orig("openPathAbsouluteAndRelative");
1758 m_deepDir_01 = new DeepDir(orig, 1);
1759- m_dirModel_01 = new DirModel();
1760+
1761 connect(m_dirModel_01, SIGNAL(error(QString,QString)),
1762 this, SLOT(slotError(QString,QString)));
1763
1764@@ -1425,7 +1408,6 @@
1765 {
1766 QString orig("existsDirAnCanReadDir");
1767 m_deepDir_01 = new DeepDir(orig, 1);
1768- m_dirModel_01 = new DirModel();
1769
1770 connect(m_dirModel_01, SIGNAL(error(QString,QString)),
1771 this, SLOT(slotError(QString,QString)));
1772@@ -1471,7 +1453,7 @@
1773 {
1774 QString orig("existsFileAndCanReadFile");
1775 m_deepDir_01 = new DeepDir(orig, 1);
1776- m_dirModel_01 = new DirModel();
1777+
1778 m_dirModel_01->setPath(m_deepDir_01->path());
1779 QTest::qWait(TIME_TO_REFRESH_DIR);
1780
1781@@ -1528,7 +1510,6 @@
1782 temp.addSubDirLevel(orig);
1783 temp.create(1);
1784
1785- m_dirModel_01 = new DirModel();
1786 m_dirModel_01->setPath(m_deepDir_01->path());
1787 QTest::qWait(TIME_TO_REFRESH_DIR);
1788
1789@@ -1575,31 +1556,37 @@
1790 DirModel thirdFM;
1791 thirdFM.setPath(tempUnderFirstLevel.lastPath());
1792
1793- m_dirModel_01 = new DirModel();
1794+
1795+ connect(m_dirModel_01, SIGNAL(error(QString,QString)),
1796+ this, SLOT(slotError(QString,QString)));
1797 m_dirModel_01->setPath(m_deepDir_01->path());
1798- m_dirModel_01->setEnabledExternalFSWatcher(true);
1799-
1800- m_dirModel_02 = new DirModel();
1801+
1802+ QTest::qWait(TIME_TO_REFRESH_DIR);
1803+
1804+ connect(m_dirModel_02, SIGNAL(error(QString,QString)),
1805+ this, SLOT(slotError(QString,QString)));
1806 m_dirModel_02->setPath(m_deepDir_01->path());
1807- m_dirModel_02->setEnabledExternalFSWatcher(true);
1808
1809- QTest::qWait(TIME_TO_REFRESH_DIR+30);
1810+ QTest::qWait(TIME_TO_REFRESH_DIR);
1811
1812 QCOMPARE(thirdFM.rowCount(), cut_items);
1813 QCOMPARE(m_dirModel_01->rowCount(), 1);
1814 QCOMPARE(m_dirModel_02->rowCount(), 1);
1815
1816- //modification loop
1817- int pieceTime = EX_FS_WATCHER_TIMER_INTERVAL/cut_items;
1818- int odd = 0;
1819+ qDebug() << "dirModelObjs:" << m_dirModel_01 << m_dirModel_02 << &thirdFM;
1820+
1821 QString createdOutsideName;
1822 TempFiles createdOutsideFiles;
1823 createdOutsideFiles.addSubDirLevel(orig);
1824 int total_removed = 0;
1825+ int odd=0;
1826+
1827+ thirdFM.setEnabledExternalFSWatcher(true);
1828+
1829 for ( int counter = 0; counter < cut_items; ++counter )
1830 {
1831 thirdFM.cutIndex(0);
1832- if ( (odd ^= 1))
1833+ if ( (odd^=1) )
1834 {
1835 m_dirModel_01->paste();
1836 }
1837@@ -1609,24 +1596,26 @@
1838 }
1839 QTest::qWait(TIME_TO_PROCESS);
1840 //at least one file is removed
1841- if (m_dirModel_01->rowCount() > 1 &&
1842+ if (m_dirModel_02->rowCount() > 1 &&
1843 (!total_removed || (QDateTime::currentDateTime().time().msec() % 100) == 0))
1844 {
1845 //using index 1 because 0 is a directory and the items are being moved up
1846- m_dirModel_01->removeIndex(1);
1847+ m_dirModel_02->removeIndex(1);
1848+ QTest::qWait(TIME_TO_PROCESS);
1849 ++total_removed;
1850- }
1851- QTest::qWait(pieceTime + TIME_TO_PROCESS);
1852+ }
1853 createdOutsideName.sprintf("created_%d", counter);
1854 createdOutsideFiles.create(createdOutsideName);
1855 }
1856-
1857 int total_created = 1 + cut_items + createdOutsideFiles.created() - total_removed;
1858- QTest::qWait(EX_FS_WATCHER_TIMER_INTERVAL + TIME_TO_PROCESS + TIME_TO_PROCESS);
1859+ QTest::qWait(EX_FS_WATCHER_TIMER_INTERVAL * 2);
1860+ qWarning("using 2 instances [cut_items]=%d [created outside]=%d, [removed outside]=%d", cut_items, createdOutsideFiles.created(), total_removed);
1861
1862- qWarning("using 2 instances [created outside]=%d, [removed outside]=%d", createdOutsideFiles.created(), total_removed);
1863 QCOMPARE(m_dirModel_01->rowCount(), total_created);
1864- QCOMPARE(m_dirModel_02->rowCount(), total_created);
1865+ if (m_dirModel_02->getEnabledExternalFSWatcher())
1866+ {
1867+ QCOMPARE(m_dirModel_02->rowCount(), total_created);
1868+ }
1869 }
1870
1871
1872@@ -1752,7 +1741,6 @@
1873 sound_44100_mp3_data_len);
1874 QCOMPARE(mp3File.isEmpty(), false);
1875
1876- m_dirModel_01 = new DirModel();
1877 m_dirModel_01->setReadsMediaMetadata(true);
1878 QFileInfo fi(mp3File);
1879
1880@@ -1836,6 +1824,140 @@
1881 #endif
1882
1883
1884+/*!
1885+ * \brief TestDirModel::extFsWatcherChangePathManyTimesModifyAllPathsLessLast() expects no Notification
1886+ *
1887+ * As the current path changes in a small interval of the time and the last path set
1888+ * is not modified, the signal pathModified() MUST NOT be fired.
1889+ */
1890+void TestDirModel::extFsWatcherChangePathManyTimesModifyAllPathsLessLast()
1891+{
1892+ ExternalFSWatcher watcher;
1893+ connect(&watcher, SIGNAL(pathModified()),
1894+ this, SLOT(slotExtFsWatcherPathModified()));
1895+
1896+ const int items = 150;
1897+ QVector<DeepDir *> deepDirs;
1898+ deepDirs.reserve(items);
1899+
1900+ for (int counter=1; counter <= items ; ++counter)
1901+ {
1902+ QString dirName(QString("extModifyAllLessLast") + QString::number(counter));
1903+ DeepDir *d = new DeepDir(dirName,0);
1904+ QTest::qWait(1);
1905+ watcher.setCurrentPath(d->path());
1906+ if (counter < items) // last dir does not receive a file
1907+ {
1908+ TempFiles file;
1909+ file.addSubDirLevel(dirName);
1910+ file.create();
1911+ QTest::qWait(1);
1912+ }
1913+ deepDirs.append(d);
1914+ }
1915+ QTest::qWait(TIME_TO_PROCESS);
1916+ qDeleteAll(deepDirs);
1917+
1918+ QCOMPARE(m_extFSWatcherPathModifiedCounter, 0);
1919+}
1920+
1921+
1922+/*!
1923+ * \brief TestDirModel::extFsWatcherChangePathManyTimesModifyManyTimes
1924+ *
1925+ * Change path many times, force one notification at each path
1926+ */
1927+void TestDirModel::extFsWatcherChangePathManyTimesModifyManyTimes()
1928+{
1929+ ExternalFSWatcher watcher;
1930+ connect(&watcher, SIGNAL(pathModified()),
1931+ this, SLOT(slotExtFsWatcherPathModified()));
1932+
1933+ const int items = 50;
1934+ QVector<DeepDir *> deepDirs;
1935+ deepDirs.reserve(items);
1936+
1937+ for (int counter=0; counter < items ; ++counter)
1938+ {
1939+ QString dirName(QString("extFsWatcherChangePathManyTimesModifyManyTimes")
1940+ + QString::number(counter));
1941+ DeepDir *d = new DeepDir(dirName,0);
1942+ watcher.setCurrentPath(d->path());
1943+ TempFiles file;
1944+ file.addSubDirLevel(dirName);
1945+ file.create(20);
1946+ QTest::qWait(watcher.getIntervalToNotifyChanges() + 20);
1947+ deepDirs.append(d);
1948+ }
1949+ QTest::qWait(TIME_TO_PROCESS);
1950+ qDeleteAll(deepDirs);
1951+
1952+ QCOMPARE(m_extFSWatcherPathModifiedCounter, items);
1953+}
1954+
1955+/*!
1956+ * \brief TestDirModel::extFsWatcherModifySamePathManyTimesWithInInterval() expects just one Notification
1957+ *
1958+ * A path is modified many times in a small time interval than ExternalFSWatcher class notifies changes,
1959+ * so only one Notification is expected.
1960+ */
1961+void TestDirModel::extFsWatcherModifySamePathManyTimesWithInInterval()
1962+{
1963+ ExternalFSWatcher watcher;
1964+ connect(&watcher, SIGNAL(pathModified()),
1965+ this, SLOT(slotExtFsWatcherPathModified()));
1966+
1967+ QString dirName("extFsWatcher_expects_just_one_signal");
1968+ m_deepDir_01 = new DeepDir(dirName,0);
1969+ watcher.setCurrentPath(m_deepDir_01->path());
1970+ int loop = 10;
1971+ int waitTime = watcher.getIntervalToNotifyChanges() / loop - 10;
1972+ while (loop--)
1973+ {
1974+ TempFiles file;
1975+ file.addSubDirLevel(dirName);
1976+ file.create(QString("file_") + QString::number(loop), 1);
1977+ QTest::qWait(waitTime);
1978+ }
1979+
1980+ QTest::qWait(TIME_TO_PROCESS);
1981+ QCOMPARE(m_extFSWatcherPathModifiedCounter, 1 );
1982+}
1983+
1984+
1985+/*!
1986+ * \brief TestDirModel::extFsWatcherSetPathAndModifyManyTimesWithInInterval() expects just one Notification
1987+ */
1988+void TestDirModel::extFsWatcherSetPathAndModifyManyTimesWithInInterval()
1989+{
1990+ ExternalFSWatcher watcher;
1991+ connect(&watcher, SIGNAL(pathModified()),
1992+ this, SLOT(slotExtFsWatcherPathModified()));
1993+
1994+ QList<DeepDir *> deepDirs;
1995+
1996+ int loop = 5;
1997+ int waitTime = watcher.getIntervalToNotifyChanges() / loop - 5;
1998+
1999+ for (int counter=1; counter <= loop ; ++counter)
2000+ {
2001+ QString dirName(QString("extModifyAll") + QString::number(counter));
2002+ DeepDir *d = new DeepDir(dirName,0);
2003+ watcher.setCurrentPath(d->path());
2004+ TempFiles file;
2005+ file.addSubDirLevel(dirName);
2006+ file.create();
2007+ QTest::qWait(waitTime);
2008+ deepDirs.append(d);
2009+ }
2010+ QTest::qWait(TIME_TO_PROCESS);
2011+ qDeleteAll(deepDirs);
2012+
2013+ QCOMPARE(m_extFSWatcherPathModifiedCounter, 1);
2014+}
2015+
2016+
2017+
2018 int main(int argc, char *argv[])
2019 {
2020 QApplication app(argc, argv);

Subscribers

People subscribed via source and target branches