*** empty log message ***
authorClaus Gittinger <cg@exept.de>
Mon, 09 Jan 2006 09:49:39 +0100
changeset 3235 422c2db64114
parent 3234 1cfdfd31f67b
child 3236 aeb1fe5a6ead
*** empty log message ***
EditTextView.st
PopUpMenu.st
--- a/EditTextView.st	Mon Jan 09 09:35:37 2006 +0100
+++ b/EditTextView.st	Mon Jan 09 09:49:39 2006 +0100
@@ -19,8 +19,8 @@
 		cursorTypeNoFocus typeOfSelection lastString lastReplacement
 		lastAction replacing showMatchingParenthesis hasKeyboardFocus
 		acceptAction lockUpdates tabMeansNextField autoIndent insertMode
-		trimBlankLines wordWrap replacementWordSelectStyle acceptChannel
-		acceptEnabled st80Mode disableIfInvisible
+		editMode trimBlankLines wordWrap replacementWordSelectStyle
+		acceptChannel acceptEnabled st80Mode disableIfInvisible
 		cursorMovementWhenUpdating learnMode learnedMacro
 		cursorLineHolder cursorColHolder dropTarget tabRequiresControl
 		undoSupport'
@@ -52,6 +52,34 @@
 	privateIn:EditTextView
 !
 
+Object subclass:#EditMode
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:EditTextView
+!
+
+EditTextView::EditMode subclass:#InsertAndSelectMode
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:EditTextView::EditMode
+!
+
+EditTextView::EditMode subclass:#InsertMode
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:EditTextView::EditMode
+!
+
+EditTextView::EditMode subclass:#OverwriteMode
+	instanceVariableNames:''
+	classVariableNames:'InsertMode OverwriteMode InsertAndSelectMode'
+	poolDictionaries:''
+	privateIn:EditTextView::EditMode
+!
+
 EditTextView::EditAction subclass:#InsertCharacter
 	instanceVariableNames:'line col character'
 	classVariableNames:''
@@ -73,6 +101,13 @@
 	privateIn:EditTextView
 !
 
+EditTextView::EditAction subclass:#ReplaceCharacters
+	instanceVariableNames:'line col1 col2 characters'
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:EditTextView
+!
+
 EditTextView::EditAction subclass:#ReplaceContents
 	instanceVariableNames:'text'
 	classVariableNames:''
@@ -721,6 +756,22 @@
     typeOfSelection := #paste
 !
 
+editModeHolder
+    ^ editMode.
+!
+
+editModeInsert
+    editMode value:EditMode insertMode
+!
+
+editModeInsertAndSelect
+    editMode value:EditMode insertAndSelectMode
+!
+
+editModeOverwrite
+    editMode value:EditMode overwriteMode
+!
+
 exceptionBlock:aBlock
     "define the action to be triggered when user tries to modify
      readonly text"
@@ -729,13 +780,19 @@
 !
 
 insertMode:aBoolean
-    insertMode value:aBoolean
+    editMode value:(aBoolean ifTrue:[EditMode insertMode] ifFalse:[EditMode overwriteMode])
 
     "Created: 6.3.1996 / 12:24:05 / cg"
 !
 
 insertModeHolder
-    ^ insertMode
+    ^ BlockValue
+        with:[:m | m value isInsertMode] 
+        argument:(editMode).
+!
+
+isInInsertMode 
+    ^ editMode value isInsertMode
 !
 
 isReadOnly
@@ -750,18 +807,17 @@
     "a valueHolder, which contains 'L' (learnMode), I (insertMode) or empty"
 
     ^ BlockValue
-	with:[:i :l |
-	    l value
-		ifTrue:[
-		    'L' asText allBold colorizeAllWith:Color red]
-		ifFalse:[
-		    i value
-			ifTrue:[
-			    'I']
-			ifFalse:[
-			    nil]]]
-	argument:(self insertModeHolder)
-	argument:(self learnModeHolder).
+        with:[:e :l |
+            self isReadOnly ifTrue:[
+                ''
+            ] ifFalse:[
+                l value
+                    ifTrue:[
+                        'L' asText allBold colorizeAllWith:Color red]
+                    ifFalse:[
+                        e value infoPrintString]]]
+        argument:(self editModeHolder)
+        argument:(self learnModeHolder).
 !
 
 modified
@@ -2764,7 +2820,7 @@
                 lastReplacement := lastReplacement copyWith:something.
 "/            ]
         ].
