001: package abbot.editor;
002:
003: import java.awt.*;
004: import java.awt.datatransfer.Transferable;
005: import java.awt.dnd.*;
006: import java.awt.event.*;
007: import java.awt.image.BufferedImage;
008: import java.net.URL;
009: import java.util.*;
010: import java.util.List;
011:
012: import javax.swing.*;
013: import javax.swing.plaf.basic.BasicTreeUI;
014: import javax.swing.table.*;
015:
016: import abbot.Log;
017: import abbot.script.*;
018:
019: /** Provides a component to edit a test script. A cursor indicates where
020: insertions will be positioned. Supports drag & drop within the component
021: itself.<p>
022: Actions supported:<br>
023: move-rows-up<br>
024: move-rows-down<br>
025: toggle<br>
026: */
027:
028: public class ScriptTable extends JTable implements Autoscroll {
029: private int cursorRow = 0;
030: private Sequence cursorParent = null;
031: private int cursorParentIndex = 0;
032: private int cursorDepth = 0;
033: private boolean isDragging = false;
034:
035: private DragSource dragSource;
036: private DragSourceListener dragSourceListener;
037: private static Icon openIcon;
038: private static Icon closedIcon;
039: private static int baseIndent;
040: private static final int MARGIN = 4;
041:
042: static {
043: URL url1 = ScriptTable.class
044: .getResource("icons/triangle-dn.gif");
045: URL url2 = ScriptTable.class
046: .getResource("icons/triangle-rt.gif");
047: if (url1 != null && url2 != null) {
048: openIcon = new ImageIcon(url1);
049: closedIcon = new ImageIcon(url2);
050: } else {
051: BasicTreeUI ui = (BasicTreeUI) (new JTree().getUI());
052: openIcon = ui.getExpandedIcon();
053: closedIcon = ui.getCollapsedIcon();
054: }
055: baseIndent = openIcon.getIconWidth();
056: }
057:
058: private ScriptModel model;
059:
060: public ScriptTable() {
061: this (new ScriptModel());
062: }
063:
064: public ScriptTable(ScriptModel scriptModel) {
065: super (scriptModel);
066: setSelectionModel(new SelectionModel());
067: model = scriptModel;
068: TableCellRenderer cr = new ScriptTableCellRenderer();
069: setDefaultRenderer(Object.class, cr);
070: Dimension spacing = getIntercellSpacing();
071: spacing.height = 2;
072: setIntercellSpacing(spacing);
073:
074: initDragDrop();
075:
076: // Detect clicks on the table in order to position the cursor
077: // and expand entries.
078: MouseListener ml = new MouseAdapter() {
079: public void mouseClicked(MouseEvent me) {
080: if (me.getModifiers() != InputEvent.BUTTON1_MASK)
081: return;
082: if (me.getClickCount() == 2) {
083: int row = rowAtPoint(me.getPoint());
084: Log.debug("Toggling row at " + row);
085: toggle(row);
086: } else {
087: click(me.getPoint());
088: }
089: }
090: };
091: addMouseListener(ml);
092: // Set up our custom actions; note that there are no default input
093: // bindings
094: ActionMap map = getActionMap();
095: map.put("move-rows-up", new AbstractAction() {
096: public void actionPerformed(ActionEvent ev) {
097: moveUp();
098: }
099: });
100: map.put("move-rows-down", new AbstractAction() {
101: public void actionPerformed(ActionEvent ev) {
102: moveDown();
103: }
104: });
105: map.put("toggle", new AbstractAction() {
106: public void actionPerformed(ActionEvent ev) {
107: int selRow = getSelectedRow();
108: if (selRow != -1) {
109: toggle(selRow);
110: }
111: }
112: });
113: }
114:
115: /** Toggle the open/closed state of a sequence. */
116: public void toggle(int row) {
117: int[] rows = getSelectedRows();
118: if (rows.length > 0) {
119: int anchor = getSelectionModel().getAnchorSelectionIndex();
120: Step first = model.getStepAt(rows[0]);
121: int lastRow = rows[rows.length - 1];
122: Step last = model.getStepAt(lastRow);
123: Step afterLast = lastRow < getRowCount() - 1 ? model
124: .getStepAt(lastRow + 1) : null;
125: clearSelection();
126: model.toggle(row);
127: int index0 = model.getRowOf(first);
128: int index1 = model.getRowOf(last);
129: // If the last step in the selection becomes hidden, change the
130: // selection and the cursor position.
131: if (index1 == -1) {
132: index1 = afterLast == null ? row : model
133: .getRowOf(afterLast) - 1;
134: }
135: if (anchor == index0) {
136: Log.debug("Updating selection to " + index0 + " to "
137: + index1);
138: setRowSelectionInterval(index0, index1);
139: } else {
140: Log.debug("Updating selection to " + index1 + " to "
141: + index0);
142: setRowSelectionInterval(index1, index0);
143: }
144: } else {
145: model.toggle(row);
146: }
147: }
148:
149: /** Return the bounding for the given cell. If the step at the given row
150: * is contained within a sequence, the rect will be offset to the right.
151: */
152: public Rectangle getCellRect(int row, int col, boolean includeBorder) {
153: Rectangle rect = super .getCellRect(row, col, includeBorder);
154: int indent = getIndentation(row);
155: rect.x += indent;
156: rect.width -= indent;
157: return rect;
158: }
159:
160: /** Return the number of pixels offset from the left edge of the table for
161: the given row.
162: */
163: public int getIndentation(int row) {
164: return getDepthIndentation(model.getNestingDepthAt(row));
165: }
166:
167: /** Return the number of pixels offset from the left edge of the table for
168: the given level of indentation.
169: */
170: public int getDepthIndentation(int depth) {
171: return baseIndent * depth;
172: }
173:
174: private void click(Point pt) {
175: int row = rowAtPoint(pt);
176: if (row == -1) {
177: clearSelection();
178: setCursorLocation(getRowCount());
179: } else {
180: Rectangle rect = getCellRect(row, 0, true);
181: // If the click is on the open/close icon, then toggle
182: if ((model.getStepAt(row) instanceof Sequence)
183: && pt.x >= rect.x
184: && pt.x < rect.x + baseIndent
185: && pt.y > rect.y + rect.height / MARGIN
186: && pt.y < rect.y + rect.height * (MARGIN - 1)
187: / MARGIN) {
188: toggle(row);
189: } else {
190: setCursorLocation(pt);
191: }
192: }
193: }
194:
195: private void initDragDrop() {
196: int action = DnDConstants.ACTION_MOVE;
197: dragSource = DragSource.getDefaultDragSource();
198: DragGestureListener dgl = new DGListener();
199: dragSource
200: .createDefaultDragGestureRecognizer(this , action, dgl);
201: dragSourceListener = new DSListener();
202:
203: DropTarget dt = new DropTarget(this , new DTListener());
204: dt.setDefaultActions(DnDConstants.ACTION_MOVE);
205: }
206:
207: /** Determine what the background color for the given step should be. */
208: protected Color getStepColor(Step step, boolean selected) {
209: return selected ? getSelectionBackground() : getBackground();
210: }
211:
212: /** Returns the script context of the currently selected row. */
213: public Script getScriptContext() {
214: int row = getSelectedRow();
215: if (row == -1)
216: return model.getScript();
217: return model.getScriptOf(row);
218: }
219:
220: /** Returns the row number of the cursor. The number of cursor locations
221: * is one greater than the number of table
222: * entries.
223: */
224: public int getCursorRow() {
225: return cursorRow;
226: }
227:
228: /** Returns the target parent of the current cursor location. */
229: public Sequence getCursorParent() {
230: return cursorParent;
231: }
232:
233: /** Returns the target index within the parent of the current cursor
234: location. */
235: public int getCursorParentIndex() {
236: return cursorParentIndex;
237: }
238:
239: protected Rectangle getCursorBounds() {
240: Insets insets = getInsets();
241: Dimension d = getSize();
242: Dimension m = getIntercellSpacing();
243: if (m.height == 0)
244: m.height = 1;
245: int width = d.width - insets.left - insets.right;
246: int row = Math.min(cursorRow, getRowCount() - 1);
247: Rectangle cellRect = super .getCellRect(row, 0, false);
248: int y = cellRect.y;
249: if (cursorRow == getRowCount())
250: y += cellRect.height + m.height;
251: int indent = getDepthIndentation(cursorDepth);
252: return new Rectangle(indent, y - m.height, width - indent,
253: m.height);
254: }
255:
256: /** Given an arbitrary point within the table, return the nearest valid
257: row for the cursor to be placed.
258: */
259: private int getCursorRowAtPoint(Point where) {
260: int row = rowAtPoint(where);
261: if (row == -1) {
262: row = where.y < 0 ? 0 : getRowCount();
263: } else {
264: Rectangle rect = super .getCellRect(row, 0, true);
265: if (where.getY() > rect.y + rect.height / 2)
266: ++row;
267: }
268: // When dragging, don't put the cursor somewhere which would produce
269: // no effect, or which would be illegal.
270: if (isDragging) {
271: int selStart = getSelectedRow();
272: int count = getSelectedRowCount();
273: if (row > selStart && row <= selStart + count) {
274: if (row > count / 2
275: && selStart + count + 1 < getRowCount()) {
276: row = selStart + count + 1;
277: } else {
278: row = selStart;
279: }
280: }
281: }
282:
283: return row;
284: }
285:
286: // FIXME sometimes the cursor row leads the selected row by two
287: public void setCursorLocation(Point where) {
288: int row = getCursorRowAtPoint(where);
289: setCursorLocation(row, where.x);
290: }
291:
292: /** Set the cursor location, using the given indentation to determine the
293: * appropriate target parent sequence.
294: */
295: private void setCursorLocation(int row, int indentation) {
296: Rectangle oldRect = getCursorBounds();
297: Script script = model.getScript();
298: if (script == null)
299: return;
300: // Can't position the cursor after a terminate step
301: if (script.hasTerminate() && row == getRowCount())
302: --row;
303: else if (script.hasLaunch() && row == 0)
304: ++row;
305: cursorRow = row;
306: Sequence parent = script;
307: int index = row == getRowCount() ? parent.size() : parent
308: .indexOf(model.getStepAt(row));
309: int depth = 0;
310: if (row > 0) {
311: // Place the cursor based on the previous step
312: Step prev = model.getStepAt(row - 1);
313: if (model.isOpen(prev)) {
314: parent = (Sequence) prev;
315: index = 0;
316: // Depth is one greater than the depth of the parent
317: depth = model.getNestingDepthAt(row - 1) + 1;
318: } else {
319: parent = model.getParent(prev);
320: index = parent.indexOf(prev) + 1;
321: depth = model.getNestingDepthAt(row - 1);
322: }
323: int indent = getDepthIndentation(depth);
324: // Shift up the hierarchy until we reach the appropriate
325: // indentation level.
326: while (indent > indentation && parent != script) {
327: Sequence nextUp = model.getParent(parent);
328: index = nextUp.indexOf(parent) + 1;
329: parent = nextUp;
330: indent = getDepthIndentation(--depth);
331: }
332: }
333: cursorParent = parent;
334: cursorParentIndex = index;
335: cursorDepth = depth;
336: if (oldRect != null)
337: repaint(oldRect);
338: repaint(getCursorBounds());
339: }
340:
341: /** Set the cursor location to a reasonable target for the given row. */
342: public void setCursorLocation(int row) {
343: setCursorLocation(row, 0);
344: }
345:
346: protected void drawCursor(Graphics g, int row) {
347: g.setColor(Color.green);
348: ((Graphics2D) g).fill(getCursorBounds());
349: }
350:
351: /** We paint a cursor where insertions will take effect. */
352: public void paint(Graphics g) {
353: super .paint(g);
354: drawCursor(g, cursorRow == getRowCount() ? cursorRow - 1
355: : cursorRow);
356: }
357:
358: public void autoscroll(Point pt) {
359: Rectangle bounds = getBounds();
360: Log.debug("autoscroll at " + pt + " bounds " + bounds);
361:
362: // Figure out which row we're on.
363: int row = rowAtPoint(pt);
364: if (row < 0)
365: return;
366:
367: if (pt.y + bounds.y <= AUTOSCROLL_MARGIN) {
368: if (row > 0)
369: --row;
370: } else {
371: if (row < getRowCount() - 1)
372: ++row;
373: }
374: scrollRectToVisible(getCellRect(row, 0, true));
375: }
376:
377: private static final int AUTOSCROLL_MARGIN = 12;
378:
379: public Insets getAutoscrollInsets() {
380: // Calculate the insets for the JTree, not the viewport the tree is
381: // in.
382: Rectangle tree = getBounds();
383: Rectangle view = getParent().getBounds();
384: return new Insets(view.y - tree.y + AUTOSCROLL_MARGIN, view.x
385: - tree.x + AUTOSCROLL_MARGIN, tree.height - view.height
386: - view.y + tree.y + AUTOSCROLL_MARGIN, tree.width
387: - view.width - view.x + tree.x + AUTOSCROLL_MARGIN);
388: }
389:
390: private class ScriptTableCellRenderer extends
391: DefaultTableCellRenderer {
392: public Component getTableCellRendererComponent(JTable table,
393: Object value, boolean sel, boolean focus, int row,
394: int col) {
395: // We know that the default renderer for a JTable
396: // is a subclass of JLabel
397: JLabel renderer = (JLabel) super
398: .getTableCellRendererComponent(table, value, sel,
399: focus, row, col);
400: Step step = model.getStepAt(row);
401: Icon icon = null;
402: if (step instanceof Sequence) {
403: icon = model.isOpen(row) ? openIcon : closedIcon;
404: }
405: renderer.setIcon(icon);
406:
407: super .setBackground(getStepColor(step, sel));
408: setOpaque(true);
409:
410: return renderer;
411: }
412: }
413:
414: /** Return the first selected step. */
415: public Step getSelectedStep() {
416: return getSelectedRowCount() > 0 ? model
417: .getStepAt(getSelectedRow()) : null;
418: }
419:
420: /** Return the set of selected steps, restricted to siblings of the first
421: selected row.
422: */
423: public List getSelectedSteps() {
424: ArrayList list = new ArrayList();
425: int[] rows = getSelectedRows();
426: if (rows.length > 0) {
427: Step step = model.getStepAt(rows[0]);
428: Sequence parent = model.getParent(step);
429: for (int i = 0; i < rows.length; i++) {
430: step = model.getStepAt(rows[i]);
431: if (model.getParent(step) == parent) {
432: list.add(step);
433: }
434: }
435: }
436: return list;
437: }
438:
439: public boolean canMoveDown() {
440: int[] rows = getSelectedRows();
441: int max = getRowCount()
442: - (model.getScript().hasTerminate() ? 2 : 1);
443: return rows[rows.length - 1] < max;
444: }
445:
446: public boolean canMoveUp() {
447: int row = getSelectedRow();
448: int min = model.getScript().hasLaunch() ? 1 : 0;
449: return row > min
450: && !(model.getStepAt(row) instanceof Terminate);
451: }
452:
453: /** Move the selected step(s) up. If the previous row is part of an open
454: * sequence, move to the end of the sequence. Otherwise, switch places
455: * with the step at the previous row.
456: */
457: public void moveUp() {
458: if (!canMoveUp())
459: return;
460: List list = getSelectedSteps();
461: int leadRow = getSelectedRow();
462: Step lead = (Step) list.get(0);
463: Sequence parent = model.getParent(lead);
464: Step prev = model.getStepAt(leadRow - 1);
465: int targetIndex = 0;
466: // If the previous row to the selection is its parent, move previous
467: // to the parent.
468: if (parent.indexOf(lead) == 0) {
469: Log.debug("Move out of sequence");
470: Sequence newParent = model.getParent(parent);
471: targetIndex = newParent.indexOf(parent);
472: parent = newParent;
473: }
474: // Is the previous step part of an open sequence?
475: else if (model.isOpen(prev)) {
476: Log.debug("Move to previous empty open sequence");
477: parent = (Sequence) prev;
478: targetIndex = 0;
479: } else if (model.getParent(prev) != parent) {
480: Log.debug("Move to previous open sequence");
481: parent = model.getParent(prev);
482: targetIndex = parent.indexOf(prev) + 1;
483: } else {
484: Log.debug("Move previous");
485: targetIndex = parent.indexOf(prev);
486: }
487: moveSelectedRows(parent, targetIndex);
488: }
489:
490: /** Move the currently selected rows down one row. */
491: public void moveDown() {
492: if (!canMoveDown()) {
493: Log.warn("Unexpected move down state");
494: return;
495: }
496: List list = getSelectedSteps();
497: Step lead = (Step) list.get(0);
498: Sequence leadParent = model.getParent(lead);
499: int[] rows = getSelectedRows();
500: Step next = model.getStepAt(rows[rows.length - 1] + 1);
501: Sequence parent = model.getParent(next);
502: // Default behavior moves after the next step
503: int targetIndex = parent.indexOf(next) + 1;
504: // If the next step after the selection is not a sibling,
505: // make the group a sibling to its old parent
506: if (leadParent != parent) {
507: Sequence nextParent = model.getParent(leadParent);
508: targetIndex = nextParent.indexOf(leadParent) + 1;
509: parent = nextParent;
510: }
511: // If the next step is an open sequence, move into it
512: else if (model.isOpen(next)) {
513: parent = (Sequence) next;
514: targetIndex = 0;
515: }
516: moveSelectedRows(parent, targetIndex);
517: }
518:
519: /** Move the currently selected rows into the given parent at the given
520: index.
521: */
522: public void moveSelectedRows(Sequence parent, int index) {
523: List steps = getSelectedSteps();
524: Step first = (Step) steps.get(0);
525: if (parent.indexOf(first) == index)
526: return;
527:
528: ListSelectionModel lsm = getSelectionModel();
529: boolean firstIsAnchor = getSelectedRow() == lsm
530: .getAnchorSelectionIndex();
531: model.moveSteps(parent, steps, index);
532: int firstRow = model.getRowOf(first);
533: if (firstIsAnchor)
534: lsm.setSelectionInterval(firstRow, firstRow + steps.size()
535: - 1);
536: else
537: lsm.setSelectionInterval(firstRow + steps.size() - 1,
538: firstRow);
539: }
540:
541: private class DGListener implements DragGestureListener {
542: public void dragGestureRecognized(DragGestureEvent e) {
543: Point where = e.getDragOrigin();
544: int firstRow = getSelectedRow();
545: if (firstRow == -1)
546: return;
547: if ((e.getDragAction() & DnDConstants.ACTION_MOVE) != 0) {
548: Transferable tf = getSelectedRowCount() > 1 ? new StepTransferable(
549: getSelectedSteps())
550: : new StepTransferable(getSelectedStep());
551: try {
552: Rectangle rect = getCellRect(firstRow, 0, true);
553: int count = getSelectedRowCount();
554: rect.height *= count;
555: Point offset = new Point(rect.x - where.x, rect.y
556: - where.y);
557: rect.x = rect.y = 0;
558: BufferedImage image = new BufferedImage(rect.width,
559: rect.height,
560: BufferedImage.TYPE_INT_ARGB_PRE);
561: Graphics2D graphics = image.createGraphics();
562:
563: graphics.setColor(Color.gray);
564: --rect.width;
565: --rect.height;
566: graphics.draw(rect);
567: graphics.dispose();
568:
569: e.startDrag(DragSource.DefaultMoveDrop, image,
570: offset, tf, dragSourceListener);
571: isDragging = true;
572: } catch (InvalidDnDOperationException exc) {
573: Log.warn(exc);
574: }
575: }
576: }
577: }
578:
579: /** Listens to events coming from the source of the drag action. */
580: private class DSListener implements DragSourceListener {
581: public void dragDropEnd(DragSourceDropEvent e) {
582: Log.debug("drag drop end " + e.getDropAction());
583: // OSX bug makes this fail, so do it in the target listener instead
584: if (!e.getDropSuccess()) {
585: Log.debug("drop failed");
586: }
587: }
588:
589: public void dragEnter(DragSourceDragEvent e) {
590: Log.debug("drag enter " + e.getDropAction());
591: DragSourceContext context = e.getDragSourceContext();
592: // intersection of the users selected action, and the source and
593: // target actions
594: int action = e.getDropAction();
595: if ((action & DnDConstants.ACTION_MOVE) != 0) {
596: context.setCursor(DragSource.DefaultMoveDrop);
597: } else {
598: context.setCursor(DragSource.DefaultMoveNoDrop);
599: }
600: }
601:
602: public void dragOver(DragSourceDragEvent e) {
603: }
604:
605: public void dragExit(DragSourceEvent e) {
606: }
607:
608: public void dropActionChanged(DragSourceDragEvent e) {
609: Log.debug("action changed " + e.getDropAction());
610: DragSourceContext context = e.getDragSourceContext();
611: context.setCursor(DragSource.DefaultMoveNoDrop);
612: }
613: }
614:
615: /** Listens to events coming from the target of the drag action. */
616: private class DTListener implements DropTargetListener {
617: public void dragEnter(DropTargetDragEvent e) {
618: if (!isDragAcceptable(e)) {
619: e.rejectDrag();
620: } else {
621: e.acceptDrag(DnDConstants.ACTION_MOVE);
622: }
623: }
624:
625: public void dragExit(DropTargetEvent e) {
626: }
627:
628: public void dropActionChanged(DropTargetDragEvent e) {
629: if (!isDragAcceptable(e)) {
630: e.rejectDrag();
631: } else {
632: e.acceptDrag(DnDConstants.ACTION_MOVE);
633: }
634: }
635:
636: public void dragOver(DropTargetDragEvent e) {
637: Log.debug("drag over target " + e.getDropAction());
638: if (isDragAcceptable(e)) {
639: e.acceptDrag(DnDConstants.ACTION_MOVE);
640: Rectangle last = getCursorBounds();
641: setCursorLocation(e.getLocation());
642: Rectangle current = getCursorBounds();
643: paintImmediately(last);
644: paintImmediately(current);
645: } else {
646: e.rejectDrag();
647: }
648: }
649:
650: public void drop(DropTargetDropEvent e) {
651: Log.debug("drop successful " + e.getDropAction());
652: if (!isDropAcceptable(e)) {
653: e.rejectDrop();
654: } else {
655: e.acceptDrop(DnDConstants.ACTION_MOVE);
656: moveSelectedRows(cursorParent, cursorParentIndex);
657: }
658: e.dropComplete(true);
659: }
660:
661: public boolean isDragAcceptable(DropTargetDragEvent e) {
662: Log.debug("drag action is " + e.getDropAction());
663: return e
664: .isDataFlavorSupported(StepTransferable.STEP_FLAVOR);
665: }
666:
667: public boolean isDropAcceptable(DropTargetDropEvent e) {
668: Log.debug("drop action is " + e.getDropAction());
669: return e
670: .isDataFlavorSupported(StepTransferable.STEP_FLAVOR);
671: }
672: }
673:
674: /** If any sub-steps of a sequence are selected, they <i>all</i> must be
675: selected. Also select all children when selecting an open sequence.
676: */
677: private class SelectionModel extends DefaultListSelectionModel {
678: public SelectionModel() {
679: setSelectionMode(SINGLE_INTERVAL_SELECTION);
680: }
681:
682: private void fixSelection() {
683: if (getSelectedRowCount() == 0
684: || (getSelectedRowCount() == 1 && !model
685: .isOpen(getSelectedRow()))) {
686: return;
687: }
688: // Ensure the first selection has at maximum the minimum depth
689: // Ensure the row after the last selection has at minimum the
690: // minimum depth.
691: int anchor = getAnchorSelectionIndex();
692: int lead = getLeadSelectionIndex();
693: int lo, hi;
694: if (anchor < lead) {
695: lo = anchor;
696: hi = lead;
697: } else {
698: lo = lead;
699: hi = anchor;
700: }
701: int loDepth = model.getNestingDepthAt(lo);
702: int minDepth = loDepth;
703: for (int i = lo + 1; i <= hi; i++) {
704: minDepth = Math.min(minDepth, model
705: .getNestingDepthAt(i));
706: }
707: if (loDepth > minDepth) {
708: for (int i = lo - 1; i >= 0; i--) {
709: if (model.getNestingDepthAt(i) == minDepth) {
710: Log.debug("Changing low end to " + i);
711: if (lo == anchor)
712: setSelectionInterval(lo = i, hi);
713: else
714: setSelectionInterval(hi, lo = i);
715: break;
716: }
717: }
718: }
719: int last = hi + 1;
720: while (last < getRowCount()
721: && model.getNestingDepthAt(last) > minDepth) {
722: ++last;
723: }
724: if (last > hi + 1) {
725: Log.debug("Changing hi end to " + (last - 1));
726: if (hi == lead)
727: setSelectionInterval(lo, last - 1);
728: else
729: setSelectionInterval(last - 1, lo);
730: }
731: }
732:
733: public void addSelectionInterval(int index0, int index1) {
734: super .addSelectionInterval(index0, index1);
735: fixSelection();
736: }
737:
738: public void removeSelectionInterval(int index0, int index1) {
739: super .removeSelectionInterval(index0, index1);
740: fixSelection();
741: }
742:
743: public void setAnchorSelectionIndex(int index) {
744: super .setAnchorSelectionIndex(index);
745: fixSelection();
746: }
747:
748: public void setLeadSelectionIndex(int index) {
749: super .setLeadSelectionIndex(index);
750: fixSelection();
751: }
752:
753: public void setSelectionInterval(int index0, int index1) {
754: super .setSelectionInterval(index0, index1);
755: fixSelection();
756: }
757:
758: public void insertIndexInterval(int index, int length,
759: boolean bfore) {
760: super .insertIndexInterval(index, length, bfore);
761: fixSelection();
762: }
763:
764: public void removeIndexInterval(int idx0, int idx1) {
765: super.removeIndexInterval(idx0, idx1);
766: fixSelection();
767: }
768: }
769: }
|