1 package org.vaadin.aceeditor.client;
2
3 import com.google.gwt.core.client.JsArray;
4 import com.google.gwt.core.client.JsArrayInteger;
5 import com.google.gwt.user.client.DOM;
6 import com.google.gwt.user.client.ui.FocusWidget;
7 import com.vaadin.client.VConsole;
8
9 import org.vaadin.aceeditor.client.AceAnnotation.MarkerAnnotation;
10 import org.vaadin.aceeditor.client.AceAnnotation.RowAnnotation;
11 import org.vaadin.aceeditor.client.AceMarker.OnTextChange;
12 import org.vaadin.aceeditor.client.ClientSideDocDiff.Adjuster;
13 import org.vaadin.aceeditor.client.gwt.*;
14 import org.vaadin.aceeditor.client.gwt.GwtAceChangeEvent.Data.Action;
15
16 import java.util.*;
17 import java.util.Map.Entry;
18
19
20
21
22
23 public class AceEditorWidget extends FocusWidget implements
24 GwtAceChangeHandler, GwtAceFocusBlurHandler,
25 GwtAceChangeSelectionHandler, GwtAceChangeCursorHandler {
26
27 public interface TextChangeListener {
28 public void changed();
29 }
30 public interface SelectionChangeListener {
31 public void selectionChanged();
32 }
33
34 public interface FocusChangeListener {
35 public void focusChanged(boolean focused);
36 }
37
38 protected LinkedList<TextChangeListener> changeListeners = new LinkedList<TextChangeListener>();
39 public void addTextChangeListener(TextChangeListener li) {
40 changeListeners.add(li);
41 }
42 public void removeTextChangeListener(TextChangeListener li) {
43 changeListeners.remove(li);
44 }
45
46 protected LinkedList<SelectionChangeListener> selChangeListeners = new LinkedList<SelectionChangeListener>();
47 public void addSelectionChangeListener(SelectionChangeListener li) {
48 selChangeListeners.add(li);
49 }
50 public void removeSelectionChangeListener(SelectionChangeListener li) {
51 selChangeListeners.remove(li);
52 }
53
54 protected FocusChangeListener focusChangeListener;
55 public void setFocusChangeListener(FocusChangeListener li) {
56 focusChangeListener = li;
57 }
58
59 protected class MarkerInEditor {
60 protected AceMarker marker;
61 protected String clientId;
62 protected MarkerInEditor(AceMarker marker, String clientId) {
63 this.marker = marker;
64 this.clientId = clientId;
65 }
66 }
67
68 protected class AnnotationInEditor {
69 protected int row;
70 protected AceAnnotation ann;
71 protected String markerId;
72 protected AnnotationInEditor(AceAnnotation ann, String markerId) {
73 this.ann = ann;
74 this.markerId = markerId;
75 }
76 }
77
78 protected GwtAceEditor editor;
79
80 protected String editorId;
81
82 protected static int idCounter = 0;
83
84 protected String text = "";
85 protected boolean readOnly = false;
86 protected boolean propertyReadOnly = false;
87 protected boolean focused;
88 protected AceRange selection = new AceRange(0,0,0,0);
89
90
91 protected Map<String,MarkerInEditor> markersInEditor = Collections.emptyMap();
92
93 protected Set<RowAnnotation> rowAnnsInEditor = Collections.emptySet();
94 protected Set<AnnotationInEditor> markerAnnsInEditor = Collections.emptySet();
95
96 protected Map<Integer, AceRange> invisibleMarkers = new HashMap<Integer, AceRange>();
97 protected int latestInvisibleMarkerId = 0;
98
99 protected boolean ignoreEditorEvents = false;
100
101 protected Set<MarkerAnnotation> markerAnnotations = Collections.emptySet();
102 protected Set<RowAnnotation> rowAnnotations = Collections.emptySet();
103
104 protected GwtAceKeyboardHandler keyboardHandler;
105
106 protected AceDoc doc;
107
108 protected static String nextId() {
109 return "_AceEditorWidget_" + (++idCounter);
110 }
111
112 public AceEditorWidget() {
113 super(DOM.createDiv());
114 this.editorId = nextId();
115 this.setStylePrimaryName("AceEditorWidget");
116
117 }
118
119 public boolean isInitialized() {
120 return editor != null;
121 }
122
123 public void initialize() {
124 editor = GwtAceEditor.create(this.getElement(), editorId);
125 editor.addChangeHandler(this);
126 editor.addFocusListener(this);
127 editor.addChangeSelectionHandler(this);
128 editor.addChangeCursorHandler(this);
129 if (keyboardHandler!=null) {
130 editor.setKeyboardHandler(keyboardHandler);
131 }
132 }
133
134 public void setKeyboardHandler(GwtAceKeyboardHandler handler) {
135 this.keyboardHandler = handler;
136 if (isInitialized()) {
137 editor.setKeyboardHandler(handler);
138 }
139 }
140
141 @Override
142 public void setWidth(String w) {
143 super.setWidth(w);
144 if (editor!=null) {
145 editor.resize();
146 }
147 }
148
149 @Override
150 public void setHeight(String h) {
151 super.setHeight(h);
152 if (editor!=null) {
153 editor.resize();
154 }
155 }
156
157 public void setWordwrap(boolean wrap) {
158 if (isInitialized()) {
159 editor.setUseWrapMode(wrap);
160 }
161 }
162
163 public void setShowGutter(boolean showGutter) {
164 if (isInitialized()) {
165 editor.setShowGutter(showGutter);
166 }
167 }
168
169 public void setShowPrintMargin(boolean showPrintMargin) {
170 if (isInitialized()) {
171 editor.setShowPrintMargin(showPrintMargin);
172 }
173 }
174
175 public void setHighlightActiveLineEnabled(boolean highlightActiveLine) {
176 if (isInitialized()) {
177 editor.setHighlightActiveLineEnabled(highlightActiveLine);
178 }
179 }
180
181 protected void setText(String text) {
182 if (!isInitialized()) {
183 return;
184 }
185 AceRange oldSelection = selection;
186 Adjuster adjuster = new Adjuster(this.text, text);
187 adjustInvisibleMarkersOnTextChange(adjuster);
188 this.text = text;
189 this.doc = null;
190 ignoreEditorEvents = true;
191 double wasAtRow = editor.getScrollTopRow();
192 editor.setText(text);
193 AceRange adjSel = adjuster.adjust(oldSelection);
194 setSelection(adjSel, true);
195 editor.scrollToRow(wasAtRow);
196 ignoreEditorEvents = false;
197 }
198
199
200 protected void adjustInvisibleMarkersOnTextChange(Adjuster adjuster) {
201 HashMap<Integer, AceRange> ims = new HashMap<Integer, AceRange>(invisibleMarkers.size());
202 for (Entry<Integer, AceRange> e : invisibleMarkers.entrySet()) {
203 ims.put(e.getKey(), adjuster.adjust(e.getValue()));
204 }
205 invisibleMarkers = ims;
206 }
207
208 public void setSelection(AceRange s) {
209 setSelection(s, false);
210 }
211
212 protected void setSelection(AceRange s, boolean force) {
213 if (!isInitialized()) {
214 return;
215 }
216 if (s.equals(selection) && !force) {
217 return;
218 }
219
220 selection = s;
221
222 int r1 = s.getStartRow();
223 int c1 = s.getStartCol();
224 int r2 = s.getEndRow();
225 int c2 = s.getEndCol();
226 boolean backwards = r1 > r2 || (r1 == r2 && c1 > c2);
227 GwtAceRange range;
228 if (backwards) {
229 range = GwtAceRange.create(r2, c2, r1, c1);
230 } else {
231 range = GwtAceRange.create(r1, c1, r2, c2);
232 }
233 editor.setSelection(range, backwards);
234 }
235
236 public void setMode(String mode) {
237 if (!isInitialized()) {
238 return;
239 }
240 editor.setMode(mode);
241 }
242
243 public void setTheme(String theme) {
244 if (!isInitialized()) {
245 return;
246 }
247 editor.setTheme(theme);
248 }
249
250 protected void setMarkers(Map<String, AceMarker> markers) {
251 if (!isInitialized()) {
252 return;
253 }
254
255 HashMap<String,MarkerInEditor> newMarkers = new HashMap<String,MarkerInEditor>();
256 for (Entry<String, AceMarker> e : markers.entrySet()) {
257 String mId = e.getKey();
258 AceMarker m = e.getValue();
259 MarkerInEditor existing = markersInEditor.get(mId);
260 if (existing!=null) {
261 editor.removeMarker(existing.clientId);
262 }
263 String clientId = editor.addMarker(convertRange(m.getRange()), m.getCssClass(), m.getType().toString(), m.isInFront());
264 existing = new MarkerInEditor(m, clientId);
265 newMarkers.put(mId, existing);
266 }
267
268
269 for (MarkerInEditor hehe : markersInEditor.values()) {
270 if (!newMarkers.containsKey(hehe.marker.getMarkerId())) {
271 editor.removeMarker(hehe.clientId);
272 }
273 }
274
275 markersInEditor = newMarkers;
276 adjustMarkerAnnotations();
277 }
278
279 protected void adjustMarkerAnnotations() {
280 boolean changed = false;
281 for (AnnotationInEditor aie : markerAnnsInEditor) {
282 int row = rowOfMarker(aie.markerId);
283 if (row!=-1 && row != aie.row) {
284 aie.row = row;
285 changed = true;
286 }
287 }
288 if (changed) {
289 setAnnotationsToEditor();
290 }
291 }
292
293 protected void setAnnotations(Set<MarkerAnnotation> manns, Set<RowAnnotation> ranns) {
294 if (!isInitialized()) {
295 return;
296 }
297 if (manns!=null) {
298 markerAnnotations = manns;
299 markerAnnsInEditor = createAIEfromMA(manns);
300 }
301 if (ranns!=null) {
302 rowAnnotations = ranns;
303 rowAnnsInEditor = ranns;
304 }
305 setAnnotationsToEditor();
306 }
307
308 protected void setAnnotationsToEditor() {
309 JsArray<GwtAceAnnotation> arr = GwtAceAnnotation.createEmptyArray();
310
311 JsArray<GwtAceAnnotation> existing = editor.getAnnotations();
312
313 for (int i=0; i<existing.length(); ++i) {
314 GwtAceAnnotation ann = existing.get(i);
315 if (!ann.isVaadinAceEditorAnnotation()) {
316 arr.push(ann);
317 }
318 }
319
320 for (AnnotationInEditor maie : markerAnnsInEditor) {
321 GwtAceAnnotation jsAnn = GwtAceAnnotation.create(maie.ann.getType().toString(), maie.ann.getMessage(), maie.row);
322 arr.push(jsAnn);
323 }
324 for (RowAnnotation ra : rowAnnsInEditor) {
325 AceAnnotation a = ra.getAnnotation();
326 GwtAceAnnotation jsAnn = GwtAceAnnotation.create(a.getType().toString(), a.getMessage(), ra.getRow());
327 arr.push(jsAnn);
328 }
329 editor.setAnnotations(arr);
330 }
331
332 protected Set<AnnotationInEditor> createAIEfromMA(
333 Set<MarkerAnnotation> anns) {
334 Set<AnnotationInEditor> adjusted = new HashSet<AnnotationInEditor>();
335 for (MarkerAnnotation a : anns) {
336 int row = rowOfMarker(a.getMarkerId());
337 if (row!=-1) {
338 AnnotationInEditor maie = new AnnotationInEditor(a.getAnnotation(), a.getMarkerId());
339 maie.row = row;
340 adjusted.add(maie);
341 }
342 }
343 return adjusted;
344 }
345
346 protected int rowOfMarker(String markerId) {
347 MarkerInEditor cm = markersInEditor.get(markerId);
348 if (cm==null) {
349 return -1;
350 }
351 return cm.marker.getRange().getStartRow();
352 }
353
354 @Override
355 public void onChange(GwtAceChangeEvent e) {
356 if (ignoreEditorEvents) {
357 return;
358 }
359 String newText = editor.getText();
360 if (newText.equals(text)) {
361 return;
362 }
363
364
365
366
367 adjustMarkers(e);
368 adjustInvisibleMarkers(e);
369 adjustMarkerAnnotations();
370 text = newText;
371 doc = null;
372 fireTextChanged();
373 }
374
375 public void fireTextChanged() {
376 for (TextChangeListener li : changeListeners) {
377 li.changed();
378 }
379 }
380
381 protected void adjustMarkers(GwtAceChangeEvent e) {
382 Action act = e.getData().getAction();
383 GwtAceRange range = e.getData().getRange();
384 Set<MarkerInEditor> moved = new HashSet<MarkerInEditor>();
385 Set<MarkerInEditor> removed = new HashSet<MarkerInEditor>();
386
387 if (act==Action.insertLines || act==Action.insertText) {
388 for (MarkerInEditor cm : markersInEditor.values()) {
389 if (cm.marker.getOnChange()==OnTextChange.ADJUST) {
390 AceRange newRange = moveMarkerOnInsert(cm.marker.getRange(), range);
391 if (newRange!=null) {
392 cm.marker = cm.marker.withNewPosition(newRange);
393 if (markerIsValid(cm.marker)) {
394 moved.add(cm);
395 }
396 else {
397 removed.add(cm);
398 }
399 }
400 }
401 else if (cm.marker.getOnChange()==OnTextChange.REMOVE) {
402 removed.add(cm);
403 }
404 }
405 }
406 else if (act==Action.removeLines || act==Action.removeText) {
407 for (MarkerInEditor cm : markersInEditor.values()) {
408 if (cm.marker.getOnChange()==OnTextChange.ADJUST) {
409 AceRange newRange = moveMarkerOnRemove(cm.marker.getRange(), range);
410 if (newRange!=null) {
411 cm.marker = cm.marker.withNewPosition(newRange);
412 if (markerIsValid(cm.marker)) {
413 moved.add(cm);
414 }
415 else {
416 removed.add(cm);
417 }
418 }
419 }
420 else if (cm.marker.getOnChange()==OnTextChange.REMOVE) {
421 removed.add(cm);
422 }
423 }
424 }
425
426 removeMarkers(removed);
427 updateMarkers(moved);
428 }
429
430 protected void adjustInvisibleMarkers(GwtAceChangeEvent event) {
431 Action act = event.getData().getAction();
432 GwtAceRange range = event.getData().getRange();
433 HashMap<Integer, AceRange> newMap = new HashMap<Integer, AceRange>();
434 if (act==Action.insertLines || act==Action.insertText) {
435 for (Entry<Integer, AceRange> e : invisibleMarkers.entrySet()) {
436 AceRange newRange = moveMarkerOnInsert(e.getValue(), range);
437 newMap.put(e.getKey(), newRange==null?e.getValue():newRange);
438 }
439 }
440 else if (act==Action.removeLines || act==Action.removeText) {
441 for (Entry<Integer, AceRange> e : invisibleMarkers.entrySet()) {
442 AceRange newRange = moveMarkerOnRemove(e.getValue(), range);
443 newMap.put(e.getKey(), newRange==null?e.getValue():newRange);
444 }
445 }
446 invisibleMarkers = newMap;
447 }
448
449 protected static boolean markerIsValid(AceMarker marker) {
450 AceRange r = marker.getRange();
451 return !r.isZeroLength() && !r.isBackwards() && r.getStartRow() >= 0 && r.getStartCol() >= 0 && r.getEndCol() >= 0;
452 }
453
454
455
456 protected static AceRange moveMarkerOnInsert(AceRange mr, GwtAceRange range) {
457 int startRow = range.getStart().getRow();
458 int startCol = range.getStart().getColumn();
459 int dRow = range.getEnd().getRow() - startRow;
460 int dCol = range.getEnd().getColumn() - startCol;
461
462 if (dRow==0 && dCol==0) {
463 return null;
464 }
465
466 if (range.getStart().getRow() > mr.getEndRow()) {
467 return null;
468 }
469
470 boolean aboveMarkerStart = startRow < mr.getStartRow();
471 boolean beforeMarkerStartOnRow = startRow == mr.getStartRow() && startCol < mr.getStartCol();
472 boolean aboveMarkerEnd = startRow < mr.getEndRow();
473 boolean beforeMarkerEndOnRow = startRow == mr.getEndRow() && startCol <= mr.getEndCol();
474
475 int row1 = mr.getStartRow();
476 int col1 = mr.getStartCol();
477 if (aboveMarkerStart) {
478 row1 += dRow;
479 }
480 else if (beforeMarkerStartOnRow) {
481 row1 += dRow;
482 col1 += dCol;
483 }
484
485 int row2 = mr.getEndRow();
486 int col2 = mr.getEndCol();
487 if (aboveMarkerEnd) {
488 row2 += dRow;
489 }
490 else if (beforeMarkerEndOnRow) {
491 row2 += dRow;
492 col2 += dCol;
493 }
494
495 return new AceRange(row1, col1, row2, col2);
496 }
497
498 protected static AceRange moveMarkerOnRemove(AceRange mr, GwtAceRange range) {
499 int[] p1 = overlapping(range, mr.getStartRow(), mr.getStartCol());
500 boolean changed = false;
501 if (p1 == null) {
502 p1 = new int[]{mr.getStartRow(), mr.getStartCol()};
503 }
504 else {
505 changed = true;
506 }
507
508 int[] p2 = overlapping(range, mr.getEndRow(), mr.getEndCol());
509 if (p2 == null) {
510 p2 = new int[]{mr.getEndRow(), mr.getEndCol()};
511 }
512 else {
513 changed = true;
514 }
515
516 return changed ? new AceRange(p1[0], p1[1], p2[0], p2[1]) : null;
517 }
518
519 protected static int[] overlapping(GwtAceRange range, int row, int col) {
520 GwtAcePosition start = range.getStart();
521
522 if (start.getRow() > row || (start.getRow() == row && start.getColumn() >= col)) {
523 return null;
524 }
525
526 GwtAcePosition end = range.getEnd();
527
528 if (end.getRow() < row) {
529 int dRow = end.getRow() - start.getRow();
530 return new int[] {row-dRow, col};
531 }
532 if (end.getRow() == row && end.getColumn() < col) {
533 int dRow = end.getRow() - start.getRow();
534 int dCol = end.getColumn() - start.getColumn();
535 return new int[] {row-dRow, col-dCol};
536 }
537 return new int[] {start.getRow(), start.getColumn()};
538 }
539
540 protected void removeMarkers(Set<MarkerInEditor> removed) {
541 for (MarkerInEditor cm : removed) {
542 editor.removeMarker(cm.clientId);
543 markersInEditor.remove(cm.marker.getMarkerId());
544 }
545 }
546
547 protected void updateMarkers(Set<MarkerInEditor> moved) {
548 for (MarkerInEditor cm : moved) {
549 editor.removeMarker(cm.clientId);
550 AceMarker m = cm.marker;
551 cm.clientId = editor.addMarker(convertRange(m.getRange()), m.getCssClass(), m.getType().toString(), m.isInFront());
552 }
553
554 }
555
556 public String getText() {
557 return text;
558 }
559
560 public void setPropertyReadOnly(boolean propertyReadOnly) {
561 if (!isInitialized()) {
562 return;
563 }
564 this.propertyReadOnly = propertyReadOnly;
565 editor.setReadOnly(this.readOnly || this.propertyReadOnly);
566 }
567
568 public void setReadOnly(boolean readOnly) {
569 if (!isInitialized()) {
570 return;
571 }
572 this.readOnly = readOnly;
573 editor.setReadOnly(this.readOnly || this.propertyReadOnly);
574 }
575
576 protected static AceRange convertSelection(GwtAceSelection selection) {
577 GwtAcePosition start = selection.getRange().getStart();
578 GwtAcePosition end = selection.getRange().getEnd();
579 if (selection.isBackwards()) {
580 return new AceRange(end.getRow(), end.getColumn(), start.getRow(),
581 start.getColumn());
582 } else {
583 return new AceRange(start.getRow(), start.getColumn(),
584 end.getRow(), end.getColumn());
585 }
586
587 }
588
589 public AceRange getSelection() {
590 return selection;
591 }
592
593 @Override
594 public void onFocus(GwtAceEvent e) {
595 if (focused) {
596 return;
597 }
598 focused = true;
599 if (focusChangeListener != null) {
600 focusChangeListener.focusChanged(true);
601 }
602 }
603
604 @Override
605 public void onBlur(GwtAceEvent e) {
606 if (!focused) {
607 return;
608 }
609 focused = false;
610 if (focusChangeListener != null) {
611 focusChangeListener.focusChanged(false);
612 }
613 }
614
615 @Override
616 public void onChangeSelection(GwtAceEvent e) {
617 selectionChanged();
618 }
619
620 @Override
621 public void onChangeCursor(GwtAceEvent e) {
622 selectionChanged();
623 }
624
625 protected void selectionChanged() {
626 if (ignoreEditorEvents) {
627 return;
628 }
629 AceRange sel = convertSelection(editor.getSelection());
630 if (!sel.equals(selection)) {
631 selection = sel;
632 for (SelectionChangeListener li : selChangeListeners) {
633 li.selectionChanged();
634 }
635 }
636 }
637
638 public void setUseWorker(boolean use) {
639 if (!isInitialized()) {
640 return;
641 }
642 editor.setUseWorker(use);
643 }
644
645 @Override
646 public void setFocus(boolean focused) {
647 super.setFocus(focused);
648 if (focused) {
649 editor.focus();
650 }
651 else {
652 editor.blur();
653 }
654
655 }
656
657 public boolean isFocused() {
658 return focused;
659 }
660
661 protected GwtAceRange convertRange(AceRange r) {
662 int r1 = r.getStartRow();
663 int c1 = r.getStartCol();
664 int r2 = r.getEndRow();
665 int c2 = r.getEndCol();
666 boolean backwards = r1 > r2 || (r1 == r2 && c1 > c2);
667 if (backwards) {
668 return GwtAceRange.create(r2, c2, r1, c1);
669 } else {
670 return GwtAceRange.create(r1, c1, r2, c2);
671 }
672 }
673
674 protected Map<String, AceMarker> getMarkers() {
675 HashMap<String, AceMarker> markers = new HashMap<String, AceMarker>();
676 for (MarkerInEditor cm : markersInEditor.values()) {
677 markers.put(cm.marker.getMarkerId(), cm.marker);
678 }
679 return markers;
680 }
681
682 public void resize() {
683 if (editor!=null) {
684 editor.resize();
685 }
686 }
687
688 public AceDoc getDoc() {
689 if (doc==null) {
690 doc = new AceDoc(getText(), getMarkers(), getRowAnnotations(), getMarkerAnnotations());
691 }
692 return doc;
693 }
694
695 public void scrollToRow(int row) {
696 editor.scrollToRow(row);
697 }
698
699 protected Set<MarkerAnnotation> getMarkerAnnotations() {
700 return markerAnnotations;
701 }
702
703 protected Set<RowAnnotation> getRowAnnotations() {
704 return rowAnnotations;
705 }
706
707 public void setDoc(AceDoc doc) {
708 if (doc.equals(this.doc)) {
709 return;
710 }
711
712 setText(doc.getText());
713
714
715
716
717
718 setMarkers(doc.getMarkers());
719 setAnnotations(doc.getMarkerAnnotations(), doc.getRowAnnotations());
720 this.doc = doc;
721 }
722
723 public int[] getCursorCoords() {
724 JsArrayInteger cc = editor.getCursorCoords();
725 return new int[] {cc.get(0), cc.get(1)};
726 }
727
728 public int addInvisibleMarker(AceRange range) {
729 int id = ++latestInvisibleMarkerId;
730 invisibleMarkers.put(id, range);
731 return id;
732 }
733
734 public void removeInvisibleMarker(int id) {
735 invisibleMarkers.remove(id);
736 }
737
738 public AceRange getInvisibleMarker(int id) {
739 return invisibleMarkers.get(id);
740 }
741
742 public void setTextAndAdjust(String text) {
743 if (this.text.equals(text)) {
744 return;
745 }
746
747 HashMap<String, AceMarker> newMarkers = adjustMarkersOnTextChange(this.text, text);
748 setText(text);
749 if (newMarkers!=null) {
750 setMarkers(newMarkers);
751 }
752 }
753
754 protected HashMap<String, AceMarker> adjustMarkersOnTextChange(String text1, String text2) {
755 Map<String, AceMarker> ms = getMarkers();
756 if (ms.isEmpty()) {
757 return null;
758 }
759 HashMap<String, AceMarker> newMarkers = new HashMap<String, AceMarker>();
760 Adjuster adjuster = new Adjuster(text1, text2);
761 boolean adjusted = false;
762 for (Entry<String, AceMarker> e : ms.entrySet()) {
763 if (e.getValue().getOnChange()==OnTextChange.ADJUST) {
764 AceMarker m1 = e.getValue();
765 AceMarker m2 = m1.withNewPosition(adjuster.adjust(m1.getRange()));
766 newMarkers.put(e.getKey(), m2);
767 adjusted = true;
768 }
769 else {
770 newMarkers.put(e.getKey(), e.getValue());
771 }
772 }
773 if (!adjusted) {
774 return null;
775 }
776 return newMarkers;
777 }
778
779 public void removeContentsOfInvisibleMarker(int imId) {
780 AceRange r = getInvisibleMarker(imId);
781 if (r==null || r.isZeroLength()) {
782 return;
783 }
784 String newText = Util.replaceContents(r, text, "");
785 setTextAndAdjust(newText);
786 }
787 }