|
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 'From Smalltalk/X, Version:6.2.3.0 on 18-02-2014 at 18:37:41' ! |
|
13 |
|
14 "{ Package: 'stx:libwidg' }" |
|
15 |
|
16 TextView subclass:#EditTextView |
|
17 instanceVariableNames:'cursorLine cursorVisibleLine cursorCol cursorShown |
|
18 prevCursorState readOnly modifiedChannel fixedSize exceptionBlock |
|
19 cursorFgColor cursorBgColor cursorNoFocusFgColor cursorType |
|
20 cursorTypeNoFocus typeOfSelection lastAction replacing |
|
21 showMatchingParenthesis hasKeyboardFocus acceptAction lockUpdates |
|
22 tabMeansNextField autoIndent insertMode editMode trimBlankLines |
|
23 wordWrap replacementWordSelectStyle acceptChannel acceptEnabled |
|
24 st80Mode disableIfInvisible cursorMovementWhenUpdating learnMode |
|
25 learnedMacro cursorLineHolder cursorColHolder tabRequiresControl |
|
26 undoSupport lastStringFromReplaceForNextSearch |
|
27 lastReplacementInfo completionSupport codeAspectHolder' |
|
28 classVariableNames:'DefaultCursorForegroundColor DefaultCursorBackgroundColor |
|
29 DefaultCursorType DefaultCursorNoFocusForegroundColor |
|
30 DefaultCursorTypeNoFocus LastColumnNumberForSort Macros' |
|
31 poolDictionaries:'' |
|
32 category:'Views-Text' |
|
33 ! |
|
34 |
|
35 Object subclass:#EditAction |
|
36 instanceVariableNames:'userFriendlyInfo' |
|
37 classVariableNames:'' |
|
38 poolDictionaries:'' |
|
39 privateIn:EditTextView |
|
40 ! |
|
41 |
|
42 EditTextView::EditAction subclass:#DeleteRange |
|
43 instanceVariableNames:'line1 col1 line2 col2' |
|
44 classVariableNames:'' |
|
45 poolDictionaries:'' |
|
46 privateIn:EditTextView |
|
47 ! |
|
48 |
|
49 EditTextView::EditAction subclass:#DeleteCharacters |
|
50 instanceVariableNames:'line col1 col2' |
|
51 classVariableNames:'' |
|
52 poolDictionaries:'' |
|
53 privateIn:EditTextView |
|
54 ! |
|
55 |
|
56 Object subclass:#EditMode |
|
57 instanceVariableNames:'' |
|
58 classVariableNames:'' |
|
59 poolDictionaries:'' |
|
60 privateIn:EditTextView |
|
61 ! |
|
62 |
|
63 EditTextView::EditMode subclass:#InsertAndSelectMode |
|
64 instanceVariableNames:'' |
|
65 classVariableNames:'' |
|
66 poolDictionaries:'' |
|
67 privateIn:EditTextView::EditMode |
|
68 ! |
|
69 |
|
70 EditTextView::EditMode subclass:#InsertMode |
|
71 instanceVariableNames:'' |
|
72 classVariableNames:'' |
|
73 poolDictionaries:'' |
|
74 privateIn:EditTextView::EditMode |
|
75 ! |
|
76 |
|
77 EditTextView::EditMode subclass:#OverwriteMode |
|
78 instanceVariableNames:'' |
|
79 classVariableNames:'InsertMode OverwriteMode InsertAndSelectMode' |
|
80 poolDictionaries:'' |
|
81 privateIn:EditTextView::EditMode |
|
82 ! |
|
83 |
|
84 Query subclass:#ExecutingMacroQuery |
|
85 instanceVariableNames:'' |
|
86 classVariableNames:'' |
|
87 poolDictionaries:'' |
|
88 privateIn:EditTextView |
|
89 ! |
|
90 |
|
91 Object subclass:#LastReplacementInfo |
|
92 instanceVariableNames:'lastReplacement lastStringToReplace lastReplaceWasMatch |
|
93 lastReplaceIgnoredCase stillCollectingInput previousReplacements' |
|
94 classVariableNames:'' |
|
95 poolDictionaries:'' |
|
96 privateIn:EditTextView |
|
97 ! |
|
98 |
|
99 EditTextView::EditAction subclass:#PasteString |
|
100 instanceVariableNames:'line col string selected' |
|
101 classVariableNames:'' |
|
102 poolDictionaries:'' |
|
103 privateIn:EditTextView |
|
104 ! |
|
105 |
|
106 EditTextView::EditAction subclass:#ReplaceCharacter |
|
107 instanceVariableNames:'line col character' |
|
108 classVariableNames:'' |
|
109 poolDictionaries:'' |
|
110 privateIn:EditTextView |
|
111 ! |
|
112 |
|
113 EditTextView::EditAction subclass:#ReplaceCharacters |
|
114 instanceVariableNames:'line col1 col2 characters' |
|
115 classVariableNames:'' |
|
116 poolDictionaries:'' |
|
117 privateIn:EditTextView |
|
118 ! |
|
119 |
|
120 EditTextView::EditAction subclass:#ReplaceContents |
|
121 instanceVariableNames:'text' |
|
122 classVariableNames:'' |
|
123 poolDictionaries:'' |
|
124 privateIn:EditTextView |
|
125 ! |
|
126 |
|
127 EditTextView::EditAction subclass:#ReplaceLine |
|
128 instanceVariableNames:'line text' |
|
129 classVariableNames:'' |
|
130 poolDictionaries:'' |
|
131 privateIn:EditTextView |
|
132 ! |
|
133 |
|
134 EditTextView::EditAction subclass:#ReplaceLines |
|
135 instanceVariableNames:'line text' |
|
136 classVariableNames:'' |
|
137 poolDictionaries:'' |
|
138 privateIn:EditTextView |
|
139 ! |
|
140 |
|
141 !EditTextView class methodsFor:'documentation'! |
|
142 |
|
143 copyright |
|
144 " |
|
145 COPYRIGHT (c) 1989 by Claus Gittinger |
|
146 All Rights Reserved |
|
147 |
|
148 This software is furnished under a license and may be used |
|
149 only in accordance with the terms of that license and with the |
|
150 inclusion of the above copyright notice. This software may not |
|
151 be provided or otherwise made available to, or used by, any |
|
152 other person. No title to or ownership of the software is |
|
153 hereby transferred. |
|
154 " |
|
155 ! |
|
156 |
|
157 documentation |
|
158 " |
|
159 a view for editable text - adds editing functionality to TextView |
|
160 Also, it adds accept functionality, and defines a new actionBlock: |
|
161 acceptAction to be performed for accept |
|
162 |
|
163 If used with a model, this is informed by sending it a changeMsg with |
|
164 the current contents as argument. |
|
165 (however, it is possible to define both changeMsg and acceptAction) |
|
166 |
|
167 Please read the historic notice in the ListView class. |
|
168 |
|
169 [Instance variables:] |
|
170 |
|
171 cursorLine <Number> line where cursor sits (1..) |
|
172 |
|
173 cursorVisibleLine <Number> visible line where cursor sits (1..nLinesShown) |
|
174 |
|
175 cursorCol <Number> col where cursor sits (1..) |
|
176 |
|
177 cursorShown <Boolean> true, if cursor is currently shown |
|
178 |
|
179 readOnly <Boolean> true, if text may not be edited |
|
180 |
|
181 modifiedChannel <ValueHolder> holding true, if text has been modified. |
|
182 cleared on accept. |
|
183 |
|
184 acceptChannel <ValueHolder> holding true, if text has been accepted. |
|
185 |
|
186 fixedSize <Boolean> true, if no lines may be added/removed |
|
187 |
|
188 exceptionBlock <Block> block to be evaluated when readonly text is about to be modified |
|
189 if it returns true, the modification will be done anyway. |
|
190 if it returns anything else, the modification is not done. |
|
191 |
|
192 cursorFgColor <Color> color used for cursor drawing |
|
193 cursorBgColor <Color> color used for cursor drawing |
|
194 |
|
195 cursorType <Symbol> how the cursor is drawn; currently implemented |
|
196 are #none, #block (solid-block cursor), #ibeam |
|
197 (vertical bar at insertion point) |
|
198 and #caret (caret below insertion-point). |
|
199 see cursorType: for an up-to-date list. |
|
200 |
|
201 cursorTypeNoFocus <Symbol> like above, if view has no focus |
|
202 nil means: hide the cursor. |
|
203 |
|
204 undoAction <Block> block which undoes last cut, paste or replace |
|
205 (not yet fully implemented) |
|
206 |
|
207 typeOfSelection <Symbol> #paste, if selection created by paste, nil otherwise |
|
208 this affects the next keyPress: if #paste it does not |
|
209 replace; otherwise it replaces the selection. |
|
210 |
|
211 lastCut <String> last cut or replaced string |
|
212 |
|
213 lastReplacementInfo <LastReplacementInfo> holds the information about the last replace action |
|
214 lastStringToReplace is the string to be replaced by lastReplacement |
|
215 lastReplacement is the string to replace lastStringToReplace |
|
216 |
|
217 lastStringFromReplaceForNextSearch <String> string to be taken be the next search action |
|
218 (cleared after a new selection) |
|
219 |
|
220 replacing <Boolean> true if entered characters replace last selection |
|
221 |
|
222 showMatchingParenthesis <Boolean> if true, shows matching parenthesis |
|
223 when entering one; this is the default. |
|
224 |
|
225 hasKeyboardFocus <Boolean> true if this view has the focus |
|
226 |
|
227 acceptAction <Block> accept action - evaluated passing the contents as |
|
228 argument |
|
229 |
|
230 tabMeansNextField <Boolean> if true, Tab is ignored as input and shifts keyboard |
|
231 focus to the next field. For editTextViews, this is false |
|
232 by default (i.e. tabs can be entered into the text). |
|
233 For some subclasses (inputFields), this may be true. |
|
234 |
|
235 trimBlankLines <Boolean> if true, trailing blanks are |
|
236 removed when editing. |
|
237 Default is true. |
|
238 |
|
239 wordWrap <Boolean> Currently not used. |
|
240 |
|
241 lockUpdates <Boolean> internal, private |
|
242 |
|
243 prevCursorState <Boolean> temporary, private |
|
244 |
|
245 cursorMovementWhenUpdating |
|
246 <Symbol> defines where the cursor is to be positioned if the |
|
247 model changes its value by some outside activity |
|
248 (i.e. not by user input into the field). |
|
249 Can be one of: |
|
250 #keep / nil -> stay where it was |
|
251 #endOfText -> cursor to the end |
|
252 #endOfLine -> stay in the line, but move to end |
|
253 #beginOfText -> cursor to the beginning |
|
254 #beginOfLine -> stay in the line, but move to begin |
|
255 The default is #beginOfText |
|
256 |
|
257 |
|
258 |
|
259 dropTarget <DropTarget|nil> drop operation descriptor or nil (drop disabled) |
|
260 |
|
261 |
|
262 userPreference values: |
|
263 userPreferences.st80EditMode |
|
264 <Boolean> if true, cursor positioning is |
|
265 done as in vi or ST80; i.e. |
|
266 wysiwyg mode is somewhat relaxed, |
|
267 in that the cursor cannot be |
|
268 positioned behind a lines end. |
|
269 This is not yet completely implemented. |
|
270 used globals: |
|
271 |
|
272 DeleteHistory <Text> last 1000 lines of deleted text |
|
273 (but only if this variable exists already) |
|
274 |
|
275 [styleSheet parameters:] |
|
276 |
|
277 textCursorForegroundColor <Color> cursor fg color; default: text background |
|
278 textCursorBackgroundColor <Color> cursor bg color; default: text foreground |
|
279 textCursorNoFocusForegroundColor |
|
280 <Color> cursor fg color if no focus; default: cursor fg color |
|
281 textCursorType <Symbol> cursor type; default: #block |
|
282 |
|
283 [author:] |
|
284 Claus Gittinger |
|
285 |
|
286 [see also:] |
|
287 CodeView Workspace TextView ListView |
|
288 EditField |
|
289 " |
|
290 ! |
|
291 |
|
292 examples |
|
293 " |
|
294 non MVC operation: |
|
295 |
|
296 basic setup: |
|
297 [exBegin] |
|
298 |top textView| |
|
299 |
|
300 top := StandardSystemView new. |
|
301 top extent:300@200. |
|
302 |
|
303 textView := EditTextView new. |
|
304 textView origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
305 top addSubView:textView. |
|
306 |
|
307 textView contents:('/etc/hosts' asFilename contentsOfEntireFile). |
|
308 |
|
309 top open. |
|
310 [exEnd] |
|
311 |
|
312 |
|
313 with vertical scrollbar: |
|
314 [exBegin] |
|
315 |top scrollView textView| |
|
316 |
|
317 top := StandardSystemView new. |
|
318 top extent:300@200. |
|
319 |
|
320 scrollView := ScrollableView for:EditTextView. |
|
321 textView := scrollView scrolledView. |
|
322 scrollView origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
323 top addSubView:scrollView. |
|
324 |
|
325 textView contents:('/etc/hosts' asFilename contentsOfEntireFile). |
|
326 |
|
327 top open. |
|
328 [exEnd] |
|
329 |
|
330 |
|
331 with horizontal & vertical scrollbars: |
|
332 [exBegin] |
|
333 |top scrollView textView| |
|
334 |
|
335 top := StandardSystemView new. |
|
336 top extent:300@200. |
|
337 |
|
338 scrollView := HVScrollableView for:EditTextView. |
|
339 textView := scrollView scrolledView. |
|
340 scrollView origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
341 top addSubView:scrollView. |
|
342 |
|
343 textView contents:('/etc/hosts' asFilename contentsOfEntireFile). |
|
344 |
|
345 top open. |
|
346 [exEnd] |
|
347 |
|
348 |
|
349 set the action for accept: |
|
350 [exBegin] |
|
351 |top textView| |
|
352 |
|
353 top := StandardSystemView new. |
|
354 top extent:300@200. |
|
355 |
|
356 textView := EditTextView new. |
|
357 textView origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
358 top addSubView:textView. |
|
359 |
|
360 textView contents:('/etc/hosts' asFilename contentsOfEntireFile). |
|
361 textView acceptAction:[:contents | |
|
362 Transcript showCR:'will not overwrite the file with:'. |
|
363 Transcript showCR:contents asString |
|
364 ]. |
|
365 top open. |
|
366 [exEnd] |
|
367 |
|
368 |
|
369 |
|
370 non-string (text) items: |
|
371 [exBegin] |
|
372 |top textView list| |
|
373 |
|
374 list := '/etc/hosts' asFilename contentsOfEntireFile asStringCollection. |
|
375 1 to:list size by:2 do:[:nr | |
|
376 list at:nr put:(Text string:(list at:nr) |
|
377 emphasis:(Array with:#bold with:(#color->Color red))) |
|
378 ]. |
|
379 |
|
380 top := StandardSystemView new. |
|
381 top extent:300@200. |
|
382 |
|
383 textView := EditTextView new. |
|
384 textView origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
385 top addSubView:textView. |
|
386 |
|
387 textView contents:list. |
|
388 top open. |
|
389 [exEnd] |
|
390 |
|
391 |
|
392 |
|
393 MVC operation: |
|
394 (the examples model here is a plug simulating a real model; |
|
395 real world applications would not use a plug ..) |
|
396 [exBegin] |
|
397 |top textView model| |
|
398 |
|
399 model := Plug new. |
|
400 model respondTo:#accepted: |
|
401 with:[:newContents | |
|
402 Transcript showCR:'will not overwrite the file with:'. |
|
403 Transcript showCR:newContents asString |
|
404 ]. |
|
405 model respondTo:#getList |
|
406 with:['/etc/hosts' asFilename contentsOfEntireFile]. |
|
407 |
|
408 |
|
409 top := StandardSystemView new. |
|
410 top extent:300@200. |
|
411 |
|
412 textView := EditTextView new. |
|
413 textView origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
414 top addSubView:textView. |
|
415 |
|
416 textView listMessage:#getList; |
|
417 model:model; |
|
418 changeMessage:#accepted:; |
|
419 aspect:#list. |
|
420 top open. |
|
421 [exEnd] |
|
422 |
|
423 |
|
424 two textViews on the same model: |
|
425 [exBegin] |
|
426 |top1 textView1 top2 textView2 model currentContents| |
|
427 |
|
428 model := Plug new. |
|
429 model respondTo:#accepted: |
|
430 with:[:newContents | |
|
431 Transcript showCR:'accepted:'. |
|
432 Transcript showCR:newContents asString. |
|
433 currentContents := newContents. |
|
434 model changed:#contents |
|
435 ]. |
|
436 model respondTo:#getList |
|
437 with:[Transcript showCR:'query'. |
|
438 currentContents]. |
|
439 |
|
440 |
|
441 top1 := StandardSystemView new. |
|
442 top1 extent:300@200. |
|
443 |
|
444 textView1 := EditTextView new. |
|
445 textView1 origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
446 top1 addSubView:textView1. |
|
447 |
|
448 textView1 listMessage:#getList; |
|
449 model:model; |
|
450 aspect:#contents; |
|
451 changeMessage:#accepted:. |
|
452 top1 open. |
|
453 |
|
454 top2 := StandardSystemView new. |
|
455 top2 extent:300@200. |
|
456 |
|
457 textView2 := EditTextView new. |
|
458 textView2 origin:0.0 @ 0.0 corner:1.0 @ 1.0. |
|
459 top2 addSubView:textView2. |
|
460 |
|
461 textView2 listMessage:#getList; |
|
462 model:model; |
|
463 aspect:#contents; |
|
464 changeMessage:#accepted:. |
|
465 top2 open. |
|
466 [exEnd] |
|
467 " |
|
468 ! ! |
|
469 |
|
470 !EditTextView class methodsFor:'defaults'! |
|
471 |
|
472 defaultCompletionSupportClass |
|
473 ^ nil |
|
474 |
|
475 "Created: / 26-09-2013 / 17:59:27 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
476 ! |
|
477 |
|
478 st80Mode |
|
479 "return true, if the st80 editing mode is turned on. |
|
480 This setting affects the behavior of the cursor, when positioned |
|
481 beyond the end of a line or the end of the text." |
|
482 |
|
483 ^ UserPreferences current st80EditMode |
|
484 |
|
485 " |
|
486 EditTextView st80Mode:true |
|
487 EditTextView st80Mode:false |
|
488 " |
|
489 |
|
490 "Modified: / 16.1.1998 / 22:54:57 / cg" |
|
491 ! |
|
492 |
|
493 st80Mode:aBoolean |
|
494 "turns on/off st80 behavior, where the cursor cannot be positioned |
|
495 beyond the end of a line or the last line" |
|
496 |
|
497 UserPreferences current st80EditMode:aBoolean. |
|
498 |
|
499 " |
|
500 EditTextView st80Mode:true |
|
501 EditTextView st80Mode:false |
|
502 " |
|
503 |
|
504 "Modified: / 16.1.1998 / 22:55:19 / cg" |
|
505 ! |
|
506 |
|
507 updateStyleCache |
|
508 "extract values from the styleSheet and cache them in class variables" |
|
509 |
|
510 <resource: #style (#'textCursor.foregroundColor' #'textCursor.backgroundColor' |
|
511 #'textCursor.noFocusForegroundColor' |
|
512 #'textCursor.type' |
|
513 #'textCursor.typeNoFocus' |
|
514 #'editText.st80Mode')> |
|
515 |
|
516 DefaultCursorForegroundColor := StyleSheet colorAt:'textCursor.foregroundColor'. |
|
517 DefaultCursorBackgroundColor := StyleSheet colorAt:'textCursor.backgroundColor'. |
|
518 DefaultCursorNoFocusForegroundColor := StyleSheet colorAt:'textCursor.noFocusForegroundColor'. |
|
519 DefaultCursorType := StyleSheet at:'textCursor.type' default:#block. |
|
520 DefaultCursorTypeNoFocus := StyleSheet at:'textCursor.typeNoFocus'. |
|
521 |
|
522 " |
|
523 self updateStyleCache |
|
524 " |
|
525 |
|
526 "Modified: / 20.5.1998 / 04:27:41 / cg" |
|
527 ! ! |
|
528 |
|
529 !EditTextView class methodsFor:'specs'! |
|
530 |
|
531 searchReplaceDialogSpec |
|
532 "This resource specification was automatically generated |
|
533 by the UIPainter of ST/X." |
|
534 |
|
535 "Do not manually edit this!! If it is corrupted, |
|
536 the UIPainter may not be able to read the specification." |
|
537 |
|
538 " |
|
539 UIPainter new openOnClass:DAPASX::ProjectEditorTextView andSelector:#searchReplaceDialogSpec |
|
540 " |
|
541 |
|
542 <resource: #canvas> |
|
543 |
|
544 ^ |
|
545 #(FullSpec |
|
546 name: searchReplaceDialogSpec |
|
547 window: |
|
548 (WindowSpec |
|
549 label: 'String Search and Replace' |
|
550 name: 'String Search and Replace' |
|
551 min: (Point 283 196) |
|
552 max: (Point 283 196) |
|
553 bounds: (Rectangle 0 0 279 192) |
|
554 ) |
|
555 component: |
|
556 (SpecCollection |
|
557 collection: ( |
|
558 (LabelSpec |
|
559 label: 'Search Pattern:' |
|
560 name: 'label' |
|
561 layout: (LayoutFrame 1 0.0 3 0 -1 1.0 20 0) |
|
562 level: 0 |
|
563 translateLabel: true |
|
564 adjust: left |
|
565 ) |
|
566 (ComboBoxSpec |
|
567 name: 'patternComboBox' |
|
568 layout: (LayoutFrame 3 0.0 26 0 -3 1.0 48 0) |
|
569 tabable: true |
|
570 model: searchPattern |
|
571 immediateAccept: false |
|
572 acceptOnLeave: true |
|
573 acceptOnReturn: true |
|
574 acceptOnTab: true |
|
575 acceptOnLostFocus: true |
|
576 acceptOnPointerLeave: false |
|
577 autoSelectInitialText: true |
|
578 comboList: patternList |
|
579 ) |
|
580 (ComboBoxSpec |
|
581 name: 'replaceComboBox' |
|
582 layout: (LayoutFrame 3 0.0 76 0 -3 1.0 98 0) |
|
583 tabable: true |
|
584 model: replacePattern |
|
585 immediateAccept: false |
|
586 acceptOnLeave: true |
|
587 acceptOnReturn: true |
|
588 acceptOnTab: true |
|
589 acceptOnLostFocus: true |
|
590 acceptOnPointerLeave: false |
|
591 autoSelectInitialText: true |
|
592 comboList: patternList |
|
593 ) |
|
594 (CheckBoxSpec |
|
595 label: 'Ignore Case' |
|
596 name: 'ignoreCaseCheckBox' |
|
597 layout: (LayoutFrame 3 0.0 107 0 -3 1.0 130 0) |
|
598 level: 0 |
|
599 tabable: true |
|
600 model: ignoreCase |
|
601 translateLabel: true |
|
602 ) |
|
603 (VariableVerticalPanelSpec |
|
604 name: 'VariableVerticalPanel1' |
|
605 layout: (LayoutFrame 0 0 -64 1 0 1 -4 1) |
|
606 component: |
|
607 (SpecCollection |
|
608 collection: ( |
|
609 (HorizontalPanelViewSpec |
|
610 name: 'HorizontalPanel1' |
|
611 level: 0 |
|
612 horizontalLayout: fitSpace |
|
613 verticalLayout: center |
|
614 horizontalSpace: 3 |
|
615 verticalSpace: 3 |
|
616 ignoreInvisibleComponents: true |
|
617 reverseOrderIfOKAtLeft: true |
|
618 component: |
|
619 (SpecCollection |
|
620 collection: ( |
|
621 (ActionButtonSpec |
|
622 label: 'Replace' |
|
623 name: 'replaceButton' |
|
624 level: 2 |
|
625 translateLabel: true |
|
626 tabable: true |
|
627 model: replaceAction |
|
628 extent: (Point 134 21) |
|
629 ) |
|
630 (ActionButtonSpec |
|
631 label: 'Replace All' |
|
632 name: 'replaceAllButton' |
|
633 level: 2 |
|
634 borderWidth: 1 |
|
635 translateLabel: true |
|
636 tabable: true |
|
637 model: replaceAllAction |
|
638 extent: (Point 134 21) |
|
639 ) |
|
640 ) |
|
641 |
|
642 ) |
|
643 ) |
|
644 (HorizontalPanelViewSpec |
|
645 name: 'horizontalPanelView' |
|
646 level: 0 |
|
647 horizontalLayout: fitSpace |
|
648 verticalLayout: center |
|
649 horizontalSpace: 3 |
|
650 verticalSpace: 3 |
|
651 ignoreInvisibleComponents: true |
|
652 reverseOrderIfOKAtLeft: true |
|
653 component: |
|
654 (SpecCollection |
|
655 collection: ( |
|
656 (ActionButtonSpec |
|
657 label: 'Cancel' |
|
658 name: 'cancelButton' |
|
659 level: 2 |
|
660 translateLabel: true |
|
661 tabable: true |
|
662 model: cancel |
|
663 extent: (Point 88 21) |
|
664 ) |
|
665 (ActionButtonSpec |
|
666 label: 'Prev' |
|
667 name: 'prevButton' |
|
668 level: 2 |
|
669 translateLabel: true |
|
670 tabable: true |
|
671 model: prevAction |
|
672 extent: (Point 89 21) |
|
673 ) |
|
674 (ActionButtonSpec |
|
675 label: 'Next' |
|
676 name: 'nextButton' |
|
677 level: 2 |
|
678 borderWidth: 1 |
|
679 translateLabel: true |
|
680 tabable: true |
|
681 model: nextAction |
|
682 isDefault: true |
|
683 extent: (Point 88 21) |
|
684 ) |
|
685 ) |
|
686 |
|
687 ) |
|
688 ) |
|
689 ) |
|
690 |
|
691 ) |
|
692 handles: (Any 0.5 1.0) |
|
693 ) |
|
694 (LabelSpec |
|
695 label: 'Replace By:' |
|
696 name: 'ReplaceLabel' |
|
697 layout: (LayoutFrame 1 0.0 53 0 -1 1.0 70 0) |
|
698 level: 0 |
|
699 translateLabel: true |
|
700 adjust: left |
|
701 ) |
|
702 ) |
|
703 |
|
704 ) |
|
705 ) |
|
706 |
|
707 "Modified: / 11-10-2006 / 21:05:09 / cg" |
|
708 ! ! |
|
709 |
|
710 !EditTextView methodsFor:'Compatibility-ST80'! |
|
711 |
|
712 autoAccept:aBoolean |
|
713 "ignored for now" |
|
714 |
|
715 "Created: / 5.6.1998 / 15:30:32 / cg " |
|
716 ! |
|
717 |
|
718 continuousAccept:aBoolean |
|
719 "ignored for now" |
|
720 |
|
721 "Created: / 19.6.1998 / 00:03:49 / cg" |
|
722 ! |
|
723 |
|
724 cutSelection |
|
725 self cut |
|
726 |
|
727 "Created: / 31.10.1997 / 03:29:50 / cg" |
|
728 ! |
|
729 |
|
730 deselect |
|
731 "remove the selection" |
|
732 |
|
733 ^ self unselect |
|
734 |
|
735 "Created: / 19.6.1998 / 02:41:54 / cg" |
|
736 ! |
|
737 |
|
738 enabled:aBoolean |
|
739 |
|
740 self readOnly:aBoolean not |
|
741 |
|
742 "Created: / 30.3.1999 / 15:10:23 / stefan" |
|
743 "Modified: / 30.3.1999 / 15:10:53 / stefan" |
|
744 ! |
|
745 |
|
746 find:pattern |
|
747 self searchFwd:pattern ifAbsent:nil |
|
748 |
|
749 "Created: / 29.1.1999 / 19:09:42 / cg" |
|
750 "Modified: / 29.1.1999 / 19:10:12 / cg" |
|
751 ! |
|
752 |
|
753 insert:aString at:aCharacterPosition |
|
754 "insert a string at aCharacterPosition." |
|
755 |
|
756 |line col| |
|
757 |
|
758 line := self lineOfCharacterPosition:aCharacterPosition. |
|
759 col := aCharacterPosition - (self characterPositionOfLine:line col:1) + 1. |
|
760 col < 1 ifTrue:[ |
|
761 col := 1 |
|
762 ]. |
|
763 self insertString:aString atLine:line col:col. |
|
764 |
|
765 " |
|
766 |top v| |
|
767 |
|
768 top := StandardSystemView new. |
|
769 top extent:300@300. |
|
770 v := EditTextView origin:0.0@0.0 corner:1.0@1.0 in:top. |
|
771 top openAndWait. |
|
772 v contents:'1234567890\1234567890\1234567890\' withCRs. |
|
773 v insert:'<- hello there' at:5. |
|
774 " |
|
775 |
|
776 "Modified: / 5.4.1998 / 17:20:08 / cg" |
|
777 ! |
|
778 |
|
779 insertAndSelect:aString at:aCharacterPosition |
|
780 "insert a selected string at aCharacterPosition." |
|
781 |
|
782 |line col| |
|
783 |
|
784 line := self lineOfCharacterPosition:aCharacterPosition. |
|
785 col := (aCharacterPosition - (self characterPositionOfLine:line col:1) + 1) max:1. |
|
786 self insertString:aString atLine:line col:col. |
|
787 self selectFromLine:line col:col toLine:line col:col + aString size - 1 |
|
788 " |
|
789 |v| |
|
790 |
|
791 v := EditTextView new openAndWait. |
|
792 v contents:'1234567890\1234567890\1234567890\' withCRs. |
|
793 v insertAndSelect:'<- hello there' at:5. |
|
794 " |
|
795 ! |
|
796 |
|
797 pasteSelection |
|
798 self paste |
|
799 |
|
800 "Created: / 31.10.1997 / 03:28:53 / cg" |
|
801 ! |
|
802 |
|
803 replaceSelectionWith:aString |
|
804 ^ self replaceSelectionBy:aString |
|
805 |
|
806 "Created: / 19.6.1998 / 02:42:32 / cg" |
|
807 ! |
|
808 |
|
809 selectAt:pos |
|
810 "move the cursor before cursorPosition." |
|
811 |
|
812 self cursorToCharacterPosition:pos |
|
813 |
|
814 "Modified: / 19.6.1998 / 02:41:28 / cg" |
|
815 "Created: / 19.6.1998 / 02:43:39 / cg" |
|
816 ! |
|
817 |
|
818 textHasChanged |
|
819 ^ self modified |
|
820 |
|
821 "Created: / 19.6.1998 / 00:09:43 / cg" |
|
822 ! |
|
823 |
|
824 textHasChanged:aBoolean |
|
825 "ST-80 compatibility: set/clear the modified flag." |
|
826 |
|
827 self modified:aBoolean |
|
828 |
|
829 "Created: / 5.2.2000 / 17:07:59 / cg" |
|
830 ! ! |
|
831 |
|
832 !EditTextView methodsFor:'accessing'! |
|
833 |
|
834 codeAspect |
|
835 | codeAspect app | |
|
836 |
|
837 codeAspect := codeAspectHolder value. |
|
838 codeAspect notNil ifTrue:[^codeAspect]. |
|
839 self editedMethod notNil ifTrue:[^SyntaxHighlighter codeAspectMethod]. |
|
840 |
|
841 "/ Applications should set it explictly, however, to make it behavinh like |
|
842 "/ CodeView2, I kept fetching code here for now. |
|
843 ^((app := self topView application) notNil and:[app respondsTo: #codeAspect]) |
|
844 ifTrue:[app codeAspect] |
|
845 ifFalse:[nil] |
|
846 |
|
847 "Created: / 27-09-2013 / 09:53:40 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
848 ! |
|
849 |
|
850 codeAspect: aSymbol |
|
851 codeAspectHolder value: aSymbol |
|
852 |
|
853 "Created: / 27-09-2013 / 09:50:52 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
854 ! |
|
855 |
|
856 completionSupport |
|
857 ^ completionSupport |
|
858 ! |
|
859 |
|
860 completionSupport:anEditTextViewCompletionSupport |
|
861 completionSupport := anEditTextViewCompletionSupport. |
|
862 ! |
|
863 |
|
864 completionSupportClass |
|
865 ^ self class defaultCompletionSupportClass |
|
866 |
|
867 "Created: / 26-09-2013 / 17:54:24 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
868 ! |
|
869 |
|
870 editedClass |
|
871 |cm| |
|
872 |
|
873 cm := self editedMethodOrClass. |
|
874 cm isBehavior ifTrue:[^ cm]. |
|
875 cm isMethod ifTrue:[^ cm mclass]. |
|
876 ^ nil |
|
877 ! |
|
878 |
|
879 editedLanguage |
|
880 ^ nil |
|
881 |
|
882 "Created: / 18-09-2013 / 14:16:38 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
883 ! |
|
884 |
|
885 editedLanguage: aProgrammingLanguage |
|
886 "Sets the edited language. Only defined here to make it polymorph with Workspace" |
|
887 |
|
888 "Created: / 27-09-2013 / 10:15:35 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
889 ! |
|
890 |
|
891 editedMethod |
|
892 |cm| |
|
893 |
|
894 cm := self editedMethodOrClass. |
|
895 cm isMethod ifTrue:[^ cm]. |
|
896 cm isBehavior ifTrue:[^ nil]. |
|
897 ^ nil |
|
898 ! |
|
899 |
|
900 editedMethodOrClass |
|
901 ^ nil |
|
902 ! |
|
903 |
|
904 editedMethodOrClass: methodOrClass |
|
905 "Sets the edited method or class. Only defined here to make it polymorph with Workspace" |
|
906 |
|
907 "Created: / 27-09-2013 / 10:10:14 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
908 ! |
|
909 |
|
910 hasSelectionOrTextInCursorLine |
|
911 ^ (self selectionOrTextOfCursorLine:false) notNil |
|
912 ! |
|
913 |
|
914 selectionOrTextOfCursorLine |
|
915 ^ self selectionOrTextOfCursorLine:true |
|
916 ! |
|
917 |
|
918 selectionOrTextOfCursorLine:doSelect |
|
919 |sel lNr line| |
|
920 |
|
921 sel := self selectionAsString. |
|
922 sel notNil ifTrue:[^ sel]. |
|
923 |
|
924 lNr := self cursorLine. |
|
925 line := self listAt:lNr. |
|
926 line notEmptyOrNil ifTrue:[ |
|
927 doSelect ifTrue:[ |
|
928 self selectLine:lNr. |
|
929 ]. |
|
930 ^ line |
|
931 ]. |
|
932 |
|
933 ^ nil |
|
934 ! ! |
|
935 |
|
936 !EditTextView methodsFor:'accessing-behavior'! |
|
937 |
|
938 acceptAction |
|
939 "return the action to be performed on accept (or nil)" |
|
940 |
|
941 ^ acceptAction |
|
942 ! |
|
943 |
|
944 acceptAction:aBlock |
|
945 "set the action to be performed on accept" |
|
946 |
|
947 acceptAction := aBlock |
|
948 ! |
|
949 |
|
950 acceptChannel |
|
951 "return the valueHolder holding true if text was accepted. |
|
952 By placing a true into this channel, an accept can also be forced." |
|
953 |
|
954 ^ acceptChannel |
|
955 |
|
956 "Modified: / 30.1.1998 / 14:17:11 / cg" |
|
957 ! |
|
958 |
|
959 acceptChannel:aValueHolder |
|
960 "set the valueHolder holding true if text was accepted. |
|
961 By placing a true into this channel, an accept can also be forced." |
|
962 |
|
963 |prev| |
|
964 |
|
965 prev := acceptChannel. |
|
966 acceptChannel := aValueHolder. |
|
967 self setupChannel:aValueHolder for:nil withOld:prev |
|
968 |
|
969 "Created: / 30.1.1998 / 14:51:09 / cg" |
|
970 ! |
|
971 |
|
972 acceptEnabled:aBoolean |
|
973 "enable/disable accept. This greys the corresponding item in the menu" |
|
974 |
|
975 acceptEnabled := aBoolean |
|
976 |
|
977 "Created: 7.3.1997 / 11:04:34 / cg" |
|
978 ! |
|
979 |
|
980 accepted |
|
981 "return true if text was accepted" |
|
982 |
|
983 ^ acceptChannel value |
|
984 |
|
985 "Created: 14.2.1997 / 16:43:46 / cg" |
|
986 ! |
|
987 |
|
988 accepted:aBoolean |
|
989 "set/clear the accepted flag. |
|
990 This may force my current contents to be placed into my model." |
|
991 |
|
992 acceptChannel value:aBoolean. |
|
993 |
|
994 "Created: / 14.2.1997 / 16:44:01 / cg" |
|
995 "Modified: / 30.1.1998 / 14:20:15 / cg" |
|
996 ! |
|
997 |
|
998 autoIndent:aBoolean |
|
999 autoIndent := aBoolean |
|
1000 |
|
1001 "Created: 5.3.1996 / 14:37:50 / cg" |
|
1002 ! |
|
1003 |
|
1004 codeAspectHolder |
|
1005 ^ codeAspectHolder |
|
1006 ! |
|
1007 |
|
1008 codeAspectHolder:something |
|
1009 codeAspectHolder := something. |
|
1010 ! |
|
1011 |
|
1012 cursorMovementWhenUpdating |
|
1013 "return what is be done with the cursor, |
|
1014 when I get a new text (via the model or the #contents/#list) |
|
1015 Allowed arguments are: |
|
1016 #keep / nil -> stay where it was |
|
1017 #endOfText -> position cursor to the end |
|
1018 #beginOfText -> position cursor to the beginning |
|
1019 #endOfLine -> position cursor to the current lines end |
|
1020 #beginOfLine -> position cursor to the current lines start |
|
1021 The default is #beginOfText. |
|
1022 This may be useful for fields which get new values assigned from |
|
1023 the program (i.e. not from the user)" |
|
1024 |
|
1025 ^ cursorMovementWhenUpdating |
|
1026 |
|
1027 "Modified: 16.12.1995 / 16:27:55 / cg" |
|
1028 ! |
|
1029 |
|
1030 cursorMovementWhenUpdating:aSymbolOrNil |
|
1031 "define what should be done with the cursor, |
|
1032 when I get a new text (via the model or the #contents/#list) |
|
1033 Allowed arguments are: |
|
1034 #keep / nil -> stay where it was |
|
1035 #endOfText -> position cursor to the end |
|
1036 #beginOfText -> position cursor to the beginning |
|
1037 #endOfLine -> position cursor to the current lines end |
|
1038 #beginOfLine -> position cursor to the current lines start |
|
1039 The default is #beginOfText. |
|
1040 This may be useful for fields which get new values assigned from |
|
1041 the program (i.e. not from the user)" |
|
1042 |
|
1043 cursorMovementWhenUpdating := aSymbolOrNil |
|
1044 |
|
1045 "Modified: 16.12.1995 / 16:27:55 / cg" |
|
1046 ! |
|
1047 |
|
1048 disableIfInvisible:aBoolean |
|
1049 disableIfInvisible := aBoolean |
|
1050 ! |
|
1051 |
|
1052 dontReplaceSelectionOnInput |
|
1053 "remember that the current selection was created by a paste operation |
|
1054 (as opposed to an explicit selection by the user). |
|
1055 This selection will not be replaced by followup user input, |
|
1056 so multiple pastes will be possible." |
|
1057 |
|
1058 typeOfSelection := #paste |
|
1059 ! |
|
1060 |
|
1061 editModeHolder |
|
1062 ^ editMode. |
|
1063 ! |
|
1064 |
|
1065 editModeInsert |
|
1066 editMode value:EditMode insertMode |
|
1067 ! |
|
1068 |
|
1069 editModeInsertAndSelect |
|
1070 editMode value:EditMode insertAndSelectMode |
|
1071 ! |
|
1072 |
|
1073 editModeOverwrite |
|
1074 editMode value:EditMode overwriteMode |
|
1075 ! |
|
1076 |
|
1077 exceptionBlock:aBlock |
|
1078 "define the action to be triggered when user tries to modify |
|
1079 readonly text" |
|
1080 |
|
1081 exceptionBlock := aBlock |
|
1082 ! |
|
1083 |
|
1084 fixedSize |
|
1085 "make the texts size fixed (no lines may be added). |
|
1086 OBSOLETE: use readOnly" |
|
1087 |
|
1088 <resource:#obsolete> |
|
1089 |
|
1090 |menu| |
|
1091 |
|
1092 self obsoleteMethodWarning:'use #readOnly:'. |
|
1093 readOnly == true ifFalse:[ |
|
1094 readOnly := true. |
|
1095 (menu := self middleButtonMenu) notNil ifTrue:[ |
|
1096 menu disableAll:#(cut paste replace indent) |
|
1097 ] |
|
1098 ] |
|
1099 |
|
1100 "Modified: 14.2.1997 / 17:35:24 / cg" |
|
1101 ! |
|
1102 |
|
1103 insertMode:aBoolean |
|
1104 editMode value:(aBoolean ifTrue:[EditMode insertMode] ifFalse:[EditMode overwriteMode]) |
|
1105 |
|
1106 "Created: 6.3.1996 / 12:24:05 / cg" |
|
1107 ! |
|
1108 |
|
1109 insertModeHolder |
|
1110 ^ BlockValue |
|
1111 with:[:m | m isInsertMode] |
|
1112 argument:(editMode). |
|
1113 |
|
1114 "Modified: / 08-03-2007 / 22:58:37 / cg" |
|
1115 ! |
|
1116 |
|
1117 isInInsertMode |
|
1118 ^ editMode value isInsertMode |
|
1119 ! |
|
1120 |
|
1121 isReadOnly |
|
1122 "return true, if the text is readonly." |
|
1123 |
|
1124 ^ readOnly value |
|
1125 |
|
1126 "Modified: 14.2.1997 / 17:35:56 / cg" |
|
1127 ! |
|
1128 |
|
1129 modeLabelHolder |
|
1130 "a valueHolder, which contains 'L' (learnMode), I (insertMode) or empty" |
|
1131 |
|
1132 ^ BlockValue |
|
1133 with:[:e :l | |
|
1134 self isReadOnly ifTrue:[ |
|
1135 '' |
|
1136 ] ifFalse:[ |
|
1137 l ifTrue:[ 'L' allBold colorizeAllWith:Color red] |
|
1138 ifFalse:[ e infoPrintString]]] |
|
1139 argument:(self editModeHolder) |
|
1140 argument:(self learnModeHolder). |
|
1141 |
|
1142 "Modified: / 08-03-2007 / 22:58:59 / cg" |
|
1143 ! |
|
1144 |
|
1145 modified |
|
1146 "return true if text was modified" |
|
1147 |
|
1148 ^ modifiedChannel value |
|
1149 ! |
|
1150 |
|
1151 modified:aBoolean |
|
1152 "set/clear the modified flag" |
|
1153 |
|
1154 modifiedChannel value:aBoolean |
|
1155 |
|
1156 "Modified: 14.2.1997 / 16:44:05 / cg" |
|
1157 ! |
|
1158 |
|
1159 modifiedChannel |
|
1160 "return the valueHolder holding true if text was modified" |
|
1161 |
|
1162 ^ modifiedChannel |
|
1163 ! |
|
1164 |
|
1165 modifiedChannel:aValueHolder |
|
1166 "set the valueHolder holding true if text was modified" |
|
1167 |
|
1168 |prev| |
|
1169 |
|
1170 prev := modifiedChannel. |
|
1171 modifiedChannel := aValueHolder. |
|
1172 self setupChannel:aValueHolder for:nil withOld:prev |
|
1173 |
|
1174 "Created: / 30.1.1998 / 14:51:32 / cg" |
|
1175 ! |
|
1176 |
|
1177 readOnly |
|
1178 "make the text readonly. |
|
1179 Obsolete because it is obfuscating (looks like a getter) |
|
1180 - use #readOnly:" |
|
1181 |
|
1182 <resource:#obsolete> |
|
1183 |
|
1184 self obsoleteMethodWarning:'use #readOnly:'. |
|
1185 self readOnly:true. |
|
1186 |
|
1187 "Modified: / 14-02-1997 / 17:35:56 / cg" |
|
1188 "Modified (comment): / 02-08-2013 / 16:46:57 / cg" |
|
1189 ! |
|
1190 |
|
1191 readOnly:aBoolean |
|
1192 "make the text readonly (aBoolean == true) or writable (aBoolean == false). |
|
1193 The argument may also be a valueHolder." |
|
1194 |
|
1195 readOnly := aBoolean |
|
1196 |
|
1197 "Created: 14.2.1997 / 17:35:39 / cg" |
|
1198 ! |
|
1199 |
|
1200 reallyModifiedChannel |
|
1201 "return the valueHolder holding true if text was really modified. |
|
1202 For compatibility with views which use the modified flag for syntax highlighting." |
|
1203 |
|
1204 ^ self modifiedChannel |
|
1205 ! |
|
1206 |
|
1207 st80Mode:aBoolean |
|
1208 "set/clear the st80Mode flag. |
|
1209 If on, the cursor wraps at the line end (like in vi or st80); |
|
1210 if off, we have the Rand-editor behavior (random access)" |
|
1211 |
|
1212 st80Mode := aBoolean |
|
1213 |
|
1214 "Created: / 09-11-2010 / 13:55:50 / cg" |
|
1215 ! |
|
1216 |
|
1217 tabMeansNextField:aBoolean |
|
1218 "set/clear tabbing to the next field. |
|
1219 If true, Tab is ignored and shifts the keyboard focus. |
|
1220 If false, tabs can be entered into the text. |
|
1221 The default is true for editTextView, false for single-line |
|
1222 input fields." |
|
1223 |
|
1224 tabMeansNextField := aBoolean |
|
1225 ! |
|
1226 |
|
1227 tabRequiresControl |
|
1228 "returns true, if a focus tabbing requires a control-key to be pressed. |
|
1229 The default is true for editTextView, false for other widgets, |
|
1230 to allow for easier text entry" |
|
1231 |
|
1232 ^ tabRequiresControl |
|
1233 ! |
|
1234 |
|
1235 tabRequiresControl:aBoolean |
|
1236 "controls if a focus tabbing requires a control-key to be pressed. |
|
1237 The default is true for editTextView, false for other widgets, |
|
1238 to allow for easier text entry" |
|
1239 |
|
1240 tabRequiresControl := aBoolean |
|
1241 ! ! |
|
1242 |
|
1243 !EditTextView methodsFor:'accessing-contents'! |
|
1244 |
|
1245 at:lineNr basicPut:aLine |
|
1246 "change a line without change notification" |
|
1247 |
|
1248 (self at:lineNr) = aLine ifFalse:[ |
|
1249 super at:lineNr put:aLine. |
|
1250 ]. |
|
1251 ! |
|
1252 |
|
1253 at:lineNr put:aLine |
|
1254 (self at:lineNr) = aLine ifFalse:[ |
|
1255 super at:lineNr put:aLine. |
|
1256 self textChanged |
|
1257 ]. |
|
1258 ! |
|
1259 |
|
1260 characterAfterCursor |
|
1261 "return the character one after the cursor - space if beyond line." |
|
1262 |
|
1263 ^ self characterAtLine:cursorLine col:cursorCol+1 |
|
1264 ! |
|
1265 |
|
1266 characterBeforeCursor |
|
1267 "return the character to the left of cursor - space if beyond line, nil if at the beginning." |
|
1268 |
|
1269 cursorCol == 1 ifTrue:[^ nil]. |
|
1270 |
|
1271 ^ self characterAtLine:cursorLine col:cursorCol-1 |
|
1272 |
|
1273 "Created: / 17.6.1998 / 15:16:41 / cg" |
|
1274 ! |
|
1275 |
|
1276 characterUnderCursor |
|
1277 "return the character under the cursor - space if beyond line. |
|
1278 For non-block cursors, this is the character immediately to the right |
|
1279 of the insertion-bar or caret." |
|
1280 |
|
1281 ^ self characterAtLine:cursorLine col:cursorCol |
|
1282 ! |
|
1283 |
|
1284 contents |
|
1285 "return the contents as a String or Text (i.e. with emphasis)" |
|
1286 |
|
1287 list isNil ifTrue:[^ '']. |
|
1288 self removeTrailingBlankLines. |
|
1289 ^ super contents. |
|
1290 |
|
1291 "Modified: / 04-07-2006 / 19:22:32 / fm" |
|
1292 ! |
|
1293 |
|
1294 contents:something |
|
1295 self contents:something keepUndoHistory:false. |
|
1296 ! |
|
1297 |
|
1298 contents:something keepUndoHistory:keepUndoHistory |
|
1299 super contents:something. |
|
1300 keepUndoHistory ifFalse:[ |
|
1301 undoSupport resetHistories. |
|
1302 ]. |
|
1303 ! |
|
1304 |
|
1305 contentsAsString |
|
1306 "return the contents as a String (i.e. without emphasis)" |
|
1307 |
|
1308 list isNil ifTrue:[^ '']. |
|
1309 self removeTrailingBlankLines. |
|
1310 ^ (list collect:[:each | each isNil ifTrue:[''] |
|
1311 ifFalse:[each string] |
|
1312 ]) asStringWithCRs |
|
1313 ! |
|
1314 |
|
1315 cursorCol |
|
1316 "return the cursors col (1..). |
|
1317 This is the absolute col; NOT the visible col" |
|
1318 |
|
1319 ^ cursorCol |
|
1320 ! |
|
1321 |
|
1322 cursorColHolder |
|
1323 "return a valueHolder for the cursors column (1..)." |
|
1324 |
|
1325 ^ cursorColHolder |
|
1326 ! |
|
1327 |
|
1328 cursorLine |
|
1329 "return the cursors line (1..). |
|
1330 This is the absolute line; NOT the visible line" |
|
1331 |
|
1332 ^ cursorLine |
|
1333 ! |
|
1334 |
|
1335 cursorLineHolder |
|
1336 "return a valueHolder for the cursors line (1..). |
|
1337 This is the absolute line; NOT the visible line" |
|
1338 |
|
1339 ^ cursorLineHolder |
|
1340 ! |
|
1341 |
|
1342 lineStringBeforeCursor |
|
1343 "return the line's string before the cursor. |
|
1344 Pad with spaces up to the cursor position if beyond the end of line" |
|
1345 |
|
1346 |line| |
|
1347 |
|
1348 line := ((self at:cursorLine) ? '') string. |
|
1349 line size < (cursorCol-1) ifTrue:[ |
|
1350 ^ line paddedTo:(cursorCol-1) |
|
1351 ]. |
|
1352 ^ line copyTo:(cursorCol-1) |
|
1353 ! |
|
1354 |
|
1355 list:something |
|
1356 "position cursor home when setting contents" |
|
1357 |
|
1358 |prevCursorLine prevCursorCol| |
|
1359 |
|
1360 prevCursorLine := cursorLine. |
|
1361 prevCursorCol := cursorCol. |
|
1362 |
|
1363 super list:something. |
|
1364 |
|
1365 (cursorMovementWhenUpdating == #endOfText |
|
1366 or:[cursorMovementWhenUpdating == #end]) ifTrue:[ |
|
1367 ^ self cursorToEndOfText |
|
1368 ]. |
|
1369 |
|
1370 (cursorMovementWhenUpdating == #endOfLine) ifTrue:[ |
|
1371 ^ self cursorLine:prevCursorLine col:(self listAt:cursorLine) size + 1. |
|
1372 ]. |
|
1373 |
|
1374 (cursorMovementWhenUpdating == #beginOfText |
|
1375 or:[cursorMovementWhenUpdating == #begin]) ifTrue:[ |
|
1376 ^ self cursorHome |
|
1377 ]. |
|
1378 (cursorMovementWhenUpdating == #beginOfLine) ifTrue:[ |
|
1379 ^ self cursorLine:prevCursorLine col:1. |
|
1380 ]. |
|
1381 |
|
1382 "/ default: stay where it was |
|
1383 "/ self cursorLine:prevCursorLine col:prevCursorCol. |
|
1384 ! |
|
1385 |
|
1386 setContents:something |
|
1387 |selType| |
|
1388 |
|
1389 undoSupport resetHistories. |
|
1390 |
|
1391 selType := typeOfSelection. |
|
1392 super setContents:something. |
|
1393 typeOfSelection := selType. |
|
1394 |
|
1395 "Created: / 31.3.1998 / 23:35:06 / cg" |
|
1396 ! ! |
|
1397 |
|
1398 !EditTextView methodsFor:'accessing-dimensions'! |
|
1399 |
|
1400 absoluteXOfPosition:positionInText |
|
1401 |accumulatedX container| |
|
1402 |
|
1403 accumulatedX := 0. |
|
1404 container := self. |
|
1405 [ container notNil ] whileTrue:[ |
|
1406 accumulatedX := accumulatedX + container origin x. |
|
1407 container := container isTopView ifFalse:[ |
|
1408 container container |
|
1409 ] ifTrue:[ nil ]. |
|
1410 ]. |
|
1411 ^ (self xOfPosition:positionInText) + accumulatedX |
|
1412 |
|
1413 "Created: / 16-02-2010 / 10:05:19 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
1414 ! |
|
1415 |
|
1416 absoluteYOfCursor |
|
1417 |
|
1418 | accumulatedY container | |
|
1419 accumulatedY := 0. |
|
1420 container := self. |
|
1421 [ container notNil ] whileTrue:[ |
|
1422 accumulatedY := accumulatedY + container origin y. |
|
1423 container := container isTopView |
|
1424 ifFalse:[container container] |
|
1425 ifTrue:[nil]. |
|
1426 ]. |
|
1427 ^(self yOfCursor) + accumulatedY |
|
1428 |
|
1429 "Created: / 27-05-2005 / 07:45:53 / janfrog" |
|
1430 "Modified: / 27-05-2005 / 23:03:40 / janfrog" |
|
1431 ! |
|
1432 |
|
1433 xOfCursor |
|
1434 |point| |
|
1435 |
|
1436 cursorVisibleLine isNil ifTrue:[ |
|
1437 "/ take the end of the selection, if any |
|
1438 (selectionStartLine notNil |
|
1439 and:[ self listLineIsVisible:selectionEndLine ]) |
|
1440 ifTrue:[ |
|
1441 ^ self xOfCol:selectionEndCol inVisibleLine:selectionEndLine. |
|
1442 ]. |
|
1443 |
|
1444 "/ point := device |
|
1445 "/ translatePoint:(device pointerPosition) |
|
1446 "/ fromView:nil |
|
1447 "/ toView:self. |
|
1448 "/ ((self bounds) containsPoint:point) ifTrue:[ |
|
1449 "/ ^ point x |
|
1450 "/ ]. |
|
1451 "/ ^ 0 |
|
1452 ^ nil |
|
1453 ]. |
|
1454 ^self xOfCol:cursorCol inVisibleLine:cursorVisibleLine. |
|
1455 |
|
1456 "Created: / 27-05-2005 / 07:43:41 / janfrog" |
|
1457 ! |
|
1458 |
|
1459 xOfPosition: positionInText |
|
1460 |
|
1461 | line col | |
|
1462 line := self lineOfCharacterPosition: positionInText. |
|
1463 col := positionInText - (self characterPositionOfLine:line col:1) + 1. |
|
1464 ^ |
|
1465 (self xOfCol:col inVisibleLine:(self listLineToVisibleLine: line)) |
|
1466 - viewOrigin x. |
|
1467 |
|
1468 "Created: / 16-02-2010 / 10:04:27 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
1469 ! |
|
1470 |
|
1471 yOfCursor |
|
1472 |
|
1473 ^self yOfVisibleLine:cursorVisibleLine. |
|
1474 |
|
1475 "Created: / 27-05-2005 / 07:43:41 / janfrog" |
|
1476 ! |
|
1477 |
|
1478 yOfPosition: positionInText |
|
1479 |
|
1480 | line | |
|
1481 line := self lineOfCharacterPosition: positionInText. |
|
1482 ^self yOfVisibleLine:(self listLineToVisibleLine: line) |
|
1483 |
|
1484 "Created: / 16-02-2010 / 10:08:21 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
1485 ! ! |
|
1486 |
|
1487 !EditTextView methodsFor:'accessing-look'! |
|
1488 |
|
1489 cursorForegroundColor:color1 backgroundColor:color2 |
|
1490 "set both cursor foreground and cursor background colors" |
|
1491 |
|
1492 |wasOn| |
|
1493 |
|
1494 wasOn := self hideCursor. |
|
1495 cursorFgColor := color1 onDevice:self graphicsDevice. |
|
1496 cursorBgColor := color2 onDevice:self graphicsDevice. |
|
1497 wasOn ifTrue:[self showCursor] |
|
1498 ! |
|
1499 |
|
1500 cursorType |
|
1501 "return the style of the text cursor. |
|
1502 Currently, supported are: #none |
|
1503 #block, #frame, #ibeam, #caret, #solidCaret |
|
1504 #bigCaret and #bigSolidCaret" |
|
1505 |
|
1506 ^ cursorType |
|
1507 |
|
1508 "Modified: / 5.5.1999 / 14:52:33 / cg" |
|
1509 ! |
|
1510 |
|
1511 cursorType:aCursorTypeSymbol |
|
1512 "set the style of the text cursor. |
|
1513 Currently, supported are: #none |
|
1514 #block, #frame, #ibeam, #caret, #solidCaret |
|
1515 #bigCaret and #bigSolidCaret" |
|
1516 |
|
1517 cursorType := aCursorTypeSymbol. |
|
1518 |
|
1519 "Created: 21.9.1997 / 13:42:23 / cg" |
|
1520 "Modified: 21.9.1997 / 13:43:35 / cg" |
|
1521 ! |
|
1522 |
|
1523 cursorTypeNoFocus |
|
1524 "return the style of the text cursor when the view has no focus. |
|
1525 If left unspecified, this is the same as the regular cursorType." |
|
1526 |
|
1527 ^ cursorTypeNoFocus |
|
1528 |
|
1529 "Created: / 5.5.1999 / 14:52:46 / cg" |
|
1530 ! |
|
1531 |
|
1532 cursorTypeNoFocus:aCursorTypeSymbol |
|
1533 "set the style of the text cursor when the view has no focus. |
|
1534 If left unspecified, this is the same as the regular cursorType." |
|
1535 |
|
1536 cursorTypeNoFocus := aCursorTypeSymbol |
|
1537 ! ! |
|
1538 |
|
1539 !EditTextView methodsFor:'accessing-replace'! |
|
1540 |
|
1541 lastReplacementInfo |
|
1542 ^ lastReplacementInfo |
|
1543 ! |
|
1544 |
|
1545 lastStringToReplace: aString |
|
1546 ! |
|
1547 |
|
1548 previousReplacements |
|
1549 "accessor for the code completion" |
|
1550 |
|
1551 ^ lastReplacementInfo previousReplacements |
|
1552 ! ! |
|
1553 |
|
1554 !EditTextView methodsFor:'change & update'! |
|
1555 |
|
1556 accept |
|
1557 "accept the current contents by executing the accept-action and/or |
|
1558 changeMessage." |
|
1559 |
|
1560 acceptEnabled == false ifTrue:[ |
|
1561 self beep. |
|
1562 ^ self |
|
1563 ]. |
|
1564 (disableIfInvisible == true and:[self reallyRealized not]) ifTrue:[ |
|
1565 ^ self |
|
1566 ]. |
|
1567 |
|
1568 lockUpdates := true. |
|
1569 |
|
1570 "/ |
|
1571 "/ ST-80 way of doing it |
|
1572 "/ |
|
1573 model notNil ifTrue:[ |
|
1574 self sendChangeMessage:changeMsg with:self argForChangeMessage. |
|
1575 acceptChannel value:true withoutNotifying:self. |
|
1576 ]. |
|
1577 |
|
1578 "/ |
|
1579 "/ ST/X way of doing things |
|
1580 "/ as a historic (and temporary) leftover, |
|
1581 "/ the block is called with a stringCollection |
|
1582 "/ - not with the actual string |
|
1583 "/ |
|
1584 acceptAction notNil ifTrue:[ |
|
1585 acceptAction value:self list |
|
1586 ]. |
|
1587 |
|
1588 lockUpdates := false. |
|
1589 |
|
1590 "Modified: / 30.1.1998 / 14:19:00 / cg" |
|
1591 ! |
|
1592 |
|
1593 argForChangeMessage |
|
1594 "return the argument to be passed with the change notification. |
|
1595 Defined as separate method for easier subclassability." |
|
1596 |
|
1597 ^ self contents |
|
1598 |
|
1599 "Modified: 29.4.1996 / 12:42:14 / cg" |
|
1600 ! |
|
1601 |
|
1602 getListFromModel |
|
1603 "get my contents from the model. |
|
1604 Redefined to ignore updates resulting from my own changes |
|
1605 (i.e. if lockUpdates is true)." |
|
1606 |
|
1607 " |
|
1608 ignore updates from my own change |
|
1609 " |
|
1610 lockUpdates ifTrue:[ |
|
1611 lockUpdates := false. |
|
1612 ^ self |
|
1613 ]. |
|
1614 super getListFromModel. |
|
1615 undoSupport resetHistories. |
|
1616 |
|
1617 "/ validate the cursorLine |
|
1618 (cursorLine notNil |
|
1619 and:[ cursorLine > list size ]) ifTrue:[ |
|
1620 self cursorLine:list size + 1 col:1 |
|
1621 ]. |
|
1622 ! |
|
1623 |
|
1624 update:something with:aParameter from:changedObject |
|
1625 changedObject == acceptChannel ifTrue:[ |
|
1626 acceptChannel value == true ifTrue:[ |
|
1627 self accept. |
|
1628 ]. |
|
1629 ^ self. |
|
1630 ]. |
|
1631 super update:something with:aParameter from:changedObject |
|
1632 |
|
1633 "Created: / 30.1.1998 / 14:15:56 / cg" |
|
1634 "Modified: / 1.2.1998 / 13:15:55 / cg" |
|
1635 ! ! |
|
1636 |
|
1637 !EditTextView methodsFor:'cursor handling'! |
|
1638 |
|
1639 basicCursorReturn |
|
1640 "move cursor to start of next line; scroll if at end of visible text" |
|
1641 |
|
1642 |wasOn| |
|
1643 |
|
1644 self checkForExistingLine:(cursorLine + 1). |
|
1645 cursorVisibleLine notNil ifTrue:[ |
|
1646 nFullLinesShown notNil ifTrue:[ |
|
1647 (cursorVisibleLine >= nFullLinesShown) ifTrue:[self scrollDown] |
|
1648 ] |
|
1649 ]. |
|
1650 |
|
1651 wasOn := self hideCursor. |
|
1652 self setValidatedCursorLine:(cursorLine + 1) col:1. |
|
1653 self makeCursorVisibleAndShowCursor:wasOn. |
|
1654 |
|
1655 "Modified: 22.5.1996 / 18:27:34 / cg" |
|
1656 ! |
|
1657 |
|
1658 characterPositionOfCursor |
|
1659 ^ self characterPositionOfLine:cursorLine col:cursorCol |
|
1660 ! |
|
1661 |
|
1662 cursorBacktab |
|
1663 "move cursor to prev tabstop" |
|
1664 |
|
1665 self cursorCol:(self prevTabBefore:cursorCol). |
|
1666 ! |
|
1667 |
|
1668 cursorCol:newCol |
|
1669 "move cursor to some column in the current line" |
|
1670 |
|
1671 |wasOn| |
|
1672 |
|
1673 (cursorCol == newCol) ifTrue:[^ self]. |
|
1674 |
|
1675 wasOn := self hideCursor. |
|
1676 self setValidatedCursorCol:newCol. |
|
1677 self makeCursorVisibleAndShowCursor:wasOn. |
|
1678 |
|
1679 "Modified: 22.5.1996 / 14:25:53 / cg" |
|
1680 ! |
|
1681 |
|
1682 cursorDown |
|
1683 "move cursor down; scroll if at end of visible text; |
|
1684 beep if at end of physical text." |
|
1685 |
|
1686 |wasOn| |
|
1687 |
|
1688 self cursorDown:1. |
|
1689 |
|
1690 "/ cursor beyond text ? |
|
1691 cursorLine > list size ifTrue:[ |
|
1692 wasOn := self hideCursor. |
|
1693 self setValidatedCursorLine:(list size + 1) col:cursorCol. |
|
1694 self makeCursorVisibleAndShowCursor:wasOn. |
|
1695 self beep. |
|
1696 ]. |
|
1697 |
|
1698 "Modified: / 10.6.1998 / 17:00:23 / cg" |
|
1699 ! |
|
1700 |
|
1701 cursorDown:n |
|
1702 "move cursor down by n lines; scroll if at end of visible text" |
|
1703 |
|
1704 |wasOn nv nL| |
|
1705 |
|
1706 (nL := cursorLine) isNil ifTrue:[ |
|
1707 nL := firstLineShown |
|
1708 ]. |
|
1709 |
|
1710 self st80EditMode ifTrue:[ |
|
1711 nL == list size ifTrue:[ |
|
1712 wasOn := self hideCursor. |
|
1713 self setValidatedCursorLine:(list size) col:(self listAt:list size) size + 1. |
|
1714 self makeCursorVisibleAndShowCursor:wasOn. |
|
1715 self beep. |
|
1716 ^ self. |
|
1717 ] |
|
1718 ]. |
|
1719 |
|
1720 cursorVisibleLine notNil ifTrue:[ |
|
1721 wasOn := self hideCursor. |
|
1722 nv := cursorVisibleLine + n - 1. |
|
1723 (nv >= nFullLinesShown) ifTrue:[ |
|
1724 self scrollDown:(nv - nFullLinesShown + 1) |
|
1725 ]. |
|
1726 self setValidatedCursorLine:(cursorLine + n) col:cursorCol. |
|
1727 self makeCursorVisibleAndShowCursor:wasOn. |
|
1728 ] ifFalse:[ |
|
1729 self setValidatedCursorLine:(nL + n) col:cursorCol. |
|
1730 self makeCursorVisible. |
|
1731 ]. |
|
1732 |
|
1733 "Modified: / 10.6.1998 / 16:59:17 / cg" |
|
1734 ! |
|
1735 |
|
1736 cursorHome |
|
1737 "scroll to top AND move cursor to first line of text." |
|
1738 |
|
1739 self cursorLine:1 col:1 |
|
1740 |
|
1741 "/ |wasOn| |
|
1742 "/ |
|
1743 "/ wasOn := self hideCursor. |
|
1744 "/ self scrollToTop. |
|
1745 "/ cursorLine := cursorVisibleLine := 1. |
|
1746 "/ cursorCol := self validateCursorCol:1 inLine:cursorLine. |
|
1747 "/ self makeCursorVisibleAndShowCursor:wasOn. |
|
1748 |
|
1749 "Modified: 22.5.1996 / 18:26:42 / cg" |
|
1750 ! |
|
1751 |
|
1752 cursorLeft |
|
1753 "move cursor to left" |
|
1754 |
|
1755 (cursorCol ~~ 1) ifTrue:[ |
|
1756 self cursorCol:(cursorCol - 1) |
|
1757 ] ifFalse:[ |
|
1758 cursorLine ~~ 1 ifTrue:[ |
|
1759 self st80EditMode ifTrue:[ |
|
1760 self cursorUp. |
|
1761 self cursorToEndOfLine. |
|
1762 ] |
|
1763 ] |
|
1764 ] |
|
1765 |
|
1766 "Modified: / 23.1.1998 / 12:37:13 / cg" |
|
1767 ! |
|
1768 |
|
1769 cursorLeft:n |
|
1770 "move cursor to left" |
|
1771 |
|
1772 n timesRepeat:[ |
|
1773 self cursorLeft |
|
1774 ]. |
|
1775 ! |
|
1776 |
|
1777 cursorLine:line col:col |
|
1778 "this positions onto physical - not visible - line" |
|
1779 |
|
1780 |wasOn newCol| |
|
1781 |
|
1782 ((line == cursorLine) and:[col == cursorCol]) ifTrue:[^ self]. |
|
1783 |
|
1784 wasOn := self hideCursor. |
|
1785 self setValidatedCursorLine:line. |
|
1786 |
|
1787 (col < 1) ifTrue:[ |
|
1788 newCol := 1 |
|
1789 ] ifFalse:[ |
|
1790 newCol := col. |
|
1791 ]. |
|
1792 self st80EditMode ifTrue:[ |
|
1793 (cursorLine == list size |
|
1794 and:[cursorLine ~~ line]) ifTrue:[ |
|
1795 newCol := (self listAt:(list size)) size + 1. |
|
1796 ] |
|
1797 ]. |
|
1798 self setValidatedCursorCol:newCol. |
|
1799 self makeCursorVisibleAndShowCursor:wasOn. |
|
1800 |
|
1801 "Modified: / 20.6.1998 / 18:19:06 / cg" |
|
1802 ! |
|
1803 |
|
1804 cursorMovementAllowed |
|
1805 "return true, if the user may move the cursor around |
|
1806 (via button-click, or cursor-key with selection). |
|
1807 By default, true is returned, but this may be redefined |
|
1808 in special subclasses (such as a terminal view), where |
|
1809 this is not wanted" |
|
1810 |
|
1811 ^ true |
|
1812 |
|
1813 "Created: / 18.6.1998 / 14:11:16 / cg" |
|
1814 ! |
|
1815 |
|
1816 cursorReturn |
|
1817 "move cursor to start of next line; scroll if at end of visible text" |
|
1818 |
|
1819 self basicCursorReturn |
|
1820 ! |
|
1821 |
|
1822 cursorRight |
|
1823 "move cursor to right" |
|
1824 |
|
1825 |l| |
|
1826 |
|
1827 self st80EditMode ifTrue:[ |
|
1828 l := (self listAt:cursorLine). |
|
1829 cursorCol >= (l size + 1) ifTrue:[ |
|
1830 cursorLine < list size ifTrue:[ |
|
1831 self cursorReturn. |
|
1832 ]. |
|
1833 ^ self |
|
1834 ] |
|
1835 ]. |
|
1836 self cursorCol:(cursorCol + 1) |
|
1837 |
|
1838 "Modified: / 20.6.1998 / 18:19:07 / cg" |
|
1839 ! |
|
1840 |
|
1841 cursorRight:n |
|
1842 "move cursor to right" |
|
1843 |
|
1844 n timesRepeat:[ |
|
1845 self cursorRight |
|
1846 ]. |
|
1847 ! |
|
1848 |
|
1849 cursorShown:aBoolean |
|
1850 "change cursor visibility |
|
1851 return true if cursor was visible before." |
|
1852 |
|
1853 |oldState| |
|
1854 |
|
1855 aBoolean == cursorShown ifTrue:[ |
|
1856 ^ cursorShown |
|
1857 ]. |
|
1858 |
|
1859 oldState := cursorShown. |
|
1860 |
|
1861 aBoolean ifTrue:[ |
|
1862 self drawCursor. |
|
1863 ] ifFalse:[ |
|
1864 (cursorShown and:[shown]) ifTrue: [ |
|
1865 self undrawCursor. |
|
1866 ]. |
|
1867 ]. |
|
1868 cursorShown := aBoolean. |
|
1869 |
|
1870 ^ oldState |
|
1871 |
|
1872 "Modified: / 30.3.1999 / 15:32:43 / stefan" |
|
1873 "Created: / 30.3.1999 / 15:59:30 / stefan" |
|
1874 ! |
|
1875 |
|
1876 cursorTab |
|
1877 "move cursor to next tabstop" |
|
1878 |
|
1879 self cursorCol:(self nextTabAfter:cursorCol). |
|
1880 ! |
|
1881 |
|
1882 cursorToBeginOfLine |
|
1883 "move cursor to the start of the current line" |
|
1884 |
|
1885 |textStart l| |
|
1886 |
|
1887 l := self listAt:cursorLine. |
|
1888 textStart := l isNil ifTrue:[1] ifFalse:[l indexOfNonSeparator]. |
|
1889 cursorCol > textStart ifTrue:[ |
|
1890 self cursorCol:textStart |
|
1891 ] ifFalse:[ |
|
1892 self cursorCol:1 |
|
1893 ] |
|
1894 |
|
1895 "Created: / 8.8.2004 / 18:51:21 / janfrog" |
|
1896 ! |
|
1897 |
|
1898 cursorToBottom |
|
1899 "move cursor to the last line of text (col 1)" |
|
1900 |
|
1901 |wasOn newTop| |
|
1902 |
|
1903 wasOn := self hideCursor. |
|
1904 |
|
1905 newTop := list size - nFullLinesShown. |
|
1906 (newTop < 1) ifTrue:[ |
|
1907 newTop := 1 |
|
1908 ]. |
|
1909 self scrollToLine:newTop. |
|
1910 |
|
1911 self setValidatedCursorLine:(list size) col:1. |
|
1912 |
|
1913 self makeCursorVisibleAndShowCursor:wasOn. |
|
1914 |
|
1915 "Modified: 22.5.1996 / 18:27:45 / cg" |
|
1916 ! |
|
1917 |
|
1918 cursorToCharacterPosition:pos |
|
1919 "compute line/col from character position (1..) |
|
1920 and move the cursor onto that char" |
|
1921 |
|
1922 |line col| |
|
1923 |
|
1924 line := self lineOfCharacterPosition:pos. |
|
1925 col := pos - (self characterPositionOfLine:line col:1) + 1. |
|
1926 self cursorLine:line col:col |
|
1927 |
|
1928 "Created: / 15.1.1998 / 21:55:33 / cg" |
|
1929 ! |
|
1930 |
|
1931 cursorToEnd |
|
1932 "move cursor down below last line of text" |
|
1933 |
|
1934 |wasOn newTop lineNr line| |
|
1935 |
|
1936 lineNr := list size. |
|
1937 |
|
1938 cursorLine >= lineNr ifTrue:[ |
|
1939 line := self listAt:cursorLine. |
|
1940 (line isEmptyOrNil) ifTrue:[ |
|
1941 ^ self |
|
1942 ] |
|
1943 ]. |
|
1944 |
|
1945 wasOn := self hideCursor. |
|
1946 |
|
1947 lineNr := lineNr + 1. |
|
1948 newTop := lineNr - nFullLinesShown. |
|
1949 (newTop < 1) ifTrue:[ |
|
1950 newTop := 1 |
|
1951 ]. |
|
1952 self scrollToLine:newTop. |
|
1953 |
|
1954 self setValidatedCursorLine:lineNr col:1. |
|
1955 |
|
1956 self makeCursorVisibleAndShowCursor:wasOn. |
|
1957 |
|
1958 "Modified: 22.5.1996 / 18:27:53 / cg" |
|
1959 ! |
|
1960 |
|
1961 cursorToEndOfLine |
|
1962 "move cursor to end of current line" |
|
1963 |
|
1964 |line| |
|
1965 |
|
1966 line := (self listAt:cursorLine). |
|
1967 self cursorCol:(line size + 1) |
|
1968 |
|
1969 "Modified: 13.8.1997 / 15:34:02 / cg" |
|
1970 ! |
|
1971 |
|
1972 cursorToEndOfText |
|
1973 "move cursor to the end of the text (behind the last character in last line)" |
|
1974 |
|
1975 |wasOn newTop lastLineLength pos| |
|
1976 |
|
1977 wasOn := self hideCursor. |
|
1978 |
|
1979 newTop := list size - nFullLinesShown. |
|
1980 (newTop < 1) ifTrue:[ |
|
1981 newTop := 1 |
|
1982 ]. |
|
1983 self scrollToLine:newTop. |
|
1984 |
|
1985 self setValidatedCursorLine:list size. |
|
1986 lastLineLength := (self listAt:cursorLine) size. |
|
1987 pos := (lastLineLength==0) ifTrue:[0] ifFalse:[lastLineLength+1]. |
|
1988 self setCursorCol:(self validateCursorCol:pos inLine:cursorLine). |
|
1989 |
|
1990 self makeCursorVisibleAndShowCursor:wasOn. |
|
1991 |
|
1992 "Modified: / 15-07-2011 / 20:14:43 / cg" |
|
1993 ! |
|
1994 |
|
1995 cursorToEndOfWord |
|
1996 "move the cursor to the end of the word" |
|
1997 |
|
1998 (cursorLine > list size) ifTrue:[^ self]. |
|
1999 |
|
2000 self wordAtLine:cursorLine col:cursorCol do:[ |
|
2001 :beginLine :beginCol :endLine :endCol :style | |
|
2002 |
|
2003 self cursorLine:endLine col:endCol+1 |
|
2004 ] |
|
2005 |
|
2006 "Created: / 28-06-2006 / 19:16:30 / cg" |
|
2007 ! |
|
2008 |
|
2009 cursorToFirstVisibleLine |
|
2010 "place cursor into the first visible line; do not scroll." |
|
2011 |
|
2012 self cursorLine:(self visibleLineToAbsoluteLine:1) col:1 |
|
2013 ! |
|
2014 |
|
2015 cursorToLastVisibleLine |
|
2016 "place cursor into the first visible line; do not scroll." |
|
2017 |
|
2018 self cursorLine:(self visibleLineToAbsoluteLine:nFullLinesShown) col:1 |
|
2019 ! |
|
2020 |
|
2021 cursorToNextWord |
|
2022 "move the cursor to the beginning of the next word" |
|
2023 |
|
2024 |col line searching| |
|
2025 |
|
2026 (cursorLine > list size) ifTrue:[^ self]. |
|
2027 |
|
2028 self |
|
2029 wordAtLine:cursorLine col:cursorCol |
|
2030 do:[ |
|
2031 :beginLine :beginCol :endLine :endCol :style | |
|
2032 |
|
2033 line := endLine. |
|
2034 col := endCol + 1. |
|
2035 searching := true. |
|
2036 [searching and:[(self characterAtLine:line col:col) isSeparator]] whileTrue:[ |
|
2037 self wordAtLine:line col:col do:[ |
|
2038 :beginLine :beginCol :endLine :endCol :style | |
|
2039 |
|
2040 (line > list size) ifTrue:[ |
|
2041 "break out" |
|
2042 searching := false |
|
2043 ] ifFalse:[ |
|
2044 line := endLine. |
|
2045 col := endCol + 1. |
|
2046 ] |
|
2047 ] |
|
2048 ]. |
|
2049 self cursorLine:line col:col |
|
2050 ] |
|
2051 ! |
|
2052 |
|
2053 cursorToPreviousWord |
|
2054 "move the cursor to the beginning of this or the previous word" |
|
2055 |
|
2056 |col line searching l| |
|
2057 |
|
2058 (cursorLine > list size) ifTrue:[^ self]. "/ this is rubbish |
|
2059 |
|
2060 self wordAtLine:cursorLine col:cursorCol do:[ |
|
2061 :beginLine :beginCol :endLine :endCol :style | |
|
2062 |
|
2063 line := beginLine. |
|
2064 col := beginCol. |
|
2065 style == #wordLeft ifTrue:[ |
|
2066 col := col + 1 |
|
2067 ]. |
|
2068 |
|
2069 (cursorLine == line |
|
2070 and:[cursorCol == col]) ifTrue:[ |
|
2071 searching := true. |
|
2072 |
|
2073 col > 1 ifTrue:[ |
|
2074 col := col - 1. |
|
2075 ]. |
|
2076 |
|
2077 [searching] whileTrue:[ |
|
2078 (col == 1) ifTrue:[ |
|
2079 line == 1 ifTrue:[ |
|
2080 searching := false |
|
2081 ] ifFalse:[ |
|
2082 line := line - 1. |
|
2083 l := list at:line. |
|
2084 col := l size + 1. |
|
2085 ] |
|
2086 ] ifFalse:[ |
|
2087 (self characterAtLine:line col:col) isSeparator ifFalse:[ |
|
2088 self wordAtLine:line col:col do:[ |
|
2089 :beginLine :beginCol :endLine :endCol :style | |
|
2090 |
|
2091 line := beginLine. |
|
2092 col := beginCol. |
|
2093 style == #wordLeft ifTrue:[ |
|
2094 col := col + 1 |
|
2095 ]. |
|
2096 searching := false. |
|
2097 ] |
|
2098 ] ifTrue:[ |
|
2099 col := col - 1 |
|
2100 ] |
|
2101 ] |
|
2102 ] |
|
2103 ]. |
|
2104 self cursorLine:line col:col |
|
2105 ] |
|
2106 |
|
2107 "Created: 8.3.1996 / 21:52:48 / cg" |
|
2108 "Modified: 8.3.1996 / 22:12:45 / cg" |
|
2109 ! |
|
2110 |
|
2111 cursorToTop |
|
2112 "move cursor to absolute home" |
|
2113 |
|
2114 self cursorLine:1 col:1 |
|
2115 ! |
|
2116 |
|
2117 cursorUp |
|
2118 "move cursor up; scroll if at start of visible text" |
|
2119 |
|
2120 self cursorUp:1 |
|
2121 ! |
|
2122 |
|
2123 cursorUp:n |
|
2124 "move cursor up n lines; scroll if at start of visible text" |
|
2125 |
|
2126 |wasOn nv nl| |
|
2127 |
|
2128 cursorLine isNil ifTrue:[ |
|
2129 self setCursorLine:(firstLineShown + nFullLinesShown - 1). |
|
2130 ]. |
|
2131 nl := cursorLine - n. |
|
2132 nl < 1 ifTrue:[nl := 1]. |
|
2133 |
|
2134 (nl ~~ cursorLine) ifTrue: [ |
|
2135 wasOn := self hideCursor. |
|
2136 cursorVisibleLine notNil ifTrue:[ |
|
2137 nv := cursorVisibleLine - n. |
|
2138 nv < 1 ifTrue:[ |
|
2139 self scrollUp:(nv negated + 1) |
|
2140 ]. |
|
2141 ]. |
|
2142 self setValidatedCursorLine:nl col:cursorCol. |
|
2143 "/ wasOn ifTrue:[self showCursor]. |
|
2144 self makeCursorVisibleAndShowCursor:wasOn. |
|
2145 ] |
|
2146 |
|
2147 "Modified: 22.5.1996 / 18:28:11 / cg" |
|
2148 ! |
|
2149 |
|
2150 cursorVisibleLine:visibleLineNr col:colNr |
|
2151 "put cursor to visibleline/col" |
|
2152 |
|
2153 |wasOn newCol listLine| |
|
2154 |
|
2155 wasOn := self hideCursor. |
|
2156 |
|
2157 listLine := self visibleLineToAbsoluteLine:visibleLineNr. |
|
2158 self setValidatedCursorLine:listLine. |
|
2159 cursorVisibleLine := visibleLineNr. |
|
2160 |
|
2161 newCol := colNr. |
|
2162 (newCol < 1) ifTrue:[ |
|
2163 newCol := 1 |
|
2164 ]. |
|
2165 self setValidatedCursorCol:newCol. |
|
2166 |
|
2167 self makeCursorVisibleAndShowCursor:wasOn. |
|
2168 |
|
2169 "Modified: / 20.6.1998 / 18:40:28 / cg" |
|
2170 ! |
|
2171 |
|
2172 cursorX:x y:y |
|
2173 "put cursor to position next to x/y coordinate in view" |
|
2174 |
|
2175 |line col| |
|
2176 |
|
2177 line := self visibleLineOfY:y. |
|
2178 col := self colOfX:x inVisibleLine:line. |
|
2179 self cursorVisibleLine:line col:col. |
|
2180 ! |
|
2181 |
|
2182 drawCursor |
|
2183 "draw the cursor if shown and cursor is visible. |
|
2184 (but not, if there is a selection - to avoid confusion)" |
|
2185 |
|
2186 shown ifTrue:[ |
|
2187 cursorVisibleLine notNil ifTrue:[ |
|
2188 self hasSelection ifFalse:[ |
|
2189 self drawCursorCharacter |
|
2190 ] |
|
2191 ] |
|
2192 ] |
|
2193 ! |
|
2194 |
|
2195 drawCursor:cursorType with:fgColor and:bgColor |
|
2196 "draw a cursor; the argument cursorType specifies what type |
|
2197 of cursor should be drawn. |
|
2198 Currently, supported are: #none, |
|
2199 #block, #frame, #ibeam, #caret, #solidCaret |
|
2200 #bigCaret and #bigSolidCaret" |
|
2201 |
|
2202 |x y w char y2 x1 x2 oldPaint oldClip| |
|
2203 |
|
2204 self hasSelection ifTrue:[ |
|
2205 " |
|
2206 hide cursor, if there is a selection |
|
2207 " |
|
2208 ^ super redrawVisibleLine:cursorVisibleLine col:cursorCol. |
|
2209 ]. |
|
2210 |
|
2211 cursorType == #none ifTrue:[ |
|
2212 ^ self |
|
2213 ]. |
|
2214 |
|
2215 cursorType == #block ifTrue:[ |
|
2216 super drawVisibleLine:cursorVisibleLine col:cursorCol with:fgColor and:bgColor. |
|
2217 ^ self |
|
2218 ]. |
|
2219 x := (self xOfCol:cursorCol inVisibleLine:cursorVisibleLine) - viewOrigin x. |
|
2220 y := self yOfVisibleLine:cursorVisibleLine. |
|
2221 |
|
2222 oldPaint := self paint. "/ do not clobber GC |
|
2223 cursorType == #frame ifTrue:[ |
|
2224 super redrawVisibleLine:cursorVisibleLine col:cursorCol. |
|
2225 |
|
2226 char := self characterUnderCursor asString. |
|
2227 self paint:bgColor. |
|
2228 self displayRectangleX:x y:y width:(gc font widthOf:char) height:fontHeight-2. |
|
2229 ] ifFalse:[ |
|
2230 self paint:bgColor. |
|
2231 cursorType == #ibeam ifTrue:[ |
|
2232 x1 := x - 1. |
|
2233 y2 := y + fontHeight - lineSpacing. |
|
2234 self displayLineFromX:x1 y:y toX:x1 y:y2. |
|
2235 self displayLineFromX:x y:y toX:x y:y2. |
|
2236 ^ self |
|
2237 ]. |
|
2238 |
|
2239 cursorType == #Ibeam ifTrue:[ |
|
2240 x1 := x - 1. |
|
2241 y := y + 1. |
|
2242 y2 := y + fontHeight - lineSpacing. |
|
2243 self displayLineFromX:x1 y:y toX:x1 y:y2. |
|
2244 self displayLineFromX:x y:y toX:x y:y2. |
|
2245 self displayLineFromX:x1-2 y:y toX:x+2 y:y. |
|
2246 self displayLineFromX:x1-2 y:y2 toX:x+2 y:y2. |
|
2247 ^ self |
|
2248 ]. |
|
2249 |
|
2250 y := y + fontHeight - 3. |
|
2251 ((cursorType == #bigCaret) or:[cursorType == #bigSolidCaret]) ifTrue:[ |
|
2252 w := (fontWidth * 2 // 3) max:4. |
|
2253 y2 := y + w + (w//2). |
|
2254 ] ifFalse:[ |
|
2255 w := (fontWidth // 2) max:4. |
|
2256 y2 := y + w. |
|
2257 ]. |
|
2258 x1 := x - w. |
|
2259 x2 := x + w. |
|
2260 |
|
2261 oldClip := self clippingRectangleOrNil. |
|
2262 self clippingRectangle:(margin@margin extent:(width-margin) @ (height-margin)). |
|
2263 |
|
2264 cursorType == #caret ifTrue:[ |
|
2265 self lineWidth:2. |
|
2266 self displayLineFromX:x1 y:y2 toX:x y:y. |
|
2267 self displayLineFromX:x y:y toX:x2 y:y2. |
|
2268 ] ifFalse:[ |
|
2269 "anything else: solidCaret" |
|
2270 |
|
2271 self fillPolygon:(Array with:(x1 @ y2) |
|
2272 with:(x @ y) |
|
2273 with:(x2 @ y2)) |
|
2274 ]. |
|
2275 |
|
2276 self clippingRectangle:oldClip |
|
2277 ]. |
|
2278 self paint:oldPaint. |
|
2279 |
|
2280 "Modified: / 15.12.1999 / 22:24:17 / cg" |
|
2281 ! |
|
2282 |
|
2283 drawCursorCharacter |
|
2284 "draw the cursor. |
|
2285 (i.e. the cursor if no selection) |
|
2286 - helper for many cursor methods" |
|
2287 |
|
2288 (hasKeyboardFocus |
|
2289 and:[self enabled |
|
2290 and:[self isReadOnly not]]) ifTrue:[ |
|
2291 self drawFocusCursor |
|
2292 ] ifFalse:[ |
|
2293 self drawNoFocusCursor |
|
2294 ] |
|
2295 |
|
2296 "Modified: / 23.3.1999 / 13:52:48 / cg" |
|
2297 ! |
|
2298 |
|
2299 drawFocusCursor |
|
2300 "draw the cursor when the focus is in the view." |
|
2301 |
|
2302 self hasSelection ifTrue:[ |
|
2303 ^ super redrawVisibleLine:cursorVisibleLine col:cursorCol. |
|
2304 ]. |
|
2305 cursorType == #none ifTrue:[ |
|
2306 ^ self undrawCursor |
|
2307 ]. |
|
2308 self drawCursor:cursorType with:cursorFgColor and:cursorBgColor. |
|
2309 |
|
2310 "Modified: 22.9.1997 / 00:16:38 / cg" |
|
2311 ! |
|
2312 |
|
2313 drawNoFocusCursor |
|
2314 "draw the cursor for the case when the view has no keyboard focus" |
|
2315 |
|
2316 |cType| |
|
2317 |
|
2318 self hasSelection ifTrue:[ |
|
2319 ^ super redrawVisibleLine:cursorVisibleLine col:cursorCol. |
|
2320 ]. |
|
2321 |
|
2322 cType := cursorTypeNoFocus ? cursorType. |
|
2323 cType == #none ifTrue:[ |
|
2324 ^ self undrawCursor |
|
2325 ]. |
|
2326 |
|
2327 cType == #block ifTrue:[ |
|
2328 ^ self drawCursor:#frame with:cursorNoFocusFgColor and:cursorBgColor |
|
2329 ]. |
|
2330 |
|
2331 ^ self drawCursor:cType with:cursorNoFocusFgColor and:cursorNoFocusFgColor. |
|
2332 |
|
2333 "Modified: 22.9.1997 / 00:16:13 / cg" |
|
2334 ! |
|
2335 |
|
2336 gotoLine:aLineNumber |
|
2337 "position cursor onto line, aLineNumber. |
|
2338 Make certain that this line is visible" |
|
2339 |
|
2340 self makeLineVisible:aLineNumber. |
|
2341 self unselect. |
|
2342 self cursorLine:aLineNumber col:1 |
|
2343 ! |
|
2344 |
|
2345 hideCursor |
|
2346 "make cursor invisible if currently invisible" |
|
2347 |
|
2348 ^ self cursorShown:false |
|
2349 |
|
2350 "Modified: / 30.3.1999 / 16:02:28 / stefan" |
|
2351 ! |
|
2352 |
|
2353 makeCursorVisible |
|
2354 "scroll text to make cursorline visible |
|
2355 (i.e. to have cursorLine in visible area)" |
|
2356 |
|
2357 |line col| |
|
2358 |
|
2359 cursorLine notNil ifTrue:[ |
|
2360 line := cursorLine. |
|
2361 col := cursorCol. |
|
2362 " |
|
2363 if there is a selection, its better to |
|
2364 have its start being visible, instead of the end |
|
2365 " |
|
2366 (selectionStartLine notNil |
|
2367 and:[selectionEndLine notNil]) ifTrue:[ |
|
2368 expandingTop ~~ false ifTrue:[ |
|
2369 line := selectionStartLine. |
|
2370 col := selectionStartCol. |
|
2371 ] ifFalse:[ |
|
2372 line := selectionEndLine. |
|
2373 col := selectionEndCol |
|
2374 ] |
|
2375 ]. |
|
2376 self makeLineVisible:line. |
|
2377 self makeColVisible:col inLine:line |
|
2378 ] |
|
2379 |
|
2380 "Modified: 6.3.1996 / 13:46:46 / cg" |
|
2381 ! |
|
2382 |
|
2383 makeCursorVisibleAndShowCursor:flag |
|
2384 "scroll to make cursorLine visible; |
|
2385 if flag is true, draw the cursor" |
|
2386 |
|
2387 self makeCursorVisible. |
|
2388 flag ifTrue:[self showCursor] |
|
2389 ! |
|
2390 |
|
2391 setCursorCol:colNr |
|
2392 "strictly private: set the cursorCol" |
|
2393 |
|
2394 cursorCol := (colNr max:1). |
|
2395 cursorColHolder value:cursorCol. |
|
2396 ! |
|
2397 |
|
2398 setCursorLine:lineNr |
|
2399 "strictly private: set the cursorLine" |
|
2400 |
|
2401 "/ self assert:(lineNr notNil). |
|
2402 |
|
2403 cursorLine := (lineNr ? 1). |
|
2404 cursorLineHolder value:cursorLine. |
|
2405 self updateCursorVisibleLine. |
|
2406 ! |
|
2407 |
|
2408 setCursorLine:lineNr col:colNr |
|
2409 "strictly private: set the cursorLine, col and update the visibleLine" |
|
2410 |
|
2411 self setCursorLine:lineNr. |
|
2412 self setCursorCol:colNr. |
|
2413 ! |
|
2414 |
|
2415 setValidatedCursorCol:colNr |
|
2416 "strictly private: set the cursorCol" |
|
2417 |
|
2418 self setCursorCol:(self validateCursorCol:colNr inLine:cursorLine). |
|
2419 ! |
|
2420 |
|
2421 setValidatedCursorLine:lineNr |
|
2422 "strictly private: set the cursorLine and update the visibleLine" |
|
2423 |
|
2424 self setCursorLine:(self validateCursorLine:lineNr). |
|
2425 ! |
|
2426 |
|
2427 setValidatedCursorLine:lineNr col:colNr |
|
2428 "strictly private: set the cursorLine, col and update the visibleLine" |
|
2429 |
|
2430 self setValidatedCursorLine:lineNr. |
|
2431 self setValidatedCursorCol:colNr. |
|
2432 ! |
|
2433 |
|
2434 showCursor |
|
2435 "make cursor visible if currently invisible" |
|
2436 |
|
2437 ^ self cursorShown:true |
|
2438 |
|
2439 "Modified: / 30.3.1999 / 16:02:34 / stefan" |
|
2440 ! |
|
2441 |
|
2442 undrawCursor |
|
2443 "undraw the cursor (i.e. redraw the character(s) under the cursor)" |
|
2444 |
|
2445 |prevCol line oldClip x y e1 e2 e3| |
|
2446 |
|
2447 cursorVisibleLine notNil ifTrue:[ |
|
2448 prevCol := cursorCol - 1. |
|
2449 |
|
2450 "/ if there is any italic stuff in the cursor line, |
|
2451 "/ redraw it completely (because characters overlap). |
|
2452 cursorCol > 1 ifTrue:[ |
|
2453 (line := self listAt:cursorLine) notNil ifTrue:[ |
|
2454 line hasChangeOfEmphasis ifTrue:[ |
|
2455 line size >= (cursorCol-1) ifTrue:[ |
|
2456 e1 := Text extractEmphasis:#italic from:(line emphasisAt:cursorCol-1). |
|
2457 line size >= (cursorCol) ifTrue:[ |
|
2458 e2 := Text extractEmphasis:#italic from:(line emphasisAt:cursorCol). |
|
2459 line size >= (cursorCol+1) ifTrue:[ |
|
2460 e3 := Text extractEmphasis:#italic from:(line emphasisAt:cursorCol+1) |
|
2461 ]. |
|
2462 ]. |
|
2463 ]. |
|
2464 (e1 notNil or:[e2 notNil or:[e3 notNil]]) ifTrue:[ |
|
2465 ^ super redrawVisibleLine:cursorVisibleLine |
|
2466 ] |
|
2467 ] |
|
2468 ] |
|
2469 ]. |
|
2470 |
|
2471 ((cursorType == #caret) |
|
2472 or:[cursorType == #solidCaret |
|
2473 or:[cursorType == #bigSolidCaret |
|
2474 or:[cursorType == #bigCaret |
|
2475 or:[cursorType == #Ibeam]]]]) ifTrue:[ |
|
2476 "caret-cursor touches 4 characters" |
|
2477 ((cursorCol > 1) and:[fontIsFixedWidth]) ifTrue:[ |
|
2478 super redrawVisibleLine:cursorVisibleLine-1 from:prevCol to:cursorCol. |
|
2479 super redrawVisibleLine:cursorVisibleLine from:prevCol to:cursorCol. |
|
2480 super redrawVisibleLine:cursorVisibleLine+1 from:prevCol to:cursorCol. |
|
2481 ] ifFalse:[ |
|
2482 "care for left margin" |
|
2483 super redrawVisibleLine:cursorVisibleLine; redrawVisibleLine:cursorVisibleLine+1. |
|
2484 ]. |
|
2485 ^ self |
|
2486 ]. |
|
2487 |
|
2488 cursorType == #ibeam ifTrue:[ |
|
2489 "ibeam-cursor touches 2 characters" |
|
2490 cursorCol > 1 ifTrue:[ |
|
2491 super redrawVisibleLine:cursorVisibleLine from:prevCol to:cursorCol. |
|
2492 ] ifFalse:[ |
|
2493 "care for left margin" |
|
2494 super redrawVisibleLine:cursorVisibleLine. |
|
2495 ]. |
|
2496 ^ self |
|
2497 ]. |
|
2498 |
|
2499 "block cursor is simple - just one character under cursor" |
|
2500 |
|
2501 "/ however, if italic characters are involved, we must care |
|
2502 "/ for the chars before/after the cursor. |
|
2503 "/ We redraw the part of the previous character which got |
|
2504 "/ detroyed by the block cursor. |
|
2505 "/ (must change the clip, to avoid destroying the prev-prev character) |
|
2506 |
|
2507 line := self visibleAt:cursorVisibleLine. |
|
2508 (line notNil and:[line isText]) ifTrue:[ |
|
2509 cursorCol > 1 ifTrue:[ |
|
2510 oldClip := self clippingRectangleOrNil. |
|
2511 x := (self xOfCol:cursorCol inVisibleLine:cursorVisibleLine) - viewOrigin x. |
|
2512 y := self yOfVisibleLine:cursorVisibleLine. |
|
2513 self clippingRectangle:(x@y extent:((gc font width * 2) @ fontHeight)). |
|
2514 super redrawVisibleLine:cursorVisibleLine from:cursorCol-1 to:cursorCol. |
|
2515 self clippingRectangle:oldClip. |
|
2516 ^ self. |
|
2517 ]. |
|
2518 ]. |
|
2519 super redrawVisibleLine:cursorVisibleLine col:cursorCol |
|
2520 ] |
|
2521 |
|
2522 "Modified: / 15.12.1999 / 22:25:59 / cg" |
|
2523 ! |
|
2524 |
|
2525 updateCursorVisibleLine |
|
2526 "strictly private: set the visibleLine from the cursorLine. |
|
2527 notice: visibleLine will be set to nil if the cursor is not visible" |
|
2528 |
|
2529 cursorVisibleLine := self listLineToVisibleLine:cursorLine. |
|
2530 ! |
|
2531 |
|
2532 validateCursorCol:col inLine:line |
|
2533 "check of col is a valid cursor position; return a new col-nr if not. |
|
2534 Here, no limits are enforced (and col is returned), |
|
2535 but it may be redefined in EditFields or views which dont like the |
|
2536 cursor to be positioned behind the end of a textLine (vi/st-80 behavior)" |
|
2537 |
|
2538 |l max| |
|
2539 |
|
2540 "/ in ST80 mode, |
|
2541 "/ the cursor may not be positioned beyond the |
|
2542 "/ end of a line or beyond the last line of the text |
|
2543 |
|
2544 self st80EditMode ifTrue:[ |
|
2545 l := (self listAt:line). |
|
2546 max := l size + 1. |
|
2547 col > max ifTrue:[ |
|
2548 ^ max |
|
2549 ] |
|
2550 ]. |
|
2551 ^ col |
|
2552 |
|
2553 "Created: / 22.5.1996 / 14:25:30 / cg" |
|
2554 "Modified: / 20.6.1998 / 18:19:24 / cg" |
|
2555 ! |
|
2556 |
|
2557 validateCursorLine:line |
|
2558 "check of line is a valid cursor line; return a fixed line-nr if not. |
|
2559 Here, no limits are enforced (and line is returned), but it may be |
|
2560 redefined in views which dont like the cursor to be positioned |
|
2561 behind the end of the text (vi/st-80 behavior), or want to |
|
2562 skip reserved regions" |
|
2563 |
|
2564 "/ |
|
2565 "/ in st80Mode, the cursor may not be positioned |
|
2566 "/ beyond the last line |
|
2567 "/ |
|
2568 self st80EditMode ifTrue:[ |
|
2569 ^ (line min:(list size)) max:1 |
|
2570 ]. |
|
2571 ^ line |
|
2572 |
|
2573 "Created: / 22.5.1996 / 18:22:23 / cg" |
|
2574 "Modified: / 20.6.1998 / 18:19:26 / cg" |
|
2575 ! |
|
2576 |
|
2577 withCursorOffDo:aBlock |
|
2578 "evaluate aBlock with cursor off; turn it on afterwards." |
|
2579 |
|
2580 (shown not or:[cursorShown not]) ifTrue:[ |
|
2581 ^ aBlock value |
|
2582 ]. |
|
2583 self hideCursor. |
|
2584 aBlock ensure:[ |
|
2585 self showCursor |
|
2586 ] |
|
2587 ! ! |
|
2588 |
|
2589 !EditTextView methodsFor:'drag & drop'! |
|
2590 |
|
2591 allowDrop:aBoolean |
|
2592 "enable/disable drop support" |
|
2593 |
|
2594 aBoolean ifFalse:[ |
|
2595 dropTarget := nil. |
|
2596 ] ifTrue:[ |
|
2597 dropTarget isNil ifTrue:[ |
|
2598 dropTarget := DropTarget |
|
2599 receiver:self |
|
2600 argument:nil |
|
2601 dropSelector:#'drop:' |
|
2602 canDropSelector:#'canDrop:' |
|
2603 ] |
|
2604 ]. |
|
2605 ! |
|
2606 |
|
2607 canDrop:aDropContext |
|
2608 "public from d&d. |
|
2609 I accept textObjects and fileObjects only." |
|
2610 |
|
2611 "/ cg: disabled to avoid unintended drop (is same as copy-past, anyway) |
|
2612 aDropContext sourceWidget == self ifTrue:[^ false]. |
|
2613 ^ self canDropObjects:aDropContext dropObjects |
|
2614 |
|
2615 "Modified: / 13-10-2006 / 17:41:09 / cg" |
|
2616 ! |
|
2617 |
|
2618 canDropObjects:aCollectionOfDropObjects |
|
2619 "public from d&d. |
|
2620 I accept textObjects and fileObjects only." |
|
2621 |
|
2622 self checkModificationsAllowed ifFalse:[^ false]. |
|
2623 |
|
2624 aCollectionOfDropObjects isEmpty ifTrue:[ ^ false ]. |
|
2625 ^ aCollectionOfDropObjects conform:[:obj| (obj isTextObject or:[obj isFileObject])] |
|
2626 |
|
2627 "Created: / 13-10-2006 / 15:56:57 / cg" |
|
2628 "Modified: / 13-10-2006 / 17:41:14 / cg" |
|
2629 ! |
|
2630 |
|
2631 drop:aDropContext |
|
2632 "public from d&d. |
|
2633 drop objects (new API)" |
|
2634 |
|
2635 self dropObjects:(aDropContext dropObjects) |
|
2636 |
|
2637 "Modified: / 13-10-2006 / 17:41:19 / cg" |
|
2638 ! |
|
2639 |
|
2640 dropFileObject:aDropObject |
|
2641 "drop objects |
|
2642 For bw. compatibility, also collections of drop objects are handled (may vanish)" |
|
2643 |
|
2644 |answer text fn pasteWhat sensor dontAskAgainHolder enforcedDropMode app| |
|
2645 |
|
2646 pasteWhat := #name. |
|
2647 |
|
2648 fn := aDropObject asFilename. |
|
2649 (fn exists and:[fn isRegularFile]) ifTrue:[ |
|
2650 enforcedDropMode := UserPreferences current enforcedDropModeForFiles. |
|
2651 (enforcedDropMode notNil |
|
2652 and:[enforcedDropMode ~~ #name or:[fn fileSize <= (1024*1024)]]) ifTrue:[ |
|
2653 pasteWhat := enforcedDropMode. |
|
2654 ] ifFalse:[ |
|
2655 sensor := self sensor. |
|
2656 (sensor shiftDown or:[sensor ctrlDown]) ifTrue:[ |
|
2657 pasteWhat := #name. |
|
2658 ] ifFalse:[ |
|
2659 (sensor metaDown) ifTrue:[ |
|
2660 pasteWhat := #contents. |
|
2661 ] ifFalse:[ |
|
2662 dontAskAgainHolder := false asValue. |
|
2663 answer := Dialog |
|
2664 confirmWithCancel:(resources |
|
2665 stringWithCRs:'Drop the Filename (%1)\or its Contents ?\\Hint: bypass this dialog by pressing SHIFT/CTRL or ALT during the next drop.\SHIFT/CTRL to drop the name, ALT for the contents.' |
|
2666 with:fn name allBold) |
|
2667 labels:#( 'Cancel' 'Name' 'Contents' ) |
|
2668 values:#( nil #name #contents ) |
|
2669 default:#contents |
|
2670 check:(resources string:'Do not ask again; instead, always paste the contents of small files.') on:dontAskAgainHolder |
|
2671 title:(resources string:'Drop What'). |
|
2672 answer isNil ifTrue:[ ^ self ]. |
|
2673 |
|
2674 dontAskAgainHolder value ifTrue:[ |
|
2675 UserPreferences current enforcedDropModeForFiles:#contents |
|
2676 ]. |
|
2677 pasteWhat := answer. |
|
2678 ] |
|
2679 ] |
|
2680 ]. |
|
2681 ]. |
|
2682 |
|
2683 pasteWhat == #name ifTrue:[ |
|
2684 text := fn pathName |
|
2685 ] ifFalse:[ |
|
2686 self withWaitCursorDo:[ |
|
2687 text := fn contentsOfEntireFile |
|
2688 ]. |
|
2689 (app := self application) notNil ifTrue:[ |
|
2690 app droppedFile:fn in:self |
|
2691 ]. |
|
2692 ]. |
|
2693 |
|
2694 self |
|
2695 undoablePaste:text |
|
2696 info:'Drop File'. |
|
2697 |
|
2698 "Created: / 13-10-2006 / 17:38:31 / cg" |
|
2699 "Modified: / 28-07-2007 / 13:27:09 / cg" |
|
2700 ! |
|
2701 |
|
2702 dropObject:aDropObject |
|
2703 "drop objects |
|
2704 For bw. compatibility, also collections of drop objects are handled (may vanish)" |
|
2705 |
|
2706 |text| |
|
2707 |
|
2708 (aDropObject isFileObject) ifTrue:[ |
|
2709 self dropFileObject:aDropObject |
|
2710 ] ifFalse:[ |
|
2711 aDropObject isTextObject ifTrue:[ |
|
2712 text := aDropObject theObject. |
|
2713 text isStringCollection ifTrue:[ |
|
2714 text := text asStringWithoutFinalCR |
|
2715 ]. |
|
2716 ] ifFalse:[ |
|
2717 text := aDropObject theObject asString |
|
2718 ]. |
|
2719 self |
|
2720 undoablePaste:text |
|
2721 info:'Drop'. |
|
2722 ]. |
|
2723 |
|
2724 "Created: / 13-10-2006 / 17:37:05 / cg" |
|
2725 "Modified: / 28-07-2007 / 13:26:53 / cg" |
|
2726 ! |
|
2727 |
|
2728 dropObjects:aCollectionOfDropObjects |
|
2729 "public from d&d. |
|
2730 drop objects (old API)" |
|
2731 |
|
2732 aCollectionOfDropObjects do:[:el | |
|
2733 self dropObject:el |
|
2734 ]. |
|
2735 |
|
2736 "Created: / 13-10-2006 / 15:59:40 / cg" |
|
2737 "Modified: / 13-10-2006 / 17:41:23 / cg" |
|
2738 ! ! |
|
2739 |
|
2740 !EditTextView methodsFor:'editing'! |
|
2741 |
|
2742 convertSelectionToLowercaseOrUppercaseOrUppercaseFirst |
|
2743 "toLower/toUppercaseFirst/toUpper selected text" |
|
2744 |
|
2745 |line1 line2| |
|
2746 |
|
2747 line1 := self selectionStartLine. |
|
2748 line2 := self selectionEndLine. |
|
2749 line1 isNil ifTrue:[ |
|
2750 line1 := self perform:#cursorLine ifNotUnderstood:nil. |
|
2751 line1 notNil ifTrue:[ |
|
2752 line2 := line1 |
|
2753 ] |
|
2754 ]. |
|
2755 line1 notNil ifTrue:[ |
|
2756 line1 to:line2 do:[:lineNr | |
|
2757 |line col1 col2 isAllLower isLowerFirst isAllUpper isUpperFirst |
|
2758 makeLowercase makeUppercase makeUppercaseFirst makeLowercaseFirst| |
|
2759 |
|
2760 line := (self listAt:lineNr) copy. |
|
2761 line size > 0 ifTrue:[ |
|
2762 lineNr == line1 ifTrue:[ |
|
2763 col1 := selectionStartCol. |
|
2764 ] ifFalse:[ |
|
2765 col1 := 1. |
|
2766 ]. |
|
2767 lineNr == line2 ifTrue:[ |
|
2768 col2 := selectionEndCol. |
|
2769 ] ifFalse:[ |
|
2770 col2 := (self listAt:lineNr) size. |
|
2771 ]. |
|
2772 isAllLower := isAllUpper := isUpperFirst := isLowerFirst := true. |
|
2773 col1 to:col2 do:[:col | |
|
2774 |ch| |
|
2775 |
|
2776 ch := line at:col. |
|
2777 ch isUppercase ifTrue:[ |
|
2778 isAllLower := false. |
|
2779 col == col1 ifTrue:[ |
|
2780 isLowerFirst := false. |
|
2781 ]. |
|
2782 ] ifFalse:[ |
|
2783 ch isLowercase ifTrue:[ |
|
2784 isAllUpper := false. |
|
2785 col == col1 ifTrue:[ |
|
2786 isUpperFirst := false. |
|
2787 ]. |
|
2788 ] |
|
2789 ]. |
|
2790 ]. |
|
2791 |
|
2792 makeLowercase := makeUppercase := makeUppercaseFirst := makeLowercaseFirst := false. |
|
2793 isLowerFirst ifTrue:[ |
|
2794 makeUppercaseFirst := true. |
|
2795 ] ifFalse:[ |
|
2796 "/ must remember where we come from - otherwise, we end up |
|
2797 "/ in upperFirst - lowerFirst cycle. |
|
2798 "/ think about a good place to store this state |
|
2799 false "(isUpperFirst and:[isAllUpper not])" ifTrue:[ |
|
2800 makeLowercaseFirst := true. |
|
2801 ] ifFalse:[ |
|
2802 isAllUpper ifTrue:[ |
|
2803 makeLowercase := true. |
|
2804 ] ifFalse:[ |
|
2805 makeUppercase := true. |
|
2806 ] |
|
2807 ] |
|
2808 ]. |
|
2809 makeUppercaseFirst ifTrue:[ |
|
2810 line at:col1 put:(line at:col1) asUppercase. |
|
2811 ] ifFalse:[ |
|
2812 makeLowercaseFirst ifTrue:[ |
|
2813 line at:col1 put:(line at:col1) asLowercase. |
|
2814 ] ifFalse:[ |
|
2815 col1 to:col2 do:[:col | |
|
2816 |ch| |
|
2817 |
|
2818 ch := line at:col. |
|
2819 ch := makeLowercase |
|
2820 ifTrue:[ ch asLowercase ] |
|
2821 ifFalse:[ |
|
2822 makeUppercase |
|
2823 ifTrue:[ ch asUppercase ] |
|
2824 ifFalse:[ |
|
2825 col == col1 |
|
2826 ifTrue:[ ch asUppercase ] |
|
2827 ifFalse:[ ch asLowercase ] |
|
2828 ] |
|
2829 ]. |
|
2830 line at:col put:ch. |
|
2831 ]. |
|
2832 ]. |
|
2833 ]. |
|
2834 self withoutRedrawAt:lineNr put:line. |
|
2835 self invalidateLine:lineNr. |
|
2836 ]. |
|
2837 ]. |
|
2838 ] |
|
2839 |
|
2840 "Created: / 14-07-2011 / 11:40:26 / cg" |
|
2841 ! |
|
2842 |
|
2843 copyAndDeleteSelection |
|
2844 "copy the selection into the pastBuffer and delete it" |
|
2845 |
|
2846 selectionStartLine notNil ifTrue:[ |
|
2847 self setClipboardText:(self selection). |
|
2848 self deleteSelection. |
|
2849 ]. |
|
2850 |
|
2851 "Created: 27.1.1996 / 16:23:28 / cg" |
|
2852 ! |
|
2853 |
|
2854 deleteCharAtCursor |
|
2855 "delete single character under cursor; does not merge lines" |
|
2856 |
|
2857 |wasOn| |
|
2858 |
|
2859 wasOn := self hideCursor. |
|
2860 self deleteCharAtLine:cursorLine col:cursorCol. |
|
2861 wasOn ifTrue:[self showCursor] |
|
2862 ! |
|
2863 |
|
2864 deleteCharAtLine:lineNr col:colNr |
|
2865 "delete a single character at colNr in line lineNr" |
|
2866 |
|
2867 self st80EditMode ifTrue:[ |
|
2868 (self listAt:cursorLine) size + 1 = colNr ifTrue:[ |
|
2869 | wasOn | |
|
2870 wasOn := self hideCursor. |
|
2871 self |
|
2872 cursorReturn; |
|
2873 cursorCol:1; |
|
2874 deleteCharBeforeCursor. |
|
2875 wasOn ifTrue:[ self showCursor]. |
|
2876 ^ self. |
|
2877 ]. |
|
2878 ]. |
|
2879 |
|
2880 self deleteCharsAtLine:lineNr fromCol:colNr toCol:colNr |
|
2881 ! |
|
2882 |
|
2883 deleteCharBeforeCursor |
|
2884 "delete single character to the left of cursor and move cursor to left" |
|
2885 |
|
2886 |soCol wasOn lineNrAboveCursor ln originalLine prevTab| |
|
2887 |
|
2888 wasOn := self hideCursor. |
|
2889 (autoIndent and:[ (tabPositions includes:cursorCol)]) ifTrue:[ |
|
2890 prevTab := (self prevTabBefore:cursorCol) max:1. |
|
2891 ln := originalLine := (list at:cursorLine ifAbsent:'') ? ''. |
|
2892 ln size < prevTab ifTrue:[ |
|
2893 ln := ln , (String new:prevTab withAll:Character space). |
|
2894 ]. |
|
2895 (ln copyTo:prevTab) isBlank ifTrue:[ |
|
2896 (ln copyFrom:prevTab+1) isBlank ifTrue:[ |
|
2897 cursorCol > prevTab ifTrue:[ |
|
2898 self st80EditMode ifTrue:[ |
|
2899 "/ ensure that there is no conflict here: st80EditMode will |
|
2900 "/ not allow a cursor position beyond the end of line, |
|
2901 "/ so avoid that cursorLine:col: will force us to the beginning of the line |
|
2902 originalLine size < prevTab ifTrue:[ |
|
2903 self basicListAt:cursorLine put:ln |
|
2904 ] |
|
2905 ]. |
|
2906 self cursorLine:cursorLine col:prevTab. |
|
2907 wasOn ifTrue:[ self showCursor ]. |
|
2908 ^ self |
|
2909 ]. |
|
2910 ] ifFalse:[ |
|
2911 self deleteFromLine:cursorLine col:prevTab toLine:cursorLine col:cursorCol-1. |
|
2912 self cursorLine:cursorLine col:prevTab. |
|
2913 wasOn ifTrue:[ self showCursor ]. |
|
2914 ^ self. |
|
2915 ] |
|
2916 ]. |
|
2917 ]. |
|
2918 |
|
2919 "/ (autoIndent |
|
2920 "/ and:[cursorCol ~~ 1 |
|
2921 "/ and:[cursorLine <= (list size)]]) |
|
2922 "/ ifTrue:[ |
|
2923 "/ soCol := (self leftIndentForLine:cursorLine) + 1. |
|
2924 "/ |
|
2925 "/ (cursorCol == soCol and:[soCol > 1]) ifTrue:[ |
|
2926 "/ ln := list at:cursorLine. |
|
2927 "/ (ln notNil and:[(ln indexOfNonSeparatorStartingAt:1) < soCol]) ifTrue:[ |
|
2928 "/ soCol := 1 |
|
2929 "/ ] |
|
2930 "/ ] |
|
2931 "/ ] ifFalse:[ |
|
2932 soCol := 1. |
|
2933 "/ ]. |
|
2934 |
|
2935 (cursorCol ~~ soCol and:[cursorCol ~~ 1]) ifTrue:[ |
|
2936 " |
|
2937 somewhere in the middle of a line |
|
2938 " |
|
2939 self cursorLeft. |
|
2940 self deleteCharAtLine:cursorLine col:cursorCol. |
|
2941 ] ifFalse:[ |
|
2942 " |
|
2943 at begin of line - merge with previous line; |
|
2944 except for the very first line. |
|
2945 " |
|
2946 (cursorLine == 1) ifFalse:[ |
|
2947 lineNrAboveCursor := self validateCursorLine:(cursorLine - 1). |
|
2948 lineNrAboveCursor < cursorLine ifTrue:[ |
|
2949 (lineNrAboveCursor > 0 and:[lineNrAboveCursor > list size]) ifTrue:[ |
|
2950 "/ we are beyond the end of the text. |
|
2951 "/ move the cursor to the previous line. |
|
2952 self cursorLine:lineNrAboveCursor col:1. |
|
2953 ] ifFalse:[ |
|
2954 self mergeLine:lineNrAboveCursor removeBlanks:false. |
|
2955 ] |
|
2956 ] |
|
2957 ] |
|
2958 ]. |
|
2959 wasOn ifTrue:[ self showCursor ] |
|
2960 |
|
2961 "Modified: / 16.1.1998 / 22:33:04 / cg" |
|
2962 ! |
|
2963 |
|
2964 deleteCharsAtLine:lineNr fromCol:colNr |
|
2965 "delete characters from colNr up to the end in line lineNr" |
|
2966 |
|
2967 |line| |
|
2968 |
|
2969 (line := self listAt:lineNr) notNil ifTrue:[ |
|
2970 self deleteCharsAtLine:lineNr fromCol:colNr toCol:(line size) |
|
2971 ] |
|
2972 |
|
2973 ! |
|
2974 |
|
2975 deleteCharsAtLine:lineNr fromCol:startCol toCol:endCol |
|
2976 "delete characters from startCol to endCol in line lineNr" |
|
2977 |
|
2978 |deleted| |
|
2979 |
|
2980 deleted := self textFromLine:lineNr col:startCol toLine:lineNr col:endCol. |
|
2981 self basicDeleteCharsAtLine:lineNr fromCol:startCol toCol:endCol. |
|
2982 self addUndo:(PasteString line:lineNr col:startCol string:deleted info:'delete'). |
|
2983 ! |
|
2984 |
|
2985 deleteCharsAtLine:lineNr toCol:colNr |
|
2986 "delete characters from start up to colNr in line lineNr" |
|
2987 |
|
2988 self deleteCharsAtLine:lineNr fromCol:1 toCol:colNr |
|
2989 |
|
2990 |
|
2991 ! |
|
2992 |
|
2993 deleteCursorLine |
|
2994 "delete the line where the cursor sits" |
|
2995 |
|
2996 self deleteLine:cursorLine |
|
2997 ! |
|
2998 |
|
2999 deleteFromCharacterPosition:charPos1 to:charPos2 |
|
3000 "delete a substring at a character position" |
|
3001 |
|
3002 |line1 col1 line2 col2| |
|
3003 |
|
3004 line1 := self lineOfCharacterPosition:charPos1. |
|
3005 col1 := charPos1 - (self characterPositionOfLine:line1 col:1) + 1. |
|
3006 col1 == 0 ifTrue:[ |
|
3007 line1 := line1 - 1. |
|
3008 col1 := (self listAt:line1) size + 1. |
|
3009 ]. |
|
3010 |
|
3011 line2 := self lineOfCharacterPosition:charPos2. |
|
3012 col2 := charPos2 - (self characterPositionOfLine:line2 col:1) + 1. |
|
3013 |
|
3014 self deleteFromLine:line1 col:col1 toLine:line2 col:col2. |
|
3015 ! |
|
3016 |
|
3017 deleteFromLine:startLine col:startCol toLine:endLine col:endCol |
|
3018 "delete all text from startLine/startCol to endLine/endCol - |
|
3019 joining lines if nescessary" |
|
3020 |
|
3021 |line newLine lineSize nMore| |
|
3022 |
|
3023 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
3024 list isNil ifTrue:[^ self]. |
|
3025 startLine > list size ifTrue:[ ^ self]. "/ deleted space below text |
|
3026 |
|
3027 (startLine == endLine) ifTrue:[ |
|
3028 "/ delete chars within a line |
|
3029 self deleteCharsAtLine:startLine fromCol:startCol toCol:endCol. |
|
3030 ^ self |
|
3031 ]. |
|
3032 |
|
3033 ((startCol == 1) and:[endCol == 0]) ifTrue:[ |
|
3034 "/ delete full lines only |
|
3035 endLine > startLine ifTrue:[ |
|
3036 self deleteFromLine:startLine toLine:(endLine - 1) |
|
3037 ]. |
|
3038 ^ self |
|
3039 ]. |
|
3040 |
|
3041 "/ delete right rest of 1st line |
|
3042 self deleteCharsAtLine:startLine fromCol:(startCol max:1). |
|
3043 |
|
3044 "/ delete the inner lines ... |
|
3045 endLine > (startLine + 1) ifTrue:[ |
|
3046 self deleteFromLine:(startLine + 1) toLine:(endLine - 1) |
|
3047 ]. |
|
3048 |
|
3049 (endCol ~~ 0) ifTrue:[ |
|
3050 "/ delete the left rest of the last line |
|
3051 |
|
3052 self deleteCharsAtLine:(startLine + 1) toCol:endCol. |
|
3053 |
|
3054 "/ must add blanks, if startCol lies beyond end of startLine |
|
3055 startLine <= list size ifTrue:[ |
|
3056 line := list at:startLine. |
|
3057 lineSize := line size. |
|
3058 (startCol > lineSize) ifTrue:[ |
|
3059 newLine := line. |
|
3060 line isNil ifTrue:[ |
|
3061 newLine := String new:(startCol - 1) |
|
3062 ] ifFalse:[ |
|
3063 nMore := startCol - 1 - lineSize. |
|
3064 nMore > 0 ifTrue:[ |
|
3065 newLine := line , (line species new:nMore) |
|
3066 ] |
|
3067 ]. |
|
3068 newLine ~~ line ifTrue:[ |
|
3069 self basicListAt:startLine put:newLine. |
|
3070 ]. |
|
3071 "/ TODO: remember old maxwidth of linerange, |
|
3072 "/ only clear widthOfWidestLine, if this max |
|
3073 "/ length was (one of) the longest. |
|
3074 "/ avoids slow delete with huge texts. |
|
3075 widthOfWidestLine := nil. "/ i.e. unknown |
|
3076 self textChanged. |
|
3077 ] |
|
3078 ] |
|
3079 ]. |
|
3080 |
|
3081 "/ merge the left rest of 1st line with right rest of last line into one |
|
3082 self mergeLine:startLine removeBlanks:false |
|
3083 |
|
3084 "Modified: / 10-11-1998 / 23:52:59 / cg" |
|
3085 "Modified: / 18-03-2011 / 18:25:01 / az" |
|
3086 ! |
|
3087 |
|
3088 deleteFromLine:startLineNr toLine:endLineNr |
|
3089 "delete some lines" |
|
3090 |
|
3091 |deleted| |
|
3092 |
|
3093 deleted := self textFromLine:startLineNr col:1 toLine:endLineNr+1 col:0. |
|
3094 self basicDeleteFromLine:startLineNr toLine:endLineNr. |
|
3095 self addUndo:(PasteString line:startLineNr col:1 string:deleted info:'delete'). |
|
3096 ! |
|
3097 |
|
3098 deleteLine:lineNr |
|
3099 "delete line" |
|
3100 |
|
3101 self deleteFromLine:lineNr toLine:lineNr |
|
3102 |
|
3103 |
|
3104 ! |
|
3105 |
|
3106 deleteLineWithoutRedraw:lineNr |
|
3107 "delete line - no redraw; |
|
3108 return true, if something was really deleted" |
|
3109 |
|
3110 |deleted ret| |
|
3111 |
|
3112 deleted := self textFromLine:lineNr col:1 toLine:lineNr+1 col:0. |
|
3113 ret := self basicDeleteLineWithoutRedraw:lineNr. |
|
3114 self addUndo:(PasteString line:lineNr col:1 string:deleted info:'delete'). |
|
3115 ^ ret. |
|
3116 ! |
|
3117 |
|
3118 deleteLinesWithoutRedrawFrom:startLine to:endLine |
|
3119 "delete lines - no redraw; |
|
3120 return true, if something was really deleted" |
|
3121 |
|
3122 |lastLine| |
|
3123 |
|
3124 self checkModificationsAllowed ifFalse:[^ false]. |
|
3125 |
|
3126 (list isNil or:[startLine > list size]) ifTrue:[^ false]. |
|
3127 (endLine > list size) ifTrue:[ |
|
3128 lastLine := list size |
|
3129 ] ifFalse:[ |
|
3130 lastLine := endLine |
|
3131 ]. |
|
3132 self basicListRemoveFromIndex:startLine toIndex:lastLine. |
|
3133 "/ TODO: remember old maxwidth of linerange, |
|
3134 "/ only clear widthOfWidestLine, if this max |
|
3135 "/ length was (one of) the longest. |
|
3136 "/ avoids slow delete with huge texts. |
|
3137 widthOfWidestLine := nil. "/ i.e. unknown |
|
3138 self textChanged. |
|
3139 ^ true |
|
3140 |
|
3141 "Modified: / 10.11.1998 / 23:55:29 / cg" |
|
3142 ! |
|
3143 |
|
3144 deleteSelection |
|
3145 "delete the selection" |
|
3146 |
|
3147 |wasOn startLine startCol endLine endCol| |
|
3148 |
|
3149 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
3150 |
|
3151 selectionStartLine notNil ifTrue:[ |
|
3152 wasOn := self hideCursor. |
|
3153 |
|
3154 startLine := selectionStartLine. |
|
3155 startCol := selectionStartCol. |
|
3156 endLine := selectionEndLine. |
|
3157 endCol := selectionEndCol. |
|
3158 self unselectWithoutRedraw. |
|
3159 self deleteFromLine:startLine col:startCol toLine:endLine col:endCol. |
|
3160 self setCursorLine:startLine col:startCol. |
|
3161 |
|
3162 self makeCursorVisibleAndShowCursor:wasOn |
|
3163 ] |
|
3164 ! |
|
3165 |
|
3166 deleteWordBeforeCursor |
|
3167 "delete the word to the left of cursor and move cursor to left" |
|
3168 |
|
3169 |wasOn beginCol beginLine endCol endLine| |
|
3170 |
|
3171 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
3172 |
|
3173 wasOn := self hideCursor. |
|
3174 self |
|
3175 undoableDo:[ |
|
3176 endCol := cursorCol-1. |
|
3177 endLine := cursorLine. |
|
3178 self cursorToPreviousWord. |
|
3179 beginCol := cursorCol. |
|
3180 beginLine := cursorLine. |
|
3181 self deleteFromLine:beginLine col:beginCol toLine:endLine col:endCol. |
|
3182 ] |
|
3183 info:'Delete Word'. |
|
3184 wasOn ifTrue:[ self showCursor ]. |
|
3185 |
|
3186 "Modified: / 22.2.2000 / 23:59:04 / cg" |
|
3187 ! |
|
3188 |
|
3189 insert:aCharacter atLine:lineNr col:colNr |
|
3190 "insert a single character at lineNr/colNr; |
|
3191 set emphasis to character at current position" |
|
3192 |
|
3193 self basicInsert:aCharacter atLine:lineNr col:colNr. |
|
3194 aCharacter ~~ Character cr ifTrue:[ |
|
3195 self addUndo:(DeleteCharacters line:lineNr col:colNr info:'insert'). |
|
3196 ] |
|
3197 ! |
|
3198 |
|
3199 insertCharAtCursor:aCharacter |
|
3200 "insert a single character at cursor-position - advance cursor." |
|
3201 |
|
3202 |wasOn| |
|
3203 |
|
3204 wasOn := self hideCursor. |
|
3205 aCharacter == Character tab ifTrue:[ |
|
3206 "/ needs special care to advance cursor correctly |
|
3207 self insertTabAtCursor |
|
3208 ] ifFalse:[ |
|
3209 self insert:aCharacter atLine:cursorLine col:cursorCol. |
|
3210 aCharacter == (Character cr) ifTrue:[ |
|
3211 self basicCursorReturn |
|
3212 ] ifFalse:[ |
|
3213 self cursorRight. |
|
3214 ]. |
|
3215 ]. |
|
3216 self makeCursorVisibleAndShowCursor:wasOn. |
|
3217 |
|
3218 "Modified: / 12.6.1998 / 21:50:20 / cg" |
|
3219 ! |
|
3220 |
|
3221 insertLine:aString before:lineNr |
|
3222 "insert the line aString before line lineNr" |
|
3223 |
|
3224 ^ self insertLines:(Array with:aString) from:1 to:1 before:lineNr. |
|
3225 |
|
3226 "Modified: 14.5.1996 / 13:42:54 / cg" |
|
3227 ! |
|
3228 |
|
3229 insertLines:aStringCollection before:lineNr |
|
3230 "insert a bunch before line lineNr" |
|
3231 |
|
3232 self insertLines:aStringCollection from:1 to:aStringCollection size before:lineNr |
|
3233 |
|
3234 "Modified: 6.9.1995 / 20:51:03 / claus" |
|
3235 ! |
|
3236 |
|
3237 insertLines:someText from:start to:end before:lineNr |
|
3238 "insert a bunch of lines before line lineNr. |
|
3239 The cursor position is left unchanged." |
|
3240 |
|
3241 |text indent visLine w nLines "{ Class: SmallInteger }" |
|
3242 srcY "{ Class: SmallInteger }" |
|
3243 dstY "{ Class: SmallInteger }" | |
|
3244 |
|
3245 autoIndent ifTrue:[ |
|
3246 indent := self leftIndentForLine:lineNr. |
|
3247 |
|
3248 text := someText |
|
3249 collect:[:ln||line| |
|
3250 ln notNil ifTrue:[ |
|
3251 line := ln withoutLeadingSeparators. |
|
3252 (line isEmpty or:[indent == 0]) ifFalse:[ |
|
3253 line := (String new:indent), line |
|
3254 ]. |
|
3255 line |
|
3256 ] ifFalse:[ |
|
3257 nil |
|
3258 ] |
|
3259 ]. |
|
3260 ] ifFalse:[ |
|
3261 text := someText |
|
3262 ]. |
|
3263 |
|
3264 visLine := self listLineToVisibleLine:lineNr. |
|
3265 (shown not or:[visLine isNil]) ifTrue:[ |
|
3266 self withoutRedrawInsertLines:text |
|
3267 from:start to:end |
|
3268 before:lineNr. |
|
3269 ] ifFalse:[ |
|
3270 nLines := end - start + 1. |
|
3271 ((visLine + nLines) >= nLinesShown) ifTrue:[ |
|
3272 self withoutRedrawInsertLines:text |
|
3273 from:start to:end |
|
3274 before:lineNr. |
|
3275 self redrawFromVisibleLine:visLine to:nLinesShown |
|
3276 ] ifFalse:[ |
|
3277 w := self widthForScrollBetween:(lineNr + nLines) |
|
3278 and:(firstLineShown + nLines + nLinesShown). |
|
3279 srcY := topMargin + ((visLine - 1) * fontHeight). |
|
3280 dstY := srcY + (nLines * fontHeight). |
|
3281 |
|
3282 "/ |
|
3283 "/ scroll ... |
|
3284 "/ |
|
3285 " |
|
3286 stupid: must catchExpose before inserting new |
|
3287 stuff - since catchExpose may perform redraws |
|
3288 " |
|
3289 self catchExpose. |
|
3290 self withoutRedrawInsertLines:text |
|
3291 from:start to:end |
|
3292 before:lineNr. |
|
3293 self |
|
3294 copyFrom:self |
|
3295 x:textStartLeft y:srcY |
|
3296 toX:textStartLeft y:dstY |
|
3297 width:w |
|
3298 height:(height - dstY) |
|
3299 async:true. |
|
3300 self redrawFromVisibleLine:visLine to:(visLine + nLines - 1). |
|
3301 self waitForExpose |
|
3302 ]. |
|
3303 ]. |
|
3304 widthOfWidestLine notNil ifTrue:[ |
|
3305 text do:[:line | |
|
3306 widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line). |
|
3307 ] |
|
3308 ]. |
|
3309 self textChanged. |
|
3310 |
|
3311 "Modified: 29.1.1997 / 13:02:39 / cg" |
|
3312 ! |
|
3313 |
|
3314 insertLines:lines withCR:withCr |
|
3315 "insert a bunch of lines at cursor position. |
|
3316 Cursor is moved behind insertion. |
|
3317 If withCr is true, append cr after last line" |
|
3318 |
|
3319 |start end nLines wasOn| |
|
3320 |
|
3321 lines notNil ifTrue:[ |
|
3322 nLines := lines size. |
|
3323 (nLines == 1) ifTrue:[ |
|
3324 self insertStringAtCursor:(lines at:1). |
|
3325 withCr ifTrue:[ |
|
3326 self insertCharAtCursor:(Character cr) |
|
3327 ] |
|
3328 ] ifFalse:[ |
|
3329 (cursorCol ~~ 1) ifTrue:[ |
|
3330 self insertStringAtCursor:(lines at:1). |
|
3331 self insertCharAtCursor:(Character cr). |
|
3332 start := 2 |
|
3333 ] ifFalse:[ |
|
3334 start := 1 |
|
3335 ]. |
|
3336 withCr ifTrue:[ |
|
3337 end := nLines |
|
3338 ] ifFalse:[ |
|
3339 end := nLines - 1 |
|
3340 ]. |
|
3341 (start <= nLines) ifTrue:[ |
|
3342 (end >= start) ifTrue:[ |
|
3343 wasOn := self hideCursor. |
|
3344 self insertLines:lines from:start to:end before:cursorLine. |
|
3345 self setCursorLine:(cursorLine + (end - start + 1)). |
|
3346 wasOn ifTrue:[self showCursor]. |
|
3347 ] |
|
3348 ]. |
|
3349 withCr ifFalse:[ |
|
3350 "last line without cr" |
|
3351 self insertStringAtCursor:(lines at:nLines) |
|
3352 ] |
|
3353 ] |
|
3354 ] |
|
3355 |
|
3356 "Created: / 18.5.1996 / 15:32:06 / cg" |
|
3357 "Modified: / 12.6.1998 / 21:51:16 / cg" |
|
3358 ! |
|
3359 |
|
3360 insertLines:lines withCr:withCr |
|
3361 "insert a bunch of lines at cursor position. Cursor |
|
3362 is moved behind insertion. |
|
3363 If withCr is true, append cr after last line" |
|
3364 |
|
3365 <resource:#obsolete> |
|
3366 |
|
3367 self obsoleteMethodWarning:'use #insertLines:withCR:'. |
|
3368 self insertLines:lines withCR:withCr. |
|
3369 |
|
3370 "Modified: 31.7.1997 / 23:07:22 / cg" |
|
3371 ! |
|
3372 |
|
3373 insertSelectedStringAtCursor:aString |
|
3374 "insert the argument, aString at cursor position and select it" |
|
3375 |
|
3376 |startLine startCol| |
|
3377 |
|
3378 startLine := cursorLine. |
|
3379 startCol := cursorCol. |
|
3380 self insertStringAtCursor:aString. |
|
3381 self selectFromLine:startLine col:startCol |
|
3382 toLine:cursorLine col:(cursorCol - 1). |
|
3383 self makeSelectionVisible. |
|
3384 ! |
|
3385 |
|
3386 insertString:aString atCharacterPosition:charPos |
|
3387 "insert the argument, aString at a character position" |
|
3388 |
|
3389 |line col| |
|
3390 |
|
3391 line := self lineOfCharacterPosition:charPos. |
|
3392 col := charPos - (self characterPositionOfLine:line col:1) + 1. |
|
3393 self insertString:aString atLine:line col:col |
|
3394 ! |
|
3395 |
|
3396 insertString:aString atLine:lineNr col:colNr |
|
3397 "insert the string, aString at line/col; |
|
3398 handle cr's correctly" |
|
3399 |
|
3400 |start "{ Class: SmallInteger }" |
|
3401 stop "{ Class: SmallInteger }" |
|
3402 end "{ Class: SmallInteger }" |
|
3403 subString c |
|
3404 l "{ Class: SmallInteger }" | |
|
3405 |
|
3406 aString isNil ifTrue:[^ self]. |
|
3407 (aString includes:(Character cr)) ifFalse:[ |
|
3408 ^ self insertStringWithoutCRs:aString atLine:lineNr col:colNr |
|
3409 ]. |
|
3410 |
|
3411 l := lineNr. |
|
3412 c := colNr. |
|
3413 start := 1. |
|
3414 end := aString size. |
|
3415 [start <= end] whileTrue:[ |
|
3416 stop := aString indexOf:(Character cr) startingAt:start. |
|
3417 stop == 0 ifTrue:[ |
|
3418 stop := end + 1 |
|
3419 ]. |
|
3420 subString := aString copyFrom:start to:(stop - 1). |
|
3421 self insertStringWithoutCRs:subString atLine:l col:c. |
|
3422 (stop <= end) ifTrue:[ |
|
3423 c := c + subString size. |
|
3424 self insert:(Character cr) atLine:l col:c. |
|
3425 l := l + 1. |
|
3426 c := 1 |
|
3427 ]. |
|
3428 start := stop + 1 |
|
3429 ] |
|
3430 |
|
3431 "Modified: / 10.6.1998 / 19:03:59 / cg" |
|
3432 ! |
|
3433 |
|
3434 insertStringAtCursor:aString |
|
3435 "insert the argument, aString at cursor position |
|
3436 handle cr's correctly. A nil argument is interpreted as an empty line." |
|
3437 |
|
3438 aString isNil ifTrue:[ |
|
3439 "new:" |
|
3440 self insertCharAtCursor:(Character cr). |
|
3441 ^ self |
|
3442 ]. |
|
3443 (aString includes:(Character cr)) ifFalse:[ |
|
3444 ^ self insertStringWithoutCRsAtCursor:aString |
|
3445 ]. |
|
3446 |
|
3447 self insertLines:aString asStringCollection withCR:false. |
|
3448 |
|
3449 "Modified: / 10.6.1998 / 19:03:21 / cg" |
|
3450 ! |
|
3451 |
|
3452 insertStringWithoutCRs:aString atLine:lineNr col:colNr |
|
3453 "insert aString (which has no crs) at lineNr/colNr" |
|
3454 |
|
3455 self withoutRedrawInsertStringWithoutCRs:aString atLine:lineNr col:colNr. |
|
3456 shown ifTrue:[ |
|
3457 gc font hasOverlappingCharacters ifTrue:[ |
|
3458 self invalidateLine:lineNr. |
|
3459 ] ifFalse:[ |
|
3460 self redrawLine:lineNr from:colNr |
|
3461 ] |
|
3462 ] |
|
3463 |
|
3464 "Modified: / 09-11-2010 / 13:43:03 / cg" |
|
3465 ! |
|
3466 |
|
3467 insertStringWithoutCRsAtCursor:aString |
|
3468 "insert a string (which has no crs) at cursor position |
|
3469 - advance cursor" |
|
3470 |
|
3471 |wasOn oldLen newLen deltaLen| |
|
3472 |
|
3473 aString size > 0 ifTrue:[ |
|
3474 wasOn := self hideCursor. |
|
3475 (aString includes:Character tab) ifTrue:[ |
|
3476 self checkForExistingLine:cursorLine. |
|
3477 oldLen := (list at:cursorLine) size. |
|
3478 self insertString:aString atLine:cursorLine col:cursorCol. |
|
3479 newLen := (list at:cursorLine) size. |
|
3480 deltaLen := newLen - oldLen. |
|
3481 ] ifFalse:[ |
|
3482 self insertString:aString atLine:(cursorLine ? 1) col:cursorCol. |
|
3483 deltaLen := aString size. |
|
3484 ]. |
|
3485 self setCursorCol:(cursorCol + deltaLen). |
|
3486 wasOn ifTrue:[self showCursor] |
|
3487 ] |
|
3488 |
|
3489 "Modified: / 10.6.1998 / 20:43:52 / cg" |
|
3490 ! |
|
3491 |
|
3492 insertTabAtCursor |
|
3493 "insert spaces to next tab" |
|
3494 |
|
3495 |wasOn nextTab| |
|
3496 |
|
3497 wasOn := self hideCursor. |
|
3498 nextTab := self nextTabAfter:cursorCol. |
|
3499 self insertStringAtCursor:(String new:(nextTab - cursorCol)). |
|
3500 self makeCursorVisibleAndShowCursor:wasOn. |
|
3501 ! |
|
3502 |
|
3503 joinLines |
|
3504 "join lines (remove line-break)" |
|
3505 |
|
3506 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
3507 |
|
3508 self |
|
3509 undoableDo:[ |
|
3510 |line col lineLen| |
|
3511 |
|
3512 line := cursorLine. |
|
3513 col := cursorCol. |
|
3514 lineLen := (list at:line) size. |
|
3515 col > lineLen ifTrue:[ |
|
3516 self insertString:(String new:col-lineLen) atLine:line col:col+1. |
|
3517 ] ifFalse:[ |
|
3518 self deleteCharsAtLine:line fromCol:col toCol:lineLen. |
|
3519 ]. |
|
3520 self mergeLine:line removeBlanks:true. |
|
3521 self cursorLine:line col:col. |
|
3522 ] |
|
3523 info:'Join' |
|
3524 ! |
|
3525 |
|
3526 mergeLine:lineNr |
|
3527 "merge line lineNr with line lineNr+1" |
|
3528 |
|
3529 self mergeLine:lineNr removeBlanks:true |
|
3530 |
|
3531 "Modified: 9.9.1997 / 09:28:03 / cg" |
|
3532 ! |
|
3533 |
|
3534 mergeLine:lineNr removeBlanks:removeBlanks |
|
3535 "merge line lineNr with line lineNr+1" |
|
3536 |
|
3537 |len| |
|
3538 |
|
3539 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
3540 |
|
3541 len := (self listAt:lineNr) size. |
|
3542 self nonUndoableDo:[ |
|
3543 self basicMergeLine:lineNr removeBlanks:removeBlanks. |
|
3544 ]. |
|
3545 self addUndo:(PasteString new line:lineNr col:len+1 string:(Character cr asString) selected:false). |
|
3546 ! |
|
3547 |
|
3548 parenthizeSelectionWith:openingCharacter and:closingCharacter |
|
3549 |newSelectionEnd| |
|
3550 |
|
3551 self hasSelection ifFalse:[^ self]. |
|
3552 |
|
3553 newSelectionEnd := selectionEndCol. |
|
3554 |
|
3555 (self characterAtLine:selectionStartLine col:selectionStartCol) == openingCharacter ifTrue:[ |
|
3556 (self characterAtLine:selectionEndLine col:selectionEndCol) == closingCharacter ifTrue:[ |
|
3557 self deleteCharAtLine:selectionEndLine col:selectionEndCol. |
|
3558 newSelectionEnd := newSelectionEnd-1. |
|
3559 ]. |
|
3560 self deleteCharAtLine:selectionStartLine col:selectionStartCol. |
|
3561 selectionStartLine == selectionEndLine ifTrue:[ |
|
3562 newSelectionEnd := newSelectionEnd-1. |
|
3563 ] |
|
3564 ] ifFalse:[ |
|
3565 self insert:closingCharacter atLine:selectionEndLine col:selectionEndCol+1. |
|
3566 newSelectionEnd := newSelectionEnd+1. |
|
3567 self insert:openingCharacter atLine:selectionStartLine col:selectionStartCol. |
|
3568 selectionStartLine == selectionEndLine ifTrue:[ |
|
3569 newSelectionEnd := newSelectionEnd+1. |
|
3570 ] |
|
3571 ]. |
|
3572 self |
|
3573 selectFromLine:selectionStartLine col:selectionStartCol |
|
3574 toLine:selectionEndLine col:newSelectionEnd. |
|
3575 ! |
|
3576 |
|
3577 removeTrailingBlankLines |
|
3578 "remove all blank lines at end of text" |
|
3579 |
|
3580 |lastLine "{ Class: SmallInteger }" |
|
3581 line finished| |
|
3582 |
|
3583 lastLine := list size. |
|
3584 finished := false. |
|
3585 [finished] whileFalse:[ |
|
3586 (lastLine <= 1) ifTrue:[ |
|
3587 finished := true |
|
3588 ] ifFalse:[ |
|
3589 line := list at:lastLine. |
|
3590 line notNil ifTrue:[ |
|
3591 line isBlank ifTrue:[ |
|
3592 self basicListAt:lastLine put:nil. |
|
3593 line := nil |
|
3594 ] |
|
3595 ]. |
|
3596 line notNil ifTrue:[ |
|
3597 finished := true |
|
3598 ] ifFalse:[ |
|
3599 lastLine := lastLine - 1 |
|
3600 ] |
|
3601 ] |
|
3602 ]. |
|
3603 (lastLine ~~ list size) ifTrue:[ |
|
3604 list grow:lastLine. |
|
3605 "/ self textChanged |
|
3606 ] |
|
3607 ! |
|
3608 |
|
3609 replace:aCharacter atLine:lineNr col:colNr |
|
3610 "replace a single character at lineNr/colNr" |
|
3611 |
|
3612 |originalChar| |
|
3613 |
|
3614 originalChar := self characterAtLine:lineNr col:colNr. |
|
3615 self basicReplace:aCharacter atLine:lineNr col:colNr. |
|
3616 self addUndo:(ReplaceCharacters line:lineNr col:colNr character:originalChar info:'replace'). |
|
3617 ! |
|
3618 |
|
3619 replace:patternArg by:replacePatternArg all:all ignoreCase:ignoreCase |
|
3620 |pattern replacePattern| |
|
3621 |
|
3622 pattern := patternArg string. |
|
3623 replacePattern := replacePatternArg string. |
|
3624 (pattern notEmpty and:[ replacePattern notEmpty ]) ifTrue:[ |
|
3625 self rememberSearchPattern:pattern. |
|
3626 self rememberSearchPattern:replacePattern. |
|
3627 LastSearchIgnoredCase := ignoreCase. |
|
3628 self |
|
3629 undoableDo:[ |
|
3630 all ifTrue:[ |
|
3631 self |
|
3632 replaceString:pattern |
|
3633 to:replacePattern |
|
3634 ignoreCase:ignoreCase |
|
3635 ] ifFalse:[ |
|
3636 (self selectionAsString notNil |
|
3637 and:[ self selectionAsString sameAs:pattern caseSensitive:ignoreCase not ]) |
|
3638 ifTrue:[ |
|
3639 self replaceSelectionBy:replacePattern. |
|
3640 self |
|
3641 search:pattern |
|
3642 ignoreCase:ignoreCase |
|
3643 forward:(lastSearchDirection = #forward). |
|
3644 ]. |
|
3645 ] |
|
3646 ] |
|
3647 info:'Replace' |
|
3648 ] |
|
3649 |
|
3650 "Created: / 11-07-2006 / 11:19:57 / fm" |
|
3651 ! |
|
3652 |
|
3653 replaceCharAtCursor:aCharacter |
|
3654 "replace a single character at cursor-position - advance cursor" |
|
3655 |
|
3656 |wasOn| |
|
3657 |
|
3658 wasOn := self hideCursor. |
|
3659 aCharacter == (Character cr) ifTrue:[ |
|
3660 self cursorReturn |
|
3661 ] ifFalse:[ |
|
3662 self replace:aCharacter atLine:cursorLine col:cursorCol. |
|
3663 self cursorRight. |
|
3664 ]. |
|
3665 self makeCursorVisibleAndShowCursor:wasOn. |
|
3666 |
|
3667 "Created: 6.3.1996 / 12:27:42 / cg" |
|
3668 ! |
|
3669 |
|
3670 replaceContentsWith:newContents |
|
3671 "replace everything" |
|
3672 |
|
3673 |originalContents| |
|
3674 |
|
3675 originalContents := self contents. |
|
3676 self contents:newContents keepUndoHistory:true. |
|
3677 self addUndo:(ReplaceContents text:originalContents info:'replace'). |
|
3678 ! |
|
3679 |
|
3680 replaceFromCharacterPosition:charPos1 to:charPos2 with:newString |
|
3681 "replace a substring at a character position" |
|
3682 |
|
3683 "/ sigh - insert first, to avoid troible due to shifing-in virtual line ends |
|
3684 self insertString:newString atCharacterPosition:charPos1. |
|
3685 self deleteFromCharacterPosition:charPos1+newString size to:charPos2+newString size. |
|
3686 ! |
|
3687 |
|
3688 replaceLine:lineNr with:newText |
|
3689 "replace a line at lineNr" |
|
3690 |
|
3691 |originalLine| |
|
3692 |
|
3693 originalLine := self listAt:lineNr. |
|
3694 originalLine isNil ifTrue:[ |
|
3695 self checkForExistingLine:lineNr |
|
3696 ]. |
|
3697 self list at:lineNr put:newText. |
|
3698 self addUndo:(ReplaceLine line:lineNr string:originalLine info:'replace'). |
|
3699 self invalidateLine:lineNr. |
|
3700 |
|
3701 "Modified: / 12-04-2007 / 09:31:33 / cg" |
|
3702 ! |
|
3703 |
|
3704 replaceLines:lines withCR:withCr |
|
3705 "replace a bunch of lines at cursor position. Cursor |
|
3706 is moved behind replacement. |
|
3707 If withCr is true, move to the beginning of the next line |
|
3708 after the last line" |
|
3709 |
|
3710 |line col nLines wasOn| |
|
3711 |
|
3712 lines notNil ifTrue:[ |
|
3713 wasOn := self hideCursor. |
|
3714 nLines := lines size. |
|
3715 line := cursorLine. |
|
3716 col := cursorCol. |
|
3717 lines keysAndValuesDo:[:i :l | |
|
3718 self replaceString:(l ? '') atLine:line col:col. |
|
3719 (i ~~ nLines or:[withCr]) ifTrue:[ |
|
3720 line := line + 1. |
|
3721 col := 1. |
|
3722 ] ifFalse:[ |
|
3723 col := col + (l size). |
|
3724 ] |
|
3725 ]. |
|
3726 self cursorLine:line col:col. |
|
3727 self makeCursorVisibleAndShowCursor:wasOn. |
|
3728 "/ wasOn ifTrue:[self showCursor]. |
|
3729 ] |
|
3730 |
|
3731 "Created: / 18-05-1996 / 15:32:06 / cg" |
|
3732 "Modified: / 25-07-2013 / 17:00:53 / cg" |
|
3733 ! |
|
3734 |
|
3735 replaceSelectionBy:something |
|
3736 "delete the selection (if any) and insert something, a character or string; |
|
3737 leave cursor after insertion" |
|
3738 |
|
3739 self replaceSelectionBy:something keepCursor:false select:false |
|
3740 ! |
|
3741 |
|
3742 replaceSelectionBy:something keepCursor:keep |
|
3743 "delete the selection (if any) and insert something, a character or string; |
|
3744 leave cursor after insertion or leave it, depending on keep" |
|
3745 |
|
3746 self replaceSelectionBy:something keepCursor:keep select:false |
|
3747 |
|
3748 "Modified: 9.10.1996 / 16:14:35 / cg" |
|
3749 ! |
|
3750 |
|
3751 replaceSelectionBy:something keepCursor:keep select:selectNewText |
|
3752 "delete the selection (if any) and insert something, a character or string; |
|
3753 leave cursor after insertion or leave it, depending on keep. |
|
3754 If selectNewText is true, select the new text; otherwise deselect" |
|
3755 |
|
3756 |sel l c selStartLine selStartCol| |
|
3757 |
|
3758 l := cursorLine. |
|
3759 c := cursorCol. |
|
3760 |
|
3761 sel := self selectionAsString. |
|
3762 sel isNil ifTrue:[ |
|
3763 selStartLine := l. |
|
3764 selStartCol := c. |
|
3765 ] ifFalse:[ |
|
3766 selStartLine := selectionStartLine. |
|
3767 selStartCol := selectionStartCol. |
|
3768 |
|
3769 self setLastStringToReplace: sel. |
|
3770 |
|
3771 self deleteSelection. |
|
3772 replacing := true. |
|
3773 lastReplacementInfo rememberReplacement. |
|
3774 lastReplacementInfo lastReplacement: ''. |
|
3775 lastReplacementInfo stillCollectingInput:true. |
|
3776 undoSupport actionInfo:'replace'. |
|
3777 ]. |
|
3778 |
|
3779 something isCharacter ifTrue:[ |
|
3780 lastReplacementInfo lastReplacement notNil ifTrue:[ |
|
3781 lastReplacementInfo stillCollectingInput ifTrue:[ |
|
3782 lastReplacementInfo lastReplacement: (lastReplacementInfo lastReplacement copyWith:something). |
|
3783 ]. |
|
3784 ]. |
|
3785 self isInInsertMode ifTrue:[ |
|
3786 self insertCharAtCursor:something |
|
3787 ] ifFalse:[ |
|
3788 self replaceCharAtCursor:something |
|
3789 ] |
|
3790 ] ifFalse:[ |
|
3791 something isString ifTrue:[ |
|
3792 lastReplacementInfo lastReplacement: something. |
|
3793 self isInInsertMode ifTrue:[ |
|
3794 self insertStringAtCursor:something |
|
3795 ] ifFalse:[ |
|
3796 self replaceStringAtCursor:something |
|
3797 ] |
|
3798 ] ifFalse:[ |
|
3799 Transcript showCR:'EditTextView: non String-or-Character in replace'. |
|
3800 ]. |
|
3801 ]. |
|
3802 keep ifTrue:[ |
|
3803 self cursorLine:l col:c |
|
3804 ]. |
|
3805 selectNewText ifTrue:[ |
|
3806 self selectFromLine:selStartLine col:selStartCol toLine:cursorLine col:cursorCol-1 |
|
3807 ] |
|
3808 |
|
3809 "Modified: 9.10.1996 / 16:14:35 / cg" |
|
3810 ! |
|
3811 |
|
3812 replaceString:aString atLine:lineNr col:colNr |
|
3813 "replace multiple characters starting at lineNr/colNr. |
|
3814 This is not prepared to encounter special chars (except TAB) in the string." |
|
3815 |
|
3816 |originalString| |
|
3817 |
|
3818 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
3819 |
|
3820 originalString := self textFromLine:lineNr col:colNr toLine:lineNr col:colNr+aString size-1. |
|
3821 |
|
3822 self basicReplaceString:aString atLine:lineNr col:colNr. |
|
3823 self addUndo:(ReplaceCharacters line:lineNr col:colNr characters:originalString info:'replace'). |
|
3824 ! |
|
3825 |
|
3826 replaceString:aString to:aNewString ignoreCase:ignoreCase |
|
3827 |continue count| |
|
3828 |
|
3829 self cursorToTop. |
|
3830 self selectFromBeginning. |
|
3831 count := 0. |
|
3832 continue := true. |
|
3833 [ continue ] whileTrue:[ |
|
3834 (self selectionAsString notNil |
|
3835 and:[ self selectionAsString sameAs:aString caseSensitive:ignoreCase not ]) |
|
3836 ifTrue:[ |
|
3837 self replaceSelectionBy:aNewString. |
|
3838 count := count + 1. |
|
3839 ]. |
|
3840 self |
|
3841 searchFwd:aString |
|
3842 ignoreCase:ignoreCase |
|
3843 ifAbsent:[ |
|
3844 Dialog information:('%1 has been replaced by %2 %3 times' |
|
3845 bindWith:aString with:aNewString with:count). |
|
3846 continue := false. |
|
3847 ]. |
|
3848 ]. |
|
3849 |
|
3850 "Created: / 10-07-2006 / 16:42:48 / fm" |
|
3851 ! |
|
3852 |
|
3853 replaceStringAtCursor:aString |
|
3854 "replace multiple characters at cursor-position - advance cursor" |
|
3855 |
|
3856 |wasOn i1 i2| |
|
3857 |
|
3858 wasOn := self hideCursor. |
|
3859 (aString includes:Character tab) ifTrue:[ |
|
3860 "/ need special care for TAB (to move cursor correctly) |
|
3861 i1 := 1. |
|
3862 [i1 ~~ 0] whileTrue:[ |
|
3863 i2 := aString indexOf:Character tab startingAt:i1. |
|
3864 i2 ~~ 0 ifTrue:[ |
|
3865 i1 ~~ i2 ifTrue:[ |
|
3866 self replaceString:(aString copyFrom:i1 to:i2-1) atLine:cursorLine col:cursorCol. |
|
3867 self cursorCol:(cursorCol + (i2 - i1)). |
|
3868 ]. |
|
3869 self replaceTABAtCursor. |
|
3870 i2 := i2 + 1. |
|
3871 ] ifFalse:[ |
|
3872 self replaceString:(aString copyFrom:i1) atLine:cursorLine col:cursorCol. |
|
3873 self cursorCol:(cursorCol + (aString size - i1 + 1)). |
|
3874 ]. |
|
3875 i1 := i2. |
|
3876 ] |
|
3877 ] ifFalse:[ |
|
3878 self replaceString:aString atLine:cursorLine col:cursorCol. |
|
3879 self cursorCol:(cursorCol + aString size). |
|
3880 ]. |
|
3881 self makeCursorVisibleAndShowCursor:wasOn. |
|
3882 |
|
3883 "Created: / 9.6.1998 / 20:33:20 / cg" |
|
3884 "Modified: / 20.6.1998 / 19:41:02 / cg" |
|
3885 ! |
|
3886 |
|
3887 replaceTABAtCursor |
|
3888 "replace a single character at cursor-position by a TAB character" |
|
3889 |
|
3890 |wasOn nextTab| |
|
3891 |
|
3892 wasOn := self hideCursor. |
|
3893 nextTab := self nextTabAfter:cursorCol. |
|
3894 self replaceStringAtCursor:(String new:(nextTab - cursorCol)). |
|
3895 self makeCursorVisibleAndShowCursor:wasOn. |
|
3896 |
|
3897 "Created: / 12.6.1998 / 21:53:23 / cg" |
|
3898 ! |
|
3899 |
|
3900 selectWordBeforeCursor |
|
3901 "select the word to the left of cursor" |
|
3902 |
|
3903 |savCursorLine savCursorCol beginCol beginLine endCol endLine| |
|
3904 |
|
3905 savCursorLine := cursorLine. |
|
3906 savCursorCol := cursorCol. |
|
3907 |
|
3908 endCol := cursorCol-1. |
|
3909 endLine := cursorLine. |
|
3910 self cursorToPreviousWord. |
|
3911 beginCol := cursorCol. |
|
3912 beginLine := cursorLine. |
|
3913 self cursorLine:savCursorLine col:savCursorCol. |
|
3914 self selectFromLine:beginLine col:beginCol toLine:endLine col:endCol. |
|
3915 |
|
3916 "Created: / 14-06-2011 / 14:46:35 / cg" |
|
3917 ! |
|
3918 |
|
3919 splitLine:lineNr before:colNr |
|
3920 "split the line linNr before colNr; the right part (from colNr) |
|
3921 is cut off and inserted after lineNr; the view is redrawn" |
|
3922 |
|
3923 self basicSplitLine:lineNr before:colNr. |
|
3924 self addUndo:(DeleteRange line1:lineNr col1:colNr line2:lineNr+1 col2:0 info:'split'). |
|
3925 ! |
|
3926 |
|
3927 withoutRedrawAt:lineNr put:aString |
|
3928 "replace a line at lineNr" |
|
3929 |
|
3930 |originalLine| |
|
3931 |
|
3932 originalLine := self listAt:lineNr. |
|
3933 self addUndo:(ReplaceLine line:lineNr string:originalLine info:'replace'). |
|
3934 super withoutRedrawAt:lineNr put:aString. |
|
3935 ! |
|
3936 |
|
3937 withoutRedrawInsertLine:aString before:lineNr |
|
3938 "insert the argument, aString before line lineNr; the string |
|
3939 becomes line lineNr; everything else is moved down; the view |
|
3940 is not redrawn" |
|
3941 |
|
3942 self basicWithoutRedrawInsertLines:{ aString } from:1 to:1 before:lineNr. |
|
3943 self addUndo:(DeleteRange line1:lineNr col1:1 line2:lineNr+1 col2:0 info:'insert'). |
|
3944 ! |
|
3945 |
|
3946 withoutRedrawInsertLines:lines from:start to:end before:lineNr |
|
3947 "insert a bunch of lines before line lineNr; the view is not redrawn" |
|
3948 |
|
3949 self basicWithoutRedrawInsertLines:lines from:start to:end before:lineNr. |
|
3950 self isReadOnly ifFalse:[ |
|
3951 self addUndo:(DeleteRange line1:lineNr col1:1 line2:lineNr+end-start+1 col2:0 info:'insert'). |
|
3952 ]. |
|
3953 ! |
|
3954 |
|
3955 withoutRedrawInsertStringWithoutCRs:aString atLine:lineNr col:colNr |
|
3956 "insert aString (which has no crs) at lineNr/colNr" |
|
3957 |
|
3958 self basicWithoutRedrawInsertStringWithoutCRs:aString atLine:lineNr col:colNr. |
|
3959 self addUndo:(DeleteRange line1:lineNr col1:colNr line2:lineNr col2:colNr+aString size-1 info:'insert'). |
|
3960 ! |
|
3961 |
|
3962 wrapLines |
|
3963 "wrap lines (insert line-break)" |
|
3964 |
|
3965 |lineLength answerString string| |
|
3966 |
|
3967 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
3968 |
|
3969 self hasSelection ifFalse:[ |
|
3970 self selectLine:cursorLine. |
|
3971 ]. |
|
3972 string := self selectionAsString. |
|
3973 string isEmptyOrNil ifTrue:[ |
|
3974 Dialog information:(resources string:'Nothing selected.'). |
|
3975 ^ self. |
|
3976 ]. |
|
3977 |
|
3978 answerString := Dialog request:(resources string:'Line length (wrap after how many chars)?') initialAnswer:80. |
|
3979 lineLength := Number readFrom:answerString onError:nil. |
|
3980 lineLength isNil ifTrue:[^ self]. |
|
3981 lineLength < 1 ifTrue:[ |
|
3982 lineLength := 1. |
|
3983 ]. |
|
3984 |
|
3985 self |
|
3986 undoableDo:[ |
|
3987 |inStream line col lineLen lastGoodCol lastStartCol word| |
|
3988 |
|
3989 line := selectionStartLine. |
|
3990 col := selectionStartCol. |
|
3991 |
|
3992 self cutSelection. |
|
3993 self cursorLine:line col:col. |
|
3994 |
|
3995 lastGoodCol := col. |
|
3996 |
|
3997 inStream := string readStream. |
|
3998 [ inStream atEnd ] whileFalse:[ |
|
3999 [inStream atEnd not and:[inStream peek isSeparator]] whileTrue:[ inStream next ]. |
|
4000 word := WriteStream on:(String new:10). |
|
4001 [inStream atEnd not and:[inStream peek isSeparator not]] whileTrue:[ word nextPut:inStream next ]. |
|
4002 (col + 1 + word size > lineLength) ifTrue:[ |
|
4003 self insertCharAtCursor:(Character cr). |
|
4004 col := 1. |
|
4005 ] ifFalse:[ |
|
4006 col ~~ 1 ifTrue:[ |
|
4007 self insertStringAtCursor:' '. |
|
4008 col := col + 1. |
|
4009 ] |
|
4010 ]. |
|
4011 self insertStringAtCursor:word contents. |
|
4012 col := col + word size. |
|
4013 ]. |
|
4014 ] |
|
4015 info:'Wrap' |
|
4016 |
|
4017 "Modified: / 01-03-2012 / 19:56:22 / cg" |
|
4018 ! ! |
|
4019 |
|
4020 !EditTextView methodsFor:'editing-basic'! |
|
4021 |
|
4022 basicDeleteCharsAtLine:lineNr fromCol:startCol toCol:endCol |
|
4023 "delete characters from startCol to endCol in line lineNr" |
|
4024 |
|
4025 |line lineSize newLine start stop prevWidth newWidth| |
|
4026 |
|
4027 self unselect. |
|
4028 |
|
4029 cursorLine == lineNr ifTrue:[ |
|
4030 cursorCol >= startCol ifTrue:[ |
|
4031 cursorCol >= endCol ifTrue:[ |
|
4032 cursorCol := startCol. |
|
4033 ] ifFalse:[ |
|
4034 cursorCol := cursorCol - (endCol - startCol + 1). |
|
4035 ] |
|
4036 ]. |
|
4037 ]. |
|
4038 |
|
4039 line := self listAt:lineNr. |
|
4040 |
|
4041 (self checkModificationsAllowed and:[line notNil]) ifFalse:[^ self]. |
|
4042 |
|
4043 lineSize := line size. |
|
4044 |
|
4045 startCol == 0 ifFalse:[ start := startCol ] ifTrue:[ start := 1 ]. |
|
4046 endCol > lineSize ifFalse:[ stop := endCol ] ifTrue:[ stop := lineSize ]. |
|
4047 |
|
4048 stop >= start ifTrue:[ |
|
4049 start ~~ 1 ifTrue:[ newLine := line copyFrom:1 to:(start-1) ] |
|
4050 ifFalse:[ newLine := '' ]. |
|
4051 |
|
4052 stop == lineSize ifFalse:[ |
|
4053 line bitsPerCharacter > newLine bitsPerCharacter ifTrue:[ |
|
4054 newLine := line string species fromString:newLine. |
|
4055 ]. |
|
4056 newLine := newLine, (line copyFrom:(stop + 1) to:lineSize) |
|
4057 ]. |
|
4058 |
|
4059 (trimBlankLines and:[newLine isBlank]) ifTrue:[ |
|
4060 newLine := nil |
|
4061 ]. |
|
4062 |
|
4063 prevWidth := self widthOfLine:lineNr. |
|
4064 |
|
4065 self basicListAt:lineNr put:newLine. |
|
4066 |
|
4067 (prevWidth = widthOfWidestLine) ifTrue:[ |
|
4068 "/ remember old width of this line, |
|
4069 "/ only clear widthOfWidestLine, if this lines |
|
4070 "/ length was (one of) the longest. |
|
4071 "/ avoids slow delete with huge texts. |
|
4072 widthOfWidestLine := nil. "i.e. unknown" |
|
4073 |
|
4074 "/ scroll left if reqiured |
|
4075 viewOrigin x > 0 ifTrue:[ |
|
4076 newWidth := self widthOfLine:lineNr. |
|
4077 newWidth < (viewOrigin x + width) ifTrue:[ |
|
4078 self scrollHorizontalTo:(newWidth |
|
4079 - width |
|
4080 + margin + margin |
|
4081 + (gc font widthOf:' ')) |
|
4082 ] |
|
4083 ]. |
|
4084 self textChanged. |
|
4085 ] ifFalse:[ |
|
4086 self textChanged "/ textChangedButNoSizeChange |
|
4087 ]. |
|
4088 gc font hasOverlappingCharacters ifTrue:[ |
|
4089 self invalidateLine:lineNr. |
|
4090 ] ifFalse:[ |
|
4091 self redrawLine:lineNr from:start. |
|
4092 ]. |
|
4093 ]. |
|
4094 |
|
4095 "Modified: / 09-11-2010 / 13:42:45 / cg" |
|
4096 ! |
|
4097 |
|
4098 basicDeleteFromLine:startLineNr toLine:endLineNr |
|
4099 "delete some lines" |
|
4100 |
|
4101 |wasOn nLines| |
|
4102 |
|
4103 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
4104 list isNil ifTrue:[^ self]. |
|
4105 |
|
4106 wasOn := self hideCursor. |
|
4107 |
|
4108 "/ isnt this the same as: |
|
4109 "/ self deleteLinesWithoutRedrawFrom:startLineNr to:endLineNr. |
|
4110 startLineNr <= list size ifTrue:[ |
|
4111 self basicListRemoveFromIndex:startLineNr toIndex:(endLineNr min:list size). |
|
4112 ]. |
|
4113 "/ TODO: remember old maxwidth of linerange, |
|
4114 "/ only clear widthOfWidestLine, if this max |
|
4115 "/ length was (one of) the longest. |
|
4116 "/ avoids slow delete with huge texts. |
|
4117 widthOfWidestLine := nil. "/ i.e. unknown |
|
4118 self textChanged. |
|
4119 |
|
4120 self redrawFromLine:startLineNr. |
|
4121 |
|
4122 nLines := list size. |
|
4123 (firstLineShown >= nLines) ifTrue:[ |
|
4124 self makeLineVisible:nLines |
|
4125 ]. |
|
4126 wasOn ifTrue:[self showCursor]. |
|
4127 |
|
4128 "Modified: / 10-11-1998 / 23:55:05 / cg" |
|
4129 "Modified: / 18-03-2011 / 18:26:23 / az" |
|
4130 ! |
|
4131 |
|
4132 basicDeleteLineWithoutRedraw:lineNr |
|
4133 "delete line - no redraw; |
|
4134 return true, if something was really deleted" |
|
4135 |
|
4136 self checkModificationsAllowed ifFalse:[ ^ false]. |
|
4137 |
|
4138 (list isNil or:[lineNr > list size]) ifTrue:[^ false]. |
|
4139 list removeIndex:lineNr. |
|
4140 "/ TODO: remember old maxwidth of linerange, |
|
4141 "/ only clear widthOfWidestLine, if this max |
|
4142 "/ length was (one of) the longest. |
|
4143 "/ avoids slow delete with huge texts. |
|
4144 widthOfWidestLine := nil. "/ i.e. unknown |
|
4145 self textChanged. |
|
4146 ^ true |
|
4147 |
|
4148 "Modified: / 10.11.1998 / 23:53:24 / cg" |
|
4149 ! |
|
4150 |
|
4151 basicInsert:aCharacter atLine:lineNr col:colNr |
|
4152 "insert a single character at lineNr/colNr; |
|
4153 set emphasis to character at current position" |
|
4154 |
|
4155 |line lineSize newLine drawCharacterOnly attribute oldClip x y| |
|
4156 |
|
4157 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
4158 |
|
4159 aCharacter == (Character cr) ifTrue:[ |
|
4160 self splitLine:lineNr before:colNr. |
|
4161 ^ self |
|
4162 ]. |
|
4163 |
|
4164 drawCharacterOnly := false. |
|
4165 self checkForExistingLine:lineNr. |
|
4166 line := list at:lineNr. |
|
4167 lineSize := line size. |
|
4168 |
|
4169 self st80EditMode ifFalse:[ |
|
4170 (trimBlankLines |
|
4171 and:[colNr > lineSize |
|
4172 and:[aCharacter == Character space]]) ifTrue:[ |
|
4173 ^ self |
|
4174 ] |
|
4175 ]. |
|
4176 |
|
4177 (lineSize == 0) ifTrue:[ |
|
4178 newLine := aCharacter asString species new:colNr. |
|
4179 drawCharacterOnly := true |
|
4180 ] ifFalse: [ |
|
4181 (colNr > lineSize) ifTrue: [ |
|
4182 colNr == (lineSize +1) ifTrue:[ |
|
4183 attribute := line emphasisAt:lineSize |
|
4184 ]. |
|
4185 newLine := line species new:colNr. |
|
4186 newLine replaceFrom:1 to:lineSize with:line startingAt:1. |
|
4187 drawCharacterOnly := true |
|
4188 ] ifFalse: [ |
|
4189 attribute := line emphasisAt:colNr. |
|
4190 newLine := line species new:(lineSize + 1). |
|
4191 |
|
4192 newLine replaceFrom:1 to:(colNr - 1) with:line startingAt:1. |
|
4193 newLine replaceFrom:(colNr + 1) to:(lineSize + 1) with:line startingAt:colNr |
|
4194 ] |
|
4195 ]. |
|
4196 |
|
4197 aCharacter asString bitsPerCharacter > newLine bitsPerCharacter ifTrue:[ |
|
4198 newLine := aCharacter asString species fromString:newLine. |
|
4199 line isText ifTrue:[ |
|
4200 newLine := newLine asText |
|
4201 ] |
|
4202 ]. |
|
4203 newLine at:colNr put:aCharacter. |
|
4204 |
|
4205 attribute notNil ifTrue:[ |
|
4206 newLine emphasisAt:colNr put:attribute. |
|
4207 ]. |
|
4208 |
|
4209 aCharacter == (Character tab) ifTrue:[ |
|
4210 newLine := self withTabsExpanded:newLine. |
|
4211 drawCharacterOnly := false |
|
4212 ]. |
|
4213 |
|
4214 self basicListAt:lineNr put:(newLine ifNil:[newLine] ifNotNil:[newLine asSingleByteStringIfPossible]). |
|
4215 widthOfWidestLine notNil ifTrue:[ |
|
4216 widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:newLine). |
|
4217 ]. |
|
4218 self textChanged. |
|
4219 shown ifTrue:[ |
|
4220 "/ care for italic text - in this case, we must also |
|
4221 "/ redraw the character before the insertion in order |
|
4222 "/ to fix the slanted piece of the character. |
|
4223 "/ (but we must clip, to avoid destoying the character before) |
|
4224 (newLine notNil and:[newLine isText]) ifTrue:[ |
|
4225 colNr > 1 ifTrue:[ |
|
4226 cursorVisibleLine notNil ifTrue:[ |
|
4227 oldClip := self clippingRectangleOrNil. |
|
4228 x := (self xOfCol:colNr-1 inVisibleLine:cursorVisibleLine) - viewOrigin x. |
|
4229 y := self yOfVisibleLine:cursorVisibleLine. |
|
4230 |
|
4231 gc font hasOverlappingCharacters ifTrue:[ |
|
4232 self invalidateLine:lineNr. |
|
4233 ] ifFalse:[ |
|
4234 drawCharacterOnly ifTrue:[ |
|
4235 self clippingRectangle:(x@y extent:((gc font width * 2) @ fontHeight)). |
|
4236 self redrawLine:lineNr from:colNr-1 to:colNr |
|
4237 ] ifFalse:[ |
|
4238 self clippingRectangle:(x@y extent:((width - x) @ fontHeight)). |
|
4239 self redrawLine:lineNr from:colNr-1 |
|
4240 ]. |
|
4241 self clippingRectangle:oldClip. |
|
4242 ]. |
|
4243 ]. |
|
4244 ^ self. |
|
4245 ]. |
|
4246 ]. |
|
4247 gc font hasOverlappingCharacters ifTrue:[ |
|
4248 self invalidateLine:lineNr. |
|
4249 ] ifFalse:[ |
|
4250 drawCharacterOnly ifTrue:[ |
|
4251 self redrawLine:lineNr col:colNr |
|
4252 ] ifFalse:[ |
|
4253 self redrawLine:lineNr from:colNr |
|
4254 ] |
|
4255 ] |
|
4256 ] |
|
4257 |
|
4258 "Modified: / 09-11-2010 / 13:43:18 / cg" |
|
4259 ! |
|
4260 |
|
4261 basicListAt:lineNr put:newLine |
|
4262 "redefinable for special subclasses (with virtual list)" |
|
4263 |
|
4264 list at:lineNr put:newLine. |
|
4265 ! |
|
4266 |
|
4267 basicListRemoveFromIndex:startLineNr toIndex:endLineNr |
|
4268 "redefinable for special subclasses (with virtual list)" |
|
4269 |
|
4270 list removeFromIndex:startLineNr toIndex:(endLineNr min:list size). |
|
4271 ! |
|
4272 |
|
4273 basicMergeLine:lineNr removeBlanks:removeBlanks |
|
4274 "merge line lineNr with line lineNr+1" |
|
4275 |
|
4276 |leftPart rightPart bothParts nextLineNr i| |
|
4277 |
|
4278 (list notNil and:[(list size) >= lineNr]) ifFalse:[ |
|
4279 "/ empty list or beyond end of text |
|
4280 ^ self |
|
4281 ]. |
|
4282 leftPart := self listAt:lineNr. |
|
4283 |
|
4284 leftPart isNil ifTrue:[ |
|
4285 leftPart := ''. |
|
4286 autoIndent ifTrue:[ |
|
4287 (i := self leftIndentForLine:cursorLine) == 0 ifFalse:[ |
|
4288 leftPart := String new:i |
|
4289 ] |
|
4290 ] |
|
4291 ]. |
|
4292 self cursorLine:lineNr col:((leftPart size) + 1). |
|
4293 nextLineNr := self validateCursorLine:(lineNr + 1). |
|
4294 |
|
4295 nextLineNr > (list size) ifFalse:[ |
|
4296 (rightPart := self listAt:nextLineNr) isNil ifTrue:[ |
|
4297 rightPart := '' |
|
4298 ] ifFalse:[ |
|
4299 removeBlanks ifTrue:[ |
|
4300 rightPart := rightPart withoutLeadingSeparators. |
|
4301 ] |
|
4302 ]. |
|
4303 |
|
4304 bothParts := leftPart , rightPart. |
|
4305 (trimBlankLines and:[bothParts isBlank]) ifTrue:[bothParts := nil]. |
|
4306 self basicListAt:lineNr put:bothParts. |
|
4307 self redrawLine:lineNr. |
|
4308 self deleteLine:nextLineNr |
|
4309 ] |
|
4310 |
|
4311 "Created: 9.9.1997 / 09:27:38 / cg" |
|
4312 "Modified: 9.9.1997 / 09:28:27 / cg" |
|
4313 ! |
|
4314 |
|
4315 basicReplace:aCharacter atLine:lineNr col:colNr |
|
4316 "replace a single character at lineNr/colNr" |
|
4317 |
|
4318 |line lineSize newLine drawCharacterOnly| |
|
4319 |
|
4320 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
4321 |
|
4322 aCharacter == (Character cr) ifTrue:[ |
|
4323 ^ self |
|
4324 ]. |
|
4325 |
|
4326 drawCharacterOnly := true. |
|
4327 self checkForExistingLine:lineNr. |
|
4328 line := list at:lineNr. |
|
4329 lineSize := line size. |
|
4330 |
|
4331 (trimBlankLines |
|
4332 and:[colNr > lineSize |
|
4333 and:[aCharacter == Character space]]) ifTrue:[ |
|
4334 ^ self |
|
4335 ]. |
|
4336 |
|
4337 (lineSize == 0) ifTrue:[ |
|
4338 newLine := aCharacter asString species new:colNr. |
|
4339 ] ifFalse: [ |
|
4340 (colNr > lineSize) ifTrue: [ |
|
4341 newLine := line species new:colNr. |
|
4342 newLine replaceFrom:1 to:lineSize with:line startingAt:1. |
|
4343 ] ifFalse: [ |
|
4344 newLine := line copy. |
|
4345 ] |
|
4346 ]. |
|
4347 newLine at:colNr put:aCharacter. |
|
4348 aCharacter == (Character tab) ifTrue:[ |
|
4349 newLine := self withTabsExpanded:newLine. |
|
4350 drawCharacterOnly := false |
|
4351 ]. |
|
4352 self basicListAt:lineNr put:(newLine ifNil:[newLine] ifNotNil:[newLine asSingleByteStringIfPossible]). |
|
4353 widthOfWidestLine notNil ifTrue:[ |
|
4354 widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:newLine). |
|
4355 ]. |
|
4356 self textChanged. |
|
4357 shown ifTrue:[ |
|
4358 gc font hasOverlappingCharacters ifTrue:[ |
|
4359 self invalidateLine:lineNr. |
|
4360 ] ifFalse:[ |
|
4361 drawCharacterOnly ifTrue:[ |
|
4362 self redrawLine:lineNr col:colNr |
|
4363 ] ifFalse:[ |
|
4364 self redrawLine:lineNr from:colNr |
|
4365 ] |
|
4366 ] |
|
4367 ] |
|
4368 |
|
4369 "Created: / 06-03-1996 / 12:29:20 / cg" |
|
4370 "Modified: / 09-11-2010 / 13:42:54 / cg" |
|
4371 ! |
|
4372 |
|
4373 basicReplaceString:aString atLine:lineNr col:colNr |
|
4374 "replace multiple characters starting at lineNr/colNr. |
|
4375 This is not prepared to encounter special chars (except TAB) |
|
4376 in the string." |
|
4377 |
|
4378 |line lineSize newLine endCol| |
|
4379 |
|
4380 self checkModificationsAllowed ifFalse:[ ^ self]. |
|
4381 |
|
4382 self checkForExistingLine:lineNr. |
|
4383 line := list at:lineNr. |
|
4384 lineSize := line size. |
|
4385 |
|
4386 endCol := colNr + aString size - 1. |
|
4387 (lineSize == 0) ifTrue:[ |
|
4388 newLine := aString species new:endCol. |
|
4389 ] ifFalse: [ |
|
4390 (endCol > lineSize) ifTrue: [ |
|
4391 aString isText ifTrue:[ |
|
4392 newLine := aString species new:endCol. |
|
4393 ] ifFalse:[ |
|
4394 newLine := line species new:endCol. |
|
4395 ]. |
|
4396 newLine replaceFrom:1 to:lineSize with:line startingAt:1. |
|
4397 ] ifFalse: [ |
|
4398 aString isText ifTrue:[ |
|
4399 newLine := aString species new:line size. |
|
4400 newLine replaceFrom:1 to:lineSize with:line startingAt:1. |
|
4401 ] ifFalse:[ |
|
4402 newLine := line copy. |
|
4403 ] |
|
4404 ] |
|
4405 ]. |
|
4406 newLine replaceFrom:colNr with:aString. |
|
4407 (aString includes:(Character tab)) ifTrue:[ |
|
4408 newLine := self withTabsExpanded:newLine. |
|
4409 ]. |
|
4410 self basicListAt:lineNr put:(newLine ifNil:[newLine] ifNotNil:[newLine asSingleByteStringIfPossible]). |
|
4411 widthOfWidestLine notNil ifTrue:[ |
|
4412 widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:newLine). |
|
4413 ]. |
|
4414 self textChanged. |
|
4415 shown ifTrue:[ |
|
4416 gc font hasOverlappingCharacters ifTrue:[ |
|
4417 self invalidateLine:lineNr. |
|
4418 ] ifFalse:[ |
|
4419 self redrawLine:lineNr from:colNr |
|
4420 ] |
|
4421 ] |
|
4422 |
|
4423 "Created: / 11-06-1998 / 10:38:32 / cg" |
|
4424 "Modified: / 09-11-2010 / 13:42:56 / cg" |
|
4425 ! |
|
4426 |
|
4427 basicSplitLine:lineNr before:colNr |
|
4428 "split the line linNr before colNr; the right part (from colNr) |
|
4429 is cut off and inserted after lineNr; the view is redrawn" |
|
4430 |
|
4431 |line lineSize leftRest rightRest visLine w h mustWait |
|
4432 srcY "{ Class: SmallInteger }" | |
|
4433 |
|
4434 list isNil ifTrue:[ ^ self ]. |
|
4435 lineNr > (list size) ifTrue:[ ^ self ]. |
|
4436 |
|
4437 (colNr == 1) ifTrue:[ |
|
4438 self nonUndoableDo:[ |
|
4439 self insertLine:nil before:lineNr. |
|
4440 ]. |
|
4441 ^ self |
|
4442 ]. |
|
4443 |
|
4444 line := list at:lineNr. |
|
4445 line notNil ifTrue:[ |
|
4446 lineSize := line size. |
|
4447 (colNr <= lineSize) ifTrue:[ |
|
4448 rightRest := line copyFrom:colNr to:lineSize. |
|
4449 (colNr > 1) ifTrue:[ |
|
4450 leftRest := line copyTo:(colNr - 1) |
|
4451 ] |
|
4452 ] ifFalse:[ |
|
4453 leftRest := line |
|
4454 ] |
|
4455 ]. |
|
4456 leftRest notNil ifTrue:[ |
|
4457 (trimBlankLines and:[leftRest isBlank]) ifTrue:[leftRest := nil] |
|
4458 ]. |
|
4459 self basicListAt:lineNr put:leftRest. |
|
4460 self nonUndoableDo:[ |
|
4461 self withoutRedrawInsertLine:rightRest before:(lineNr + 1). |
|
4462 ]. |
|
4463 visLine := self listLineToVisibleLine:(lineNr). |
|
4464 visLine notNil ifTrue:[ |
|
4465 w := self widthForScrollBetween:lineNr |
|
4466 and:(firstLineShown + nLinesShown). |
|
4467 srcY := topMargin + (visLine * fontHeight). |
|
4468 h := ((nLinesShown - visLine - 1) * fontHeight). |
|
4469 (mustWait := (w > 0 and:[h > 0])) ifTrue:[ |
|
4470 self catchExpose. |
|
4471 self |
|
4472 copyFrom:self |
|
4473 x:textStartLeft y:srcY |
|
4474 toX:textStartLeft y:(srcY + fontHeight) |
|
4475 width:w |
|
4476 height:((nLinesShown - visLine - 1) * fontHeight) |
|
4477 async:true. |
|
4478 ]. |
|
4479 self redrawLine:lineNr. |
|
4480 self redrawLine:(lineNr + 1). |
|
4481 mustWait ifTrue:[self waitForExpose] |
|
4482 ]. |
|
4483 widthOfWidestLine := nil. "/ unknown |
|
4484 self textChanged. |
|
4485 |
|
4486 "Modified: / 06-12-2010 / 13:12:55 / cg" |
|
4487 ! |
|
4488 |
|
4489 basicWithoutRedrawInsertLines:lines from:start to:end before:lineNr |
|
4490 "insert a bunch of lines before line lineNr; the view is not redrawn. |
|
4491 Tabs are expanded here with a tab=8 setting (independent of any editor-setting, |
|
4492 because the text might have been pasted from an alien view." |
|
4493 |
|
4494 |newLine newLines nLines| |
|
4495 |
|
4496 nLines := end - start + 1. |
|
4497 newLines := Array new:(lines size). |
|
4498 start to:end do:[:index | |
|
4499 newLine := lines at:index. |
|
4500 newLine notNil ifTrue:[ |
|
4501 newLine isString ifTrue:[ |
|
4502 newLine isBlank ifTrue:[ |
|
4503 newLine := nil |
|
4504 ] ifFalse:[ |
|
4505 (newLine includes:(Character tab)) ifTrue:[ |
|
4506 newLine := self withTabs:(ListView tab8Positions) expand:newLine |
|
4507 ] |
|
4508 ] |
|
4509 ] |
|
4510 ]. |
|
4511 newLines at:index put:newLine |
|
4512 ]. |
|
4513 list isNil ifTrue: [ |
|
4514 list := StringCollection new:(lineNr + nLines + 1) |
|
4515 ] ifFalse: [ |
|
4516 list grow:((list size + nLines) max:(lineNr + nLines - 1)) |
|
4517 ]. |
|
4518 |
|
4519 "I have changed 'replaceFrom:to:with:startingAt:' to correctly handle |
|
4520 overlapping copy - if it didn't, we had to use:" |
|
4521 " |
|
4522 index := list size. |
|
4523 [index > lineNr] whileTrue: [ |
|
4524 pIndex := index - 1. |
|
4525 list at:index put:(list at:pIndex). |
|
4526 index := pIndex |
|
4527 ]. |
|
4528 " |
|
4529 list replaceFrom:(lineNr + nLines) to:(list size) with:list startingAt:lineNr. |
|
4530 list replaceFrom:lineNr to:(lineNr + nLines - 1) with:newLines startingAt:start. |
|
4531 self contentsChanged |
|
4532 |
|
4533 "Modified: / 07-10-2011 / 15:55:18 / cg" |
|
4534 ! |
|
4535 |
|
4536 basicWithoutRedrawInsertStringWithoutCRs:aString atLine:lineNr col:colNr |
|
4537 "insert aString (which has no crs) at lineNr/colNr. |
|
4538 Tabs are expanded here with a tab=8 setting (independent of any editor-setting, |
|
4539 because the text might have been pasted from an alien view." |
|
4540 |
|
4541 |isText strLen line lineSize newLine stringType sz lineCharWidth stringCharWidth| |
|
4542 |
|
4543 (aString isNil) ifTrue:[ ^ self]. |
|
4544 |
|
4545 strLen := aString size. |
|
4546 self checkForExistingLine:lineNr. |
|
4547 |
|
4548 stringType := aString string species. |
|
4549 isText := aString isText. |
|
4550 line := list at:lineNr. |
|
4551 |
|
4552 line notNil ifTrue:[ |
|
4553 lineSize := line size. |
|
4554 line isString ifFalse:[ |
|
4555 stringType := line species |
|
4556 ] ifTrue:[ |
|
4557 lineCharWidth := line bitsPerCharacter. |
|
4558 stringCharWidth := aString bitsPerCharacter. |
|
4559 lineCharWidth > stringCharWidth ifTrue:[ |
|
4560 stringType := line string species |
|
4561 ] ifFalse:[ |
|
4562 stringCharWidth > lineCharWidth ifTrue:[ |
|
4563 stringType := aString string species |
|
4564 ] |
|
4565 ]. |
|
4566 line isText ifTrue:[ isText := true ] |
|
4567 ]. |
|
4568 ] ifFalse:[ |
|
4569 lineSize := 0 |
|
4570 ]. |
|
4571 |
|
4572 ((colNr == 1) and:[lineSize == 0]) ifTrue: [ |
|
4573 newLine := aString |
|
4574 ] ifFalse:[ |
|
4575 (lineSize == 0 or:[colNr > lineSize]) ifTrue: [ |
|
4576 sz := colNr + strLen - 1 |
|
4577 ] ifFalse:[ |
|
4578 sz := lineSize + strLen |
|
4579 ]. |
|
4580 |
|
4581 newLine := stringType new:sz. |
|
4582 isText ifTrue:[ |
|
4583 newLine := Text string:newLine |
|
4584 ]. |
|
4585 |
|
4586 (lineSize ~~ 0) ifTrue: [ |
|
4587 (colNr > lineSize) ifTrue: [ |
|
4588 newLine replaceFrom:1 to:lineSize with:line startingAt:1 |
|
4589 ] ifFalse: [ |
|
4590 newLine replaceFrom:1 to:(colNr - 1) with:line startingAt:1. |
|
4591 newLine replaceFrom:(colNr + strLen) to:(lineSize + strLen) with:line startingAt:colNr |
|
4592 ] |
|
4593 ]. |
|
4594 newLine replaceFrom:(colNr max:1) to:(colNr + strLen - 1) with:aString startingAt:1 |
|
4595 ]. |
|
4596 |
|
4597 (aString includes:(Character tab)) ifTrue:[ |
|
4598 newLine := self withTabs:(ListView tab8Positions) expand:newLine |
|
4599 ]. |
|
4600 |
|
4601 self basicListAt:lineNr put:(newLine ifNil:[newLine] ifNotNil:[newLine asSingleByteStringIfPossible]). |
|
4602 widthOfWidestLine notNil ifTrue:[ |
|
4603 widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:newLine). |
|
4604 ]. |
|
4605 self textChanged. |
|
4606 |
|
4607 "Modified: / 25-01-2012 / 00:37:29 / cg" |
|
4608 ! ! |
|
4609 |
|
4610 !EditTextView methodsFor:'event handling'! |
|
4611 |
|
4612 buttonPress:button x:x y:y |
|
4613 "hide the cursor when button is activated" |
|
4614 |
|
4615 hasKeyboardFocus := true. |
|
4616 dragIsActive := false. |
|
4617 |
|
4618 completionSupport notNil ifTrue:[ |
|
4619 "/ also give that guy a chance to close its popup view |
|
4620 completionSupport buttonPress:button x:x y:y |
|
4621 ]. |
|
4622 |
|
4623 cursorShown ifTrue: [ |
|
4624 self drawCursor |
|
4625 ]. |
|
4626 |
|
4627 "On X11, be nice and paste PRIMARY when middle click. |
|
4628 Note, that middle button on X11 is translated to button |
|
4629 128 in Smalltalk/X - see XWorkstation class>>initializeConstants" |
|
4630 (button == #paste and:[self graphicsDevice platformName == #X11]) ifTrue:[ |
|
4631 self undoableDo:[ |
|
4632 self paste: (self getClipboardText:#selection). |
|
4633 ]. |
|
4634 ^self. |
|
4635 ]. |
|
4636 |
|
4637 (button == 1) ifTrue:[ |
|
4638 self hideCursor |
|
4639 ]. |
|
4640 "/ some very old code from times, when a right-click was a paste in X11 |
|
4641 "/ |
|
4642 "/ (button == #paste) ifTrue:[ |
|
4643 "/ self pasteOrReplace. |
|
4644 "/ ^ self |
|
4645 "/ ]. |
|
4646 super buttonPress:button x:x y:y |
|
4647 |
|
4648 "Modified: / 23-03-1999 / 13:51:40 / cg" |
|
4649 "Modified (comment): / 17-04-2012 / 21:02:25 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
4650 ! |
|
4651 |
|
4652 buttonRelease:button x:x y:y |
|
4653 "move the cursor to the click-position of previous button press" |
|
4654 |
|
4655 |x1 x2 x2_3 newCursorCol| |
|
4656 |
|
4657 (button == 1) ifTrue:[ |
|
4658 typeOfSelection := nil. |
|
4659 |
|
4660 dragIsActive ifTrue:[ |
|
4661 self unselect |
|
4662 ]. |
|
4663 selectionStartLine isNil ifTrue:[ |
|
4664 clickCol notNil ifTrue:[ |
|
4665 self cursorMovementAllowed ifTrue:[ |
|
4666 newCursorCol := clickCol. |
|
4667 |
|
4668 cursorType ~~ #block ifTrue:[ |
|
4669 clickPos notNil ifTrue:[ |
|
4670 "/ we do something special, if the text-cursor's type is not a block-cursor |
|
4671 "/ (i.e. if its an ibeam). |
|
4672 "/ adjust clickCol if the user clicked in the right third of a character. |
|
4673 x1 := self xOfCol:clickCol inVisibleLine:clickLine. |
|
4674 x2 := self xOfCol:clickCol+1 inVisibleLine:clickLine. |
|
4675 x2_3 := x1 + ((x2-x1) * (2/3)). |
|
4676 (clickPos x >= x2_3) ifTrue:[ newCursorCol := clickCol+1 ]. |
|
4677 ]. |
|
4678 ]. |
|
4679 self cursorLine:clickLine col:newCursorCol. |
|
4680 ]. |
|
4681 true "self hadSelectionBeforeClick not" ifTrue:[ |
|
4682 list notEmptyOrNil ifTrue:[ |
|
4683 UserPreferences current selectAllWhenClickingBeyondEnd ifTrue:[ |
|
4684 (clickLine >= list size) ifTrue:[ |
|
4685 (clickLine > (self list size + 2) |
|
4686 or:[ clickCol > (list last size + 5) ]) ifTrue:[ |
|
4687 self selectAll |
|
4688 ]. |
|
4689 ]. |
|
4690 ] |
|
4691 ] |
|
4692 ] |
|
4693 ] |
|
4694 ] ifFalse:[ |
|
4695 lastStringFromReplaceForNextSearch := nil. "new selection invalidates remembered string" |
|
4696 ]. |
|
4697 self showCursor |
|
4698 ]. |
|
4699 super buttonRelease:button x:x y:y |
|
4700 |
|
4701 "Modified: / 07-03-2012 / 18:48:37 / cg" |
|
4702 ! |
|
4703 |
|
4704 cursorKeyPress:key shifted:shifted |
|
4705 <resource: #keyboard (#CursorRight #CursorDown #CursorUp #CursorDown)> |
|
4706 |
|
4707 |n| |
|
4708 |
|
4709 self changeTypeOfSelectionTo:nil. |
|
4710 |
|
4711 (key == #CursorRight) ifTrue:[ |
|
4712 (shifted and:[selectionStartLine isNil]) ifTrue:[ |
|
4713 selectionStartLine := selectionEndLine := clickStartLine := cursorLine. |
|
4714 selectionStartCol := selectionEndCol := clickStartCol := cursorCol. |
|
4715 expandingTop := false. |
|
4716 self validateNewSelection. |
|
4717 self setPrimarySelection. |
|
4718 self selectionChanged. |
|
4719 self redrawLine:selectionStartLine. |
|
4720 ^ self. |
|
4721 ]. |
|
4722 |
|
4723 selectionStartLine notNil ifTrue:[ |
|
4724 self cursorMovementAllowed ifTrue:[ |
|
4725 "/ |
|
4726 "/ treat the whole selection as cursor |
|
4727 "/ |
|
4728 self setCursorLine:(selectionEndLine ? selectionStartLine). |
|
4729 selectionEndCol == 0 ifTrue:[ |
|
4730 selectionEndCol := 1. |
|
4731 ]. |
|
4732 self setCursorCol:selectionEndCol. |
|
4733 shifted ifTrue:[ |
|
4734 self expandSelectionRight. |
|
4735 ^ self |
|
4736 ]. |
|
4737 self unselect; makeCursorVisible. |
|
4738 cursorCol == 1 ifTrue:[^ self]. |
|
4739 ]. |
|
4740 ]. |
|
4741 self cursorRight. |
|
4742 ^ self |
|
4743 ]. |
|
4744 (key == #CursorDown) ifTrue:[ |
|
4745 (shifted and:[selectionStartLine isNil]) ifTrue:[ |
|
4746 selectionStartLine := clickStartLine := cursorLine. selectionEndLine := cursorLine + 1. |
|
4747 selectionStartCol := clickStartCol := selectionEndCol := cursorCol. |
|
4748 selectionEndCol == 1 ifTrue:[ |
|
4749 selectionEndCol := 0. |
|
4750 ]. |
|
4751 self validateNewSelection. |
|
4752 self selectionChanged. |
|
4753 self redrawLine:selectionStartLine. |
|
4754 expandingTop := false. |
|
4755 self redrawLine:selectionEndLine. |
|
4756 ^ self |
|
4757 ]. |
|
4758 |
|
4759 selectionStartLine notNil ifTrue:[ |
|
4760 self cursorMovementAllowed ifTrue:[ |
|
4761 "/ |
|
4762 "/ treat the whole selection as cursor |
|
4763 "/ |
|
4764 self setCursorLine:(selectionEndLine ? selectionStartLine). |
|
4765 self setCursorCol:selectionStartCol. |
|
4766 (cursorCol == 0 or:[selectionEndCol == 0]) ifTrue:[ |
|
4767 self setCursorCol:1. |
|
4768 self setCursorLine:(cursorLine - 1). |
|
4769 ]. |
|
4770 self makeCursorVisible. |
|
4771 |
|
4772 shifted ifTrue:[ |
|
4773 clickLine := cursorLine. |
|
4774 clickCol := cursorCol. |
|
4775 self expandSelectionDown. |
|
4776 ^ self |
|
4777 ]. |
|
4778 self unselect. |
|
4779 ]. |
|
4780 ]. |
|
4781 |
|
4782 n := 1 + (self sensor compressKeyPressEventsWithKey:#CursorDown). |
|
4783 self cursorDown:n. |
|
4784 "/ |
|
4785 "/ flush keyboard to avoid runaway cursor |
|
4786 "/ |
|
4787 self sensor flushKeyboardFor:self. |
|
4788 ^ self |
|
4789 ]. |
|
4790 (key == #CursorLeft or:[key == #CursorUp]) ifTrue:[ |
|
4791 (shifted and:[selectionStartLine isNil]) ifTrue:[ |
|
4792 expandingTop := true. |
|
4793 key == #CursorLeft ifTrue:[ |
|
4794 cursorCol > 1 ifTrue:[ |
|
4795 selectionStartLine := selectionEndLine := clickStartLine := cursorLine. |
|
4796 selectionEndCol := clickStartCol := cursorCol-1. |
|
4797 selectionStartCol := cursorCol-1. |
|
4798 self validateNewSelection. |
|
4799 self selectionChanged. |
|
4800 self redrawLine:selectionStartLine. |
|
4801 ^ self |
|
4802 ] |
|
4803 ] ifFalse:[ |
|
4804 cursorLine > 1 ifTrue:[ |
|
4805 selectionEndLine := clickStartLine := cursorLine. |
|
4806 selectionEndCol := selectionStartCol := clickStartCol := cursorCol. |
|
4807 selectionStartLine := cursorLine - 1. |
|
4808 selectionEndCol == 1 ifTrue:[ |
|
4809 selectionEndCol := 0. |
|
4810 ]. |
|
4811 self validateNewSelection. |
|
4812 self selectionChanged. |
|
4813 self redrawFromLine:selectionStartLine to:cursorLine. |
|
4814 ^ self |
|
4815 ] |
|
4816 ] |
|
4817 ]. |
|
4818 |
|
4819 selectionStartLine notNil ifTrue:[ |
|
4820 self cursorMovementAllowed ifTrue:[ |
|
4821 "/ |
|
4822 "/ treat the whole selection as cursor |
|
4823 "/ |
|
4824 self setCursorLine:selectionStartLine. |
|
4825 self setCursorCol:selectionStartCol. |
|
4826 (key == #CursorLeft) ifTrue:[ |
|
4827 self setCursorCol:(cursorCol+1). "/ compensate for followup crsr-left |
|
4828 ]. |
|
4829 self makeCursorVisible. |
|
4830 |
|
4831 shifted ifTrue:[ |
|
4832 (key == #CursorUp) ifTrue:[ |
|
4833 clickLine := cursorLine. |
|
4834 self expandSelectionUp. |
|
4835 ] ifFalse:[ |
|
4836 self expandSelectionLeft. |
|
4837 ]. |
|
4838 ^ self |
|
4839 ]. |
|
4840 self unselect. |
|
4841 ]. |
|
4842 ]. |
|
4843 (key == #CursorLeft) ifTrue:[ |
|
4844 self cursorLeft. ^self |
|
4845 ]. |
|
4846 (key == #CursorUp) ifTrue:[ |
|
4847 n := 1 + (self sensor compressKeyPressEventsWithKey:#CursorUp). |
|
4848 self cursorUp:n. |
|
4849 "/ |
|
4850 "/ flush keyboard to avoid runaway cursor |
|
4851 "/ |
|
4852 self sensor flushKeyboardFor:self. |
|
4853 ^ self |
|
4854 ]. |
|
4855 ]. |
|
4856 |
|
4857 "Modified: / 17-04-2012 / 21:01:15 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
4858 ! |
|
4859 |
|
4860 doKeyPress:key x:x y:y |
|
4861 "handle keyboard input" |
|
4862 |
|
4863 <resource: #keyboard (#Paste #Insert #PasteFromHistory #Cut #Again #AgainForAll |
|
4864 #Replace #Undo #Redo #Accept |
|
4865 #Delete #BasicDelete #BackSpace #BasicBackspace |
|
4866 #DeleteSpaces #Join |
|
4867 #SearchMatchingParent #SelectMatchingParents |
|
4868 #SelectWord #ExpandSelectionByWord |
|
4869 #SelectToEnd #SelectFromBeginning |
|
4870 #SelectLine #ExpandSelectionByLine |
|
4871 #BeginOfLine #EndOfLine #NextWord #PreviousWord |
|
4872 #CursorRight #CursorDown #CursorLeft #CursorUp |
|
4873 #Return #Tab #BackTab #NonInsertingTab #Escape |
|
4874 #GotoLine #BeginOfText #EndOfText |
|
4875 #InsertLine #DeleteLine |
|
4876 #SelectLineFromBeginning |
|
4877 #LearnKeyboardMacro #ExecuteKeyboardMacro #ToggleInsertMode |
|
4878 #OpenSpecialCharacterWindow |
|
4879 #'F*' #'f*')> |
|
4880 |
|
4881 |fKeyMacros shiftPressed ctrlPressed i event macroName |
|
4882 immediateCompletion currentUserPrefs| |
|
4883 |
|
4884 currentUserPrefs := UserPreferences current. |
|
4885 |
|
4886 "/ experimental |
|
4887 immediateCompletion := currentUserPrefs immediateCodeCompletion. |
|
4888 (immediateCompletion |
|
4889 or:[currentUserPrefs codeCompletionOnControlKey |
|
4890 or:[currentUserPrefs codeCompletionOnTabKey]]) ifTrue:[ |
|
4891 completionSupport isNil ifTrue:[ |
|
4892 self initializeCompletionSupport. |
|
4893 ]. |
|
4894 ]. |
|
4895 "/ JV: why setting it to nil here? |
|
4896 "/ ifFalse:[ |
|
4897 "/ completionService := nil |
|
4898 "/ ]. |
|
4899 completionSupport notNil ifTrue:[ |
|
4900 (completionSupport handleKeyPress:key x:x y:y) ifTrue:["eaten" ^ self]. |
|
4901 ]. |
|
4902 |
|
4903 key isSymbol ifTrue:[ |
|
4904 (self graphicsDevice modifierKeys includes:key) ifFalse:[ |
|
4905 lastReplacementInfo stillCollectingInput:false. |
|
4906 ] |
|
4907 ]. |
|
4908 (key == #LearnKeyboardMacro) ifTrue:[ |
|
4909 lastReplacementInfo stillCollectingInput:false. |
|
4910 self toggleLearnMode. |
|
4911 ^ self |
|
4912 ]. |
|
4913 (key == #ExecuteKeyboardMacro) ifTrue:[ |
|
4914 lastReplacementInfo stillCollectingInput:false. |
|
4915 self executeLearnedKeyboardMacro. |
|
4916 ^ self. |
|
4917 ]. |
|
4918 (key == #Undo) ifTrue:[self undo. ^self]. |
|
4919 (key == #Redo) ifTrue:[self redo. ^self]. |
|
4920 |
|
4921 self learnMode ifTrue:[ |
|
4922 event := WindowGroup lastEventQuerySignal query. |
|
4923 learnedMacro add:event. |
|
4924 ]. |
|
4925 |
|
4926 (self executekeyboardMacroNamed:key) ifTrue:[ |
|
4927 "the macro named key exists" |
|
4928 ^ self |
|
4929 ]. |
|
4930 |
|
4931 key isSymbol ifFalse:[ |
|
4932 "the usual case: key is a character, but maybe a string also (in X11)" |
|
4933 self handleNonCommandKey:key. |
|
4934 ^ self |
|
4935 ]. |
|
4936 |
|
4937 event isNil ifTrue:[ |
|
4938 event := WindowGroup lastEventQuerySignal query. |
|
4939 ]. |
|
4940 shiftPressed := event hasShift. |
|
4941 ctrlPressed := event hasCtrl and:[(event rawKey asString startsWith:'Ctrl') not]. |
|
4942 |
|
4943 (key == #DeleteWordBeforeCursor) ifTrue:[ |
|
4944 self deleteWordBeforeCursor. |
|
4945 ^ self. |
|
4946 ]. |
|
4947 |
|
4948 (key == #BackSpace or:[key == #BasicBackspace]) ifTrue:[ |
|
4949 selectionStartLine notNil ifTrue:[ |
|
4950 ((key == #BasicBackspace) |
|
4951 or:[ currentUserPrefs deleteSetsClipboardText not ]) |
|
4952 ifTrue:[ |
|
4953 self deleteSelection. |
|
4954 ] ifFalse: [ |
|
4955 self copyAndDeleteSelection. |
|
4956 ]. |
|
4957 ] ifFalse:[ |
|
4958 self makeCursorVisible. |
|
4959 "/ (shiftPressed and:[ ctrlPressed ]) ifTrue:[ |
|
4960 "/ self deleteWordBeforeCursor. |
|
4961 "/ ] ifFalse:[ |
|
4962 self deleteCharBeforeCursor. |
|
4963 "/ ]. |
|
4964 ]. |
|
4965 true "immediateCompletion" ifTrue:[ |
|
4966 completionSupport notNil ifTrue:[ completionSupport postKeyPress:key]. |
|
4967 ]. |
|
4968 ^ self |
|
4969 ]. |
|
4970 |
|
4971 (key == #ToggleAutoIndent) ifTrue:[ |
|
4972 self autoIndent:(autoIndent not). |
|
4973 ^ self. |
|
4974 ]. |
|
4975 |
|
4976 key == #ToggleInsertMode ifTrue:[ |
|
4977 self insertMode:(editMode value == EditMode insertMode) not. |
|
4978 ^ self. |
|
4979 ]. |
|
4980 |
|
4981 key == #OpenSpecialCharacterWindow ifTrue:[ |
|
4982 CharacterSetView notNil ifTrue:[ |
|
4983 self specialCharacters. |
|
4984 ^ self. |
|
4985 ] |
|
4986 ]. |
|
4987 |
|
4988 replacing := false. |
|
4989 |
|
4990 " |
|
4991 Fn pastes a key-sequence (but only if not overlayed with |
|
4992 another function in the keyboard map) |
|
4993 |
|
4994 see TextView>>:x:y |
|
4995 " |
|
4996 (key at:1) asLowercase == $f ifTrue:[ |
|
4997 (('[fF][0-9]' match:key) |
|
4998 or:['[fF][0-9][0-9]' match:key]) ifTrue:[ |
|
4999 shiftPressed ifFalse:[ |
|
5000 fKeyMacros := currentUserPrefs functionKeySequences. |
|
5001 fKeyMacros notNil ifTrue:[ |
|
5002 (fKeyMacros includesKey:key) ifTrue:[ |
|
5003 self pasteOrReplace:(fKeyMacros at:key) asStringCollection. |
|
5004 ^ self |
|
5005 ] |
|
5006 ] |
|
5007 ] |
|
5008 ]. |
|
5009 ]. |
|
5010 |
|
5011 (key == #'Ctrl8' or:[key == #'Ctrl9']) ifTrue:[ |
|
5012 self parenthizeSelectionWith:$( and:$). |
|
5013 ^ self. |
|
5014 ]. |
|
5015 (key == #'Ctrl2') ifTrue:[ |
|
5016 self parenthizeSelectionWith:$" and:$". |
|
5017 ^ self. |
|
5018 ]. |
|
5019 (key == #'Ctrl#') ifTrue:[ |
|
5020 self parenthizeSelectionWith:$' and:$'. |
|
5021 ^ self. |
|
5022 ]. |
|
5023 (key == #'ConvertSelectionToLowercaseOrUppercaseOrUppercaseFirst') ifTrue:[ |
|
5024 self convertSelectionToLowercaseOrUppercaseOrUppercaseFirst. |
|
5025 ^ self. |
|
5026 ]. |
|
5027 |
|
5028 (key == #Accept) ifTrue:[^ self accept]. |
|
5029 |
|
5030 ((key == #Paste) or:[key == #Insert or:[key == #PasteFromHistory]]) ifTrue:[self pasteOrReplace. ^self]. |
|
5031 (key == #Cut) ifTrue:[self cut. ^self]. |
|
5032 (key == #Again) ifTrue:[self again. ^self]. |
|
5033 (key == #AgainForAll) ifTrue:[self multipleAgain. ^self]. |
|
5034 |
|
5035 (key == #Join) ifTrue:[self joinLines. ^self]. |
|
5036 (key == #Replace) ifTrue:[self replace. ^self]. |
|
5037 (key == #ExpandSelectionByWord) ifTrue:[ |
|
5038 self makeCursorVisible. |
|
5039 self findNextWordAfterSelectionAndAddToSelection. |
|
5040 ^ self |
|
5041 ]. |
|
5042 (key == #SelectWord) ifTrue:[ |
|
5043 self makeCursorVisible. |
|
5044 self selectWordUnderCursor. |
|
5045 ^ self |
|
5046 ]. |
|
5047 |
|
5048 (key == #SearchMatchingParent) ifTrue:[self searchForMatchingParenthesis. ^ self]. |
|
5049 (key == #SelectMatchingParents) ifTrue:[self searchForAndSelectMatchingParenthesis. ^ self]. |
|
5050 (key == #SelectToEnd) ifTrue:[self selectUpToEnd. ^ self]. |
|
5051 (key == #SelectFromBeginning) ifTrue:[self selectFromBeginning. ^ self]. |
|
5052 |
|
5053 " disabled - nobody liked it ... |
|
5054 and if you like it, its better done in the keymap. |
|
5055 |
|
5056 (key == #Ctrlb) ifTrue:[self unselect. self cursorLeft. ^ self]. |
|
5057 (key == #Ctrlf) ifTrue:[self unselect. self cursorRight. ^ self]. |
|
5058 (key == #Ctrln) ifTrue:[self unselect. self cursorDown. ^ self]. |
|
5059 (key == #Ctrlp) ifTrue:[self unselect. self cursorUp. ^ self]. |
|
5060 " |
|
5061 |
|
5062 (key == #BeginOfLine) ifTrue:[ |
|
5063 shiftPressed ifTrue: [ |
|
5064 "/ "Original St/X code - now use Ctrl modifier" |
|
5065 "/ self unselect. |
|
5066 "/ self cursorHome. |
|
5067 "Jan's modification" |
|
5068 "/ self addToSelectionAfter:[ self cursorToBeginOfLine ]. |
|
5069 "/ Jan's modification modified by his own request ;-)) |
|
5070 self selectFromBeginOfLine. |
|
5071 ] ifFalse: [ |
|
5072 self unselect. |
|
5073 ctrlPressed ifTrue:[ |
|
5074 self cursorHome. |
|
5075 ] ifFalse:[ |
|
5076 self cursorToBeginOfLine. |
|
5077 ] |
|
5078 ]. |
|
5079 ^ self |
|
5080 ]. |
|
5081 (key == #EndOfLine) ifTrue:[ |
|
5082 shiftPressed ifTrue:[ |
|
5083 "/ "Original St/X code - now use Ctrl modifier" |
|
5084 "/ self unselect. |
|
5085 "/ self cursorToBottom |
|
5086 " Jan's modification" |
|
5087 "/ self addToSelectionAfter:[ self cursorToEndOfLine ] . |
|
5088 "/ Jan's modification modified by his own request ;-)) |
|
5089 self selectToEndOfLine. |
|
5090 ] ifFalse:[ |
|
5091 self unselect. |
|
5092 ctrlPressed ifTrue:[ |
|
5093 self cursorToBottom |
|
5094 ] ifFalse:[ |
|
5095 self cursorToEndOfLine. |
|
5096 ] |
|
5097 ]. |
|
5098 ^ self |
|
5099 ]. |
|
5100 (key == #NextWord) ifTrue:[self cursorToNextWord. ^self]. |
|
5101 (key == #EndOfWord) ifTrue:[self cursorToEndOfWord. ^self]. |
|
5102 (key == #PreviousWord) ifTrue:[self cursorToPreviousWord. ^self]. |
|
5103 (key == #GotoLine) ifTrue:[self gotoLine. ^self]. |
|
5104 |
|
5105 (key == #CursorRight |
|
5106 or:[key == #CursorDown |
|
5107 or:[key == #CursorLeft |
|
5108 or:[key == #CursorUp]]]) ifTrue:[ |
|
5109 self cursorKeyPress:key shifted:shiftPressed. |
|
5110 ^ self. |
|
5111 ]. |
|
5112 |
|
5113 (key == #NonInsertingReturn) ifTrue:[ |
|
5114 self unselect. self cursorReturn. |
|
5115 ^ self |
|
5116 ]. |
|
5117 |
|
5118 (key == #Return) ifTrue:[ |
|
5119 shiftPressed ifTrue:[ |
|
5120 self unselect. self cursorReturn. |
|
5121 ^ self |
|
5122 ]. |
|
5123 |
|
5124 self isReadOnly ifTrue:[ |
|
5125 self unselect; makeCursorVisible. |
|
5126 self cursorReturn |
|
5127 ] ifFalse:[ |
|
5128 self isInInsertMode ifFalse:[ |
|
5129 self cursorReturn. |
|
5130 autoIndent == true ifTrue:[ |
|
5131 i := self leftIndentForLine:(cursorLine + 1). |
|
5132 (self listAt:cursorLine) isEmptyOrNil ifTrue:[ |
|
5133 self cursorCol:(i+1 max:1) |
|
5134 ] |
|
5135 ] |
|
5136 ] ifTrue:[ |
|
5137 |left right oldIndent| |
|
5138 |
|
5139 "/ old version just unselected ... |
|
5140 "/ self unselect; makeCursorVisible. |
|
5141 |
|
5142 "/ new version deletes ... |
|
5143 typeOfSelection == #paste ifTrue:[ |
|
5144 self unselect; makeCursorVisible. |
|
5145 ] ifFalse:[ |
|
5146 self copyAndDeleteSelection. |
|
5147 ]. |
|
5148 left := (self listAt:cursorLine to:cursorCol-1) ? ''. |
|
5149 right := (self listAt:cursorLine from:cursorCol) ? ''. |
|
5150 self insertCharAtCursor:(Character cr). |
|
5151 autoIndent == true ifTrue:[ |
|
5152 (right isEmpty and:[cursorCol ~~ 1]) ifTrue:[ |
|
5153 "/ nothing to do. |
|
5154 ] ifFalse:[ |
|
5155 ((self listAt:cursorLine) isEmptyOrNil |
|
5156 or:[ cursorCol == 1 ]) ifTrue:[ |
|
5157 i := (self leftIndentForLine:cursorLine). |
|
5158 left := left withoutSeparators. |
|
5159 right := right withoutSeparators. |
|
5160 (left endsWith:'[') ifTrue:[ |
|
5161 "/ i := i + 4. |
|
5162 ] ifFalse:[ |
|
5163 (false "(left endsWith:']')" or:[(right startsWith:']')]) ifTrue:[ |
|
5164 i := i - 4. |
|
5165 ]. |
|
5166 ]. |
|
5167 oldIndent := self leftIndentOfLine:cursorLine. |
|
5168 self indentFromLine:cursorLine toLine:cursorLine by:(i-oldIndent). |
|
5169 self st80EditMode ifTrue:[ |
|
5170 (self listAt:cursorLine) size < i ifTrue:[ |
|
5171 self insertStringAtCursor:(String new:((i-oldIndent) max:0)). |
|
5172 ]. |
|
5173 ]. |
|
5174 self cursorCol:(i+1 max:1) |
|
5175 ]. |
|
5176 ] |
|
5177 ]. |
|
5178 ]. |
|
5179 ]. |
|
5180 ^ self |
|
5181 ]. |
|
5182 |
|
5183 (key == #NonInsertingTab) ifTrue:[ |
|
5184 self unselect. self cursorTab. |
|
5185 ^ self |
|
5186 ]. |
|
5187 ((key == #BackTab) or:[(key == #Tab)]) ifTrue:[ |
|
5188 self tabMeansNextField ifTrue:[^ super keyPress:key x:x y:y]. |
|
5189 |
|
5190 self hasSelection ifTrue:[ |
|
5191 selectStyle == #line ifTrue:[ |
|
5192 ((key == #Tab) and:[shiftPressed not]) ifTrue:[ |
|
5193 macroName := #IndentBy4. |
|
5194 ] ifFalse:[ |
|
5195 macroName := #UndentBy4. |
|
5196 ]. |
|
5197 macroName notNil ifTrue:[ |
|
5198 self executekeyboardMacroNamed:macroName. |
|
5199 ]. |
|
5200 ] |
|
5201 ]. |
|
5202 |
|
5203 self unselect. |
|
5204 (key == #Tab) ifTrue:[ |
|
5205 (shiftPressed or:[self isInInsertMode not]) ifTrue:[ |
|
5206 self cursorTab. |
|
5207 ^ self |
|
5208 ]. |
|
5209 self insertTabAtCursor. |
|
5210 ^ self |
|
5211 ]. |
|
5212 self cursorBacktab. |
|
5213 ^ self |
|
5214 ]. |
|
5215 |
|
5216 "/ key == #DeleteSpaces ifTrue:[ |
|
5217 (key == #Delete) ifTrue:[ |
|
5218 shiftPressed ifTrue:[ |
|
5219 [(cursorCol <= (self listAt:cursorLine) size) |
|
5220 and:[self characterUnderCursor isSeparator]] whileTrue:[ |
|
5221 self makeCursorVisible. |
|
5222 self deleteCharAtCursor. |
|
5223 ]. |
|
5224 ^ self |
|
5225 ] |
|
5226 ]. |
|
5227 |
|
5228 (key == #Delete |
|
5229 or:[key == #BasicDelete]) ifTrue:[ |
|
5230 selectionStartLine notNil ifTrue:[ |
|
5231 "/ Again function is not supporting Delete action (on purpose, to avoid replacing the next search string) |
|
5232 "/ To remove text repetetively, use Cut instead. |
|
5233 "/ self setLastStringToReplace: self selection asStringWithoutFinalCR. |
|
5234 "/ lastReplacementInfo lastReplacement: nil. |
|
5235 ((key == #BasicDelete) |
|
5236 or:[currentUserPrefs deleteSetsClipboardText not]) ifTrue:[ |
|
5237 self deleteSelection. |
|
5238 ] ifFalse:[ |
|
5239 self copyAndDeleteSelection. |
|
5240 ]. |
|
5241 ^ self |
|
5242 ]. |
|
5243 self makeCursorVisible. |
|
5244 self deleteCharAtCursor. |
|
5245 ^ self |
|
5246 ]. |
|
5247 |
|
5248 (key == #BeginOfText) ifTrue:[ "i.e. HOME" |
|
5249 self unselect. |
|
5250 cursorVisibleLine == 1 ifTrue:[ |
|
5251 self cursorHome. |
|
5252 ] ifFalse:[ |
|
5253 self cursorToFirstVisibleLine |
|
5254 ]. |
|
5255 ^ self |
|
5256 ]. |
|
5257 (key == #EndOfText) ifTrue:[ "i.e. END" |
|
5258 self unselect. |
|
5259 cursorVisibleLine == nFullLinesShown ifTrue:[ |
|
5260 self cursorToBottom. |
|
5261 ] ifFalse:[ |
|
5262 self cursorToLastVisibleLine |
|
5263 ]. |
|
5264 ^ self |
|
5265 ]. |
|
5266 ((key == #Escape) |
|
5267 or:[key == #SelectLineFromBeginning]) ifTrue:[ |
|
5268 self makeCursorVisible. |
|
5269 self unselect. self selectCursorLineFromBeginning. |
|
5270 ^ self |
|
5271 ]. |
|
5272 (key == #SelectLine) ifTrue:[ |
|
5273 self makeCursorVisible. |
|
5274 self unselect. self selectCursorLine. |
|
5275 ^ self |
|
5276 ]. |
|
5277 (key == #ExpandSelectionByLine) ifTrue:[ |
|
5278 "/ self makeCursorVisible. |
|
5279 self selectExpandCursorLine. |
|
5280 ^ self |
|
5281 ]. |
|
5282 (key == #DeleteLine) ifTrue:[ |
|
5283 self makeCursorVisible. |
|
5284 self unselect. self deleteCursorLine. |
|
5285 ^ self |
|
5286 ]. |
|
5287 (key == #InsertLine) ifTrue:[ |
|
5288 self makeCursorVisible. |
|
5289 self unselect. self insertLine:nil before:cursorLine. |
|
5290 ^ self |
|
5291 ]. |
|
5292 |
|
5293 super keyPress:key x:x y:y |
|
5294 |
|
5295 "Modified: / 06-02-1998 / 11:59:59 / stefan" |
|
5296 "Modified: / 14-07-2011 / 12:08:28 / cg" |
|
5297 "Modified: / 26-09-2013 / 17:52:04 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
5298 ! |
|
5299 |
|
5300 executeKeyboardMacro:cmdMacro |
|
5301 Error handle:[:ex | |
|
5302 self warn:'Error in keyboard macro: ' , ex description. |
|
5303 ex return. |
|
5304 ] do:[ |
|
5305 AbortOperationRequest handle:[:ex | |
|
5306 self warn:'Keyboard macro aborted'. |
|
5307 ex return. |
|
5308 ] do:[ |
|
5309 Parser |
|
5310 evaluate:cmdMacro asString |
|
5311 receiver:self |
|
5312 notifying:nil |
|
5313 compile:false. |
|
5314 ]. |
|
5315 ]. |
|
5316 ! |
|
5317 |
|
5318 handleNonCommandKey:keyArg |
|
5319 |selStartLineBefore selStartColBefore selEndLineBefore selEndColBefore key| |
|
5320 |
|
5321 self isReadOnly ifTrue:[ |
|
5322 self flashReadOnly. |
|
5323 ^ self. |
|
5324 ]. |
|
5325 |
|
5326 key := keyArg. |
|
5327 |
|
5328 typeOfSelection == #paste ifTrue:[ |
|
5329 "pasted selection will NOT be replaced by keystroke" |
|
5330 self unselect |
|
5331 ]. |
|
5332 |
|
5333 selStartLineBefore := selectionStartLine. |
|
5334 selStartColBefore := self selectionStartCol. |
|
5335 selEndLineBefore := selectionEndLine. |
|
5336 selEndColBefore := self selectionEndCol. |
|
5337 |
|
5338 (gc characterEncoding ? #'iso10646-1') ~~ #'iso10646-1' ifTrue:[ |
|
5339 key isCharacter ifTrue:[ |
|
5340 key := CharacterEncoder encode:key from:#'iso10646-1' into:gc characterEncoding. |
|
5341 ] ifFalse:[ |
|
5342 key := CharacterEncoder encodeString:key from:#'iso10646-1' into:gc characterEncoding. |
|
5343 ]. |
|
5344 ]. |
|
5345 |
|
5346 "replace selection by what is typed in - |
|
5347 if word was selected with a space, keep it. |
|
5348 if there was no selection, the key's character is inserted" |
|
5349 |
|
5350 editMode value isInsertAndSelectMode ifTrue:[ |
|
5351 selectionStartLine := selectionStartCol := selectionEndLine := selectionEndCol := nil. |
|
5352 ]. |
|
5353 |
|
5354 (selectStyle == #wordLeft) ifTrue:[ |
|
5355 self replaceSelectionBy:(' ' , key asString) |
|
5356 ] ifFalse:[ |
|
5357 (selectStyle == #wordRight) ifTrue:[ |
|
5358 self replaceSelectionBy:(key asString , ' '). |
|
5359 self cursorLeft |
|
5360 ] ifFalse:[ |
|
5361 self replaceSelectionBy:key |
|
5362 ] |
|
5363 ]. |
|
5364 selectStyle := nil. |
|
5365 |
|
5366 editMode value isInsertAndSelectMode ifTrue:[ |
|
5367 selectionStartLine := selStartLineBefore. |
|
5368 selectionStartCol := selStartColBefore. |
|
5369 selectionEndLine := selEndLineBefore. |
|
5370 selectionEndCol := selEndColBefore. |
|
5371 ]. |
|
5372 |
|
5373 showMatchingParenthesis ifTrue:[ |
|
5374 "emacs style parenthesis shower" |
|
5375 (ExecutingMacroQuery query ? false) ifFalse:[ |
|
5376 "claus: only do it for closing parenthesis - |
|
5377 otherwise its too anoying. |
|
5378 " |
|
5379 " |
|
5380 ('()[]{}' includes:key) ifTrue:[ |
|
5381 " |
|
5382 (')]}' includes:key) ifTrue:[ |
|
5383 self |
|
5384 searchForMatchingParenthesisFromLine:cursorLine col:(cursorCol - 1) |
|
5385 ifFound:[:line :col | |
|
5386 |savLine savCol sensor| |
|
5387 |
|
5388 self withCursor:Cursor eye do:[ |
|
5389 savLine := cursorLine. |
|
5390 savCol := cursorCol. |
|
5391 self cursorLine:line col:col. |
|
5392 self flush. |
|
5393 |
|
5394 "/ want to wait 200ms, but not if another keyPress |
|
5395 "/ arrives in the meantime ... |
|
5396 |
|
5397 sensor := self sensor. |
|
5398 5 timesRepeat:[ |
|
5399 (sensor hasKeyPressEventFor:self) ifFalse:[ |
|
5400 Processor activeProcess millisecondDelay:40. |
|
5401 ] |
|
5402 ]. |
|
5403 self cursorLine:savLine col:savCol |
|
5404 ] |
|
5405 ] |
|
5406 ifNotFound:[self showNotFound] |
|
5407 onError:[self beep] |
|
5408 ]. |
|
5409 ] |
|
5410 ]. |
|
5411 |
|
5412 "/ true "autoExpandWhileTyping" ifTrue:[ |
|
5413 "/ self wordAtLine:cursorLine col:cursorCol-1 do:[ |
|
5414 "/ :beginLine :beginCol :endLine :endCol :style | |
|
5415 "/ |
|
5416 "/ self selectFromLine:beginLine col:beginCol toLine:endLine col:endCol. |
|
5417 "/ self selection. |
|
5418 "/ typeOfSelection := #paste. |
|
5419 "/ ]. |
|
5420 "/ ]. |
|
5421 editMode value isInsertAndSelectMode ifTrue:[ |
|
5422 selectionStartLine isNil ifTrue:[ |
|
5423 self selectFromLine:cursorLine col:cursorCol-1 toLine:cursorLine col:cursorCol-1. |
|
5424 ] ifFalse:[ |
|
5425 self selectFromLine:selectionStartLine col:selectionStartCol toLine:cursorLine col:cursorCol-1. |
|
5426 ]. |
|
5427 ]. |
|
5428 completionSupport notNil ifTrue:[ completionSupport postKeyPress:keyArg ]. |
|
5429 |
|
5430 "Modified (comment): / 25-01-2012 / 00:30:11 / cg" |
|
5431 ! |
|
5432 |
|
5433 keyPress:key x:x y:y |
|
5434 "handle keyboard input" |
|
5435 |
|
5436 |wasOn| |
|
5437 |
|
5438 wasOn := cursorShown. |
|
5439 |
|
5440 NoModificationError handle:[:ex | |
|
5441 self flashReadOnly. |
|
5442 (cursorShown not and:[wasOn]) ifTrue:[ |
|
5443 self makeCursorVisibleAndShowCursor:wasOn. |
|
5444 ]. |
|
5445 ] do:[ |
|
5446 self undoableDo:[ |
|
5447 self doKeyPress:key x:x y:y |
|
5448 ]. |
|
5449 ]. |
|
5450 self repairDamage |
|
5451 |
|
5452 "Modified: / 18-04-2011 / 21:35:27 / cg" |
|
5453 ! |
|
5454 |
|
5455 mapped |
|
5456 "view was made visible" |
|
5457 |
|
5458 super mapped. |
|
5459 self updateCursorVisibleLine. |
|
5460 ! |
|
5461 |
|
5462 requestAutoAccept |
|
5463 "this is invoked when a dialog closes via accept or cancel. |
|
5464 This forces my value to be accepted into my model" |
|
5465 |
|
5466 acceptEnabled == false ifTrue:[ |
|
5467 "/ nope - |
|
5468 ^ false |
|
5469 ]. |
|
5470 self accept. |
|
5471 ^ true. |
|
5472 ! |
|
5473 |
|
5474 sizeChanged:how |
|
5475 "make certain, cursor is visible after the sizechange" |
|
5476 |
|
5477 |cv| |
|
5478 |
|
5479 cv := cursorVisibleLine. |
|
5480 super sizeChanged:how. |
|
5481 cv notNil ifTrue:[ |
|
5482 self makeLineVisible:cursorLine |
|
5483 ] |
|
5484 ! |
|
5485 |
|
5486 unmapped |
|
5487 super unmapped. |
|
5488 |
|
5489 completionSupport notNil ifTrue:[ |
|
5490 completionSupport release. |
|
5491 ]. |
|
5492 ! ! |
|
5493 |
|
5494 !EditTextView methodsFor:'focus handling'! |
|
5495 |
|
5496 focusOut |
|
5497 super focusOut. |
|
5498 |
|
5499 completionSupport notNil ifTrue:[ |
|
5500 completionSupport release. |
|
5501 ]. |
|
5502 ! |
|
5503 |
|
5504 hasKeyboardFocus:aBoolean |
|
5505 "sent by the windowGroup, a delegate or myself to make me show a block cursor |
|
5506 (otherwise, I would not know about this)" |
|
5507 |
|
5508 hasKeyboardFocus := aBoolean. |
|
5509 |
|
5510 (cursorShown |
|
5511 and:[self enabled |
|
5512 and:[self isReadOnly not]]) ifTrue:[ |
|
5513 self drawCursor |
|
5514 ]. |
|
5515 |
|
5516 hasKeyboardFocus ifFalse:[ |
|
5517 completionSupport notNil ifTrue:[ |
|
5518 "/ this is a hack for Windows: |
|
5519 "/ on windows, an activate:false event is first sent to my textView, |
|
5520 "/ then an activate is sent to the completion popup. |
|
5521 "/ this is done BEFORE the buttonPress event is delivered. |
|
5522 "/ therefore, allow for the activate of the completionMenu and it's button event to be processed. |
|
5523 "/ before forcing it to be closed... |
|
5524 Processor addTimedBlock:[completionSupport "release" editViewLostFocus] afterMilliseconds:200. |
|
5525 ]. |
|
5526 ]. |
|
5527 |
|
5528 "Modified (format): / 06-11-2013 / 15:37:31 / cg" |
|
5529 ! |
|
5530 |
|
5531 showFocus:explicit |
|
5532 "in addition to however my superclass thinks how a focusView is to be |
|
5533 displayed, show the cursor when I got the focus" |
|
5534 |
|
5535 self showCursor. |
|
5536 self hasKeyboardFocus:true. |
|
5537 super showFocus:explicit |
|
5538 |
|
5539 "Modified: 11.12.1996 / 16:56:54 / cg" |
|
5540 ! |
|
5541 |
|
5542 showNoFocus:explicit |
|
5543 "the view lost the keyboard focus |
|
5544 (either explicit, via tabbing; or implicit, by pointer movement) |
|
5545 - change any display attributes as req'd." |
|
5546 |
|
5547 super showNoFocus:explicit. |
|
5548 completionSupport notNil ifTrue:[ |
|
5549 completionSupport release. |
|
5550 ]. |
|
5551 ! |
|
5552 |
|
5553 wantsFocusWithPointerEnter |
|
5554 "return true, if I want the focus when |
|
5555 the mouse pointer enters" |
|
5556 |
|
5557 (UserPreferences current focusFollowsMouse ~~ false |
|
5558 and:[(styleSheet at:#'editText.requestFocusOnPointerEnter' default:true) |
|
5559 and:[self enabled |
|
5560 and:[true "self isReadOnly not"]]] |
|
5561 ) ifTrue:[ |
|
5562 ^ true |
|
5563 ]. |
|
5564 |
|
5565 ^ false |
|
5566 ! ! |
|
5567 |
|
5568 !EditTextView methodsFor:'formatting'! |
|
5569 |
|
5570 executekeyboardMacroNamed:macroName |
|
5571 "try to execute the keyboard macro; |
|
5572 return true if that worked, false otherwise" |
|
5573 |
|
5574 |cmdMacro| |
|
5575 |
|
5576 cmdMacro := UserPreferences current functionKeySequences at:macroName ifAbsent:[^ false]. |
|
5577 self |
|
5578 undoableDo:[ self executeKeyboardMacro:cmdMacro ] |
|
5579 info: macroName. |
|
5580 ^ true |
|
5581 |
|
5582 " |
|
5583 EditTextView open |
|
5584 contents:'bla'; |
|
5585 selectAll; |
|
5586 executekeyboardMacroNamed:#IndentBy4. |
|
5587 EditTextView open |
|
5588 contents:'bla'; |
|
5589 selectAll; |
|
5590 executekeyboardMacroNamed:#blabla. |
|
5591 " |
|
5592 |
|
5593 "Modified: / 14-02-2012 / 11:17:27 / cg" |
|
5594 ! |
|
5595 |
|
5596 indent |
|
5597 "indent a line-range - this is done by searching for the |
|
5598 last non-empty line before the selection, and changing the indent |
|
5599 of the selected line-range based on that line's indent." |
|
5600 |
|
5601 |start end| |
|
5602 |
|
5603 selectionStartLine isNil ifTrue:[^ self]. |
|
5604 |
|
5605 start := selectionStartLine. |
|
5606 end := selectionEndLine. |
|
5607 (selectionEndCol == 0) ifTrue:[ |
|
5608 end := end - 1 |
|
5609 ]. |
|
5610 self unselect. |
|
5611 self |
|
5612 undoableDo:[self indentFromLine:start toLine:end] |
|
5613 info:'Indent' |
|
5614 ! |
|
5615 |
|
5616 indentBy4 |
|
5617 self executekeyboardMacroNamed:#IndentBy4. |
|
5618 |
|
5619 "Modified: / 06-04-2011 / 18:52:40 / cg" |
|
5620 ! |
|
5621 |
|
5622 indentFromLine:start toLine:end |
|
5623 "indent a line-range - this is done by searching for the |
|
5624 last non-empty line before start, and change the indent |
|
5625 of the selected line-range based on that line's indent." |
|
5626 |
|
5627 |leftStart delta| |
|
5628 |
|
5629 leftStart := self leftIndentForLine:start. |
|
5630 (leftStart == 0) ifTrue:[^ self]. |
|
5631 |
|
5632 delta := leftStart - (self leftIndentOfLine:start). |
|
5633 (delta == 0) ifTrue:[^ self]. |
|
5634 self indentFromLine:start toLine:end by:delta |
|
5635 ! |
|
5636 |
|
5637 indentFromLine:start toLine:end by:delta |
|
5638 "indent a line-range - this is done by searching for the |
|
5639 last non-empty line before start, and change the indent |
|
5640 of the selected line-range based on that line's indent." |
|
5641 |
|
5642 |d line spaces anyChange| |
|
5643 |
|
5644 (delta == 0) ifTrue:[^ self]. |
|
5645 (delta > 0) ifTrue:[ |
|
5646 spaces := String new:delta |
|
5647 ]. |
|
5648 |
|
5649 anyChange := false. |
|
5650 start to:end do:[:lineNr | |
|
5651 line := self listAt:lineNr. |
|
5652 line notNil ifTrue:[ |
|
5653 line isBlank ifTrue:[ |
|
5654 self basicListAt:lineNr put:nil |
|
5655 ] ifFalse:[ |
|
5656 (delta > 0) ifTrue:[ |
|
5657 line := spaces , line. |
|
5658 widthOfWidestLine notNil ifTrue:[ |
|
5659 widthOfWidestLine := widthOfWidestLine max:(self widthOfLineString:line). |
|
5660 ] |
|
5661 ] ifFalse:[ |
|
5662 "check if deletion is ok" |
|
5663 d := delta negated + 1. |
|
5664 |
|
5665 line size > d ifTrue:[ |
|
5666 (line copyTo:(d - 1)) withoutSeparators isEmpty ifTrue:[ |
|
5667 line := line copyFrom:d |
|
5668 ] |
|
5669 ]. |
|
5670 widthOfWidestLine := nil |
|
5671 ]. |
|
5672 self replaceLine:lineNr with:line. |
|
5673 anyChange := true. |
|
5674 ] |
|
5675 ] |
|
5676 ]. |
|
5677 |
|
5678 anyChange ifTrue:[ self textChanged ]. |
|
5679 |
|
5680 "/ self redrawFromLine:start to:end |
|
5681 |
|
5682 "Modified: 5.3.1996 / 14:59:18 / cg" |
|
5683 ! |
|
5684 |
|
5685 leftIndentForLine:lineNr |
|
5686 "find an appropriate indent for a line. |
|
5687 this is done by searching for the last non-empty line before it |
|
5688 and returning its indent. |
|
5689 cg: changed: only look for the single previous line." |
|
5690 |
|
5691 "SHOULD GO TO ListView" |
|
5692 |
|
5693 |line lnr indent| |
|
5694 |
|
5695 lnr := lineNr. |
|
5696 |
|
5697 "/ [lnr ~~ 1] whileTrue:[ |
|
5698 (lnr ~~ 1) ifTrue:[ |
|
5699 lnr := lnr - 1. |
|
5700 line := self listAt:lnr. |
|
5701 |
|
5702 line notNil ifTrue:[ |
|
5703 indent := line indexOfNonSeparatorStartingAt:1. |
|
5704 indent ~~ 0 ifTrue:[ |
|
5705 (line endsWith:$[) ifTrue:[ |
|
5706 ^ indent + 4 - 1 |
|
5707 ]. |
|
5708 ^ indent - 1 |
|
5709 ] |
|
5710 ] |
|
5711 ]. |
|
5712 ^ 0 |
|
5713 |
|
5714 "Created: 5.3.1996 / 14:58:53 / cg" |
|
5715 ! |
|
5716 |
|
5717 undentBy4 |
|
5718 self executekeyboardMacroNamed:#UndentBy4. |
|
5719 |
|
5720 "Modified: / 06-04-2011 / 18:52:49 / cg" |
|
5721 ! ! |
|
5722 |
|
5723 !EditTextView methodsFor:'initialization'! |
|
5724 |
|
5725 fetchDeviceResources |
|
5726 "fetch device colors, to avoid reallocation at redraw time" |
|
5727 |
|
5728 super fetchDeviceResources. |
|
5729 |
|
5730 cursorFgColor notNil ifTrue:[cursorFgColor := cursorFgColor onDevice:self graphicsDevice]. |
|
5731 cursorBgColor notNil ifTrue:[cursorBgColor := cursorBgColor onDevice:self graphicsDevice]. |
|
5732 cursorNoFocusFgColor notNil ifTrue:[cursorNoFocusFgColor := cursorNoFocusFgColor onDevice:self graphicsDevice]. |
|
5733 |
|
5734 "Created: 14.1.1997 / 00:15:24 / cg" |
|
5735 "Modified: 18.2.1997 / 15:02:46 / cg" |
|
5736 ! |
|
5737 |
|
5738 initEvents |
|
5739 "enable enter/leave events in addition" |
|
5740 |
|
5741 super initEvents. |
|
5742 self enableEnterLeaveEvents |
|
5743 ! |
|
5744 |
|
5745 initStyle |
|
5746 "initialize style specific stuff" |
|
5747 |
|
5748 super initStyle. |
|
5749 "/ lineSpacing := 2. "/ for underwave - also looks better |
|
5750 lockUpdates := false. |
|
5751 |
|
5752 cursorFgColor := DefaultCursorForegroundColor. |
|
5753 cursorFgColor isNil ifTrue:[cursorFgColor := bgColor]. |
|
5754 cursorBgColor := DefaultCursorBackgroundColor. |
|
5755 cursorBgColor isNil ifTrue:[cursorBgColor := fgColor]. |
|
5756 cursorType isNil ifTrue:[cursorType := DefaultCursorType]. |
|
5757 cursorTypeNoFocus isNil ifTrue:[ |
|
5758 cursorTypeNoFocus := cursorType. |
|
5759 DefaultCursorTypeNoFocus notNil ifTrue:[ |
|
5760 cursorTypeNoFocus := DefaultCursorTypeNoFocus. |
|
5761 ] |
|
5762 ]. |
|
5763 cursorNoFocusFgColor := DefaultCursorNoFocusForegroundColor. |
|
5764 cursorNoFocusFgColor isNil ifTrue:[ |
|
5765 cursorType ~~ #block ifTrue:[ |
|
5766 cursorNoFocusFgColor := cursorBgColor |
|
5767 ] ifFalse:[ |
|
5768 cursorNoFocusFgColor := cursorFgColor |
|
5769 ] |
|
5770 ]. |
|
5771 |
|
5772 "Modified: / 15.12.1999 / 22:27:45 / cg" |
|
5773 ! |
|
5774 |
|
5775 initialize |
|
5776 "initialize a new EditTextView; |
|
5777 setup some instance variables" |
|
5778 |
|
5779 super initialize. |
|
5780 |
|
5781 self level:-1. |
|
5782 readOnly := false. |
|
5783 fixedSize := false. |
|
5784 exceptionBlock := [:errorText | ]. |
|
5785 cursorShown := prevCursorState := true. |
|
5786 cursorLine := 1. |
|
5787 cursorVisibleLine := 1. |
|
5788 cursorCol := 1. |
|
5789 cursorLineHolder := 1 asValue. |
|
5790 cursorColHolder := 1 asValue. |
|
5791 modifiedChannel := ValueHolder with:false. |
|
5792 acceptChannel := ValueHolder with:false. |
|
5793 acceptChannel addDependent:self. |
|
5794 showMatchingParenthesis := false. |
|
5795 hasKeyboardFocus := false. |
|
5796 tabMeansNextField := false. |
|
5797 autoIndent := false. |
|
5798 editMode := EditMode insertMode asValue. |
|
5799 learnMode := false asValue. |
|
5800 trimBlankLines := self st80EditMode not. |
|
5801 cursorMovementWhenUpdating := #beginOfText. |
|
5802 lastReplacementInfo := LastReplacementInfo new. |
|
5803 |
|
5804 "/ enable drop by default |
|
5805 self allowDrop:true. "/ readOnly tested in #canDrop: |
|
5806 |
|
5807 undoSupport := UndoSupport for:self. |
|
5808 codeAspectHolder := nil asValue. |
|
5809 |
|
5810 "Modified: / 27-09-2013 / 09:41:32 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
5811 ! |
|
5812 |
|
5813 initializeCompletionSupport |
|
5814 |supportClass| |
|
5815 |
|
5816 completionSupport isNil ifTrue:[ |
|
5817 (supportClass := self completionSupportClass) notNil ifTrue:[ |
|
5818 completionSupport := supportClass for:self. |
|
5819 ]. |
|
5820 ]. |
|
5821 |
|
5822 "Created: / 26-09-2013 / 17:51:45 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
5823 ! |
|
5824 |
|
5825 release |
|
5826 completionSupport notNil ifTrue:[ |
|
5827 completionSupport release |
|
5828 ]. |
|
5829 super release |
|
5830 ! ! |
|
5831 |
|
5832 !EditTextView methodsFor:'macros'! |
|
5833 |
|
5834 executeLearnedKeyboardMacro |
|
5835 "replay the characters as learned previously" |
|
5836 |
|
5837 (self learnMode not and:[learnedMacro size > 0]) ifTrue:[ |
|
5838 ExecutingMacroQuery |
|
5839 answer:true |
|
5840 do:[ |
|
5841 learnedMacro do:[:event | |
|
5842 WindowGroup lastEventQuerySignal answer:event |
|
5843 do:[ |
|
5844 self |
|
5845 dispatchEvent:event |
|
5846 withFocusOn:nil |
|
5847 delegate:false |
|
5848 ] |
|
5849 ] |
|
5850 ]. |
|
5851 ] ifFalse:[ |
|
5852 self flash. |
|
5853 ]. |
|
5854 ! |
|
5855 |
|
5856 learnMode |
|
5857 "true if currently learning" |
|
5858 |
|
5859 ^ (learnMode value ? false). |
|
5860 ! |
|
5861 |
|
5862 learnMode:aBoolean |
|
5863 "toggle the learn-mode" |
|
5864 |
|
5865 |fg bg| |
|
5866 |
|
5867 self learnModeHolder value:aBoolean. |
|
5868 |
|
5869 aBoolean ifTrue:[ |
|
5870 learnedMacro := OrderedCollection new. |
|
5871 fg := Color white. |
|
5872 bg := Color black. |
|
5873 ] ifFalse:[ |
|
5874 cursorFgColor := fg := (DefaultCursorForegroundColor ? bgColor). |
|
5875 cursorBgColor := bg := (DefaultCursorBackgroundColor ? fgColor). |
|
5876 ]. |
|
5877 self cursorForegroundColor:fg backgroundColor:bg. |
|
5878 ! |
|
5879 |
|
5880 learnModeHolder |
|
5881 "a holder returning true, if in learn mode" |
|
5882 |
|
5883 learnMode isNil ifTrue:[ |
|
5884 learnMode := false asValue |
|
5885 ]. |
|
5886 ^ learnMode |
|
5887 ! |
|
5888 |
|
5889 rememberLearnedMacroAs: nameString |
|
5890 Macros isNil ifTrue:[ |
|
5891 Macros := Dictionary new. |
|
5892 ]. |
|
5893 Macros at:nameString put:learnedMacro |
|
5894 ! |
|
5895 |
|
5896 toggleLearnMode |
|
5897 "toggle the learn-mode" |
|
5898 |
|
5899 self learnMode:(self learnMode not). |
|
5900 ! ! |
|
5901 |
|
5902 !EditTextView methodsFor:'menu & menu actions'! |
|
5903 |
|
5904 babelFishTranslate:fromToModeString |
|
5905 "translate the selected text and paste it after the selection" |
|
5906 |
|
5907 |original translated| |
|
5908 |
|
5909 original := self selectionAsString. |
|
5910 original size == 0 ifTrue:[^ self]. |
|
5911 |
|
5912 self withWaitCursorDo:[ |
|
5913 (HostNameLookupError , SOAP::SoapImplError) handle:[:ex | |
|
5914 Dialog warn:('Translation failed - WEB Service error:\\%1.' bindWith:ex description allBold) withCRs |
|
5915 ] do:[ |
|
5916 translated := SOAP::BabelFishClient new translate:original mode:fromToModeString. |
|
5917 ] |
|
5918 ]. |
|
5919 |
|
5920 "/ v pasteOrReplace:translated |
|
5921 self cursorLine:(self selectionEndLine) col:(self selectionEndCol + 1). |
|
5922 self unselect. |
|
5923 self |
|
5924 undoablePaste:translated |
|
5925 info:'Translate' |
|
5926 |
|
5927 "Modified: / 28-07-2007 / 13:27:21 / cg" |
|
5928 ! |
|
5929 |
|
5930 compareWithClipboard |
|
5931 "compare the selection against the clipboard contents" |
|
5932 |
|
5933 |t1 t2| |
|
5934 |
|
5935 t2 := self getClipboardText. |
|
5936 t2 isEmptyOrNil ifTrue:[ |
|
5937 Dialog information:'Clipboard is empty.'. |
|
5938 ^ self. |
|
5939 ]. |
|
5940 |
|
5941 self hasSelection ifTrue:[ |
|
5942 t1 := self selectionAsString. |
|
5943 ] ifFalse:[ |
|
5944 t1 := self contents asString |
|
5945 ]. |
|
5946 t1 := t1 string. |
|
5947 |
|
5948 t1 = t2 ifTrue:[ |
|
5949 Dialog information:'Strings are equal.'. |
|
5950 ^ self. |
|
5951 ]. |
|
5952 DiffTextView |
|
5953 openOn:t1 label:'Editor' |
|
5954 and:t2 label:'Clipboard' |
|
5955 ! |
|
5956 |
|
5957 cut |
|
5958 "cut selection into copybuffer" |
|
5959 |
|
5960 self deleteCopyToClipboard:true |
|
5961 ! |
|
5962 |
|
5963 defaultForGotoLine |
|
5964 "return a default value to show in the gotoLine box" |
|
5965 |
|
5966 cursorLine notNil ifTrue:[ |
|
5967 ^ cursorLine |
|
5968 ]. |
|
5969 ^ super defaultForGotoLine |
|
5970 ! |
|
5971 |
|
5972 deleteCopyToClipboard:toClipboard |
|
5973 "cut selection into copybuffer" |
|
5974 |
|
5975 |line col history sel | |
|
5976 |
|
5977 (self checkModificationsAllowed) ifFalse:[ |
|
5978 self flashReadOnly. |
|
5979 ^ self |
|
5980 ]. |
|
5981 |
|
5982 sel := self selection. |
|
5983 sel notNil ifTrue:[ |
|
5984 self setLastStringToReplace: sel. |
|
5985 |
|
5986 line := selectionStartLine. |
|
5987 col := selectionStartCol. |
|
5988 |
|
5989 toClipboard ifTrue:[ |
|
5990 " |
|
5991 remember in CopyBuffer |
|
5992 " |
|
5993 self setClipboardText:sel. "/ lastString. |
|
5994 ]. |
|
5995 |
|
5996 " |
|
5997 append to DeleteHistory (if there is one) |
|
5998 " |
|
5999 history := Smalltalk at:#DeleteHistory. |
|
6000 history notNil ifTrue:[ |
|
6001 history addAll:(sel asStringCollection). |
|
6002 history size > 1000 ifTrue:[ |
|
6003 history := history copyFrom:(history size - 1000) |
|
6004 ]. |
|
6005 ]. |
|
6006 |
|
6007 " |
|
6008 now, delete it |
|
6009 " |
|
6010 self |
|
6011 undoableDo:[self deleteSelection] |
|
6012 info:'Delete'. |
|
6013 lastReplacementInfo lastReplacement: nil |
|
6014 ] ifFalse:[ |
|
6015 " |
|
6016 a cut without selection will search&cut again |
|
6017 " |
|
6018 self undoableDo:[ |
|
6019 self again |
|
6020 ] |
|
6021 ] |
|
6022 |
|
6023 "Modified: / 5.4.1998 / 16:51:53 / cg" |
|
6024 ! |
|
6025 |
|
6026 editMenu |
|
6027 "return the views middleButtonMenu" |
|
6028 |
|
6029 <resource: #keyboard (#Again #AgainForAll #Copy #Cut #Paste #Accept |
|
6030 #Find #GotoLine #SaveAs #Print |
|
6031 #PasteFromHistory #Join #Wrap #Undo #Redo |
|
6032 #ToggleAutoIndent #ToggleInsertMode |
|
6033 #LearnKeyboardMacro #ExecuteKeyboardMacro )> |
|
6034 <resource: #programMenu> |
|
6035 |
|
6036 |items m sub translateItems sortItems miscItems toolItems subSub toolSub |
|
6037 transSub sortSub what undoIdx redoIdx sensor main mainItems| |
|
6038 |
|
6039 items := #( |
|
6040 ('Redo' redo Redo ) |
|
6041 ('Again (for All)' multipleAgain AgainForAll ) |
|
6042 ('-' ) |
|
6043 ('Search...' search Find ) |
|
6044 ('Goto Line...' gotoLine GotoLine ) |
|
6045 ('-' ) |
|
6046 ('Tools' tools ) |
|
6047 ('Insert Unicode...' insertUnicode ) |
|
6048 ). |
|
6049 CharacterSetView notNil ifTrue:[ |
|
6050 items := items , |
|
6051 #( |
|
6052 ('Special Characters...' specialCharacters OpenSpecialCharacterWindow ) |
|
6053 ). |
|
6054 ]. |
|
6055 items := items , #( |
|
6056 ('-' ) |
|
6057 ('Save As...' save SaveAs ) |
|
6058 ('Print' doPrint Print ) |
|
6059 ('=' ) |
|
6060 ('Misc' misc ShiftCtrl) ). |
|
6061 |
|
6062 miscItems := #( |
|
6063 ('AutoIndent \c' autoIndent: ToggleAutoIndent ) |
|
6064 ('InsertMode \c' insertMode: ToggleInsertMode ) |
|
6065 ('-' ) |
|
6066 ('Paste Previous...' pasteOrReplaceFromHistory PasteFromHistory ) |
|
6067 ('Join Lines' joinLines Join ) |
|
6068 ('Wrap Lines...' wrapLines Wrap ) |
|
6069 ('-' ) |
|
6070 ('Learn Macro' learnMode: LearnKeyboardMacro) |
|
6071 ('Execute Macro' executeLearnedKeyboardMacro ExecuteKeyboardMacro ) |
|
6072 ('-' ) |
|
6073 ('Insert File...' insertFile ) |
|
6074 ('Insert URL Contents...' insertURL ) |
|
6075 ('Insert new UUID' insertUUID ) |
|
6076 ('Insert Date && Time' insertDateAndTime ) |
|
6077 ('-' ) |
|
6078 ('Insert File as String Literal...' insertFileAsStringLiteral ) |
|
6079 ('Paste as String Literal' pasteAsStringLiteral ) |
|
6080 ('-' ) |
|
6081 ). |
|
6082 "/ CharacterSetView notNil ifTrue:[ |
|
6083 "/ miscItems := miscItems , |
|
6084 "/ #( |
|
6085 "/ ('Special Characters...' specialCharacters OpenSpecialCharacterWindow ) |
|
6086 "/ ). |
|
6087 "/ ]. |
|
6088 miscItems := miscItems , |
|
6089 #( |
|
6090 ('Font...' changeFont ) |
|
6091 "/ ('Encoding...' changeEncoding ) |
|
6092 ). |
|
6093 |
|
6094 translateItems := #( |
|
6095 ('English -> German' (babelFishTranslate: 'en_de') ) |
|
6096 ('English -> French' (babelFishTranslate: 'en_fr') ) |
|
6097 ('English -> Italian' (babelFishTranslate: 'en_it') ) |
|
6098 ('English -> Spanish' (babelFishTranslate: 'en_es') ) |
|
6099 ('English -> Portuguese' (babelFishTranslate: 'en_pt') ) |
|
6100 ('-' ) |
|
6101 ('German -> English' (babelFishTranslate: 'de_en') ) |
|
6102 ('French -> English' (babelFishTranslate: 'fr_en') ) |
|
6103 ('Italian -> English' (babelFishTranslate: 'it_en') ) |
|
6104 ('Spanish -> English' (babelFishTranslate: 'es_en') ) |
|
6105 ('Portuguese -> English' (babelFishTranslate: 'pt_en') ) |
|
6106 ). |
|
6107 |
|
6108 sortItems := #( |
|
6109 ('Lines' (sortSelection:ignoreCase: #lines false) ) |
|
6110 ('Lines by First Word' (sortSelection:ignoreCase: #linesByFirstWord false) ) |
|
6111 ('Lines by n''th Word' (sortSelection:ignoreCase: #linesByNthWord false) ) |
|
6112 ('Lines by n''th Number' (sortSelection:ignoreCase: #linesByNthNumber false) ) |
|
6113 ('Lines by n''th Hex Number' (sortSelection:ignoreCase: #linesByNthHexNumber false) ) |
|
6114 ('Words' (sortSelection:ignoreCase: #words false) ) |
|
6115 ('-' ) |
|
6116 ('Lines (ignore case)' (sortSelection:ignoreCase: #lines true) ) |
|
6117 ('Lines by First Word (ignore case)' (sortSelection:ignoreCase: #linesByFirstWord true) ) |
|
6118 ('Lines by n''th Word (ignore case)' (sortSelection:ignoreCase: #linesByNthWord true) ) |
|
6119 ('Words (ignore case)' (sortSelection:ignoreCase: #words true) ) |
|
6120 ('-' ) |
|
6121 ('By Line Length' (sortSelection:ignoreCase: #linesByLength nil) ) |
|
6122 ('Reverse' (sortSelection:ignoreCase: #reverse nil) ) |
|
6123 ). |
|
6124 |
|
6125 toolItems := #( |
|
6126 ('Indent' indent ) |
|
6127 ('Toggle Case' convertSelectionToLowercaseOrUppercaseOrUppercaseFirst ConvertSelectionToLowercaseOrUppercaseOrUppercaseFirst) |
|
6128 ('Sort' sort ) |
|
6129 ('-' ) |
|
6130 ('Google Spell Check' googleSpellingSuggestion ) |
|
6131 ('Builtin Spell Check' internalSpellingSuggestion ) |
|
6132 ('Translate' babelFishTranslate ) |
|
6133 ('Compare with Clipboard...' compareWithClipboard ) |
|
6134 ). |
|
6135 |
|
6136 Smalltalk isStandAloneApp ifFalse:[ |
|
6137 toolItems := toolItems , #( |
|
6138 ('-' ) |
|
6139 ('Open FileBrowser on It' openFileBrowserOnIt ) |
|
6140 ('Open Workspace with It' openWorkspaceWithIt ) |
|
6141 ). |
|
6142 ]. |
|
6143 |
|
6144 sub := PopUpMenu itemList:items resources:resources performer:model. |
|
6145 sub receiver:self. |
|
6146 |
|
6147 toolSub := PopUpMenu itemList:toolItems resources:resources performer:model. |
|
6148 toolSub receiver:self. |
|
6149 sub subMenuAt:#tools put:toolSub. |
|
6150 |
|
6151 transSub := PopUpMenu itemList:translateItems resources:resources performer:model. |
|
6152 transSub receiver:self. |
|
6153 toolSub subMenuAt:#babelFishTranslate put:transSub. |
|
6154 |
|
6155 sortSub := PopUpMenu itemList:sortItems resources:resources performer:model. |
|
6156 sortSub receiver:self. |
|
6157 toolSub subMenuAt:#sort put:sortSub. |
|
6158 |
|
6159 subSub := PopUpMenu itemList:miscItems resources:resources performer:model. |
|
6160 subSub receiver:self. |
|
6161 subSub checkToggleAt:#autoIndent: put:autoIndent. |
|
6162 subSub checkToggleAt:#insertMode: put:(self isInInsertMode). |
|
6163 subSub checkToggleAt:#learnMode: put:(self learnModeHolder value). |
|
6164 |
|
6165 sub subMenuAt:#misc put:subSub. |
|
6166 |
|
6167 mainItems := #( |
|
6168 ('Undo' undo Undo ) |
|
6169 ('Again' again Again ) |
|
6170 ('-' ) |
|
6171 ('Cut' cut Cut ) |
|
6172 ('Copy' copySelection Copy ) |
|
6173 ('Paste' pasteOrReplace Paste ) |
|
6174 ('-' ) |
|
6175 ('Accept' accept Accept ) |
|
6176 ('=' ) |
|
6177 ('More' others Ctrl ) |
|
6178 ). |
|
6179 main := PopUpMenu itemList:mainItems resources:resources. |
|
6180 main subMenuAt:#others put:sub. |
|
6181 |
|
6182 sensor := self sensor. |
|
6183 (sensor notNil and:[sensor ctrlDown]) ifTrue:[ |
|
6184 sensor shiftDown ifTrue:[ |
|
6185 m := subSub |
|
6186 ] ifFalse:[ |
|
6187 m := sub |
|
6188 ] |
|
6189 ] ifFalse:[ |
|
6190 m := main |
|
6191 ]. |
|
6192 |
|
6193 "/ the 'Smalltalk at:' code is here to |
|
6194 "/ avoid making the SOAP package a prerequisite for this package (libwidg) |
|
6195 (Smalltalk at:#'SOAP::GoogleClient') isNil ifTrue:[ |
|
6196 "/ GoogleClient new spellingSuggestionOf: 'Smmalltlaak and Soaap'. |
|
6197 m disable:#googleSpellingSuggestion |
|
6198 ]. |
|
6199 (Smalltalk at:#'RBSpellChecker') isNil ifTrue:[ |
|
6200 m disable:#internalSpellingSuggestion |
|
6201 ]. |
|
6202 |
|
6203 HTTPInterface isNil ifTrue:[ |
|
6204 m disableAll:#(insertURL) |
|
6205 ]. |
|
6206 |
|
6207 self isReadOnly ifTrue:[ |
|
6208 m disableAll:#(accept undo again multipleAgain redo |
|
6209 paste pasteOrReplace pasteOrReplaceFromHistory |
|
6210 cut indent autoIndent: insertMode: |
|
6211 insertFile insertFileAsStringLiteral insertURL |
|
6212 babelFishTranslate googleSpellingSuggestion sort |
|
6213 convertSelectionToLowercaseOrUppercaseOrUppercaseFirst |
|
6214 joinLines wrapLines insertUUID insertDateAndTime pasteAsStringLiteral |
|
6215 insertUnicode specialCharacters) |
|
6216 ]. |
|
6217 self hasSelectionForCopy ifFalse:[ |
|
6218 m disable:#copySelection. |
|
6219 ]. |
|
6220 self hasSelection ifFalse:[ |
|
6221 m disableAll:#(cut googleSpellingSuggestion babelFishTranslate openFileBrowserOnIt openWorkspaceWithIt sort indent). |
|
6222 ] ifTrue:[ |
|
6223 (Error handle:[:ex | |
|
6224 ex return:false |
|
6225 ] do:[ |
|
6226 |fn| |
|
6227 fn := self selectionAsString. |
|
6228 fn asFilename exists or:[ fn withoutSeparators withoutQuotes asFilename exists ] |
|
6229 ]) ifFalse:[ |
|
6230 m disableAll:#(openFileBrowserOnIt). |
|
6231 ] |
|
6232 ]. |
|
6233 self hasUndoAction ifFalse:[ |
|
6234 m disable:#undo. |
|
6235 ] ifTrue:[ |
|
6236 what := undoSupport undoActionInfo. |
|
6237 what notNil ifTrue:[ |
|
6238 undoIdx := m indexOf:#undo. |
|
6239 m labelAt:undoIdx put:(resources string:'Undo (%1)' with:what). |
|
6240 ] |
|
6241 ]. |
|
6242 self hasRedoAction ifFalse:[ |
|
6243 sub disable:#redo. |
|
6244 ] ifTrue:[ |
|
6245 what := undoSupport redoActionInfo. |
|
6246 what notNil ifTrue:[ |
|
6247 redoIdx := sub indexOf:#redo. |
|
6248 sub labelAt:redoIdx put:(resources string:'Redo (%1)' with:what). |
|
6249 ] |
|
6250 ]. |
|
6251 acceptEnabled == false ifTrue:[ |
|
6252 m disable:#accept |
|
6253 ]. |
|
6254 ^ m. |
|
6255 |
|
6256 "Modified: / 01-03-2012 / 19:56:58 / cg" |
|
6257 ! |
|
6258 |
|
6259 getTextSelectionFromHistory |
|
6260 |sel list box history| |
|
6261 |
|
6262 history := self graphicsDevice getCopyBufferHistory copy. |
|
6263 list := history collect:[:entry | |
|
6264 |text shown| |
|
6265 |
|
6266 text := entry asString string asCollectionOfLines. |
|
6267 shown := text detect:[:line| line notEmptyOrNil] ifNone:[' ']. |
|
6268 text size > 1 ifTrue:[ |
|
6269 shown := shown,(resources string:' ... [%1 lines]' with:text size). |
|
6270 ]. |
|
6271 shown |
|
6272 ]. |
|
6273 |
|
6274 box := ListSelectionBox |
|
6275 title:(resources string:'Clipboard History') |
|
6276 okText:(resources string:'Paste') |
|
6277 abortText:(resources string:'Cancel') |
|
6278 list:list |
|
6279 action:[:idx | idx notNil ifTrue:[sel := history at:idx]]. |
|
6280 box label:(resources string:'Select Previous Copybuffer String'). |
|
6281 box useIndex:true. |
|
6282 box show. |
|
6283 ^ sel. |
|
6284 |
|
6285 "Modified: / 25-08-2010 / 22:02:14 / cg" |
|
6286 ! |
|
6287 |
|
6288 getTextSelectionOrTextSelectionFromHistory |
|
6289 |
|
6290 self sensor shiftDown ifTrue:[ |
|
6291 ^ self getTextSelectionFromHistory |
|
6292 ]. |
|
6293 |
|
6294 "/ return either the (xterm-) selection or the clipBoard depending on |
|
6295 "/ the Ctrl-Key state. |
|
6296 |
|
6297 "/ ouch - this used to be ok for ALT-c / ALT-v, |
|
6298 "/ but no longer works with CTRL-c / CTRL-v. |
|
6299 ^ self getClipboardText:#clipboard |
|
6300 |
|
6301 "/ ^ self |
|
6302 "/ getClipboardText:(self sensor ctrlDown |
|
6303 "/ ifTrue:[#selection] |
|
6304 "/ ifFalse:[#clipboard]) |
|
6305 |
|
6306 "Modified: / 13-07-2011 / 14:55:58 / cg" |
|
6307 ! |
|
6308 |
|
6309 googleSpellingSuggestion |
|
6310 "insert the google-spelling suggestion for the selected text. |
|
6311 Requires that the SOAP stuff is loaded and working." |
|
6312 |
|
6313 |text suggestion| |
|
6314 |
|
6315 self withWaitCursorDo:[ |
|
6316 text := self selection asString string withoutSeparators. |
|
6317 text size == 0 ifTrue:[^ self]. |
|
6318 |
|
6319 "/ the 'Smalltalk at:' code is here to |
|
6320 "/ avoid making the SOAP package a prerequisite for this package (libwidg) |
|
6321 (Smalltalk at:#'SOAP::SoapImplError') handle:[:ex | |
|
6322 Dialog warn:('Spelling correction failed - WEB Service error:\\%1.' bindWith:ex description allBold) withCRs. |
|
6323 ^ self. |
|
6324 ] do:[ |
|
6325 suggestion := (Smalltalk at:#'SOAP::GoogleClient') new spellingSuggestionOf:text. |
|
6326 ]. |
|
6327 suggestion size == 0 ifTrue:[ |
|
6328 self information:('No spelling suggestion from Google for: ' , text). |
|
6329 Transcript showCR:('No spelling suggestion from Google for: ' , text). |
|
6330 ^ self. |
|
6331 ]. |
|
6332 ]. |
|
6333 self |
|
6334 undoablePaste:suggestion |
|
6335 info:'Spelling Suggestion'. |
|
6336 |
|
6337 "Modified: / 28-07-2007 / 13:25:10 / cg" |
|
6338 ! |
|
6339 |
|
6340 insertDateAndTime |
|
6341 "insert the curent date and time string" |
|
6342 |
|
6343 typeOfSelection := nil. |
|
6344 self |
|
6345 undoableDo:[ self pasteOrReplace:(Timestamp now printStringRFC1123Format)] |
|
6346 info:'Paste Date and Time' |
|
6347 ! |
|
6348 |
|
6349 insertFile |
|
6350 "insert contents of a file |
|
6351 - ask user for filename using a fileSelectionBox." |
|
6352 |
|
6353 self insertFileAsStringLiteral:false |
|
6354 ! |
|
6355 |
|
6356 insertFileAsStringLiteral |
|
6357 "insert a file's contents as a string literal. |
|
6358 Almost the same as the insert file, but single-quotes are doubled, |
|
6359 to make it a legal string literal" |
|
6360 |
|
6361 self insertFileAsStringLiteral:true |
|
6362 ! |
|
6363 |
|
6364 insertFileAsStringLiteral:asStringLiteral |
|
6365 "insert contents of a file; either as-is or as a string literal. |
|
6366 - ask user for filename using a fileSelectionBox." |
|
6367 |
|
6368 |sel selFn file text ok initial| |
|
6369 |
|
6370 ((sel := self selectionAsString) notEmptyOrNil |
|
6371 and:[ (selFn := sel asFilename) exists |
|
6372 and:[ selFn isRegularFile ]]) |
|
6373 ifTrue:[ |
|
6374 initial := selFn pathName. |
|
6375 ]. |
|
6376 |
|
6377 [ |
|
6378 |why| |
|
6379 |
|
6380 file := Dialog |
|
6381 requestFileName:(resources string:'Insert Contents Of:') |
|
6382 default:initial |
|
6383 ok:(resources string:'Insert') |
|
6384 abort:(resources string:'Cancel') |
|
6385 pattern:nil |
|
6386 fromDirectory:directoryForFileDialog. |
|
6387 file isNil ifTrue:[ |
|
6388 "cancel" |
|
6389 ^ self. |
|
6390 ]. |
|
6391 file := file asFilename. |
|
6392 directoryForFileDialog := file. |
|
6393 |
|
6394 ok := file isReadable and:[file isDirectory not]. |
|
6395 ok ifFalse:[ |
|
6396 file isReadable ifFalse:[ |
|
6397 why := '%1 is unreadable.\\Please try again.' |
|
6398 ] ifTrue:[ |
|
6399 why := '%1 is a directory.\\Please try again.' |
|
6400 ]. |
|
6401 Dialog warn:(resources stringWithCRs:why with:file pathName). |
|
6402 ]. |
|
6403 ] doUntil:[ok]. |
|
6404 |
|
6405 text := file contentsOfEntireFile. |
|
6406 self |
|
6407 undoableDo:[ self paste:(asStringLiteral ifTrue:[text storeString] ifFalse:[text]) ] |
|
6408 info:'Paste File' |
|
6409 |
|
6410 "Modified: / 28-07-2007 / 13:23:32 / cg" |
|
6411 ! |
|
6412 |
|
6413 insertURL |
|
6414 "insert contents of a URL |
|
6415 - ask user for URL using a dialog." |
|
6416 |
|
6417 self insertURLAsStringLiteral:false |
|
6418 ! |
|
6419 |
|
6420 insertURLAsStringLiteral:asStringLiteral |
|
6421 "insert contents of a file; either as-is or as a string literal. |
|
6422 - ask user for filename using a fileSelectionBox." |
|
6423 |
|
6424 |sel url text response initial| |
|
6425 |
|
6426 (sel := self selectionAsString) notEmptyOrNil |
|
6427 ifTrue:[ |
|
6428 initial := sel. |
|
6429 ]. |
|
6430 |
|
6431 url := Dialog |
|
6432 request:(resources string:'Insert Contents of URL:') |
|
6433 initialAnswer:initial |
|
6434 okLabel:(resources string:'Insert') |
|
6435 title:(resources string:'URL'). |
|
6436 url isNil ifTrue:[ |
|
6437 "cancel" |
|
6438 ^ self. |
|
6439 ]. |
|
6440 response := HTTPInterface get:url. |
|
6441 response isErrorResponse ifTrue:[ |
|
6442 Dialog warn:(resources string:'Could not fetch the document: %1' with:url). |
|
6443 ^ self. |
|
6444 ]. |
|
6445 text := response data asString. |
|
6446 |
|
6447 self |
|
6448 undoableDo:[ |
|
6449 self paste:(asStringLiteral ifTrue:[text storeString] ifFalse:[text]) |
|
6450 ] |
|
6451 info:'Insert Contents of URL' |
|
6452 ! |
|
6453 |
|
6454 insertUUID |
|
6455 "insert a new UUID's string" |
|
6456 |
|
6457 typeOfSelection := nil. |
|
6458 self |
|
6459 undoableDo:[ self pasteOrReplace:(UUID genUUID printString)] |
|
6460 info:'Paste New UUID' |
|
6461 |
|
6462 "Created: / 28-07-2007 / 13:01:16 / cg" |
|
6463 ! |
|
6464 |
|
6465 insertUnicode |
|
6466 "open a Dialog requesting an integer value and insert it as unicode character" |
|
6467 |
|
6468 |unicodePoint unicodeChar unicodeString| |
|
6469 |
|
6470 unicodeString := Dialog request:'Enter unicode (U+01FF or decimal number):'. |
|
6471 unicodeString size < 2 ifTrue:[ |
|
6472 ^ self. |
|
6473 ]. |
|
6474 (unicodeString second = $+ and:['Uu' includes:unicodeString first]) ifTrue:[ |
|
6475 unicodePoint := Integer readFrom:(unicodeString copyFrom:3) radix:16 onError:[^ self]. |
|
6476 ] ifFalse:[ |
|
6477 unicodePoint := Integer readFrom:unicodeString onError:[^ self]. |
|
6478 ]. |
|
6479 |
|
6480 unicodeChar := Character value:unicodePoint. |
|
6481 self keyPress:unicodeChar x:0 y:0. |
|
6482 self keyRelease:unicodeChar x:0 y:0. |
|
6483 ! |
|
6484 |
|
6485 internalSpellingSuggestion |
|
6486 "insert the internal-spelling suggestion for the selected text. |
|
6487 Requires that the RefactoryBrowser/line/spelCheck stuff is loaded." |
|
6488 |
|
6489 |text suggestions best| |
|
6490 |
|
6491 self withWaitCursorDo:[ |
|
6492 text := self selection asString string withoutSeparators. |
|
6493 text size == 0 ifTrue:[^ self]. |
|
6494 |
|
6495 suggestions := RBSpellChecker default bestMatchesFor:text. |
|
6496 suggestions size == 0 ifTrue:[ |
|
6497 self information:('No spelling suggestion from builtin checker for: ' , text). |
|
6498 Transcript showCR:('No spelling suggestion from builtin checker for: ' , text). |
|
6499 ^ self. |
|
6500 ]. |
|
6501 Transcript showCR:suggestions. |
|
6502 best := suggestions first. |
|
6503 ]. |
|
6504 self |
|
6505 undoablePaste:best |
|
6506 info:'Spelling Suggestion'. |
|
6507 ! |
|
6508 |
|
6509 openFileBrowserOnFileNamed:fileNameString |
|
6510 "open a fileBrowser on the given fileNameString" |
|
6511 |
|
6512 |fn| |
|
6513 |
|
6514 fn := fileNameString asFilename. |
|
6515 fn exists ifFalse:[ |
|
6516 fn := fileNameString withoutSeparators withoutQuotes asFilename. |
|
6517 fn exists ifFalse:[ |
|
6518 ^ self warn:'Oops - file is gone'. |
|
6519 ]. |
|
6520 ]. |
|
6521 UserPreferences fileBrowserClass openOn:fn |
|
6522 |
|
6523 "Modified: / 06-09-2012 / 14:47:22 / cg" |
|
6524 ! |
|
6525 |
|
6526 openFileBrowserOnIt |
|
6527 "open a fileBrowser on the selected fileName" |
|
6528 |
|
6529 |fileNameString| |
|
6530 |
|
6531 fileNameString := self selectionAsString. |
|
6532 self openFileBrowserOnFileNamed:fileNameString |
|
6533 |
|
6534 "Modified: / 06-09-2012 / 14:47:22 / cg" |
|
6535 ! |
|
6536 |
|
6537 openWorkspaceWithIt |
|
6538 "open a workspace containing the selected text" |
|
6539 |
|
6540 |text| |
|
6541 |
|
6542 text := self selectionAsString. |
|
6543 WorkspaceApplication openWith:text selected:true |
|
6544 |
|
6545 "Created: / 26-05-2007 / 06:05:22 / cg" |
|
6546 ! |
|
6547 |
|
6548 paste |
|
6549 "paste the copybuffer; if there is a selection, unselect first. |
|
6550 Then paste at cursor position." |
|
6551 |
|
6552 self checkModificationsAllowed ifTrue:[ |
|
6553 self withSelfAndTextForPasteDo:[:me :text | |
|
6554 me unselect. |
|
6555 me undoablePaste:text |
|
6556 ] |
|
6557 ] |
|
6558 ! |
|
6559 |
|
6560 paste:someText |
|
6561 "paste someText at cursor" |
|
6562 |
|
6563 self paste:someText withCR:false |
|
6564 ! |
|
6565 |
|
6566 paste:someText withCR:withCR |
|
6567 "paste someText at cursor" |
|
6568 |
|
6569 |s nLines startLine startCol l1 l2 c1 c2 codingErrorReported| |
|
6570 |
|
6571 self checkModificationsAllowed ifFalse:[^ self]. |
|
6572 someText isNil ifTrue:[^ self]. |
|
6573 |
|
6574 s := someText. |
|
6575 codingErrorReported := false. |
|
6576 CharacterEncoderError handle:[:ex | |
|
6577 |code msg| |
|
6578 |
|
6579 code := ex parameter. |
|
6580 codingErrorReported ifFalse:[ |
|
6581 msg := 'Cannot represent pasted string in this Views encoding (',gc characterEncoding,').'. |
|
6582 code notNil ifTrue:[ |
|
6583 msg := msg , '\\Reason: No representation for ' , (code radixPrintStringRadix:16). |
|
6584 ]. |
|
6585 Dialog warn:(resources stringWithCRs:msg). |
|
6586 codingErrorReported := true. |
|
6587 ]. |
|
6588 ex proceedWith:ex defaultValue |
|
6589 ] do:[ |
|
6590 s isString ifTrue:[ |
|
6591 s encoding ~~ gc characterEncoding ifTrue:[ |
|
6592 s := s encodeFrom:(s encoding) into:gc characterEncoding. |
|
6593 ]. |
|
6594 |
|
6595 s := s asStringCollection. |
|
6596 (someText endsWith:Character cr) ifTrue:[ |
|
6597 "/ s := s copyWith:nil. |
|
6598 s := s copyWith:'' "/ an empty line at the end |
|
6599 |
|
6600 ] |
|
6601 ] ifFalse:[ |
|
6602 s isStringCollection ifTrue:[ |
|
6603 s := s encodeFrom:(s encoding) into:gc characterEncoding. |
|
6604 ] ifFalse:[ |
|
6605 (self |
|
6606 confirm:(resources |
|
6607 stringWithCRs:'Selection (%1) is not convertable to Text.\\Paste storeString ?' |
|
6608 with:s class name)) ifFalse:[^ self]. |
|
6609 s := StringCollection with:s storeString . |
|
6610 "/ ^ self |
|
6611 ]. |
|
6612 ]. |
|
6613 ]. |
|
6614 |
|
6615 (nLines := s size) == 0 ifTrue:[^ self]. |
|
6616 (nLines == 1 and:[(s at:1) size == 0]) ifTrue:[^ self]. |
|
6617 |
|
6618 typeOfSelection := #paste. |
|
6619 |
|
6620 startLine := l1 := cursorLine. |
|
6621 startCol := c1 := cursorCol. |
|
6622 |
|
6623 "do not expand tabs into spaces here - |
|
6624 they get expanded in basicWithoutRedrawInsertStringWithoutCRs:aString atLine:lineNr col:colNr. |
|
6625 Some Subviews want to paste with unexpanded tabs!!" |
|
6626 |
|
6627 self insertLines:s withCR:withCR. |
|
6628 l2 := cursorLine. |
|
6629 c2 := (cursorCol - 1). |
|
6630 self selectFromLine:l1 col:c1 toLine:l2 col:c2. |
|
6631 typeOfSelection := #paste. "/ sigh - cleared by #selectFromLine: |
|
6632 |
|
6633 "Modified: / 14-02-1996 / 11:14:14 / stefan" |
|
6634 "Modified: / 25-01-2012 / 00:31:30 / cg" |
|
6635 ! |
|
6636 |
|
6637 pasteAsStringLiteral |
|
6638 "insert clipboard string as a string literal. |
|
6639 Almost the same as a normal paste, but single-quotes are doubled, |
|
6640 to make it a legal string literal" |
|
6641 |
|
6642 typeOfSelection := nil. |
|
6643 self |
|
6644 undoableDo:[ self pasteOrReplace:(self getClipboardText storeString) ] |
|
6645 info:'Paste as String Literal' |
|
6646 ! |
|
6647 |
|
6648 pasteOrReplace |
|
6649 "paste the copybuffer; if there is a selection, replace it. |
|
6650 otherwise paste at cursor position. |
|
6651 Replace is not done for selections which were created by a paste, |
|
6652 to allow multiple paste operations in a row." |
|
6653 |
|
6654 self withSelfAndTextForPasteDo:[:me :text | me pasteOrReplace:text] |
|
6655 ! |
|
6656 |
|
6657 pasteOrReplace:someText |
|
6658 "paste someText; if there is a selection, replace it. |
|
6659 otherwise paste at cursor position. Replace is not done |
|
6660 for originating by a paste, to allow multiple |
|
6661 paste." |
|
6662 |
|
6663 self checkModificationsAllowed ifFalse:[^ self]. |
|
6664 |
|
6665 self undoableDo:[ |
|
6666 ((self hasSelection == true) and:[typeOfSelection ~~ #paste]) ifTrue:[ |
|
6667 self replace:someText |
|
6668 ] ifFalse:[ |
|
6669 self paste:someText. |
|
6670 ] |
|
6671 ] info:'Paste/Replace'. |
|
6672 |
|
6673 "Modified: / 30.1.2000 / 02:33:00 / cg" |
|
6674 ! |
|
6675 |
|
6676 pasteOrReplaceFromHistory |
|
6677 "paste a previous item from the copybuffer history. |
|
6678 (i.e. repaste some previously deleted or copied text)" |
|
6679 |
|
6680 |text| |
|
6681 |
|
6682 self checkModificationsAllowed ifFalse:[ |
|
6683 self flashReadOnly. |
|
6684 ^ self |
|
6685 ]. |
|
6686 text := self getTextSelectionFromHistory. |
|
6687 text notNil ifTrue:[ |
|
6688 self pasteOrReplace:text |
|
6689 ] |
|
6690 ! |
|
6691 |
|
6692 replace |
|
6693 "replace the selection by the contents of the copybuffer" |
|
6694 |
|
6695 self hasSelection ifFalse:[^ self]. |
|
6696 self checkModificationsAllowed ifFalse:[^ self]. |
|
6697 |
|
6698 self withSelfAndTextForPasteDo:[:me :text | |
|
6699 me undoableDo:[ me replace:text ] |
|
6700 info:'Replace' |
|
6701 ] |
|
6702 ! |
|
6703 |
|
6704 replace:someText |
|
6705 "replace the selection by someText" |
|
6706 |
|
6707 |selected selectedString |
|
6708 selStartLine selStartCol selEndLine selEndCol| |
|
6709 |
|
6710 self checkModificationsAllowed ifFalse:[^ self]. |
|
6711 |
|
6712 self undoableDo:[ |
|
6713 selected := self selection. |
|
6714 selected isNil ifTrue:[ |
|
6715 ^ self paste:someText |
|
6716 ]. |
|
6717 |
|
6718 self deleteSelection. |
|
6719 |
|
6720 "take care, if we replace a selection without space by a word selected |
|
6721 with one - in this case we usually do not want the space. |
|
6722 But, if we replace a word-selected selection by something without a |
|
6723 space, we DO want the space added." |
|
6724 |
|
6725 selected size == 1 ifTrue:[ |
|
6726 selectedString := selected at:1. |
|
6727 ]. |
|
6728 |
|
6729 someText size == 1 ifTrue:[ |
|
6730 |cutOffSpace addSpace replacement replacementString| |
|
6731 |
|
6732 cutOffSpace := false. |
|
6733 addSpace := false. |
|
6734 replacement := someText copyFrom:1. |
|
6735 |
|
6736 selectedString notNil ifTrue:[ |
|
6737 ((selectedString startsWith:' ') or:[selectedString endsWith:' ']) ifFalse:[ |
|
6738 "selection has no space" |
|
6739 |
|
6740 ((selectStyle == #wordleft) or:[selectStyle == #wordRight]) ifTrue:[ |
|
6741 cutOffSpace := true |
|
6742 ] |
|
6743 ] ifTrue:[ |
|
6744 addSpace := true |
|
6745 ] |
|
6746 ]. |
|
6747 replacementString := replacement at:1. |
|
6748 cutOffSpace ifTrue:[ |
|
6749 (replacementString startsWith:' ') ifTrue:[ |
|
6750 replacementString := replacementString withoutSpaces |
|
6751 ]. |
|
6752 ] ifFalse:[ |
|
6753 selectStyle == #wordLeft ifTrue:[ |
|
6754 "want a space at left" |
|
6755 (replacementString startsWith:' ') ifFalse:[ |
|
6756 replacementString := replacementString withoutSpaces. |
|
6757 replacementString := ' ' , replacementString |
|
6758 ] |
|
6759 ]. |
|
6760 selectStyle == #wordRight ifTrue:[ |
|
6761 "want a space at right" |
|
6762 |
|
6763 (replacementString endsWith:' ') ifFalse:[ |
|
6764 replacementString := replacementString withoutSpaces. |
|
6765 replacementString := replacementString , ' ' |
|
6766 ] |
|
6767 ]. |
|
6768 ]. |
|
6769 replacement at:1 put: replacementString. |
|
6770 self paste:replacement. |
|
6771 ] ifFalse:[ |
|
6772 self paste:someText |
|
6773 ]. |
|
6774 self setLastStringToReplace: selectedString. |
|
6775 |
|
6776 lastReplacementInfo lastReplacement: someText. |
|
6777 |
|
6778 selStartLine := selectionStartLine. |
|
6779 selStartCol := self selectionStartCol. |
|
6780 selEndLine := selectionEndLine. |
|
6781 selEndCol := self selectionEndCol. |
|
6782 ] |
|
6783 info:'Replace' |
|
6784 |
|
6785 "Modified: / 14.2.1996 / 10:37:02 / stefan" |
|
6786 "Modified: / 5.4.1998 / 16:55:28 / cg" |
|
6787 ! |
|
6788 |
|
6789 searchReplace |
|
6790 "search for a string - show a box to enter searchpattern |
|
6791 replace for the found searchpattern or replace all searchpattern found to a new pattern - show a box to enter replacepattern |
|
6792 - currently no regular expressions are handled." |
|
6793 |
|
6794 |searchBox patternHolder replacePatternHolder caseHolder flag ign initialString bindings bldr search modal replace action| |
|
6795 |
|
6796 modal := false "(UserPreferences current searchDialogIsModal)". |
|
6797 lastSearchDirection := #forward. |
|
6798 ign := lastSearchIgnoredCase ? LastSearchIgnoredCase ? true. |
|
6799 caseHolder := ign asValue. |
|
6800 patternHolder := '' asValue. |
|
6801 replacePatternHolder := '' asValue. |
|
6802 lastSearchPattern notNil ifTrue:[ |
|
6803 initialString := lastSearchPattern |
|
6804 ]. |
|
6805 self hasSelectionWithinSingleLine ifTrue:[ |
|
6806 initialString := self selectionAsString |
|
6807 ]. |
|
6808 initialString isNil ifTrue:[ |
|
6809 LastSearchPatterns size > 0 ifTrue:[ |
|
6810 initialString := LastSearchPatterns first |
|
6811 ] |
|
6812 ]. |
|
6813 initialString notNil ifTrue:[ |
|
6814 patternHolder value:initialString. |
|
6815 replacePatternHolder value:initialString. |
|
6816 ]. |
|
6817 flag := true. |
|
6818 search := [:fwd | |
|
6819 self |
|
6820 search:patternHolder value |
|
6821 ignoreCase:caseHolder value |
|
6822 forward:fwd. |
|
6823 ]. |
|
6824 replace := [:all | |
|
6825 self |
|
6826 replace:patternHolder value |
|
6827 by:replacePatternHolder value |
|
6828 all:all |
|
6829 ignoreCase:caseHolder value |
|
6830 ]. |
|
6831 bindings := IdentityDictionary new. |
|
6832 bindings at:#searchPattern put:patternHolder. |
|
6833 bindings at:#replacePattern put:replacePatternHolder. |
|
6834 modal ifTrue:[ |
|
6835 bindings at:#nextAction |
|
6836 put:[ |
|
6837 flag := true. |
|
6838 action := search. |
|
6839 searchBox doAccept. |
|
6840 ]. |
|
6841 bindings at:#prevAction |
|
6842 put:[ |
|
6843 flag := false. |
|
6844 action := search. |
|
6845 searchBox doAccept. |
|
6846 ]. |
|
6847 bindings at:#replaceAction |
|
6848 put:[ |
|
6849 flag := false. |
|
6850 action := replace. |
|
6851 searchBox doAccept. |
|
6852 ]. |
|
6853 bindings at:#replaceAllAction |
|
6854 put:[ |
|
6855 flag := true. |
|
6856 action := replace. |
|
6857 searchBox doAccept. |
|
6858 ]. |
|
6859 ] ifFalse:[ |
|
6860 bindings at:#nextAction put:[ search value:true. ]. |
|
6861 bindings at:#prevAction put:[ search value:false. ]. |
|
6862 bindings at:#replaceAction put:[ replace value:false. ]. |
|
6863 bindings at:#replaceAllAction put:[ replace value:true. ]. |
|
6864 ]. |
|
6865 bindings at:#ignoreCase put:caseHolder. |
|
6866 bindings at:#patternList put:LastSearchPatterns. |
|
6867 modal ifTrue:[ |
|
6868 searchBox := SimpleDialog new. |
|
6869 ] ifFalse:[ |
|
6870 searchBox := ApplicationModel new. |
|
6871 searchBox createBuilder. |
|
6872 ]. |
|
6873 searchBox resources:(self resources). |
|
6874 bldr := searchBox builder. |
|
6875 bldr addBindings:bindings. |
|
6876 searchBox allButOpenFrom:(self class searchReplaceDialogSpec). |
|
6877 (bldr componentAt:#nextButton) cursor:(Cursor thumbsUp). |
|
6878 (bldr componentAt:#prevButton) cursor:(Cursor thumbsUp). |
|
6879 (bldr componentAt:#cancelButton) cursor:(Cursor thumbsDown). |
|
6880 modal ifTrue:[ |
|
6881 searchBox openDialog. |
|
6882 searchBox accepted ifTrue:[ |
|
6883 action value:flag |
|
6884 ]. |
|
6885 ] ifFalse:[ |
|
6886 (bldr componentAt:#nextButton) isReturnButton:false. |
|
6887 (bldr componentAt:#cancelButton) |
|
6888 label:(resources string:'Close'); |
|
6889 action:[ searchBox closeRequest ]. |
|
6890 |
|
6891 "/ searchBox masterApplication:self application. |
|
6892 |
|
6893 self topView beMaster. |
|
6894 (searchBox window) |
|
6895 beSlave; |
|
6896 openInGroup:(self windowGroup). |
|
6897 |
|
6898 "/ searchBox window open. |
|
6899 |
|
6900 searchBox window assignKeyboardFocusToFirstInputField. |
|
6901 ] |
|
6902 |
|
6903 "Modified: / 11-07-2006 / 11:20:06 / fm" |
|
6904 ! |
|
6905 |
|
6906 showDeleted |
|
6907 "open a readonly editor on all deleted text" |
|
6908 |
|
6909 |v| |
|
6910 |
|
6911 v := EditTextView openWith:(Smalltalk at:#DeleteHistory). |
|
6912 v readOnly:true. |
|
6913 v topView label:'deleted text'. |
|
6914 ! |
|
6915 |
|
6916 sort:how ignoreCase:ignoreCase fromLine:start toLine:end |
|
6917 "sort/reorder the selected lines. |
|
6918 how: |
|
6919 #lines |
|
6920 #linesByFirstWord |
|
6921 #linesByNthWord |
|
6922 #linesByNthNumber |
|
6923 #linesByNthHexNumber |
|
6924 #words |
|
6925 #linesByLength |
|
6926 #reverse |
|
6927 " |
|
6928 |
|
6929 |lines extractor innerExtractor fetcher operation lineWise nStr n s words| |
|
6930 |
|
6931 lineWise := true. |
|
6932 |
|
6933 how == #reverse ifTrue:[ |
|
6934 operation := [:lines | lines reverse]. |
|
6935 ] ifFalse:[ |
|
6936 operation := [:linesOrWords | |
|
6937 linesOrWords sort:[:item1 :item2 | (fetcher value:item1) < (fetcher value:item2)] |
|
6938 ]. |
|
6939 |
|
6940 how == #linesByLength ifTrue:[ |
|
6941 fetcher := [:l | l size]. |
|
6942 ] ifFalse:[ |
|
6943 how == #lines ifTrue:[ |
|
6944 extractor := [:l | l withoutLeadingSeparators]. |
|
6945 ] ifFalse:[ |
|
6946 how == #linesByFirstWord ifTrue:[ |
|
6947 extractor := [:l | ((l asCollectionOfWords select:[:w | w isEmpty or:[w first isLetterOrDigit]]) at:1 ifAbsent:'')]. |
|
6948 ] ifFalse:[ |
|
6949 ((how == #linesByNthWord) or:[ how == #linesByNthNumber or:[ how == #linesByNthHexNumber]]) ifTrue:[ |
|
6950 nStr := Dialog request:'Word/Column (1..)' initialAnswer:(LastColumnNumberForSort ? 2). |
|
6951 nStr isEmptyOrNil ifTrue:[^ self]. |
|
6952 n := Integer readFrom:nStr onError:[^ self]. |
|
6953 LastColumnNumberForSort := n. |
|
6954 extractor := [:l | ((l string asCollectionOfWords) at:n ifAbsent:'')]. |
|
6955 how == #linesByNthNumber ifTrue:[ |
|
6956 innerExtractor := extractor. |
|
6957 extractor := [:l | Integer readFrom:(innerExtractor value:l) onError:0] |
|
6958 ] ifFalse:[ |
|
6959 how == #linesByNthHexNumber ifTrue:[ |
|
6960 innerExtractor := extractor. |
|
6961 extractor := [:l | |
|
6962 |s| |
|
6963 s := innerExtractor value:l. |
|
6964 (s startsWith:'16r') ifTrue:[ |
|
6965 (Integer readSmalltalkSyntaxFrom:s) ? 0 |
|
6966 ] ifFalse:[ |
|
6967 Integer readFrom:s radix:16 onError:[ 0 ] |
|
6968 ] |
|
6969 ] |
|
6970 ] |
|
6971 ]. |
|
6972 ] ifFalse:[ |
|
6973 how == #words ifTrue:[ |
|
6974 lineWise := false. |
|
6975 extractor := [:w | w]. |
|
6976 ] ifFalse:[ |
|
6977 self error:'unknown sort criteria: ', how printString. |
|
6978 ] |
|
6979 ] |
|
6980 ] |
|
6981 ]. |
|
6982 ignoreCase ifTrue:[ |
|
6983 fetcher := [:l | (extractor value:l) asLowercase]. |
|
6984 ] ifFalse:[ |
|
6985 fetcher := extractor. |
|
6986 ]. |
|
6987 ]. |
|
6988 ]. |
|
6989 |
|
6990 lineWise ifTrue:[ |
|
6991 "process the lines of the selection (aka a collection of lines)" |
|
6992 start == end ifTrue:[^ self ]. |
|
6993 lines := (start to:end) collect:[:lineNr | (self listAt:lineNr) ? '']. |
|
6994 lines := operation value:lines. |
|
6995 (start to:end) with:lines do:[:lineNr :line | self replaceLine:lineNr with:line]. |
|
6996 ] ifFalse:[ |
|
6997 "process the whole selection as a string" |
|
6998 s := self selectionAsString. |
|
6999 words := s asCollectionOfWords. |
|
7000 words := operation value:words. |
|
7001 s := words asStringCollection asStringWith:Character space. |
|
7002 self replace:s. |
|
7003 ]. |
|
7004 self textChanged. |
|
7005 |
|
7006 "Modified: / 31-03-2012 / 10:59:28 / cg" |
|
7007 ! |
|
7008 |
|
7009 sortSelection:how ignoreCase:ignoreCase |
|
7010 "sort the selected lines" |
|
7011 |
|
7012 |start end| |
|
7013 |
|
7014 selectionStartLine isNil ifTrue:[^ self]. |
|
7015 |
|
7016 start := selectionStartLine. |
|
7017 end := selectionEndLine. |
|
7018 (selectionEndCol == 0) ifTrue:[ |
|
7019 end := end - 1 |
|
7020 ]. |
|
7021 |
|
7022 self |
|
7023 undoableDo:[ |
|
7024 self sort:how ignoreCase:ignoreCase fromLine:start toLine:end |
|
7025 ] |
|
7026 info:'Sort' |
|
7027 |
|
7028 "Modified (format): / 15-02-2012 / 16:52:53 / cg" |
|
7029 ! |
|
7030 |
|
7031 specialCharacters |
|
7032 CharacterSetView |
|
7033 openAsInputFor:self |
|
7034 label:'Special Character Input' |
|
7035 clickLabel:'Click to Insert Character'. |
|
7036 ! |
|
7037 |
|
7038 undoablePaste:someText |
|
7039 self undoablePaste:someText info:nil. |
|
7040 |
|
7041 "Modified: / 28-07-2007 / 13:25:46 / cg" |
|
7042 ! |
|
7043 |
|
7044 undoablePaste:someText info:infoOrNil |
|
7045 self |
|
7046 undoableDo:[ |
|
7047 self paste:someText. |
|
7048 ] |
|
7049 info:infoOrNil |
|
7050 |
|
7051 "Created: / 28-07-2007 / 13:25:30 / cg" |
|
7052 ! |
|
7053 |
|
7054 undoablePasteOrReplace:someText info:infoOrNil |
|
7055 self |
|
7056 undoableDo:[ |
|
7057 self pasteOrReplace:someText. |
|
7058 ] |
|
7059 info:infoOrNil |
|
7060 |
|
7061 "Created: / 28-07-2007 / 13:26:16 / cg" |
|
7062 ! |
|
7063 |
|
7064 undoablePasteReplacingAll:someText info:infoOrNil |
|
7065 self |
|
7066 undoableDo:[ |
|
7067 self selectAll. |
|
7068 self pasteOrReplace:someText. |
|
7069 ] |
|
7070 info:infoOrNil |
|
7071 |
|
7072 "Created: / 28-07-2007 / 13:25:30 / cg" |
|
7073 ! |
|
7074 |
|
7075 withSelfAndTextForPasteDo:aBlock |
|
7076 "common code for paste/replace of the copybuffer" |
|
7077 |
|
7078 |sel| |
|
7079 |
|
7080 self checkModificationsAllowed ifFalse:[ |
|
7081 self flashReadOnly. |
|
7082 ^ self |
|
7083 ]. |
|
7084 |
|
7085 sel := self getTextSelectionOrTextSelectionFromHistory. |
|
7086 sel notNil ifTrue:[ |
|
7087 aBlock value:self value:sel. |
|
7088 ] |
|
7089 ! ! |
|
7090 |
|
7091 !EditTextView methodsFor:'private'! |
|
7092 |
|
7093 beep |
|
7094 UserPreferences current beepInEditor ifTrue:[ |
|
7095 super beep |
|
7096 ] |
|
7097 ! |
|
7098 |
|
7099 checkModificationsAllowed |
|
7100 "check if the text can be modified (i.e. is not readOnly). |
|
7101 evaluate the exceptionBlock if not. |
|
7102 This block should be provided by the application or user of the textView, |
|
7103 and may show a warnBox or whatever." |
|
7104 |
|
7105 self isReadOnly ifTrue: [ |
|
7106 exceptionBlock isNil ifTrue:[ |
|
7107 ^ false |
|
7108 ]. |
|
7109 |
|
7110 (exceptionBlock value:'Text may not be modified') ~~ true ifTrue:[ |
|
7111 ^ false |
|
7112 ] |
|
7113 ]. |
|
7114 ^ true |
|
7115 |
|
7116 "Modified: / 17.6.1998 / 15:51:10 / cg" |
|
7117 ! |
|
7118 |
|
7119 currentSelectionBgColor |
|
7120 typeOfSelection == #paste ifTrue:[ |
|
7121 ^ DefaultAlternativeSelectionBackgroundColor ? selectionBgColor |
|
7122 ]. |
|
7123 ^ super currentSelectionBgColor |
|
7124 |
|
7125 " |
|
7126 DefaultAlternativeSelectionBackgroundColor := Color yellow blendWith:Color green |
|
7127 " |
|
7128 ! |
|
7129 |
|
7130 currentSelectionFgColor |
|
7131 typeOfSelection == #paste ifTrue:[ |
|
7132 ^ DefaultAlternativeSelectionForegroundColor ? selectionFgColor |
|
7133 ]. |
|
7134 ^ super currentSelectionFgColor |
|
7135 ! |
|
7136 |
|
7137 resetVariablesBeforeNewSearch |
|
7138 "clear the autosearch action, when the first pattern is searched for" |
|
7139 |
|
7140 super resetVariablesBeforeNewSearch. |
|
7141 |
|
7142 "/ new search invalidates remembered string |
|
7143 lastStringFromReplaceForNextSearch := nil. |
|
7144 |
|
7145 "Modified (comment): / 07-03-2012 / 23:21:06 / cg" |
|
7146 ! |
|
7147 |
|
7148 setLastStringToReplace: aString |
|
7149 |
|
7150 "This method will set the information coming from the last replace into the replacementInfo" |
|
7151 |
|
7152 |lastReplaceIgnoredCase| |
|
7153 |
|
7154 "/ The searchAction is mantained until a cut/replace or a search with a user selection is done |
|
7155 self clearSearchAction. |
|
7156 |
|
7157 lastReplacementInfo lastStringToReplace: aString. |
|
7158 lastStringFromReplaceForNextSearch := aString. |
|
7159 |
|
7160 "If the replace came after a search, the next replace will have the ignored case from that search action" |
|
7161 lastReplaceIgnoredCase := (typeOfSelection == #search) |
|
7162 ifTrue: [lastSearchIgnoredCase] |
|
7163 ifFalse: [nil]. |
|
7164 lastReplacementInfo lastReplaceIgnoredCase: lastReplaceIgnoredCase. |
|
7165 ! |
|
7166 |
|
7167 st80EditMode |
|
7168 ^ st80Mode ? (UserPreferences current st80EditMode) |
|
7169 ! |
|
7170 |
|
7171 suppressEmphasisInSelection |
|
7172 "selection is shown without emphasis" |
|
7173 |
|
7174 ^ true |
|
7175 ! |
|
7176 |
|
7177 textChanged |
|
7178 "my text was modified (internally). |
|
7179 Sent whenever text has been edited (not to confuse with |
|
7180 contentsChanged, which is triggered when the size has changed, and |
|
7181 is used to notify scrollers, other views etc.). |
|
7182 |
|
7183 As some authors of this code have been very sloppy in tha past |
|
7184 (not sending contentsChanged, but textChanged), |
|
7185 we do it here despite what is written above, to ensure that scrollers update correctly." |
|
7186 |
|
7187 self contentsChanged. |
|
7188 self modified:true. |
|
7189 contentsWasSaved := false |
|
7190 |
|
7191 "Modified: 14.2.1997 / 16:58:38 / cg" |
|
7192 ! |
|
7193 |
|
7194 textChangedButNoSizeChange |
|
7195 "my text was modified (internally). |
|
7196 Sent whenever text has been edited (not to confuse with |
|
7197 contentsChanged, which is triggered when the size has changed, and |
|
7198 is used to notify scrollers, other views etc.)" |
|
7199 |
|
7200 self modified:true. |
|
7201 contentsWasSaved := false |
|
7202 |
|
7203 "Modified: 14.2.1997 / 16:58:38 / cg" |
|
7204 ! ! |
|
7205 |
|
7206 !EditTextView methodsFor:'queries'! |
|
7207 |
|
7208 currentLine |
|
7209 "the current line (for relative gotos)" |
|
7210 |
|
7211 ^ cursorLine |
|
7212 |
|
7213 "Created: / 17.5.1998 / 20:07:52 / cg" |
|
7214 ! |
|
7215 |
|
7216 hasSearchActionSelection |
|
7217 |
|
7218 ^ typeOfSelection == #searchAction |
|
7219 ! |
|
7220 |
|
7221 isKeyboardConsumer |
|
7222 "return true, if the receiver is a keyboard consumer; |
|
7223 Return true here, redefined from SimpleView." |
|
7224 |
|
7225 ^ self isReadOnly not |
|
7226 ! |
|
7227 |
|
7228 specClass |
|
7229 "redefined, since the name of my specClass is nonStandard (i.e. not EditTextSpec)" |
|
7230 |
|
7231 self class == EditTextView ifTrue:[^ TextEditorSpec]. |
|
7232 ^ super specClass |
|
7233 |
|
7234 "Modified: / 31.10.1997 / 19:48:19 / cg" |
|
7235 ! |
|
7236 |
|
7237 tabMeansNextField |
|
7238 "return true, if a Tab character should shift focus." |
|
7239 |
|
7240 "if not readOnly, I want my tab keys ..." |
|
7241 |
|
7242 ^ self isReadOnly or:[tabMeansNextField] |
|
7243 |
|
7244 "Created: 7.2.1996 / 19:15:31 / cg" |
|
7245 ! |
|
7246 |
|
7247 widthOfContents |
|
7248 "return the width of the contents in pixels |
|
7249 Redefined to add the size of a space (for the cursor). |
|
7250 this enables us to scroll one position further than the longest |
|
7251 line (and possibly see the cursor behind the line)" |
|
7252 |
|
7253 |w dev| |
|
7254 |
|
7255 w := super widthOfContents. |
|
7256 (dev := self graphicsDevice ) isNil ifTrue:[ |
|
7257 "/ really don't know ... |
|
7258 dev := Screen current |
|
7259 ]. |
|
7260 ^ w + (gc font widthOn:dev) |
|
7261 |
|
7262 "Modified: 28.5.1996 / 19:32:25 / cg" |
|
7263 ! ! |
|
7264 |
|
7265 !EditTextView methodsFor:'realization'! |
|
7266 |
|
7267 realize |
|
7268 "make the view visible - scroll to make the cursor visible." |
|
7269 |
|
7270 super realize. |
|
7271 |
|
7272 self makeCursorVisible. |
|
7273 cursorFgColor := cursorFgColor onDevice:self graphicsDevice. |
|
7274 cursorBgColor := cursorBgColor onDevice:self graphicsDevice. |
|
7275 |
|
7276 "Modified: 20.12.1996 / 14:16:05 / cg" |
|
7277 "Created: 24.7.1997 / 18:24:12 / cg" |
|
7278 ! ! |
|
7279 |
|
7280 !EditTextView methodsFor:'redrawing'! |
|
7281 |
|
7282 redrawCursorIfBetweenVisibleLine:startVisLine and:endVisLine |
|
7283 "redraw the cursor, if it sits in a line range" |
|
7284 |
|
7285 cursorShown ifTrue:[ |
|
7286 cursorVisibleLine notNil ifTrue:[ |
|
7287 (cursorVisibleLine between:startVisLine and:endVisLine) ifTrue:[ |
|
7288 self drawCursorCharacter |
|
7289 ] |
|
7290 ] |
|
7291 ] |
|
7292 ! |
|
7293 |
|
7294 redrawCursorIfInVisibleLine:visLine |
|
7295 "redraw the cursor, if it sits in visible line" |
|
7296 |
|
7297 cursorShown ifTrue:[ |
|
7298 (visLine == cursorVisibleLine) ifTrue:[ |
|
7299 self drawCursorCharacter |
|
7300 ] |
|
7301 ] |
|
7302 ! |
|
7303 |
|
7304 redrawFromVisibleLine:startVisLine to:endVisLine |
|
7305 "redraw a visible line range" |
|
7306 |
|
7307 super redrawFromVisibleLine:startVisLine to:endVisLine. |
|
7308 self redrawCursorIfBetweenVisibleLine:startVisLine and:endVisLine |
|
7309 ! |
|
7310 |
|
7311 redrawVisibleLine:visLine |
|
7312 "redraw a visible line" |
|
7313 |
|
7314 super redrawVisibleLine:visLine. |
|
7315 self redrawCursorIfInVisibleLine:visLine |
|
7316 ! |
|
7317 |
|
7318 redrawVisibleLine:visLine col:colNr |
|
7319 "redraw the single character in visibleline at colNr" |
|
7320 |
|
7321 super redrawVisibleLine:visLine col:colNr. |
|
7322 cursorShown ifTrue:[ |
|
7323 (visLine == cursorVisibleLine) ifTrue:[ |
|
7324 (colNr == cursorCol) ifTrue:[ |
|
7325 self drawCursorCharacter. |
|
7326 ^ self |
|
7327 ] |
|
7328 ] |
|
7329 ]. |
|
7330 |
|
7331 "Modified: / 05-11-2007 / 17:35:53 / cg" |
|
7332 ! |
|
7333 |
|
7334 redrawVisibleLine:visLine from:startCol |
|
7335 "redraw a visible line from startCol to the end of line" |
|
7336 |
|
7337 super redrawVisibleLine:visLine from:startCol. |
|
7338 cursorShown ifTrue:[ |
|
7339 self redrawCursorIfInVisibleLine:visLine |
|
7340 ] |
|
7341 ! |
|
7342 |
|
7343 redrawVisibleLine:visLine from:startCol to:endCol |
|
7344 "redraw a visible line from startCol to endCol" |
|
7345 |
|
7346 super redrawVisibleLine:visLine from:startCol to:endCol. |
|
7347 self redrawCursorIfInVisibleLine:visLine |
|
7348 ! ! |
|
7349 |
|
7350 !EditTextView methodsFor:'scrolling'! |
|
7351 |
|
7352 additionalMarginForHorizontalScroll |
|
7353 "return the number of pixels by which we may scroll more than the actual |
|
7354 width of the document would allow. |
|
7355 This is redefined by editable textViews, to allo for the cursor |
|
7356 to be visible if it is positioned right behind the longest line of text. |
|
7357 The default returned here is 10 pixels, which should be ok for most cursors" |
|
7358 |
|
7359 ^ 10 max:gc font width |
|
7360 ! |
|
7361 |
|
7362 halfPageDown |
|
7363 "half a page down - to keep cursor on same visible line, it has to be moved |
|
7364 within the real text " |
|
7365 |
|
7366 |prevCursorLine| |
|
7367 |
|
7368 prevCursorLine := cursorVisibleLine. |
|
7369 super halfPageDown. |
|
7370 self cursorVisibleLine:prevCursorLine col:cursorCol |
|
7371 ! |
|
7372 |
|
7373 halfPageUp |
|
7374 "half a page up - to keep cursor on same visible line, it has to be moved |
|
7375 within the real text " |
|
7376 |
|
7377 |prevCursorLine| |
|
7378 |
|
7379 prevCursorLine := cursorVisibleLine. |
|
7380 super halfPageUp. |
|
7381 self cursorVisibleLine:prevCursorLine col:cursorCol |
|
7382 ! |
|
7383 |
|
7384 originChanged:delta |
|
7385 "sent after scrolling - have to show the cursor if it was on before" |
|
7386 |
|
7387 super originChanged:delta. |
|
7388 " |
|
7389 should we move the cursor with the scroll - or leave it ? |
|
7390 " |
|
7391 self updateCursorVisibleLine. |
|
7392 prevCursorState ifTrue:[ |
|
7393 self showCursor |
|
7394 ] |
|
7395 |
|
7396 "Modified: / 17.6.1998 / 16:13:24 / cg" |
|
7397 ! |
|
7398 |
|
7399 originWillChange |
|
7400 "sent before scrolling - have to hide the cursor" |
|
7401 |
|
7402 prevCursorState := cursorShown. |
|
7403 "/ cursorShown := false. |
|
7404 cursorShown ifTrue:[ |
|
7405 self hideCursor |
|
7406 ] |
|
7407 |
|
7408 "Modified: / 6.7.1998 / 13:07:23 / cg" |
|
7409 ! |
|
7410 |
|
7411 pageDown |
|
7412 "page down - to keep cursor on same visible line, it has to be moved |
|
7413 within the real text " |
|
7414 |
|
7415 |prevCursorLine| |
|
7416 |
|
7417 prevCursorLine := cursorVisibleLine. |
|
7418 super pageDown. |
|
7419 self cursorVisibleLine:prevCursorLine col:cursorCol |
|
7420 ! |
|
7421 |
|
7422 pageUp |
|
7423 "page up - to keep cursor on same visible line, it has to be moved |
|
7424 within the real text " |
|
7425 |
|
7426 |prevCursorLine| |
|
7427 |
|
7428 prevCursorLine := cursorVisibleLine. |
|
7429 super pageUp. |
|
7430 self cursorVisibleLine:prevCursorLine col:cursorCol |
|
7431 ! ! |
|
7432 |
|
7433 !EditTextView methodsFor:'searching'! |
|
7434 |
|
7435 searchBwd:pattern ifAbsent:aBlock |
|
7436 "do a backward search" |
|
7437 |
|
7438 self searchBwd:pattern ignoreCase:false ifAbsent:aBlock |
|
7439 ! |
|
7440 |
|
7441 searchBwd:pattern ignoreCase:ign ifAbsent:aBlock |
|
7442 "do a backward search" |
|
7443 |
|
7444 cursorLine isNil ifTrue:[^ self]. |
|
7445 super searchBwd:pattern ignoreCase:ign ifAbsent:aBlock |
|
7446 ! |
|
7447 |
|
7448 searchBwd:pattern ignoreCase:ign startingAtLine:startLine col:startCol ifAbsent:aBlock |
|
7449 "do a backward search" |
|
7450 |
|
7451 cursorLine isNil ifTrue:[^ self]. |
|
7452 |
|
7453 self |
|
7454 searchBackwardFor:pattern |
|
7455 ignoreCase:ign |
|
7456 startingAtLine:startLine col:startCol |
|
7457 ifFound:[:line :col | |
|
7458 self cursorMovementAllowed ifTrue:[ |
|
7459 self cursorLine:line col:col. |
|
7460 ]. |
|
7461 self showMatch:pattern isMatch:false atLine:line col:col. |
|
7462 "/ self makeLineVisible:cursorLine |
|
7463 typeOfSelection := #search] |
|
7464 ifAbsent:aBlock |
|
7465 |
|
7466 "Modified: 9.10.1997 / 13:02:13 / cg" |
|
7467 ! |
|
7468 |
|
7469 searchForAndSelectMatchingParenthesis |
|
7470 "select characters enclosed by matching parenthesis if one is under cusor" |
|
7471 |
|
7472 self searchForAndSelectMatchingParenthesisFromLine:cursorLine col:cursorCol |
|
7473 ! |
|
7474 |
|
7475 searchForMatchingParenthesis |
|
7476 "search for a matching parenthesis starting at cursor position. |
|
7477 Search for the corresponding character is done forward if its an opening, |
|
7478 backwards if its a closing parenthesis. |
|
7479 Positions the cursor if found, peeps if not" |
|
7480 |
|
7481 self cursorMovementAllowed ifFalse:[^ self]. |
|
7482 |
|
7483 self |
|
7484 searchForMatchingParenthesisFromLine:cursorLine col:cursorCol |
|
7485 ifFound:[:line :col | self cursorLine:line col:col] |
|
7486 ifNotFound:[self showNotFound] |
|
7487 onError:[self beep] |
|
7488 |
|
7489 "Modified: 9.10.1997 / 12:56:30 / cg" |
|
7490 ! |
|
7491 |
|
7492 searchFwd:pattern ignoreCase:ign match: match startingAtLine:startLine col:startCol ifAbsent:aBlock |
|
7493 "do a forward search" |
|
7494 |
|
7495 cursorLine isNil ifTrue:[^ self]. |
|
7496 self |
|
7497 searchForwardFor:pattern |
|
7498 ignoreCase:ign |
|
7499 match: match |
|
7500 startingAtLine:startLine col:startCol |
|
7501 ifFound:[:line :col | |
|
7502 self cursorMovementAllowed ifTrue:[ |
|
7503 self cursorLine:line col:col. |
|
7504 ]. |
|
7505 self showMatch:pattern isMatch:match atLine:line col:col. |
|
7506 "/ self makeLineVisible:cursorLine |
|
7507 typeOfSelection := #search |
|
7508 ] |
|
7509 ifAbsent:aBlock |
|
7510 |
|
7511 "Modified: 9.10.1997 / 12:57:47 / cg" |
|
7512 "Created: 9.10.1997 / 13:01:12 / cg" |
|
7513 ! |
|
7514 |
|
7515 searchFwd:pattern ignoreCase:ign startingAtLine:startLine col:startCol ifAbsent:aBlock |
|
7516 "do a forward search" |
|
7517 |
|
7518 self searchFwd:pattern ignoreCase:ign match: false startingAtLine:startLine col:startCol ifAbsent:aBlock |
|
7519 ! |
|
7520 |
|
7521 searchFwd:pattern startingAtLine:startLine col:startCol ifAbsent:aBlock |
|
7522 "do a forward search" |
|
7523 |
|
7524 self searchFwd:pattern ignoreCase:false startingAtLine:startLine col:startCol ifAbsent:aBlock |
|
7525 ! |
|
7526 |
|
7527 searchPatternForSearchBar |
|
7528 |
|
7529 "Returns the next searchPattern from the user selection or from the autoSearch" |
|
7530 |
|
7531 |searchPattern| |
|
7532 |
|
7533 searchPattern := self searchPatternFromUserSelectionOrReplace. |
|
7534 searchPattern isNil |
|
7535 ifTrue: [searchPattern := lastSearchPattern] |
|
7536 ifFalse: [lastSearchPattern := searchPattern]. |
|
7537 ^ searchPattern |
|
7538 ! |
|
7539 |
|
7540 setSearchPatternWithMatchEscapes: match |
|
7541 "set the searchpattern from the selection if there is one, and position |
|
7542 cursor to start of pattern" |
|
7543 |
|
7544 |sel| |
|
7545 |
|
7546 "/ |
|
7547 "/ if the last operation was a replace, set pattern to last |
|
7548 "/ original string (for search after again) |
|
7549 "/ for cut or delete actions allow lastReplacement with nil |
|
7550 "/ |
|
7551 "/ (lastStringFromReplaceForNextSearch notNil |
|
7552 "/ and:[typeOfSelection ~~ #search]) ifTrue:[ |
|
7553 "/ lastStringFromReplaceForNextSearch isString ifTrue:[ |
|
7554 "/ lastSearchPattern := lastStringFromReplaceForNextSearch. |
|
7555 "/ ] ifFalse:[ |
|
7556 "/ lastSearchPattern := lastStringFromReplaceForNextSearch asStringWithoutFinalCR. |
|
7557 "/ ]. |
|
7558 "/ ^ self |
|
7559 "/ ]. |
|
7560 |
|
7561 "/ |
|
7562 "/ if there is a selection: |
|
7563 "/ if there was no previous search, take it as search pattern. |
|
7564 "/ if there was a previous search, only take the selection if |
|
7565 "/ it did not result from a paste or from the last search itself. |
|
7566 "/ (to allow search-paste to be repeated) |
|
7567 "/ |
|
7568 sel := self selection. |
|
7569 sel notNil ifTrue:[ |
|
7570 (lastSearchPattern isNil |
|
7571 or:[typeOfSelection ~~ #paste and:[typeOfSelection ~~ #search]] |
|
7572 ) ifTrue:[ |
|
7573 self cursorLine:selectionStartLine col:selectionStartCol. |
|
7574 lastSearchPattern := sel asStringWithoutFinalCR. |
|
7575 match ifTrue:[lastSearchPattern := lastSearchPattern withMatchEscapes]. |
|
7576 ] |
|
7577 ] |
|
7578 |
|
7579 "Modified: / 07-05-2011 / 17:25:59 / cg" |
|
7580 ! |
|
7581 |
|
7582 showMatch:pattern isMatch:isMatch atLine:line col:col |
|
7583 super showMatch:pattern isMatch:isMatch atLine:line col:col. |
|
7584 typeOfSelection := #search. |
|
7585 ! |
|
7586 |
|
7587 startPositionForSearchBackward |
|
7588 ^ self startPositionForSearchBackwardBasedOnCursorOrSelection |
|
7589 ! |
|
7590 |
|
7591 startPositionForSearchBackwardBasedOnCursorOrSelection |
|
7592 |startLine startCol| |
|
7593 |
|
7594 selectionStartLine notNil ifTrue:[ |
|
7595 startLine := selectionStartLine. |
|
7596 startCol := selectionStartCol |
|
7597 ] ifFalse:[ |
|
7598 cursorLine isNil ifTrue:[ |
|
7599 startLine := list size. |
|
7600 startCol := self listAt:startLine size. |
|
7601 ] ifFalse:[ |
|
7602 startLine := cursorLine min:list size. |
|
7603 startCol := cursorCol |
|
7604 ] |
|
7605 ]. |
|
7606 |
|
7607 ^ startCol @ cursorLine |
|
7608 ! |
|
7609 |
|
7610 startPositionForSearchForward |
|
7611 ^ self startPositionForSearchForwardBasedOnCursorOrSelection |
|
7612 ! |
|
7613 |
|
7614 startPositionForSearchForwardBasedOnCursorOrSelection |
|
7615 |startCol| |
|
7616 |
|
7617 "/ if there is no selection and the cursor is at the origin, |
|
7618 "/ assume its the first search and do not skip the very first match |
|
7619 startCol := cursorCol. |
|
7620 self hasSelection ifTrue:[ |
|
7621 ^ selectionEndCol @ selectionEndLine. |
|
7622 ] ifFalse:[ |
|
7623 (cursorLine == 1 and:[cursorCol == 1]) ifTrue:[ |
|
7624 startCol := 0 |
|
7625 ]. |
|
7626 startCol := startCol min:(self at:cursorLine) size |
|
7627 ]. |
|
7628 |
|
7629 ^ startCol @ cursorLine |
|
7630 |
|
7631 "Modified (format): / 24-05-2012 / 13:58:37 / cg" |
|
7632 ! ! |
|
7633 |
|
7634 !EditTextView methodsFor:'selections'! |
|
7635 |
|
7636 addToSelectionAfter:aBlock |
|
7637 "Pokud existuje selekce, upravi ji |
|
7638 podle aktualni pozice kurzoru a pozice |
|
7639 po provedeni blocku. |
|
7640 Urceno k implementaci Shift-Home a Shift-End |
|
7641 Nejak nevim, jak to presneji popsat :-)" |
|
7642 |
|
7643 |startLine startCol endLine endCol | |
|
7644 |
|
7645 self hasSelection ifTrue: [ |
|
7646 startLine := selectionStartLine . |
|
7647 startCol := selectionStartCol . |
|
7648 endLine := selectionEndLine . |
|
7649 endCol := selectionEndCol . |
|
7650 ] ifFalse: [ |
|
7651 startLine := endLine := cursorLine . |
|
7652 startCol := endCol := cursorCol . |
|
7653 ]. |
|
7654 |
|
7655 "deselectim a provedu presun kurzoru..." |
|
7656 self unselect . |
|
7657 aBlock value . |
|
7658 |
|
7659 "funguje dost mizerne, jen na jednom radku..." |
|
7660 (startCol - cursorCol) abs <= (endCol - cursorCol) abs |
|
7661 ifTrue: [ |
|
7662 startCol := cursorCol. |
|
7663 ] ifFalse: [ |
|
7664 endCol := cursorCol - 1. |
|
7665 ]. |
|
7666 self selectFromLine:startLine col:startCol toLine: endLine col:endCol . |
|
7667 ! |
|
7668 |
|
7669 autoMoveCursorToEndOfSelection |
|
7670 "return true, if the cursor should be automatically moved to the |
|
7671 end of a selection. |
|
7672 Redefined to return false in terminalViews, where the cursor should |
|
7673 not be affected by selecting" |
|
7674 |
|
7675 ^ true |
|
7676 ! |
|
7677 |
|
7678 changeTypeOfSelectionTo:newType |
|
7679 typeOfSelection ~~ newType ifTrue:[ |
|
7680 typeOfSelection := newType. |
|
7681 selectionStartLine notNil ifTrue:[ |
|
7682 self |
|
7683 redrawFromLine:selectionStartLine col:selectionStartCol |
|
7684 toLine:selectionEndLine col:selectionEndCol |
|
7685 ]. |
|
7686 ]. |
|
7687 ! |
|
7688 |
|
7689 findNextWordAfterSelectionAndAddToSelection |
|
7690 |selStartCol selStartLine selEndCol selEndLine| |
|
7691 |
|
7692 selectionStartCol isNil ifTrue:[ |
|
7693 self selectWordUnderCursor. |
|
7694 ^ self |
|
7695 ]. |
|
7696 |
|
7697 selStartCol := selectionStartCol. |
|
7698 selEndCol := selectionEndCol. |
|
7699 selStartLine := selectionStartLine. |
|
7700 selEndLine := selectionEndLine. |
|
7701 |
|
7702 self cursorToNextWord. |
|
7703 self selectWordUnderCursor. |
|
7704 |
|
7705 self selectFromLine:selStartLine col:selStartCol toLine:selectionEndLine col:selectionEndCol. |
|
7706 ! |
|
7707 |
|
7708 searchPatternFromUserSelectionOrReplace |
|
7709 |
|
7710 |sel searchPattern| |
|
7711 |
|
7712 "/ |
|
7713 "/ if the last operation was a replace, set pattern to last |
|
7714 "/ original string (for search after again) |
|
7715 "/ |
|
7716 (lastStringFromReplaceForNextSearch notNil |
|
7717 and:[typeOfSelection ~~ #search]) ifTrue:[ |
|
7718 lastStringFromReplaceForNextSearch isString ifTrue:[ |
|
7719 searchPattern := lastStringFromReplaceForNextSearch. |
|
7720 ] ifFalse:[ |
|
7721 searchPattern := lastStringFromReplaceForNextSearch asStringWithoutFinalCR. |
|
7722 ]. |
|
7723 ^ searchPattern |
|
7724 ]. |
|
7725 |
|
7726 "/ |
|
7727 "/ if there is a selection: |
|
7728 "/ if there was no previous search, take it as search pattern. |
|
7729 "/ if there was a previous search, only take the selection if |
|
7730 "/ it did not result from a paste. |
|
7731 "/ (to allow search-paste to be repeated) |
|
7732 "/ |
|
7733 sel := self selection. |
|
7734 sel notNil ifTrue:[ |
|
7735 typeOfSelection ~~ #search ifTrue:[ |
|
7736 typeOfSelection ~~ #paste ifTrue:[ |
|
7737 self cursorLine:selectionStartLine col:selectionStartCol. |
|
7738 searchPattern := sel asStringWithoutFinalCR. |
|
7739 ] |
|
7740 ]. |
|
7741 ]. |
|
7742 |
|
7743 ^ searchPattern |
|
7744 ! |
|
7745 |
|
7746 selectAll |
|
7747 "select the whole text. |
|
7748 redefined to send super selectFrom... since we dont want the |
|
7749 cursor to be moved in this case." |
|
7750 |
|
7751 list isNil ifTrue:[ |
|
7752 self unselect |
|
7753 ] ifFalse:[ |
|
7754 super selectFromLine:1 col:1 toLine:(list size + 1) col:0. |
|
7755 typeOfSelection := nil |
|
7756 ] |
|
7757 |
|
7758 "Modified: 28.2.1997 / 19:14:54 / cg" |
|
7759 ! |
|
7760 |
|
7761 selectAllInitially |
|
7762 "select the whole text. This is called only once during the initialization |
|
7763 for editFields which are shown in a table or tree. |
|
7764 The selectAll is called via this method to allow for easier redefinition and |
|
7765 to distinguish auto-select from user-initiated selects." |
|
7766 |
|
7767 self selectAll |
|
7768 ! |
|
7769 |
|
7770 selectCursorLine |
|
7771 "select cursorline" |
|
7772 |
|
7773 self selectFromLine:cursorLine col:1 toLine:cursorLine+1 col:0 |
|
7774 ! |
|
7775 |
|
7776 selectCursorLineFromBeginning |
|
7777 "select cursorline up to cursor position" |
|
7778 |
|
7779 cursorCol > 1 ifTrue:[ |
|
7780 self selectFromLine:cursorLine col:1 |
|
7781 toLine:cursorLine col:(cursorCol-1) |
|
7782 ] |
|
7783 |
|
7784 "Modified: 16.8.1996 / 19:14:14 / cg" |
|
7785 ! |
|
7786 |
|
7787 selectExpandCursorLine |
|
7788 "expand selection by one line or select cursorline" |
|
7789 |
|
7790 selectionStartLine isNil ifTrue:[ |
|
7791 self selectCursorLine |
|
7792 ] ifFalse:[ |
|
7793 self selectFromLine:selectionStartLine col:selectionStartCol |
|
7794 toLine:cursorLine+1 col:0. |
|
7795 self makeLineVisible:selectionEndLine |
|
7796 ] |
|
7797 ! |
|
7798 |
|
7799 selectFromBeginOfLine |
|
7800 "select the text from the beginning of the current line to the current cursor position." |
|
7801 |
|
7802 | newCursorCol ln | |
|
7803 |
|
7804 list isNil ifTrue:[ |
|
7805 self unselect |
|
7806 ] ifFalse:[ |
|
7807 cursorCol > 1 ifTrue:[ |
|
7808 ln := list at: cursorLine. |
|
7809 newCursorCol := ln notEmptyOrNil ifTrue:[ln indexOfNonSeparator] ifFalse:[1]. |
|
7810 self selectFromLine:cursorLine col:newCursorCol toLine:cursorLine col:cursorCol-1. |
|
7811 cursorCol := newCursorCol. |
|
7812 typeOfSelection := nil |
|
7813 ] |
|
7814 ] |
|
7815 |
|
7816 "Created: / 28-06-2011 / 22:47:04 / cg" |
|
7817 "Modified: / 18-07-2012 / 17:00:26 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
7818 ! |
|
7819 |
|
7820 selectFromBeginning |
|
7821 "select the text from the beginning to the current cursor position." |
|
7822 |
|
7823 |col| |
|
7824 |
|
7825 list isNil ifTrue:[ |
|
7826 self unselect |
|
7827 ] ifFalse:[ |
|
7828 cursorCol == 0 ifTrue:[ |
|
7829 col := 0 |
|
7830 ] ifFalse:[ |
|
7831 col := cursorCol - 1 |
|
7832 ]. |
|
7833 super selectFromLine:1 col:1 toLine:cursorLine col:col. |
|
7834 typeOfSelection := nil |
|
7835 ] |
|
7836 ! |
|
7837 |
|
7838 selectFromLine:startLine col:startCol toLine:endLine col:endCol |
|
7839 "when a range is selected, position the cursor behind the selection |
|
7840 for easier editing. Also typeOfSelection is nilled here." |
|
7841 |
|
7842 super selectFromLine:startLine col:startCol toLine:endLine col:endCol. |
|
7843 (selectionEndLine notNil and:[self autoMoveCursorToEndOfSelection]) ifTrue:[ |
|
7844 self cursorLine:selectionEndLine col:(selectionEndCol + 1). |
|
7845 ]. |
|
7846 typeOfSelection := nil |
|
7847 ! |
|
7848 |
|
7849 selectToEndOfLine |
|
7850 "select the text from the current cursor position to the end of the current line" |
|
7851 |
|
7852 | newCursorCol line | |
|
7853 |
|
7854 list isNil ifTrue:[ |
|
7855 self unselect |
|
7856 ] ifFalse:[ |
|
7857 cursorCol >= 1 ifTrue:[ |
|
7858 line := list at: cursorLine. |
|
7859 newCursorCol := line size. |
|
7860 [ newCursorCol > 1 and:[(line at:newCursorCol) isSeparator] ] |
|
7861 whileTrue:[newCursorCol := newCursorCol - 1]. |
|
7862 |
|
7863 self selectFromLine:cursorLine col:cursorCol toLine:cursorLine col: newCursorCol. |
|
7864 cursorCol := newCursorCol. |
|
7865 typeOfSelection := nil |
|
7866 ] |
|
7867 ] |
|
7868 |
|
7869 "Created: / 28-06-2011 / 23:07:07 / cg" |
|
7870 "Modified: / 30-06-2011 / 19:51:21 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
7871 ! |
|
7872 |
|
7873 selectUpToEnd |
|
7874 "select the text from the current cursor position to the end." |
|
7875 |
|
7876 list isNil ifTrue:[ |
|
7877 self unselect |
|
7878 ] ifFalse:[ |
|
7879 super selectFromLine:cursorLine col:cursorCol toLine:(list size + 1) col:0. |
|
7880 typeOfSelection := nil |
|
7881 ] |
|
7882 ! |
|
7883 |
|
7884 selectWordUnderCursor |
|
7885 "select the word under the cursor" |
|
7886 |
|
7887 self selectWordAtLine:cursorLine col:cursorCol |
|
7888 ! |
|
7889 |
|
7890 unselect |
|
7891 "forget and unhilight selection - must take care of cursor here" |
|
7892 |
|
7893 |wasOn| |
|
7894 |
|
7895 wasOn := self hideCursor. |
|
7896 super unselect. |
|
7897 typeOfSelection := nil. |
|
7898 wasOn ifTrue:[self showCursor] |
|
7899 ! ! |
|
7900 |
|
7901 !EditTextView methodsFor:'undo & again'! |
|
7902 |
|
7903 addUndo:action |
|
7904 ^ undoSupport addUndo:action. |
|
7905 ! |
|
7906 |
|
7907 again |
|
7908 "repeat the last action (which was a cut or replace). |
|
7909 If current selection is not last string, search forward to |
|
7910 next occurrence of it before repeating the last operation." |
|
7911 |
|
7912 |s l c sel savedSelectStyle startColForSearch |
|
7913 lastStringToReplace lastReplaceIgnoredCase lastReplaceWasMatch| |
|
7914 |
|
7915 lastStringToReplace := lastReplacementInfo lastStringToReplace. |
|
7916 lastStringToReplace isNil ifTrue:[ |
|
7917 ^ false |
|
7918 ]. |
|
7919 lastReplaceIgnoredCase := lastReplacementInfo lastReplaceIgnoredCase. |
|
7920 lastReplaceWasMatch := lastReplacementInfo lastReplaceWasMatch. |
|
7921 |
|
7922 self undoableDo:[ |
|
7923 s := lastStringToReplace asString. |
|
7924 "remove final cr" |
|
7925 (s endsWith:Character cr) ifTrue:[s := s copyButLast:1]. |
|
7926 "/ s := s withoutSpaces. "XXX - replacing text with spaces ..." |
|
7927 |
|
7928 "set lastStringToReplace as the next search string |
|
7929 and set lastReplaceIgnoredCase as the next search ignored case flag" |
|
7930 lastStringFromReplaceForNextSearch := s. |
|
7931 lastSearchIgnoredCase := lastReplaceIgnoredCase. |
|
7932 |
|
7933 savedSelectStyle := selectStyle. |
|
7934 selectStyle := nil. |
|
7935 |
|
7936 sel := self selection. |
|
7937 |
|
7938 "if we are already there (after a find), ommit search" |
|
7939 |
|
7940 (sel notNil and:[sel asString withoutSeparators = s]) ifTrue:[ |
|
7941 l := selectionStartLine "cursorLine". |
|
7942 c := selectionStartCol "cursorCol". |
|
7943 self deleteSelection. |
|
7944 lastReplacementInfo lastReplacement notNil ifTrue:[ |
|
7945 self insertLines:lastReplacementInfo lastReplacement asStringCollection withCR:false. |
|
7946 self selectFromLine:l col:c toLine:cursorLine col:(cursorCol - 1). |
|
7947 typeOfSelection := #paste |
|
7948 ]. |
|
7949 selectStyle := savedSelectStyle. |
|
7950 ^ true |
|
7951 ]. |
|
7952 |
|
7953 sel isEmptyOrNil ifTrue:[ |
|
7954 startColForSearch := cursorCol - 1 |
|
7955 ] ifFalse:[ |
|
7956 startColForSearch := selectionEndCol ? (cursorCol - 1) |
|
7957 ]. |
|
7958 self |
|
7959 searchForwardFor:s |
|
7960 ignoreCase: lastReplaceIgnoredCase |
|
7961 match: lastReplaceWasMatch |
|
7962 startingAtLine:cursorLine col:startColForSearch |
|
7963 ifFound: |
|
7964 [ |
|
7965 :line :col | |
|
7966 |
|
7967 |repl| |
|
7968 |
|
7969 self selectFromLine:line col:col |
|
7970 toLine:line col:(col + s size - 1). |
|
7971 self makeLineVisible:line. |
|
7972 |
|
7973 self deleteSelection. |
|
7974 lastReplacementInfo lastReplacement notNil ifTrue:[ |
|
7975 lastReplacementInfo lastReplacement isString ifFalse:[ |
|
7976 repl := lastReplacementInfo lastReplacement asString "withoutSpaces" |
|
7977 ] ifTrue:[ |
|
7978 repl := lastReplacementInfo lastReplacement "withoutSpaces". |
|
7979 ]. |
|
7980 self insertLines:repl asStringCollection withCR:false. |
|
7981 self selectFromLine:line col:col toLine:cursorLine col:(cursorCol - 1). |
|
7982 undoSupport actionInfo:'replace'. |
|
7983 ]. |
|
7984 selectStyle := savedSelectStyle. |
|
7985 typeOfSelection := #paste. |
|
7986 ^ true |
|
7987 ] |
|
7988 ifAbsent: |
|
7989 [ |
|
7990 self sensor compressKeyPressEventsWithKey:#Again. |
|
7991 self showNotFound. |
|
7992 selectStyle := savedSelectStyle. |
|
7993 ^ false |
|
7994 ]. |
|
7995 ]. |
|
7996 |
|
7997 ^ true. |
|
7998 |
|
7999 "Modified: 9.10.1996 / 16:14:11 / cg" |
|
8000 ! |
|
8001 |
|
8002 hasRedoAction |
|
8003 ^ undoSupport hasRedoAction. |
|
8004 ! |
|
8005 |
|
8006 hasUndoAction |
|
8007 ^ undoSupport hasUndoAction. |
|
8008 ! |
|
8009 |
|
8010 multipleAgain |
|
8011 "repeat the last action (which was a cut or replace) until search fails" |
|
8012 |
|
8013 [self again] whileTrue:[] |
|
8014 ! |
|
8015 |
|
8016 nonUndoableDo:aBlock |
|
8017 undoSupport nonUndoableDo:aBlock. |
|
8018 ! |
|
8019 |
|
8020 redo |
|
8021 "undo the last undo" |
|
8022 |
|
8023 undoSupport hasRedoAction ifFalse:[ |
|
8024 self beep |
|
8025 ] ifTrue:[ |
|
8026 undoSupport redo. |
|
8027 ] |
|
8028 ! |
|
8029 |
|
8030 undo |
|
8031 "undo the last edit operation" |
|
8032 |
|
8033 undoSupport hasUndoAction ifFalse:[ |
|
8034 self beep |
|
8035 ] ifTrue:[ |
|
8036 undoSupport undo. |
|
8037 ] |
|
8038 ! |
|
8039 |
|
8040 undoableDo:aBlock |
|
8041 self undoableDo:aBlock info:nil. |
|
8042 |
|
8043 "Modified: / 28-07-2007 / 13:20:14 / cg" |
|
8044 ! |
|
8045 |
|
8046 undoableDo:aBlock info:aString |
|
8047 self checkModificationsAllowed ifFalse:[ |
|
8048 "/ will trigger an error-dialog there (no need for undo-carekeeping) |
|
8049 aBlock value. |
|
8050 ] ifTrue:[ |
|
8051 undoSupport undoableDo:aBlock info:aString. |
|
8052 ]. |
|
8053 |
|
8054 "Modified: / 28-07-2007 / 13:21:00 / cg" |
|
8055 ! ! |
|
8056 |
|
8057 !EditTextView::EditAction class methodsFor:'instance creation'! |
|
8058 |
|
8059 line1:arg1 col1:arg2 line2:arg3 col2:arg4 |
|
8060 ^ self new line1:arg1 col1:arg2 line2:arg3 col2:arg4 |
|
8061 ! |
|
8062 |
|
8063 line1:arg1 col1:arg2 line2:arg3 col2:arg4 info:info |
|
8064 ^ (self new line1:arg1 col1:arg2 line2:arg3 col2:arg4) info:info |
|
8065 ! |
|
8066 |
|
8067 line:arg1 col:arg2 character:arg3 |
|
8068 ^ self new line:arg1 col:arg2 character:arg3 |
|
8069 ! |
|
8070 |
|
8071 line:arg1 col:arg2 character:arg3 info:info |
|
8072 ^ (self new line:arg1 col:arg2 character:arg3) info:info |
|
8073 ! |
|
8074 |
|
8075 line:arg1 col:arg2 characters:arg3 info:info |
|
8076 ^ (self new line:arg1 col:arg2 characters:arg3) info:info |
|
8077 ! |
|
8078 |
|
8079 line:arg1 col:arg2 info:arg3 |
|
8080 ^ self new line:arg1 col:arg2 info:arg3 |
|
8081 ! |
|
8082 |
|
8083 line:arg1 col:arg2 string:arg3 |
|
8084 ^ self new line:arg1 col:arg2 string:arg3 |
|
8085 ! |
|
8086 |
|
8087 line:arg1 col:arg2 string:arg3 info:info |
|
8088 ^ (self new line:arg1 col:arg2 string:arg3) info:info |
|
8089 ! |
|
8090 |
|
8091 line:arg1 string:arg3 info:info |
|
8092 ^ (self new line:arg1 string:arg3) info:info |
|
8093 ! |
|
8094 |
|
8095 text:arg info:info |
|
8096 ^ (self new text:arg) info:info |
|
8097 ! ! |
|
8098 |
|
8099 !EditTextView::EditAction methodsFor:'accessing'! |
|
8100 |
|
8101 info |
|
8102 ^ userFriendlyInfo |
|
8103 ! |
|
8104 |
|
8105 info:aString |
|
8106 userFriendlyInfo := aString |
|
8107 ! ! |
|
8108 |
|
8109 !EditTextView::EditAction methodsFor:'combining'! |
|
8110 |
|
8111 canCombineWithPreviousPasteStringAction: aPasteStringAction |
|
8112 ^ false. |
|
8113 |
|
8114 "Created: / 25-09-2006 / 12:16:25 / cg" |
|
8115 ! ! |
|
8116 |
|
8117 !EditTextView::EditAction methodsFor:'queries'! |
|
8118 |
|
8119 canCombineWithNext:nextAction |
|
8120 ^ false |
|
8121 ! ! |
|
8122 |
|
8123 !EditTextView::DeleteRange methodsFor:'accessing'! |
|
8124 |
|
8125 line1:line1Arg col1:col1Arg line2:line2Arg col2:col2Arg |
|
8126 "set instance variables (automatically generated)" |
|
8127 |
|
8128 self assert:(line1Arg notNil). |
|
8129 self assert:(col1Arg notNil). |
|
8130 self assert:(line2Arg notNil). |
|
8131 self assert:(col2Arg notNil). |
|
8132 |
|
8133 line1 := line1Arg. |
|
8134 col1 := col1Arg. |
|
8135 line2 := line2Arg. |
|
8136 col2 := col2Arg. |
|
8137 ! ! |
|
8138 |
|
8139 !EditTextView::DeleteRange methodsFor:'execution'! |
|
8140 |
|
8141 executeIn:editor |
|
8142 editor unselect. |
|
8143 editor |
|
8144 deleteFromLine:line1 |
|
8145 col:col1 |
|
8146 toLine:line2 |
|
8147 col:col2. |
|
8148 editor cursorLine:line1 col:col1. |
|
8149 ! ! |
|
8150 |
|
8151 !EditTextView::DeleteCharacters methodsFor:'accessing'! |
|
8152 |
|
8153 col1 |
|
8154 ^ col1 |
|
8155 ! |
|
8156 |
|
8157 col2 |
|
8158 ^ col2 |
|
8159 ! |
|
8160 |
|
8161 line |
|
8162 ^ line |
|
8163 ! |
|
8164 |
|
8165 line:lineArg col1:col1Arg col2:col2Arg |
|
8166 "set instance variables (automatically generated)" |
|
8167 |
|
8168 self assert:(lineArg notNil). |
|
8169 self assert:(col1Arg notNil). |
|
8170 self assert:(col2Arg notNil). |
|
8171 |
|
8172 line := lineArg. |
|
8173 col1 := col1Arg. |
|
8174 col2 := col2Arg. |
|
8175 ! |
|
8176 |
|
8177 line:lineArg col:colArg info:infoArg |
|
8178 self assert:(lineArg notNil). |
|
8179 self assert:(colArg notNil). |
|
8180 |
|
8181 line := lineArg. |
|
8182 col1 := col2 := colArg. |
|
8183 self info:infoArg. |
|
8184 ! ! |
|
8185 |
|
8186 !EditTextView::DeleteCharacters methodsFor:'combining'! |
|
8187 |
|
8188 canCombineWithNext:anotherAction |
|
8189 ^ anotherAction perform:#canCombineWithPreviousDeleteCharactersAction: with:self ifNotUnderstood:false |
|
8190 ! |
|
8191 |
|
8192 canCombineWithPreviousDeleteCharactersAction:previousDeleteAction |
|
8193 "I will combine only if we both are single character deletes, |
|
8194 and my col-to-delete is the next after anotherDeleteActions col-to-delete. |
|
8195 (i.e. single-character typing)" |
|
8196 |
|
8197 previousDeleteAction line == line ifTrue:[ |
|
8198 previousDeleteAction col2 == (col1-1) ifTrue:[ |
|
8199 ^ true |
|
8200 ]. |
|
8201 ]. |
|
8202 |
|
8203 ^ false |
|
8204 ! |
|
8205 |
|
8206 combineWithNext:nextDeleteAction |
|
8207 self assert:(line == nextDeleteAction line). |
|
8208 self assert:(col2 == (nextDeleteAction col1 - 1)). |
|
8209 |
|
8210 col2 := nextDeleteAction col2. |
|
8211 userFriendlyInfo := 'insert ' , (col2 - col1 + 1) printString |
|
8212 ! ! |
|
8213 |
|
8214 !EditTextView::DeleteCharacters methodsFor:'execution'! |
|
8215 |
|
8216 executeIn:editor |
|
8217 editor unselect. |
|
8218 editor |
|
8219 deleteFromLine:line |
|
8220 col:col1 |
|
8221 toLine:line |
|
8222 col:col2. |
|
8223 editor cursorLine:line col:col1. |
|
8224 ! ! |
|
8225 |
|
8226 !EditTextView::EditMode class methodsFor:'constants'! |
|
8227 |
|
8228 insertAndSelectMode |
|
8229 ^ InsertAndSelectMode |
|
8230 ! |
|
8231 |
|
8232 insertMode |
|
8233 ^ InsertMode |
|
8234 ! |
|
8235 |
|
8236 overwriteMode |
|
8237 ^ OverwriteMode |
|
8238 ! ! |
|
8239 |
|
8240 !EditTextView::EditMode class methodsFor:'queries'! |
|
8241 |
|
8242 isInsertAndSelectMode |
|
8243 ^ false |
|
8244 ! |
|
8245 |
|
8246 isInsertMode |
|
8247 ^ false |
|
8248 ! |
|
8249 |
|
8250 symbolicName |
|
8251 self subclassResponsibility |
|
8252 ! ! |
|
8253 |
|
8254 !EditTextView::EditMode::InsertAndSelectMode class methodsFor:'info'! |
|
8255 |
|
8256 infoPrintString |
|
8257 ^ 'IS' |
|
8258 ! ! |
|
8259 |
|
8260 !EditTextView::EditMode::InsertAndSelectMode class methodsFor:'queries'! |
|
8261 |
|
8262 isInsertAndSelectMode |
|
8263 ^ true |
|
8264 ! |
|
8265 |
|
8266 isInsertMode |
|
8267 ^ true |
|
8268 ! ! |
|
8269 |
|
8270 !EditTextView::EditMode::InsertMode class methodsFor:'info'! |
|
8271 |
|
8272 infoPrintString |
|
8273 ^ 'I' |
|
8274 ! ! |
|
8275 |
|
8276 !EditTextView::EditMode::InsertMode class methodsFor:'queries'! |
|
8277 |
|
8278 isInsertMode |
|
8279 ^ true |
|
8280 ! ! |
|
8281 |
|
8282 !EditTextView::EditMode::OverwriteMode class methodsFor:'info'! |
|
8283 |
|
8284 infoPrintString |
|
8285 ^ 'O' |
|
8286 ! ! |
|
8287 |
|
8288 !EditTextView::LastReplacementInfo methodsFor:'accessing'! |
|
8289 |
|
8290 lastReplaceIgnoredCase |
|
8291 ^ lastReplaceIgnoredCase ? false |
|
8292 ! |
|
8293 |
|
8294 lastReplaceIgnoredCase:something |
|
8295 lastReplaceIgnoredCase := something. |
|
8296 ! |
|
8297 |
|
8298 lastReplaceWasMatch |
|
8299 ^ lastReplaceWasMatch ? false |
|
8300 ! |
|
8301 |
|
8302 lastReplaceWasMatch:something |
|
8303 lastReplaceWasMatch := something. |
|
8304 ! |
|
8305 |
|
8306 lastReplacement |
|
8307 ^ lastReplacement |
|
8308 ! |
|
8309 |
|
8310 lastReplacement:something |
|
8311 "/Transcript showCR: 'lastReplacement:', something printString. |
|
8312 lastReplacement := something. |
|
8313 ! |
|
8314 |
|
8315 lastStringToReplace |
|
8316 ^ lastStringToReplace |
|
8317 ! |
|
8318 |
|
8319 lastStringToReplace:something |
|
8320 lastStringToReplace := something. |
|
8321 ! |
|
8322 |
|
8323 previousReplacements |
|
8324 ^ previousReplacements ? #() |
|
8325 ! |
|
8326 |
|
8327 stillCollectingInput |
|
8328 ^ stillCollectingInput |
|
8329 ! |
|
8330 |
|
8331 stillCollectingInput:aBoolean |
|
8332 stillCollectingInput := aBoolean. |
|
8333 ! ! |
|
8334 |
|
8335 !EditTextView::LastReplacementInfo methodsFor:'history'! |
|
8336 |
|
8337 rememberReplacement |
|
8338 "remember the previous replacement (called when a new one appears). |
|
8339 Mostly for the benefit of the code completion..." |
|
8340 |
|
8341 |oldString newString| |
|
8342 |
|
8343 oldString := lastStringToReplace. |
|
8344 newString := lastReplacement. |
|
8345 (oldString notEmptyOrNil and:[newString notEmptyOrNil]) ifTrue:[ |
|
8346 previousReplacements isNil ifTrue:[ |
|
8347 previousReplacements := OrderedCollection new. |
|
8348 ]. |
|
8349 previousReplacements := previousReplacements reject:[:entry | entry key = oldString]. |
|
8350 previousReplacements addFirst:(oldString -> newString). |
|
8351 previousReplacements size > 20 ifTrue:[ |
|
8352 previousReplacements removeLast. |
|
8353 ] |
|
8354 ]. |
|
8355 ! ! |
|
8356 |
|
8357 !EditTextView::PasteString methodsFor:'accessing'! |
|
8358 |
|
8359 col |
|
8360 ^ col |
|
8361 |
|
8362 "Created: / 25-09-2006 / 12:19:59 / cg" |
|
8363 ! |
|
8364 |
|
8365 col2 |
|
8366 ^ col + string size - 1 |
|
8367 |
|
8368 "Created: / 25-09-2006 / 12:20:18 / cg" |
|
8369 ! |
|
8370 |
|
8371 line |
|
8372 ^ line |
|
8373 |
|
8374 "Created: / 25-09-2006 / 12:21:08 / cg" |
|
8375 ! |
|
8376 |
|
8377 line:lineArg col:colArg string:stringArg |
|
8378 self assert:(lineArg notNil). |
|
8379 self assert:(colArg notNil). |
|
8380 self assert:(stringArg notNil). |
|
8381 |
|
8382 line := lineArg. |
|
8383 col := colArg. |
|
8384 string := stringArg. |
|
8385 ! |
|
8386 |
|
8387 line:lineArg col:colArg string:stringArg selected:selectedArg |
|
8388 self assert:(lineArg notNil). |
|
8389 self assert:(colArg notNil). |
|
8390 self assert:(stringArg notNil). |
|
8391 |
|
8392 line := lineArg. |
|
8393 col := colArg. |
|
8394 string := stringArg. |
|
8395 selected := selectedArg. |
|
8396 ! |
|
8397 |
|
8398 string |
|
8399 ^ string |
|
8400 |
|
8401 "Created: / 25-09-2006 / 12:25:59 / cg" |
|
8402 ! ! |
|
8403 |
|
8404 !EditTextView::PasteString methodsFor:'combining'! |
|
8405 |
|
8406 canCombineWithNext:anotherAction |
|
8407 ^ anotherAction canCombineWithPreviousPasteStringAction:self |
|
8408 |
|
8409 "Created: / 25-09-2006 / 12:15:59 / cg" |
|
8410 ! |
|
8411 |
|
8412 canCombineWithPreviousPasteStringAction: previousPasteAction |
|
8413 "I will combine only if we both are single character inserts, |
|
8414 and my col-to-insert is the next after anotherInsertActions end-col. |
|
8415 (i.e. single-character deletes)" |
|
8416 |
|
8417 previousPasteAction line == line ifTrue:[ |
|
8418 previousPasteAction col == (self col2+1) ifTrue:[ |
|
8419 ^ true |
|
8420 ]. |
|
8421 ]. |
|
8422 |
|
8423 ^ false |
|
8424 |
|
8425 "Modified: / 25-09-2006 / 12:22:21 / cg" |
|
8426 ! |
|
8427 |
|
8428 combineWithNext:nextPasteAction |
|
8429 |s1 s2| |
|
8430 |
|
8431 self assert:(line == nextPasteAction line). |
|
8432 self assert:((col - 1) == (nextPasteAction col2)). |
|
8433 |
|
8434 s1 := nextPasteAction string. |
|
8435 s1 isString ifFalse:[s1 := s1 asStringWith:nil]. |
|
8436 s2 := string. |
|
8437 s2 isString ifFalse:[s2 := s2 asStringWith:nil]. |
|
8438 |
|
8439 string := s1, s2. |
|
8440 col := nextPasteAction col. |
|
8441 userFriendlyInfo := 'delete ' , string size printString |
|
8442 |
|
8443 "Created: / 25-09-2006 / 12:24:10 / cg" |
|
8444 ! ! |
|
8445 |
|
8446 !EditTextView::PasteString methodsFor:'execution'! |
|
8447 |
|
8448 executeIn:editor |
|
8449 editor cursorLine:line col:col. |
|
8450 editor paste:string. |
|
8451 selected ~~ true ifTrue:[ |
|
8452 editor unselect |
|
8453 ]. |
|
8454 ! ! |
|
8455 |
|
8456 !EditTextView::ReplaceCharacter methodsFor:'accessing'! |
|
8457 |
|
8458 col |
|
8459 ^ col |
|
8460 ! |
|
8461 |
|
8462 col1 |
|
8463 ^ col |
|
8464 ! |
|
8465 |
|
8466 col2 |
|
8467 ^ col |
|
8468 ! |
|
8469 |
|
8470 line |
|
8471 ^ line |
|
8472 ! |
|
8473 |
|
8474 line:lineArg col:colArg character:characterArg |
|
8475 line := lineArg. |
|
8476 col := colArg. |
|
8477 character := characterArg. |
|
8478 ! ! |
|
8479 |
|
8480 !EditTextView::ReplaceCharacter methodsFor:'execution'! |
|
8481 |
|
8482 executeIn:editor |
|
8483 editor |
|
8484 replace:character |
|
8485 atLine:line |
|
8486 col:col. |
|
8487 editor cursorLine:line col:col. |
|
8488 ! ! |
|
8489 |
|
8490 !EditTextView::ReplaceCharacters methodsFor:'accessing'! |
|
8491 |
|
8492 characters |
|
8493 ^ characters |
|
8494 ! |
|
8495 |
|
8496 col1 |
|
8497 ^ col1 |
|
8498 ! |
|
8499 |
|
8500 col2 |
|
8501 ^ col2 |
|
8502 ! |
|
8503 |
|
8504 line |
|
8505 ^ line |
|
8506 ! |
|
8507 |
|
8508 line:lineArg col:colArg character:characterArg |
|
8509 line := lineArg. |
|
8510 col1 := col2 := colArg. |
|
8511 characters := characterArg asString. |
|
8512 ! |
|
8513 |
|
8514 line:lineArg col:colArg characters:charactersArg |
|
8515 line := lineArg. |
|
8516 col1 := colArg. |
|
8517 characters := charactersArg asString. |
|
8518 col2 := col1 + charactersArg size - 1 |
|
8519 ! ! |
|
8520 |
|
8521 !EditTextView::ReplaceCharacters methodsFor:'combining'! |
|
8522 |
|
8523 canCombineWithNext:anotherAction |
|
8524 ^ anotherAction perform:#canCombineWithPreviousReplaceCharactersAction: with:self ifNotUnderstood:false |
|
8525 ! |
|
8526 |
|
8527 canCombineWithPreviousReplaceCharactersAction:previousReplaceAction |
|
8528 "I will combine only if we both are single character deletes, |
|
8529 and my col-to-delete is the next after anotherDeleteActions col-to-delete. |
|
8530 (i.e. single-character typing)" |
|
8531 |
|
8532 previousReplaceAction line == line ifTrue:[ |
|
8533 previousReplaceAction col2 == (col1-1) ifTrue:[ |
|
8534 ^ true |
|
8535 ]. |
|
8536 ]. |
|
8537 |
|
8538 ^ false |
|
8539 ! |
|
8540 |
|
8541 combineWithNext:nextReplaceAction |
|
8542 self assert:(line == nextReplaceAction line). |
|
8543 self assert:(self col2 == (nextReplaceAction col1 - 1)). |
|
8544 |
|
8545 col2 := nextReplaceAction col2. |
|
8546 userFriendlyInfo := 'replace ' , (col2 - col1 + 1) printString. |
|
8547 characters := characters , nextReplaceAction characters. |
|
8548 ! ! |
|
8549 |
|
8550 !EditTextView::ReplaceCharacters methodsFor:'execution'! |
|
8551 |
|
8552 executeIn:editor |
|
8553 editor |
|
8554 replaceString:characters |
|
8555 atLine:line |
|
8556 col:col1. |
|
8557 editor cursorLine:line col:col1. |
|
8558 ! ! |
|
8559 |
|
8560 !EditTextView::ReplaceContents methodsFor:'accessing'! |
|
8561 |
|
8562 text:something |
|
8563 text := something. |
|
8564 ! ! |
|
8565 |
|
8566 !EditTextView::ReplaceContents methodsFor:'execution'! |
|
8567 |
|
8568 executeIn:editor |
|
8569 editor contents:text |
|
8570 ! ! |
|
8571 |
|
8572 !EditTextView::ReplaceLine methodsFor:'accessing'! |
|
8573 |
|
8574 line:lineArg string:stringArg |
|
8575 line := lineArg. |
|
8576 text := stringArg. |
|
8577 ! ! |
|
8578 |
|
8579 !EditTextView::ReplaceLine methodsFor:'execution'! |
|
8580 |
|
8581 executeIn:editor |
|
8582 editor list at:line put:text. |
|
8583 editor invalidateLine:line |
|
8584 ! ! |
|
8585 |
|
8586 !EditTextView::ReplaceLines methodsFor:'accessing'! |
|
8587 |
|
8588 line:lineArg lines:lineCollectionArg |
|
8589 line := lineArg. |
|
8590 text := lineCollectionArg. |
|
8591 |
|
8592 "Created: / 09-10-2006 / 10:35:22 / cg" |
|
8593 ! ! |
|
8594 |
|
8595 !EditTextView::ReplaceLines methodsFor:'execution'! |
|
8596 |
|
8597 executeIn:editor |
|
8598 |lnr| |
|
8599 |
|
8600 lnr := line. |
|
8601 text do:[:eachLine | |
|
8602 editor list at:lnr put:eachLine. |
|
8603 editor invalidateLine:lnr. |
|
8604 lnr := lnr + 1. |
|
8605 ]. |
|
8606 |
|
8607 "Modified: / 09-10-2006 / 10:39:16 / cg" |
|
8608 ! ! |
|
8609 |
|
8610 !EditTextView class methodsFor:'documentation'! |
|
8611 |
|
8612 version |
|
8613 ^ '$Header: /cvs/stx/stx/libwidg/EditTextView.st,v 1.604.2.1 2014-05-08 08:30:56 stefan Exp $' |
|
8614 ! |
|
8615 |
|
8616 version_CVS |
|
8617 ^ '$Header: /cvs/stx/stx/libwidg/EditTextView.st,v 1.604.2.1 2014-05-08 08:30:56 stefan Exp $' |
|
8618 ! ! |
|
8619 |