TextView.st
branchjv
changeset 5562 0219152fb99f
parent 5552 58ac0bd34b7b
parent 5561 ee6a77852e84
child 5616 60d4ad0cccfb
--- a/TextView.st	Sat Jan 16 10:40:59 2016 +0000
+++ b/TextView.st	Tue Jan 19 07:05:36 2016 +0000
@@ -30,7 +30,8 @@
 		WordSelectCatchesBlanks LastSearchPatterns
 		NumRememberedSearchPatterns LastSearchIgnoredCase
 		LastSearchWasMatch DefaultParenthesisSpecification
-		LastSearchWasMatchWithRegex LastSearchWasWrapAtEndOfText'
+		LastSearchWasMatchWithRegex LastSearchWasWrapAtEndOfText
+		LastSearchWasReplace LastSearchReplacedString'
 	poolDictionaries:''
 	category:'Views-Text'
 !
@@ -355,6 +356,17 @@
 #selectLines
 'If checked, lines containing the matched string are selected.'
 
+#replacePreserveCase
+'Preserve the case of replaced text'
+
+#replaceAll
+'Search and replace all occurrences of the searched string'
+
+#searchWithWrap
+'Wrap around at the end of the text, an continue the search from the top'
+
+#matchWithRegex
+'Use regex pattern for search (as opposed to glob pattern)'
 )
 ! !
 
@@ -382,7 +394,7 @@
 	 name: 'String search'
 	 min: (Point 10 10)
 	 max: (Point 1280 1024)
-         bounds: (Rectangle 0 0 420 323)
+         bounds: (Rectangle 0 0 429 349)
        )
        component:
       (SpecCollection
@@ -426,7 +438,7 @@
 		   tabable: true
 		   model: caseSensitive
 		   translateLabel: true
-                   extent: (Point 420 24)
+                   extent: (Point 429 24)
 		 )
                 (ViewSpec
                    name: 'MatchBox'
@@ -447,15 +459,15 @@
                          label: 'Regex Match'
                          name: 'CheckBox6'
                          layout: (LayoutFrame -151 1 0 0 0 1 22 0)
-                         visibilityChannel: matchWithRegexVisible
-                         enableChannel: match
+                         activeHelpKey: matchWithRegex
+                         enableChannel: matchWithRegexVisible
                          model: matchWithRegex
                          translateLabel: true
                        )
                       )
                     
                    )
