#FEATURE by exept
authorClaus Gittinger <cg@exept.de>
Fri, 09 Aug 2019 17:22:23 +0200
changeset 18978 ff91b0569f14
parent 18977 b339f4cc41a7
child 18979 80fa568a5922
#FEATURE by exept class: DirectoryDifferenceViewApplication filters class definition added: #excludedDirectoryNamePatternHolder #generateResultStringForTimeElapsed: #ignoreCaseInDirectoryNameHolder #ignoreCaseInExcludedDirectoryNameHolder #ignoreCaseInExcludedNameHolder #ignoreCaseInNameHolder changed: #doSearch class: DirectoryDifferenceViewApplication class added: #documentation #examples changed: #helpSpec #windowSpec
DirectoryDifferenceViewApplication.st
--- a/DirectoryDifferenceViewApplication.st	Fri Aug 09 17:22:07 2019 +0200
+++ b/DirectoryDifferenceViewApplication.st	Fri Aug 09 17:22:23 2019 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 2006 by eXept Software AG
               All Rights Reserved
@@ -18,7 +20,11 @@
 		filesOnlyInDirectory1 filesOnlyInDirectory2
 		filesWhichAreDifferent directoriesOnlyInDirectory1
 		directoriesOnlyInDirectory2 namePatternHolder
-		excludedNamePatternHolder'
+		excludedNamePatternHolder excludedDirectoryNamePatternHolder
+		ignoreCaseInNameHolder ignoreCaseInExcludedNameHolder
+		ignoreCaseInExcludedDirectoryNameHolder
+		ignoreCaseInDirectoryNameHolder filesSkippedCount
+		directoriesSkippedCount'
 	classVariableNames:''
 	poolDictionaries:''
 	category:'Interface-Tools-File'
@@ -38,6 +44,58 @@
  other person.  No title to or ownership of the software is
  hereby transferred.
 "
+!
+
+documentation
+"
+    documentation to be added.
+
+    class:
+        <a short class summary here, describing what instances represent>
+
+    responsibilities:    
+        <describing what my main role is>
+
+    collaborators:    
+        <describing with whom and how I talk to>
+
+    API:
+        <public api and main messages>
+        
+    example:
+        <a one-line examples on how to use - can also be in a separate example method>
+
+    implementation:
+        <implementation points>
+
+    [author:]
+        exept MBP
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+!
+
+examples
+"
+ Notice that everything between [exBegin] and [exEnd] is extracted by the html-doc generator
+ to create nicely formatted and clickable executable examples in the generated html-doc.
+ (see the browser's class-documentation menu items for more)
+
+ opening the application:
+                                                        [exBegin]
+    DirectoryDifferenceViewApplication open
+                                                        [exEnd]
+
+ opening the application on some model:
+                                                        [exBegin]
+    DirectoryDifferenceViewApplication openOn:aModel
+                                                        [exEnd]
+"
 ! !
 
 !DirectoryDifferenceViewApplication class methodsFor:'help specs'!
@@ -50,18 +108,30 @@
      the UIHelpTool may not be able to read the specification."
 
     "
-     UIHelpTool openOnClass:FindFileApplication    
+     UIHelpTool openOnClass:DirectoryDifferenceViewApplication
     "
 
     <resource: #help>
 
     ^ super helpSpec addPairsFrom:#(
 
-#namePattern
-'Filename(s) to search for. Can be matchPatterns, separated by ";".\(eg. "*.c ; *.h" searches for C and header files. So does "*.[ch]")'
+#excludedDirectoryNamePattern
+'Directory name(s) to skip.\Can be matchPatterns, separated by ";"'
 
 #excludedNamePattern
-'Filename(s) to skip. Can be matchPatterns, separated by ";"'
+'File name(s) to skip.\Can be matchPatterns, separated by ";"'
+
+#ignoreCaseInExcludedDirectoryName
+'Ignore case in directory name exclude pattern(s)'
+
+#ignoreCaseInExcludedName
+'Ignore case in file name exclude pattern(s)'
+
+#ignoreCaseInName
+'Ignore case in file name pattern(s)'
+
+#namePattern
+'Filename(s) to search for.\Can be matchPatterns, separated by ";".\(eg. "*.c ; *.h" searches for C and header files. So does "*.[ch]")'
 
 #searchDirectory1
 'The first folder, to be compared against folder2'
@@ -70,8 +140,6 @@
 'The second folder, to be compared against folder1'
 
 )
