Author: stippi Date: 2010-01-13 18:20:01 +0100 (Wed, 13 Jan 2010) New Revision: 35055 Changeset: http://dev.haiku-os.org/changeset/35055/haiku Modified: haiku/trunk/src/kits/tracker/FSUtils.cpp haiku/trunk/src/kits/tracker/FSUtils.h Log: * First attempt at cleaning up the CopyLoopControl mess. Instantiate one TrackerCopyLoopControl and pass it on when needed. Avoid access to gStatusWindow directly. Later on, I will try to make it possible to drop more files/folders onto an ongoing copy process to append it to the job, i.e. copy those files to the same target folder. * For each updating the status, entry_refs were copied instead of passed by reference, which was a bit unnecessary overhead. * Some coding style cleanup. Modified: haiku/trunk/src/kits/tracker/FSUtils.cpp =================================================================== --- haiku/trunk/src/kits/tracker/FSUtils.cpp 2010-01-13 17:19:14 UTC (rev 35054) +++ haiku/trunk/src/kits/tracker/FSUtils.cpp 2010-01-13 17:20:01 UTC (rev 35055) @@ -111,7 +111,8 @@ status_t CalcItemsAndSize(BObjectList<entry_ref> *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<entry_ref> *srcList, const BDirectory *destDir, int32 *collisionCount, uint32 moveMode); status_t CheckName(uint32 moveMode, const BEntry *srcEntry, @@ -171,12 +172,69 @@ }; +// #pragma mark - + + CopyLoopControl::~CopyLoopControl() { } +void +CopyLoopControl::ChecksumChunk(const char *, size_t) +{ +} + + bool +CopyLoopControl::ChecksumFile(const entry_ref *) +{ + return true; +} + + +bool +CopyLoopControl::SkipAttribute(const char*) +{ + return false; +} + + +bool +CopyLoopControl::PreserveAttribute(const char*) +{ + return false; +} + + +// #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) { @@ -199,8 +257,8 @@ void -TrackerCopyLoopControl::UpdateStatus(const char *name, entry_ref, int32 count, - bool optional) +TrackerCopyLoopControl::UpdateStatus(const char *name, const entry_ref&, + int32 count, bool optional) { if (gStatusWindow) gStatusWindow->UpdateStatus(fThread, name, count, optional); @@ -210,7 +268,18 @@ bool TrackerCopyLoopControl::CheckUserCanceled() { - return gStatusWindow && gStatusWindow->CheckCanceledOrPaused(fThread); + 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; } @@ -234,41 +303,25 @@ TrackerCopyLoopControl::SkipAttribute(const char *attributeName) { for (const char **skipAttribute = kSkipAttributes; *skipAttribute; - skipAttribute++) + skipAttribute++) { if (strcmp(*skipAttribute, attributeName) == 0) return true; + } return false; } void -CopyLoopControl::ChecksumChunk(const char *, size_t) +TrackerCopyLoopControl::SetSourceList(EntryList* list) { + fSourceList = list; } -bool -CopyLoopControl::ChecksumFile(const entry_ref *) -{ - return true; -} +// #pragma mark - -bool -CopyLoopControl::SkipAttribute(const char*) -{ - return false; -} - - -bool -CopyLoopControl::PreserveAttribute(const char*) -{ - return false; -} - - static BNode * GetWritableNode(BEntry *entry, StatStruct *statBuf = 0) { @@ -396,8 +449,8 @@ 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 @@ static status_t InitCopy(uint32 moveMode, BObjectList<entry_ref> *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 @@ static status_t -MoveTask(BObjectList<entry_ref> *srcList, BEntry *destEntry, BList *pointList, uint32 moveMode) +MoveTask(BObjectList<entry_ref> *srcList, BEntry *destEntry, BList *pointList, + uint32 moveMode) { ASSERT(!srcList->IsEmpty()); @@ -686,7 +741,7 @@ dev_t destVolumeDevice = srcVolumeDevice; StatStruct deststat; - BVolume volume (srcVolumeDevice); + BVolume volume(srcVolumeDevice); entry_ref destRef; const entry_ref *destRefToCheck = NULL; @@ -732,16 +787,19 @@ } // 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 @@ 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 @@ && srcRef->directory == deststat.st_ino)) continue; - if (gStatusWindow && gStatusWindow->CheckCanceledOrPaused(thread)) + if (loopControl.CheckUserCanceled()) break; BEntry sourceEntry(srcRef); @@ -824,8 +884,7 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ } // 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 @@ } 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 @@ 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 @@ 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); Modified: haiku/trunk/src/kits/tracker/FSUtils.h =================================================================== --- haiku/trunk/src/kits/tracker/FSUtils.h 2010-01-13 17:19:14 UTC (rev 35054) +++ haiku/trunk/src/kits/tracker/FSUtils.h 2010-01-13 17:20:01 UTC (rev 35055) @@ -57,92 +57,101 @@ 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 <name> - // 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 <name>. + // \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 <name> - // 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<entry_ref> 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