-                   extent: (Point 420 24)
+                   extent: (Point 429 24)
 		 )
 		(CheckBoxSpec
 		   label: 'Search Full Words'
@@ -466,7 +478,7 @@
 		   tabable: true
 		   model: searchFullWord
 		   translateLabel: true
-                   extent: (Point 420 24)
+                   extent: (Point 429 24)
                  )
                 (CheckBoxSpec
                    label: 'At Begin of Line Only'
@@ -476,7 +488,7 @@
                    tabable: true
                    model: searchAtBeginOfLineOnly
                    translateLabel: true
-                   extent: (Point 420 24)
+                   extent: (Point 429 24)
 		 )
 		(CheckBoxSpec
 		   label: 'Variable Only'
@@ -489,7 +501,7 @@
 		   model: searchVariable
 		   translateLabel: true
 		   labelChannel: stringWithVariableUnderCursorHolder
-                   extent: (Point 420 24)
+                   extent: (Point 429 24)
 		 )
 		(CheckBoxSpec
 		   label: 'Select Lines'
@@ -505,32 +517,36 @@
                 (CheckBoxSpec
                    label: 'Wrap at End of Text (forward only)'
                    name: 'CheckBox7'
-                   activeHelpKey: searchAtBeginOfLineOnly
+                   activeHelpKey: searchWithWrap
                    level: 0
                    tabable: true
                    model: wrapAtEndOfTextHolder
                    translateLabel: true
-                   extent: (Point 420 24)
+                   extent: (Point 429 24)
                  )
-		(ViewSpec
-                   name: 'ReplaceBox'
+                (HorizontalPanelViewSpec
+                   name: 'HorizontalPanel1'
+                   horizontalLayout: leftFit
+                   verticalLayout: fit
+                   ignoreInvisibleComponents: false
+                   elementsChangeSize: true
 		   component:
 		  (SpecCollection
 		     collection: (
 		      (CheckBoxSpec
-			 label: 'Global Replace With:'
+                         label: 'Replace By:'
 			 name: 'CheckBox4'
-                         layout: (LayoutFrame 0 0 0 0 180 0 23 0)
 			 activeHelpKey: replaceText
 			 level: 0
 			 enableChannel: replaceEnabled
 			 tabable: true
 			 model: replaceBoolean
 			 translateLabel: true
+                         resizeForLabel: true
+                         useDefaultExtent: true
 		       )
 		      (InputFieldSpec
 			 name: 'ReplaceEntryField'
-                         layout: (LayoutFrame 180 0 0 0 -2 1 22 0)
 			 activeHelpKey: replaceText
 			 visibilityChannel: replaceBoolean
 			 enableChannel: replaceBoolean
@@ -538,11 +554,34 @@
 			 acceptOnReturn: true
 			 acceptOnTab: true
 			 acceptOnPointerLeave: true
+                         extent: (Point 299 24)
 		       )
 		      )
 
 		   )
-                   extent: (Point 420 24)
+                   extent: (Point 429 24)
+                 )
+                (CheckBoxSpec
+                   label: '  Replace All (to End of Text)'
+                   name: 'CheckBox8'
+                   activeHelpKey: replaceAll
+                   level: 0
+                   enableChannel: replaceBoolean
+                   tabable: true
+                   model: replaceAllBoolean
+                   translateLabel: true
+                   extent: (Point 429 24)
+                 )
+                (CheckBoxSpec
+                   label: '  Preserve Case'
+                   name: 'CheckBox9'
+                   activeHelpKey: replacePreserveCase
+                   level: 0
+                   enableChannel: replaceBoolean
+                   tabable: true
+                   model: replacePreserveCaseBoolean
+                   translateLabel: true
+                   extent: (Point 429 24)
 		 )
 		)
 
@@ -2211,7 +2250,8 @@
      fwd ign match initialString
      bindings bldr doSearch modal searchVariableHolder selectedVariable searchFullWordHolder
      replaceBooleanEnabledHolder replaceBooleanHolder replaceTextHolder
-     searchAtBeginOfLineOnlyHolder|
+     replaceAllBooleanHolder replacePreserveCaseBooleanHolder
+     searchAtBeginOfLineOnlyHolder updateReturnKeyBehavior|
 
     searchBarActionBlock notNil ifTrue:[
 	self resetVariablesBeforeNewSearch.
@@ -2231,8 +2271,10 @@
     searchVariableHolder := (lastSearchWasVariableSearch ? false) asValue.
     searchFullWordHolder := false asValue.
     searchAtBeginOfLineOnlyHolder := false asValue.
-    replaceBooleanHolder := false asValue.
-    replaceTextHolder := '' asValue.
+    replaceBooleanHolder := ("LastSearchWasReplace ?" false) asValue.
+    replaceAllBooleanHolder := false asValue.
+    replacePreserveCaseBooleanHolder := false asValue.
+    replaceTextHolder := (LastSearchReplacedString ? '') asValue.
     replaceBooleanEnabledHolder := self isReadOnly not asValue.
 
     patternHolder := '' asValue.
@@ -2268,34 +2310,42 @@
 				and:[selectedVariable notNil]].
 
 	isVariableSearch ifTrue:[
-	    searchAction := [self searchVariableWithSyntaxElement:selectedVariable forward:fwd].
+            searchAction := 
+                [
+                    self searchVariableWithSyntaxElement:selectedVariable forward:fwd
+                ].
 	] ifFalse:[
 	    lastSearchWasVariableSearch := false.
 	    LastSearchIgnoredCase := lastSearchIgnoredCase := (caseHolder value not).
 	    LastSearchWasMatch := lastSearchWasMatch := matchHolder value.
             LastSearchWasMatchWithRegex := matchWithRegexHolder value.
             LastSearchWasWrapAtEndOfText := wrapAtEndHolder value.
+            LastSearchWasReplace :=replaceBooleanHolder value.
+            LastSearchReplacedString := replaceTextHolder value.
+            
 	    pattern := patternHolder value.
 	    pattern notEmptyOrNil ifTrue:[
-		searchAction := [
-		    self searchUsingSpec:(
-			ListView::SearchSpec new
-			    pattern:pattern
-			    ignoreCase:lastSearchIgnoredCase
-                            match: lastSearchWasMatch 
-                            regexMatch:matchWithRegexHolder value 
-			    variable: searchVariableHolder value
-			    fullWord: searchFullWordHolder value
-                            forward:fwd
-                            atBeginOfLineOnly:searchAtBeginOfLineOnlyHolder value
-                            wrapAtEnd:wrapAtEndHolder value).
-		]
+                searchAction := 
+                    [
+                        self searchUsingSpec:(
+                            ListView::SearchSpec new
+                                pattern:pattern
+                                ignoreCase:lastSearchIgnoredCase
+                                match: lastSearchWasMatch 
+                                regexMatch:matchWithRegexHolder value 
+                                variable: searchVariableHolder value
+                                fullWord: searchFullWordHolder value
+                                forward:fwd
+                                atBeginOfLineOnly:searchAtBeginOfLineOnlyHolder value
+                                wrapAtEnd:wrapAtEndHolder value).
+                    ]
 	    ]
 	].
 
 	replaceBooleanHolder value ifTrue:[
-	    |selStart|
-
+            |selStart replacement replaceAction|
+
+            replacement := replaceTextHolder value.
 	    isVariableSearch ifTrue:[
 		"/ must replace from the end towards beginning,
 		"/ because syntax-elements do not update their position, when
@@ -2303,23 +2353,39 @@
 
 		selectedVariable := selectedVariable lastElementInChain.
 		self selectFromCharacterPosition:selectedVariable start to:selectedVariable stop.
-		searchAction := [selectedVariable := selectedVariable previousElement.
-				 selectedVariable notNil ifTrue:[
-				     self selectFromCharacterPosition:selectedVariable start to:selectedVariable stop.
-				 ].
-				 "/ self searchVariableWithSyntaxElement:selectedVariable forward:false
-				].
+                searchAction := 
+                    [
+                        selectedVariable := selectedVariable previousElement.
+                        selectedVariable notNil ifTrue:[
+                            self selectFromCharacterPosition:selectedVariable start to:selectedVariable stop.
+                        ].
+                        "/ self searchVariableWithSyntaxElement:selectedVariable forward:false
+                    ].
 	    ].
 
+            replaceAction := [ self replace:replacement ].
+            replacePreserveCaseBooleanHolder value ifTrue:[
+                replaceAction := [
+                    self selectionAsString isUppercaseFirst ifTrue:[
+                        self replace:replacement asUppercaseFirst
+                    ] ifFalse:[
+                        self replace:replacement asLowercaseFirst
+                    ]
+                ].    
+            ].    
+
 	    selStart := self characterPositionOfSelection.
-	    self replace:(replaceTextHolder value).
-
+
+            replaceAction value.
 	    searchAction value.
-	    [self characterPositionOfSelection ~= selStart] whileTrue:[
-		selStart := self characterPositionOfSelection.
-		self replace:(replaceTextHolder value).
-		searchAction value.
-	    ]
+            
+            replaceAllBooleanHolder value ifTrue:[
+                [self characterPositionOfSelection ~= selStart] whileTrue:[
+                    selStart := self characterPositionOfSelection.
+                    replaceAction value.
+                    searchAction value.
+                ]
+            ]
 	] ifFalse:[
 	    searchAction value.
 	].
@@ -2328,11 +2394,23 @@
     bindings := IdentityDictionary new.
     bindings at:#searchPattern put:patternHolder.
     modal ifTrue:[
-	bindings at:#nextAction put:[searchBox doAccept.].
-	bindings at:#prevAction put:[fwd := false. searchBox doAccept.].
+        bindings at:#nextAction put:[
+            replaceAllBooleanHolder value ifTrue:[
+                searchBox doAccept.
+            ] ifFalse:[
+                doSearch value:true
+            ]    
+        ].
+        bindings at:#prevAction put:[
+            replaceAllBooleanHolder value ifTrue:[
+                fwd := false. searchBox doAccept.
+            ] ifFalse:[
+                doSearch value:false
+            ]    
+        ].
     ] ifFalse:[
-	bindings at:#nextAction put:[doSearch value:true.  "searchBox doAccept."].
-	bindings at:#prevAction put:[doSearch value:false. "fwd := false. searchBox doAccept."].
+        bindings at:#nextAction put:[doSearch value:true.].
+        bindings at:#prevAction put:[doSearch value:false.].
     ].
     bindings at:#caseSensitive put:caseHolder.
     bindings at:#match put:matchHolder.
