ETxtView.st
changeset 2009 853cece96ee7
parent 2008 1d02c2e994b6
child 2010 ca8dcc8723dc
equal deleted inserted replaced
2008:1d02c2e994b6 2009:853cece96ee7
     1 "
       
     2  COPYRIGHT (c) 1989 by Claus Gittinger
       
     3 	      All Rights Reserved
       
     4 
       
     5  This software is furnished under a license and may be used
       
     6  only in accordance with the terms of that license and with the
       
     7  inclusion of the above copyright notice.   This software may not
       
     8  be provided or otherwise made available to, or used by, any
       
     9  other person.  No title to or ownership of the software is
       
    10  hereby transferred.
       
    11 "
       
    12 
       
    13 TextView subclass:#EditTextView
       
    14 	instanceVariableNames:'cursorLine cursorVisibleLine cursorCol cursorShown
       
    15 		prevCursorState readOnly modifiedChannel fixedSize exceptionBlock
       
    16 		cursorFgColor cursorBgColor cursorNoFocusFgColor cursorType
       
    17 		cursorTypeNoFocus undoAction typeOfSelection lastString
       
    18 		lastReplacement lastAction replacing showMatchingParenthesis
       
    19 		hasKeyboardFocus acceptAction lockUpdates tabMeansNextField
       
    20 		autoIndent insertMode trimBlankLines wordWrap
       
    21 		replacementWordSelectStyle acceptChannel acceptEnabled st80Mode'
       
    22 	classVariableNames:'DefaultCursorForegroundColor DefaultCursorBackgroundColor
       
    23 		DefaultCursorType DefaultCursorNoFocusForegroundColor ST80Mode
       
    24 		DefaultCursorTypeNoFocus'
       
    25 	poolDictionaries:''
       
    26 	category:'Views-Text'
       
    27 !
       
    28 
       
    29 !EditTextView class methodsFor:'documentation'!
       
    30 
       
    31 copyright
       
    32 "
       
    33  COPYRIGHT (c) 1989 by Claus Gittinger
       
    34 	      All Rights Reserved
       
    35 
       
    36  This software is furnished under a license and may be used
       
    37  only in accordance with the terms of that license and with the
       
    38  inclusion of the above copyright notice.   This software may not
       
    39  be provided or otherwise made available to, or used by, any
       
    40  other person.  No title to or ownership of the software is
       
    41  hereby transferred.
       
    42 "
       
    43 !
       
    44 
       
    45 documentation
       
    46 "
       
    47     a view for editable text - adds editing functionality to TextView
       
    48     Also, it adds accept functionality, and defines a new actionBlock: 
       
    49     acceptAction to be performed for accept
       
    50 
       
    51     If used with a model, this is informed by sending it a changeMsg with
       
    52     the current contents as argument.
       
    53     (however, it is possible to define both changeMsg and acceptAction)
       
    54 
       
    55     Please read the historic notice in the ListView class.
       
    56 
       
    57     [Instance variables:]
       
    58 
       
    59 	cursorLine              <Number>        line where cursor sits (1..)
       
    60 
       
    61 	cursorVisibleLine       <Number>        visible line where cursor sits (1..nLinesShown)
       
    62 
       
    63 	cursorCol               <Number>        col where cursor sits (1..)
       
    64 
       
    65 	cursorShown             <Boolean>       true, if cursor is currently shown
       
    66 
       
    67 	readOnly                <Boolean>       true, if text may not be edited
       
    68 
       
    69 	modifiedChannel         <ValueHolder>   holding true, if text has been modified.
       
    70 						cleared on accept.
       
    71 
       
    72 	acceptChannel           <ValueHolder>   holding true, if text has been accepted.
       
    73 
       
    74 	fixedSize               <Boolean>       true, if no lines may be added/removed
       
    75 
       
    76 	exceptionBlock          <Block>         block to be evaluated when readonly text is about to be modified
       
    77 						if it returns true, the modification will be done anyway.
       
    78 						if it returns anything else, the modification is not done.
       
    79 
       
    80 	cursorFgColor           <Color>         color used for cursor drawing
       
    81 	cursorBgColor           <Color>         color used for cursor drawing
       
    82 
       
    83 	cursorType              <Symbol>        how the cursor is drawn; currently implemented
       
    84 						are #block (solid-block cursor), #ibeam
       
    85 						(vertical bar at insertion point) 
       
    86 						and #caret (caret below insertion-point)
       
    87 
       
    88 	cursorTypeNoFocus       <Symbol>        like above, if view has no focus
       
    89 						nil means: hide the cursor.
       
    90 
       
    91 	undoAction              <Block>         block which undoes last cut, paste or replace
       
    92 						(not yet fully implemented)
       
    93 
       
    94 	typeOfSelection         <Symbol>        #paste, if selection created by paste, nil otherwise
       
    95 						this affects the next keyPress: if #paste it does not
       
    96 						replace; otherwise it replaces the selection.
       
    97 
       
    98 	lastCut                 <String>        last cut or replaced string
       
    99 
       
   100 	lastReplacement         <String>        last replacement
       
   101 
       
   102 	replacing               <Boolean>       true if entered characters replace last selection
       
   103 
       
   104 	showMatchingParenthesis <Boolean>       if true, shows matching parenthesis
       
   105 						when entering one; this is the default.
       
   106 
       
   107 	hasKeyboardFocus        <Boolean>       true if this view has the focus
       
   108 
       
   109 	acceptAction            <Block>         accept action - evaluated passing the contents as 
       
   110 						argument 
       
   111 
       
   112 	tabMeansNextField       <Boolean>       if true, Tab is ignored as input and shifts keyboard
       
   113 						focus to the next field. For editTextViews, this is false
       
   114 						by default (i.e. tabs can be entered into the text).
       
   115 						For some subclasses (inputFields), this may be true.
       
   116 
       
   117 	trimBlankLines          <Boolean>       if true, trailing blanks are
       
   118 						removed when editing.
       
   119 						Default is true.
       
   120 
       
   121 	wordWrap                <Boolean>       Currently not used.
       
   122 
       
   123 	lockUpdates             <Boolean>       internal, private
       
   124 
       
   125 	prevCursorState         <Boolean>       temporary, private
       
   126 
       
   127 
       
   128     class variables:
       
   129 	ST80Mode                <Boolean>       if true, cursor positioning is
       
   130 						done as in vi or ST80; i.e.
       
   131 						wysiwyg mode is somewhat relaxed,
       
   132 						in that the cursor cannot be
       
   133 						positioned behind a lines end.
       
   134 						This is not yet completely implemented.
       
   135     used globals:
       
   136 
       
   137 	DeleteHistory           <Text>          last 1000 lines of deleted text
       
   138 						(but only if this variable exists already)
       
   139 
       
   140     [styleSheet parameters:]
       
   141 
       
   142 	textCursorForegroundColor <Color>       cursor fg color; default: text background
       
   143 	textCursorBackgroundColor <Color>       cursor bg color; default: text foreground
       
   144 	textCursorNoFocusForegroundColor 
       
   145 				  <Color>       cursor fg color if no focus; default: cursor fg color
       
   146 	textCursorType            <Symbol>      cursor type; default:  #block
       
   147 
       
   148     [author:]
       
   149 	Claus Gittinger
       
   150 
       
   151     [see also:]
       
   152 	CodeView Workspace TextView ListView
       
   153 	EditField
       
   154 "
       
   155 !
       
   156 
       
   157 examples
       
   158 "
       
   159   non MVC operation:
       
   160 
       
   161     basic setup:
       
   162 									[exBegin]
       
   163 	|top textView|
       
   164 
       
   165 	top := StandardSystemView new.
       
   166 	top extent:300@200.
       
   167 
       
   168 	textView := EditTextView new.
       
   169 	textView origin:0.0 @ 0.0 corner:1.0 @ 1.0.
       
   170 	top addSubView:textView.
       
   171 
       
   172 	textView contents:('/etc/hosts' asFilename contentsOfEntireFile).
       
   173 
       
   174 	top open.
       
   175 									[exEnd]
       
   176 
       
   177 
       
   178     with vertical scrollbar:
       
   179 									[exBegin]
       
   180 	|top scrollView textView|
       
   181 
       
   182 	top := StandardSystemView new.
       
   183 	top extent:300@200.
       
   184 
       
   185 	scrollView := ScrollableView for:EditTextView.
       
   186 	textView := scrollView scrolledView.
       
   187 	scrollView origin:0.0 @ 0.0 corner:1.0 @ 1.0.
       
   188 	top addSubView:scrollView.
       
   189 
       
   190 	textView contents:('/etc/hosts' asFilename contentsOfEntireFile).
       
   191 
       
   192 	top open.
       
   193 									[exEnd]
       
   194 
       
   195 
       
   196     with horizontal & vertical scrollbars:
       
   197 									[exBegin]
       
   198 	|top scrollView textView|
       
   199 
       
   200 	top := StandardSystemView new.
       
   201 	top extent:300@200.
       
   202 
       
   203 	scrollView := HVScrollableView for:EditTextView.
       
   204 	textView := scrollView scrolledView.
       
   205 	scrollView origin:0.0 @ 0.0 corner:1.0 @ 1.0.
       
   206 	top addSubView:scrollView.
       
   207 
       
   208 	textView contents:('/etc/hosts' asFilename contentsOfEntireFile).
       
   209 
       
   210 	top open.
       
   211 									[exEnd]
       
   212 
       
   213 
       
   214     set the action for accept:
       
   215 									[exBegin]
       
   216 	|top textView|
       
   217 
       
   218 	top := StandardSystemView new.
       
   219 	top extent:300@200.
       
   220 
       
   221 	textView := EditTextView new.
       
   222 	textView origin:0.0 @ 0.0 corner:1.0 @ 1.0.
       
   223 	top addSubView:textView.
       
   224 
       
   225 	textView contents:('/etc/hosts' asFilename contentsOfEntireFile).
       
   226 	textView acceptAction:[:contents |
       
   227 				Transcript showCR:'will not overwrite the file with:'.
       
   228 				Transcript showCR:contents asString
       
   229 			      ].
       
   230 	top open.
       
   231 									[exEnd]
       
   232 
       
   233 
       
   234 
       
   235     non-string (text) items:
       
   236 									[exBegin]
       
   237 	|top textView list|
       
   238 
       
   239 	list := '/etc/hosts' asFilename contentsOfEntireFile asStringCollection.
       
   240 	1 to:list size by:2 do:[:nr |
       
   241 	    list at:nr put:(Text string:(list at:nr)
       
   242 				 emphasis:(Array with:#bold with:(#color->Color red)))
       
   243 	].
       
   244 
       
   245 	top := StandardSystemView new.
       
   246 	top extent:300@200.
       
   247 
       
   248 	textView := EditTextView new.
       
   249 	textView origin:0.0 @ 0.0 corner:1.0 @ 1.0.
       
   250 	top addSubView:textView.
       
   251 
       
   252 	textView contents:list.
       
   253 	top open.
       
   254 									[exEnd]
       
   255 
       
   256 
       
   257 
       
   258   MVC operation:
       
   259     (the examples model here is a plug simulating a real model;
       
   260      real world applications would not use a plug ..)
       
   261 									[exBegin]
       
   262 	|top textView model|
       
   263 
       
   264 	model := Plug new.
       
   265 	model respondTo:#accepted:
       
   266 		   with:[:newContents | 
       
   267 				Transcript showCR:'will not overwrite the file with:'.
       
   268 				Transcript showCR:newContents asString
       
   269 			].
       
   270 	model respondTo:#getList
       
   271 		   with:['/etc/hosts' asFilename contentsOfEntireFile].
       
   272 
       
   273         
       
   274 	top := StandardSystemView new.
       
   275 	top extent:300@200.
       
   276 
       
   277 	textView := EditTextView new.
       
   278 	textView origin:0.0 @ 0.0 corner:1.0 @ 1.0.
       
   279 	top addSubView:textView.
       
   280 
       
   281 	textView listMessage:#getList;
       
   282 		 model:model;
       
   283 		 changeMessage:#accepted:;
       
   284 		 aspect:#list.
       
   285 	top open.
       
   286 									[exEnd]
       
   287 
       
   288 
       
   289     two textViews on the same model:
       
   290 									[exBegin]
       
   291 	|top1 textView1 top2 textView2 model currentContents|
       
   292 
       
   293 	model := Plug new.
       
   294 	model respondTo:#accepted:
       
   295 		   with:[:newContents |
       
   296 				Transcript showCR:'accepted:'.
       
   297 				Transcript showCR:newContents asString.
       
   298 				currentContents := newContents.
       
   299 				model changed:#contents
       
   300 			].
       
   301 	model respondTo:#getList
       
   302 		   with:[Transcript showCR:'query'.
       
   303 			 currentContents].
       
   304 
       
   305 
       
   306 	top1 := StandardSystemView new.
       
   307 	top1 extent:300@200.
       
   308 
       
   309 	textView1 := EditTextView new.
       
   310 	textView1 origin:0.0 @ 0.0 corner:1.0 @ 1.0.
       
   311 	top1 addSubView:textView1.
       
   312 
       
   313 	textView1 listMessage:#getList;
       
   314 		  model:model;
       
   315 		  aspect:#contents;
       
   316 		  changeMessage:#accepted:.
       
   317 	top1 open.
       
   318 
       
   319 	top2 := StandardSystemView new.
       
   320 	top2 extent:300@200.
       
   321 
       
   322 	textView2 := EditTextView new.
       
   323 	textView2 origin:0.0 @ 0.0 corner:1.0 @ 1.0.
       
   324 	top2 addSubView:textView2.
       
   325 
       
   326 	textView2 listMessage:#getList;
       
   327 		  model:model;
       
   328 		  aspect:#contents;
       
   329 		  changeMessage:#accepted:.
       
   330 	top2 open.
       
   331 									[exEnd]
       
   332 "
       
   333 ! !
       
   334 
       
   335 !EditTextView class methodsFor:'defaults'!
       
   336 
       
   337 st80Mode
       
   338     "return true, if the st80 editing mode is turned on.
       
   339      This setting affects the behavior of the cursor, when positioned
       
   340      behond the end of a line or the end of the text.
       
   341      The default is initialized from the viewStyle."
       
   342 
       
   343     ^ ST80Mode
       
   344 
       
   345    "
       
   346     EditTextView st80Mode:true
       
   347     EditTextView st80Mode:false
       
   348    "
       
   349 
       
   350     "Modified: / 16.1.1998 / 22:54:57 / cg"
       
   351 !
       
   352 
       
   353 st80Mode:aBoolean
       
   354     "turns on/off st80 behavior, where the cursor cannot be positioned
       
   355      behond the end of a line or the last line"
       
   356 
       
   357     ST80Mode := aBoolean.
       
   358 
       
   359    "
       
   360     EditTextView st80Mode:true
       
   361     EditTextView st80Mode:false
       
   362    "
       
   363 
       
   364     "Modified: / 16.1.1998 / 22:55:19 / cg"
       
   365 !
       
   366 
       
   367 updateStyleCache
       
   368     "extract values from the styleSheet and cache them in class variables"
       
   369 
       
   370     <resource: #style (#'textCursor.foregroundColor' #'textCursor.backgroundColor'
       
   371                        #'textCursor.noFocusForegroundColor' 
       
   372                        #'textCursor.type' #'textCursor.typeNoFocus'
       
   373                        #'editText.st80Mode')>
       
   374 
       
   375     DefaultCursorForegroundColor := StyleSheet colorAt:'textCursor.foregroundColor'.
       
   376     DefaultCursorBackgroundColor := StyleSheet colorAt:'textCursor.backgroundColor'.
       
   377     DefaultCursorNoFocusForegroundColor := StyleSheet colorAt:'textCursor.noFocusForegroundColor'.
       
   378     DefaultCursorType := StyleSheet at:'textCursor.type' default:#block.
       
   379     DefaultCursorTypeNoFocus := StyleSheet at:'textCursor.typeNoFocus'.
       
   380 
       
   381     ST80Mode := StyleSheet at:'editText.st80Mode' default:false.
       
   382 
       
   383     "
       
   384      self updateStyleCache
       
   385     "
       
   386 
       
   387     "Modified: / 20.5.1998 / 04:27:41 / cg"
       
   388 ! !
       
   389 
       
   390 !EditTextView methodsFor:'ST-80 compatibility'!
       
   391 
       
   392 autoAccept:aBoolean
       
   393     "ignored for now"
       
   394 
       
   395     "Created: / 5.6.1998 / 15:30:32 / cg"
       
   396 !
       
   397 
       
   398 continuousAccept:aBoolean
       
   399     "ignored for now"
       
   400 
       
   401     "Created: / 19.6.1998 / 00:03:49 / cg"
       
   402 !
       
   403 
       
   404 enabled:aBoolean
       
   405 
       
   406     self readOnly:aBoolean not
       
   407 
       
   408     "Created: / 30.3.1999 / 15:10:23 / stefan"
       
   409     "Modified: / 30.3.1999 / 15:10:53 / stefan"
       
   410 !
       
   411 
       
   412 textHasChanged
       
   413     ^ self modified
       
   414 
       
   415     "Created: / 19.6.1998 / 00:09:43 / cg"
       
   416 ! !
       
   417 
       
   418 !EditTextView methodsFor:'ST-80 compatibility editing'!
       
   419 
       
   420 cutSelection
       
   421     self cut
       
   422 
       
   423     "Created: / 31.10.1997 / 03:29:50 / cg"
       
   424 !
       
   425 
       
   426 deselect
       
   427     "remove the selection"
       
   428 
       
   429     ^ self unselect
       
   430 
       
   431     "Created: / 19.6.1998 / 02:41:54 / cg"
       
   432 !
       
   433 
       
   434 find:pattern
       
   435     self searchFwd:pattern ifAbsent:nil
       
   436 
       
   437     "Created: / 29.1.1999 / 19:09:42 / cg"
       
   438     "Modified: / 29.1.1999 / 19:10:12 / cg"
       
   439 !
       
   440 
       
   441 insert:aString at:aCharacterPosition
       
   442     "insert a string at aCharacterPosition."
       
   443 
       
   444     |line col|
       
   445 
       
   446     line := self lineOfCharacterPosition:aCharacterPosition.
       
   447     col := aCharacterPosition - (self characterPositionOfLine:line col:1) + 1.
       
   448     col < 1 ifTrue:[
       
   449         col := 1
       
   450     ].
       
   451     self insertString:aString atLine:line col:col.
       
   452 
       
   453     "
       
   454      |top v|
       
   455 
       
   456      top := StandardSystemView new.
       
   457      top extent:300@300.
       
   458      v := EditTextView origin:0.0@0.0 corner:1.0@1.0 in:top.
       
   459      top openAndWait.
       
   460      v contents:'1234567890\1234567890\1234567890\' withCRs.
       
   461      v insert:'<- hello there' at:5.
       
   462     "
       
   463 
       
   464     "Modified: / 5.4.1998 / 17:20:08 / cg"
       
   465 !
       
   466 
       
   467 insertAndSelect:aString at:aCharacterPosition
       
   468     "insert a selected string at aCharacterPosition."
       
   469 
       
   470     |line col|
       
   471 
       
   472     line := self lineOfCharacterPosition:aCharacterPosition.
       
   473     col := aCharacterPosition - (self characterPositionOfLine:line col:1) + 1.
       
   474     self insertString:aString atLine:line col:col.
       
   475     self selectFromLine:line col:col toLine:line col:col + aString size - 1
       
   476     "
       
   477      |v|
       
   478 
       
   479      v := EditTextView new openAndWait.
       
   480      v contents:'1234567890\1234567890\1234567890\' withCRs.
       
   481      v insertAndSelect:'<- hello there' at:5.
       
   482     "
       
   483 !
       
   484 
       
   485 pasteSelection
       
   486     self paste
       
   487 
       
   488     "Created: / 31.10.1997 / 03:28:53 / cg"
       
   489 !
       
   490 
       
   491 replaceSelectionWith:aString
       
   492     ^ self replaceSelectionBy:aString
       
   493 
       
   494     "Created: / 19.6.1998 / 02:42:32 / cg"
       
   495 !
       
   496 
       
   497 selectAt:pos
       
   498     "move the cursor before cursorPosition."
       
   499 
       
   500     self cursorToCharacterPosition:pos
       
   501 
       
   502     "Modified: / 19.6.1998 / 02:41:28 / cg"
       
   503     "Created: / 19.6.1998 / 02:43:39 / cg"
       
   504 !
       
   505 
       
   506 selectFrom:startPos to:endPos
       
   507     "change the selection given two aCharacterPositions."
       
   508 
       
   509     |line1 col1 line2 col2|
       
   510 
       
   511     startPos > endPos ifTrue:[
       
   512         ^ self unselect
       
   513     ].
       
   514 
       
   515     line1 := self lineOfCharacterPosition:startPos.
       
   516     col1 := startPos - (self characterPositionOfLine:line1 col:1) + 1.
       
   517     col1 < 1 ifTrue:[
       
   518         col1 := 1
       
   519     ].
       
   520     line2 := self lineOfCharacterPosition:endPos.
       
   521     col2 := startPos - (self characterPositionOfLine:line2 col:1) + 1.
       
   522     col2 < 1 ifTrue:[
       
   523         col2 := 1
       
   524     ].
       
   525     self selectFromLine:line1 col:col1 toLine:line2 col:col2
       
   526 
       
   527     "Modified: / 19.6.1998 / 02:41:28 / cg"
       
   528 ! !
       
   529 
       
   530 !EditTextView methodsFor:'accessing-behavior'!
       
   531 
       
   532 acceptAction
       
   533     "return the action to be performed on accept (or nil)"
       
   534 
       
   535     ^ acceptAction
       
   536 !
       
   537 
       
   538 acceptAction:aBlock
       
   539     "set the action to be performed on accept"
       
   540 
       
   541     acceptAction := aBlock
       
   542 !
       
   543 
       
   544 acceptEnabled:aBoolean
       
   545     "enable/disable accept. This greys the corresponding item in the menu"
       
   546 
       
   547     acceptEnabled := aBoolean
       
   548 
       
   549     "Created: 7.3.1997 / 11:04:34 / cg"
       
   550 !
       
   551 
       
   552 autoIndent:aBoolean
       
   553     autoIndent := aBoolean
       
   554 
       
   555     "Created: 5.3.1996 / 14:37:50 / cg"
       
   556 !
       
   557 
       
   558 exceptionBlock:aBlock
       
   559     "define the action to be triggered when user tries to modify
       
   560      readonly text"
       
   561 
       
   562     exceptionBlock := aBlock
       
   563 !
       
   564 
       
   565 insertMode:aBoolean
       
   566     insertMode := aBoolean
       
   567 
       
   568     "Created: 6.3.1996 / 12:24:05 / cg"
       
   569 !
       
   570 
       
   571 tabMeansNextField:aBoolean
       
   572     "set/clear tabbing to the next field.
       
   573      If true, Tab is ignored and shifts the keyboard focus.
       
   574      If false, tabs can be entered into the text.
       
   575      The default is true for editTextView, false for single-line
       
   576      input fields."
       
   577 
       
   578     tabMeansNextField := aBoolean
       
   579 ! !
       
   580 
       
   581 !EditTextView methodsFor:'accessing-contents'!
       
   582 
       
   583 acceptChannel
       
   584     "return the valueHolder holding true if text was accepted.
       
   585      By placing a true into this channel, an accept can also be forced."
       
   586 
       
   587     ^ acceptChannel
       
   588 
       
   589     "Modified: / 30.1.1998 / 14:17:11 / cg"
       
   590 !
       
   591 
       
   592 acceptChannel:aValueHolder
       
   593     "set the valueHolder holding true if text was accepted.
       
   594      By placing a true into this channel, an accept can also be forced."
       
   595 
       
   596     |prev|
       
   597 
       
   598     prev := acceptChannel.
       
   599     acceptChannel := aValueHolder.
       
   600     self setupChannel:aValueHolder for:nil withOld:prev
       
   601 
       
   602     "Created: / 30.1.1998 / 14:51:09 / cg"
       
   603 !
       
   604 
       
   605 accepted
       
   606     "return true if text was accepted"
       
   607 
       
   608     ^ acceptChannel value
       
   609 
       
   610     "Created: 14.2.1997 / 16:43:46 / cg"
       
   611 !
       
   612 
       
   613 accepted:aBoolean
       
   614     "set/clear the accepted flag.
       
   615      This may force my current contents to be placed into my model."
       
   616 
       
   617     acceptChannel value:aBoolean.
       
   618 
       
   619     "Created: / 14.2.1997 / 16:44:01 / cg"
       
   620     "Modified: / 30.1.1998 / 14:20:15 / cg"
       
   621 !
       
   622 
       
   623 at:lineNr basicPut:aLine
       
   624     "change a line without change notification"
       
   625 
       
   626     (self at:lineNr) = aLine ifFalse:[
       
   627         super at:lineNr put:aLine.
       
   628     ].
       
   629 !
       
   630 
       
   631 at:lineNr put:aLine
       
   632     (self at:lineNr) = aLine ifFalse:[
       
   633 	super at:lineNr put:aLine.
       
   634 	self textChanged
       
   635     ].
       
   636 !
       
   637 
       
   638 characterBeforeCursor
       
   639     "return the character under the cursor - space if behond line.
       
   640      For non-block cursors, this is the character immediately to the right
       
   641      of the insertion-bar or caret."
       
   642 
       
   643     cursorCol == 1 ifTrue:[^ nil].
       
   644 
       
   645     ^ self characterAtLine:cursorLine col:cursorCol-1
       
   646 
       
   647     "Created: / 17.6.1998 / 15:16:41 / cg"
       
   648 !
       
   649 
       
   650 characterUnderCursor
       
   651     "return the character under the cursor - space if behond line.
       
   652      For non-block cursors, this is the character immediately to the right
       
   653      of the insertion-bar or caret."
       
   654 
       
   655     ^ self characterAtLine:cursorLine col:cursorCol
       
   656 !
       
   657 
       
   658 contents
       
   659     "return the contents as a String"
       
   660 
       
   661     list isNil ifTrue:[^ ''].
       
   662     self removeTrailingBlankLines.
       
   663     ^ list asStringWithCRs
       
   664 !
       
   665 
       
   666 cursorCol
       
   667     "return the cursors col (1..).
       
   668      This is the absolute col; NOT the visible col"
       
   669 
       
   670     ^ cursorCol
       
   671 !
       
   672 
       
   673 cursorLine
       
   674     "return the cursors line (1..). 
       
   675      This is the absolute line; NOT the visible line"
       
   676 
       
   677     ^ cursorLine
       
   678 !
       
   679 
       
   680 fixedSize
       
   681     "make the texts size fixed (no lines may be added).
       
   682      OBSOLETE: use readOnly"
       
   683 
       
   684     self obsoleteMethodWarning:'use #readOnly:'.
       
   685     readOnly == true ifFalse:[
       
   686         readOnly := true.
       
   687         middleButtonMenu notNil ifTrue:[
       
   688             middleButtonMenu disableAll:#(cut paste replace indent)
       
   689         ]
       
   690     ]
       
   691 
       
   692     "Modified: 14.2.1997 / 17:35:24 / cg"
       
   693 !
       
   694 
       
   695 isReadOnly
       
   696     "return true, if the text is readonly."
       
   697 
       
   698     ^ readOnly value
       
   699 
       
   700     "Modified: 14.2.1997 / 17:35:56 / cg"
       
   701 !
       
   702 
       
   703 list:something
       
   704     "position cursor home when setting contents"
       
   705 
       
   706     super list:something.
       
   707     self cursorHome
       
   708 !
       
   709 
       
   710 modified
       
   711     "return true if text was modified"
       
   712 
       
   713     ^ modifiedChannel value
       
   714 !
       
   715 
       
   716 modified:aBoolean
       
   717     "set/clear the modified flag"
       
   718 
       
   719     modifiedChannel value:aBoolean
       
   720 
       
   721     "Modified: 14.2.1997 / 16:44:05 / cg"
       
   722 !
       
   723 
       
   724 modifiedChannel
       
   725     "return the valueHolder holding true if text was modified"
       
   726 
       
   727     ^ modifiedChannel
       
   728 !
       
   729 
       
   730 modifiedChannel:aValueHolder
       
   731     "set the valueHolder holding true if text was modified"
       
   732 
       
   733     |prev|
       
   734 
       
   735     prev := modifiedChannel.
       
   736     modifiedChannel := aValueHolder.
       
   737     self setupChannel:aValueHolder for:nil withOld:prev
       
   738 
       
   739     "Created: / 30.1.1998 / 14:51:32 / cg"
       
   740 !
       
   741 
       
   742 readOnly
       
   743     "make the text readonly.
       
   744      Somewhat obsolete - use #readOnly:"
       
   745 
       
   746     self obsoleteMethodWarning:'use #readOnly:'.
       
   747     readOnly := true
       
   748 
       
   749     "Modified: 14.2.1997 / 17:35:56 / cg"
       
   750 !
       
   751 
       
   752 readOnly:aBoolean
       
   753     "make the text readonly (aBoolean == true) or writable (aBoolean == false).
       
   754      The argument may also be a valueHolder."
       
   755 
       
   756     readOnly := aBoolean
       
   757 
       
   758     "Created: 14.2.1997 / 17:35:39 / cg"
       
   759 !
       
   760 
       
   761 setContents:something
       
   762     |selType|
       
   763 
       
   764     selType := typeOfSelection.
       
   765     super setContents:something.
       
   766     typeOfSelection := selType.
       
   767 
       
   768     "Created: / 31.3.1998 / 23:35:06 / cg"
       
   769 ! !
       
   770 
       
   771 !EditTextView methodsFor:'accessing-look'!
       
   772 
       
   773 cursorForegroundColor:color1 backgroundColor:color2
       
   774     "set both cursor foreground and cursor background colors"
       
   775 
       
   776     |wasOn|
       
   777 
       
   778     wasOn := self hideCursor.
       
   779     cursorFgColor := color1 onDevice:device.
       
   780     cursorBgColor := color2 onDevice:device.
       
   781     wasOn ifTrue:[self showCursor]
       
   782 !
       
   783 
       
   784 cursorType
       
   785     "return the style of the text cursor.
       
   786      Currently, supported are: #block, #frame, #ibeam, #caret, #solidCaret
       
   787                                #bigCaret and #bigSolidCaret"
       
   788 
       
   789     ^ cursorType
       
   790 
       
   791     "Modified: / 5.5.1999 / 14:52:33 / cg"
       
   792 !
       
   793 
       
   794 cursorType:aCursorTypeSymbol
       
   795     "set the style of the text cursor.
       
   796      Currently, supported are: #block, #frame, #ibeam, #caret, #solidCaret
       
   797 			       #bigCaret and #bigSolidCaret"
       
   798 
       
   799     cursorType := aCursorTypeSymbol.
       
   800 
       
   801     "Created: 21.9.1997 / 13:42:23 / cg"
       
   802     "Modified: 21.9.1997 / 13:43:35 / cg"
       
   803 !
       
   804 
       
   805 cursorTypeNoFocus
       
   806     "return the style of the text cursor when the view has no focus.
       
   807      If left unspecified, this is the same as the regular cursorType."
       
   808 
       
   809     ^ cursorTypeNoFocus
       
   810 
       
   811     "Created: / 5.5.1999 / 14:52:46 / cg"
       
   812 !
       
   813 
       
   814 cursorTypeNoFocus:aCursorTypeSymbol
       
   815     "set the style of the text cursor when the view has no focus.
       
   816      If left unspecified, this is the same as the regular cursorType."
       
   817 
       
   818     cursorTypeNoFocus := aCursorTypeSymbol
       
   819 ! !
       
   820 
       
   821 !EditTextView methodsFor:'change & update '!
       
   822 
       
   823 accept
       
   824     "accept the current contents by executing the accept-action and/or
       
   825      changeMessage."
       
   826 
       
   827     acceptEnabled == false ifTrue:[
       
   828         device beep.
       
   829         ^ self
       
   830     ].
       
   831 
       
   832     lockUpdates := true.
       
   833 
       
   834     "/
       
   835     "/ ST-80 way of doing it
       
   836     "/
       
   837     model notNil ifTrue:[
       
   838         self sendChangeMessageWith:self argForChangeMessage.
       
   839     ].
       
   840 
       
   841     "/
       
   842     "/ ST/X way of doing things
       
   843     "/ as a historic (and temporary) leftover,
       
   844     "/ the block is called with a stringCollection
       
   845     "/ - not with the actual string
       
   846     "/
       
   847     acceptAction notNil ifTrue:[
       
   848         acceptAction value:self list
       
   849     ].
       
   850 
       
   851     "/ NO - must be manually reset by application
       
   852     "/ self modified:false.
       
   853 
       
   854     "/ self accepted:true.
       
   855     "/ changed to:
       
   856     acceptChannel value:true withoutNotifying:self.
       
   857 
       
   858     lockUpdates := false.
       
   859 
       
   860     "Modified: / 30.1.1998 / 14:19:00 / cg"
       
   861 !
       
   862 
       
   863 argForChangeMessage
       
   864     "return the argument to be passed with the change notification.
       
   865      Defined as separate method for easier subclassability."
       
   866 
       
   867     ^ self contents
       
   868 
       
   869     "Modified: 29.4.1996 / 12:42:14 / cg"
       
   870 !
       
   871 
       
   872 getListFromModel
       
   873     "get my contents from the model.
       
   874      Redefined to ignore updates resulting from my own changes
       
   875      (i.e. if lockUpdates is true)."
       
   876 
       
   877     "
       
   878      ignore updates from my own change
       
   879     "
       
   880     lockUpdates ifTrue:[
       
   881 	lockUpdates := false.
       
   882 	^ self
       
   883     ].
       
   884     ^ super getListFromModel
       
   885 
       
   886     "Modified: 29.4.1996 / 12:42:33 / cg"
       
   887 !
       
   888 
       
   889 update:something with:aParameter from:changedObject
       
   890     changedObject == acceptChannel ifTrue:[
       
   891         acceptChannel value == true ifTrue:[ 
       
   892             self accept.
       
   893         ].
       
   894         ^ self.
       
   895     ].
       
   896     super update:something with:aParameter from:changedObject
       
   897 
       
   898     "Created: / 30.1.1998 / 14:15:56 / cg"
       
   899     "Modified: / 1.2.1998 / 13:15:55 / cg"
       
   900 ! !
       
   901 
       
   902 !EditTextView methodsFor:'cursor handling'!
       
   903 
       
   904 cursorBacktab
       
   905     "move cursor to prev tabstop"
       
   906 
       
   907     self cursorCol:(self prevTabBefore:cursorCol).
       
   908 !
       
   909 
       
   910 cursorCol:newCol
       
   911     "move cursor to some column in the current line"
       
   912 
       
   913     |wasOn|
       
   914 
       
   915     wasOn := self hideCursor.
       
   916     cursorCol := self validateCursorCol:newCol inLine:cursorLine.
       
   917     self makeCursorVisibleAndShowCursor:wasOn.
       
   918 
       
   919     "Modified: 22.5.1996 / 14:25:53 / cg"
       
   920 !
       
   921 
       
   922 cursorDown
       
   923     "move cursor down; scroll if at end of visible text;
       
   924      beep if at end of physical text."
       
   925 
       
   926     |wasOn|
       
   927 
       
   928     self cursorDown:1.
       
   929 
       
   930     "/ cursor behond text ?
       
   931     cursorLine > list size ifTrue:[
       
   932         wasOn := self hideCursor.
       
   933         cursorLine := self validateCursorLine:(list size + 1).
       
   934         cursorCol := self validateCursorCol:cursorCol inLine:cursorLine.
       
   935         cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
   936         "/ wasOn ifTrue:[self showCursor].
       
   937         self makeCursorVisibleAndShowCursor:wasOn.
       
   938         self beep.
       
   939     ].
       
   940 
       
   941     "Modified: / 10.6.1998 / 17:00:23 / cg"
       
   942 !
       
   943 
       
   944 cursorDown:n
       
   945     "move cursor down by n lines; scroll if at end of visible text"
       
   946 
       
   947     |wasOn nv|
       
   948 
       
   949     cursorVisibleLine notNil ifTrue:[
       
   950         wasOn := self hideCursor.
       
   951         nv := cursorVisibleLine + n - 1.
       
   952         (nv >= nFullLinesShown) ifTrue:[
       
   953             self scrollDown:(nv - nFullLinesShown + 1)
       
   954         ].
       
   955         cursorLine := self validateCursorLine:(cursorLine + n).
       
   956         cursorCol := self validateCursorCol:cursorCol inLine:cursorLine.
       
   957         cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
   958         "/ wasOn ifTrue:[self showCursor].
       
   959         self makeCursorVisibleAndShowCursor:wasOn.
       
   960     ] ifFalse:[
       
   961         cursorLine isNil ifTrue:[
       
   962             cursorLine := firstLineShown
       
   963         ].
       
   964         cursorLine := self validateCursorLine:(cursorLine + n).
       
   965         cursorCol := self validateCursorCol:cursorCol inLine:cursorLine.
       
   966         cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
   967         self makeCursorVisible.
       
   968     ].
       
   969 
       
   970     "Modified: / 10.6.1998 / 16:59:17 / cg"
       
   971 !
       
   972 
       
   973 cursorHome
       
   974     "scroll to top AND move cursor to first line of text."
       
   975 
       
   976     self cursorLine:1 col:1
       
   977 
       
   978 "/    |wasOn|
       
   979 "/
       
   980 "/    wasOn := self hideCursor.
       
   981 "/    self scrollToTop.
       
   982 "/    cursorLine := cursorVisibleLine := 1.
       
   983 "/    cursorCol := self validateCursorCol:1 inLine:cursorLine.
       
   984 "/    self makeCursorVisibleAndShowCursor:wasOn.
       
   985 
       
   986     "Modified: 22.5.1996 / 18:26:42 / cg"
       
   987 !
       
   988 
       
   989 cursorLeft
       
   990     "move cursor to left"
       
   991 
       
   992     (cursorCol ~~ 1) ifTrue:[
       
   993         self cursorCol:(cursorCol - 1)
       
   994     ] ifFalse:[
       
   995 "/ no, do not wrap back to previous line
       
   996 "/        cursorLine ~~ 1 ifTrue:[
       
   997 "/            ST80Mode == true ifTrue:[
       
   998 "/                self cursorUp.
       
   999 "/                self cursorToEndOfLine.
       
  1000 "/           ]
       
  1001 "/        ]
       
  1002     ]
       
  1003 
       
  1004     "Modified: / 23.1.1998 / 12:37:13 / cg"
       
  1005 !
       
  1006 
       
  1007 cursorLine:line col:col
       
  1008     "this positions onto physical - not visible - line"
       
  1009 
       
  1010     |wasOn newCol|
       
  1011 
       
  1012     wasOn := self hideCursor.
       
  1013     cursorLine := self validateCursorLine:line.
       
  1014     cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  1015     (col < 1) ifTrue:[
       
  1016         newCol := 1
       
  1017     ] ifFalse:[
       
  1018         newCol := col.
       
  1019     ].
       
  1020     st80Mode ifTrue:[
       
  1021         (cursorLine == list size
       
  1022         and:[cursorLine ~~ line]) ifTrue:[
       
  1023             newCol := (self listAt:(list size)) size + 1.
       
  1024         ]
       
  1025     ].
       
  1026     cursorCol := self validateCursorCol:newCol inLine:cursorLine.
       
  1027     self makeCursorVisibleAndShowCursor:wasOn.
       
  1028 
       
  1029     "Modified: / 20.6.1998 / 18:19:06 / cg"
       
  1030 !
       
  1031 
       
  1032 cursorMovementAllowed
       
  1033     "return true, if the user may move the cursor around
       
  1034      (via button-click, or cursor-key with selection).
       
  1035      By default, true is returned, but this may be redefined
       
  1036      in special subclasses (such as a terminal view), where
       
  1037      this is not wanted"
       
  1038 
       
  1039     ^ true
       
  1040 
       
  1041     "Created: / 18.6.1998 / 14:11:16 / cg"
       
  1042 !
       
  1043 
       
  1044 cursorReturn
       
  1045     "move cursor to start of next line; scroll if at end of visible text"
       
  1046 
       
  1047     |wasOn|
       
  1048 
       
  1049     self checkForExistingLine:(cursorLine + 1).
       
  1050     cursorVisibleLine notNil ifTrue:[
       
  1051 	nFullLinesShown notNil ifTrue:[
       
  1052 	    (cursorVisibleLine >= nFullLinesShown) ifTrue:[self scrollDown]
       
  1053 	]
       
  1054     ].
       
  1055 
       
  1056     wasOn := self hideCursor.
       
  1057     cursorLine := self validateCursorLine:cursorLine + 1.
       
  1058     cursorCol := self validateCursorCol:1 inLine:cursorLine.
       
  1059     cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  1060     self makeCursorVisibleAndShowCursor:wasOn.
       
  1061 
       
  1062     "Modified: 22.5.1996 / 18:27:34 / cg"
       
  1063 !
       
  1064 
       
  1065 cursorRight
       
  1066     "move cursor to right"
       
  1067 
       
  1068     |l|
       
  1069 
       
  1070     st80Mode == true ifTrue:[
       
  1071         l := (self listAt:cursorLine).
       
  1072         cursorCol >= (l size + 1) ifTrue:[
       
  1073 "/ no, do not wrap to next line
       
  1074 "/            cursorLine < list size ifTrue:[
       
  1075 "/                self cursorReturn.
       
  1076 "/            ].
       
  1077             ^ self    
       
  1078         ]
       
  1079     ].    
       
  1080     self cursorCol:(cursorCol + 1)
       
  1081 
       
  1082     "Modified: / 20.6.1998 / 18:19:07 / cg"
       
  1083 !
       
  1084 
       
  1085 cursorShown:aBoolean
       
  1086     "change cursor visibility
       
  1087      return true if cursor was visible before."
       
  1088 
       
  1089     |oldState|
       
  1090 
       
  1091     oldState := cursorShown.
       
  1092 
       
  1093     aBoolean ifTrue:[
       
  1094         self drawCursor.
       
  1095     ] ifFalse:[
       
  1096         (cursorShown and:[shown]) ifTrue: [
       
  1097             self undrawCursor.
       
  1098         ].
       
  1099     ].
       
  1100     cursorShown := aBoolean.
       
  1101 
       
  1102     ^ oldState
       
  1103 
       
  1104     "Modified: / 30.3.1999 / 15:32:43 / stefan"
       
  1105     "Created: / 30.3.1999 / 15:59:30 / stefan"
       
  1106 !
       
  1107 
       
  1108 cursorTab
       
  1109     "move cursor to next tabstop"
       
  1110 
       
  1111     self cursorCol:(self nextTabAfter:cursorCol).
       
  1112 !
       
  1113 
       
  1114 cursorToBeginOfLine
       
  1115     "move cursor to start of current line"
       
  1116 
       
  1117     self cursorCol:1
       
  1118 !
       
  1119 
       
  1120 cursorToBottom
       
  1121     "move cursor to last line of text"
       
  1122 
       
  1123     |wasOn newTop|
       
  1124 
       
  1125     wasOn := self hideCursor.
       
  1126 
       
  1127     newTop := list size - nFullLinesShown.
       
  1128     (newTop < 1) ifTrue:[
       
  1129 	newTop := 1
       
  1130     ].
       
  1131     self scrollToLine:newTop.
       
  1132     cursorLine := self validateCursorLine:list size.
       
  1133     cursorCol := self validateCursorCol:1 inLine:cursorLine.
       
  1134     cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  1135 
       
  1136     self makeCursorVisibleAndShowCursor:wasOn.
       
  1137 
       
  1138     "Modified: 22.5.1996 / 18:27:45 / cg"
       
  1139 !
       
  1140 
       
  1141 cursorToCharacterPosition:pos
       
  1142     "compute line/col from character position (1..)
       
  1143      and move the cursor onto that char"
       
  1144 
       
  1145     |line col|
       
  1146 
       
  1147     line := self lineOfCharacterPosition:pos.
       
  1148     col := pos - (self characterPositionOfLine:line col:1) + 1.
       
  1149     self cursorLine:line col:col
       
  1150 
       
  1151     "Created: / 15.1.1998 / 21:55:33 / cg"
       
  1152 !
       
  1153 
       
  1154 cursorToEnd
       
  1155     "move cursor down below last line of text"
       
  1156 
       
  1157     |wasOn newTop l line|
       
  1158 
       
  1159     l := list size.
       
  1160 
       
  1161     cursorLine >= l ifTrue:[
       
  1162 	line := self listAt:cursorLine.
       
  1163 	(line isNil or:[line isEmpty]) ifTrue:[
       
  1164 	    ^ self
       
  1165 	]
       
  1166     ].
       
  1167 
       
  1168     wasOn := self hideCursor.
       
  1169 
       
  1170     l := l + 1.
       
  1171     newTop :=  l - nFullLinesShown.
       
  1172     (newTop < 1) ifTrue:[
       
  1173 	newTop := 1
       
  1174     ].
       
  1175     self scrollToLine:newTop.
       
  1176     cursorLine := self validateCursorLine:l.
       
  1177     cursorCol := self validateCursorCol:1 inLine:1.
       
  1178     cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  1179 
       
  1180     self makeCursorVisibleAndShowCursor:wasOn.
       
  1181 
       
  1182     "Modified: 22.5.1996 / 18:27:53 / cg"
       
  1183 !
       
  1184 
       
  1185 cursorToEndOfLine
       
  1186     "move cursor to end of current line"
       
  1187 
       
  1188     |line|
       
  1189 
       
  1190     line := (self listAt:cursorLine).
       
  1191     self cursorCol:(line size + 1)
       
  1192 
       
  1193     "Modified: 13.8.1997 / 15:34:02 / cg"
       
  1194 !
       
  1195 
       
  1196 cursorToFirstVisibleLine
       
  1197     "place cursor into the first visible line; do not scroll."
       
  1198 
       
  1199     self cursorLine:(self visibleLineToAbsoluteLine:1) col:1
       
  1200 !
       
  1201 
       
  1202 cursorToLastVisibleLine
       
  1203     "place cursor into the first visible line; do not scroll."
       
  1204 
       
  1205     self cursorLine:(self visibleLineToAbsoluteLine:nFullLinesShown) col:1
       
  1206 !
       
  1207 
       
  1208 cursorToNextWord
       
  1209     "move the cursor to the beginning of the next word"
       
  1210 
       
  1211     |col line searching|
       
  1212 
       
  1213     (cursorLine > list size) ifTrue:[^ self].
       
  1214     self wordAtLine:cursorLine col:cursorCol do:[
       
  1215 	:beginLine :beginCol :endLine :endCol :style | 
       
  1216 
       
  1217 	line := endLine.
       
  1218 	col := endCol + 1.
       
  1219 	searching := true.
       
  1220 	[searching 
       
  1221 	 and:[(self characterAtLine:line col:col) isSeparator]] whileTrue:[
       
  1222 	    self wordAtLine:line col:col do:[
       
  1223 		:beginLine :beginCol :endLine :endCol :style |
       
  1224 
       
  1225 		(line > list size) ifTrue:[
       
  1226 		    "break out"
       
  1227 		    searching := false
       
  1228 		] ifFalse:[
       
  1229 		    line := endLine.
       
  1230 		    col := endCol + 1.
       
  1231 		]
       
  1232 	    ]
       
  1233 	].
       
  1234 	self cursorLine:line col:col
       
  1235     ]
       
  1236 !
       
  1237 
       
  1238 cursorToPreviousWord
       
  1239     "move the cursor to the beginning of this or the previous word"
       
  1240 
       
  1241     |col line searching l|
       
  1242 
       
  1243     (cursorLine > list size) ifTrue:[^ self].
       
  1244 
       
  1245     self wordAtLine:cursorLine col:cursorCol do:[
       
  1246 	:beginLine :beginCol :endLine :endCol :style | 
       
  1247 
       
  1248 	line := beginLine.
       
  1249 	col := beginCol.
       
  1250 	style == #wordLeft ifTrue:[
       
  1251 	    col := col + 1
       
  1252 	].
       
  1253 
       
  1254 	(cursorLine == line
       
  1255 	and:[cursorCol == col]) ifTrue:[
       
  1256 	    searching := true.
       
  1257 
       
  1258 	    col > 1 ifTrue:[
       
  1259 		col := col - 1.
       
  1260 	    ].
       
  1261 
       
  1262 	    [searching] whileTrue:[
       
  1263 		(col == 1) ifTrue:[    
       
  1264 		    line == 1 ifTrue:[
       
  1265 			searching := false
       
  1266 		    ] ifFalse:[
       
  1267 			line := line - 1.
       
  1268 			l := list at:line.
       
  1269 			col := l size + 1.
       
  1270 		    ]
       
  1271 		] ifFalse:[
       
  1272 		    (self characterAtLine:line col:col) isSeparator ifFalse:[
       
  1273 			self wordAtLine:line col:col do:[
       
  1274 			    :beginLine :beginCol :endLine :endCol :style |
       
  1275 
       
  1276 			    line := beginLine.
       
  1277 			    col := beginCol.
       
  1278 			    style == #wordLeft ifTrue:[
       
  1279 				col := col + 1
       
  1280 			    ].
       
  1281 			    searching := false.
       
  1282 			]
       
  1283 		    ] ifTrue:[
       
  1284 			col := col - 1
       
  1285 		    ]
       
  1286 		]
       
  1287 	    ]
       
  1288 	].
       
  1289 	self cursorLine:line col:col
       
  1290     ]
       
  1291 
       
  1292     "Created: 8.3.1996 / 21:52:48 / cg"
       
  1293     "Modified: 8.3.1996 / 22:12:45 / cg"
       
  1294 !
       
  1295 
       
  1296 cursorToTop
       
  1297     "move cursor to absolute home"
       
  1298 
       
  1299     self cursorLine:1 col:1
       
  1300 !
       
  1301 
       
  1302 cursorUp
       
  1303     "move cursor up; scroll if at start of visible text"
       
  1304 
       
  1305     self cursorUp:1
       
  1306 !
       
  1307 
       
  1308 cursorUp:n
       
  1309     "move cursor up n lines; scroll if at start of visible text"
       
  1310 
       
  1311     |wasOn nv nl|
       
  1312 
       
  1313     cursorLine isNil ifTrue:[
       
  1314 	cursorLine := firstLineShown + nFullLinesShown - 1.
       
  1315     ].
       
  1316     nl := cursorLine - n.
       
  1317     nl < 1 ifTrue:[nl := 1].
       
  1318 
       
  1319     (nl ~~ cursorLine) ifTrue: [
       
  1320 	wasOn := self hideCursor.
       
  1321 	cursorVisibleLine notNil ifTrue:[
       
  1322 	    nv := cursorVisibleLine - n.
       
  1323 	    nv < 1 ifTrue:[
       
  1324 		self scrollUp:(nv negated + 1)
       
  1325 	    ].
       
  1326 	].
       
  1327 	cursorLine := self validateCursorLine:nl.
       
  1328 	cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  1329 	cursorCol := self validateCursorCol:cursorCol inLine:cursorLine.
       
  1330 	wasOn ifTrue:[self showCursor].
       
  1331 "/
       
  1332 "/ to make cursor visible (even if below visible end):
       
  1333 "/
       
  1334 "/      self makeCursorVisibleAndShowCursor:wasOn.
       
  1335     ]
       
  1336 
       
  1337     "Modified: 22.5.1996 / 18:28:11 / cg"
       
  1338 !
       
  1339 
       
  1340 cursorVisibleLine:visibleLineNr col:colNr
       
  1341     "put cursor to visibleline/col"
       
  1342 
       
  1343     |wasOn newCol|
       
  1344 
       
  1345     wasOn := self hideCursor.
       
  1346     cursorLine := self validateCursorLine:(self visibleLineToAbsoluteLine:visibleLineNr).
       
  1347     cursorVisibleLine := visibleLineNr.
       
  1348     newCol := colNr.
       
  1349     (newCol < 1) ifTrue:[
       
  1350         newCol := 1
       
  1351     ].
       
  1352     cursorCol := self validateCursorCol:newCol inLine:cursorLine.
       
  1353     self makeCursorVisibleAndShowCursor:wasOn.
       
  1354 
       
  1355     "Modified: / 20.6.1998 / 18:40:28 / cg"
       
  1356 !
       
  1357 
       
  1358 cursorX:x y:y
       
  1359     "put cursor to position next to x/y coordinate in view"
       
  1360 
       
  1361     |line col|
       
  1362 
       
  1363     line := self visibleLineOfY:y.
       
  1364     col := self colOfX:x inVisibleLine:line.
       
  1365     self cursorVisibleLine:line col:col.
       
  1366 !
       
  1367 
       
  1368 drawCursor
       
  1369     "draw the cursor if shown and cursor is visible.
       
  1370      (but not, if there is a selection - to avoid confusion)"
       
  1371 
       
  1372     shown ifTrue:[
       
  1373 	cursorVisibleLine notNil ifTrue:[
       
  1374 	    self hasSelection ifFalse:[
       
  1375 		self drawCursorCharacter
       
  1376 	    ]
       
  1377 	]
       
  1378     ]
       
  1379 !
       
  1380 
       
  1381 drawCursor:cursorType with:fgColor and:bgColor
       
  1382     "draw a cursor; the argument cursorType specifies what type
       
  1383      of cursor should be drawn.
       
  1384      Currently, supported are: #block, #frame, #ibeam, #caret, #solidCaret
       
  1385                                #bigCaret and #bigSolidCaret"
       
  1386 
       
  1387     |x y w char y2 x1 x2 oldPaint oldClip|
       
  1388 
       
  1389     self hasSelection ifTrue:[
       
  1390         "
       
  1391          hide cursor, if there is a selection
       
  1392         "
       
  1393         ^ super redrawVisibleLine:cursorVisibleLine col:cursorCol.
       
  1394     ].
       
  1395 
       
  1396     cursorType == #none ifTrue:[
       
  1397         ^ self
       
  1398     ].
       
  1399 
       
  1400     cursorType == #block ifTrue:[
       
  1401         super drawVisibleLine:cursorVisibleLine 
       
  1402                           col:cursorCol 
       
  1403                          with:fgColor
       
  1404                           and:bgColor.
       
  1405         ^ self
       
  1406     ].
       
  1407     x := (self xOfCol:cursorCol inVisibleLine:cursorVisibleLine) - leftOffset.
       
  1408     y := self yOfVisibleLine:cursorVisibleLine.
       
  1409 
       
  1410     oldPaint := self paint. "/ do not clobber GC
       
  1411     cursorType == #frame ifTrue:[
       
  1412         super redrawVisibleLine:cursorVisibleLine col:cursorCol.
       
  1413 
       
  1414         char := self characterUnderCursor asString.
       
  1415         self paint:bgColor.
       
  1416         self displayRectangleX:x y:y 
       
  1417                          width:(font widthOf:char) height:fontHeight.
       
  1418     ] ifFalse:[
       
  1419         self paint:bgColor.
       
  1420         cursorType == #ibeam ifTrue:[
       
  1421             x1 := x - 1.
       
  1422             y2 := y + fontHeight - 1.
       
  1423             self displayLineFromX:x1 y:y toX:x1 y:y2. 
       
  1424             self displayLineFromX:x y:y toX:x y:y2. 
       
  1425             ^ self
       
  1426         ].
       
  1427 
       
  1428         cursorType == #Ibeam ifTrue:[
       
  1429             x1 := x - 1.
       
  1430             y2 := y + fontHeight - 1.
       
  1431             self displayLineFromX:x1 y:y toX:x1 y:y2. 
       
  1432             self displayLineFromX:x y:y toX:x y:y2. 
       
  1433             self displayLineFromX:x1-2 y:y toX:x+2 y:y. 
       
  1434             self displayLineFromX:x1-2 y:y2 toX:x+2 y:y2. 
       
  1435             ^ self
       
  1436         ].
       
  1437 
       
  1438         y := y + fontHeight - 3.
       
  1439         ((cursorType == #bigCaret) or:[cursorType == #bigSolidCaret]) ifTrue:[
       
  1440             w := (fontWidth * 2 // 3) max:4.
       
  1441             y2 := y + w + (w//2).
       
  1442         ] ifFalse:[
       
  1443             w := (fontWidth // 2) max:4.
       
  1444             y2 := y + w.
       
  1445         ].
       
  1446         x1 := x - w.
       
  1447         x2 := x + w.
       
  1448 
       
  1449         oldClip := self clippingRectangleOrNil.
       
  1450         self clippingRectangle:(margin@margin extent:(width-margin) @ (height-margin)).
       
  1451 
       
  1452         cursorType == #caret ifTrue:[
       
  1453             self lineWidth:2.
       
  1454             self displayLineFromX:x1 y:y2 toX:x y:y. 
       
  1455             self displayLineFromX:x y:y toX:x2 y:y2. 
       
  1456         ] ifFalse:[
       
  1457             "anything else: solidCaret"
       
  1458 
       
  1459             self fillPolygon:(Array with:(x1 @ y2)
       
  1460                                     with:(x @ y)
       
  1461                                     with:(x2 @ y2))
       
  1462         ].
       
  1463 
       
  1464         self clippingRectangle:oldClip
       
  1465     ].
       
  1466     self paint:oldPaint.
       
  1467 
       
  1468     "Modified: 18.2.1997 / 15:19:03 / cg"
       
  1469 !
       
  1470 
       
  1471 drawCursorCharacter
       
  1472     "draw the cursor. 
       
  1473      (i.e. the cursor if no selection)
       
  1474      - helper for many cursor methods"
       
  1475 
       
  1476     (hasKeyboardFocus 
       
  1477     and:[self enabled
       
  1478     and:[readOnly not]]) ifTrue:[
       
  1479         self drawFocusCursor
       
  1480     ] ifFalse:[
       
  1481         self drawNoFocusCursor
       
  1482     ]
       
  1483 
       
  1484     "Modified: / 23.3.1999 / 13:52:48 / cg"
       
  1485 !
       
  1486 
       
  1487 drawFocusCursor
       
  1488     "draw the cursor when the focus is in the view."
       
  1489 
       
  1490     self hasSelection ifTrue:[
       
  1491 	^ super redrawVisibleLine:cursorVisibleLine col:cursorCol.
       
  1492     ].
       
  1493     cursorType == #none ifTrue:[
       
  1494 	^ self undrawCursor
       
  1495     ].
       
  1496     self drawCursor:cursorType with:cursorFgColor and:cursorBgColor.
       
  1497 
       
  1498     "Modified: 22.9.1997 / 00:16:38 / cg"
       
  1499 !
       
  1500 
       
  1501 drawNoFocusCursor
       
  1502     "draw the cursor for the case when the view has no keyboard focus" 
       
  1503 
       
  1504     |cType|
       
  1505 
       
  1506     self hasSelection ifTrue:[
       
  1507 	^ super redrawVisibleLine:cursorVisibleLine col:cursorCol.
       
  1508     ].
       
  1509 
       
  1510     cType := cursorTypeNoFocus ? cursorType.
       
  1511     cType == #none ifTrue:[
       
  1512 	^ self undrawCursor
       
  1513     ].
       
  1514 
       
  1515     cType == #block ifTrue:[
       
  1516 	^ self drawCursor:#frame with:cursorNoFocusFgColor and:cursorBgColor
       
  1517     ].
       
  1518 
       
  1519     ^ self drawCursor:cType with:cursorNoFocusFgColor and:cursorNoFocusFgColor.
       
  1520 
       
  1521     "Modified: 22.9.1997 / 00:16:13 / cg"
       
  1522 !
       
  1523 
       
  1524 gotoLine:aLineNumber
       
  1525     "position cursor onto line, aLineNumber.
       
  1526      Make certain that this line is visible"
       
  1527 
       
  1528     self makeLineVisible:aLineNumber.
       
  1529     self cursorLine:aLineNumber col:1
       
  1530 !
       
  1531 
       
  1532 hideCursor
       
  1533     "make cursor invisible if currently invisible"
       
  1534 
       
  1535     ^ self cursorShown:false
       
  1536 
       
  1537     "Modified: / 30.3.1999 / 16:02:28 / stefan"
       
  1538 !
       
  1539 
       
  1540 makeCursorVisible
       
  1541     "scroll text to make cursorline visible 
       
  1542      (i.e. to have cursorLine in visible area)"
       
  1543 
       
  1544     |line col|
       
  1545 
       
  1546     cursorLine notNil ifTrue:[
       
  1547 	line := cursorLine.
       
  1548 	col := cursorCol.
       
  1549 	"
       
  1550 	 if there is a selection, its better to
       
  1551 	 have its start being visible, instead of the end
       
  1552 	"
       
  1553 	(selectionStartLine notNil 
       
  1554 	and:[selectionEndLine notNil]) ifTrue:[
       
  1555 	    expandingTop ~~ false ifTrue:[
       
  1556 		line := selectionStartLine.
       
  1557 		col := selectionStartCol.
       
  1558 	    ] ifFalse:[
       
  1559 		line := selectionEndLine.
       
  1560 		col := selectionEndCol
       
  1561 	    ]
       
  1562 	].
       
  1563 	self makeLineVisible:line.
       
  1564 	self makeColVisible:col inLine:line 
       
  1565     ]
       
  1566 
       
  1567     "Modified: 6.3.1996 / 13:46:46 / cg"
       
  1568 !
       
  1569 
       
  1570 makeCursorVisibleAndShowCursor:flag
       
  1571     "scroll to make cursorLine visible;
       
  1572      if flag is true, draw the cursor"
       
  1573 
       
  1574     self makeCursorVisible.
       
  1575     flag ifTrue:[self showCursor]
       
  1576 !
       
  1577 
       
  1578 showCursor
       
  1579     "make cursor visible if currently invisible"
       
  1580 
       
  1581     ^ self cursorShown:true
       
  1582 
       
  1583     "Modified: / 30.3.1999 / 16:02:34 / stefan"
       
  1584 !
       
  1585 
       
  1586 undrawCursor
       
  1587     "undraw the cursor (i.e. redraw the character(s) under the cursor)"
       
  1588 
       
  1589     |prevCol line oldClip x y|
       
  1590 
       
  1591     cursorVisibleLine notNil ifTrue:[
       
  1592         prevCol := cursorCol - 1.
       
  1593 
       
  1594         ((cursorType == #caret)
       
  1595          or:[cursorType == #solidCaret
       
  1596          or:[cursorType == #bigSolidCaret
       
  1597          or:[cursorType == #bigCaret
       
  1598          or:[cursorType == #Ibeam]]]]) ifTrue:[
       
  1599             "caret-cursor touches 4 characters"
       
  1600             ((cursorCol > 1) and:[fontIsFixedWidth]) ifTrue:[
       
  1601                 super redrawVisibleLine:cursorVisibleLine from:prevCol to:cursorCol.
       
  1602                 super redrawVisibleLine:cursorVisibleLine+1 from:prevCol to:cursorCol.
       
  1603             ] ifFalse:[
       
  1604                 "care for left margin"
       
  1605                 super redrawVisibleLine:cursorVisibleLine; redrawVisibleLine:cursorVisibleLine+1.
       
  1606             ].
       
  1607             ^ self
       
  1608         ].
       
  1609 
       
  1610         cursorType == #ibeam ifTrue:[
       
  1611             "ibeam-cursor touches 2 characters"
       
  1612             cursorCol > 1 ifTrue:[
       
  1613                 super redrawVisibleLine:cursorVisibleLine from:prevCol to:cursorCol.
       
  1614             ] ifFalse:[
       
  1615                 "care for left margin"
       
  1616                 super redrawVisibleLine:cursorVisibleLine.
       
  1617             ].
       
  1618             ^ self
       
  1619         ].
       
  1620 
       
  1621         "block cursor is simple - just one character under cursor"
       
  1622 
       
  1623         "/ however, if italic characters are involved, we must care
       
  1624         "/ for the chars before/after the cursor.
       
  1625         "/ We redraw the part of the previous character which got
       
  1626         "/ detroyed by the block cursor.
       
  1627         "/ (must change the clip, to avoid destroying the prev-prev character) 
       
  1628 
       
  1629         line := self visibleAt:cursorVisibleLine.
       
  1630         (line notNil and:[line isText]) ifTrue:[
       
  1631             cursorCol > 1 ifTrue:[
       
  1632                 oldClip := self clippingRectangleOrNil.
       
  1633                 x := (self xOfCol:cursorCol inVisibleLine:cursorVisibleLine) - leftOffset.
       
  1634                 y := self yOfVisibleLine:cursorVisibleLine.
       
  1635                 self clippingRectangle:(x@y extent:((font width * 2) @ fontHeight)).
       
  1636                 super redrawVisibleLine:cursorVisibleLine from:cursorCol-1 to:cursorCol.
       
  1637                 self clippingRectangle:oldClip.
       
  1638                 ^ self.
       
  1639             ].
       
  1640         ].
       
  1641         super redrawVisibleLine:cursorVisibleLine col:cursorCol
       
  1642     ]
       
  1643 
       
  1644     "Modified: / 22.4.1998 / 09:13:07 / cg"
       
  1645 !
       
  1646 
       
  1647 validateCursorCol:col inLine:line
       
  1648     "check of col is a valid cursor position; return a new col-nr if not.
       
  1649      Here, no limits are enforced (and col is returned), 
       
  1650      but it may be redefined in EditFields or views which dont like the 
       
  1651      cursor to be positioned behind the end of a textLine (vi/st-80 behavior)"
       
  1652 
       
  1653     |l max|
       
  1654 
       
  1655     "/ in ST80 mode,
       
  1656     "/ the cursor may not be positioned behond the
       
  1657     "/ end of a line or behond the last line of the text
       
  1658     "/
       
  1659     st80Mode == true ifTrue:[
       
  1660         l := (self listAt:line).
       
  1661         max := l size + 1.
       
  1662         col > max ifTrue:[
       
  1663             ^ max
       
  1664         ]
       
  1665     ].
       
  1666     ^ col
       
  1667 
       
  1668     "Created: / 22.5.1996 / 14:25:30 / cg"
       
  1669     "Modified: / 20.6.1998 / 18:19:24 / cg"
       
  1670 !
       
  1671 
       
  1672 validateCursorLine:line
       
  1673     "check of line is a valid cursor line; return a fixed line-nr if not.
       
  1674      Here, no limits are enforced (and line is returned), but it may be 
       
  1675      redefined in views which dont like the cursor to be positioned
       
  1676      behind the end of the text (vi/st-80 behavior), or want to
       
  1677      skip reserved regions"
       
  1678 
       
  1679     "/
       
  1680     "/ in st80Mode, the cursor may not be positioned
       
  1681     "/ behond the last line
       
  1682     "/
       
  1683     st80Mode == true ifTrue:[
       
  1684         ^ (line min:(list size)) max:1
       
  1685     ].
       
  1686     ^ line
       
  1687 
       
  1688     "Created: / 22.5.1996 / 18:22:23 / cg"
       
  1689     "Modified: / 20.6.1998 / 18:19:26 / cg"
       
  1690 !
       
  1691 
       
  1692 withCursorOffDo:aBlock
       
  1693     "evaluate aBlock with cursor off; turn it on afterwards."
       
  1694 
       
  1695     (shown not or:[cursorShown not]) ifTrue:[
       
  1696 	^ aBlock value
       
  1697     ].
       
  1698     self hideCursor.
       
  1699     aBlock valueNowOrOnUnwindDo:[
       
  1700 	self showCursor
       
  1701     ]
       
  1702 ! !
       
  1703 
       
  1704 !EditTextView methodsFor:'editing'!
       
  1705 
       
  1706 copyAndDeleteSelection
       
  1707     "copy the selection into the pastBuffer and delete it"
       
  1708 
       
  1709     selectionStartLine notNil ifTrue:[
       
  1710 	self setTextSelection:(self selection).
       
  1711 	self deleteSelection.
       
  1712     ].
       
  1713 
       
  1714     "Created: 27.1.1996 / 16:23:28 / cg"
       
  1715 !
       
  1716 
       
  1717 deleteCharAtCursor
       
  1718     "delete single character under cursor; does not merge lines"
       
  1719 
       
  1720     |wasOn|
       
  1721 
       
  1722     wasOn := self hideCursor.
       
  1723     self deleteCharAtLine:cursorLine col:cursorCol.
       
  1724     wasOn ifTrue:[self showCursor]
       
  1725 !
       
  1726 
       
  1727 deleteCharAtLine:lineNr col:colNr
       
  1728     "delete a single character at colNr in line lineNr"
       
  1729 
       
  1730     self deleteCharsAtLine:lineNr fromCol:colNr toCol:colNr
       
  1731 !
       
  1732 
       
  1733 deleteCharBeforeCursor
       
  1734     "delete single character to the left of cursor and move cursor to left"
       
  1735 
       
  1736     |soCol wasOn lineNrAboveCursor ln|
       
  1737 
       
  1738     wasOn := self hideCursor.
       
  1739 
       
  1740 	(autoIndent
       
  1741     and:[cursorCol  ~~ 1
       
  1742     and:[cursorLine <= (list size)]]) 
       
  1743      ifTrue:[
       
  1744 	soCol := (self leftIndentForLine:cursorLine) + 1.
       
  1745 
       
  1746 	(cursorCol == soCol and:[soCol > 1]) ifTrue:[
       
  1747 	    ln := list at:cursorLine.
       
  1748 	    (ln notNil and:[(ln indexOfNonSeparatorStartingAt:1) < soCol]) ifTrue:[
       
  1749 		soCol := 1
       
  1750 	    ]
       
  1751 	]
       
  1752     ] ifFalse:[
       
  1753 	soCol := 1
       
  1754     ].
       
  1755 
       
  1756     (cursorCol ~~ soCol and:[cursorCol ~~ 1]) ifTrue:[
       
  1757 	"
       
  1758 	 somewhere in the middle of a line
       
  1759 	"
       
  1760 	self cursorLeft.
       
  1761 	self deleteCharAtLine:cursorLine col:cursorCol.
       
  1762     ] ifFalse:[
       
  1763 	"
       
  1764 	 at begin of line - merge with previous line;
       
  1765 	 except for the very first line.
       
  1766 	"
       
  1767 	(cursorLine == 1) ifFalse:[
       
  1768 	    lineNrAboveCursor := self validateCursorLine:(cursorLine - 1).
       
  1769 	    lineNrAboveCursor < cursorLine ifTrue:[
       
  1770 		self mergeLine:lineNrAboveCursor removeBlanks:false.
       
  1771 	    ]
       
  1772 	]
       
  1773     ].
       
  1774     wasOn ifTrue:[ self showCursor ]
       
  1775 
       
  1776     "Modified: / 16.1.1998 / 22:33:04 / cg"
       
  1777 !
       
  1778 
       
  1779 deleteCharsAtLine:lineNr fromCol:colNr
       
  1780     "delete characters from colNr up to the end in line lineNr"
       
  1781 
       
  1782     |line|
       
  1783 
       
  1784     (line := self listAt:lineNr) notNil ifTrue:[
       
  1785 	self deleteCharsAtLine:lineNr fromCol:colNr toCol:(line size)
       
  1786     ]
       
  1787 
       
  1788 !
       
  1789 
       
  1790 deleteCharsAtLine:lineNr toCol:colNr
       
  1791     "delete characters from start up to colNr in line lineNr"
       
  1792 
       
  1793     self deleteCharsAtLine:lineNr fromCol:1 toCol:colNr
       
  1794 
       
  1795 
       
  1796 !
       
  1797 
       
  1798 deleteCursorLine
       
  1799     "delete the line where the cursor sits"
       
  1800 
       
  1801     self deleteLine:cursorLine
       
  1802 !
       
  1803 
       
  1804 deleteLine:lineNr
       
  1805     "delete line"
       
  1806 
       
  1807     self deleteFromLine:lineNr toLine:lineNr
       
  1808 
       
  1809 
       
  1810 !
       
  1811 
       
  1812 deleteLinesWithoutRedrawFrom:startLine to:endLine
       
  1813     "delete lines - no redraw;
       
  1814      return true, if something was really deleted"
       
  1815 
       
  1816     |lastLine|
       
  1817 
       
  1818     self checkModificationsAllowed ifFalse:[ ^ self].
       
  1819 
       
  1820     (list isNil or:[startLine > list size]) ifTrue:[^ false].
       
  1821     (endLine > list size) ifTrue:[
       
  1822         lastLine := list size
       
  1823     ] ifFalse:[
       
  1824         lastLine := endLine
       
  1825     ].
       
  1826     list removeFromIndex:startLine toIndex:lastLine.
       
  1827     "/ TODO: remember old maxwidth of linerange,
       
  1828     "/ only clear widthOfWidestLine, if this max
       
  1829     "/ length was (one of) the longest.
       
  1830     "/ avoids slow delete with huge texts.
       
  1831     widthOfWidestLine := nil. "/ i.e. unknown
       
  1832     self textChanged.
       
  1833     ^ true
       
  1834 
       
  1835     "Modified: / 10.11.1998 / 23:55:29 / cg"
       
  1836 !
       
  1837 
       
  1838 deleteSelection
       
  1839     "delete the selection"
       
  1840 
       
  1841     |wasOn startLine startCol endLine endCol|
       
  1842 
       
  1843     self checkModificationsAllowed ifFalse:[ ^ self].
       
  1844 
       
  1845     selectionStartLine notNil ifTrue:[
       
  1846 	wasOn := self hideCursor.
       
  1847 
       
  1848 	startLine := selectionStartLine.
       
  1849 	startCol := selectionStartCol.
       
  1850 	endLine := selectionEndLine.
       
  1851 	endCol := selectionEndCol.
       
  1852 	self unselectWithoutRedraw.
       
  1853 	self deleteFromLine:startLine col:startCol 
       
  1854 		     toLine:endLine col:endCol.
       
  1855 	cursorCol := startCol.
       
  1856 	cursorLine := startLine.
       
  1857 	cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  1858 	self makeCursorVisibleAndShowCursor:wasOn
       
  1859     ]
       
  1860 !
       
  1861 
       
  1862 insertCharAtCursor:aCharacter
       
  1863     "insert a single character at cursor-position - advance cursor."
       
  1864 
       
  1865     |wasOn|
       
  1866 
       
  1867     wasOn := self hideCursor.
       
  1868     aCharacter == Character tab ifTrue:[
       
  1869         "/ needs special care to advance cursor correctly
       
  1870         self insertTabAtCursor
       
  1871     ] ifFalse:[
       
  1872         self insert:aCharacter atLine:cursorLine col:cursorCol.
       
  1873         aCharacter == (Character cr) ifTrue:[
       
  1874             self cursorReturn
       
  1875         ] ifFalse:[
       
  1876             self cursorRight.
       
  1877         ].
       
  1878     ].
       
  1879     self makeCursorVisibleAndShowCursor:wasOn.
       
  1880 
       
  1881     "Modified: / 12.6.1998 / 21:50:20 / cg"
       
  1882 !
       
  1883 
       
  1884 insertLine:aString before:lineNr
       
  1885     "insert the line aString before line lineNr"
       
  1886 
       
  1887     ^ self insertLines:(Array with:aString) from:1 to:1  before:lineNr.
       
  1888 
       
  1889     "Modified: 14.5.1996 / 13:42:54 / cg"
       
  1890 !
       
  1891 
       
  1892 insertLines:aStringCollection before:lineNr
       
  1893     "insert a bunch before line lineNr"
       
  1894 
       
  1895     self insertLines:aStringCollection from:1 to:aStringCollection size before:lineNr
       
  1896 
       
  1897     "Modified: 6.9.1995 / 20:51:03 / claus"
       
  1898 !
       
  1899 
       
  1900 insertLines:lines withCR:withCr
       
  1901     "insert a bunch of lines at cursor position. 
       
  1902      Cursor is moved behind insertion.
       
  1903      If withCr is true, append cr after last line"
       
  1904 
       
  1905     |start end nLines wasOn|
       
  1906 
       
  1907     lines notNil ifTrue:[
       
  1908         nLines := lines size.
       
  1909         (nLines == 1) ifTrue:[
       
  1910             self insertStringAtCursor:(lines at:1).
       
  1911             withCr ifTrue:[
       
  1912                 self insertCharAtCursor:(Character cr)
       
  1913             ] 
       
  1914         ] ifFalse:[
       
  1915             (cursorCol ~~ 1) ifTrue:[
       
  1916                 self insertStringAtCursor:(lines at:1).
       
  1917                 self insertCharAtCursor:(Character cr).
       
  1918                 start := 2
       
  1919             ] ifFalse:[
       
  1920                 start := 1
       
  1921             ].
       
  1922             withCr ifTrue:[
       
  1923                 end := nLines
       
  1924             ] ifFalse:[
       
  1925                 end := nLines - 1
       
  1926             ].
       
  1927             (start < nLines) ifTrue:[
       
  1928                 (end >= start) ifTrue:[
       
  1929                     wasOn := self hideCursor.
       
  1930                     self insertLines:lines from:start to:end before:cursorLine.
       
  1931                     cursorLine := cursorLine + (end - start + 1).
       
  1932                     cursorVisibleLine := self absoluteLineToVisibleLine:cursorLine.
       
  1933                     wasOn ifTrue:[self showCursor].
       
  1934                 ]
       
  1935             ].
       
  1936             withCr ifFalse:[
       
  1937                 "last line without cr"
       
  1938                 self insertStringAtCursor:(lines at:nLines)
       
  1939             ]
       
  1940         ]
       
  1941     ]
       
  1942 
       
  1943     "Created: / 18.5.1996 / 15:32:06 / cg"
       
  1944     "Modified: / 12.6.1998 / 21:51:16 / cg"
       
  1945 !
       
  1946 
       
  1947 insertLines:lines withCr:withCr
       
  1948     "insert a bunch of lines at cursor position. Cursor
       
  1949      is moved behind insertion.
       
  1950      If withCr is true, append cr after last line"
       
  1951 
       
  1952     self obsoleteMethodWarning:'use #insertLines:withCR:'.
       
  1953     self insertLines:lines withCR:withCr.
       
  1954 
       
  1955     "Modified: 31.7.1997 / 23:07:22 / cg"
       
  1956 !
       
  1957 
       
  1958 insertSelectedStringAtCursor:aString
       
  1959     "insert the argument, aString at cursor position and select it"
       
  1960 
       
  1961     |startLine startCol|
       
  1962 
       
  1963     startLine := cursorLine.
       
  1964     startCol := cursorCol.
       
  1965     self insertStringAtCursor:aString.
       
  1966     self selectFromLine:startLine col:startCol
       
  1967 		 toLine:cursorLine col:(cursorCol - 1)
       
  1968 !
       
  1969 
       
  1970 insertString:aString atCharacterPosition:charPos
       
  1971     "insert the argument, aString at a character position"
       
  1972 
       
  1973     |line col|
       
  1974 
       
  1975     line := self lineOfCharacterPosition:charPos.
       
  1976     col := charPos - (self characterPositionOfLine:line col:1) + 1.
       
  1977     self insertString:aString atLine:line col:col
       
  1978 !
       
  1979 
       
  1980 insertString:aString atLine:lineNr col:colNr
       
  1981     "insert the string, aString at line/col;
       
  1982      handle cr's correctly"
       
  1983 
       
  1984     |start           "{ Class: SmallInteger }"
       
  1985      stop            "{ Class: SmallInteger }"
       
  1986      end             "{ Class: SmallInteger }"
       
  1987      subString c
       
  1988      l               "{ Class: SmallInteger }" |
       
  1989 
       
  1990     aString isNil ifTrue:[^ self].
       
  1991     (aString includes:(Character cr)) ifFalse:[
       
  1992         ^ self insertStringWithoutCRs:aString atLine:lineNr col:colNr
       
  1993     ].
       
  1994 
       
  1995     l := lineNr.
       
  1996     c := colNr.
       
  1997     start := 1.
       
  1998     end := aString size.
       
  1999     [start <= end] whileTrue:[
       
  2000         stop := aString indexOf:(Character cr) startingAt:start.
       
  2001         stop == 0 ifTrue:[
       
  2002             stop := end + 1
       
  2003         ].
       
  2004         subString := aString copyFrom:start to:(stop - 1).
       
  2005         self insertStringWithoutCRs:subString atLine:l col:c.
       
  2006         (stop <= end) ifTrue:[
       
  2007             c := c + subString size.
       
  2008             self insert:(Character cr) atLine:l col:c.
       
  2009             l := l + 1.
       
  2010             c := 1
       
  2011         ].
       
  2012         start := stop + 1
       
  2013     ]
       
  2014 
       
  2015     "Modified: / 10.6.1998 / 19:03:59 / cg"
       
  2016 !
       
  2017 
       
  2018 insertStringAtCursor:aString
       
  2019     "insert the argument, aString at cursor position
       
  2020      handle cr's correctly. A nil argument is interpreted as an empty line."
       
  2021 
       
  2022     aString isNil ifTrue:[
       
  2023         "new:"
       
  2024         self insertCharAtCursor:(Character cr).
       
  2025         ^ self
       
  2026     ].
       
  2027     (aString includes:(Character cr)) ifFalse:[
       
  2028         ^ self insertStringWithoutCRsAtCursor:aString
       
  2029     ].
       
  2030 
       
  2031     self insertLines:aString asStringCollection withCR:false.
       
  2032 
       
  2033     "Modified: / 10.6.1998 / 19:03:21 / cg"
       
  2034 !
       
  2035 
       
  2036 insertStringWithoutCRs:aString atLine:lineNr col:colNr
       
  2037     "insert aString (which has no crs) at lineNr/colNr"
       
  2038 
       
  2039     self withoutRedrawInsertStringWithoutCRs:aString atLine:lineNr col:colNr.
       
  2040     shown ifTrue:[self redrawLine:lineNr from:colNr]
       
  2041 
       
  2042     "Modified: / 5.4.1998 / 16:51:14 / cg"
       
  2043 !
       
  2044 
       
  2045 insertStringWithoutCRsAtCursor:aString
       
  2046     "insert a string (which has no crs) at cursor position
       
  2047      - advance cursor"
       
  2048 
       
  2049     |wasOn oldLen newLen|
       
  2050 
       
  2051     aString notNil ifTrue:[
       
  2052         wasOn := self hideCursor.
       
  2053         (aString includes:Character tab) ifTrue:[
       
  2054             self checkForExistingLine:cursorLine.
       
  2055             oldLen := (list at:cursorLine) size.
       
  2056             self insertString:aString atLine:cursorLine col:cursorCol.
       
  2057             newLen := (list at:cursorLine) size.
       
  2058             cursorCol := cursorCol + (newLen - oldLen).
       
  2059         ] ifFalse:[
       
  2060             self insertString:aString atLine:cursorLine col:cursorCol.
       
  2061             cursorCol := cursorCol + aString size.
       
  2062         ].
       
  2063         wasOn ifTrue:[self showCursor]
       
  2064     ]
       
  2065 
       
  2066     "Modified: / 10.6.1998 / 20:43:52 / cg"
       
  2067 !
       
  2068 
       
  2069 insertTabAtCursor
       
  2070     "insert spaces to next tab"
       
  2071 
       
  2072     |wasOn nextTab|
       
  2073 
       
  2074     wasOn := self hideCursor.
       
  2075     nextTab := self nextTabAfter:cursorCol.
       
  2076     self insertStringAtCursor:(String new:(nextTab - cursorCol)).
       
  2077     self makeCursorVisibleAndShowCursor:wasOn.
       
  2078 !
       
  2079 
       
  2080 removeTrailingBlankLines
       
  2081     "remove all blank lines at end of text"
       
  2082 
       
  2083     |lastLine "{ Class: SmallInteger }"
       
  2084      line finished|
       
  2085 
       
  2086     lastLine := list size.
       
  2087     finished := false.
       
  2088     [finished] whileFalse:[
       
  2089 	(lastLine <= 1) ifTrue:[
       
  2090 	    finished := true
       
  2091 	] ifFalse:[
       
  2092 	    line := list at:lastLine.
       
  2093 	    line notNil ifTrue:[
       
  2094 		line isBlank ifTrue:[
       
  2095 		    list at:lastLine put:nil.
       
  2096 		    line := nil
       
  2097 		]
       
  2098 	    ].
       
  2099 	    line notNil ifTrue:[
       
  2100 		finished := true
       
  2101 	    ] ifFalse:[
       
  2102 		lastLine := lastLine - 1
       
  2103 	    ]
       
  2104 	]
       
  2105     ].
       
  2106     (lastLine ~~ list size) ifTrue:[
       
  2107 	list grow:lastLine.
       
  2108 "/        self textChanged
       
  2109     ]
       
  2110 !
       
  2111 
       
  2112 replaceCharAtCursor:aCharacter
       
  2113     "replace a single character at cursor-position - advance cursor"
       
  2114 
       
  2115     |wasOn|
       
  2116 
       
  2117     wasOn := self hideCursor.
       
  2118     aCharacter == (Character cr) ifTrue:[
       
  2119 	self cursorReturn
       
  2120     ] ifFalse:[
       
  2121 	self replace:aCharacter atLine:cursorLine col:cursorCol.
       
  2122 	self cursorRight.
       
  2123     ].
       
  2124     self makeCursorVisibleAndShowCursor:wasOn.
       
  2125 
       
  2126     "Created: 6.3.1996 / 12:27:42 / cg"
       
  2127 !
       
  2128 
       
  2129 replaceLines:lines withCR:withCr
       
  2130     "replace a bunch of lines at cursor position. Cursor
       
  2131      is moved behind replacement.
       
  2132      If withCr is true, move to the beginning of the next line
       
  2133      after the last line"
       
  2134 
       
  2135     |line col nLines wasOn|
       
  2136 
       
  2137     lines notNil ifTrue:[
       
  2138         wasOn := self hideCursor.
       
  2139         nLines := lines size.
       
  2140         line := cursorLine.
       
  2141         col := cursorCol.
       
  2142         lines keysAndValuesDo:[:i :l |
       
  2143             self replaceString:l atLine:line col:col.
       
  2144             (i ~~ nLines or:[withCr]) ifTrue:[
       
  2145                 line := line + 1.
       
  2146                 col := 1.
       
  2147             ] ifFalse:[
       
  2148                 col := col + (l size).
       
  2149             ]
       
  2150         ].
       
  2151         self cursorLine:line col:col.
       
  2152         self makeCursorVisibleAndShowCursor:wasOn.
       
  2153         "/ wasOn ifTrue:[self showCursor].
       
  2154     ]
       
  2155 
       
  2156     "Created: / 18.5.1996 / 15:32:06 / cg"
       
  2157     "Modified: / 12.6.1998 / 22:05:51 / cg"
       
  2158 !
       
  2159 
       
  2160 replaceSelectionBy:something
       
  2161     "delete the selection (if any) and insert something, a character or string;
       
  2162      leave cursor after insertion"
       
  2163 
       
  2164     self replaceSelectionBy:something keepCursor:false
       
  2165 !
       
  2166 
       
  2167 replaceSelectionBy:something keepCursor:keep
       
  2168     "delete the selection (if any) and insert something, a character or string;
       
  2169      leave cursor after insertion or leave it, depending on keep"
       
  2170 
       
  2171     |sel l c|
       
  2172 
       
  2173     l := cursorLine.
       
  2174     c := cursorCol.
       
  2175 
       
  2176     sel := self selection.
       
  2177     sel notNil ifTrue:[
       
  2178 	lastString := sel.
       
  2179 	self deleteSelection.
       
  2180 	replacing := true.
       
  2181 	lastReplacement := ''
       
  2182     ].
       
  2183 
       
  2184     (something isMemberOf:Character) ifTrue:[
       
  2185 	lastReplacement notNil ifTrue:[
       
  2186 "/ "XXX - replacing text with spaces ..."
       
  2187 "/            (lastReplacement endsWith:Character space) ifTrue:[
       
  2188 "/                lastReplacement := lastReplacement copyWithoutLast:1 "copyTo:(lastReplacement size - 1)".
       
  2189 "/                lastReplacement := lastReplacement copyWith:something.
       
  2190 "/                lastReplacement := lastReplacement copyWith:Character space
       
  2191 "/            ] ifFalse:[
       
  2192 		lastReplacement := lastReplacement copyWith:something.
       
  2193 "/            ]
       
  2194 	].
       
  2195 	insertMode ifTrue:[
       
  2196 	    self insertCharAtCursor:something
       
  2197 	] ifFalse:[
       
  2198 	    self replaceCharAtCursor:something
       
  2199 	]
       
  2200     ] ifFalse:[
       
  2201 	lastReplacement := something.
       
  2202 	insertMode ifTrue:[
       
  2203 	    self insertStringAtCursor:something
       
  2204 	] ifFalse:[
       
  2205 	    self replaceStringAtCursor
       
  2206 	]
       
  2207     ].
       
  2208     keep ifTrue:[
       
  2209 	self cursorLine:l col:c
       
  2210     ]
       
  2211 
       
  2212     "Modified: 9.10.1996 / 16:14:35 / cg"
       
  2213 !
       
  2214 
       
  2215 replaceStringAtCursor:aString
       
  2216     "replace multiple characters at cursor-position - advance cursor"
       
  2217 
       
  2218     |wasOn i1 i2|
       
  2219 
       
  2220     wasOn := self hideCursor.
       
  2221     (aString includes:Character tab) ifTrue:[
       
  2222         "/ need special care for TAB (to move cursor correctly)
       
  2223         i1 := 1.
       
  2224         [i1 ~~ 0] whileTrue:[
       
  2225             i2 := aString indexOf:Character tab startingAt:i1.
       
  2226             i2 ~~ 0 ifTrue:[
       
  2227                 i1 ~~ i2 ifTrue:[
       
  2228                     self replaceString:(aString copyFrom:i1 to:i2-1) atLine:cursorLine col:cursorCol.
       
  2229                     self cursorCol:(cursorCol + (i2 - i1)).
       
  2230                 ].
       
  2231                 self replaceTABAtCursor.
       
  2232                 i2 := i2 + 1.
       
  2233             ] ifFalse:[
       
  2234                 self replaceString:(aString copyFrom:i1) atLine:cursorLine col:cursorCol.
       
  2235                 self cursorCol:(cursorCol + (aString size - i1 + 1)).
       
  2236             ].
       
  2237             i1 := i2.
       
  2238         ]
       
  2239     ] ifFalse:[
       
  2240         self replaceString:aString atLine:cursorLine col:cursorCol.
       
  2241         self cursorCol:(cursorCol + aString size).
       
  2242     ].
       
  2243     self makeCursorVisibleAndShowCursor:wasOn.
       
  2244 
       
  2245     "Created: / 9.6.1998 / 20:33:20 / cg"
       
  2246     "Modified: / 20.6.1998 / 19:41:02 / cg"
       
  2247 !
       
  2248 
       
  2249 replaceTABAtCursor
       
  2250     "replace a single character at cursor-position by a TAB character"
       
  2251 
       
  2252     |wasOn nextTab|
       
  2253 
       
  2254     wasOn := self hideCursor.
       
  2255     nextTab := self nextTabAfter:cursorCol.
       
  2256     self replaceStringAtCursor:(String new:(nextTab - cursorCol)).
       
  2257     self makeCursorVisibleAndShowCursor:wasOn.
       
  2258 
       
  2259     "Created: / 12.6.1998 / 21:53:23 / cg"
       
  2260 ! !
       
  2261 
       
  2262 !EditTextView methodsFor:'editing - basic'!
       
  2263 
       
  2264 deleteCharsAtLine:lineNr fromCol:startCol toCol:endCol
       
  2265     "delete characters from startCol to endCol in line lineNr
       
  2266     "
       
  2267     |line lineSize newLine start stop prevWidth newWidth|
       
  2268 
       
  2269     line := self listAt:lineNr.
       
  2270 
       
  2271     (self checkModificationsAllowed and:[line notNil]) ifTrue:[ 
       
  2272         lineSize := line size.
       
  2273 
       
  2274         startCol == 0     ifFalse:[ start := startCol ]
       
  2275                            ifTrue:[ start := 1 ]. 
       
  2276 
       
  2277         endCol > lineSize ifFalse:[ stop  := endCol ]
       
  2278                            ifTrue:[ stop  := lineSize ].
       
  2279 
       
  2280         stop >= start ifTrue:[
       
  2281             start ~~ 1 ifTrue:[ newLine := line copyFrom:1 to:(start-1) ]
       
  2282                       ifFalse:[ newLine := '' ].
       
  2283 
       
  2284             stop == lineSize ifFalse:[
       
  2285                 line bitsPerCharacter > newLine bitsPerCharacter ifTrue:[
       
  2286                     newLine := line string species fromString:newLine.
       
  2287                 ].
       
  2288                 newLine := newLine, (line copyFrom:(stop + 1) to:lineSize)
       
  2289             ].
       
  2290 
       
  2291             (trimBlankLines and:[newLine isBlank]) ifTrue:[
       
  2292                 newLine := nil
       
  2293             ].
       
  2294 
       
  2295             prevWidth := self widthOfLine:lineNr.
       
  2296 
       
  2297             list at:lineNr put:newLine.
       
  2298 
       
  2299             (prevWidth = widthOfWidestLine) ifTrue:[
       
  2300                 "/ remember old width of this line,
       
  2301                 "/ only clear widthOfWidestLine, if this lines
       
  2302                 "/ length was (one of) the longest.
       
  2303                 "/ avoids slow delete with huge texts.
       
  2304                 widthOfWidestLine := nil.   "i.e. unknown"
       
  2305 
       
  2306                 "/ scroll left if reqiured
       
  2307                 viewOrigin x > 0 ifTrue:[
       
  2308                     newWidth := self widthOfLine:lineNr.
       
  2309                     newWidth < (viewOrigin x + width) ifTrue:[
       
  2310                         self scrollHorizontalTo:(newWidth 
       
  2311                                                  - width 
       
  2312                                                  + margin + margin 
       
  2313                                                  + (font widthOf:'  '))
       
  2314                     ]
       
  2315                 ].
       
  2316             ].
       
  2317             self textChanged.
       
  2318             self redrawLine:lineNr from:start.
       
  2319 
       
  2320         ]
       
  2321     ]
       
  2322 
       
  2323     "Modified: / 11.11.1998 / 00:01:09 / cg"
       
  2324 !
       
  2325 
       
  2326 deleteFromLine:startLine col:startCol toLine:endLine col:endCol
       
  2327     "delete all text from startLine/startCol to endLine/endCol -
       
  2328      joining lines if nescessary"
       
  2329 
       
  2330     |line newLine lineSize nMore|
       
  2331 
       
  2332     self checkModificationsAllowed ifFalse:[ ^ self].
       
  2333     list isNil ifTrue:[^ self].
       
  2334     startLine > list size ifTrue:[ ^ self]. "/ deleted space below text
       
  2335 
       
  2336     (startLine == endLine) ifTrue:[
       
  2337         "/ delete chars within a line
       
  2338         self deleteCharsAtLine:startLine fromCol:startCol toCol:endCol.
       
  2339         ^ self
       
  2340     ].
       
  2341 
       
  2342     ((startCol == 1) and:[endCol == 0]) ifTrue:[
       
  2343         "/ delete full lines only
       
  2344         endLine > startLine ifTrue:[
       
  2345             self deleteFromLine:startLine toLine:(endLine - 1)
       
  2346         ].
       
  2347         ^ self
       
  2348     ].
       
  2349 
       
  2350     "/ delete right rest of 1st line
       
  2351     self deleteCharsAtLine:startLine fromCol:startCol.
       
  2352 
       
  2353     "/ delete the inner lines ...
       
  2354     endLine > (startLine + 1) ifTrue:[
       
  2355         self deleteFromLine:(startLine + 1) toLine:(endLine - 1)
       
  2356     ].
       
  2357 
       
  2358     (endCol ~~ 0) ifTrue:[
       
  2359         "/ delete the left rest of the last line
       
  2360 
       
  2361         self deleteCharsAtLine:(startLine + 1) toCol:endCol.
       
  2362 
       
  2363         "/ must add blanks, if startCol lies behond end of startLine
       
  2364 
       
  2365         line := list at:startLine.
       
  2366         lineSize := line size.
       
  2367         (startCol > lineSize) ifTrue:[
       
  2368             newLine := line.
       
  2369             line isNil ifTrue:[
       
  2370                 newLine := String new:(startCol - 1)
       
  2371             ] ifFalse:[
       
  2372                 nMore := startCol - 1 - lineSize.
       
  2373                 nMore > 0 ifTrue:[
       
  2374                     newLine := line , (line species new:nMore)
       
  2375                 ]
       
  2376             ].
       
  2377             newLine ~~ line ifTrue:[
       
  2378                 list at:startLine put:newLine.
       
  2379             ].
       
  2380             "/ TODO: remember old maxwidth of linerange,
       
  2381             "/ only clear widthOfWidestLine, if this max
       
  2382             "/ length was (one of) the longest.
       
  2383             "/ avoids slow delete with huge texts.
       
  2384             widthOfWidestLine := nil. "/ i.e. unknown
       
  2385             self textChanged.
       
  2386         ]
       
  2387     ].
       
  2388 
       
  2389     "/ merge the left rest of 1st line with right rest of last line into one
       
  2390     self mergeLine:startLine removeBlanks:false
       
  2391 
       
  2392     "Modified: / 10.11.1998 / 23:52:59 / cg"
       
  2393 !
       
  2394 
       
  2395 deleteFromLine:startLineNr toLine:endLineNr
       
  2396     "delete some lines"
       
  2397 
       
  2398     |wasOn nLines|
       
  2399 
       
  2400     self checkModificationsAllowed ifFalse:[ ^ self].
       
  2401     list isNil ifTrue:[^ self].
       
  2402 
       
  2403     wasOn := self hideCursor.
       
  2404 
       
  2405     "/ isnt this the same as:
       
  2406     "/ self deleteLinesWithoutRedrawFrom:startLineNr to:endLineNr.
       
  2407 
       
  2408     list removeFromIndex:startLineNr toIndex:(endLineNr min:list size).
       
  2409     "/ TODO: remember old maxwidth of linerange,
       
  2410     "/ only clear widthOfWidestLine, if this max
       
  2411     "/ length was (one of) the longest.
       
  2412     "/ avoids slow delete with huge texts.
       
  2413     widthOfWidestLine := nil. "/ i.e. unknown
       
  2414     self textChanged.
       
  2415 
       
  2416     self redrawFromLine:startLineNr.
       
  2417 
       
  2418     nLines := list size.
       
  2419     (firstLineShown >= nLines) ifTrue:[
       
  2420         self makeLineVisible:nLines
       
  2421     ].
       
  2422     wasOn ifTrue:[self showCursor].
       
  2423 
       
  2424     "Modified: / 10.11.1998 / 23:55:05 / cg"
       
  2425 !
       
  2426 
       
  2427 deleteLineWithoutRedraw:lineNr
       
  2428     "delete line - no redraw;
       
  2429      return true, if something was really deleted"
       
  2430 
       
  2431     self checkModificationsAllowed ifFalse:[ ^ self].
       
  2432 
       
  2433     (list isNil or:[lineNr > list size]) ifTrue:[^ false].
       
  2434     list removeIndex:lineNr.
       
  2435     "/ TODO: remember old maxwidth of linerange,
       
  2436     "/ only clear widthOfWidestLine, if this max
       
  2437     "/ length was (one of) the longest.
       
  2438     "/ avoids slow delete with huge texts.
       
  2439     widthOfWidestLine := nil. "/ i.e. unknown
       
  2440     self textChanged.
       
  2441     ^ true
       
  2442 
       
  2443     "Modified: / 10.11.1998 / 23:53:24 / cg"
       
  2444 !
       
  2445 
       
  2446 insert:aCharacter atLine:lineNr col:colNr
       
  2447     "insert a single character at lineNr/colNr; 
       
  2448      set emphasis to character at current position"
       
  2449 
       
  2450     |line lineSize newLine drawCharacterOnly attribute oldClip x y|
       
  2451 
       
  2452     self checkModificationsAllowed ifFalse:[ ^ self].
       
  2453 
       
  2454     aCharacter == (Character cr) ifTrue:[
       
  2455         self splitLine:lineNr before:colNr.
       
  2456         ^ self
       
  2457     ].
       
  2458 
       
  2459     drawCharacterOnly := false.
       
  2460     self checkForExistingLine:lineNr.
       
  2461     line := list at:lineNr.
       
  2462     lineSize := line size.
       
  2463 
       
  2464     st80Mode ~~ true ifTrue:[
       
  2465         (trimBlankLines 
       
  2466         and:[colNr > lineSize
       
  2467         and:[aCharacter == Character space]]) ifTrue:[
       
  2468             ^ self
       
  2469         ]
       
  2470     ].
       
  2471 
       
  2472     (lineSize == 0) ifTrue:[
       
  2473         newLine := aCharacter asString species new:colNr.
       
  2474         drawCharacterOnly := true
       
  2475     ] ifFalse: [
       
  2476         (colNr > lineSize) ifTrue: [
       
  2477             colNr == (lineSize +1) ifTrue:[
       
  2478                 attribute := line emphasisAt:lineSize
       
  2479             ].
       
  2480             newLine := line species new:colNr.
       
  2481             newLine replaceFrom:1 to:lineSize
       
  2482                            with:line startingAt:1.
       
  2483             drawCharacterOnly := true
       
  2484         ] ifFalse: [
       
  2485             attribute := line emphasisAt:colNr.
       
  2486             newLine   := line species new:(lineSize + 1).
       
  2487 
       
  2488             newLine replaceFrom:1 to:(colNr - 1)
       
  2489                            with:line startingAt:1.
       
  2490             newLine replaceFrom:(colNr + 1) to:(lineSize + 1)
       
  2491                            with:line startingAt:colNr
       
  2492         ]
       
  2493     ].
       
  2494 
       
  2495     newLine at:colNr put:aCharacter.
       
  2496 
       
  2497     attribute notNil ifTrue:[
       
  2498         newLine emphasisAt:colNr put:attribute
       
  2499     ].
       
  2500 
       
  2501     aCharacter == (Character tab) ifTrue:[
       
  2502         newLine := self withTabsExpanded:newLine.
       
  2503         drawCharacterOnly := false
       
  2504     ].
       
  2505 
       
  2506     list at:lineNr put:newLine.
       
  2507     widthOfWidestLine notNil ifTrue:[
       
  2508         widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line).
       
  2509     ].
       
  2510     self textChanged.
       
  2511     shown ifTrue:[
       
  2512         "/ care for italic text - in this case, we must also
       
  2513         "/ redraw the character before the insertion in order
       
  2514         "/ to fix the slanted piece of the character.
       
  2515         "/ (but we must clip, to avoid destoying the character before)
       
  2516         (newLine notNil and:[newLine isText]) ifTrue:[
       
  2517             colNr > 1 ifTrue:[
       
  2518                 oldClip := self clippingRectangleOrNil.
       
  2519                 x := (self xOfCol:colNr inVisibleLine:cursorVisibleLine) - leftOffset.
       
  2520                 y := self yOfVisibleLine:cursorVisibleLine.
       
  2521                 drawCharacterOnly ifTrue:[
       
  2522                     self clippingRectangle:(x@y extent:((font width * 2) @ fontHeight)).
       
  2523                     self redrawLine:lineNr from:colNr-1 to:colNr
       
  2524                 ] ifFalse:[
       
  2525                     self clippingRectangle:(x@y extent:((width - x) @ fontHeight)).
       
  2526                     self redrawLine:lineNr from:colNr-1
       
  2527                 ].
       
  2528                 self clippingRectangle:oldClip.
       
  2529                 ^ self.
       
  2530             ].
       
  2531         ].
       
  2532         drawCharacterOnly ifTrue:[
       
  2533             self redrawLine:lineNr col:colNr
       
  2534         ] ifFalse:[
       
  2535             self redrawLine:lineNr from:colNr
       
  2536         ]
       
  2537     ]
       
  2538 
       
  2539     "Modified: / 20.6.1998 / 18:19:22 / cg"
       
  2540 !
       
  2541 
       
  2542 insertLines:someText from:start to:end before:lineNr
       
  2543     "insert a bunch of lines before line lineNr"
       
  2544 
       
  2545     |text indent visLine w nLines "{ Class: SmallInteger }"
       
  2546      srcY "{ Class: SmallInteger }"
       
  2547      dstY "{ Class: SmallInteger }" |
       
  2548 
       
  2549     self isReadOnly ifTrue:[
       
  2550         ^ self
       
  2551     ].
       
  2552 
       
  2553     autoIndent ifTrue:[
       
  2554         indent := self leftIndentForLine:lineNr.
       
  2555 
       
  2556         text := someText collect:[:ln||line|
       
  2557             ln notNil ifTrue:[
       
  2558                 line := ln withoutLeadingSeparators.
       
  2559                 (line isEmpty or:[indent == 0]) ifFalse:[
       
  2560                     line := (String new:indent), line
       
  2561                 ].
       
  2562                 line
       
  2563             ] ifFalse:[
       
  2564                 nil
       
  2565             ]
       
  2566         ].
       
  2567     ] ifFalse:[
       
  2568         text := someText
       
  2569     ].
       
  2570 
       
  2571     visLine := self listLineToVisibleLine:lineNr.
       
  2572     (shown not or:[visLine isNil]) ifTrue:[
       
  2573         self withoutRedrawInsertLines:text
       
  2574                                  from:start to:end
       
  2575                                before:lineNr.
       
  2576     ] ifFalse:[
       
  2577         nLines := end - start + 1.
       
  2578         ((visLine + nLines) >= nLinesShown) ifTrue:[
       
  2579             self withoutRedrawInsertLines:text
       
  2580                                      from:start to:end
       
  2581                                    before:lineNr.
       
  2582             self redrawFromVisibleLine:visLine to:nLinesShown
       
  2583         ] ifFalse:[
       
  2584             w := self widthForScrollBetween:(lineNr + nLines)
       
  2585                                         and:(firstLineShown + nLines + nLinesShown).
       
  2586             srcY := topMargin + ((visLine - 1) * fontHeight).
       
  2587             dstY := srcY + (nLines * fontHeight).
       
  2588 
       
  2589             "/
       
  2590             "/ scroll ...
       
  2591             "/
       
  2592             "
       
  2593              stupid: must catchExpose before inserting new
       
  2594              stuff - since catchExpose may perform redraws
       
  2595             "
       
  2596             self catchExpose.
       
  2597             self withoutRedrawInsertLines:text
       
  2598                                      from:start to:end
       
  2599                                    before:lineNr.
       
  2600             self 
       
  2601                 copyFrom:self 
       
  2602                 x:textStartLeft y:srcY
       
  2603                 toX:textStartLeft y:dstY
       
  2604                 width:w
       
  2605                 height:(height - dstY)
       
  2606                 async:true.
       
  2607             self redrawFromVisibleLine:visLine to:(visLine + nLines - 1).
       
  2608             self waitForExpose
       
  2609         ].
       
  2610     ].
       
  2611     widthOfWidestLine notNil ifTrue:[
       
  2612         text do:[:line |
       
  2613             widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line).
       
  2614         ]
       
  2615     ].
       
  2616     self textChanged.
       
  2617 
       
  2618     "Modified: 29.1.1997 / 13:02:39 / cg"
       
  2619 !
       
  2620 
       
  2621 mergeLine:lineNr
       
  2622     "merge line lineNr with line lineNr+1"
       
  2623 
       
  2624     self mergeLine:lineNr removeBlanks:true
       
  2625 
       
  2626     "Modified: 9.9.1997 / 09:28:03 / cg"
       
  2627 !
       
  2628 
       
  2629 mergeLine:lineNr removeBlanks:removeBlanks
       
  2630     "merge line lineNr with line lineNr+1"
       
  2631 
       
  2632     |leftPart rightPart bothParts nextLineNr i|
       
  2633 
       
  2634     (list notNil and:[(list size) > lineNr]) ifFalse:[
       
  2635 	^ self
       
  2636     ].
       
  2637     leftPart := self listAt:lineNr.
       
  2638 
       
  2639     leftPart isNil ifTrue:[
       
  2640 	leftPart := ''.
       
  2641 	autoIndent ifTrue:[
       
  2642 	    (i := self leftIndentForLine:cursorLine) == 0 ifFalse:[
       
  2643 		leftPart := String new:i
       
  2644 	    ]
       
  2645 	]
       
  2646     ].
       
  2647     self cursorLine:lineNr col:((leftPart size) + 1).
       
  2648     nextLineNr := self validateCursorLine:(lineNr + 1).
       
  2649 
       
  2650     nextLineNr > (list size) ifFalse:[
       
  2651 	(rightPart := self listAt:nextLineNr) isNil ifTrue:[
       
  2652 	    rightPart := ''
       
  2653 	] ifFalse:[
       
  2654 	    removeBlanks ifTrue:[
       
  2655 		rightPart := rightPart withoutLeadingSeparators.
       
  2656 	    ]
       
  2657 	].
       
  2658 
       
  2659 	bothParts := leftPart , rightPart.
       
  2660 	(trimBlankLines and:[bothParts isBlank]) ifTrue:[bothParts := nil].
       
  2661 	list at:lineNr put:bothParts.
       
  2662 	self redrawLine:lineNr.
       
  2663 	self deleteLine:nextLineNr
       
  2664     ]
       
  2665 
       
  2666     "Created: 9.9.1997 / 09:27:38 / cg"
       
  2667     "Modified: 9.9.1997 / 09:28:27 / cg"
       
  2668 !
       
  2669 
       
  2670 replace:aCharacter atLine:lineNr col:colNr
       
  2671     "replace a single character at lineNr/colNr"
       
  2672 
       
  2673     |line lineSize newLine drawCharacterOnly|
       
  2674 
       
  2675     self checkModificationsAllowed ifFalse:[ ^ self].
       
  2676 
       
  2677     aCharacter == (Character cr) ifTrue:[
       
  2678         ^ self
       
  2679     ].
       
  2680 
       
  2681     drawCharacterOnly := true.
       
  2682     self checkForExistingLine:lineNr.
       
  2683     line := list at:lineNr.
       
  2684     lineSize := line size.
       
  2685 
       
  2686     (trimBlankLines
       
  2687     and:[colNr > lineSize
       
  2688     and:[aCharacter == Character space]]) ifTrue:[
       
  2689         ^ self
       
  2690     ].
       
  2691 
       
  2692     (lineSize == 0) ifTrue:[
       
  2693         newLine := aCharacter asString species new:colNr.
       
  2694     ] ifFalse: [
       
  2695         (colNr > lineSize) ifTrue: [
       
  2696             newLine := line species new:colNr.
       
  2697             newLine replaceFrom:1 to:lineSize with:line startingAt:1.
       
  2698         ] ifFalse: [
       
  2699             newLine := line copy.
       
  2700         ]
       
  2701     ].
       
  2702     newLine at:colNr put:aCharacter.
       
  2703     aCharacter == (Character tab) ifTrue:[
       
  2704         newLine := self withTabsExpanded:newLine.
       
  2705         drawCharacterOnly := false
       
  2706     ].
       
  2707     list at:lineNr put:newLine.
       
  2708     widthOfWidestLine notNil ifTrue:[
       
  2709         widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line).
       
  2710     ].
       
  2711     self textChanged.
       
  2712     shown ifTrue:[
       
  2713         drawCharacterOnly ifTrue:[
       
  2714             self redrawLine:lineNr col:colNr
       
  2715         ] ifFalse:[
       
  2716             self redrawLine:lineNr from:colNr
       
  2717         ]
       
  2718     ]
       
  2719 
       
  2720     "Created: / 6.3.1996 / 12:29:20 / cg"
       
  2721     "Modified: / 10.6.1998 / 18:50:18 / cg"
       
  2722 !
       
  2723 
       
  2724 replaceString:aString atLine:lineNr col:colNr
       
  2725     "replace multiple characters starting at lineNr/colNr.
       
  2726      This is not prepared to encounter special chars (except TAB)
       
  2727      in the string."
       
  2728 
       
  2729     |line lineSize newLine endCol|
       
  2730 
       
  2731     self checkModificationsAllowed ifFalse:[ ^ self].
       
  2732 
       
  2733     self checkForExistingLine:lineNr.
       
  2734     line := list at:lineNr.
       
  2735     lineSize := line size.
       
  2736 
       
  2737     endCol := colNr + aString size - 1.
       
  2738     (lineSize == 0) ifTrue:[
       
  2739         newLine := aString species new:endCol.
       
  2740     ] ifFalse: [
       
  2741         (endCol > lineSize) ifTrue: [
       
  2742             aString isText ifTrue:[
       
  2743                 newLine := aString species new:endCol.
       
  2744             ] ifFalse:[
       
  2745                 newLine := line species new:endCol.
       
  2746             ].
       
  2747             newLine replaceFrom:1 to:lineSize with:line startingAt:1.
       
  2748         ] ifFalse: [
       
  2749             aString isText ifTrue:[
       
  2750                 newLine := aString species new:line size.
       
  2751                 newLine replaceFrom:1 to:lineSize with:line startingAt:1.
       
  2752             ] ifFalse:[
       
  2753                 newLine := line copy.
       
  2754             ]
       
  2755         ]
       
  2756     ].
       
  2757     newLine replaceFrom:colNr with:aString.
       
  2758     (aString includes:(Character tab)) ifTrue:[
       
  2759         newLine := self withTabsExpanded:newLine.
       
  2760     ].
       
  2761     list at:lineNr put:newLine.
       
  2762     widthOfWidestLine notNil ifTrue:[
       
  2763         widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line).
       
  2764     ].
       
  2765     self textChanged.
       
  2766     shown ifTrue:[
       
  2767         self redrawLine:lineNr from:colNr
       
  2768     ]
       
  2769 
       
  2770     "Created: / 11.6.1998 / 10:38:32 / cg"
       
  2771     "Modified: / 20.6.1998 / 20:23:50 / cg"
       
  2772 !
       
  2773 
       
  2774 splitLine:lineNr before:colNr
       
  2775     "split the line linNr before colNr; the right part (from colNr)
       
  2776      is cut off and inserted after lineNr; the view is redrawn"
       
  2777 
       
  2778     |line lineSize leftRest rightRest visLine w h mustWait    
       
  2779      srcY    "{ Class: SmallInteger }" |
       
  2780 
       
  2781     list isNil ifFalse:[
       
  2782 	lineNr > (list size) ifFalse:[
       
  2783 	    (colNr == 1) ifTrue:[
       
  2784 		self insertLine:nil before:lineNr.
       
  2785 		^ self
       
  2786 	    ].
       
  2787 	    line := list at:lineNr.
       
  2788 	    line isNil ifFalse:[
       
  2789 		lineSize := line size.
       
  2790 		(colNr <= lineSize) ifTrue:[
       
  2791 		    rightRest := line copyFrom:colNr to:lineSize.
       
  2792 		    (colNr > 1) ifTrue:[
       
  2793 			leftRest := line copyTo:(colNr - 1)
       
  2794 		    ]
       
  2795 		] ifFalse:[
       
  2796 		    leftRest := line
       
  2797 		]
       
  2798 	    ].
       
  2799 	    leftRest notNil ifTrue:[
       
  2800 		(trimBlankLines and:[leftRest isBlank]) ifTrue:[leftRest := nil]
       
  2801 	    ].
       
  2802 	    list at:lineNr put:leftRest.
       
  2803 	    self withoutRedrawInsertLine:rightRest before:(lineNr + 1).
       
  2804 
       
  2805 	    visLine := self listLineToVisibleLine:(lineNr).
       
  2806 	    visLine notNil ifTrue:[
       
  2807 		w := self widthForScrollBetween:lineNr
       
  2808 					    and:(firstLineShown + nLinesShown).
       
  2809 		srcY := topMargin + (visLine * fontHeight).
       
  2810 		h := ((nLinesShown - visLine - 1) * fontHeight).
       
  2811 		(mustWait := (w > 0 and:[h > 0])) ifTrue:[
       
  2812 		    self catchExpose.
       
  2813 		    self 
       
  2814 			copyFrom:self 
       
  2815 			x:textStartLeft y:srcY
       
  2816 			toX:textStartLeft y:(srcY + fontHeight)
       
  2817 			width:w
       
  2818 			height:((nLinesShown - visLine - 1) * fontHeight)
       
  2819 			async:true.
       
  2820 		].
       
  2821 		self redrawLine:lineNr.
       
  2822 		self redrawLine:(lineNr + 1).
       
  2823 		mustWait ifTrue:[self waitForExpose]
       
  2824 	    ].
       
  2825 	    widthOfWidestLine := nil. "/ unknown
       
  2826 	    self textChanged.
       
  2827 	]
       
  2828     ]
       
  2829 
       
  2830     "Modified: 29.1.1997 / 13:03:22 / cg"
       
  2831 !
       
  2832 
       
  2833 withoutRedrawInsertLine:aString before:lineNr
       
  2834     "insert the argument, aString before line lineNr; the string
       
  2835      becomes line nileNr; everything else is moved down; the view
       
  2836      is not redrawn"
       
  2837 
       
  2838     |line|
       
  2839 
       
  2840     self checkModificationsAllowed ifFalse:[ ^ self].
       
  2841 
       
  2842     line := aString.
       
  2843     line notNil ifTrue:[
       
  2844         line isString ifTrue:[
       
  2845             line isBlank ifTrue:[
       
  2846                 line := nil
       
  2847             ] ifFalse:[
       
  2848                 (line includes:(Character tab)) ifTrue:[
       
  2849                     line := self withTabsExpanded:line
       
  2850                 ]
       
  2851             ]
       
  2852         ]
       
  2853     ].
       
  2854     list isNil ifTrue: [
       
  2855         list := StringCollection new:lineNr
       
  2856     ] ifFalse: [
       
  2857         list grow:((list size + 1) max:lineNr)
       
  2858     ].
       
  2859 
       
  2860     "I have changed 'replaceFrom:to:with:startingAt:' to correctly handle 
       
  2861      overlapping copy - if it didn't, we had to use:"
       
  2862 "
       
  2863     index := list size.
       
  2864     [index > lineNr] whileTrue: [
       
  2865         pIndex := index - 1.
       
  2866         list at:index put:(list at:pIndex).
       
  2867         index := pIndex
       
  2868     ].
       
  2869 "
       
  2870     list replaceFrom:(lineNr + 1) to:(list size) with:list startingAt:lineNr.
       
  2871     list at:lineNr put:line.
       
  2872     self contentsChanged
       
  2873 
       
  2874     "Modified: / 10.6.1998 / 19:00:56 / cg"
       
  2875 !
       
  2876 
       
  2877 withoutRedrawInsertLines:lines from:start to:end before:lineNr
       
  2878     "insert a bunch of lines before line lineNr; the view is not redrawn"
       
  2879 
       
  2880     |newLine newLines nLines|
       
  2881 
       
  2882     self checkModificationsAllowed ifFalse:[ ^ self].
       
  2883 
       
  2884     nLines := end - start + 1.
       
  2885     newLines := Array new:(lines size).
       
  2886     start to:end do:[:index |
       
  2887         newLine := lines at:index.
       
  2888         newLine notNil ifTrue:[
       
  2889             newLine isString ifTrue:[
       
  2890                 newLine isBlank ifTrue:[
       
  2891                     newLine := nil
       
  2892                 ] ifFalse:[
       
  2893                     (newLine includes:(Character tab)) ifTrue:[
       
  2894                         newLine := self withTabsExpanded:newLine
       
  2895                     ]
       
  2896                 ]
       
  2897             ]
       
  2898         ].
       
  2899         newLines at:index put:newLine
       
  2900     ].
       
  2901     list isNil ifTrue: [
       
  2902         list := StringCollection new:(lineNr + nLines + 1)
       
  2903     ] ifFalse: [
       
  2904         list grow:((list size + nLines) max:(lineNr + nLines - 1))
       
  2905     ].
       
  2906 
       
  2907     "I have changed 'replaceFrom:to:with:startingAt:' to correctly handle 
       
  2908      overlapping copy - if it didn't, we had to use:"
       
  2909 "
       
  2910     index := list size.
       
  2911     [index > lineNr] whileTrue: [
       
  2912         pIndex := index - 1.
       
  2913         list at:index put:(list at:pIndex).
       
  2914         index := pIndex
       
  2915     ].
       
  2916 "
       
  2917     list replaceFrom:(lineNr + nLines) to:(list size) with:list startingAt:lineNr.
       
  2918     list replaceFrom:lineNr to:(lineNr + nLines - 1) with:newLines startingAt:start.
       
  2919     self contentsChanged
       
  2920 
       
  2921     "Modified: / 10.6.1998 / 19:01:16 / cg"
       
  2922 !
       
  2923 
       
  2924 withoutRedrawInsertStringWithoutCRs:aString atLine:lineNr col:colNr
       
  2925     "insert aString (which has no crs) at lineNr/colNr"
       
  2926 
       
  2927     |isText strLen line lineSize newLine stringType sz|
       
  2928 
       
  2929     (aString notNil) ifFalse:[ ^ self].
       
  2930 
       
  2931     strLen := aString size.
       
  2932     self checkForExistingLine:lineNr.
       
  2933 
       
  2934     stringType := aString string species.
       
  2935     isText     := aString isText.
       
  2936     line       := list at:lineNr.
       
  2937 
       
  2938     line notNil ifTrue:[
       
  2939         lineSize := line size.
       
  2940         line bitsPerCharacter > aString bitsPerCharacter ifTrue:[
       
  2941             stringType := line string species
       
  2942         ].
       
  2943         line isText ifTrue:[ isText := true ]
       
  2944 
       
  2945     ] ifFalse:[
       
  2946         lineSize := 0
       
  2947     ].
       
  2948 
       
  2949     ((colNr == 1) and:[lineSize == 0]) ifTrue: [
       
  2950         newLine := aString
       
  2951     ] ifFalse:[
       
  2952         (lineSize == 0 or:[colNr > lineSize]) ifTrue: [
       
  2953             sz := colNr + strLen - 1
       
  2954         ] ifFalse:[
       
  2955             sz := lineSize + strLen
       
  2956         ].
       
  2957 
       
  2958         isText ifFalse:[
       
  2959             newLine := stringType new:sz
       
  2960         ] ifTrue:[
       
  2961             newLine := Text string:(stringType new:sz)
       
  2962         ].
       
  2963 
       
  2964         (lineSize ~~ 0) ifTrue: [
       
  2965             (colNr > lineSize) ifTrue: [
       
  2966                 newLine replaceFrom:1 to:lineSize
       
  2967                                with:line startingAt:1
       
  2968             ] ifFalse: [
       
  2969                 newLine replaceFrom:1 to:(colNr - 1)
       
  2970                                with:line startingAt:1.
       
  2971                 newLine replaceFrom:(colNr + strLen) to:(lineSize + strLen)
       
  2972                                with:line startingAt:colNr
       
  2973             ]
       
  2974         ].
       
  2975         newLine replaceFrom:colNr to:(colNr + strLen - 1)
       
  2976                        with:aString startingAt:1
       
  2977     ].
       
  2978 
       
  2979     (aString includes:(Character tab)) ifTrue:[
       
  2980         newLine := self withTabsExpanded:newLine
       
  2981     ].
       
  2982 
       
  2983     list at:lineNr put:newLine.
       
  2984     widthOfWidestLine notNil ifTrue:[
       
  2985         widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:newLine).
       
  2986     ].
       
  2987     self textChanged.
       
  2988 
       
  2989     "Modified: / 10.6.1998 / 19:01:52 / cg"
       
  2990 ! !
       
  2991 
       
  2992 !EditTextView methodsFor:'event processing'!
       
  2993 
       
  2994 buttonPress:button x:x y:y
       
  2995     "hide the cursor when button is activated"
       
  2996 
       
  2997     hasKeyboardFocus := true.
       
  2998     cursorShown ifTrue: [
       
  2999         self drawCursor
       
  3000     ].
       
  3001 
       
  3002     ((button == 1) or:[button == #select]) ifTrue:[
       
  3003         self hideCursor
       
  3004     ].
       
  3005     (button == #paste) ifTrue:[
       
  3006         self pasteOrReplace.
       
  3007         ^ self
       
  3008     ].
       
  3009     super buttonPress:button x:x y:y
       
  3010 
       
  3011     "Modified: / 23.3.1999 / 13:51:40 / cg"
       
  3012 !
       
  3013 
       
  3014 buttonRelease:button x:x y:y
       
  3015     "move the cursor to the click-position of previous button press"
       
  3016 
       
  3017     ((button == 1) or:[button == #select]) ifTrue:[
       
  3018         typeOfSelection := nil. 
       
  3019         selectionStartLine isNil ifTrue:[
       
  3020             clickCol notNil ifTrue:[
       
  3021                 self cursorMovementAllowed ifTrue:[
       
  3022                     self cursorLine:clickLine col:clickCol
       
  3023                 ]
       
  3024             ]
       
  3025         ] ifFalse:[
       
  3026             lastString := nil. "new selection invalidates remembered string"
       
  3027         ].
       
  3028         self showCursor
       
  3029     ].
       
  3030     super buttonRelease:button x:x y:y
       
  3031 
       
  3032     "Modified: / 18.6.1998 / 14:14:05 / cg"
       
  3033 !
       
  3034 
       
  3035 keyPress:key x:x y:y
       
  3036     "handle keyboard input"
       
  3037 
       
  3038     <resource: #keyboard (#Paste #Insert #Cut #Again #Replace #Accept
       
  3039                           #Delete #BasicDelete #BackSpace #BasicBackspace
       
  3040                           #SelectWord
       
  3041                           #SearchMatchingParent #SelectMatchingParents 
       
  3042                           #SelectToEnd #SelectFromBeginning
       
  3043                           #BeginOfLine #EndOfLine #NextWord #PreviousWord
       
  3044                           #CursorRight #CursorDown #CursorLeft #CursorUp
       
  3045                           #Return #Tab #Escape
       
  3046                           #GotoLine #Delete #BeginOfText #EndOfText
       
  3047                           #SelectLine #ExpandSelectionByLine #DeleteLine
       
  3048                           #InsertLine
       
  3049                           #SelectLineFromBeginning
       
  3050                           #'F*' #'f*')>
       
  3051 
       
  3052     |sensor n fKeyMacros shifted i|
       
  3053 
       
  3054     sensor := self sensor.
       
  3055     shifted := (sensor ? device) shiftDown.
       
  3056 
       
  3057     (key isMemberOf:Character) ifTrue:[
       
  3058         self isReadOnly ifTrue:[
       
  3059             self flash
       
  3060         ] ifFalse:[
       
  3061             typeOfSelection == #paste ifTrue:[
       
  3062                 "pasted selection will NOT be replaced by keystroke"
       
  3063                 self unselect
       
  3064             ].
       
  3065 
       
  3066             "replace selection by what is typed in -
       
  3067              if word was selected with a space, keep it"
       
  3068 
       
  3069             (selectStyle == #wordLeft) ifTrue:[
       
  3070                 self replaceSelectionBy:(' ' copyWith:key)
       
  3071             ] ifFalse:[
       
  3072                 (selectStyle == #wordRight) ifTrue:[
       
  3073                     self replaceSelectionBy:(key asString , ' ').
       
  3074                     self cursorLeft
       
  3075                 ] ifFalse:[
       
  3076                     self replaceSelectionBy:key
       
  3077                 ]
       
  3078             ].
       
  3079             selectStyle := nil.
       
  3080 
       
  3081             showMatchingParenthesis ifTrue:[
       
  3082                 "emacs style parenthesis shower"
       
  3083 
       
  3084                 "claus: only do it for closing parenthesis -
       
  3085                         otherwise its too anoying.
       
  3086                 "
       
  3087 "
       
  3088                 (#( $( $) $[ $] ${ $} ) includes:key) ifTrue:[
       
  3089 "
       
  3090                 (#( $) $] $} ) includes:key) ifTrue:[
       
  3091                 self searchForMatchingParenthesisFromLine:cursorLine col:(cursorCol - 1)
       
  3092                                    ifFound:[:line :col |
       
  3093                                                 |savLine savCol|
       
  3094 
       
  3095                                                 self withCursor:Cursor eye do:[
       
  3096                                                     savLine := cursorLine.
       
  3097                                                     savCol := cursorCol.
       
  3098                                                     self cursorLine:line col:col.
       
  3099                                                     device flush.
       
  3100                                                     "/ want to wait 200ms, but not if another keyPress
       
  3101                                                     "/ arrives in the meantime ...
       
  3102                                                     "/
       
  3103                                                     5 timesRepeat:[
       
  3104                                                         (sensor notNil and:[sensor hasKeyPressEventFor:self]) ifFalse:[
       
  3105                                                             Processor activeProcess millisecondDelay:40.
       
  3106                                                         ]
       
  3107                                                     ].
       
  3108                                                     self cursorLine:savLine col:savCol
       
  3109                                                 ]
       
  3110                                            ]
       
  3111                                 ifNotFound:[self showNotFound]
       
  3112                                    onError:[self beep]
       
  3113                 ].
       
  3114             ].
       
  3115         ].
       
  3116         ^ self
       
  3117     ].                         
       
  3118 
       
  3119     replacing := false.
       
  3120 
       
  3121     "
       
  3122      Fn      pastes a key-sequence (but only if not overlayed with
       
  3123              another function in the keyboard map)
       
  3124 
       
  3125      see TextView>>:x:y
       
  3126     "
       
  3127     (key at:1) asLowercase == $f ifTrue:[
       
  3128         (('[fF][0-9]' match:key)
       
  3129         or:['[fF][0-9][0-9]' match:key]) ifTrue:[
       
  3130             shifted ifFalse:[
       
  3131                 fKeyMacros := UserPreferences current functionKeySequences.
       
  3132                 fKeyMacros notNil ifTrue:[
       
  3133                     (fKeyMacros includesKey:key) ifTrue:[
       
  3134                         self pasteOrReplace:(fKeyMacros at:key) asStringCollection.
       
  3135                         ^ self
       
  3136                     ]
       
  3137                 ]
       
  3138             ]
       
  3139         ].
       
  3140     ].
       
  3141 
       
  3142     (key == #Accept)  ifTrue:[^ self accept].
       
  3143 
       
  3144     ((key == #Paste) or:[key == #Insert]) ifTrue:[self pasteOrReplace. ^self].
       
  3145     (key == #Cut) ifTrue:[self cut. ^self].
       
  3146     (key == #Again) ifTrue:[self again. ^self].
       
  3147 
       
  3148     (key == #Replace) ifTrue:[self replace. ^self].
       
  3149     (key == #SelectWord) ifTrue:[
       
  3150         self makeCursorVisible.
       
  3151         ^ self selectWordUnderCursor. 
       
  3152     ].
       
  3153 
       
  3154     (key == #SearchMatchingParent) ifTrue:[^ self searchForMatchingParenthesis.].
       
  3155     (key == #SelectMatchingParents) ifTrue:[^ self searchForAndSelectMatchingParenthesis.].
       
  3156     (key == #SelectToEnd) ifTrue:[^ self selectUpToEnd.].
       
  3157     (key == #SelectFromBeginning) ifTrue:[^ self selectFromBeginning.].
       
  3158 
       
  3159 " disabled - nobody liked it ...
       
  3160   and if you like it, its better done in the keymap.
       
  3161 
       
  3162     (key == #Ctrlb) ifTrue:[self unselect. self cursorLeft. ^ self].
       
  3163     (key == #Ctrlf) ifTrue:[self unselect. self cursorRight. ^ self].
       
  3164     (key == #Ctrln) ifTrue:[self unselect. self cursorDown. ^ self].
       
  3165     (key == #Ctrlp) ifTrue:[self unselect. self cursorUp. ^ self].
       
  3166 "
       
  3167 
       
  3168     (key == #BeginOfLine) ifTrue:[
       
  3169         self unselect.
       
  3170         shifted ifTrue:[
       
  3171             self cursorHome
       
  3172         ] ifFalse:[
       
  3173             self cursorToBeginOfLine. 
       
  3174         ].
       
  3175         ^ self
       
  3176     ].
       
  3177     (key == #EndOfLine) ifTrue:[
       
  3178         self unselect.
       
  3179         shifted ifTrue:[
       
  3180             self cursorToBottom
       
  3181         ] ifFalse:[
       
  3182             self cursorToEndOfLine. 
       
  3183         ].
       
  3184         ^ self
       
  3185     ].
       
  3186     (key == #NextWord) ifTrue:[self cursorToNextWord. ^self].
       
  3187     (key == #PreviousWord) ifTrue:[self cursorToPreviousWord. ^self].
       
  3188     (key == #GotoLine) ifTrue:[self gotoLine. ^self].
       
  3189 
       
  3190     (key == #CursorRight) ifTrue:[
       
  3191         (shifted and:[selectionStartLine isNil]) ifTrue:[
       
  3192             selectionStartLine := selectionEndLine := clickStartLine := cursorLine.
       
  3193             selectionStartCol := selectionEndCol := clickStartCol := cursorCol.
       
  3194             expandingTop := false.
       
  3195             ^ self redrawLine:selectionStartLine. 
       
  3196         ].
       
  3197 
       
  3198         selectionStartLine notNil ifTrue:[
       
  3199             self cursorMovementAllowed ifTrue:[
       
  3200                 "/
       
  3201                 "/ treat the whole selection as cursor
       
  3202                 "/
       
  3203                 cursorLine := selectionEndLine.
       
  3204                 cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  3205                 selectionEndCol == 0 ifTrue:[
       
  3206                     selectionEndCol := 1.
       
  3207                 ].
       
  3208                 cursorCol := selectionEndCol.
       
  3209                 shifted ifTrue:[
       
  3210                     self expandSelectionRight.
       
  3211                     ^ self
       
  3212                 ].
       
  3213                 self unselect; makeCursorVisible.
       
  3214                 cursorCol == 1 ifTrue:[^ self].
       
  3215             ].
       
  3216         ].
       
  3217         self cursorRight. ^self
       
  3218     ].
       
  3219     (key == #CursorDown) ifTrue:[
       
  3220         (shifted and:[selectionStartLine isNil]) ifTrue:[
       
  3221             selectionStartLine := clickStartLine := cursorLine. selectionEndLine := cursorLine + 1.
       
  3222             selectionStartCol := clickStartCol := selectionEndCol := cursorCol.
       
  3223             self redrawLine:selectionStartLine. 
       
  3224             expandingTop := false.
       
  3225             ^ self redrawLine:selectionEndLine. 
       
  3226         ].
       
  3227 
       
  3228         selectionStartLine notNil ifTrue:[
       
  3229             self cursorMovementAllowed ifTrue:[
       
  3230                 "/
       
  3231                 "/ treat the whole selection as cursor
       
  3232                 "/
       
  3233                 cursorLine := selectionEndLine.
       
  3234                 cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  3235                 cursorCol := selectionStartCol.
       
  3236                 cursorCol == 0 ifTrue:[
       
  3237                     cursorCol := 1.
       
  3238                     cursorLine := cursorLine - 1.
       
  3239                     cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  3240                 ].
       
  3241                 self makeCursorVisible.
       
  3242 
       
  3243                 shifted ifTrue:[
       
  3244                     clickLine := cursorLine.
       
  3245                     clickCol := cursorCol.
       
  3246                     self expandSelectionDown.
       
  3247                     ^ self
       
  3248                 ].
       
  3249                 self unselect. 
       
  3250             ].
       
  3251         ].
       
  3252 
       
  3253         sensor isNil ifTrue:[
       
  3254             n := 1
       
  3255         ] ifFalse:[
       
  3256             n := 1 + (sensor compressKeyPressEventsWithKey:#CursorDown).
       
  3257         ].
       
  3258         self cursorDown:n. 
       
  3259         "/
       
  3260         "/ flush keyboard to avoid runaway cursor
       
  3261         "/
       
  3262         sensor notNil ifTrue:[self sensor flushKeyboardFor:self].
       
  3263         ^ self
       
  3264     ].
       
  3265     (key == #CursorLeft or:[key == #CursorUp]) ifTrue:[
       
  3266         (shifted and:[selectionStartLine isNil]) ifTrue:[
       
  3267             expandingTop := true.
       
  3268             key == #CursorLeft ifTrue:[
       
  3269                 cursorCol > 1 ifTrue:[
       
  3270                     selectionStartLine := selectionEndLine := clickStartLine := cursorLine.
       
  3271                     selectionEndCol := clickStartCol := cursorCol-1.
       
  3272                     selectionStartCol := cursorCol-1.
       
  3273                     ^ self redrawLine:selectionStartLine. 
       
  3274                 ]
       
  3275             ] ifFalse:[
       
  3276                 cursorLine > 1 ifTrue:[
       
  3277                     selectionEndLine := clickStartLine := cursorLine.
       
  3278                     selectionEndCol := selectionStartCol := clickStartCol := cursorCol.
       
  3279                     selectionStartLine := cursorLine - 1.
       
  3280                     ^ self redrawFromLine:selectionStartLine to:cursorLine. 
       
  3281                 ]
       
  3282             ]
       
  3283         ].
       
  3284 
       
  3285         selectionStartLine notNil ifTrue:[
       
  3286             self cursorMovementAllowed ifTrue:[
       
  3287                 "/
       
  3288                 "/ treat the whole selection as cursor
       
  3289                 "/
       
  3290                 cursorLine := selectionStartLine.
       
  3291                 cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  3292                 cursorCol := selectionStartCol.
       
  3293                 (key == #CursorLeft) ifTrue:[    
       
  3294                     cursorCol := cursorCol+1.  "/ compensate for followup crsr-left
       
  3295                 ].
       
  3296                 self makeCursorVisible.
       
  3297 
       
  3298                 shifted ifTrue:[
       
  3299                     (key == #CursorUp) ifTrue:[
       
  3300                         clickLine := cursorLine.
       
  3301                         ^ self expandSelectionUp.
       
  3302                     ].
       
  3303                     ^ self expandSelectionLeft.
       
  3304                 ].
       
  3305                 self unselect. 
       
  3306             ].
       
  3307         ].
       
  3308         (key == #CursorLeft) ifTrue:[
       
  3309             self cursorLeft. ^self
       
  3310         ].
       
  3311         (key == #CursorUp)        ifTrue:[
       
  3312             sensor isNil ifTrue:[
       
  3313                 n := 1
       
  3314             ] ifFalse:[
       
  3315                 n := 1 + (sensor compressKeyPressEventsWithKey:#CursorUp).
       
  3316             ].
       
  3317             self cursorUp:n. 
       
  3318             "/
       
  3319             "/ flush keyboard to avoid runaway cursor
       
  3320             "/
       
  3321             sensor notNil ifTrue:[sensor flushKeyboardFor:self].
       
  3322             ^ self
       
  3323         ].
       
  3324     ].
       
  3325 
       
  3326     (key == #Return)    ifTrue:[
       
  3327         shifted ifTrue:[
       
  3328             self unselect. self cursorReturn. ^self
       
  3329         ].
       
  3330         self isReadOnly ifTrue:[
       
  3331             self unselect; makeCursorVisible.
       
  3332             self cursorReturn
       
  3333         ] ifFalse:[
       
  3334             insertMode ifFalse:[
       
  3335                 self cursorReturn.
       
  3336                 autoIndent == true ifTrue:[
       
  3337                     i := self leftIndentForLine:(cursorLine + 1).
       
  3338                     self cursorCol:(i+1 max:1)
       
  3339                 ]
       
  3340             ] ifTrue:[
       
  3341                 "/ old version just unselected ...
       
  3342                 "/ self unselect; makeCursorVisible.
       
  3343 
       
  3344                 "/ new version deletes ...
       
  3345                 typeOfSelection == #paste ifTrue:[
       
  3346                     self unselect; makeCursorVisible.
       
  3347                 ] ifFalse:[
       
  3348                     self copyAndDeleteSelection.            
       
  3349                 ].
       
  3350                 self insertCharAtCursor:(Character cr). 
       
  3351                 autoIndent == true ifTrue:[
       
  3352                     i := self leftIndentForLine:cursorLine.
       
  3353                     self indentFromLine:cursorLine toLine:cursorLine.
       
  3354                     self cursorCol:(i+1 max:1)
       
  3355                 ].
       
  3356             ].
       
  3357         ].
       
  3358         ^self
       
  3359     ].
       
  3360 
       
  3361     (key == #Tab) ifTrue:[
       
  3362         self tabMeansNextField ifTrue:[^ super keyPress:key x:x y:y].
       
  3363 
       
  3364         shifted ifTrue:[
       
  3365             "
       
  3366              the old version used shift-tab as backtab,
       
  3367              however, backtab was seldom used.
       
  3368              An alternative is to make it a non-inserting tab ...
       
  3369             "
       
  3370             "/ self unselect. self cursorBacktab.
       
  3371             self unselect. self cursorTab. 
       
  3372             ^self
       
  3373         ].
       
  3374 
       
  3375         "
       
  3376          uncomment line below, if you like RAND/INed/MAXed editor behavior
       
  3377          (where tab-key is only cursor positioning)
       
  3378          this was the original behavior of the TAB key, but many people
       
  3379          complained ....
       
  3380         "
       
  3381         insertMode ifFalse:[
       
  3382             self unselect. self cursorTab. ^self
       
  3383         ].
       
  3384         self unselect. self insertTabAtCursor. 
       
  3385         ^self
       
  3386     ].
       
  3387 
       
  3388     (key == #BackSpace
       
  3389      or:[key == #BasicBackspace]) ifTrue:[
       
  3390         selectionStartLine notNil ifTrue:[
       
  3391             (key == #BasicBackspace) ifTrue:[
       
  3392                 ^ self deleteSelection.
       
  3393             ] ifFalse:[
       
  3394                 ^ self copyAndDeleteSelection.
       
  3395             ].
       
  3396         ].
       
  3397 
       
  3398         self makeCursorVisible.
       
  3399         self deleteCharBeforeCursor. ^self
       
  3400     ].
       
  3401 
       
  3402     (key == #Delete
       
  3403      or:[key == #BasicDelete]) ifTrue:[
       
  3404         selectionStartLine notNil ifTrue:[
       
  3405             (key == #BasicDelete) ifTrue:[
       
  3406                 ^ self deleteSelection.
       
  3407             ] ifFalse:[
       
  3408                 ^ self copyAndDeleteSelection.
       
  3409             ].
       
  3410         ].
       
  3411         self makeCursorVisible.
       
  3412         self deleteCharAtCursor. ^self
       
  3413     ].
       
  3414 
       
  3415     (key == #BeginOfText) ifTrue:[     "i.e. HOME"
       
  3416         self unselect. 
       
  3417         cursorVisibleLine == 1 ifTrue:[
       
  3418             self cursorHome.
       
  3419         ] ifFalse:[
       
  3420             self cursorToFirstVisibleLine
       
  3421         ].
       
  3422         ^ self
       
  3423     ].
       
  3424     (key == #EndOfText) ifTrue:[       "i.e. END"
       
  3425         self unselect.
       
  3426         cursorVisibleLine == nFullLinesShown ifTrue:[
       
  3427             self cursorToBottom.
       
  3428         ] ifFalse:[
       
  3429             self cursorToLastVisibleLine
       
  3430         ].
       
  3431         ^self
       
  3432     ].
       
  3433     ((key == #Escape)
       
  3434     or:[key == #SelectLineFromBeginning])    ifTrue:[
       
  3435         self makeCursorVisible.
       
  3436         self unselect. self selectCursorLineFromBeginning. ^ self
       
  3437     ].
       
  3438     (key == #SelectLine)    ifTrue:[
       
  3439         self makeCursorVisible.
       
  3440         self unselect. self selectCursorLine. ^ self
       
  3441     ].
       
  3442     (key == #ExpandSelectionByLine)    ifTrue:[
       
  3443 "/        self makeCursorVisible.
       
  3444         self selectExpandCursorLine. ^ self
       
  3445     ].
       
  3446     (key == #DeleteLine)    ifTrue:[
       
  3447         self makeCursorVisible.
       
  3448         self unselect. self deleteCursorLine. ^self
       
  3449     ].
       
  3450     (key == #InsertLine)    ifTrue:[
       
  3451         self makeCursorVisible.
       
  3452         self unselect. self insertLine:nil before:cursorLine. ^self
       
  3453     ].
       
  3454     super keyPress:key x:x y:y
       
  3455 
       
  3456     "Modified: / 6.2.1998 / 11:59:59 / stefan"
       
  3457     "Modified: / 20.9.1998 / 17:55:11 / cg"
       
  3458 !
       
  3459 
       
  3460 mapped
       
  3461     "view was made visible"
       
  3462 
       
  3463     super mapped.
       
  3464 "/    self makeCursorVisible.
       
  3465     cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  3466 
       
  3467     "Modified: 20.12.1996 / 14:15:56 / cg"
       
  3468 !
       
  3469 
       
  3470 pointerEnter:state x:x y:y
       
  3471     "mouse pointer entered - request the keyboard focus (sometimes)"
       
  3472 
       
  3473     self wantsFocusWithPointerEnter ifTrue:[
       
  3474         self requestFocus.
       
  3475     ].
       
  3476 !
       
  3477 
       
  3478 sizeChanged:how
       
  3479     "make certain, cursor is visible after the sizechange"
       
  3480 
       
  3481     |cv|
       
  3482 
       
  3483     cv := cursorVisibleLine.
       
  3484     super sizeChanged:how.
       
  3485     cv notNil ifTrue:[
       
  3486 	self makeLineVisible:cursorLine
       
  3487     ]
       
  3488 ! !
       
  3489 
       
  3490 !EditTextView methodsFor:'focus handling'!
       
  3491 
       
  3492 hasKeyboardFocus:aBoolean
       
  3493     "sent by the windowGroup, a delegate or myself to make me show a block cursor
       
  3494      (otherwise, I would not know about this)"
       
  3495 
       
  3496     hasKeyboardFocus := aBoolean.
       
  3497     (cursorShown 
       
  3498     and:[self enabled 
       
  3499     and:[readOnly not]]) ifTrue:[
       
  3500         self drawCursor
       
  3501     ].
       
  3502 
       
  3503     "Modified: / 23.3.1999 / 13:49:35 / cg"
       
  3504 !
       
  3505 
       
  3506 showFocus:explicit
       
  3507     "in addition to however my superclass thinks how a focusView is to be
       
  3508      displayed, show the cursor when I got the focus"
       
  3509 
       
  3510     self showCursor.
       
  3511     self hasKeyboardFocus:true.
       
  3512     super showFocus:explicit
       
  3513 
       
  3514     "Modified: 11.12.1996 / 16:56:54 / cg"
       
  3515 !
       
  3516 
       
  3517 wantsFocusWithPointerEnter
       
  3518     "return true, if I want the focus when
       
  3519      the mouse pointer enters"
       
  3520 
       
  3521     |pref|
       
  3522 
       
  3523     pref := UserPreferences current focusFollowsMouse.
       
  3524     (pref ~~ false
       
  3525     and:[(styleSheet at:#'editText.requestFocusOnPointerEnter' default:true)
       
  3526     and:[self enabled 
       
  3527     and:[readOnly not]]]) ifTrue:[
       
  3528         ^ true
       
  3529     ].
       
  3530 
       
  3531     ^ false
       
  3532 
       
  3533 
       
  3534 
       
  3535 ! !
       
  3536 
       
  3537 !EditTextView methodsFor:'formatting'!
       
  3538 
       
  3539 indent
       
  3540     "indent selected line-range"
       
  3541 
       
  3542     |start end|
       
  3543 
       
  3544     selectionStartLine isNil ifTrue:[^ self].
       
  3545     start := selectionStartLine.
       
  3546     end := selectionEndLine.
       
  3547     (selectionEndCol == 0) ifTrue:[
       
  3548 	end := end - 1
       
  3549     ].
       
  3550     self unselect.
       
  3551     self indentFromLine:start toLine:end
       
  3552 !
       
  3553 
       
  3554 indentFromLine:start toLine:end
       
  3555     "indent a line-range - this is don by searching for the 
       
  3556      last non-empty line before start, and change the indent
       
  3557      of the line based on that indent."
       
  3558 
       
  3559     |leftStart delta d line spaces|
       
  3560 
       
  3561     leftStart := self leftIndentForLine:start.
       
  3562     (leftStart == 0) ifTrue:[^ self].
       
  3563 
       
  3564     delta := leftStart - (self leftIndentOfLine:start).
       
  3565     (delta == 0) ifTrue:[^ self].
       
  3566     (delta > 0) ifTrue:[
       
  3567 	spaces := String new:delta
       
  3568     ].
       
  3569     start to:end do:[:lineNr |
       
  3570 	line := self listAt:lineNr.
       
  3571 	line notNil ifTrue:[
       
  3572 	    line isBlank ifTrue:[
       
  3573 		list at:lineNr put:nil
       
  3574 	    ] ifFalse:[
       
  3575 		(delta > 0) ifTrue:[
       
  3576 		    line := spaces , line.
       
  3577 		    widthOfWidestLine notNil ifTrue:[
       
  3578 			widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line).
       
  3579 		    ]
       
  3580 		] ifFalse:[
       
  3581 		    "check if deletion is ok"
       
  3582 		    d := delta negated + 1.
       
  3583 
       
  3584 		    line size > d ifTrue:[
       
  3585 			(line copyTo:(d - 1)) withoutSeparators isEmpty ifTrue:[
       
  3586 			    line := line copyFrom:d
       
  3587 			]
       
  3588 		    ].
       
  3589 		    widthOfWidestLine := nil
       
  3590 		].
       
  3591 		list at:lineNr put:line.
       
  3592 		self textChanged.
       
  3593 	    ]
       
  3594 	]
       
  3595     ].
       
  3596     self redrawFromLine:start to:end
       
  3597 
       
  3598     "Modified: 5.3.1996 / 14:59:18 / cg"
       
  3599 !
       
  3600 
       
  3601 leftIndentForLine:lineNr
       
  3602     "find an appropriate indent for a line.
       
  3603      this is done by searching for the last non-empty line before it
       
  3604      and returning its indent."
       
  3605 
       
  3606     "SHOULD GO TO ListView"
       
  3607 
       
  3608     |line lnr indent|
       
  3609 
       
  3610     lnr := lineNr.
       
  3611 
       
  3612     [lnr ~~ 1] whileTrue:[
       
  3613 	lnr  := lnr - 1.
       
  3614 	line := self listAt:lnr.
       
  3615 
       
  3616 	line notNil ifTrue:[
       
  3617 	    indent := line indexOfNonSeparatorStartingAt:1.
       
  3618 	    indent ~~ 0 ifTrue:[
       
  3619 		^ indent - 1
       
  3620 	    ]
       
  3621 	]
       
  3622     ].
       
  3623     ^ 0
       
  3624 
       
  3625     "Created: 5.3.1996 / 14:58:53 / cg"
       
  3626 ! !
       
  3627 
       
  3628 !EditTextView methodsFor:'initialization'!
       
  3629 
       
  3630 fetchDeviceResources
       
  3631     "fetch device colors, to avoid reallocation at redraw time"
       
  3632 
       
  3633     super fetchDeviceResources.
       
  3634 
       
  3635     cursorFgColor notNil ifTrue:[cursorFgColor := cursorFgColor onDevice:device].
       
  3636     cursorBgColor notNil ifTrue:[cursorBgColor := cursorBgColor onDevice:device].
       
  3637     cursorNoFocusFgColor notNil ifTrue:[cursorNoFocusFgColor := cursorNoFocusFgColor onDevice:device].
       
  3638 
       
  3639     "Created: 14.1.1997 / 00:15:24 / cg"
       
  3640     "Modified: 18.2.1997 / 15:02:46 / cg"
       
  3641 !
       
  3642 
       
  3643 initEvents
       
  3644     "enable enter/leave events in addition"
       
  3645 
       
  3646     super initEvents.
       
  3647     self enableEnterLeaveEvents
       
  3648 !
       
  3649 
       
  3650 initStyle
       
  3651     "initialize style specific stuff"
       
  3652 
       
  3653     super initStyle.
       
  3654     lockUpdates := false.
       
  3655 
       
  3656     cursorFgColor := DefaultCursorForegroundColor.
       
  3657     cursorFgColor isNil ifTrue:[cursorFgColor := bgColor].
       
  3658     cursorBgColor := DefaultCursorBackgroundColor.
       
  3659     cursorBgColor isNil ifTrue:[cursorBgColor := fgColor].
       
  3660     cursorType := cursorTypeNoFocus := DefaultCursorType.
       
  3661     DefaultCursorTypeNoFocus notNil ifTrue:[
       
  3662         cursorTypeNoFocus := DefaultCursorTypeNoFocus.
       
  3663     ].
       
  3664     cursorNoFocusFgColor := DefaultCursorNoFocusForegroundColor.
       
  3665     cursorNoFocusFgColor isNil ifTrue:[
       
  3666         cursorType ~~ #block ifTrue:[
       
  3667             cursorNoFocusFgColor := cursorBgColor
       
  3668         ] ifFalse:[
       
  3669             cursorNoFocusFgColor := cursorFgColor
       
  3670         ]
       
  3671     ].
       
  3672 
       
  3673     "Modified: / 20.5.1998 / 04:26:31 / cg"
       
  3674 !
       
  3675 
       
  3676 initialize
       
  3677     "initialize a new EditTextView;
       
  3678      setup some instance variables"
       
  3679 
       
  3680     super initialize.
       
  3681 
       
  3682     self level:-1.
       
  3683     readOnly := false.
       
  3684     fixedSize := false.
       
  3685     exceptionBlock := [:errorText | ].
       
  3686     cursorShown := prevCursorState := true.
       
  3687     cursorLine := 1.
       
  3688     cursorVisibleLine := 1.
       
  3689     cursorCol := 1.
       
  3690     modifiedChannel := ValueHolder newBoolean.
       
  3691     acceptChannel := ValueHolder newBoolean.
       
  3692     acceptChannel addDependent:self.
       
  3693     showMatchingParenthesis := false.
       
  3694     hasKeyboardFocus := false. "/ true.
       
  3695     tabMeansNextField := false.
       
  3696     autoIndent := false.
       
  3697     insertMode := true.
       
  3698     st80Mode := ST80Mode.
       
  3699     trimBlankLines := st80Mode not. "true."
       
  3700 
       
  3701     "Modified: / 20.6.1998 / 18:19:17 / cg"
       
  3702 ! !
       
  3703 
       
  3704 !EditTextView methodsFor:'menu actions'!
       
  3705 
       
  3706 cut
       
  3707     "cut selection into copybuffer"
       
  3708 
       
  3709     |line col history sel s|
       
  3710 
       
  3711     (self checkModificationsAllowed) ifFalse:[
       
  3712         self flash.
       
  3713         ^ self
       
  3714     ].
       
  3715 
       
  3716     sel := self selection.
       
  3717     sel notNil ifTrue:[
       
  3718         lastString := s := sel asStringWithCRs.
       
  3719         line := selectionStartLine.
       
  3720         col := selectionStartCol.
       
  3721         undoAction := [ self cursorLine:line col:col.
       
  3722                         self insertLines:(Array with:s) withCR:false.
       
  3723                       ].
       
  3724 
       
  3725         "
       
  3726          remember in CopyBuffer
       
  3727         "
       
  3728         self setTextSelection:lastString.
       
  3729 
       
  3730         "
       
  3731          append to DeleteHistory (if there is one)
       
  3732         "
       
  3733         history := Smalltalk at:#DeleteHistory.
       
  3734         history notNil ifTrue:[
       
  3735             history addAll:(lastString asStringCollection).
       
  3736             history size > 1000 ifTrue:[
       
  3737                 history := history copyFrom:(history size - 1000)
       
  3738             ].
       
  3739         ].
       
  3740 
       
  3741         "
       
  3742          now, delete it
       
  3743         "
       
  3744         self deleteSelection.
       
  3745         lastReplacement := nil
       
  3746     ] ifFalse:[
       
  3747         "
       
  3748          a cut without selection will search&cut again
       
  3749         "
       
  3750         self again
       
  3751     ]
       
  3752 
       
  3753     "Modified: / 5.4.1998 / 16:51:53 / cg"
       
  3754 !
       
  3755 
       
  3756 defaultForGotoLine
       
  3757     "return a default value to show in the gotoLine box"
       
  3758 
       
  3759     cursorLine notNil ifTrue:[
       
  3760 	^ cursorLine
       
  3761     ].
       
  3762     ^ super defaultForGotoLine
       
  3763 !
       
  3764 
       
  3765 editMenu
       
  3766     "return the views middleButtonMenu"
       
  3767 
       
  3768     <resource: #keyboard (#Again #Copy #Cut #Paste #Accept #Find #GotoLine #SaveAs #Print)>
       
  3769     <resource: #programMenu>
       
  3770 
       
  3771     |items m sub sensor|
       
  3772 
       
  3773     ((sensor := self sensor) notNil and:[sensor ctrlDown]) ifTrue:[
       
  3774         items := #(
       
  3775                         ('again (for all)'      multipleAgain)  
       
  3776                   ).
       
  3777     ] ifFalse:[
       
  3778         items := #(
       
  3779 "/                        ('undo'     undo                   )
       
  3780                         ('again'   again            Again  )
       
  3781                         ('-'                               )
       
  3782                         ('copy'    copySelection    Copy   )
       
  3783                         ('cut'     cut              Cut    )
       
  3784                         ('paste'   pasteOrReplace   Paste  )
       
  3785                         ('-'                               )
       
  3786                         ('accept'  accept           Accept )
       
  3787                         ('='                               )
       
  3788                         ('others'  others                  )
       
  3789                   ).
       
  3790     ].
       
  3791 
       
  3792     m := PopUpMenu itemList:items resources:resources.
       
  3793 
       
  3794     items := #(
       
  3795                     ('search ...'    search         Find         )
       
  3796                     ('goto ...'      gotoLine       GotoLine     )
       
  3797                     ('-'                                         )
       
  3798                     ('font ...'      changeFont                  )
       
  3799                     ('-'                                         )
       
  3800                     ('indent'        indent                      )
       
  3801                     ('autoIndent \c' autoIndent:                 )
       
  3802                     ('insertMode \c' insertMode:                 )
       
  3803                     ('-'                                         )
       
  3804                     ('save as ...'   save           SaveAs       )
       
  3805                     ('print'         doPrint        Print        )
       
  3806               ).
       
  3807 
       
  3808     sub := PopUpMenu itemList:items resources:resources performer:model.
       
  3809 
       
  3810     m subMenuAt:#others put:sub.
       
  3811     sub checkToggleAt:#autoIndent: put:autoIndent.
       
  3812     sub checkToggleAt:#insertMode: put:insertMode.
       
  3813 
       
  3814     self isReadOnly ifTrue:[
       
  3815         m disableAll:#(paste pasteOrReplace cut indent autoIndent: insertMode:)
       
  3816     ].
       
  3817     self hasSelection not ifTrue:[
       
  3818         m disable:#copySelection.
       
  3819     ].
       
  3820     (self hasSelection not or:[self isReadOnly]) ifTrue:[
       
  3821         m disable:#cut.
       
  3822     ].
       
  3823     (undoAction isNil) ifTrue:[
       
  3824         m disable:#undo.
       
  3825     ].
       
  3826     acceptEnabled == false ifTrue:[
       
  3827         m disable:#accept
       
  3828     ].
       
  3829     ^ m.
       
  3830 
       
  3831     "Modified: / 21.5.1998 / 15:52:38 / cg"
       
  3832 !
       
  3833 
       
  3834 paste
       
  3835     "paste the copybuffer; if there is a selection, unselect first.
       
  3836      Then paste at cursor position."
       
  3837 
       
  3838     |sel|
       
  3839 
       
  3840     self checkModificationsAllowed ifFalse:[
       
  3841         self flash.
       
  3842         ^ self
       
  3843     ].
       
  3844 
       
  3845     sel := self getTextSelection.
       
  3846     self unselect.  
       
  3847     sel notNil ifTrue:[
       
  3848         self paste:sel.
       
  3849     ]
       
  3850 
       
  3851     "Modified: / 5.4.1998 / 16:55:02 / cg"
       
  3852 !
       
  3853 
       
  3854 paste:someText
       
  3855     "paste someText at cursor"
       
  3856 
       
  3857     |s nLines startLine startCol l1 l2 c1 c2|
       
  3858 
       
  3859     self checkModificationsAllowed ifFalse:[^ self].
       
  3860 
       
  3861     someText notNil ifTrue:[
       
  3862         s := someText.
       
  3863         s isString ifTrue:[
       
  3864             s := s asStringCollection
       
  3865         ] ifFalse:[
       
  3866             (s isStringCollection) ifFalse:[
       
  3867                 self warn:'selection (' , s class name , ') is not convertable to Text'.
       
  3868                 ^ self
       
  3869             ]
       
  3870         ].
       
  3871         (nLines := s size) == 0 ifTrue:[^ self].
       
  3872         (nLines == 1 and:[(s at:1) size == 0]) ifTrue:[^ self].
       
  3873 
       
  3874         startLine := l1 := cursorLine.
       
  3875         startCol := c1 := cursorCol.
       
  3876         self insertLines:(s withTabsExpanded) withCR:false.
       
  3877         l2 := cursorLine.
       
  3878         c2 := (cursorCol - 1).
       
  3879         self selectFromLine:l1 col:c1 toLine:l2 col:c2.
       
  3880         typeOfSelection := #paste.
       
  3881         undoAction := [ self unselect.
       
  3882                         self deleteFromLine:l1 col:c1 toLine:l2 col:c2.
       
  3883                         self cursorLine:l1 col:c1.
       
  3884                       ].
       
  3885     ]
       
  3886 
       
  3887     "Modified: / 14.2.1996 / 11:14:14 / stefan"
       
  3888     "Modified: / 12.6.1998 / 22:12:00 / cg"
       
  3889 !
       
  3890 
       
  3891 pasteOrReplace
       
  3892     "paste the copybuffer; if there is a selection, replace it.
       
  3893      otherwise paste at cursor position. Replace is not done
       
  3894      for originating by a paste, to allow multiple
       
  3895      paste."
       
  3896 
       
  3897     |sel|
       
  3898 
       
  3899     self checkModificationsAllowed ifFalse:[
       
  3900         self flash.
       
  3901         ^ self
       
  3902     ].
       
  3903 
       
  3904     sel := self getTextSelection.
       
  3905     self pasteOrReplace:sel.
       
  3906 
       
  3907     "Modified: / 5.4.1998 / 16:55:16 / cg"
       
  3908 !
       
  3909 
       
  3910 pasteOrReplace:someText
       
  3911     "paste someText; if there is a selection, replace it.
       
  3912      otherwise paste at cursor position. Replace is not done
       
  3913      for originating by a paste, to allow multiple
       
  3914      paste."
       
  3915 
       
  3916     self checkModificationsAllowed ifFalse:[^ self].
       
  3917 
       
  3918     ((self hasSelection == true) and:[typeOfSelection ~~ #paste]) ifTrue:[
       
  3919         ^ self replace:someText
       
  3920     ].
       
  3921     self paste:someText.
       
  3922 
       
  3923     "Modified: / 5.4.1998 / 16:55:21 / cg"
       
  3924 !
       
  3925 
       
  3926 replace
       
  3927     "replace the selection by the contents of the copybuffer"
       
  3928 
       
  3929     |sel|
       
  3930 
       
  3931     self checkModificationsAllowed ifFalse:[^ self].
       
  3932 
       
  3933     sel := self getTextSelection.
       
  3934     sel notNil ifTrue:[
       
  3935         self replace:sel
       
  3936     ]
       
  3937 
       
  3938     "Modified: / 5.4.1998 / 16:55:24 / cg"
       
  3939 !
       
  3940 
       
  3941 replace:someText
       
  3942     "replace the selection by someText"
       
  3943 
       
  3944     |selected selectedString| 
       
  3945 
       
  3946     self checkModificationsAllowed ifFalse:[^ self].
       
  3947 
       
  3948     selected := self selection.
       
  3949     selected isNil ifTrue:[
       
  3950         ^ self paste:someText
       
  3951     ].
       
  3952     self deleteSelection.
       
  3953 
       
  3954     "take care, if we replace a selection without space by a word selected
       
  3955      with one - in this case we usually do not want the space.
       
  3956      But, if we replace a word-selected selection by something without a
       
  3957      space, we DO want the space added."
       
  3958 
       
  3959     selected size == 1 ifTrue:[
       
  3960         selectedString := selected at:1.
       
  3961     ].
       
  3962 
       
  3963     someText size == 1 ifTrue:[
       
  3964         |cutOffSpace addSpace replacement replacementString|
       
  3965 
       
  3966         cutOffSpace := false.
       
  3967         addSpace := false.
       
  3968         replacement := someText copy.
       
  3969 
       
  3970         selectedString notNil ifTrue:[
       
  3971             ((selectedString startsWith:' ') or:[selectedString endsWith:' ']) ifFalse:[
       
  3972                "selection has no space"
       
  3973 
       
  3974                 ((selectStyle == #wordleft) or:[selectStyle == #wordRight]) ifTrue:[
       
  3975                     cutOffSpace := true
       
  3976                 ]
       
  3977             ] ifTrue:[
       
  3978                 addSpace := true
       
  3979             ]
       
  3980         ].
       
  3981         replacementString := replacement at:1.
       
  3982         cutOffSpace ifTrue:[
       
  3983             (replacementString startsWith:' ') ifTrue:[
       
  3984                 replacementString := replacementString withoutSpaces
       
  3985             ].
       
  3986         ] ifFalse:[
       
  3987             selectStyle == #wordLeft ifTrue:[
       
  3988                 "want a space at left"
       
  3989                 (replacementString startsWith:' ') ifFalse:[
       
  3990                     replacementString := replacementString withoutSpaces.
       
  3991                     replacementString := ' ' , replacementString
       
  3992                 ]
       
  3993             ].
       
  3994             selectStyle == #wordRight ifTrue:[
       
  3995                 "want a space at right"
       
  3996 
       
  3997                 (replacementString endsWith:' ') ifFalse:[
       
  3998                     replacementString := replacementString withoutSpaces.
       
  3999                     replacementString := replacementString , ' '
       
  4000                 ]
       
  4001             ].
       
  4002         ].
       
  4003         replacement at:1 put: replacementString.
       
  4004         self paste:replacement.
       
  4005     ] ifFalse:[
       
  4006         self paste:someText
       
  4007     ].
       
  4008     lastString := selectedString.
       
  4009     lastReplacement := someText
       
  4010 
       
  4011     "Modified: / 14.2.1996 / 10:37:02 / stefan"
       
  4012     "Modified: / 5.4.1998 / 16:55:28 / cg"
       
  4013 !
       
  4014 
       
  4015 showDeleted
       
  4016     "open a readonly editor on all deleted text"
       
  4017 
       
  4018     |v|
       
  4019 
       
  4020     v := EditTextView openWith:(Smalltalk at:#DeleteHistory).
       
  4021     v readOnly:true.
       
  4022     v topView label:'deleted text'.
       
  4023 ! !
       
  4024 
       
  4025 !EditTextView methodsFor:'private'!
       
  4026 
       
  4027 checkModificationsAllowed
       
  4028     "check if the text can be modified (i.e. is not readOnly).
       
  4029      evaluate the exceptionBlock if not.
       
  4030      This block should be provided by the application or user of the textView,
       
  4031      and may show a warnBox or whatever."
       
  4032 
       
  4033     self isReadOnly ifTrue: [
       
  4034         exceptionBlock isNil ifTrue:[
       
  4035             ^ false
       
  4036         ].
       
  4037 
       
  4038         (exceptionBlock value:'Text may not be modified') ~~ true ifTrue:[
       
  4039             ^ false
       
  4040         ]
       
  4041     ].
       
  4042     ^ true
       
  4043 
       
  4044     "Modified: / 17.6.1998 / 15:51:10 / cg"
       
  4045 !
       
  4046 
       
  4047 textChanged
       
  4048     "my text was modified (internally).
       
  4049      Sent whenever text has been edited (not to confuse with
       
  4050      contentsChanged, which is triggered when the size has changed, and
       
  4051      is used to notify scrollers, other views etc.)"
       
  4052 
       
  4053     self contentsChanged.
       
  4054     self modified:true.
       
  4055     contentsWasSaved := false
       
  4056 
       
  4057     "Modified: 14.2.1997 / 16:58:38 / cg"
       
  4058 ! !
       
  4059 
       
  4060 !EditTextView methodsFor:'queries'!
       
  4061 
       
  4062 currentLine
       
  4063     "the current line (for relative gotos)"
       
  4064 
       
  4065     ^ cursorLine
       
  4066 
       
  4067     "Created: / 17.5.1998 / 20:07:52 / cg"
       
  4068 !
       
  4069 
       
  4070 isKeyboardConsumer
       
  4071     "return true, if the receiver is a keyboard consumer;
       
  4072      Return true here, redefined from SimpleView."
       
  4073 
       
  4074     ^ true
       
  4075 
       
  4076 !
       
  4077 
       
  4078 specClass
       
  4079     "redefined, since the name of my specClass is nonStandard (i.e. not EditTextSpec)"
       
  4080 
       
  4081     self class == EditTextView ifTrue:[^ TextEditorSpec].
       
  4082     ^ super specClass
       
  4083 
       
  4084     "Modified: / 31.10.1997 / 19:48:19 / cg"
       
  4085 !
       
  4086 
       
  4087 tabMeansNextField
       
  4088     "return true, if a Tab character should shift focus."
       
  4089 
       
  4090     "if not readOnly, I want my tab keys ..."
       
  4091 
       
  4092     ^ self isReadOnly or:[tabMeansNextField]
       
  4093 
       
  4094     "Created: 7.2.1996 / 19:15:31 / cg"
       
  4095 !
       
  4096 
       
  4097 widthOfContents
       
  4098     "return the width of the contents in pixels
       
  4099      Redefined to add the size of a space (for the cursor).
       
  4100      this enables us to scroll one position further than the longest
       
  4101      line (and possibly see the cursor behind the line)"
       
  4102 
       
  4103     |w dev|
       
  4104 
       
  4105     w := super widthOfContents.
       
  4106     (dev := device) isNil ifTrue:[
       
  4107 	"/ really dont know ...
       
  4108 	dev := Screen current
       
  4109     ].
       
  4110     ^ w + (font widthOn:dev)
       
  4111 
       
  4112     "Modified: 28.5.1996 / 19:32:25 / cg"
       
  4113 ! !
       
  4114 
       
  4115 !EditTextView methodsFor:'realization'!
       
  4116 
       
  4117 realize
       
  4118     "make the view visible - scroll to make the cursor visible."
       
  4119 
       
  4120     super realize.
       
  4121 
       
  4122     self makeCursorVisible.
       
  4123     cursorFgColor := cursorFgColor onDevice:device.
       
  4124     cursorBgColor := cursorBgColor onDevice:device.
       
  4125 
       
  4126     "Modified: 20.12.1996 / 14:16:05 / cg"
       
  4127     "Created: 24.7.1997 / 18:24:12 / cg"
       
  4128 ! !
       
  4129 
       
  4130 !EditTextView methodsFor:'redrawing'!
       
  4131 
       
  4132 redrawCursorIfBetweenVisibleLine:startVisLine and:endVisLine
       
  4133     "redraw the cursor, if it sits in a line range"
       
  4134 
       
  4135     cursorShown ifTrue:[
       
  4136 	cursorVisibleLine notNil ifTrue:[
       
  4137 	    (cursorVisibleLine between:startVisLine and:endVisLine) ifTrue:[
       
  4138 		self drawCursorCharacter
       
  4139 	    ]
       
  4140 	]
       
  4141     ]
       
  4142 !
       
  4143 
       
  4144 redrawCursorIfInVisibleLine:visLine
       
  4145     "redraw the cursor, if it sits in visible line"
       
  4146 
       
  4147     cursorShown ifTrue:[
       
  4148 	(visLine == cursorVisibleLine) ifTrue:[
       
  4149 	    self drawCursorCharacter
       
  4150 	]
       
  4151     ]
       
  4152 !
       
  4153 
       
  4154 redrawFromVisibleLine:startVisLine to:endVisLine
       
  4155     "redraw a visible line range"
       
  4156 
       
  4157     super redrawFromVisibleLine:startVisLine to:endVisLine.
       
  4158     self redrawCursorIfBetweenVisibleLine:startVisLine and:endVisLine
       
  4159 !
       
  4160 
       
  4161 redrawVisibleLine:visLine
       
  4162     "redraw a visible line"
       
  4163 
       
  4164     super redrawVisibleLine:visLine.
       
  4165     self redrawCursorIfInVisibleLine:visLine
       
  4166 !
       
  4167 
       
  4168 redrawVisibleLine:visLine col:colNr
       
  4169     "redraw the single character in visibleline at colNr"
       
  4170 
       
  4171     cursorShown ifTrue:[
       
  4172 	(visLine == cursorVisibleLine) ifTrue:[
       
  4173 	    (colNr == cursorCol) ifTrue:[
       
  4174 		self drawCursorCharacter.
       
  4175 		^ self
       
  4176 	    ]
       
  4177 	]
       
  4178     ].
       
  4179     super redrawVisibleLine:visLine col:colNr
       
  4180 !
       
  4181 
       
  4182 redrawVisibleLine:visLine from:startCol
       
  4183     "redraw a visible line from startCol to the end of line"
       
  4184 
       
  4185     super redrawVisibleLine:visLine from:startCol.
       
  4186     self redrawCursorIfInVisibleLine:visLine
       
  4187 !
       
  4188 
       
  4189 redrawVisibleLine:visLine from:startCol to:endCol
       
  4190     "redraw a visible line from startCol to endCol"
       
  4191 
       
  4192     super redrawVisibleLine:visLine from:startCol to:endCol.
       
  4193     self redrawCursorIfInVisibleLine:visLine
       
  4194 ! !
       
  4195 
       
  4196 !EditTextView methodsFor:'scrolling'!
       
  4197 
       
  4198 halfPageDown
       
  4199     "half a page down - to keep cursor on same visible line, it has to be moved
       
  4200      within the real text  "
       
  4201 
       
  4202     |prevCursorLine|
       
  4203 
       
  4204     prevCursorLine := cursorVisibleLine.
       
  4205     super halfPageDown.
       
  4206     self cursorVisibleLine:prevCursorLine col:cursorCol
       
  4207 !
       
  4208 
       
  4209 halfPageUp
       
  4210     "half a page up - to keep cursor on same visible line, it has to be moved
       
  4211      within the real text  "
       
  4212 
       
  4213     |prevCursorLine|
       
  4214 
       
  4215     prevCursorLine := cursorVisibleLine.
       
  4216     super halfPageUp.
       
  4217     self cursorVisibleLine:prevCursorLine col:cursorCol
       
  4218 !
       
  4219 
       
  4220 originChanged:delta
       
  4221     "sent after scrolling - have to show the cursor if it was on before"
       
  4222 
       
  4223     super originChanged:delta.
       
  4224     "
       
  4225      should we move the cursor with the scroll - or leave it ?
       
  4226     "
       
  4227     cursorVisibleLine := self listLineToVisibleLine:cursorLine.
       
  4228     prevCursorState ifTrue:[
       
  4229         self showCursor
       
  4230     ]
       
  4231 
       
  4232     "Modified: / 17.6.1998 / 16:13:24 / cg"
       
  4233 !
       
  4234 
       
  4235 originWillChange
       
  4236     "sent before scrolling - have to hide the cursor"
       
  4237 
       
  4238     prevCursorState := cursorShown.
       
  4239     "/ cursorShown := false.
       
  4240     cursorShown ifTrue:[
       
  4241         self hideCursor
       
  4242     ]
       
  4243 
       
  4244     "Modified: / 6.7.1998 / 13:07:23 / cg"
       
  4245 !
       
  4246 
       
  4247 pageDown
       
  4248     "page down - to keep cursor on same visible line, it has to be moved
       
  4249      within the real text  "
       
  4250 
       
  4251     |prevCursorLine|
       
  4252 
       
  4253     prevCursorLine := cursorVisibleLine.
       
  4254     super pageDown.
       
  4255     self cursorVisibleLine:prevCursorLine col:cursorCol
       
  4256 !
       
  4257 
       
  4258 pageUp
       
  4259     "page up - to keep cursor on same visible line, it has to be moved
       
  4260      within the real text  "
       
  4261 
       
  4262     |prevCursorLine|
       
  4263 
       
  4264     prevCursorLine := cursorVisibleLine.
       
  4265     super pageUp.
       
  4266     self cursorVisibleLine:prevCursorLine col:cursorCol
       
  4267 ! !
       
  4268 
       
  4269 !EditTextView methodsFor:'searching'!
       
  4270 
       
  4271 searchBwd:pattern ifAbsent:aBlock
       
  4272     "do a backward search"
       
  4273 
       
  4274     |startLine startCol|
       
  4275 
       
  4276     cursorLine isNil ifTrue:[^ self].
       
  4277     selectionStartLine notNil ifTrue:[
       
  4278 	startLine := selectionStartLine.
       
  4279 	startCol := selectionStartCol
       
  4280     ] ifFalse:[
       
  4281 	startLine := cursorLine min:list size.
       
  4282 	startCol := cursorCol
       
  4283     ].
       
  4284     self 
       
  4285 	searchBackwardFor:pattern 
       
  4286 	startingAtLine:startLine col:startCol
       
  4287 	ifFound:[:line :col |
       
  4288 	    self cursorLine:line col:col.
       
  4289 	    self showMatch:pattern atLine:line col:col.
       
  4290 "/            self makeLineVisible:cursorLine
       
  4291 	    typeOfSelection := #search] 
       
  4292 	ifAbsent:aBlock
       
  4293 
       
  4294     "Modified: 9.10.1997 / 13:02:04 / cg"
       
  4295 !
       
  4296 
       
  4297 searchBwd:pattern ignoreCase:ign ifAbsent:aBlock
       
  4298     "do a backward search"
       
  4299 
       
  4300     |startLine startCol|
       
  4301 
       
  4302     cursorLine isNil ifTrue:[^ self].
       
  4303     selectionStartLine notNil ifTrue:[
       
  4304 	startLine := selectionStartLine.
       
  4305 	startCol := selectionStartCol
       
  4306     ] ifFalse:[
       
  4307 	startLine := cursorLine min:list size.
       
  4308 	startCol := cursorCol
       
  4309     ].
       
  4310     self 
       
  4311 	searchBackwardFor:pattern
       
  4312 	ignoreCase:ign
       
  4313 	startingAtLine:startLine col:startCol
       
  4314 	ifFound:[:line :col |
       
  4315 	    self cursorLine:line col:col.
       
  4316 	    self showMatch:pattern atLine:line col:col.
       
  4317 "/            self makeLineVisible:cursorLine
       
  4318 	    typeOfSelection := #search] 
       
  4319 	ifAbsent:aBlock
       
  4320 
       
  4321     "Modified: 9.10.1997 / 13:02:13 / cg"
       
  4322 !
       
  4323 
       
  4324 searchForAndSelectMatchingParenthesis
       
  4325     "select characters enclosed by matching parenthesis if one is under cusor"
       
  4326 
       
  4327     self 
       
  4328 	searchForMatchingParenthesisFromLine:cursorLine col:cursorCol
       
  4329 	ifFound:[:line :col | 
       
  4330 		  self selectFromLine:cursorLine col:cursorCol
       
  4331 			       toLine:line col:col]
       
  4332 	ifNotFound:[self showNotFound]
       
  4333 	onError:[self beep]
       
  4334 
       
  4335     "Modified: 9.10.1997 / 12:57:34 / cg"
       
  4336 !
       
  4337 
       
  4338 searchForMatchingParenthesis
       
  4339     "search for a matching parenthesis starting at cursor position. 
       
  4340      Search for the corresponding character is done forward if its an opening, 
       
  4341      backwards if its a closing parenthesis.
       
  4342      Positions the cursor if found, peeps if not"
       
  4343 
       
  4344      self 
       
  4345 	searchForMatchingParenthesisFromLine:cursorLine col:cursorCol
       
  4346 	ifFound:[:line :col | self cursorLine:line col:col]
       
  4347 	ifNotFound:[self showNotFound]
       
  4348 	onError:[self beep]
       
  4349 
       
  4350     "Modified: 9.10.1997 / 12:56:30 / cg"
       
  4351 !
       
  4352 
       
  4353 searchFwd:pattern ifAbsent:aBlock
       
  4354     "do a forward search"
       
  4355 
       
  4356     |startCol|
       
  4357 
       
  4358     "/ if there is no selection and the cursor is at the origin, 
       
  4359     "/ assume its the first search and do not skip the very first match
       
  4360     startCol := cursorCol.
       
  4361     self hasSelection ifFalse:[
       
  4362 	(cursorLine == 1 and:[cursorCol == 1]) ifTrue:[
       
  4363 	    startCol := 0
       
  4364 	]
       
  4365     ].
       
  4366 
       
  4367     self 
       
  4368 	searchFwd:pattern 
       
  4369 	startingAtLine:cursorLine col:startCol 
       
  4370 	ifAbsent:aBlock
       
  4371 
       
  4372     "Modified: 9.10.1997 / 12:58:59 / cg"
       
  4373 !
       
  4374 
       
  4375 searchFwd:pattern ignoreCase:ign ifAbsent:aBlock
       
  4376     "do a forward search"
       
  4377 
       
  4378     |startCol|
       
  4379 
       
  4380     "/ if there is no selection and the cursor is at the origin, 
       
  4381     "/ assume its the first search and do not skip the very first match
       
  4382     startCol := cursorCol.
       
  4383     self hasSelection ifFalse:[
       
  4384 	(cursorLine == 1 and:[cursorCol == 1]) ifTrue:[
       
  4385 	    startCol := 0
       
  4386 	]
       
  4387     ].
       
  4388 
       
  4389     self 
       
  4390 	searchFwd:pattern
       
  4391 	ignoreCase:ign
       
  4392 	startingAtLine:cursorLine col:startCol 
       
  4393 	ifAbsent:aBlock
       
  4394 
       
  4395     "Modified: 9.10.1997 / 12:58:59 / cg"
       
  4396     "Created: 9.10.1997 / 13:04:10 / cg"
       
  4397 !
       
  4398 
       
  4399 searchFwd:pattern ignoreCase:ign startingAtLine:startLine col:startCol ifAbsent:aBlock
       
  4400     "do a forward search"
       
  4401 
       
  4402     cursorLine isNil ifTrue:[^ self].
       
  4403     self 
       
  4404 	searchForwardFor:pattern 
       
  4405 	ignoreCase:ign
       
  4406 	startingAtLine:startLine col:startCol
       
  4407 	ifFound:[:line :col |
       
  4408 	    self cursorLine:line col:col.
       
  4409 	    self showMatch:pattern atLine:line col:col.
       
  4410 "/            self makeLineVisible:cursorLine
       
  4411 	    typeOfSelection := #search]
       
  4412 	ifAbsent:aBlock
       
  4413 
       
  4414     "Modified: 9.10.1997 / 12:57:47 / cg"
       
  4415     "Created: 9.10.1997 / 13:01:12 / cg"
       
  4416 !
       
  4417 
       
  4418 searchFwd:pattern startingAtLine:startLine col:startCol ifAbsent:aBlock
       
  4419     "do a forward search"
       
  4420 
       
  4421     self 
       
  4422 	searchForwardFor:pattern 
       
  4423 	startingAtLine:startLine col:startCol
       
  4424 	ifFound:[:line :col |
       
  4425 	    self cursorLine:line col:col.
       
  4426 	    self showMatch:pattern atLine:line col:col.
       
  4427 	    typeOfSelection := #search]
       
  4428 	ifAbsent:aBlock
       
  4429 
       
  4430     "Modified: 9.10.1997 / 13:07:52 / cg"
       
  4431 !
       
  4432 
       
  4433 setSearchPattern
       
  4434     "set the searchpattern from the selection if there is one, and position
       
  4435      cursor to start of pattern"
       
  4436 
       
  4437     |sel|
       
  4438 
       
  4439     "/
       
  4440     "/ if the last operation was a replcae, set pattern to last
       
  4441     "/ original string (for search after again)
       
  4442     "/
       
  4443     (lastString notNil 
       
  4444      and:[lastReplacement notNil
       
  4445      and:[typeOfSelection ~~ #search]]) ifTrue:[
       
  4446 	lastSearchPattern := lastString asString withoutSeparators.
       
  4447 	^ self
       
  4448     ].
       
  4449 
       
  4450     "/
       
  4451     "/ if there is a selection:
       
  4452     "/    if there was no previous search, take it as search pattern.
       
  4453     "/    if there was a previous search, only take the selection if
       
  4454     "/    it did not result from a paste.
       
  4455     "/    (to allow search-paste to be repeated)
       
  4456     "/
       
  4457     sel := self selection.
       
  4458     sel notNil ifTrue:[
       
  4459 	(lastSearchPattern isNil
       
  4460 	or:[typeOfSelection ~~ #paste]) ifTrue:[
       
  4461 	    self cursorLine:selectionStartLine col:selectionStartCol.
       
  4462 	    lastSearchPattern := sel asString withoutSeparators
       
  4463 	]
       
  4464     ]
       
  4465 
       
  4466     "Modified: 20.4.1996 / 12:50:13 / cg"
       
  4467 ! !
       
  4468 
       
  4469 !EditTextView methodsFor:'selections'!
       
  4470 
       
  4471 autoMoveCursorToEndOfSelection
       
  4472     "return true, if the cursor should be automatically moved to the
       
  4473      end of a selection.
       
  4474      Redefined to return false in terminaViews, where the cursor should
       
  4475      not be affected by selecting"
       
  4476 
       
  4477     ^ true
       
  4478 !
       
  4479 
       
  4480 selectAll
       
  4481     "select the whole text.
       
  4482      redefined to send super selectFrom... since we dont want the
       
  4483      cursor to be moved in this case."
       
  4484 
       
  4485     list isNil ifTrue:[
       
  4486 	self unselect
       
  4487     ] ifFalse:[
       
  4488 	super selectFromLine:1 col:1 toLine:(list size + 1) col:0.
       
  4489 	typeOfSelection := nil
       
  4490     ]
       
  4491 
       
  4492     "Modified: 28.2.1997 / 19:14:54 / cg"
       
  4493 !
       
  4494 
       
  4495 selectCursorLine
       
  4496     "select cursorline"
       
  4497 
       
  4498     self selectFromLine:cursorLine col:1 toLine:cursorLine+1 col:0 
       
  4499 !
       
  4500 
       
  4501 selectCursorLineFromBeginning
       
  4502     "select cursorline up to cursor position"
       
  4503 
       
  4504     cursorCol > 1 ifTrue:[
       
  4505 	self selectFromLine:cursorLine col:1
       
  4506 		     toLine:cursorLine col:(cursorCol-1)
       
  4507     ]
       
  4508 
       
  4509     "Modified: 16.8.1996 / 19:14:14 / cg"
       
  4510 !
       
  4511 
       
  4512 selectExpandCursorLine
       
  4513     "expand selection by one line or select cursorline"
       
  4514 
       
  4515     selectionStartLine isNil ifTrue:[
       
  4516 	self selectCursorLine
       
  4517     ] ifFalse:[
       
  4518 	self selectFromLine:selectionStartLine col:selectionStartCol
       
  4519 		     toLine:cursorLine+1 col:0.
       
  4520 	self makeLineVisible:selectionEndLine
       
  4521     ]
       
  4522 !
       
  4523 
       
  4524 selectFromBeginning
       
  4525     "select the text from the beginning to the current cursor position."
       
  4526 
       
  4527     |col|
       
  4528 
       
  4529     list isNil ifTrue:[
       
  4530 	self unselect
       
  4531     ] ifFalse:[
       
  4532 	cursorCol == 0 ifTrue:[
       
  4533 	    col := 0
       
  4534 	] ifFalse:[
       
  4535 	    col := cursorCol - 1
       
  4536 	].
       
  4537 	super selectFromLine:1 col:1 toLine:cursorLine col:col.
       
  4538 	typeOfSelection := nil
       
  4539     ]
       
  4540 !
       
  4541 
       
  4542 selectFromLine:startLine col:startCol toLine:endLine col:endCol
       
  4543     "when a range is selected, position the cursor behind the selection
       
  4544      for easier editing. Also typeOfSelection is nilled here."
       
  4545 
       
  4546     super selectFromLine:startLine col:startCol toLine:endLine col:endCol.
       
  4547     (selectionEndLine notNil and:[self autoMoveCursorToEndOfSelection]) ifTrue:[
       
  4548         self cursorLine:selectionEndLine col:(selectionEndCol + 1).
       
  4549     ].
       
  4550     typeOfSelection := nil
       
  4551 !
       
  4552 
       
  4553 selectUpToEnd
       
  4554     "select the text from the current cursor position to the end."
       
  4555 
       
  4556     list isNil ifTrue:[
       
  4557 	self unselect
       
  4558     ] ifFalse:[
       
  4559 	super selectFromLine:cursorLine col:cursorCol toLine:(list size + 1) col:0.
       
  4560 	typeOfSelection := nil
       
  4561     ]
       
  4562 !
       
  4563 
       
  4564 selectWordUnderCursor
       
  4565     "select the word under the cursor"
       
  4566 
       
  4567     self selectWordAtLine:cursorLine col:cursorCol
       
  4568 !
       
  4569 
       
  4570 unselect
       
  4571     "forget and unhilight selection - must take care of cursor here"
       
  4572 
       
  4573     |wasOn|
       
  4574 
       
  4575     wasOn := self hideCursor.
       
  4576     super unselect.
       
  4577     wasOn ifTrue:[self showCursor]
       
  4578 ! !
       
  4579 
       
  4580 !EditTextView methodsFor:'undo & again'!
       
  4581 
       
  4582 again
       
  4583     "repeat the last action (which was a cut or replace).
       
  4584      If current selection is not last string, search forward to
       
  4585      next occurence of it before repeating the last operation."
       
  4586 
       
  4587     |s l c sel savedSelectStyle|
       
  4588 
       
  4589     lastString notNil ifTrue:[
       
  4590 	s := lastString asString.
       
  4591 
       
  4592 	"remove final cr"
       
  4593 	s := s copyWithoutLast:1.
       
  4594 "/        s := s withoutSpaces.        "XXX - replacing text with spaces ..."
       
  4595 	savedSelectStyle := selectStyle.
       
  4596 	selectStyle := nil.
       
  4597 
       
  4598 	sel := self selection.
       
  4599 
       
  4600 	"if we are already there (after a find), ommit search"
       
  4601 
       
  4602 	(sel notNil and:[sel asString withoutSeparators = s]) ifTrue:[
       
  4603 	    undoAction := [self insertLines:lastString atLine:cursorLine col:cursorCol].
       
  4604 	    l := selectionStartLine "cursorLine". 
       
  4605 	    c := selectionStartCol "cursorCol".
       
  4606 	    self deleteSelection.
       
  4607 	    lastReplacement notNil ifTrue:[
       
  4608 		self insertLines:lastReplacement asStringCollection withCR:false.
       
  4609 		self selectFromLine:l col:c toLine:cursorLine col:(cursorCol - 1).
       
  4610 	    ].
       
  4611 	    selectStyle := savedSelectStyle.
       
  4612 	    ^ true
       
  4613 	].
       
  4614 
       
  4615 	self searchForwardFor:s startingAtLine:cursorLine col:cursorCol 
       
  4616 	    ifFound:
       
  4617 		[
       
  4618 		    :line :col |
       
  4619 
       
  4620 		    |repl|
       
  4621 
       
  4622 		    self selectFromLine:line col:col
       
  4623 				 toLine:line col:(col + s size - 1).
       
  4624 		    self makeLineVisible:line.
       
  4625 		    undoAction := [self insertLines:lastString atLine:line col:col].
       
  4626 
       
  4627 		    self deleteSelection.
       
  4628 		    lastReplacement notNil ifTrue:[
       
  4629 			lastReplacement isString ifFalse:[
       
  4630 			    repl := lastReplacement asString withoutSpaces
       
  4631 			] ifTrue:[
       
  4632 			    repl := lastReplacement withoutSpaces.
       
  4633 			].
       
  4634 			self insertLines:repl asStringCollection withCR:false.
       
  4635 			self selectFromLine:line col:col toLine:cursorLine col:(cursorCol - 1).
       
  4636 		    ].
       
  4637 		    selectStyle := savedSelectStyle.
       
  4638 		    ^ true
       
  4639 		] 
       
  4640 	   ifAbsent:
       
  4641 		[
       
  4642 		    self showNotFound.
       
  4643 		    selectStyle := savedSelectStyle.
       
  4644 		    ^ false
       
  4645 		]
       
  4646     ]
       
  4647 
       
  4648     "Modified: 9.10.1996 / 16:14:11 / cg"
       
  4649 !
       
  4650 
       
  4651 multipleAgain
       
  4652     "repeat the last action (which was a cut or replace) until search fails"
       
  4653 
       
  4654     [self again] whileTrue:[]
       
  4655 !
       
  4656 
       
  4657 undo
       
  4658     "currently not implemented"
       
  4659 
       
  4660     undoAction notNil ifTrue:[
       
  4661         undoAction value.
       
  4662         undoAction := nil.
       
  4663     ]
       
  4664 ! !
       
  4665 
       
  4666 !EditTextView class methodsFor:'documentation'!
       
  4667 
       
  4668 version
       
  4669     ^ '$Header: /cvs/stx/stx/libwidg/Attic/ETxtView.st,v 1.212 1999-08-18 15:06:16 cg Exp $'
       
  4670 ! !