diff -r 8d251b3d7721 -r ef51c640ee76 AbstractFileBrowser.st --- a/AbstractFileBrowser.st Sun Jul 10 17:47:24 2011 +0200 +++ b/AbstractFileBrowser.st Mon Jul 11 12:56:34 2011 +0200 @@ -2075,7 +2075,6 @@ translateLabel: true ) (MenuItem - "/ enabled: hasXmlFileSelected label: 'XML Inspector' itemValue: inspectXmlFile translateLabel: true @@ -2270,19 +2269,6 @@ itemValue: fileHexDump translateLabel: true ) -"/ something I would like to have... -"/ (MenuItem -"/ enabled: hasFileSelection -"/ label: 'Hex Dump of First n Bytes...' -"/ itemValue: fileHexDumpOfFirstNBytes -"/ translateLabel: true -"/ ) -"/ (MenuItem -"/ enabled: hasFileSelection -"/ label: 'Hex Dump of Last n Bytes...' -"/ itemValue: fileHexDumpOfLastNBytes -"/ translateLabel: true -"/ ) ) nil nil @@ -2300,6 +2286,11 @@ translateLabel: true ) (MenuItem + label: 'Duplicate File' + itemValue: fileFindDuplicateFile + translateLabel: true + ) + (MenuItem label: 'Duplicate Files' itemValue: fileFindDuplicates translateLabel: true @@ -2325,8 +2316,6 @@ nil nil ) - - "Modified: / 17-02-2011 / 13:55:43 / cg" ! viewDetailsMenuSpec @@ -5801,6 +5790,188 @@ "Modified: / 25-07-2006 / 09:07:22 / cg" ! +fileFindDuplicateFile + "scan directory for duplicates of the selected files" + + |files filesBySize samePerFile stream textBox| + + files := self currentSelectedFiles. + files isEmpty ifTrue:[^ self]. + + filesBySize := Dictionary new. + files do:[:fn | + |sz entry| + + sz := fn asFilename fileSize. + (filesBySize at:sz ifAbsentPut:[Set new]) add:fn. + ]. + + samePerFile := Dictionary new. + + self currentSelectedDirectories do:[:eachDir | + eachDir recursiveDirectoryContentsAsFilenamesDo:[:eachFile | + eachFile isDirectory ifFalse:[ + |sz possibleMatches| + + sz := eachFile fileSize. + possibleMatches := filesBySize at:sz ifAbsent:nil. + possibleMatches notNil ifTrue:[ + possibleMatches do:[:eachFileWithSameSize | + (eachFileWithSameSize sameContentsAs:eachFile) ifTrue:[ + (samePerFile at:eachFileWithSameSize ifAbsentPut:[Set new]) add:eachFile + ] + ] + ] + ] + ] + ]. + + stream := WriteStream on:''. + samePerFile keysAndValuesDo:[:origFile :sameFiles| + stream nextPutLine:origFile baseName. + (sameFiles asOrderedCollection collect:[:each | each baseName]) sort do:[:eachSameName | + stream nextPutAll:' '; nextPutLine:eachSameName. + ] + ]. + + textBox := TextBox new. + textBox initialText:(stream contents). + textBox title:'Files with same contents'. + textBox readOnly:true. + textBox noCancel. + textBox extent:(350@400). + textBox maxExtent:Screen current extent. + textBox openModeless. "/ showAtPointer. + +"/ +"/ self withActivityIndicationDo:[ +"/ result := Dictionary new. +"/ +"/ infoDir := Dictionary new. +"/ allFiles do:[:fn | +"/ infoDir at:fn put:(fn info) +"/ ]. +"/ +"/ "/ for each, get the files size. +"/ "/ in a first pass, look for files of the same size and +"/ "/ compare them ... +"/ +"/ filesBySize := Dictionary new. +"/ infoDir keysAndValuesDo:[:fn :info | +"/ |sz entry| +"/ +"/ sz := info size. +"/ entry := filesBySize at:sz ifAbsentPut:[Set new]. +"/ entry add:fn. +"/ ]. +"/ +"/ "/ any of same size ? +"/ +"/ filesBySize do:[:entry | +"/ |files| +"/ +"/ entry size > 1 ifTrue:[ +"/ files := entry asArray. +"/ 1 to:files size-1 do:[:idx1 | +"/ idx1+1 to:files size do:[:idx2 | +"/ |fn1 fn2| +"/ +"/ fn1 := files at:idx1. +"/ fn2 := files at:idx2. +"/ +"/ (result at:fn2 ifAbsent:nil) ~= fn1 ifTrue:[ +"/ "/ compare the files +"/ (fn1 sameContentsAs:fn2) ifTrue:[ +"/"/ Transcript show:'Same: '; show:fn1 baseName; show:' and '; showCR:fn2 baseName. +"/ result at:fn1 put:fn2. +"/ ] +"/ ] +"/ ] +"/ ] +"/ ] +"/ ]. +"/ +"/ result := result associations. +"/ result := result collect:[:assoc | +"/ |f1 f2| +"/ +"/ f1 := assoc key asString. +"/ f2 := assoc value asString. +"/ f1 < f2 ifTrue:[ +"/ f2 -> f1 +"/ ] ifFalse:[ +"/ f1 -> f2 +"/ ] +"/ ]. +"/ "/ result sort:[:f1 :f2 | f1 key > f2 key "f2 value < f1 key value"]. +"/ result sort:[:f1 :f2 | " f1 key > f2 key" f2 value < f1 key value]. +"/ +"/ info := OrderedCollection new. +"/ size := self getBestDirectory asString size. +"/ result do:[:assoc | +"/ |fn1 fn2| +"/ +"/ fn1 := assoc key. +"/ fn2 := assoc value. +"/ size > 1 ifTrue:[ +"/ fn1 := ('..', (fn1 copyFrom:(size + 1))). +"/ fn2 := ('..', (fn2 copyFrom:(size + 1))). +"/ ]. +"/ (fn1 includes:Character space) ifTrue:[ +"/ fn1 := '"' , fn1 , '"' +"/ ]. +"/ (fn2 includes:Character space) ifTrue:[ +"/ fn2 := '"' , fn2 , '"' +"/ ]. +"/ info add:(fn1 , ' same as ' , fn2) +"/ ]. +"/ info isEmpty ifTrue:[ +"/ Dialog information:'No duplicate files found.'. +"/ ^ self. +"/ ]. +"/ ]. +"/ stream := WriteStream on:''. +"/ info do:[:el| +"/ stream nextPutLine:el. +"/ ]. +"/ titleStream := WriteStream on:''. +"/ titleStream nextPutAll:'File duplicates in director'. +"/ directories size == 1 ifTrue:[ +"/ titleStream nextPutAll:'y: ', directories first asString. +"/ ] ifFalse:[ +"/ titleStream nextPutLine:'ies: '. +"/ directories do:[:dir| +"/ size > 1 ifTrue:[ +"/ titleStream nextPutAll:'..'. +"/ titleStream nextPutLine:((dir asString) copyFrom:(size + 1)). +"/ ] ifFalse:[ +"/ titleStream nextPutLine:(dir asString). +"/ ]. +"/ ] +"/ ]. +"/ +"/ textBox := TextBox new. +"/ textBox initialText:(stream contents). +"/ textBox title:(titleStream contents). +"/ textBox readOnly:true. +"/ textBox noCancel. +"/ stream := WriteStream on:'Duplicates in '. +"/ directories do:[ :aDirectory | +"/ stream nextPutAll:aDirectory baseName. +"/ stream space. +"/ ]. +"/ textBox label:stream contents. +"/ maxLength := 10. +"/ info do:[: el | +"/ maxLength := maxLength max:(el size). +"/ ]. +"/ textBox extent:((maxLength * 5)@((info size max:40)* 10)). +"/ textBox maxExtent:Screen current extent. +"/ textBox openModeless. "/ showAtPointer. + + "Created: / 11-07-2011 / 12:39:44 / cg" +! + fileFindDuplicates "scan directory for duplicate files" @@ -7417,7 +7588,6 @@ ^ false ! ! - !AbstractFileBrowser methodsFor:'presentation'! getModeString:modeBits @@ -8334,5 +8504,5 @@ !AbstractFileBrowser class methodsFor:'documentation'! version_CVS - ^ '$Header: /cvs/stx/stx/libtool/AbstractFileBrowser.st,v 1.461 2011-07-07 14:14:30 vrany Exp $' + ^ '$Header: /cvs/stx/stx/libtool/AbstractFileBrowser.st,v 1.462 2011-07-11 10:56:34 cg Exp $' ! !