-        insertMode value ifTrue:[
+        self isInInsertMode ifTrue:[
             self insertCharAtCursor:something
         ] ifFalse:[
             self replaceCharAtCursor:something
@@ -2772,7 +2828,7 @@
     ] ifFalse:[
         something isString ifTrue:[
             lastReplacement := something.
-            insertMode value ifTrue:[
+            self isInInsertMode ifTrue:[
                 self insertStringAtCursor:something
             ] ifFalse:[
                 self replaceStringAtCursor:something
@@ -3149,6 +3205,56 @@
     "Modified: / 10.6.1998 / 18:50:18 / cg"
 !
 
+basicReplaceString:aString atLine:lineNr col:colNr
+    "replace multiple characters starting at lineNr/colNr.
+     This is not prepared to encounter special chars (except TAB)
+     in the string."
+
+    |line lineSize newLine endCol|
+
+    self checkModificationsAllowed ifFalse:[ ^ self].
+
+    self checkForExistingLine:lineNr.
+    line := list at:lineNr.
+    lineSize := line size.
+
+    endCol := colNr + aString size - 1.
+    (lineSize == 0) ifTrue:[
+        newLine := aString species new:endCol.
+    ] ifFalse: [
+        (endCol > lineSize) ifTrue: [
+            aString isText ifTrue:[
+                newLine := aString species new:endCol.
+            ] ifFalse:[
+                newLine := line species new:endCol.
+            ].
+            newLine replaceFrom:1 to:lineSize with:line startingAt:1.
+        ] ifFalse: [
+            aString isText ifTrue:[
+                newLine := aString species new:line size.
+                newLine replaceFrom:1 to:lineSize with:line startingAt:1.
+            ] ifFalse:[
+                newLine := line copy.
+            ]
+        ]
+    ].
+    newLine replaceFrom:colNr with:aString.
+    (aString includes:(Character tab)) ifTrue:[
+        newLine := self withTabsExpanded:newLine.
+    ].
+    list at:lineNr put:newLine.
+    widthOfWidestLine notNil ifTrue:[
+        widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line).
+    ].
+    self textChanged.
+    shown ifTrue:[
+        self redrawLine:lineNr from:colNr
+    ]
+
+    "Created: / 11.6.1998 / 10:38:32 / cg"
+    "Modified: / 20.6.1998 / 20:23:50 / cg"
+!
+
 basicSplitLine:lineNr before:colNr
     "split the line linNr before colNr; the right part (from colNr)
      is cut off and inserted after lineNr; the view is redrawn"
@@ -3512,7 +3618,7 @@
 
     originalChar := self characterAtLine:lineNr col:colNr.
     self basicReplace:aCharacter atLine:lineNr col:colNr.
-    self addUndo:(ReplaceCharacter line:lineNr col:colNr character:originalChar info:'replace').
+    self addUndo:(ReplaceCharacters line:lineNr col:colNr character:originalChar info:'replace').
 !
 
 replaceContentsWith:newContents
@@ -3538,52 +3644,16 @@
 
 replaceString:aString atLine:lineNr col:colNr
     "replace multiple characters starting at lineNr/colNr.
-     This is not prepared to encounter special chars (except TAB)
-     in the string."
-
-    |line lineSize newLine endCol|
+     This is not prepared to encounter special chars (except TAB) in the string."
+
+    |originalString|
 
     self checkModificationsAllowed ifFalse:[ ^ self].
 
-    self checkForExistingLine:lineNr.
-    line := list at:lineNr.
-    lineSize := line size.
-
-    endCol := colNr + aString size - 1.
-    (lineSize == 0) ifTrue:[
-	newLine := aString species new:endCol.
-    ] ifFalse: [
-	(endCol > lineSize) ifTrue: [
-	    aString isText ifTrue:[
-		newLine := aString species new:endCol.
-	    ] ifFalse:[
-		newLine := line species new:endCol.
-	    ].
-	    newLine replaceFrom:1 to:lineSize with:line startingAt:1.
-	] ifFalse: [
-	    aString isText ifTrue:[
-		newLine := aString species new:line size.
-		newLine replaceFrom:1 to:lineSize with:line startingAt:1.
-	    ] ifFalse:[
-		newLine := line copy.
-	    ]
-	]
-    ].
-    newLine replaceFrom:colNr with:aString.
-    (aString includes:(Character tab)) ifTrue:[
-	newLine := self withTabsExpanded:newLine.
-    ].
-    list at:lineNr put:newLine.
-    widthOfWidestLine notNil ifTrue:[
-	widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line).
-    ].
-    self textChanged.
-    shown ifTrue:[
-	self redrawLine:lineNr from:colNr
-    ]
-
-    "Created: / 11.6.1998 / 10:38:32 / cg"
-    "Modified: / 20.6.1998 / 20:23:50 / cg"
+    originalString := self textFromLine:lineNr col:colNr toLine:lineNr col:colNr+aString size-1.
+
+    self basicReplaceString:aString atLine:lineNr col:colNr.
+    self addUndo:(ReplaceCharacters line:lineNr col:colNr characters:originalString info:'replace').
 !
 
 splitLine:lineNr before:colNr
@@ -3828,19 +3898,19 @@
     "handle keyboard input"
 
     <resource: #keyboard (#Paste #Insert #Cut #Again #Replace #Undo #Accept
-			  #Delete #BasicDelete #BackSpace #BasicBackspace
-			  #SelectWord #DeleteSpaces
-			  #SearchMatchingParent #SelectMatchingParents
-			  #SelectToEnd #SelectFromBeginning
-			  #BeginOfLine #EndOfLine #NextWord #PreviousWord
-			  #CursorRight #CursorDown #CursorLeft #CursorUp
-			  #Return #Tab #BackTab #NonInsertingTab #Escape
-			  #GotoLine #Delete #BeginOfText #EndOfText
-			  #SelectLine #ExpandSelectionByLine #DeleteLine
-			  #InsertLine
-			  #SelectLineFromBeginning
-			  #LearnKeyboardMacro #ExecuteKeyboardMacro
-			  #'F*' #'f*')>
+                          #Delete #BasicDelete #BackSpace #BasicBackspace
+                          #SelectWord #DeleteSpaces
+                          #SearchMatchingParent #SelectMatchingParents
+                          #SelectToEnd #SelectFromBeginning
+                          #BeginOfLine #EndOfLine #NextWord #PreviousWord
+                          #CursorRight #CursorDown #CursorLeft #CursorUp
+                          #Return #Tab #BackTab #NonInsertingTab #Escape
+                          #GotoLine #Delete #BeginOfText #EndOfText
+                          #SelectLine #ExpandSelectionByLine #DeleteLine
+                          #InsertLine
+                          #SelectLineFromBeginning
+                          #LearnKeyboardMacro #ExecuteKeyboardMacro #ToggleInsertMode
+                          #'F*' #'f*')>
 
     |fKeyMacros shiftPressed ctrlPressed i event cmdMacro|
 
@@ -3850,85 +3920,101 @@
 
     cmdMacro := UserPreferences current functionKeySequences at:key ifAbsent:nil.
     cmdMacro notNil ifTrue:[
-	self
-	    undoableDo:
-		[ self executeKeyboardMacro:cmdMacro ]
-	    info: key.
-	^ self
+        self
+            undoableDo:
+                [ self executeKeyboardMacro:cmdMacro ]
+            info: key.
+        ^ self
     ].
 
     (key == #BackSpace
      or:[key == #BasicBackspace]) ifTrue:[
-	selectionStartLine notNil ifTrue:[
-	    (key == #BasicBackspace) ifTrue:[
-		self deleteSelection.
-	    ] ifFalse: [
-		self copyAndDeleteSelection.
-	    ].
-	    ^ self
-	].
-
-	self makeCursorVisible.
-	shiftPressed ifTrue:[
-	    self deleteWordBeforeCursor.
-	] ifFalse:[
-	    self deleteCharBeforeCursor.
-	].
-
-	^ self
+        selectionStartLine notNil ifTrue:[
+            (key == #BasicBackspace) ifTrue:[
+                self deleteSelection.
+            ] ifFalse: [
+                self copyAndDeleteSelection.
+            ].
+            ^ self
+        ].
+
+        self makeCursorVisible.
+        shiftPressed ifTrue:[
+            self deleteWordBeforeCursor.
+        ] ifFalse:[
+            self deleteCharBeforeCursor.
+        ].
+
+        ^ self
     ].
 
     (key == #LearnKeyboardMacro) ifTrue:[
-	self toggleLearnMode.
-	^ self
+        self toggleLearnMode.
+        ^ self
     ].
     (key == #ExecuteKeyboardMacro) ifTrue:[
-	self executeLearnedKeyboardMacro.
-	^ self.
+        self executeLearnedKeyboardMacro.
+        ^ self.
     ].
     self learnMode ifTrue:[
-	learnedMacro add:event.
+        learnedMacro add:event.
     ].
 
     (key isMemberOf:Character) ifTrue:[
-	self handleNonCommandKey:key.
-	^ self
+        self handleNonCommandKey:key.
+        ^ self
+    ].
+
+    key == #ToggleInsertMode ifTrue:[
+        editMode value == EditMode insertMode ifTrue:[
+            editMode value:(EditMode overwriteMode).
+            ^ self.
+        ].
+        editMode value == EditMode overwriteMode ifTrue:[
+            editMode value:(EditMode insertAndSelectMode).
+            ^ self.
+        ].
+        editMode value == EditMode insertAndSelectMode ifTrue:[
+            editMode value:(EditMode insertMode).
+            ^ self.
+        ].
+        ^ self.
     ].
 
     replacing := false.
 
     "
      Fn      pastes a key-sequence (but only if not overlayed with
-	     another function in the keyboard map)
+             another function in the keyboard map)
 
      see TextView>>:x:y
     "
     (key at:1) asLowercase == $f ifTrue:[
-	(('[fF][0-9]' match:key)
-	or:['[fF][0-9][0-9]' match:key]) ifTrue:[
-	    shiftPressed ifFalse:[
-		fKeyMacros := UserPreferences current functionKeySequences.
-		fKeyMacros notNil ifTrue:[
-		    (fKeyMacros includesKey:key) ifTrue:[
-			self pasteOrReplace:(fKeyMacros at:key) asStringCollection.
-			^ self
-		    ]
-		]
-	    ]
-	].
+        (('[fF][0-9]' match:key)
+        or:['[fF][0-9][0-9]' match:key]) ifTrue:[
+            shiftPressed ifFalse:[
+                fKeyMacros := UserPreferences current functionKeySequences.
+                fKeyMacros notNil ifTrue:[
+                    (fKeyMacros includesKey:key) ifTrue:[
+                        self pasteOrReplace:(fKeyMacros at:key) asStringCollection.
+                        ^ self
+                    ]
+                ]
+            ]
+        ].
     ].
 
     (key == #'Ctrl8' or:[key == #'Ctrl9']) ifTrue:[
-	self parenthizeSelectionWith:$( and:$).
-	^ self.
+        self parenthizeSelectionWith:$( and:$).
+        ^ self.
     ].
     (key == #'Ctrl2') ifTrue:[
-	self parenthizeSelectionWith:$" and:$".
-	^ self.
+        self parenthizeSelectionWith:$" and:$".
+        ^ self.
     ].
     (key == #'Ctrl#') ifTrue:[
-	self parenthizeSelectionWith:$' and:$'.
-	^ self.
+        self parenthizeSelectionWith:$' and:$'.
+        ^ self.
     ].
 
     (key == #Accept)  ifTrue:[^ self accept].
@@ -3940,9 +4026,9 @@
 
     (key == #Replace) ifTrue:[self replace. ^self].
     (key == #SelectWord) ifTrue:[
-	self makeCursorVisible.
-	self selectWordUnderCursor.
-	^ self
+        self makeCursorVisible.
+        self selectWordUnderCursor.
+        ^ self
     ].
 
     (key == #SearchMatchingParent) ifTrue:[self searchForMatchingParenthesis. ^ self].
@@ -3960,38 +4046,38 @@
 "
 
     (key == #BeginOfLine) ifTrue:[
-	shiftPressed ifTrue: [
-	    "/ "Original St/X code - now use Ctrl modifier"
-	    "/ self unselect.
-	    "/ self cursorHome.
-	    "Jan's modification"
-	    self addToSelectionAfter:[ self cursorToBeginOfLine ].
-	] ifFalse: [
-	    self unselect.
-	    ctrlPressed ifTrue:[
-		self cursorHome.
-	    ] ifFalse:[
-		self cursorToBeginOfLine.
-	    ]
-	].
-	^ self
+        shiftPressed ifTrue: [
+            "/ "Original St/X code - now use Ctrl modifier"
+            "/ self unselect.
+            "/ self cursorHome.
+            "Jan's modification"
+            self addToSelectionAfter:[ self cursorToBeginOfLine ].
+        ] ifFalse: [
+            self unselect.
+            ctrlPressed ifTrue:[
+                self cursorHome.
+            ] ifFalse:[
+                self cursorToBeginOfLine.
+            ]
+        ].
+        ^ self
     ].
     (key == #EndOfLine) ifTrue:[
-	shiftPressed ifTrue:[
-	    "/ "Original St/X code - now use Ctrl modifier"
-	    "/ self unselect.
-	    "/ self cursorToBottom
-	    "Jan's modification"
-	    self addToSelectionAfter:[ self cursorToEndOfLine ] .
-	] ifFalse:[
-	    self unselect.
-	    ctrlPressed ifTrue:[
-		self cursorToBottom
-	    ] ifFalse:[
-		self cursorToEndOfLine.
-	    ]
-	].
-	^ self
+        shiftPressed ifTrue:[
+            "/ "Original St/X code - now use Ctrl modifier"
+            "/ self unselect.
+            "/ self cursorToBottom
+            "Jan's modification"
+            self addToSelectionAfter:[ self cursorToEndOfLine ] .
+        ] ifFalse:[
+            self unselect.
+            ctrlPressed ifTrue:[
+                self cursorToBottom
+            ] ifFalse:[
+                self cursorToEndOfLine.
+            ]
+        ].
+        ^ self
     ].
     (key == #NextWord) ifTrue:[self cursorToNextWord. ^self].
     (key == #PreviousWord) ifTrue:[self cursorToPreviousWord. ^self].
@@ -4001,136 +4087,136 @@
     or:[key == #CursorDown
     or:[key == #CursorLeft
     or:[key == #CursorUp]]]) ifTrue:[
-	self cursorKeyPress:key shifted:shiftPressed.
-	^ self.
+        self cursorKeyPress:key shifted:shiftPressed.
+        ^ self.
     ].
 
     (key == #Return)    ifTrue:[
-	shiftPressed ifTrue:[
-	    self unselect. self cursorReturn.
-	    ^ self
-	].
-	self isReadOnly ifTrue:[
-	    self unselect; makeCursorVisible.
-	    self cursorReturn
-	] ifFalse:[
-	    insertMode value ifFalse:[
-		self cursorReturn.
-		autoIndent == true ifTrue:[
-		    i := self leftIndentForLine:(cursorLine + 1).
-		    self cursorCol:(i+1 max:1)
-		]
-	    ] ifTrue:[
-		"/ old version just unselected ...
-		"/ self unselect; makeCursorVisible.
-
-		"/ new version deletes ...
-		typeOfSelection == #paste ifTrue:[
-		    self unselect; makeCursorVisible.
-		] ifFalse:[
-		    self copyAndDeleteSelection.
-		].
-		self insertCharAtCursor:(Character cr).
-		autoIndent == true ifTrue:[
-		    i := self leftIndentForLine:cursorLine.
-		    self indentFromLine:cursorLine toLine:cursorLine.
-		    self cursorCol:(i+1 max:1)
-		].
-	    ].
-	].
-	^ self
+        shiftPressed ifTrue:[
+            self unselect. self cursorReturn.
+            ^ self
+        ].
+        self isReadOnly ifTrue:[
+            self unselect; makeCursorVisible.
+            self cursorReturn
+        ] ifFalse:[
+            self isInInsertMode ifFalse:[
+                self cursorReturn.
+                autoIndent == true ifTrue:[
+                    i := self leftIndentForLine:(cursorLine + 1).
+                    self cursorCol:(i+1 max:1)
+                ]
+            ] ifTrue:[
+                "/ old version just unselected ...
+                "/ self unselect; makeCursorVisible.
+
+                "/ new version deletes ...
+                typeOfSelection == #paste ifTrue:[
+                    self unselect; makeCursorVisible.
+                ] ifFalse:[
+                    self copyAndDeleteSelection.
+                ].
+                self insertCharAtCursor:(Character cr).
+                autoIndent == true ifTrue:[
+                    i := self leftIndentForLine:cursorLine.
+                    self indentFromLine:cursorLine toLine:cursorLine.
+                    self cursorCol:(i+1 max:1)
+                ].
+            ].
+        ].
+        ^ self
     ].
 
     (key == #NonInsertingTab) ifTrue:[
-	self unselect. self cursorTab.
-	^ self
+        self unselect. self cursorTab.
+        ^ self
     ].
     (key == #BackTab) ifTrue:[
-	self tabMeansNextField ifTrue:[^ super keyPress:key x:x y:y].
-	self unselect. self cursorBacktab.
-	^ self
+        self tabMeansNextField ifTrue:[^ super keyPress:key x:x y:y].
+        self unselect. self cursorBacktab.
+        ^ self
     ].
 
     (key == #Tab) ifTrue:[
-	self tabMeansNextField ifTrue:[^ super keyPress:key x:x y:y].
-
-	insertMode value ifFalse:[
-	    self unselect. self cursorTab. ^self
-	].
-	self unselect. self insertTabAtCursor.
-	^ self
+        self tabMeansNextField ifTrue:[^ super keyPress:key x:x y:y].
+
+        self isInInsertMode ifFalse:[
+            self unselect. self cursorTab. ^self
+        ].
+        self unselect. self insertTabAtCursor.
+        ^ self
     ].
 
     "/ key == #DeleteSpaces ifTrue:[
     (key == #Delete) ifTrue:[
-	shiftPressed ifTrue:[
-	    [(cursorCol <= (self listAt:cursorLine) size)
-	     and:[self characterUnderCursor isSeparator]] whileTrue:[
-		self makeCursorVisible.
-		self deleteCharAtCursor.
-	    ].
-	    ^ self
-	]
+        shiftPressed ifTrue:[
+            [(cursorCol <= (self listAt:cursorLine) size)
+             and:[self characterUnderCursor isSeparator]] whileTrue:[
+                self makeCursorVisible.
+                self deleteCharAtCursor.
+            ].
+            ^ self
+        ]
     ].
 
     (key == #Delete
      or:[key == #BasicDelete]) ifTrue:[
-	selectionStartLine notNil ifTrue:[
-	    (key == #BasicDelete) ifTrue:[
-		self deleteSelection.
-	    ] ifFalse:[
-		self copyAndDeleteSelection.
-	    ].
-	    ^ self
-	].
-	self makeCursorVisible.
-	self deleteCharAtCursor.
-	^ self
+        selectionStartLine notNil ifTrue:[
+            (key == #BasicDelete) ifTrue:[
+                self deleteSelection.
+            ] ifFalse:[
+                self copyAndDeleteSelection.
+            ].
+            ^ self
+        ].
+        self makeCursorVisible.
+        self deleteCharAtCursor.
+        ^ self
     ].
 
     (key == #BeginOfText) ifTrue:[     "i.e. HOME"
-	self unselect.
-	cursorVisibleLine == 1 ifTrue:[
-	    self cursorHome.
-	] ifFalse:[
-	    self cursorToFirstVisibleLine
-	].
-	^ self
+        self unselect.
+        cursorVisibleLine == 1 ifTrue:[
+            self cursorHome.
+        ] ifFalse:[
+            self cursorToFirstVisibleLine
+        ].
+        ^ self
     ].
     (key == #EndOfText) ifTrue:[       "i.e. END"
-	self unselect.
-	cursorVisibleLine == nFullLinesShown ifTrue:[
-	    self cursorToBottom.
-	] ifFalse:[
-	    self cursorToLastVisibleLine
-	].
-	^ self
+        self unselect.
+        cursorVisibleLine == nFullLinesShown ifTrue:[
+            self cursorToBottom.
+        ] ifFalse:[
+            self cursorToLastVisibleLine
+        ].
+        ^ self
     ].
     ((key == #Escape)
     or:[key == #SelectLineFromBeginning])    ifTrue:[
-	self makeCursorVisible.
-	self unselect. self selectCursorLineFromBeginning.
-	^ self
+        self makeCursorVisible.
+        self unselect. self selectCursorLineFromBeginning.
+        ^ self
     ].
     (key == #SelectLine)    ifTrue:[
-	self makeCursorVisible.
-	self unselect. self selectCursorLine.
-	^ self
+        self makeCursorVisible.
+        self unselect. self selectCursorLine.
+        ^ self
     ].
     (key == #ExpandSelectionByLine)    ifTrue:[
 "/        self makeCursorVisible.
-	self selectExpandCursorLine.
-	^ self
+        self selectExpandCursorLine.
+        ^ self
     ].
     (key == #DeleteLine)    ifTrue:[
-	self makeCursorVisible.
-	self unselect. self deleteCursorLine.
-	^ self
+        self makeCursorVisible.
+        self unselect. self deleteCursorLine.
+        ^ self
     ].
     (key == #InsertLine)    ifTrue:[
-	self makeCursorVisible.
-	self unselect. self insertLine:nil before:cursorLine.
-	^ self
+        self makeCursorVisible.
+        self unselect. self insertLine:nil before:cursorLine.
+        ^ self
     ].
     super keyPress:key x:x y:y
 
@@ -4160,15 +4246,15 @@
     |selStartLine selStartCol selEndLine selEndCol sel key|
 
     self isReadOnly ifTrue:[
-	self flash.
-	^ self.
+        self flash.
+        ^ self.
     ].
 
     key := keyArg.
 
     typeOfSelection == #paste ifTrue:[
-	"pasted selection will NOT be replaced by keystroke"
-	self unselect
+        "pasted selection will NOT be replaced by keystroke"
+        self unselect
     ].
 
     selStartLine := selectionStartLine.
@@ -4178,60 +4264,72 @@
     sel := self selection.
 
     (characterEncoding ? #'iso10646-1') ~~ #'iso10646-1' ifTrue:[
-	key := CharacterEncoder encode:key from:#'iso10646-1' into:characterEncoding.
+        key := CharacterEncoder encode:key from:#'iso10646-1' into:characterEncoding.
     ].
 
     "replace selection by what is typed in -
-     if word was selected with a space, keep it"
+     if word was selected with a space, keep it.
+     if there was no selection, the keys character is inserted"
+
+    editMode value isInsertAndSelectMode ifTrue:[
+        selectionStartLine := selectionStartCol := selectionEndLine := selectionEndCol := nil.
+    ].
 
     (selectStyle == #wordLeft) ifTrue:[
-	self replaceSelectionBy:(' ' , key asString)
+        self replaceSelectionBy:(' ' , key asString)
     ] ifFalse:[
-	(selectStyle == #wordRight) ifTrue:[
-	    self replaceSelectionBy:(key asString , ' ').
-	    self cursorLeft
-	] ifFalse:[
-	    self replaceSelectionBy:key
-	]
+        (selectStyle == #wordRight) ifTrue:[
+            self replaceSelectionBy:(key asString , ' ').
+            self cursorLeft
+        ] ifFalse:[
+            self replaceSelectionBy:key
+        ]
     ].
     selectStyle := nil.
 
+    editMode value isInsertAndSelectMode ifTrue:[
+        selectionStartLine := selStartLine.
+        selectionStartCol := selStartCol.
+        selectionEndLine := selEndLine.
+        selectionEndCol := selEndCol.
+    ].
+
     showMatchingParenthesis ifTrue:[
-	"emacs style parenthesis shower"
-
-	"claus: only do it for closing parenthesis -
-		otherwise its too anoying.
-	"
+        "emacs style parenthesis shower"
+
+        "claus: only do it for closing parenthesis -
+                otherwise its too anoying.
+        "
 "
-	(#( $( $) $[ $] ${ $} ) includes:key) ifTrue:[
+        (#( $( $) $[ $] ${ $} ) includes:key) ifTrue:[
 "
-	(#( $) $] $} ) includes:key) ifTrue:[
-	self
-	    searchForMatchingParenthesisFromLine:cursorLine col:(cursorCol - 1)
-	    ifFound:[:line :col |
-			 |savLine savCol sensor|
-
-			 self withCursor:Cursor eye do:[
-			     savLine := cursorLine.
-			     savCol := cursorCol.
-			     self cursorLine:line col:col.
-			     device flush.
-
-			     "/ want to wait 200ms, but not if another keyPress
-			     "/ arrives in the meantime ...
-
-			     sensor := self sensor.
-			     5 timesRepeat:[
-				 (sensor hasKeyPressEventFor:self) ifFalse:[
-				     Processor activeProcess millisecondDelay:40.
-				 ]
-			     ].
-			     self cursorLine:savLine col:savCol
-			 ]
-		    ]
-	    ifNotFound:[self showNotFound]
-	    onError:[self beep]
-	].
+        (#( $) $] $} ) includes:key) ifTrue:[
+        self
+            searchForMatchingParenthesisFromLine:cursorLine col:(cursorCol - 1)
+            ifFound:[:line :col |
+                         |savLine savCol sensor|
+
+                         self withCursor:Cursor eye do:[
+                             savLine := cursorLine.
+                             savCol := cursorCol.
+                             self cursorLine:line col:col.
+                             device flush.
+
+                             "/ want to wait 200ms, but not if another keyPress
+                             "/ arrives in the meantime ...
+
+                             sensor := self sensor.
+                             5 timesRepeat:[
+                                 (sensor hasKeyPressEventFor:self) ifFalse:[
+                                     Processor activeProcess millisecondDelay:40.
+                                 ]
+                             ].
+                             self cursorLine:savLine col:savCol
+                         ]
+                    ]
+            ifNotFound:[self showNotFound]
+            onError:[self beep]
+        ].
     ].
 
 "/    true "autoExpandWhileTyping" ifTrue:[
@@ -4242,7 +4340,14 @@
 "/            self selection.
 "/            typeOfSelection := #paste.
 "/        ].
-"/    ].
+"/    ].   
+    editMode value isInsertAndSelectMode ifTrue:[
+        selectionStartLine isNil ifTrue:[
+            self selectFromLine:cursorLine col:cursorCol-1 toLine:cursorLine col:cursorCol-1.
+        ] ifFalse:[
+            self selectFromLine:selectionStartLine col:selectionStartCol toLine:cursorLine col:cursorCol-1.
+        ].
+    ].
 !
 
 keyPress:key x:x y:y
@@ -4489,7 +4594,7 @@
     hasKeyboardFocus := false. "/ true.
     tabMeansNextField := false.
     autoIndent := false.
-    insertMode := true asValue.
+    editMode := EditMode insertMode asValue.
     learnMode := false asValue.
     "/ trimBlankLines := st80Mode not. "true."
     trimBlankLines := self st80EditMode not. "true."
@@ -4724,7 +4829,7 @@
     subSub := PopUpMenu itemList:miscItems resources:resources performer:model.
     subSub receiver:self.
     subSub checkToggleAt:#autoIndent: put:autoIndent.
-    subSub checkToggleAt:#insertMode: put:(self insertModeHolder value).
+    subSub checkToggleAt:#insertMode: put:(self isInInsertMode).
     subSub checkToggleAt:#learnMode: put:(self learnModeHolder value).
     sub subMenuAt:#misc put:subSub.
 
@@ -6018,6 +6123,10 @@
     ^ (self new line:arg1 col:arg2 character:arg3) info:info
 !
 
+line:arg1 col:arg2 characters:arg3 info:info
+    ^ (self new line:arg1 col:arg2 characters:arg3) info:info
+!
+
 line:arg1 col:arg2 info:arg3
     ^ self new line:arg1 col:arg2 info:arg3
 !
@@ -6157,6 +6266,68 @@
     editor cursorLine:line col:col1.
 ! !
 
+!EditTextView::EditMode class methodsFor:'constants'!
+
+insertAndSelectMode
+    ^ InsertAndSelectMode
+!
+
+insertMode
+    ^ InsertMode
+!
+
+overwriteMode
+    ^ OverwriteMode
+! !
+
+!EditTextView::EditMode class methodsFor:'queries'!
+
+isInsertAndSelectMode
+    ^ false
+!
+
+isInsertMode
+    ^ false
+!
+
+symbolicName
+    self subclassResponsibility
+! !
+
+!EditTextView::EditMode::InsertAndSelectMode class methodsFor:'info'!
+
+infoPrintString
+    ^ 'IS'
+! !
+
+!EditTextView::EditMode::InsertAndSelectMode class methodsFor:'queries'!
+
+isInsertAndSelectMode
+    ^ true
+!
+
+isInsertMode
+    ^ true
+! !
+
+!EditTextView::EditMode::InsertMode class methodsFor:'info'!
+
+infoPrintString
+    ^ 'I'
+! !
+
+!EditTextView::EditMode::InsertMode class methodsFor:'queries'!
+
+isInsertMode
+    ^ true
+! !
+
+!EditTextView::EditMode::OverwriteMode class methodsFor:'info'!
+
+infoPrintString
+    ^ 'O'
+! !
+
 !EditTextView::InsertCharacter methodsFor:'accessing'!
 
 line:lineArg col:colArg character:characterArg
@@ -6212,6 +6383,22 @@
 
 !EditTextView::ReplaceCharacter methodsFor:'accessing'!
 
+col
+    ^ col
+!
+
+col1
+    ^ col
+!
+
+col2
+    ^ col
+!
+
+line
+    ^ line
+!
+
 line:lineArg col:colArg character:characterArg
     line := lineArg.
     col := colArg.
@@ -6228,6 +6415,76 @@
     editor cursorLine:line col:col.
 ! !
 
+!EditTextView::ReplaceCharacters methodsFor:'accessing'!
+
+characters
+    ^ characters
+!
+
+col1
+    ^ col1
+!
+
+col2
+    ^ col2
+!
+
+line
+    ^ line
+!
+
+line:lineArg col:colArg character:characterArg
+    line := lineArg.
+    col1 := col2 := colArg.
+    characters := characterArg asString.
+!
+
+line:lineArg col:colArg characters:charactersArg
+    line := lineArg.
+    col1 := colArg.
+    characters := charactersArg asString.
+    col2 := col1 + charactersArg size - 1
+! !
+
+!EditTextView::ReplaceCharacters methodsFor:'combining'!
+
+canCombineWithNext:anotherAction
+    ^ anotherAction perform:#canCombineWithPreviousReplaceCharactersAction: with:self ifNotUnderstood:false
+!
+
+canCombineWithPreviousReplaceCharactersAction:previousReplaceAction
+    "I will combine only if we both are single character deletes,
+     and my col-to-delete is the next after anotherDeleteActions col-to-delete.
+     (i.e. single-character typing)"
+
+    previousReplaceAction line == line ifTrue:[
+        previousReplaceAction col2 == (col1-1) ifTrue:[
+            ^ true
+        ].
+    ].
+
+    ^ false
+!
+
+combineWithNext:nextReplaceAction
+    self assert:(line == nextReplaceAction line).
+    self assert:(self col2 == (nextReplaceAction col1 - 1)).
+
+    col2 := nextReplaceAction col2.
+    userFriendlyInfo := 'replace ' , (col2 - col1 + 1) printString.
+    characters := characters , nextReplaceAction characters.
+! !
+
+!EditTextView::ReplaceCharacters methodsFor:'execution'!
+
+executeIn:editor
+    editor
+        replaceString:characters
+        atLine:line
+        col:col1.
+    editor cursorLine:line col:col1.
+! !
+
 !EditTextView::ReplaceContents methodsFor:'accessing'!
 
 text:something
@@ -6257,5 +6514,5 @@
 !EditTextView class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libwidg/EditTextView.st,v 1.382 2005-12-27 16:28:06 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libwidg/EditTextView.st,v 1.383 2006-01-09 08:48:56 cg Exp $'
 ! !
--- a/PopUpMenu.st	Mon Jan 09 09:35:37 2006 +0100
+++ b/PopUpMenu.st	Mon Jan 09 09:49:39 2006 +0100
@@ -1042,6 +1042,10 @@
 
 !PopUpMenu methodsFor:'accessing-items'!
 
+addItem:anItem
+    menuView addItem:anItem
+!
+
 indexOf:indexOrName
     "return the index of a submenu - or 0 if there is none"
 
@@ -1591,5 +1595,5 @@
 !PopUpMenu class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libwidg/PopUpMenu.st,v 1.96 2004-03-20 13:18:36 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libwidg/PopUpMenu.st,v 1.97 2006-01-09 08:49:39 cg Exp $'
 ! !