-
-    "Modified: / 11-10-2017 / 15:49:43 / cg"
 ! !
 
 !DirectoryDifferenceViewApplication class methodsFor:'interface specs'!
@@ -92,163 +160,206 @@
     <resource: #canvas>
 
     ^ 
-     #(FullSpec
-        name: windowSpec
-        window: 
-       (WindowSpec
-          label: 'Directory Diff'
-          name: 'Directory Diff'
-          min: (Point 377 131)
-          bounds: (Rectangle 0 0 758 512)
-        )
-        component: 
-       (SpecCollection
-          collection: (
-           (MenuPanelSpec
-              name: 'ToolBar1'
-              layout: (LayoutFrame 0 0.0 0 0 0 1.0 32 0)
-              level: 0
-              menu: searchMenu
-              textDefault: true
-            )
-           (ProgressIndicatorSpec
-              name: 'ProgressIndicator1'
-              layout: (LayoutFrame 125 0 11 0 231 0 21 0)
-              visibilityChannel: enableStop
-              backgroundColor: (Color 0.0 66.9993133440146 66.9993133440146)
-              showPercentage: false
-              isActivityIndicator: true
-            )
-           (ViewSpec
-              name: 'Box1'
-              layout: (LayoutFrame 0 0.0 32 0 0 1.0 130 0)
-              component: 
-             (SpecCollection
-                collection: (
-                 (LabelSpec
-                    label: 'Directory1:'
-                    name: 'DirectoryLabel'
-                    layout: (LayoutFrame 2 0 7 0 154 0 24 0)
-                    activeHelpKey: searchDirectory1
-                    translateLabel: true
-                    adjust: right
-                  )
-                 (FilenameInputFieldSpec
-                    name: 'DirectoryEntryField'
-                    layout: (LayoutFrame 156 0 4 0 0 1 24 0)
-                    activeHelpKey: searchDirectory1
-                    model: directory1Holder
-                    immediateAccept: true
-                    acceptOnPointerLeave: false
-                  )
-                 (LabelSpec
-                    label: 'Directory2:'
-                    name: 'Label2'
-                    layout: (LayoutFrame 2 0 31 0 154 0 48 0)
-                    activeHelpKey: searchDirectory2
-                    translateLabel: true
-                    adjust: right
-                  )
-                 (FilenameInputFieldSpec
-                    name: 'FilenameEntryField1'
-                    layout: (LayoutFrame 156 0 28 0 0 1 48 0)
-                    activeHelpKey: searchDirectory2
-                    model: directory2Holder
-                    immediateAccept: true
-                    acceptOnPointerLeave: false
-                  )
-                 (LabelSpec
-                    label: 'Compare Files Named:'
-                    name: 'FileNameLabel'
-                    layout: (LayoutFrame 2 0 55 0 154 0 72 0)
-                    activeHelpKey: namePattern
-                    translateLabel: true
-                    adjust: right
-                  )
-                 (InputFieldSpec
-                    name: 'FileNameEntryField'
-                    layout: (LayoutFrame 156 0 52 0 -315 1 72 0)
-                    activeHelpKey: namePattern
-                    tabable: true
-                    model: namePatternHolder
-                    immediateAccept: true
-                    acceptOnLeave: false
-                    acceptOnPointerLeave: false
-                  )
-                 (CheckBoxSpec
-                    label: 'Ignore Case'
-                    name: 'IgnoreCaseInNameCheckBox'
-                    layout: (LayoutFrame -169 1 53 0 -4 1 76 0)
-                    activeHelpKey: ignoreCase
-                    tabable: true
-                    model: ignoreCaseInName
-                    translateLabel: true
-                  )
-                 (LabelSpec
-                    label: 'But Not Named:'
-                    name: 'Label1'
-                    layout: (LayoutFrame 2 0 79 0 154 0 96 0)
-                    activeHelpKey: excludedNamePattern
-                    translateLabel: true
-                    adjust: right
-                  )
-                 (InputFieldSpec
-                    name: 'EntryField1'
-                    layout: (LayoutFrame 156 0 76 0 -315 1 96 0)
-                    activeHelpKey: excludedNamePattern
-                    tabable: true
-                    model: excludedNamePatternHolder
-                    immediateAccept: true
-                    acceptOnLeave: false
-                    acceptOnPointerLeave: false
-                  )
-                 (CheckBoxSpec
-                    label: 'Ignore Case'
-                    name: 'CheckBox1'
-                    layout: (LayoutFrame -169 1 77 0 -4 1 100 0)
-                    activeHelpKey: ignoreCase
-                    tabable: true
-                    model: ignoreCaseInExcludedName
-                    translateLabel: true
-                  )
-                 )
-               
+    #(FullSpec
+       name: windowSpec
+       uuid: '523f01a8-baab-11e9-a284-10ddb1cc5928'
+       window: 
+      (WindowSpec
+         label: 'Directory Diff'
+         name: 'Directory Diff'
+         uuid: '09a5b9c0-baa9-11e9-a284-10ddb1cc5928'
+         min: (Point 377 131)
+         bounds: (Rectangle 0 0 758 512)
+      )
+       component: 
+      (SpecCollection
+         collection: (
+          (MenuPanelSpec
+             name: 'ToolBar1'
+             layout: (LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+             uuid: '09a5bd8a-baa9-11e9-a284-10ddb1cc5928'
+             level: 0
+             menu: searchMenu
+             textDefault: true
+          )
+          (ProgressIndicatorSpec
+             name: 'ProgressIndicator1'
+             layout: (LayoutFrame 125 0 11 0 231 0 21 0)
+             uuid: '09a5c06e-baa9-11e9-a284-10ddb1cc5928'
+             visibilityChannel: enableStop
+             backgroundColor: (Color 0.0 67.0 67.0)
+             showPercentage: false
+             isActivityIndicator: true
+          )
+          (ViewSpec
+             name: 'Box1'
+             layout: (LayoutFrame 0 0.0 32 0 0 1.0 154 0)
+             uuid: '09a5c2d0-baa9-11e9-a284-10ddb1cc5928'
+             component: 
+            (SpecCollection
+               collection: (
+                (LabelSpec
+                   label: 'Directory1:'
+                   name: 'DirectoryLabel'
+                   layout: (LayoutFrame 2 0 7 0 154 0 24 0)
+                   activeHelpKey: searchDirectory1
+                   uuid: '09a5c42e-baa9-11e9-a284-10ddb1cc5928'
+                   translateLabel: true
+                   adjust: right
+                )
+                (FilenameInputFieldSpec
+                   name: 'DirectoryEntryField'
+                   layout: (LayoutFrame 156 0 4 0 0 1 24 0)
+                   activeHelpKey: searchDirectory1
+                   uuid: '09a5c67c-baa9-11e9-a284-10ddb1cc5928'
+                   model: directory1Holder
+                   immediateAccept: true
+                   acceptOnPointerLeave: false
+                )
+                (LabelSpec
+                   label: 'Directory2:'
+                   name: 'Label2'
+                   layout: (LayoutFrame 2 0 31 0 154 0 48 0)
+                   activeHelpKey: searchDirectory2
+                   uuid: '09a5ca00-baa9-11e9-a284-10ddb1cc5928'
+                   translateLabel: true
+                   adjust: right
+                )
+                (FilenameInputFieldSpec
+                   name: 'FilenameEntryField1'
+                   layout: (LayoutFrame 156 0 28 0 0 1 48 0)
+                   activeHelpKey: searchDirectory2
+                   uuid: '09a5cb40-baa9-11e9-a284-10ddb1cc5928'
+                   model: directory2Holder
+                   immediateAccept: true
+                   acceptOnPointerLeave: false
+                )
+                (LabelSpec
+                   label: 'Compare Files Named:'
+                   name: 'FileNameLabel'
+                   layout: (LayoutFrame 2 0 55 0 154 0 72 0)
+                   activeHelpKey: namePattern
+                   uuid: '09a5ccda-baa9-11e9-a284-10ddb1cc5928'
+                   translateLabel: true
+                   adjust: right
+                )
+                (InputFieldSpec
+                   name: 'FileNameEntryField'
+                   layout: (LayoutFrame 156 0 52 0 -180 1 72 0)
+                   activeHelpKey: namePattern
+                   uuid: '09a5cdf2-baa9-11e9-a284-10ddb1cc5928'
+                   tabable: true
+                   model: namePatternHolder
+                   immediateAccept: true
+                   acceptOnLeave: false
+                   acceptOnPointerLeave: false
+                )
+                (CheckBoxSpec
+                   label: 'Ignore Case'
+                   name: 'IgnoreCaseInNameCheckBox'
+                   layout: (LayoutFrame -169 1 53 0 -4 1 76 0)
+                   activeHelpKey: ignoreCaseInName
+                   uuid: '09a5cfb4-baa9-11e9-a284-10ddb1cc5928'
+                   tabable: true
+                   model: ignoreCaseInNameHolder
+                   translateLabel: true
+                )
+                (LabelSpec
+                   label: 'But Not Named:'
+                   name: 'Label1'
+                   layout: (LayoutFrame 2 0 79 0 190 0 96 0)
+                   activeHelpKey: excludedNamePattern
+                   uuid: '09a5d16c-baa9-11e9-a284-10ddb1cc5928'
+                   translateLabel: true
+                   adjust: right
+                )
+                (InputFieldSpec
+                   name: 'EntryField1'
+                   layout: (LayoutFrame 190 0 76 0 -180 1 96 0)
+                   activeHelpKey: excludedNamePattern
+                   uuid: '09a5d284-baa9-11e9-a284-10ddb1cc5928'
+                   tabable: true
+                   model: excludedNamePatternHolder
+                   immediateAccept: true
+                   acceptOnLeave: false
+                   acceptOnPointerLeave: false
+                )
+                (CheckBoxSpec
+                   label: 'Ignore Case'
+                   name: 'CheckBox1'
+                   layout: (LayoutFrame -169 1 77 0 -4 1 100 0)
+                   activeHelpKey: ignoreCaseInExcludedName
+                   uuid: '09a5d414-baa9-11e9-a284-10ddb1cc5928'
+                   tabable: true
+                   model: ignoreCaseInExcludedNameHolder
+                   translateLabel: true
+                )
+                (LabelSpec
+                   label: 'Ignore Folders Named:'
+                   name: 'Label3'
+                   layout: (LayoutFrame 2 0 103 0 190 0 120 0)
+                   activeHelpKey: excludedDirectoryNamePattern
+                   uuid: '09a5d518-baa9-11e9-a284-10ddb1cc5928'
+                   translateLabel: true
+                   adjust: right
+                )
+                (InputFieldSpec
+                   name: 'EntryField2'
+                   layout: (LayoutFrame 190 0 100 0 -180 1 120 0)
+                   activeHelpKey: excludedDirectoryNamePattern
+                   uuid: '09a5d63a-baa9-11e9-a284-10ddb1cc5928'
+                   tabable: true
+                   model: excludedDirectoryNamePatternHolder
+                   immediateAccept: true
+                   acceptOnLeave: false
+                   acceptOnPointerLeave: false
+                )
+                (CheckBoxSpec
+                   label: 'Ignore Case'
+                   name: 'CheckBox2'
+                   layout: (LayoutFrame -169 1 101 0 -4 1 124 0)
+                   activeHelpKey: ignoreCaseInExcludedDirectoryName
+                   uuid: '09a5d7d4-baa9-11e9-a284-10ddb1cc5928'
+                   tabable: true
+                   model: ignoreCaseInExcludedDirectoryNameHolder
+                   translateLabel: true
+                )
               )
             )
-           (VariableVerticalPanelSpec
-              name: 'VariableVerticalPanel1'
-              layout: (LayoutFrame 0 0.0 140 0 0 1.0 0 1)
-              component: 
-             (SpecCollection
-                collection: (
-                 (DataSetSpec
-                    name: 'Table1'
-                    model: selectionHolder
-                    hasHorizontalScrollBar: true
-                    hasVerticalScrollBar: true
-                    dataList: matchedFilesList
-                    doubleClickSelector: fileDoubleClick:
-                    columnHolder: searchResultTable
-                    valueChangeSelector: fileSelected:
-                    multipleSelectOk: true
-                  )
-                 (ArbitraryComponentSpec
-                    name: 'DiffTextView'
-                    hasHorizontalScrollBar: true
-                    hasVerticalScrollBar: true
-                    component: DiffTextView
-                  )
-                 )
-               
+          )
+          (VariableVerticalPanelSpec
+             name: 'VariableVerticalPanel1'
+             layout: (LayoutFrame 0 0.0 164 0 0 1.0 0 1)
+             uuid: '09a5d914-baa9-11e9-a284-10ddb1cc5928'
+             component: 
+            (SpecCollection
+               collection: (
+                (DataSetSpec
+                   name: 'Table1'
+                   uuid: '09a5daa4-baa9-11e9-a284-10ddb1cc5928'
+                   model: selectionHolder
+                   hasHorizontalScrollBar: true
+                   hasVerticalScrollBar: true
+                   dataList: matchedFilesList
+                   doubleClickSelector: fileDoubleClick:
+                   columnHolder: searchResultTable
+                   valueChangeSelector: fileSelected:
+                   multipleSelectOk: true
+                )
+                (ArbitraryComponentSpec
+                   name: 'DiffTextView'
+                   uuid: '09a5deaa-baa9-11e9-a284-10ddb1cc5928'
+                   hasHorizontalScrollBar: true
+                   hasVerticalScrollBar: true
+                   component: DiffTextView
+                )
               )
-              handles: (Any 0.5 1.0)
             )
-           )
-         
+             handles: (Any 0.5 1.0)
+          )
         )
       )
-
-    "Modified: / 13-01-2012 / 14:41:56 / cg"
+    )
 ! !
 
 !DirectoryDifferenceViewApplication class methodsFor:'menu specs'!
@@ -400,6 +511,15 @@
 
 !DirectoryDifferenceViewApplication methodsFor:'aspects'!
 
+excludedDirectoryNamePatternHolder
+    excludedDirectoryNamePatternHolder isNil ifTrue:[
+        excludedDirectoryNamePatternHolder := '' asValue.
+    ].
+    ^ excludedDirectoryNamePatternHolder.
+
+    "Created: / 13-01-2012 / 14:42:47 / cg"
+!
+
 excludedNamePatternHolder
     excludedNamePatternHolder isNil ifTrue:[
         excludedNamePatternHolder := '' asValue.
@@ -409,6 +529,46 @@
     "Created: / 13-01-2012 / 14:42:47 / cg"
 !
 
+ignoreCaseInDirectoryNameHolder
+
+    ignoreCaseInDirectoryNameHolder isNil ifTrue:[
+        ignoreCaseInDirectoryNameHolder := true asValue.
+    ].
+    ^ ignoreCaseInDirectoryNameHolder.
+
+    "Created: / 13-01-2012 / 14:37:28 / cg"
+!
+
+ignoreCaseInExcludedDirectoryNameHolder
+
+    ignoreCaseInExcludedDirectoryNameHolder isNil ifTrue:[
+        ignoreCaseInExcludedDirectoryNameHolder := true asValue.
+    ].
+    ^ ignoreCaseInExcludedDirectoryNameHolder.
+
+    "Created: / 13-01-2012 / 14:37:28 / cg"
+!
+
+ignoreCaseInExcludedNameHolder
+
+    ignoreCaseInExcludedNameHolder isNil ifTrue:[
+        ignoreCaseInExcludedNameHolder := true asValue.
+    ].
+    ^ ignoreCaseInExcludedNameHolder.
+
+    "Created: / 13-01-2012 / 14:37:28 / cg"
+!
+
+ignoreCaseInNameHolder
+
+    ignoreCaseInNameHolder isNil ifTrue:[
+        ignoreCaseInNameHolder := true asValue.
+    ].
+    ^ ignoreCaseInNameHolder.
+
+    "Created: / 13-01-2012 / 14:37:28 / cg"
+!
+
 namePatternHolder
 
     namePatternHolder isNil ifTrue:[
@@ -422,7 +582,10 @@
 !DirectoryDifferenceViewApplication methodsFor:'comparing'!
 
 doSearch
-    |dir1 dir2 namePattern namePatterns excludedNamePattern excludedNamePatterns|
+    |dir1 dir2 
+     namePattern excludedNamePattern excludedDirectoryNamePattern 
+     ignoreCaseInName ignoreCaseInExcludeName ignoreCaseInExcludeDirectoryName
+     fileExcludeFilterOrNil directoryExcludeFilterOrNil checkDir|
 
     filesOnlyInDirectory1 := OrderedCollection new.
     filesOnlyInDirectory2 := OrderedCollection new.
@@ -430,6 +593,8 @@
     directoriesOnlyInDirectory2 := OrderedCollection new.
     filesWhichAreDifferent := OrderedCollection new.
 
+    filesSkippedCount := directoriesSkippedCount := 0.
+
     dir1 := self directory1Holder value.
     dir1 isNil ifTrue:[^ self].
 
@@ -446,14 +611,47 @@
 
     namePattern := self namePatternHolder value.
     namePattern notEmptyOrNil ifTrue:[
-        namePatterns := namePattern asCollectionOfSubstringsSeparatedByAny:',;'.
-        namePatterns := namePatterns collect:[:p | p withoutSeparators ].
+        namePattern := namePattern withoutSeparators.
+        (namePattern isEmptyOrNil or:[namePattern = '*']) ifTrue:[
+            namePattern := nil
+        ]
     ].
+
+    ignoreCaseInName := self ignoreCaseInNameHolder value.
+    ignoreCaseInExcludeName := self ignoreCaseInExcludedNameHolder value.
+    ignoreCaseInExcludeDirectoryName := self ignoreCaseInExcludedDirectoryNameHolder value.
+
     excludedNamePattern := self excludedNamePatternHolder value.
     excludedNamePattern notEmptyOrNil ifTrue:[
-        excludedNamePatterns := excludedNamePattern asCollectionOfSubstringsSeparatedByAny:',;'.
-        excludedNamePatterns := excludedNamePatterns collect:[:p | p withoutSeparators ].
+        excludedNamePattern := excludedNamePattern withoutSeparators.
+        excludedNamePattern notEmptyOrNil ifTrue:[
+            fileExcludeFilterOrNil := 
+                ignoreCaseInExcludeName 
+                    ifTrue:[  [:baseName | (excludedNamePattern compoundMatch:baseName caseSensitive:false) not ] ]
+                    ifFalse:[  [:baseName | (excludedNamePattern compoundMatch:baseName caseSensitive:true) not ] ].
+        ].
     ].
+
+    excludedDirectoryNamePattern := self excludedDirectoryNamePatternHolder value.
+    excludedDirectoryNamePattern notEmptyOrNil ifTrue:[
+        excludedDirectoryNamePattern := excludedDirectoryNamePattern withoutSeparators.
+        excludedDirectoryNamePattern notEmptyOrNil ifTrue:[
+            checkDir := 
+                ignoreCaseInExcludeDirectoryName 
+                    ifTrue:[ [:dir | (excludedDirectoryNamePattern compoundMatch:(dir baseName) caseSensitive:false) not ] ]
+                    ifFalse:[ [:dir | (excludedDirectoryNamePattern compoundMatch:(dir baseName) caseSensitive:true) not ] ].
+            directoryExcludeFilterOrNil := 
+                [:fn |
+                    (checkDir value:fn) ifFalse:[
+                        directoriesSkippedCount := directoriesSkippedCount + 1.
+                        false.
+                    ] ifTrue:[
+                        true
+                    ]
+                ].
+        ].
+    ].
+
     self matchedFilesList removeAll.
     self windowGroup repairDamage.
 
@@ -463,51 +661,71 @@
 
             self shownListHolder valueHolder:(self matchedFilesList).
 
-            dir1 recursiveDirectoryContentsDo:[:relFn1 |
-                |fn1 fn2|
+            dir1 
+                recursiveDirectoryContentsDo:[:relFn1 |
+                    |fn1 fn2 fn1BaseName|
 
-                fn1 := dir1 construct:relFn1.
-                (namePatterns isNil or:[namePatterns contains:[:p | p match:fn1 baseName]]) ifTrue:[
-                    (excludedNamePatterns notNil and:[excludedNamePatterns contains:[:p | p match:fn1 baseName]]) ifFalse:[
-                        fn2 := dir2 construct:relFn1.
-                        fn1 isDirectory ifTrue:[
-                            self notify:('Comparing %1...' bindWith:relFn1 asString allBold).
-                            fn2 exists ifFalse:[
-                                directoriesOnlyInDirectory1 add:fn1.
-                                self matchedFilesList add:{ relFn1 . 'Directory only in directory1' }.
-                            ].
-                        ] ifFalse:[
-                            fn2 exists ifTrue:[
-                                (fn1 sameContentsAs:fn2) ifFalse:[
-                                    filesWhichAreDifferent add:fn1.
-                                    self matchedFilesList add:{ relFn1 . 'Different' }.
+                    fn1 := dir1 construct:relFn1.
+                    fn1BaseName := fn1 baseName.
+                    (namePattern isNil or:[namePattern compoundMatch:fn1BaseName caseSensitive:ignoreCaseInName not]) ifTrue:[
+                        (fileExcludeFilterOrNil isNil or:[fileExcludeFilterOrNil value:fn1BaseName]) ifTrue:[
+                            fn2 := dir2 construct:relFn1.
+                            fn1 isDirectory ifTrue:[
+                                self notify:('Comparing %1...' bindWith:relFn1 asString allBold).
+                                fn2 exists ifFalse:[
+                                    directoriesOnlyInDirectory1 add:fn1.
+                                    self matchedFilesList add:{ relFn1 . 'Directory only in directory1' }.
                                 ].
                             ] ifFalse:[
-                                filesOnlyInDirectory1 add:fn1.
-                                self matchedFilesList add:{ relFn1 . 'File only in directory1' }.
+                                fn2 exists ifTrue:[
+                                    filesSearchedCount := filesSearchedCount + 1.
+                                    (fn1 sameContentsAs:fn2) ifFalse:[
+                                        filesWhichAreDifferent add:fn1.
+                                        self matchedFilesList add:{ relFn1 . 'Different' }.
+                                    ].
+                                ] ifFalse:[
+                                    filesOnlyInDirectory1 add:fn1.
+                                    self matchedFilesList add:{ relFn1 . 'File only in directory1' }.
+                                ].
                             ].
-                        ].
+                        ] ifFalse:[
+                            filesSkippedCount := filesSkippedCount + 1.
+                        ]
                     ]
                 ]
-            ].
-            dir2 recursiveDirectoryContentsDo:[:relFn2 |
-                |fn1 fn2|
+                filterForVisitingDirectories:directoryExcludeFilterOrNil.
+
+            dir2 
+                recursiveDirectoryContentsDo:[:relFn2 |
+                    |fn1 fn2 fn2BaseName|
 
-                fn2 := dir2 construct:relFn2.
-                (namePatterns isNil or:[namePatterns contains:[:p | p match:fn2 baseName]]) ifTrue:[
-                    (excludedNamePatterns notNil and:[excludedNamePatterns contains:[:p | p match:fn2 baseName]]) ifFalse:[
-                        fn1 := dir1 construct:relFn2.
-                        fn1 exists ifFalse:[
-                            fn1 isDirectory ifTrue:[
-                                directoriesOnlyInDirectory1 add:fn1.
-                                self matchedFilesList add:{ relFn2 . 'Directory only in directory2' }.
-                            ] ifFalse:[
-                                filesOnlyInDirectory2 add:fn2.
-                                self matchedFilesList add:{ relFn2 . 'File only in directory2' }.
-                            ]
+                    fn2 := dir2 construct:relFn2.
+                    fn2BaseName := fn2 baseName.
+                    (namePattern isNil or:[namePattern compoundMatch:fn2BaseName caseSensitive:ignoreCaseInName not]) ifTrue:[
+                        (fileExcludeFilterOrNil isNil or:[fileExcludeFilterOrNil value:fn2BaseName]) ifFalse:[
+                            fn1 := dir1 construct:relFn2.
+                            fn1 exists ifFalse:[
+                                fn1 isDirectory ifTrue:[
+                                    directoriesOnlyInDirectory1 add:fn1.
+                                    self matchedFilesList add:{ relFn2 . 'Directory only in directory2' }.
+                                ] ifFalse:[
+                                    filesOnlyInDirectory2 add:fn2.
+                                    self matchedFilesList add:{ relFn2 . 'File only in directory2' }.
+                                ]
+                            ].
                         ].
-                    ].
+                    ] ifFalse:[
+                        filesSkippedCount := filesSkippedCount + 1.
+                    ]
                 ]
+                filterForVisitingDirectories:directoryExcludeFilterOrNil.
+
+            Transcript showCR:'--- search summary ------'.
+            directoriesSkippedCount ~~ 0 ifTrue:[
+                Transcript showCR:'%1 directories skipped' with:directoriesSkippedCount.
+            ].
+            filesSkippedCount ~~ 0 ifTrue:[
+                Transcript showCR:'%1 files skipped' with:filesSkippedCount.
             ].
             filesOnlyInDirectory1 notEmpty ifTrue:[
                 Transcript showCR:'%1 files only in directory1' with:filesOnlyInDirectory1 size.
@@ -529,6 +747,29 @@
 
     "Created: / 12-01-2012 / 01:07:20 / cg"
     "Modified: / 15-02-2019 / 09:42:51 / Claus Gittinger"
+!
+
+generateResultStringForTimeElapsed:timeDuration
+    "at the end of a search, generate a nice informative summary string.
+     Redefined to generate a different message."
+
+    |timeMillis timeString nIn1 nIn2 nDifferent|
+
+    timeMillis := timeDuration asMilliseconds.
+    timeString := timeDuration printStringForApproximation.
+
+    nIn1 := filesOnlyInDirectory1 size.
+    nIn2 := filesOnlyInDirectory1 size.
+    nDifferent := filesWhichAreDifferent size.
+
+    ^ resources 
+        string:('different:%1, only in one:%2 / %3 (%4 files visited; %6 files/s).') 
+        with:nDifferent 
+        with:nIn1 
+        with:nIn2
+        with:filesSearchedCount
+        with:(UnitConverter fileSizeSIStringFor:(bytesSearchedCount * 1000 / (timeMillis max:1)))
+        with:((filesSearchedCount * 1000 / (timeMillis max:1)) asFixedPoint:1).
 ! !
 
 !DirectoryDifferenceViewApplication methodsFor:'startup & release'!