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 ! ! |
|