@@ -2370,7 +2448,28 @@
     
     bindings at:#replaceEnabled put:replaceBooleanEnabledHolder.
     bindings at:#replaceBoolean put:replaceBooleanHolder.
+    bindings at:#replaceAllBoolean put:replaceAllBooleanHolder.
+    bindings at:#replacePreserveCaseBoolean put:replacePreserveCaseBooleanHolder.
     bindings at:#replaceTextHolder put:replaceTextHolder.
+
+    bindings at:#flyByHelpSpec put:self class flyByHelpSpec.
+    
+    updateReturnKeyBehavior :=
+        [
+            |lbl returnAction|
+            
+            "/ when replacing, do not close box on return    
+            replaceBooleanHolder value ifTrue:[
+                lbl := 'Close'.
+                returnAction := searchAction.        
+            ] ifFalse:[
+                lbl := 'Cancel'.
+                returnAction := nil.        
+            ].
+            (bldr componentAt:#cancelButton) label:(resources string:lbl).
+            searchBox window keyboardProcessor returnAction:returnAction.        
+        ].
+    
     replaceBooleanHolder onChangeEvaluate:
 	[
 	    replaceBooleanHolder value ifTrue:[
@@ -2378,7 +2477,9 @@
 	    ] ifFalse:[
 		(bldr componentAt:#patternComboBox) requestFocus
 	    ].
+            updateReturnKeyBehavior value.
 	].
+
     modal ifTrue:[
 	searchBox := SimpleDialog new.
     ] ifFalse:[
@@ -2397,7 +2498,8 @@
     (bldr componentAt:#cancelButton) cursor:(Cursor thumbsDown).
 
     modal ifTrue:[
-	searchBox openDialog.
+        updateReturnKeyBehavior value.
+        searchBox openDialogAtPointer.
 	searchBox accepted ifTrue:[ doSearch value:fwd ].
     ] ifFalse:[
 	(bldr componentAt:#nextButton) isReturnButton:false.