diff --git a/src/kits/tracker/FSUtils.cpp b/src/kits/tracker/FSUtils.cpp index 64d037729f..7815a58ddc 100644 --- a/src/kits/tracker/FSUtils.cpp +++ b/src/kits/tracker/FSUtils.cpp @@ -111,7 +111,8 @@ static status_t _RestoreTask(BObjectList *); status_t CalcItemsAndSize(BObjectList *refList, size_t blockSize, int32 *totalCount, off_t *totalSize); status_t MoveItem(BEntry *entry, BDirectory *destDir, BPoint *loc, - uint32 moveMode, const char *newName, Undo &undo); + uint32 moveMode, const char *newName, Undo &undo, + CopyLoopControl* loopControl); ConflictCheckResult PreFlightNameCheck(BObjectList *srcList, const BDirectory *destDir, int32 *collisionCount, uint32 moveMode); status_t CheckName(uint32 moveMode, const BEntry *srcEntry, @@ -171,77 +172,14 @@ const char *kSkipAttributes[] = { }; +// #pragma mark - + + CopyLoopControl::~CopyLoopControl() { } -bool -TrackerCopyLoopControl::FileError(const char *message, const char *name, - status_t error, bool allowContinue) -{ - char buffer[512]; - sprintf(buffer, message, name, strerror(error)); - - if (allowContinue) { - BAlert *alert = new BAlert("", buffer, "Cancel", "OK", 0, - B_WIDTH_AS_USUAL, B_STOP_ALERT); - alert->SetShortcut(0, B_ESCAPE); - return alert->Go() != 0; - } - - BAlert *alert = new BAlert("", buffer, "Cancel", 0, 0, - B_WIDTH_AS_USUAL, B_STOP_ALERT); - alert->SetShortcut(0, B_ESCAPE); - alert->Go(); - return false; -} - - -void -TrackerCopyLoopControl::UpdateStatus(const char *name, entry_ref, int32 count, - bool optional) -{ - if (gStatusWindow) - gStatusWindow->UpdateStatus(fThread, name, count, optional); -} - - -bool -TrackerCopyLoopControl::CheckUserCanceled() -{ - return gStatusWindow && gStatusWindow->CheckCanceledOrPaused(fThread); -} - - -TrackerCopyLoopControl::OverwriteMode -TrackerCopyLoopControl::OverwriteOnConflict(const BEntry *, const char *, - const BDirectory *, bool, bool) -{ - return kReplace; -} - - -bool -TrackerCopyLoopControl::SkipEntry(const BEntry *, bool) -{ - // tracker makes no exceptions - return false; -} - - -bool -TrackerCopyLoopControl::SkipAttribute(const char *attributeName) -{ - for (const char **skipAttribute = kSkipAttributes; *skipAttribute; - skipAttribute++) - if (strcmp(*skipAttribute, attributeName) == 0) - return true; - - return false; -} - - void CopyLoopControl::ChecksumChunk(const char *, size_t) { @@ -269,6 +207,121 @@ CopyLoopControl::PreserveAttribute(const char*) } +// #pragma mark - + + +TrackerCopyLoopControl::TrackerCopyLoopControl(thread_id thread) + : + fThread(thread), + fSourceList(NULL) +{ +} + + +TrackerCopyLoopControl::TrackerCopyLoopControl(thread_id thread, + int32 totalItems, off_t totalSize) + : + fThread(thread), + fSourceList(NULL) +{ + if (gStatusWindow) + gStatusWindow->InitStatusItem(thread, totalItems, totalItems); +} + + +TrackerCopyLoopControl::~TrackerCopyLoopControl() +{ +} + + +bool +TrackerCopyLoopControl::FileError(const char *message, const char *name, + status_t error, bool allowContinue) +{ + char buffer[512]; + sprintf(buffer, message, name, strerror(error)); + + if (allowContinue) { + BAlert *alert = new BAlert("", buffer, "Cancel", "OK", 0, + B_WIDTH_AS_USUAL, B_STOP_ALERT); + alert->SetShortcut(0, B_ESCAPE); + return alert->Go() != 0; + } + + BAlert *alert = new BAlert("", buffer, "Cancel", 0, 0, + B_WIDTH_AS_USUAL, B_STOP_ALERT); + alert->SetShortcut(0, B_ESCAPE); + alert->Go(); + return false; +} + + +void +TrackerCopyLoopControl::UpdateStatus(const char *name, const entry_ref&, + int32 count, bool optional) +{ + if (gStatusWindow) + gStatusWindow->UpdateStatus(fThread, name, count, optional); +} + + +bool +TrackerCopyLoopControl::CheckUserCanceled() +{ + if (gStatusWindow == NULL) + return false; + + if (gStatusWindow->CheckCanceledOrPaused(fThread)) + return true; + + if (fSourceList != NULL) { + // TODO: Check if the user dropped additional files onto this job. +// printf("%p->CheckUserCanceled()\n", this); + } + + return false; +} + + +TrackerCopyLoopControl::OverwriteMode +TrackerCopyLoopControl::OverwriteOnConflict(const BEntry *, const char *, + const BDirectory *, bool, bool) +{ + return kReplace; +} + + +bool +TrackerCopyLoopControl::SkipEntry(const BEntry *, bool) +{ + // tracker makes no exceptions + return false; +} + + +bool +TrackerCopyLoopControl::SkipAttribute(const char *attributeName) +{ + for (const char **skipAttribute = kSkipAttributes; *skipAttribute; + skipAttribute++) { + if (strcmp(*skipAttribute, attributeName) == 0) + return true; + } + + return false; +} + + +void +TrackerCopyLoopControl::SetSourceList(EntryList* list) +{ + fSourceList = list; +} + + +// #pragma mark - + + static BNode * GetWritableNode(BEntry *entry, StatStruct *statBuf = 0) { @@ -396,8 +449,8 @@ FSMoveToFolder(BObjectList *srcList, BEntry *destEntry, return; } - LaunchInNewThread("MoveTask", B_NORMAL_PRIORITY, MoveTask, srcList, destEntry, - pointList, moveMode); + LaunchInNewThread("MoveTask", B_NORMAL_PRIORITY, MoveTask, srcList, + destEntry, pointList, moveMode); } @@ -552,7 +605,8 @@ ConfirmChangeIfWellKnownDirectory(const BEntry *entry, const char *action, static status_t InitCopy(uint32 moveMode, BObjectList *srcList, thread_id thread, BVolume *dstVol, BDirectory *destDir, entry_ref *destRef, - bool preflightNameCheck, bool needSizeCalculation, int32 *collisionCount, ConflictCheckResult *preflightResult) + bool preflightNameCheck, bool needSizeCalculation, int32 *collisionCount, + ConflictCheckResult *preflightResult) { if (dstVol->IsReadOnly()) { if (gStatusWindow) @@ -675,7 +729,8 @@ delete_point(void *point) static status_t -MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, uint32 moveMode) +MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, + uint32 moveMode) { ASSERT(!srcList->IsEmpty()); @@ -686,7 +741,7 @@ MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, u dev_t destVolumeDevice = srcVolumeDevice; StatStruct deststat; - BVolume volume (srcVolumeDevice); + BVolume volume(srcVolumeDevice); entry_ref destRef; const entry_ref *destRefToCheck = NULL; @@ -732,16 +787,19 @@ MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, u } // change the move mode if needed - if (moveMode == kCopySelectionTo && destIsTrash) + if (moveMode == kCopySelectionTo && destIsTrash) { // cannot copy to trash moveMode = kMoveSelectionTo; + } if (moveMode == kMoveSelectionTo && sourceIsReadOnly) moveMode = kCopySelectionTo; bool needSizeCalculation = true; - if ((moveMode == kMoveSelectionTo && srcVolumeDevice == destVolumeDevice) || destIsTrash) + if ((moveMode == kMoveSelectionTo && srcVolumeDevice == destVolumeDevice) + || destIsTrash) { needSizeCalculation = false; + } // we need the undo object later on, so we create it no matter // if we really need it or not (it's very lightweight) @@ -755,9 +813,11 @@ MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, u status_t result = InitCopy(moveMode, srcList, thread, &volume, destDirToCheck, &destRef, needPreflightNameCheck, needSizeCalculation, &collisionCount, &conflictCheckResult); - int32 count = srcList->CountItems(); + TrackerCopyLoopControl loopControl(thread); + loopControl.SetSourceList(srcList); + if (result == B_OK) { - for (int32 i = 0; i < count; i++) { + for (int32 i = 0; i < srcList->CountItems(); i++) { BPoint *loc = (BPoint *)-1; // a loc of -1 forces autoplacement, rather than copying the // position of the original node @@ -783,7 +843,7 @@ MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, u && srcRef->directory == deststat.st_ino)) continue; - if (gStatusWindow && gStatusWindow->CheckCanceledOrPaused(thread)) + if (loopControl.CheckUserCanceled()) break; BEntry sourceEntry(srcRef); @@ -824,8 +884,7 @@ MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, u // update the status because item got skipped and the status // will not get updated by the move call - if (gStatusWindow) - gStatusWindow->UpdateStatus(thread, srcRef->name, 1); + loopControl.UpdateStatus(srcRef->name, *srcRef, 1); continue; } @@ -849,7 +908,8 @@ MoveTask(BObjectList *srcList, BEntry *destEntry, BList *pointList, u if (pointList) loc = (BPoint*)pointList->ItemAt(i); - result = MoveItem(&sourceEntry, &destDir, loc, moveMode, NULL, undo); + result = MoveItem(&sourceEntry, &destDir, loc, moveMode, NULL, undo, + &loopControl); if (result != B_OK) break; } @@ -909,7 +969,8 @@ class MoveError { void CopyFile(BEntry *srcFile, StatStruct *srcStat, BDirectory *destDir, - CopyLoopControl *loopControl, BPoint *loc, bool makeOriginalName, Undo &undo) + CopyLoopControl *loopControl, BPoint *loc, bool makeOriginalName, + Undo &undo) { if (loopControl->SkipEntry(srcFile, true)) return; @@ -1333,9 +1394,8 @@ CopyFolder(BEntry *srcEntry, BDirectory *destDir, CopyLoopControl *loopControl, status_t -RecursiveMove(BEntry *entry, BDirectory *destDir) +RecursiveMove(BEntry *entry, BDirectory *destDir, CopyLoopControl* loopControl) { - TrackerCopyLoopControl loopControl(find_thread(NULL)); char name[B_FILE_NAME_LENGTH]; if (entry->GetName(name) == B_OK) { if (destDir->Contains(name)) { @@ -1349,12 +1409,16 @@ RecursiveMove(BEntry *entry, BDirectory *destDir) BEntry current; while (source.GetNextEntry(¤t) == B_OK) { if (current.IsDirectory()) { - RecursiveMove(¤t, &subDir); + RecursiveMove(¤t, &subDir, loopControl); current.Remove(); } else { current.GetName(name); - if (loopControl.OverwriteOnConflict(¤t, name, &subDir, true, false) != TrackerCopyLoopControl::kSkip) - MoveError::FailOnError(current.MoveTo(&subDir, NULL, true)); + if (loopControl->OverwriteOnConflict(¤t, name, + &subDir, true, false) + != TrackerCopyLoopControl::kSkip) { + MoveError::FailOnError(current.MoveTo(&subDir, + NULL, true)); + } } } } @@ -1369,7 +1433,7 @@ RecursiveMove(BEntry *entry, BDirectory *destDir) status_t MoveItem(BEntry *entry, BDirectory *destDir, BPoint *loc, uint32 moveMode, - const char *newName, Undo &undo) + const char *newName, Undo &undo, CopyLoopControl* loopControl) { entry_ref ref; try { @@ -1483,20 +1547,18 @@ MoveItem(BEntry *entry, BDirectory *destDir, BPoint *loc, uint32 moveMode, // for "Move" the size for status is always 1 - since file // size is irrelevant when simply moving to a new folder - - thread_id thread = find_thread(NULL); - if (gStatusWindow) - gStatusWindow->UpdateStatus(thread, ref.name, 1); + loopControl->UpdateStatus(ref.name, ref, 1); if (entry->IsDirectory()) - return RecursiveMove(entry, destDir); + return RecursiveMove(entry, destDir, loopControl); MoveError::FailOnError(entry->MoveTo(destDir, newName)); } else { - TrackerCopyLoopControl loopControl(find_thread(NULL)); bool makeOriginalName = (moveMode == kDuplicateSelection); if (S_ISDIR(statbuf.st_mode)) { - CopyFolder(entry, destDir, &loopControl, loc, makeOriginalName, undo, moveMode == kMoveSelectionTo); + CopyFolder(entry, destDir, loopControl, loc, makeOriginalName, + undo, moveMode == kMoveSelectionTo); } else { - CopyFile(entry, &statbuf, destDir, &loopControl, loc, makeOriginalName, undo); + CopyFile(entry, &statbuf, destDir, loopControl, loc, + makeOriginalName, undo); if (moveMode == kMoveSelectionTo) entry->Remove(); } @@ -1721,7 +1783,9 @@ MoveEntryToTrash(BEntry *entry, BPoint *loc, Undo &undo) node.WriteAttrString(kAttrOriginalPath, &originalPath); } - MoveItem(entry, &trash_dir, loc, kMoveSelectionTo, name, undo); + TrackerCopyLoopControl loopControl(find_thread(NULL)); + MoveItem(entry, &trash_dir, loc, kMoveSelectionTo, name, undo, + &loopControl); return B_OK; } @@ -1911,10 +1975,9 @@ CheckName(uint32 moveMode, const BEntry *sourceEntry, const BDirectory *destDir, } // delete destination item - if (!destIsDir) { - TrackerCopyLoopControl loopControl(find_thread(NULL)); + if (!destIsDir) err = entry.Remove(); - } else + else return B_OK; if (err != B_OK) { @@ -2509,13 +2572,10 @@ empty_trash(void *) } if (err == B_OK) { - if (gStatusWindow) - gStatusWindow->InitStatusItem(thread, totalCount, totalCount); + TrackerCopyLoopControl loopControl(thread, totalCount, totalCount); volumeRoster.Rewind(); while (volumeRoster.GetNextVolume(&volume) == B_OK) { - TrackerCopyLoopControl loopControl(thread); - if (volume.IsReadOnly() || !volume.IsPersistent()) continue; @@ -2589,11 +2649,9 @@ _DeleteTask(BObjectList *list, bool confirm) status_t err = CalcItemsAndSize(list, 0, &totalItems, &totalSize); if (err == B_OK) { - if (gStatusWindow) - gStatusWindow->InitStatusItem(thread, totalItems, totalItems); + TrackerCopyLoopControl loopControl(thread, totalItems, totalItems); int32 count = list->CountItems(); - TrackerCopyLoopControl loopControl(thread); for (int32 index = 0; index < count; index++) { entry_ref ref(*list->ItemAt(index)); BEntry entry(&ref); @@ -2659,11 +2717,9 @@ _RestoreTask(BObjectList *list) status_t err = CalcItemsAndSize(list, 0, &totalItems, &totalSize); if (err == B_OK) { - if (gStatusWindow) - gStatusWindow->InitStatusItem(thread, totalItems, totalItems); + TrackerCopyLoopControl loopControl(thread, totalItems, totalItems); int32 count = list->CountItems(); - TrackerCopyLoopControl loopControl(thread); for (int32 index = 0; index < count; index++) { entry_ref ref(*list->ItemAt(index)); BEntry entry(&ref); diff --git a/src/kits/tracker/FSUtils.h b/src/kits/tracker/FSUtils.h index 7e32b85fed..6329fe22e3 100644 --- a/src/kits/tracker/FSUtils.h +++ b/src/kits/tracker/FSUtils.h @@ -57,92 +57,101 @@ namespace BPrivate { class BInfoWindow; +//! Controls the copy engine; may be overriden to specify how conflicts are +// handled, etc. class CopyLoopControl { - // controls the copy engine; may be overriden to specify how conflicts are - // handled, etc. - // Installer has it's own subclass - public: - virtual ~CopyLoopControl(); - virtual bool FileError(const char *message, const char *name, status_t error, - bool allowContinue) = 0; - // inform that a file error occurred while copying - // returns true if user decided to continue +public: + virtual ~CopyLoopControl(); - virtual void UpdateStatus(const char *name, entry_ref ref, int32 count, - bool optional = false) = 0; + //! Inform that a file error occurred while copying . + // \return \c True if user decided to continue + virtual bool FileError(const char *message, + const char *name, status_t error, + bool allowContinue) = 0; - virtual bool CheckUserCanceled() = 0; - // returns true if canceled + virtual void UpdateStatus(const char *name, + const entry_ref& ref, int32 count, + bool optional = false) = 0; - enum OverwriteMode { - kSkip, // do not replace, go to next entry - kReplace, // remove entry before copying new one - kMerge // for folders: leave existing folder, update contents leaving - // nonconflicting items + //! \return \c true if canceled + virtual bool CheckUserCanceled() = 0; + + enum OverwriteMode { + kSkip, // do not replace, go to next entry + kReplace, // remove entry before copying new one + kMerge // for folders: leave existing folder, update + // contents leaving nonconflicting items // for files: save original attributes on file. - }; + }; - virtual OverwriteMode OverwriteOnConflict(const BEntry *srcEntry, - const char *destName, const BDirectory *destDir, bool srcIsDir, - bool dstIsDir) = 0; - // override to always overwrite, never overwrite, let user decide, - // compare dates, etc. + //! Override to always overwrite, never overwrite, let user decide, + // compare dates, etc. + virtual OverwriteMode OverwriteOnConflict(const BEntry *srcEntry, + const char *destName, + const BDirectory *destDir, + bool srcIsDir, bool dstIsDir) = 0; - virtual bool SkipEntry(const BEntry *, bool file) = 0; - // override to prevent copying of a given file or directory + //! Override to prevent copying of a given file or directory + virtual bool SkipEntry(const BEntry *, bool file) = 0; - virtual void ChecksumChunk(const char *block, size_t size); - // during a file copy, this is called every time a chunk of data - // is copied. Users may override to keep a running checksum. + //! During a file copy, this is called every time a chunk of data + // is copied. Users may override to keep a running checksum. + virtual void ChecksumChunk(const char *block, size_t size); - virtual bool ChecksumFile(const entry_ref *); - // This is called when a file is finished copying. Users of this - // class may override to verify that the checksum they've been - // computing in ChecksumChunk matches. If this returns true, - // the copy will continue. If false, if will abort. + //! This is called when a file is finished copying. Users of this + // class may override to verify that the checksum they've been + // computing in ChecksumChunk matches. If this returns true, + // the copy will continue. If false, if will abort. + virtual bool ChecksumFile(const entry_ref *); - virtual bool SkipAttribute(const char *attributeName); - virtual bool PreserveAttribute(const char *attributeName); + virtual bool SkipAttribute(const char *attributeName); + virtual bool PreserveAttribute(const char *attributeName); }; +//! This is the Tracker copy-specific version of CopyLoopControl. class TrackerCopyLoopControl : public CopyLoopControl { - // this is the Tracker copy - specific version of CopyLoopControl - public: - TrackerCopyLoopControl(thread_id); - virtual ~TrackerCopyLoopControl() {} +public: + TrackerCopyLoopControl(thread_id); + TrackerCopyLoopControl(thread_id, + int32 totalItems, off_t totalSize); + virtual ~TrackerCopyLoopControl(); - virtual bool FileError(const char *message, const char *name, status_t error, - bool allowContinue); - // inform that a file error occurred while copying - // returns true if user decided to continue + virtual bool FileError(const char *message, + const char *name, status_t error, + bool allowContinue); - virtual void UpdateStatus(const char *name, entry_ref ref, int32 count, - bool optional = false); + virtual void UpdateStatus(const char *name, + const entry_ref& ref, int32 count, + bool optional = false); - virtual bool CheckUserCanceled(); - // returns true if canceled + virtual bool CheckUserCanceled(); - virtual OverwriteMode OverwriteOnConflict(const BEntry *srcEntry, - const char *destName, const BDirectory *destDir, bool srcIsDir, - bool dstIsDir); + virtual OverwriteMode OverwriteOnConflict(const BEntry *srcEntry, + const char *destName, + const BDirectory *destDir, + bool srcIsDir, bool dstIsDir); - virtual bool SkipEntry(const BEntry *, bool file); - // override to prevent copying of a given file or directory + virtual bool SkipEntry(const BEntry *, bool file); + virtual bool SkipAttribute(const char *attributeName); - virtual bool SkipAttribute(const char *attributeName); - private: - thread_id fThread; + // One can specify an entry_ref list with the source entries. This will + // then trigger the feature to pull additional source entries from the + // status window, such that the user can drop additional items onto the + // progress display of the ongoing copy process to copy these items to + // the same target directory. + typedef BObjectList EntryList; + + void SetSourceList(EntryList* list); + +private: + thread_id fThread; + + EntryList* fSourceList; }; -inline -TrackerCopyLoopControl::TrackerCopyLoopControl(thread_id thread) - : fThread(thread) -{ -} - #define B_DESKTOP_DIR_NAME "Desktop" #ifndef _IMPEXP_TRACKER