Merge lp:~carlos-mazieri/ubuntu-filemanager-app/model into lp:ubuntu-filemanager-app/plugin
- model
- Merge into plugin
Status: | Superseded |
---|---|
Proposed branch: | lp:~carlos-mazieri/ubuntu-filemanager-app/model |
Merge into: | lp:ubuntu-filemanager-app/plugin |
Diff against target: |
946 lines (+358/-193) 4 files modified
folderlistmodel/diriteminfo.h (+78/-0) folderlistmodel/filesystemaction.cpp (+250/-167) folderlistmodel/filesystemaction.h (+28/-25) test_folderlistmodel/regression/tst_folderlistmodel.cpp (+2/-1) |
To merge this branch: | bzr merge lp:~carlos-mazieri/ubuntu-filemanager-app/model |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
David Planella | Needs Fixing | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+215783@code.launchpad.net |
Commit message
preparation for Trash move/restore operations
Description of the change
Actions which represent user copy/cut operations used to copy/move items into a unique target directory. Restore from Trash requires that items can be moved into different directories in a unique Action.So, some information were moved from Action data structure to ActionEntry data structure which represents single items bening handled inside an Action.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
David Planella (dpm) wrote : | # |
Thanks Carlos. Now that the branch that includes the plugin code in the source tree has landed in trunk, would you mind resubmitting this MP against trunk? I think you can simply edit the merge proposal and change the target branch. If not, submitting a new MP would also work.
Carlos Jose Mazieri (carlos-mazieri) wrote : | # |
OK, I will do.
If I just change the target branch do I need to specify where it goes
into (like the sub-folder) ?
On 4/15/14, David Planella <email address hidden> wrote:
> Review: Needs Fixing
>
> Thanks Carlos. Now that the branch that includes the plugin code in the
> source tree has landed in trunk, would you mind resubmitting this MP against
> trunk? I think you can simply edit the merge proposal and change the target
> branch. If not, submitting a new MP would also work.
> --
> https:/
> You are the owner of lp:~carlos-mazieri/ubuntu-filemanager-app/model.
>
David Planella (dpm) wrote : | # |
On Tue, Apr 15, 2014 at 6:51 PM, Carlos Jose Mazieri <
<email address hidden>> wrote:
> OK, I will do.
>
> If I just change the target branch do I need to specify where it goes
> into (like the sub-folder) ?
>
>
Thanks Carlos! You'll just need to specify this as the target branch:
~ubuntu-
Cheers,
David.
- 65. By Carlos Jose Mazieri
-
added moveToTrash, removeFromTrash, restoreFromTrash and emptyTrash facilities.
Test View remade to use selection. - 66. By Carlos Jose Mazieri
-
remade C++ UI
Unmerged revisions
- 66. By Carlos Jose Mazieri
-
remade C++ UI
- 65. By Carlos Jose Mazieri
-
added moveToTrash, removeFromTrash, restoreFromTrash and emptyTrash facilities.
Test View remade to use selection. - 64. By Carlos Jose Mazieri
-
Preparation for Move/Restore to/from Trash and Undo Actions:
* Some information from Action data structure were moved into ActionEntry data structure.
* Actions used to have "targetPath" saying all items (ActionEntry items) were copied/moved into a unique path.
Now having ActionEntry more indenpendent allows to move/copy items to different paths inside an Action.
This is required for Restore items from Trash.
Preview Diff
1 | === modified file 'folderlistmodel/diriteminfo.h' |
2 | --- folderlistmodel/diriteminfo.h 2014-03-23 13:38:08 +0000 |
3 | +++ folderlistmodel/diriteminfo.h 2014-04-15 00:42:01 +0000 |
4 | @@ -162,4 +162,82 @@ |
5 | |
6 | |
7 | |
8 | +/*! |
9 | + * \brief The ActionPaths struct contains helper functions to do simple path handling |
10 | + * |
11 | + * Paths stored here are supposed to NOT be relative. |
12 | + * |
13 | + * It does not use any QFileInfo methods, so it may work for any URL type |
14 | + */ |
15 | +struct ActionPaths |
16 | +{ |
17 | + public: |
18 | + ActionPaths() {} |
19 | + ActionPaths(const QString& source) |
20 | + { |
21 | + setSource(source); |
22 | + } |
23 | + inline void setSource(const QString& source) |
24 | + { |
25 | + _source = source; |
26 | + int pathLen = _source.lastIndexOf(QDir::separator()); |
27 | + if (pathLen != -1) |
28 | + { |
29 | + _sFile = QStringRef(&_source, pathLen + 1, _source.size() - pathLen - 1); |
30 | + _origPath = QStringRef(&_source, 0, pathLen); |
31 | + } |
32 | + else |
33 | + { //avoid bad index |
34 | + pathLen = 0; |
35 | + } |
36 | + } |
37 | + inline void setTargetPathOnly(const QString& path) |
38 | + { |
39 | + _targetPath = path; |
40 | + _target = path + QDir::separator(); |
41 | + _target += _sFile; |
42 | + } |
43 | + inline void setTargetFullName(const QString& fullPathname) |
44 | + { |
45 | + _target = fullPathname; |
46 | + int lastSeparator = _target.lastIndexOf(QDir::separator()); |
47 | + if (lastSeparator > 0) |
48 | + { |
49 | + _targetPath = _target.mid(0, lastSeparator); |
50 | + } |
51 | + } |
52 | + inline ActionPaths& operator=(const ActionPaths& other) |
53 | + { |
54 | + setSource(other._source); |
55 | + setTargetFullName(other._target); |
56 | + return *this; |
57 | + } |
58 | + inline bool areEquals() const {return _source == _target;} |
59 | + inline bool arePathsEquals() const |
60 | + { |
61 | + return QStringRef::compare(_origPath, _targetPath) == 0; |
62 | + } |
63 | + inline const QString& source() const {return _source;} |
64 | + inline const QString& target() const {return _target;} |
65 | + inline const QString& targetPath()const {return _targetPath;} |
66 | + inline const QStringRef& file() const {return _sFile;} |
67 | + inline int baseOrigSize() const {return _origPath.size();} |
68 | + inline void toggle() |
69 | + { |
70 | + QString savedSource(_source); |
71 | + setSource(_target); |
72 | + setTargetFullName(savedSource); |
73 | + } |
74 | + private: |
75 | + QString _source; //!< source full pathname |
76 | + QString _target; //!< target full pathname |
77 | + QString _targetPath; //!< target path only |
78 | + QStringRef _sFile; //!< source file name only |
79 | + QStringRef _origPath; //!< source path only |
80 | +}; |
81 | + |
82 | +Q_DECLARE_METATYPE(ActionPaths) |
83 | + |
84 | +typedef QList<ActionPaths> ActionPathList; |
85 | + |
86 | #endif // DIRITEMINFO_H |
87 | |
88 | === modified file 'folderlistmodel/filesystemaction.cpp' |
89 | --- folderlistmodel/filesystemaction.cpp 2014-02-05 15:31:44 +0000 |
90 | +++ folderlistmodel/filesystemaction.cpp 2014-04-15 00:42:01 +0000 |
91 | @@ -70,7 +70,73 @@ |
92 | #define COMMON_SIZE_ITEM 120 |
93 | |
94 | |
95 | - |
96 | +FileSystemAction::Action::Action() |
97 | + : auxAction(0), isAux(false), canUndo(true) |
98 | +{ |
99 | + reset(); |
100 | +} |
101 | + |
102 | +FileSystemAction::Action::~Action() |
103 | +{ |
104 | + qDeleteAll(entries); |
105 | + entries.clear(); |
106 | + copyFile.clear(); |
107 | +} |
108 | + |
109 | +/*! |
110 | + * \brief FileSystemAction::Action::reset() Used for Undo operations |
111 | + */ |
112 | +void FileSystemAction::Action::reset() |
113 | +{ |
114 | + totalItems = 0; |
115 | + currItem = 0; |
116 | + currEntryIndex = 0; |
117 | + totalBytes = 0; |
118 | + bytesWritten = 0; |
119 | + done = false; |
120 | + isAux = false; |
121 | + currEntry = 0; |
122 | + steps = 1; |
123 | + copyFile.clear(); |
124 | + if (auxAction) |
125 | + { |
126 | + delete auxAction; |
127 | + auxAction = 0; |
128 | + } |
129 | +} |
130 | + |
131 | +FileSystemAction::ActionEntry::ActionEntry(): newName(0) |
132 | +{ |
133 | + init(); |
134 | +} |
135 | + |
136 | +FileSystemAction::ActionEntry::~ActionEntry() |
137 | +{ |
138 | + reversedOrder.clear(); |
139 | + if (newName) { delete newName; } |
140 | +} |
141 | + |
142 | +void FileSystemAction::ActionEntry::init() |
143 | +{ |
144 | + currItem = 0 ; |
145 | + currStep = 0; |
146 | + added = false; |
147 | + alreadyExists = false; |
148 | + if (newName) |
149 | + { |
150 | + delete newName; |
151 | + newName = 0; |
152 | + } |
153 | +} |
154 | + |
155 | +/*! |
156 | + * \brief FileSystemAction::Action::reset() Used for Undo operations |
157 | + */ |
158 | +void FileSystemAction::ActionEntry::reset() |
159 | +{ |
160 | + init(); |
161 | + reversedOrder.clear(); |
162 | +} |
163 | |
164 | void FileSystemAction::CopyFile::clear() |
165 | { |
166 | @@ -94,6 +160,9 @@ |
167 | , m_cancelCurrentAction(false) |
168 | , m_busy(false) |
169 | , m_clipboardChanged(false) |
170 | +#if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests |
171 | + , m_forceUsingOtherFS(false) |
172 | +#endif |
173 | { |
174 | |
175 | } |
176 | @@ -124,23 +193,10 @@ |
177 | * \param origBase |
178 | * \return |
179 | */ |
180 | -FileSystemAction::Action* FileSystemAction::createAction(ActionType type, int origBase) |
181 | +FileSystemAction::Action* FileSystemAction::createAction(ActionType type) |
182 | { |
183 | Action * action = new Action(); |
184 | - action->type = type; |
185 | - action->baseOrigSize = origBase; |
186 | - action->targetPath = m_path; |
187 | - action->totalItems = 0; |
188 | - action->currItem = 0; |
189 | - action->currEntryIndex = 0; |
190 | - action->totalBytes = 0; |
191 | - action->bytesWritten = 0; |
192 | - action->done = false; |
193 | - action->auxAction = 0; |
194 | - action->isAux = false; |
195 | - action->currEntry = 0; |
196 | - action->steps = 1; |
197 | - |
198 | + action->type = type; |
199 | return action; |
200 | } |
201 | |
202 | @@ -150,36 +206,50 @@ |
203 | * \param action |
204 | * \param pathname |
205 | */ |
206 | -void FileSystemAction::addEntry(Action* action, const QString& pathname) |
207 | +void FileSystemAction::addEntry(Action* action, ActionPaths& pairPaths) |
208 | { |
209 | #if DEBUG_MESSAGES |
210 | - qDebug() << Q_FUNC_INFO << pathname; |
211 | + qDebug() << Q_FUNC_INFO << pairPaths.source(); |
212 | #endif |
213 | - DirItemInfo info(pathname); |
214 | - if (!info.isAbsolute()) |
215 | + |
216 | + ActionEntry * entry = new ActionEntry(); |
217 | + entry->itemPaths = pairPaths; |
218 | + if (populateEntry(action, entry)) |
219 | { |
220 | - info.setFile(action->targetPath, pathname); |
221 | + //now put the Entry in the Action |
222 | + action->entries.append(entry); |
223 | } |
224 | +} |
225 | + |
226 | +bool FileSystemAction::populateEntry(Action* action, ActionEntry* entry) |
227 | +{ |
228 | + DirItemInfo info(entry->itemPaths.source()); |
229 | if (!info.exists()) |
230 | { |
231 | emit error(QObject::tr("File or Directory does not exist"), |
232 | - pathname + QObject::tr(" does not exist") |
233 | - ); |
234 | - return; |
235 | + info.absoluteFilePath() + QObject::tr(" does not exist") |
236 | + ); |
237 | + return false; |
238 | } |
239 | - ActionEntry * entry = new ActionEntry(); |
240 | + entry->type = action->type; |
241 | + |
242 | //this is the item being handled |
243 | entry->reversedOrder.append(info); |
244 | - // verify if the destination item already exists |
245 | - if (action->type == ActionCopy || |
246 | - action->type == ActionMove || |
247 | - action->type == ActionHardMoveCopy) |
248 | + // verify if the destination item already exists and it the destination path is in other file system |
249 | + if (entry->type == ActionCopy || |
250 | + entry->type == ActionMove |
251 | + ) |
252 | { |
253 | - DirItemInfo destination(targetFom(info.absoluteFilePath(), action)); |
254 | + DirItemInfo destination(entry->itemPaths.target()); |
255 | entry->alreadyExists = destination.exists(); |
256 | + //check if it is possible to move items |
257 | + if (entry->type == ActionMove && !moveUsingSameFileSystem(entry->itemPaths) ) |
258 | + { |
259 | + entry->type = ActionHardMoveCopy; // first step |
260 | + } |
261 | } |
262 | //ActionMove will perform a rename, so no Directory expanding is necessary |
263 | - if (action->type != ActionMove && info.isDir() && !info.isSymLink()) |
264 | + if (entry->type != ActionMove && info.isDir() && !info.isSymLink()) |
265 | { |
266 | QDirIterator it(info.absoluteFilePath(), |
267 | QDir::AllEntries | QDir::System | |
268 | @@ -196,23 +266,23 @@ |
269 | int sizeSteps = 0; |
270 | int bufferSize = (COPY_BUFFER_SIZE * STEP_FILES); |
271 | while (counter--) |
272 | - { |
273 | + { |
274 | const DirItemInfo & item = entry->reversedOrder.at(counter); |
275 | size = (item.isFile() && !item.isDir() && !item.isSymLink()) ? |
276 | item.size() : COMMON_SIZE_ITEM; |
277 | action->totalBytes += size; |
278 | - if (action->type == ActionCopy || action->type == ActionHardMoveCopy) |
279 | + if (entry->type == ActionCopy || entry->type == ActionHardMoveCopy) |
280 | { |
281 | if ( (sizeSteps = size / bufferSize) ) |
282 | { |
283 | if ( !(size % bufferSize) ) |
284 | { |
285 | --sizeSteps; |
286 | + } |
287 | } |
288 | - action->steps += sizeSteps ; |
289 | + action->steps += sizeSteps ; |
290 | } |
291 | } |
292 | - } |
293 | //set final steps for the Entry based on Items number |
294 | int entrySteps = entry->reversedOrder.count() / STEP_FILES; |
295 | if ( entry->reversedOrder.count() % STEP_FILES) entrySteps++; |
296 | @@ -222,8 +292,8 @@ |
297 | qDebug() << "entrySteps" << entrySteps << "from entry counter" << entry->reversedOrder.count() |
298 | << "total steps" << action->steps; |
299 | #endif |
300 | - //now put the Entry in the Action |
301 | - action->entries.append(entry); |
302 | + |
303 | + return true; |
304 | } |
305 | |
306 | //=============================================================================================== |
307 | @@ -233,14 +303,9 @@ |
308 | void FileSystemAction::processAction() |
309 | { |
310 | if (m_curAction) |
311 | - { |
312 | - //it will be ActionHardMoveRemove only when switched from ActionHardMoveCopy |
313 | - //in this case the move is done in two steps COPY and REMOVE |
314 | - if (m_curAction->type != ActionHardMoveCopy) |
315 | - { |
316 | + { |
317 | delete m_curAction; |
318 | m_curAction = 0; |
319 | - } |
320 | } |
321 | if (!m_curAction && m_queuedActions.count()) |
322 | { |
323 | @@ -277,12 +342,12 @@ |
324 | */ |
325 | void FileSystemAction::processActionEntry() |
326 | { |
327 | -#if DEBUG_MESSAGES |
328 | - qDebug() << Q_FUNC_INFO; |
329 | -#endif |
330 | - |
331 | ActionEntry * curEntry = m_curAction->currEntry; |
332 | |
333 | +#if DEBUG_MESSAGES |
334 | + qDebug() << Q_FUNC_INFO << "entry:" << curEntry << "type:" << curEntry->type; |
335 | +#endif |
336 | + |
337 | #if defined(SIMULATE_LONG_ACTION) |
338 | { |
339 | unsigned int delay = SIMULATE_LONG_ACTION; |
340 | @@ -295,7 +360,7 @@ |
341 | #endif |
342 | if (!m_cancelCurrentAction) |
343 | { |
344 | - switch(m_curAction->type) |
345 | + switch(curEntry->type) |
346 | { |
347 | case ActionRemove: |
348 | case ActionHardMoveRemove: |
349 | @@ -320,11 +385,12 @@ |
350 | */ |
351 | void FileSystemAction::endActionEntry() |
352 | { |
353 | -#if DEBUG_MESSAGES |
354 | - qDebug() << Q_FUNC_INFO; |
355 | -#endif |
356 | ActionEntry * curEntry = m_curAction->currEntry; |
357 | |
358 | +#if DEBUG_MESSAGES |
359 | + qDebug() << Q_FUNC_INFO << "entry:" << curEntry << "type:" << curEntry->type; |
360 | +#endif |
361 | + |
362 | // first of all check for any error or a cancel issued by the user |
363 | if (m_cancelCurrentAction) |
364 | { |
365 | @@ -336,48 +402,41 @@ |
366 | scheduleSlot(SLOT(processAction())); |
367 | return; |
368 | } |
369 | + |
370 | + int percent = notifyProgress(); |
371 | + |
372 | // check if the current entry has finished |
373 | // if so Views need to receive the notification about that |
374 | if (curEntry->currItem == curEntry->reversedOrder.count()) |
375 | { |
376 | const DirItemInfo & mainItem = curEntry->reversedOrder.at(curEntry->currItem -1); |
377 | m_curAction->currEntryIndex++; |
378 | - switch(m_curAction->type) |
379 | + switch(curEntry->type) |
380 | { |
381 | case ActionRemove: |
382 | emit removed(mainItem); |
383 | break; |
384 | case ActionHardMoveRemove: // nothing to do |
385 | break; |
386 | - case ActionHardMoveCopy: |
387 | - //check if is doing a hard move and the copy part has finished |
388 | - //if so switch the action to remove |
389 | - if (m_curAction->currEntryIndex == m_curAction->entries.count()) |
390 | - { |
391 | - m_curAction->type = ActionHardMoveRemove; |
392 | - m_curAction->currEntryIndex = 0; |
393 | - int entryCounter = m_curAction->entries.count(); |
394 | - ActionEntry * entry; |
395 | - while (entryCounter--) |
396 | - { |
397 | - entry = m_curAction->entries.at(entryCounter); |
398 | - entry->currItem = 0; |
399 | - entry->currStep = 0; |
400 | - } |
401 | - } |
402 | - case ActionCopy: // ActionHardMoveCopy is also checked here |
403 | - case ActionMove: |
404 | - { |
405 | - QString addedItem = targetFom(mainItem.absoluteFilePath(), m_curAction); |
406 | - if (!curEntry->added && !curEntry->alreadyExists) |
407 | - { |
408 | - emit added(addedItem); |
409 | - curEntry->added = true; |
410 | - } |
411 | - else |
412 | - { |
413 | - emit changed(DirItemInfo(addedItem)); |
414 | - } |
415 | + case ActionHardMoveCopy: |
416 | + case ActionCopy: // ActionHardMoveCopy is lso checked here |
417 | + case ActionMove: |
418 | + if (!curEntry->added && !curEntry->alreadyExists) |
419 | + { |
420 | + emit added(curEntry->itemPaths.target()); |
421 | + curEntry->added = true; |
422 | + } |
423 | + else |
424 | + { |
425 | + emit changed(DirItemInfo(curEntry->itemPaths.target())); |
426 | + } |
427 | + if (curEntry->type == ActionHardMoveCopy) |
428 | + { |
429 | + //process same Entry again, |
430 | + m_curAction->currEntryIndex--; |
431 | + curEntry->type = ActionHardMoveRemove; |
432 | + m_curAction->currItem -= curEntry->reversedOrder.count(); |
433 | + curEntry->init(); |
434 | } |
435 | break; |
436 | }//switch |
437 | @@ -387,9 +446,8 @@ |
438 | if (curEntry->currStep == STEP_FILES) |
439 | { |
440 | curEntry->currStep = 0; |
441 | - } |
442 | + } |
443 | |
444 | - int percent = notifyProgress(); |
445 | //Check if the current action has finished or cancelled |
446 | if (m_cancelCurrentAction || |
447 | m_curAction->currEntryIndex == m_curAction->entries.count()) |
448 | @@ -485,14 +543,14 @@ |
449 | //first item from an Entry, |
450 | if (entry->currItem == 0 && entry->alreadyExists && entry->newName == 0) |
451 | { |
452 | - //making backup only if the targetpath == origPath, otherwise the item is overwritten |
453 | - if (m_curAction->targetPath == m_curAction->origPath) |
454 | + //making backup only if the targetpath == origPath, otherwise the item is overwritten |
455 | + if (entry->itemPaths.areEquals()) |
456 | { |
457 | //it will check again if the target exists |
458 | //if so, sets the entry->newName |
459 | //then targetFom() will use entry->newName for |
460 | // sub items in the Entry if the Entry is a directory |
461 | - if (!makeBackupNameForCurrentItem(m_curAction) ) |
462 | + if (!makeBackupNameForCurrentItem(entry) ) |
463 | { |
464 | m_cancelCurrentAction = true; |
465 | m_errorTitle = QObject::tr("Could not find a suitable name to backup"); |
466 | @@ -520,7 +578,7 @@ |
467 | { |
468 | const DirItemInfo &fi = entry->reversedOrder.at(entry->currItem); |
469 | QString orig = fi.absoluteFilePath(); |
470 | - QString target = targetFom(orig, m_curAction); |
471 | + QString target = targetFom(orig, entry); |
472 | QString path(target); |
473 | // do this here to allow progress send right item number, copySingleFile will emit progress() |
474 | m_curAction->currItem++; |
475 | @@ -537,7 +595,7 @@ |
476 | && !entry->reversedOrder.last().isSymLink() |
477 | ) |
478 | { |
479 | - QString entryDir = targetFom(entry->reversedOrder.last().absoluteFilePath(), m_curAction); |
480 | + QString entryDir = targetFom(entry->reversedOrder.last().absoluteFilePath(), entry); |
481 | QDir entryDirObj(entryDir); |
482 | if (!entryDirObj.exists() && entryDirObj.mkpath(entryDir)) |
483 | { |
484 | @@ -600,7 +658,7 @@ |
485 | m_curAction->copyFile.target->close(); |
486 | } |
487 | //check if there is disk space to copy source to target |
488 | - if (needsSize > 0 && !isThereDiskSpace( needsSize )) |
489 | + if (needsSize > 0 && !isThereDiskSpace(entry, needsSize )) |
490 | { |
491 | m_cancelCurrentAction = true; |
492 | m_errorTitle = QObject::tr("There is no space on disk to copy"); |
493 | @@ -666,8 +724,7 @@ |
494 | { |
495 | const DirItemInfo &fi = entry->reversedOrder.at(entry->currItem); |
496 | file.setFileName(fi.absoluteFilePath()); |
497 | - QString target(targetFom(fi.absoluteFilePath(), m_curAction)); |
498 | - DirItemInfo targetInfo(target); |
499 | + DirItemInfo targetInfo(entry->itemPaths.target()); |
500 | //rename will fail |
501 | if (targetInfo.exists()) |
502 | { |
503 | @@ -675,10 +732,11 @@ |
504 | entry->added = true; |
505 | if (targetInfo.isFile() || targetInfo.isSymLink()) |
506 | { |
507 | - if (!QFile::remove(target)) |
508 | + if (!QFile::remove(targetInfo.absoluteFilePath())) |
509 | { |
510 | m_cancelCurrentAction = true; |
511 | - m_errorTitle = QObject::tr("Could remove the directory/file ") + target; |
512 | + m_errorTitle = QObject::tr("Could remove the directory/file ") + |
513 | + targetInfo.absoluteFilePath(); |
514 | m_errorMsg = ::strerror(errno); |
515 | } |
516 | } |
517 | @@ -687,13 +745,14 @@ |
518 | { |
519 | //move target to /tmp and remove it later by creating an Remove action |
520 | //this will emit removed() |
521 | - moveDirToTempAndRemoveItLater(target); |
522 | + moveDirToTempAndRemoveItLater(targetInfo.absoluteFilePath()); |
523 | } |
524 | } |
525 | - if (!m_cancelCurrentAction && !file.rename(target)) |
526 | + if (!m_cancelCurrentAction && !file.rename(entry->itemPaths.target())) |
527 | { |
528 | m_cancelCurrentAction = true; |
529 | - m_errorTitle = QObject::tr("Could not move the directory/file ") + target; |
530 | + m_errorTitle = QObject::tr("Could not move the directory/file ") + |
531 | + targetInfo.absoluteFilePath(); |
532 | m_errorMsg = ::strerror(errno); |
533 | } |
534 | }//for |
535 | @@ -759,12 +818,7 @@ |
536 | { |
537 | emit error(titleError, noWriteError + origin.absoluteFilePath()); |
538 | return; |
539 | - } |
540 | - //check if it is possible to move items |
541 | - if ( !moveUsingSameFileSystem(items.at(0)) ) |
542 | - { |
543 | - actionType = ActionHardMoveCopy; // first step |
544 | - } |
545 | + } |
546 | if (!destination.isWritable()) |
547 | { |
548 | emit error(titleError, noWriteError + destination.absoluteFilePath()); |
549 | @@ -780,28 +834,28 @@ |
550 | * \brief FileSystemAction::createAndProcessAction |
551 | * \param actionType |
552 | * \param paths |
553 | - * \param operation |
554 | + * |
555 | */ |
556 | void FileSystemAction::createAndProcessAction(ActionType actionType, const QStringList& paths) |
557 | { |
558 | #if DEBUG_MESSAGES |
559 | qDebug() << Q_FUNC_INFO << paths; |
560 | #endif |
561 | - Action *myAction = 0; |
562 | - int origPathLen = 0; |
563 | - myAction = createAction(actionType, origPathLen); |
564 | - myAction->origPath = DirItemInfo(paths.at(0)).absolutePath(); |
565 | - myAction->baseOrigSize = myAction->origPath.length(); |
566 | + Action *myAction = 0; |
567 | + myAction = createAction(actionType); |
568 | for (int counter=0; counter < paths.count(); counter++) |
569 | { |
570 | - addEntry(myAction, paths.at(counter)); |
571 | + DirItemInfo info(paths.at(counter)); |
572 | + if (!info.isAbsolute()) |
573 | + { |
574 | + info.setFile(m_path, paths.at(counter)); |
575 | + } |
576 | + ActionPaths pairPaths(info.absoluteFilePath()); |
577 | + pairPaths.setTargetPathOnly(m_path); |
578 | + addEntry(myAction, pairPaths); |
579 | } |
580 | if (myAction->totalItems > 0) |
581 | - { |
582 | - if (actionType == ActionHardMoveCopy) |
583 | - { |
584 | - myAction->totalItems *= 2; //duplicate this |
585 | - } |
586 | + { |
587 | /* |
588 | if (actionType == ActionHardMoveCopy || actionType == ActionCopy) |
589 | { |
590 | @@ -830,21 +884,24 @@ |
591 | //=============================================================================================== |
592 | /*! |
593 | * \brief FileSystemAction::targetFom() makes a destination full pathname from \a origItem |
594 | - * \param origItem full pathname from a item intended to be copied or moved into current path |
595 | + * \param origItem full pathname from a item intended to be copied or moved under entry->itemPaths.target |
596 | + * \param entry which the item belongs to (item may be a sub item if the entry is a Directory) |
597 | * \return full pathname of target |
598 | + * |
599 | + * \sa makeBackupNameForCurrentItem() |
600 | */ |
601 | -QString FileSystemAction::targetFom(const QString& origItem, const Action* const action) |
602 | +QString FileSystemAction::targetFom(const QString& origItem, ActionEntry *entry) |
603 | { |
604 | - QString destinationUnderTarget(origItem.mid(action->baseOrigSize)); |
605 | - if (action->currEntry && action->currEntry->newName) |
606 | + QString destinationUnderTarget(origItem.mid(entry->itemPaths.baseOrigSize())); |
607 | + if (entry->newName) |
608 | { |
609 | int len = destinationUnderTarget.indexOf(QDir::separator(), 1); |
610 | if (len == -1) { |
611 | len = destinationUnderTarget.size(); |
612 | } |
613 | - destinationUnderTarget.replace(1, len -1, *action->currEntry->newName); |
614 | + destinationUnderTarget.replace(1, len -1, *entry->newName); |
615 | } |
616 | - QString target(action->targetPath + destinationUnderTarget); |
617 | + QString target(entry->itemPaths.targetPath() + destinationUnderTarget); |
618 | |
619 | #if DEBUG_MESSAGES |
620 | qDebug() << Q_FUNC_INFO << "orig" << origItem |
621 | @@ -856,31 +913,39 @@ |
622 | |
623 | //=============================================================================================== |
624 | /*! |
625 | - * \brief FileSystemAction::moveUsingSameFileSystem() Checks if the item being moved to |
626 | - * current m_path belongs to the same File System |
627 | + * \brief FileSystemAction::moveUsingSameFileSystem() Checks if the item being moved to another path |
628 | + * belongs to the same File System as the target path |
629 | * |
630 | * It is used to set ActionHardMoveCopy or ActionMove for cut operations. |
631 | * |
632 | - * \param itemToMovePathname first item being moved from a paste operation |
633 | + * \param paths |
634 | * |
635 | - * \return true if the item being moved to the current m_path belongs to the same file system as m_path |
636 | + * \return true if the operation is going to performed in the same file system |
637 | */ |
638 | -bool FileSystemAction::moveUsingSameFileSystem(const QString& itemToMovePathname) |
639 | +bool FileSystemAction::moveUsingSameFileSystem(const ActionPaths& movedItem) |
640 | { |
641 | unsigned long targetFsId = 0xffff; |
642 | unsigned long originFsId = 0xfffe; |
643 | + |
644 | +#if defined(REGRESSION_TEST_FOLDERLISTMODEL) |
645 | + if (m_forceUsingOtherFS) |
646 | + { |
647 | + return false; |
648 | + } |
649 | +#endif |
650 | + |
651 | #if defined(Q_OS_UNIX) |
652 | struct statvfs vfs; |
653 | - if ( ::statvfs( QFile::encodeName(m_path).constData(), &vfs) == 0 ) |
654 | + if ( ::statvfs( QFile::encodeName(movedItem.source()).constData(), &vfs) == 0 ) |
655 | { |
656 | targetFsId = vfs.f_fsid; |
657 | } |
658 | - if ( ::statvfs(QFile::encodeName(itemToMovePathname).constData(), &vfs) == 0) |
659 | + if ( ::statvfs(QFile::encodeName(movedItem.targetPath()).constData(), &vfs) == 0) |
660 | { |
661 | originFsId = vfs.f_fsid; |
662 | } |
663 | #else |
664 | - Q_UNUSED(itemToMovePathname); |
665 | + Q_UNUSED(movedItem); |
666 | #endif |
667 | return targetFsId == originFsId; |
668 | } |
669 | @@ -899,26 +964,23 @@ |
670 | void FileSystemAction::endCurrentAction() |
671 | { |
672 | |
673 | - if ( !m_clipboardChanged && |
674 | - m_curAction->origPath != m_curAction->targetPath && |
675 | - (m_curAction->type == ActionMove || m_curAction->type == ActionHardMoveRemove) |
676 | - ) |
677 | - { |
678 | - QStringList items; |
679 | - const ActionEntry *entry; |
680 | - int last; |
681 | - for(int e = 0; e < m_curAction->entries.count(); e++) |
682 | - { |
683 | - entry = m_curAction->entries.at(e); |
684 | - last = entry->reversedOrder.count() -1; |
685 | - QString item(targetFom(entry->reversedOrder.at(last).absoluteFilePath(), m_curAction)); |
686 | - items.append(item); |
687 | - } |
688 | - if (items.count()) |
689 | - { |
690 | - QString targetPath = m_curAction->targetPath; |
691 | - //it is not necessary to handle own clipboard here |
692 | - emit recopy(items, targetPath); |
693 | + if ( !m_clipboardChanged && m_curAction->type == ActionMove ) |
694 | + { |
695 | + const ActionEntry *entry = m_curAction->entries.at(0); |
696 | + if (!entry->itemPaths.arePathsEquals()) |
697 | + { |
698 | + QString destinationPath = entry->itemPaths.targetPath(); |
699 | + QStringList items; |
700 | + for(int e = 0; e < m_curAction->entries.count(); e++) |
701 | + { |
702 | + entry = m_curAction->entries.at(e); |
703 | + items.append(entry->itemPaths.target()); |
704 | + } |
705 | + if (items.count()) |
706 | + { |
707 | + //it is not necessary to handle own clipboard here |
708 | + emit recopy(items, destinationPath); |
709 | + } |
710 | } |
711 | } |
712 | } |
713 | @@ -1055,7 +1117,9 @@ |
714 | |
715 | //copying empty files will have totalBytes==0 |
716 | if ( m_curAction->totalBytes > 0 && |
717 | - (m_curAction->type == ActionCopy || m_curAction->type == ActionHardMoveCopy) |
718 | + (m_curAction->currEntry->type == ActionCopy || |
719 | + m_curAction->currEntry->type == ActionHardMoveCopy |
720 | + ) |
721 | ) |
722 | { |
723 | percent = (m_curAction->bytesWritten * 100) / m_curAction->totalBytes ; |
724 | @@ -1086,17 +1150,12 @@ |
725 | { |
726 | percent = 1; |
727 | } |
728 | - if (SHOULD_EMIT_PROGRESS_SIGNAL(m_curAction) && !m_curAction->done) |
729 | - { |
730 | - if (m_curAction->type == ActionHardMoveCopy || |
731 | - m_curAction->type ==ActionHardMoveRemove) |
732 | - { |
733 | - emit progress(m_curAction->currItem/2, m_curAction->totalItems/2, percent); |
734 | - } |
735 | - else |
736 | - { |
737 | - emit progress(m_curAction->currItem, m_curAction->totalItems, percent); |
738 | - } |
739 | + if ( SHOULD_EMIT_PROGRESS_SIGNAL(m_curAction) && |
740 | + !m_curAction->done && |
741 | + m_curAction->currEntry->type != ActionHardMoveRemove |
742 | + ) |
743 | + { |
744 | + emit progress(m_curAction->currItem, m_curAction->totalItems, percent); |
745 | if (percent == 100 && m_curAction->currItem == m_curAction->totalItems) |
746 | { |
747 | m_curAction->done = true; |
748 | @@ -1177,7 +1236,8 @@ |
749 | m_curAction->auxAction->isAux = true; |
750 | m_queuedActions.append(m_curAction->auxAction); |
751 | } |
752 | - addEntry(m_curAction->auxAction, tempDir); |
753 | + ActionPaths pathToRemove(tempDir); |
754 | + addEntry(m_curAction->auxAction, pathToRemove); |
755 | } |
756 | } |
757 | |
758 | @@ -1199,13 +1259,13 @@ |
759 | * The newName field from current entry will be set to a suitable name |
760 | * \param action |
761 | */ |
762 | -bool FileSystemAction::makeBackupNameForCurrentItem(Action *action) |
763 | +bool FileSystemAction::makeBackupNameForCurrentItem(ActionEntry *entry) |
764 | { |
765 | bool ret = false; |
766 | - if (action->currEntry->alreadyExists) |
767 | + if (entry->alreadyExists) |
768 | { |
769 | const DirItemInfo& fi = |
770 | - action->currEntry->reversedOrder.at(action->currEntry->reversedOrder.count() -1); |
771 | + entry->reversedOrder.at(entry->reversedOrder.count() -1); |
772 | DirItemInfo backuped; |
773 | int counter=0; |
774 | QString name; |
775 | @@ -1233,7 +1293,8 @@ |
776 | } while (backuped.exists() && counter < 100); |
777 | if (counter < 100) |
778 | { |
779 | - action->currEntry->newName = new QString(backuped.fileName()); |
780 | + entry->newName = new QString(backuped.fileName()); |
781 | + entry->itemPaths.setTargetFullName( backuped.absoluteFilePath() ); |
782 | ret = true; |
783 | } |
784 | } |
785 | @@ -1275,12 +1336,12 @@ |
786 | } |
787 | |
788 | //================================================================== |
789 | -bool FileSystemAction::isThereDiskSpace(qint64 requiredSize) |
790 | +bool FileSystemAction::isThereDiskSpace(const ActionEntry *entry, qint64 requiredSize) |
791 | { |
792 | bool ret = true; |
793 | #if defined(Q_OS_UNIX) |
794 | struct statvfs vfs; |
795 | - if ( ::statvfs( QFile::encodeName(m_path).constData(), &vfs) == 0 ) |
796 | + if ( ::statvfs( QFile::encodeName(entry->itemPaths.targetPath()).constData(), &vfs) == 0 ) |
797 | { |
798 | qint64 free = vfs.f_bsize * vfs.f_bfree; |
799 | ret = free > requiredSize; |
800 | @@ -1300,3 +1361,25 @@ |
801 | { |
802 | m_clipboardChanged = true; |
803 | } |
804 | + |
805 | + |
806 | +//================================================================== |
807 | +/*! |
808 | + * \brief FileSystemAction::moveToTrash() Move a set of files to Trash |
809 | + * \param items files/dirs that belong to the same parent directory |
810 | + */ |
811 | +void FileSystemAction::moveToTrash(const ActionPathList &pairPaths) |
812 | +{ |
813 | + Q_UNUSED(pairPaths); |
814 | +} |
815 | + |
816 | +//================================================================== |
817 | +/*! |
818 | + * \brief FileSystemAction::restoreFromTrash() restore a set of Files to |
819 | + * their original path |
820 | + * \param pairPaths |
821 | + */ |
822 | +void FileSystemAction::restoreFromTrash(const ActionPathList &pairPaths) |
823 | +{ |
824 | + Q_UNUSED(pairPaths); |
825 | +} |
826 | |
827 | === modified file 'folderlistmodel/filesystemaction.h' |
828 | --- folderlistmodel/filesystemaction.h 2014-02-05 15:31:44 +0000 |
829 | +++ folderlistmodel/filesystemaction.h 2014-04-15 00:42:01 +0000 |
830 | @@ -108,6 +108,8 @@ |
831 | void pathChanged(const QString& path); |
832 | void copyIntoCurrentPath(const QStringList& items); |
833 | void moveIntoCurrentPath(const QStringList& items); |
834 | + void moveToTrash(const ActionPathList& pairPaths ); |
835 | + void restoreFromTrash(const ActionPathList& pairPaths); |
836 | void onClipboardChanged(); |
837 | |
838 | |
839 | @@ -164,42 +166,41 @@ |
840 | struct ActionEntry |
841 | { |
842 | public: |
843 | - ActionEntry(): currStep(0),currItem(0),alreadyExists(false), newName(0), added(false) {} |
844 | - ~ActionEntry() |
845 | - { |
846 | - reversedOrder.clear(); |
847 | - if (newName) { delete newName; } |
848 | - } |
849 | - QList<DirItemInfo> reversedOrder; //!< last item must be the item from the list |
850 | + ActionEntry(); |
851 | + ~ActionEntry(); |
852 | + void init(); |
853 | + void reset(); |
854 | + ActionPaths itemPaths; //!< identifies the item being handled source and destination |
855 | + ActionType type; |
856 | + QList<DirItemInfo> reversedOrder; //!< last item must be the item from the list |
857 | int currStep; |
858 | - int currItem; |
859 | - bool alreadyExists; |
860 | + int currItem; |
861 | QString * newName; //TODO: allow to rename an existent file when it already exists. |
862 | // So far it is possible to backup items when copy/paste in the |
863 | // same place, in this case it is renamed to "<name> Copy (%d).termination" |
864 | - |
865 | - bool added; //!< signal added() already emitted for the current ActionEntry |
866 | + bool added :1; //!< signal added() already emitted for the current ActionEntry |
867 | + bool alreadyExists :1; |
868 | }; |
869 | |
870 | struct Action |
871 | { |
872 | public: |
873 | - ~Action() {qDeleteAll(entries); entries.clear(); copyFile.clear();} |
874 | + Action(); |
875 | + ~Action(); |
876 | + void reset(); |
877 | ActionType type; |
878 | QList<ActionEntry*> entries; |
879 | int totalItems; |
880 | - int currItem; |
881 | - int baseOrigSize; |
882 | - QString origPath; |
883 | - QString targetPath; |
884 | + int currItem; |
885 | quint64 totalBytes; |
886 | quint64 bytesWritten; |
887 | int currEntryIndex; |
888 | ActionEntry * currEntry; |
889 | - CopyFile copyFile; |
890 | - bool done; |
891 | + CopyFile copyFile; |
892 | Action * auxAction; |
893 | - bool isAux; |
894 | + bool isAux :1; |
895 | + bool done :1; |
896 | + bool canUndo :1; |
897 | int steps; |
898 | }; |
899 | |
900 | @@ -215,12 +216,13 @@ |
901 | |
902 | |
903 | private: |
904 | - Action * createAction(ActionType, int origBase = 0); |
905 | - void addEntry(Action* action, const QString &pathname); |
906 | + Action * createAction(ActionType); |
907 | + void addEntry(Action* action, ActionPaths& pairPaths); |
908 | + bool populateEntry(Action* action, ActionEntry* entry); |
909 | void removeEntry(ActionEntry *); |
910 | void moveEntry(ActionEntry *entry); |
911 | - bool moveUsingSameFileSystem(const QString& itemToMovePathname); |
912 | - QString targetFom(const QString& origItem, const Action * const action); |
913 | + bool moveUsingSameFileSystem(const ActionPaths &movedItem); |
914 | + QString targetFom(const QString& origItem, ActionEntry * entry); |
915 | void endCurrentAction(); |
916 | int percentWorkDone(); |
917 | int notifyProgress(int forcePercent = 0); |
918 | @@ -228,11 +230,12 @@ |
919 | bool copySymLink(const QString& target, const QFileInfo& orig); |
920 | void scheduleSlot(const char *slot); |
921 | void moveDirToTempAndRemoveItLater(const QString& dir); |
922 | - bool makeBackupNameForCurrentItem(Action *action); |
923 | + bool makeBackupNameForCurrentItem(ActionEntry *entry); |
924 | bool endCopySingleFile(); |
925 | - bool isThereDiskSpace(qint64 requiredSize); |
926 | + bool isThereDiskSpace(const ActionEntry *entry, qint64 requiredSize); |
927 | |
928 | #if defined(REGRESSION_TEST_FOLDERLISTMODEL) //used in Unit/Regression tests |
929 | + bool m_forceUsingOtherFS; |
930 | friend class TestDirModel; |
931 | #endif |
932 | }; |
933 | |
934 | === modified file 'test_folderlistmodel/regression/tst_folderlistmodel.cpp' |
935 | --- test_folderlistmodel/regression/tst_folderlistmodel.cpp 2014-03-23 13:38:08 +0000 |
936 | +++ test_folderlistmodel/regression/tst_folderlistmodel.cpp 2014-04-15 00:42:01 +0000 |
937 | @@ -914,7 +914,8 @@ |
938 | QStringList allFiles(m_deepDir_01->firstLevel()); |
939 | allFiles.append(tempFiles.createdList()); |
940 | |
941 | - m_dirModel_02->m_fsAction->createAndProcessAction(FileSystemAction::ActionHardMoveCopy, |
942 | + m_dirModel_02->m_fsAction->m_forceUsingOtherFS = true; |
943 | + m_dirModel_02->m_fsAction->createAndProcessAction(FileSystemAction::ActionMove, |
944 | allFiles); |
945 | |
946 | QTest::qWait(TIME_TO_PROCESS); |
PASSED: Continuous integration, rev:64 91.189. 93.70:8080/ job/ubuntu- filemanager- dev-ubuntu- filemanager- app-plugin- ci/118/ 91.189. 93.70:8080/ job/ubuntu- filemanager- dev-ubuntu- filemanager- app-plugin- raring- amd64-ci/ 118 91.189. 93.70:8080/ job/ubuntu- filemanager- dev-ubuntu- filemanager- app-plugin- saucy-amd64- ci/118 91.189. 93.70:8080/ job/ubuntu- filemanager- dev-ubuntu- filemanager- app-plugin- trusty- amd64-ci/ 115
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- filemanager- dev-ubuntu- filemanager- app-plugin- ci/118/ rebuild
http://