OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [text/] [JTextComponent.java] - Blame information for rev 775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* JTextComponent.java --
2
   Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package javax.swing.text;
40
 
41
import gnu.java.lang.CPStringBuilder;
42
 
43
import java.awt.AWTEvent;
44
import java.awt.Color;
45
import java.awt.Container;
46
import java.awt.Dimension;
47
import java.awt.Insets;
48
import java.awt.Point;
49
import java.awt.Rectangle;
50
import java.awt.Shape;
51
import java.awt.datatransfer.Clipboard;
52
import java.awt.datatransfer.DataFlavor;
53
import java.awt.datatransfer.StringSelection;
54
import java.awt.datatransfer.Transferable;
55
import java.awt.datatransfer.UnsupportedFlavorException;
56
import java.awt.event.ActionEvent;
57
import java.awt.event.InputMethodListener;
58
import java.awt.event.KeyEvent;
59
import java.awt.event.MouseEvent;
60
import java.io.IOException;
61
import java.io.Reader;
62
import java.io.Writer;
63
import java.text.BreakIterator;
64
import java.util.Enumeration;
65
import java.util.Hashtable;
66
 
67
import javax.accessibility.Accessible;
68
import javax.accessibility.AccessibleAction;
69
import javax.accessibility.AccessibleContext;
70
import javax.accessibility.AccessibleEditableText;
71
import javax.accessibility.AccessibleRole;
72
import javax.accessibility.AccessibleState;
73
import javax.accessibility.AccessibleStateSet;
74
import javax.accessibility.AccessibleText;
75
import javax.swing.Action;
76
import javax.swing.ActionMap;
77
import javax.swing.InputMap;
78
import javax.swing.JComponent;
79
import javax.swing.JViewport;
80
import javax.swing.KeyStroke;
81
import javax.swing.Scrollable;
82
import javax.swing.SwingConstants;
83
import javax.swing.TransferHandler;
84
import javax.swing.UIManager;
85
import javax.swing.event.CaretEvent;
86
import javax.swing.event.CaretListener;
87
import javax.swing.event.DocumentEvent;
88
import javax.swing.event.DocumentListener;
89
import javax.swing.plaf.ActionMapUIResource;
90
import javax.swing.plaf.InputMapUIResource;
91
import javax.swing.plaf.TextUI;
92
 
93
public abstract class JTextComponent extends JComponent
94
  implements Scrollable, Accessible
95
{
96
  /**
97
   * AccessibleJTextComponent implements accessibility hooks for
98
   * JTextComponent.  It allows an accessibility driver to read and
99
   * manipulate the text component's contents as well as update UI
100
   * elements such as the caret.
101
   */
102
  public class AccessibleJTextComponent extends AccessibleJComponent implements
103
      AccessibleText, CaretListener, DocumentListener, AccessibleAction,
104
      AccessibleEditableText
105
  {
106
    private static final long serialVersionUID = 7664188944091413696L;
107
 
108
    /**
109
     * The caret's offset.
110
     */
111
    private int caretDot;
112
 
113
    /**
114
     * Construct an AccessibleJTextComponent.
115
     */
116
    public AccessibleJTextComponent()
117
    {
118
      super();
119
      JTextComponent.this.addCaretListener(this);
120
      caretDot = getCaretPosition();
121
    }
122
 
123
    /**
124
     * Retrieve the current caret position.  The index of the first
125
     * caret position is 0.
126
     *
127
     * @return caret position
128
     */
129
    public int getCaretPosition()
130
    {
131
      return JTextComponent.this.getCaretPosition();
132
    }
133
 
134
    /**
135
     * Retrieve the current text selection.  If no text is selected
136
     * this method returns null.
137
     *
138
     * @return the currently selected text or null
139
     */
140
    public String getSelectedText()
141
    {
142
      return JTextComponent.this.getSelectedText();
143
    }
144
 
145
    /**
146
     * Retrieve the index of the first character in the current text
147
     * selection.  If there is no text in the text component, this
148
     * method returns 0.  If there is text in the text component, but
149
     * there is no selection, this method returns the current caret
150
     * position.
151
     *
152
     * @return the index of the first character in the selection, the
153
     * current caret position or 0
154
     */
155
    public int getSelectionStart()
156
    {
157
      if (getSelectedText() == null
158
          || (JTextComponent.this.getText().equals("")))
159
        return 0;
160
      return JTextComponent.this.getSelectionStart();
161
    }
162
 
163
    /**
164
     * Retrieve the index of the last character in the current text
165
     * selection.  If there is no text in the text component, this
166
     * method returns 0.  If there is text in the text component, but
167
     * there is no selection, this method returns the current caret
168
     * position.
169
     *
170
     * @return the index of the last character in the selection, the
171
     * current caret position or 0
172
     */
173
    public int getSelectionEnd()
174
    {
175
      return JTextComponent.this.getSelectionEnd();
176
    }
177
 
178
    /**
179
     * Handle a change in the caret position and fire any applicable
180
     * property change events.
181
     *
182
     * @param e - the caret update event
183
     */
184
    public void caretUpdate(CaretEvent e)
185
    {
186
      int dot = e.getDot();
187
      int mark = e.getMark();
188
      if (caretDot != dot)
189
        {
190
          firePropertyChange(ACCESSIBLE_CARET_PROPERTY, new Integer(caretDot),
191
                             new Integer(dot));
192
          caretDot = dot;
193
        }
194
      if (mark != dot)
195
        {
196
          firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null,
197
                             getSelectedText());
198
        }
199
    }
200
 
201
    /**
202
     * Retreive the accessible state set of this component.
203
     *
204
     * @return the accessible state set of this component
205
     */
206
    public AccessibleStateSet getAccessibleStateSet()
207
    {
208
      AccessibleStateSet state = super.getAccessibleStateSet();
209
      if (isEditable())
210
        state.add(AccessibleState.EDITABLE);
211
      return state;
212
    }
213
 
214
    /**
215
     * Retrieve the accessible role of this component.
216
     *
217
     * @return the accessible role of this component
218
     *
219
     * @see AccessibleRole
220
     */
221
    public AccessibleRole getAccessibleRole()
222
    {
223
      return AccessibleRole.TEXT;
224
    }
225
 
226
    /**
227
     * Retrieve an AccessibleEditableText object that controls this
228
     * text component.
229
     *
230
     * @return this
231
     */
232
    public AccessibleEditableText getAccessibleEditableText()
233
    {
234
      return this;
235
    }
236
 
237
    /**
238
     * Retrieve an AccessibleText object that controls this text
239
     * component.
240
     *
241
     * @return this
242
     *
243
     * @see AccessibleText
244
     */
245
    public AccessibleText getAccessibleText()
246
    {
247
      return this;
248
    }
249
 
250
    /**
251
     * Handle a text insertion event and fire an
252
     * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
253
     * event.
254
     *
255
     * @param e - the insertion event
256
     */
257
    public void insertUpdate(DocumentEvent e)
258
    {
259
      firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
260
                         new Integer(e.getOffset()));
261
    }
262
 
263
    /**
264
     * Handle a text removal event and fire an
265
     * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
266
     * event.
267
     *
268
     * @param e - the removal event
269
     */
270
    public void removeUpdate(DocumentEvent e)
271
    {
272
      firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
273
                         new Integer(e.getOffset()));
274
    }
275
 
276
    /**
277
     * Handle a text change event and fire an
278
     * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
279
     * event.
280
     *
281
     * @param e - text change event
282
     */
283
    public void changedUpdate(DocumentEvent e)
284
    {
285
      firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
286
                         new Integer(e.getOffset()));
287
    }
288
 
289
    /**
290
     * Get the index of the character at the given point, in component
291
     * pixel co-ordinates.  If the point argument is invalid this
292
     * method returns -1.
293
     *
294
     * @param p - a point in component pixel co-ordinates
295
     *
296
     * @return a character index, or -1
297
     */
298
    public int getIndexAtPoint(Point p)
299
    {
300
      return viewToModel(p);
301
    }
302
 
303
    /**
304
     * Calculate the bounding box of the character at the given index.
305
     * The returned x and y co-ordinates are relative to this text
306
     * component's top-left corner.  If the index is invalid this
307
     * method returns null.
308
     *
309
     * @param index - the character index
310
     *
311
     * @return a character's bounding box, or null
312
     */
313
    public Rectangle getCharacterBounds(int index)
314
    {
315
      // This is basically the same as BasicTextUI.modelToView().
316
 
317
      Rectangle bounds = null;
318
      if (index >= 0 && index < doc.getLength() - 1)
319
        {
320
          if (doc instanceof AbstractDocument)
321
            ((AbstractDocument) doc).readLock();
322
          try
323
            {
324
              TextUI ui = getUI();
325
              if (ui != null)
326
                {
327
                  // Get editor rectangle.
328
                  Rectangle rect = new Rectangle();
329
                  Insets insets = getInsets();
330
                  rect.x = insets.left;
331
                  rect.y = insets.top;
332
                  rect.width = getWidth() - insets.left - insets.right;
333
                  rect.height = getHeight() - insets.top - insets.bottom;
334
                  View rootView = ui.getRootView(JTextComponent.this);
335
                  if (rootView != null)
336
                    {
337
                      rootView.setSize(rect.width, rect.height);
338
                      Shape s = rootView.modelToView(index,
339
                                                     Position.Bias.Forward,
340
                                                     index + 1,
341
                                                     Position.Bias.Backward,
342
                                                     rect);
343
                      if (s != null)
344
                        bounds = s.getBounds();
345
                    }
346
                }
347
            }
348
          catch (BadLocationException ex)
349
            {
350
              // Ignore (return null).
351
            }
352
          finally
353
            {
354
              if (doc instanceof AbstractDocument)
355
                ((AbstractDocument) doc).readUnlock();
356
            }
357
        }
358
      return bounds;
359
    }
360
 
361
    /**
362
     * Return the length of the text in this text component.
363
     *
364
     * @return a character length
365
     */
366
    public int getCharCount()
367
    {
368
      return JTextComponent.this.getText().length();
369
    }
370
 
371
   /**
372
    * Gets the character attributes of the character at index. If
373
    * the index is out of bounds, null is returned.
374
    *
375
    * @param index - index of the character
376
    *
377
    * @return the character's attributes
378
    */
379
    public AttributeSet getCharacterAttribute(int index)
380
    {
381
      AttributeSet atts;
382
      if (doc instanceof AbstractDocument)
383
        ((AbstractDocument) doc).readLock();
384
      try
385
        {
386
          Element el = doc.getDefaultRootElement();
387
          while (! el.isLeaf())
388
            {
389
              int i = el.getElementIndex(index);
390
              el = el.getElement(i);
391
            }
392
          atts = el.getAttributes();
393
        }
394
      finally
395
        {
396
          if (doc instanceof AbstractDocument)
397
            ((AbstractDocument) doc).readUnlock();
398
        }
399
      return atts;
400
    }
401
 
402
    /**
403
     * Gets the text located at index. null is returned if the index
404
     * or part is invalid.
405
     *
406
     * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
407
     * @param index - index of the part
408
     *
409
     * @return the part of text at that index, or null
410
     */
411
    public String getAtIndex(int part, int index)
412
    {
413
      return getAtIndexImpl(part, index, 0);
414
    }
415
 
416
    /**
417
     * Gets the text located after index. null is returned if the index
418
     * or part is invalid.
419
     *
420
     * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
421
     * @param index - index after the part
422
     *
423
     * @return the part of text after that index, or null
424
     */
425
    public String getAfterIndex(int part, int index)
426
    {
427
      return getAtIndexImpl(part, index, 1);
428
    }
429
 
430
    /**
431
     * Gets the text located before index. null is returned if the index
432
     * or part is invalid.
433
     *
434
     * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
435
     * @param index - index before the part
436
     *
437
     * @return the part of text before that index, or null
438
     */
439
    public String getBeforeIndex(int part, int index)
440
    {
441
      return getAtIndexImpl(part, index, -1);
442
    }
443
 
444
    /**
445
     * Implements getAtIndex(), getBeforeIndex() and getAfterIndex().
446
     *
447
     * @param part the part to return, either CHARACTER, WORD or SENTENCE
448
     * @param index the index
449
     * @param dir the direction, -1 for backwards, 0 for here, +1 for forwards
450
     *
451
     * @return the resulting string
452
     */
453
    private String getAtIndexImpl(int part, int index, int dir)
454
    {
455
      String ret = null;
456
      if (doc instanceof AbstractDocument)
457
        ((AbstractDocument) doc).readLock();
458
      try
459
        {
460
          BreakIterator iter = null;
461
          switch (part)
462
          {
463
            case CHARACTER:
464
              iter = BreakIterator.getCharacterInstance(getLocale());
465
              break;
466
            case WORD:
467
              iter = BreakIterator.getWordInstance(getLocale());
468
              break;
469
            case SENTENCE:
470
              iter = BreakIterator.getSentenceInstance(getLocale());
471
              break;
472
            default:
473
              break;
474
          }
475
          String text = doc.getText(0, doc.getLength() - 1);
476
          iter.setText(text);
477
          int start = index;
478
          int end = index;
479
          switch (dir)
480
          {
481
          case 0:
482
            if (iter.isBoundary(index))
483
              {
484
                start = index;
485
                end = iter.following(index);
486
              }
487
            else
488
              {
489
                start = iter.preceding(index);
490
                end = iter.next();
491
              }
492
            break;
493
          case 1:
494
            start = iter.following(index);
495
            end = iter.next();
496
            break;
497
          case -1:
498
            end = iter.preceding(index);
499
            start = iter.previous();
500
            break;
501
          default:
502
            assert false;
503
          }
504
          ret = text.substring(start, end);
505
        }
506
      catch (BadLocationException ex)
507
        {
508
          // Ignore (return null).
509
        }
510
      finally
511
        {
512
          if (doc instanceof AbstractDocument)
513
            ((AbstractDocument) doc).readUnlock();
514
        }
515
      return ret;
516
    }
517
 
518
    /**
519
     * Returns the number of actions for this object. The zero-th
520
     * object represents the default action.
521
     *
522
     * @return the number of actions (0-based).
523
     */
524
    public int getAccessibleActionCount()
525
    {
526
      return getActions().length;
527
    }
528
 
529
    /**
530
     * Returns the description of the i-th action. Null is returned if
531
     * i is out of bounds.
532
     *
533
     * @param i - the action to get the description for
534
     *
535
     * @return description of the i-th action
536
     */
537
    public String getAccessibleActionDescription(int i)
538
    {
539
      String desc = null;
540
      Action[] actions = getActions();
541
      if (i >= 0 && i < actions.length)
542
        desc = (String) actions[i].getValue(Action.NAME);
543
      return desc;
544
    }
545
 
546
    /**
547
     * Performs the i-th action. Nothing happens if i is
548
     * out of bounds.
549
     *
550
     * @param i - the action to perform
551
     *
552
     * @return true if the action was performed successfully
553
     */
554
    public boolean doAccessibleAction(int i)
555
    {
556
      boolean ret = false;
557
      Action[] actions = getActions();
558
      if (i >= 0 && i < actions.length)
559
        {
560
          ActionEvent ev = new ActionEvent(JTextComponent.this,
561
                                           ActionEvent.ACTION_PERFORMED, null);
562
          actions[i].actionPerformed(ev);
563
          ret = true;
564
        }
565
      return ret;
566
    }
567
 
568
    /**
569
     * Sets the text contents.
570
     *
571
     * @param s - the new text contents.
572
     */
573
    public void setTextContents(String s)
574
    {
575
      setText(s);
576
    }
577
 
578
    /**
579
     * Inserts the text at the given index.
580
     *
581
     * @param index - the index to insert the new text at.
582
     * @param s - the new text
583
     */
584
    public void insertTextAtIndex(int index, String s)
585
    {
586
      try
587
        {
588
          doc.insertString(index, s, null);
589
        }
590
      catch (BadLocationException ex)
591
        {
592
          // What should we do with this?
593
          ex.printStackTrace();
594
        }
595
    }
596
 
597
    /**
598
     * Gets the text between two indexes.
599
     *
600
     * @param start - the starting index (inclusive)
601
     * @param end - the ending index (exclusive)
602
     */
603
    public String getTextRange(int start, int end)
604
    {
605
      try
606
      {
607
        return JTextComponent.this.getText(start, end - start);
608
      }
609
      catch (BadLocationException ble)
610
      {
611
        return "";
612
      }
613
    }
614
 
615
    /**
616
     * Deletes the text between two indexes.
617
     *
618
     * @param start - the starting index (inclusive)
619
     * @param end - the ending index (exclusive)
620
     */
621
    public void delete(int start, int end)
622
    {
623
      replaceText(start, end, "");
624
    }
625
 
626
    /**
627
     * Cuts the text between two indexes. The text is put
628
     * into the system clipboard.
629
     *
630
     * @param start - the starting index (inclusive)
631
     * @param end - the ending index (exclusive)
632
     */
633
    public void cut(int start, int end)
634
    {
635
      JTextComponent.this.select(start, end);
636
      JTextComponent.this.cut();
637
    }
638
 
639
    /**
640
     * Pastes the text from the system clipboard to the given index.
641
     *
642
     * @param start - the starting index
643
     */
644
    public void paste(int start)
645
    {
646
      JTextComponent.this.setCaretPosition(start);
647
      JTextComponent.this.paste();
648
    }
649
 
650
    /**
651
     * Replaces the text between two indexes with the given text.
652
     *
653
     *
654
     * @param start - the starting index (inclusive)
655
     * @param end - the ending index (exclusive)
656
     * @param s - the text to paste
657
     */
658
    public void replaceText(int start, int end, String s)
659
    {
660
      JTextComponent.this.select(start, end);
661
      JTextComponent.this.replaceSelection(s);
662
    }
663
 
664
    /**
665
     * Selects the text between two indexes.
666
     *
667
     * @param start - the starting index (inclusive)
668
     * @param end - the ending index (exclusive)
669
     */
670
    public void selectText(int start, int end)
671
    {
672
      JTextComponent.this.select(start, end);
673
    }
674
 
675
    /**
676
     * Sets the attributes of all the text between two indexes.
677
     *
678
     * @param start - the starting index (inclusive)
679
     * @param end - the ending index (exclusive)
680
     * @param s - the new attribute set for the text in the range
681
     */
682
    public void setAttributes(int start, int end, AttributeSet s)
683
    {
684
      if (doc instanceof StyledDocument)
685
        {
686
          StyledDocument sdoc = (StyledDocument) doc;
687
          sdoc.setCharacterAttributes(start, end - start, s, true);
688
        }
689
    }
690
  }
691
 
692
  public static class KeyBinding
693
  {
694
    public KeyStroke key;
695
    public String actionName;
696
 
697
    /**
698
     * Creates a new <code>KeyBinding</code> instance.
699
     *
700
     * @param key a <code>KeyStroke</code> value
701
     * @param actionName a <code>String</code> value
702
     */
703
    public KeyBinding(KeyStroke key, String actionName)
704
    {
705
      this.key = key;
706
      this.actionName = actionName;
707
    }
708
  }
709
 
710
  /**
711
   * According to <a
712
   * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">this
713
   * report</a>, a pair of private classes wraps a {@link
714
   * javax.swing.text.Keymap} in the new {@link InputMap} / {@link
715
   * ActionMap} interfaces, such that old Keymap-using code can make use of
716
   * the new framework.
717
   *
718
   * <p>A little bit of experimentation with these classes reveals the following
719
   * structure:
720
   *
721
   * <ul>
722
   *
723
   * <li>KeymapWrapper extends {@link InputMap} and holds a reference to
724
   * the underlying {@link Keymap}.</li>
725
   *
726
   * <li>KeymapWrapper maps {@link KeyStroke} objects to {@link Action}
727
   * objects, by delegation to the underlying {@link Keymap}.</li>
728
   *
729
   * <li>KeymapActionMap extends {@link ActionMap} also holds a reference to
730
   * the underlying {@link Keymap} but only appears to use it for listing
731
   * its keys. </li>
732
   *
733
   * <li>KeymapActionMap maps all {@link Action} objects to
734
   * <em>themselves</em>, whether they exist in the underlying {@link
735
   * Keymap} or not, and passes other objects to the parent {@link
736
   * ActionMap} for resolving.
737
   *
738
   * </ul>
739
   */
740
 
741
  private class KeymapWrapper extends InputMap
742
  {
743
    Keymap map;
744
 
745
    public KeymapWrapper(Keymap k)
746
    {
747
      map = k;
748
    }
749
 
750
    public int size()
751
    {
752
      return map.getBoundKeyStrokes().length + super.size();
753
    }
754
 
755
    public Object get(KeyStroke ks)
756
    {
757
      Action mapped = null;
758
      Keymap m = map;
759
      while(mapped == null && m != null)
760
        {
761
          mapped = m.getAction(ks);
762
          if (mapped == null && ks.getKeyEventType() == KeyEvent.KEY_TYPED)
763
            mapped = m.getDefaultAction();
764
          if (mapped == null)
765
            m = m.getResolveParent();
766
        }
767
 
768
      if (mapped == null)
769
        return super.get(ks);
770
      else
771
        return mapped;
772
    }
773
 
774
    public KeyStroke[] keys()
775
    {
776
      KeyStroke[] superKeys = super.keys();
777
      KeyStroke[] mapKeys = map.getBoundKeyStrokes();
778
      KeyStroke[] bothKeys = new KeyStroke[superKeys.length + mapKeys.length];
779
      for (int i = 0; i < superKeys.length; ++i)
780
        bothKeys[i] = superKeys[i];
781
      for (int i = 0; i < mapKeys.length; ++i)
782
        bothKeys[i + superKeys.length] = mapKeys[i];
783
      return bothKeys;
784
    }
785
 
786
    public KeyStroke[] allKeys()
787
    {
788
      KeyStroke[] superKeys = super.allKeys();
789
      KeyStroke[] mapKeys = map.getBoundKeyStrokes();
790
      int skl = 0;
791
      int mkl = 0;
792
      if (superKeys != null)
793
        skl = superKeys.length;
794
      if (mapKeys != null)
795
        mkl = mapKeys.length;
796
      KeyStroke[] bothKeys = new KeyStroke[skl + mkl];
797
      for (int i = 0; i < skl; ++i)
798
        bothKeys[i] = superKeys[i];
799
      for (int i = 0; i < mkl; ++i)
800
        bothKeys[i + skl] = mapKeys[i];
801
      return bothKeys;
802
    }
803
  }
804
 
805
  private class KeymapActionMap extends ActionMap
806
  {
807
    Keymap map;
808
 
809
    public KeymapActionMap(Keymap k)
810
    {
811
      map = k;
812
    }
813
 
814
    public Action get(Object cmd)
815
    {
816
      if (cmd instanceof Action)
817
        return (Action) cmd;
818
      else
819
        return super.get(cmd);
820
    }
821
 
822
    public int size()
823
    {
824
      return map.getBoundKeyStrokes().length + super.size();
825
    }
826
 
827
    public Object[] keys()
828
    {
829
      Object[] superKeys = super.keys();
830
      Object[] mapKeys = map.getBoundKeyStrokes();
831
      Object[] bothKeys = new Object[superKeys.length + mapKeys.length];
832
      for (int i = 0; i < superKeys.length; ++i)
833
        bothKeys[i] = superKeys[i];
834
      for (int i = 0; i < mapKeys.length; ++i)
835
        bothKeys[i + superKeys.length] = mapKeys[i];
836
      return bothKeys;
837
    }
838
 
839
    public Object[] allKeys()
840
    {
841
      Object[] superKeys = super.allKeys();
842
      Object[] mapKeys = map.getBoundKeyStrokes();
843
      Object[] bothKeys = new Object[superKeys.length + mapKeys.length];
844
      for (int i = 0; i < superKeys.length; ++i)
845
        bothKeys[i] = superKeys[i];
846
      for (int i = 0; i < mapKeys.length; ++i)
847
        bothKeys[i + superKeys.length] = mapKeys[i];
848
      return bothKeys;
849
    }
850
 
851
  }
852
 
853
  static class DefaultKeymap implements Keymap
854
  {
855
    String name;
856
    Keymap parent;
857
    Hashtable map;
858
    Action defaultAction;
859
 
860
    public DefaultKeymap(String name)
861
    {
862
      this.name = name;
863
      this.map = new Hashtable();
864
    }
865
 
866
    public void addActionForKeyStroke(KeyStroke key, Action a)
867
    {
868
      map.put(key, a);
869
    }
870
 
871
    /**
872
     * Looks up a KeyStroke either in the current map or the parent Keymap;
873
     * does <em>not</em> return the default action if lookup fails.
874
     *
875
     * @param key The KeyStroke to look up an Action for.
876
     *
877
     * @return The mapping for <code>key</code>, or <code>null</code>
878
     * if no mapping exists in this Keymap or any of its parents.
879
     */
880
    public Action getAction(KeyStroke key)
881
    {
882
      if (map.containsKey(key))
883
        return (Action) map.get(key);
884
      else if (parent != null)
885
        return parent.getAction(key);
886
      else
887
        return null;
888
    }
889
 
890
    public Action[] getBoundActions()
891
    {
892
      Action [] ret = new Action[map.size()];
893
      Enumeration e = map.elements();
894
      int i = 0;
895
      while (e.hasMoreElements())
896
        {
897
          ret[i++] = (Action) e.nextElement();
898
        }
899
      return ret;
900
    }
901
 
902
    public KeyStroke[] getBoundKeyStrokes()
903
    {
904
      KeyStroke [] ret = new KeyStroke[map.size()];
905
      Enumeration e = map.keys();
906
      int i = 0;
907
      while (e.hasMoreElements())
908
        {
909
          ret[i++] = (KeyStroke) e.nextElement();
910
        }
911
      return ret;
912
    }
913
 
914
    public Action getDefaultAction()
915
    {
916
      return defaultAction;
917
    }
918
 
919
    public KeyStroke[] getKeyStrokesForAction(Action a)
920
    {
921
      int i = 0;
922
      Enumeration e = map.keys();
923
      while (e.hasMoreElements())
924
        {
925
          if (map.get(e.nextElement()).equals(a))
926
            ++i;
927
        }
928
      KeyStroke [] ret = new KeyStroke[i];
929
      i = 0;
930
      e = map.keys();
931
      while (e.hasMoreElements())
932
        {
933
          KeyStroke k = (KeyStroke) e.nextElement();
934
          if (map.get(k).equals(a))
935
            ret[i++] = k;
936
        }
937
      return ret;
938
    }
939
 
940
    public String getName()
941
    {
942
      return name;
943
    }
944
 
945
    public Keymap getResolveParent()
946
    {
947
      return parent;
948
    }
949
 
950
    public boolean isLocallyDefined(KeyStroke key)
951
    {
952
      return map.containsKey(key);
953
    }
954
 
955
    public void removeBindings()
956
    {
957
      map.clear();
958
    }
959
 
960
    public void removeKeyStrokeBinding(KeyStroke key)
961
    {
962
      map.remove(key);
963
    }
964
 
965
    public void setDefaultAction(Action a)
966
    {
967
      defaultAction = a;
968
    }
969
 
970
    public void setResolveParent(Keymap p)
971
    {
972
      parent = p;
973
    }
974
  }
975
 
976
  class DefaultTransferHandler extends TransferHandler
977
  {
978
    public boolean canImport(JComponent component, DataFlavor[] flavors)
979
    {
980
      JTextComponent textComponent = (JTextComponent) component;
981
 
982
      if (! (textComponent.isEnabled()
983
             && textComponent.isEditable()
984
             && flavors != null))
985
        return false;
986
 
987
      for (int i = 0; i < flavors.length; ++i)
988
        if (flavors[i].equals(DataFlavor.stringFlavor))
989
           return true;
990
 
991
      return false;
992
    }
993
 
994
    public void exportToClipboard(JComponent component, Clipboard clipboard,
995
                                  int action)
996
    {
997
      JTextComponent textComponent = (JTextComponent) component;
998
      int start = textComponent.getSelectionStart();
999
      int end = textComponent.getSelectionEnd();
1000
 
1001
      if (start == end)
1002
        return;
1003
 
1004
      try
1005
        {
1006
          // Copy text to clipboard.
1007
          String data = textComponent.getDocument().getText(start, end);
1008
          StringSelection selection = new StringSelection(data);
1009
          clipboard.setContents(selection, null);
1010
 
1011
          // Delete selected text on cut action.
1012
          if (action == MOVE)
1013
            doc.remove(start, end - start);
1014
        }
1015
      catch (BadLocationException e)
1016
        {
1017
          // Ignore this and do nothing.
1018
        }
1019
    }
1020
 
1021
    public int getSourceActions()
1022
    {
1023
      return NONE;
1024
    }
1025
 
1026
    public boolean importData(JComponent component, Transferable transferable)
1027
    {
1028
      DataFlavor flavor = null;
1029
      DataFlavor[] flavors = transferable.getTransferDataFlavors();
1030
 
1031
      if (flavors == null)
1032
        return false;
1033
 
1034
      for (int i = 0; i < flavors.length; ++i)
1035
        if (flavors[i].equals(DataFlavor.stringFlavor))
1036
          flavor = flavors[i];
1037
 
1038
      if (flavor == null)
1039
        return false;
1040
 
1041
      try
1042
        {
1043
          JTextComponent textComponent = (JTextComponent) component;
1044
          String data = (String) transferable.getTransferData(flavor);
1045
          textComponent.replaceSelection(data);
1046
          return true;
1047
        }
1048
      catch (IOException e)
1049
        {
1050
          // Ignored.
1051
        }
1052
      catch (UnsupportedFlavorException e)
1053
        {
1054
          // Ignored.
1055
        }
1056
 
1057
      return false;
1058
    }
1059
  }
1060
 
1061
  private static final long serialVersionUID = -8796518220218978795L;
1062
 
1063
  public static final String DEFAULT_KEYMAP = "default";
1064
  public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
1065
 
1066
  private static DefaultTransferHandler defaultTransferHandler;
1067
  private static Hashtable keymaps = new Hashtable();
1068
  private Keymap keymap;
1069
  private char focusAccelerator = '\0';
1070
  private NavigationFilter navigationFilter;
1071
 
1072
  /**
1073
   * Get a Keymap from the global keymap table, by name.
1074
   *
1075
   * @param n The name of the Keymap to look up
1076
   *
1077
   * @return A Keymap associated with the provided name, or
1078
   * <code>null</code> if no such Keymap exists
1079
   *
1080
   * @see #addKeymap
1081
   * @see #removeKeymap
1082
   * @see #keymaps
1083
   */
1084
  public static Keymap getKeymap(String n)
1085
  {
1086
    return (Keymap) keymaps.get(n);
1087
  }
1088
 
1089
  /**
1090
   * Remove a Keymap from the global Keymap table, by name.
1091
   *
1092
   * @param n The name of the Keymap to remove
1093
   *
1094
   * @return The keymap removed from the global table
1095
   *
1096
   * @see #addKeymap
1097
   * @see #getKeymap()
1098
   * @see #keymaps
1099
   */
1100
  public static Keymap removeKeymap(String n)
1101
  {
1102
    Keymap km = (Keymap) keymaps.get(n);
1103
    keymaps.remove(n);
1104
    return km;
1105
  }
1106
 
1107
  /**
1108
   * Create a new Keymap with a specific name and parent, and add the new
1109
   * Keymap to the global keymap table. The name may be <code>null</code>,
1110
   * in which case the new Keymap will <em>not</em> be added to the global
1111
   * Keymap table. The parent may also be <code>null</code>, which is
1112
   * harmless.
1113
   *
1114
   * @param n The name of the new Keymap, or <code>null</code>
1115
   * @param parent The parent of the new Keymap, or <code>null</code>
1116
   *
1117
   * @return The newly created Keymap
1118
   *
1119
   * @see #removeKeymap
1120
   * @see #getKeymap()
1121
   * @see #keymaps
1122
   */
1123
  public static Keymap addKeymap(String n, Keymap parent)
1124
  {
1125
    Keymap k = new DefaultKeymap(n);
1126
    k.setResolveParent(parent);
1127
    if (n != null)
1128
      keymaps.put(n, k);
1129
    return k;
1130
  }
1131
 
1132
  /**
1133
   * Get the current Keymap of this component.
1134
   *
1135
   * @return The component's current Keymap
1136
   *
1137
   * @see #setKeymap
1138
   * @see #keymap
1139
   */
1140
  public Keymap getKeymap()
1141
  {
1142
    return keymap;
1143
  }
1144
 
1145
  /**
1146
   * Set the current Keymap of this component, installing appropriate
1147
   * {@link KeymapWrapper} and {@link KeymapActionMap} objects in the
1148
   * {@link InputMap} and {@link ActionMap} parent chains, respectively,
1149
   * and fire a property change event with name <code>"keymap"</code>.
1150
   *
1151
   * @see #getKeymap()
1152
   * @see #keymap
1153
   */
1154
  public void setKeymap(Keymap k)
1155
  {
1156
 
1157
    // phase 1: replace the KeymapWrapper entry in the InputMap chain.
1158
    // the goal here is to always maintain the following ordering:
1159
    //
1160
    //   [InputMap]? -> [KeymapWrapper]? -> [InputMapUIResource]*
1161
    //
1162
    // that is to say, component-specific InputMaps need to remain children
1163
    // of Keymaps, and Keymaps need to remain children of UI-installed
1164
    // InputMaps (and the order of each group needs to be preserved, of
1165
    // course).
1166
 
1167
    KeymapWrapper kw = (k == null ? null : new KeymapWrapper(k));
1168
    InputMap childInputMap = getInputMap(JComponent.WHEN_FOCUSED);
1169
    if (childInputMap == null)
1170
      setInputMap(JComponent.WHEN_FOCUSED, kw);
1171
    else
1172
      {
1173
        while (childInputMap.getParent() != null
1174
               && !(childInputMap.getParent() instanceof KeymapWrapper)
1175
               && !(childInputMap.getParent() instanceof InputMapUIResource))
1176
          childInputMap = childInputMap.getParent();
1177
 
1178
        // option 1: there is nobody to replace at the end of the chain
1179
        if (childInputMap.getParent() == null)
1180
          childInputMap.setParent(kw);
1181
 
1182
        // option 2: there is already a KeymapWrapper in the chain which
1183
        // needs replacing (possibly with its own parents, possibly without)
1184
        else if (childInputMap.getParent() instanceof KeymapWrapper)
1185
          {
1186
            if (kw == null)
1187
              childInputMap.setParent(childInputMap.getParent().getParent());
1188
            else
1189
              {
1190
                kw.setParent(childInputMap.getParent().getParent());
1191
                childInputMap.setParent(kw);
1192
              }
1193
          }
1194
 
1195
        // option 3: there is an InputMapUIResource in the chain, which marks
1196
        // the place where we need to stop and insert ourselves
1197
        else if (childInputMap.getParent() instanceof InputMapUIResource)
1198
          {
1199
            if (kw != null)
1200
              {
1201
                kw.setParent(childInputMap.getParent());
1202
                childInputMap.setParent(kw);
1203
              }
1204
          }
1205
      }
1206
 
1207
    // phase 2: replace the KeymapActionMap entry in the ActionMap chain
1208
 
1209
    KeymapActionMap kam = (k == null ? null : new KeymapActionMap(k));
1210
    ActionMap childActionMap = getActionMap();
1211
    if (childActionMap == null)
1212
      setActionMap(kam);
1213
    else
1214
      {
1215
        while (childActionMap.getParent() != null
1216
               && !(childActionMap.getParent() instanceof KeymapActionMap)
1217
               && !(childActionMap.getParent() instanceof ActionMapUIResource))
1218
          childActionMap = childActionMap.getParent();
1219
 
1220
        // option 1: there is nobody to replace at the end of the chain
1221
        if (childActionMap.getParent() == null)
1222
          childActionMap.setParent(kam);
1223
 
1224
        // option 2: there is already a KeymapActionMap in the chain which
1225
        // needs replacing (possibly with its own parents, possibly without)
1226
        else if (childActionMap.getParent() instanceof KeymapActionMap)
1227
          {
1228
            if (kam == null)
1229
              childActionMap.setParent(childActionMap.getParent().getParent());
1230
            else
1231
              {
1232
                kam.setParent(childActionMap.getParent().getParent());
1233
                childActionMap.setParent(kam);
1234
              }
1235
          }
1236
 
1237
        // option 3: there is an ActionMapUIResource in the chain, which marks
1238
        // the place where we need to stop and insert ourselves
1239
        else if (childActionMap.getParent() instanceof ActionMapUIResource)
1240
          {
1241
            if (kam != null)
1242
              {
1243
                kam.setParent(childActionMap.getParent());
1244
                childActionMap.setParent(kam);
1245
              }
1246
          }
1247
      }
1248
 
1249
    // phase 3: update the explicit keymap field
1250
 
1251
    Keymap old = keymap;
1252
    keymap = k;
1253
    firePropertyChange("keymap", old, k);
1254
  }
1255
 
1256
  /**
1257
   * Resolves a set of bindings against a set of actions and inserts the
1258
   * results into a {@link Keymap}. Specifically, for each provided binding
1259
   * <code>b</code>, if there exists a provided action <code>a</code> such
1260
   * that <code>a.getValue(Action.NAME) == b.ActionName</code> then an
1261
   * entry is added to the Keymap mapping <code>b</code> to
1262
   * <code>a</code>.
1263
   *
1264
   * @param map The Keymap to add new mappings to
1265
   * @param bindings The set of bindings to add to the Keymap
1266
   * @param actions The set of actions to resolve binding names against
1267
   *
1268
   * @see Action#NAME
1269
   * @see Action#getValue
1270
   * @see KeyBinding#actionName
1271
   */
1272
  public static void loadKeymap(Keymap map,
1273
                                JTextComponent.KeyBinding[] bindings,
1274
                                Action[] actions)
1275
  {
1276
    Hashtable acts = new Hashtable(actions.length);
1277
    for (int i = 0; i < actions.length; ++i)
1278
      acts.put(actions[i].getValue(Action.NAME), actions[i]);
1279
      for (int i = 0; i < bindings.length; ++i)
1280
      if (acts.containsKey(bindings[i].actionName))
1281
        map.addActionForKeyStroke(bindings[i].key, (Action) acts.get(bindings[i].actionName));
1282
  }
1283
 
1284
  /**
1285
   * Returns the set of available Actions this component's associated
1286
   * editor can run.  Equivalent to calling
1287
   * <code>getUI().getEditorKit().getActions()</code>. This set of Actions
1288
   * is a reasonable value to provide as a parameter to {@link
1289
   * #loadKeymap}, when resolving a set of {@link KeyBinding} objects
1290
   * against this component.
1291
   *
1292
   * @return The set of available Actions on this component's {@link EditorKit}
1293
   *
1294
   * @see TextUI#getEditorKit
1295
   * @see EditorKit#getActions()
1296
   */
1297
  public Action[] getActions()
1298
  {
1299
    return getUI().getEditorKit(this).getActions();
1300
  }
1301
 
1302
  // These are package-private to avoid an accessor method.
1303
  Document doc;
1304
  Caret caret;
1305
  boolean editable;
1306
 
1307
  private Highlighter highlighter;
1308
  private Color caretColor;
1309
  private Color disabledTextColor;
1310
  private Color selectedTextColor;
1311
  private Color selectionColor;
1312
  private Insets margin;
1313
  private boolean dragEnabled;
1314
 
1315
  /**
1316
   * Creates a new <code>JTextComponent</code> instance.
1317
   */
1318
  public JTextComponent()
1319
  {
1320
    Keymap defkeymap = getKeymap(DEFAULT_KEYMAP);
1321
    if (defkeymap == null)
1322
      {
1323
        defkeymap = addKeymap(DEFAULT_KEYMAP, null);
1324
        defkeymap.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction());
1325
      }
1326
 
1327
    setFocusable(true);
1328
    setEditable(true);
1329
    enableEvents(AWTEvent.KEY_EVENT_MASK);
1330
    setOpaque(true);
1331
    updateUI();
1332
  }
1333
 
1334
  public void setDocument(Document newDoc)
1335
  {
1336
    Document oldDoc = doc;
1337
    try
1338
      {
1339
        if (oldDoc instanceof AbstractDocument)
1340
          ((AbstractDocument) oldDoc).readLock();
1341
 
1342
        doc = newDoc;
1343
        firePropertyChange("document", oldDoc, newDoc);
1344
      }
1345
    finally
1346
      {
1347
        if (oldDoc instanceof AbstractDocument)
1348
          ((AbstractDocument) oldDoc).readUnlock();
1349
      }
1350
    revalidate();
1351
    repaint();
1352
  }
1353
 
1354
  public Document getDocument()
1355
  {
1356
    return doc;
1357
  }
1358
 
1359
  /**
1360
   * Get the <code>AccessibleContext</code> of this object.
1361
   *
1362
   * @return an <code>AccessibleContext</code> object
1363
   */
1364
  public AccessibleContext getAccessibleContext()
1365
  {
1366
    return new AccessibleJTextComponent();
1367
  }
1368
 
1369
  public void setMargin(Insets m)
1370
  {
1371
    margin = m;
1372
  }
1373
 
1374
  public Insets getMargin()
1375
  {
1376
    return margin;
1377
  }
1378
 
1379
  public void setText(String text)
1380
  {
1381
    try
1382
      {
1383
        if (doc instanceof AbstractDocument)
1384
          ((AbstractDocument) doc).replace(0, doc.getLength(), text, null);
1385
        else
1386
          {
1387
            doc.remove(0, doc.getLength());
1388
            doc.insertString(0, text, null);
1389
          }
1390
      }
1391
    catch (BadLocationException e)
1392
      {
1393
        // This can never happen.
1394
        throw (InternalError) new InternalError().initCause(e);
1395
      }
1396
  }
1397
 
1398
  /**
1399
   * Retrieves the current text in this text document.
1400
   *
1401
   * @return the text
1402
   *
1403
   * @exception NullPointerException if the underlaying document is null
1404
   */
1405
  public String getText()
1406
  {
1407
    if (doc == null)
1408
      return null;
1409
 
1410
    try
1411
      {
1412
        return doc.getText(0, doc.getLength());
1413
      }
1414
    catch (BadLocationException e)
1415
      {
1416
        // This should never happen.
1417
        return "";
1418
      }
1419
  }
1420
 
1421
  /**
1422
   * Retrieves a part of the current text in this document.
1423
   *
1424
   * @param offset the postion of the first character
1425
   * @param length the length of the text to retrieve
1426
   *
1427
   * @return the text
1428
   *
1429
   * @exception BadLocationException if arguments do not hold pre-conditions
1430
   */
1431
  public String getText(int offset, int length)
1432
    throws BadLocationException
1433
  {
1434
    return getDocument().getText(offset, length);
1435
  }
1436
 
1437
  /**
1438
   * Retrieves the currently selected text in this text document.
1439
   *
1440
   * @return the selected text
1441
   *
1442
   * @exception NullPointerException if the underlaying document is null
1443
   */
1444
  public String getSelectedText()
1445
  {
1446
    int start = getSelectionStart();
1447
    int offset = getSelectionEnd() - start;
1448
 
1449
    if (offset <= 0)
1450
      return null;
1451
 
1452
    try
1453
      {
1454
        return doc.getText(start, offset);
1455
      }
1456
    catch (BadLocationException e)
1457
      {
1458
        // This should never happen.
1459
        return null;
1460
      }
1461
  }
1462
 
1463
  /**
1464
   * Returns a string that specifies the name of the Look and Feel class
1465
   * that renders this component.
1466
   *
1467
   * @return the string "TextComponentUI"
1468
   */
1469
  public String getUIClassID()
1470
  {
1471
    return "TextComponentUI";
1472
  }
1473
 
1474
  /**
1475
   * Returns a string representation of this JTextComponent.
1476
   */
1477
  protected String paramString()
1478
  {
1479
    // TODO: Do something useful here.
1480
    return super.paramString();
1481
  }
1482
 
1483
  /**
1484
   * This method returns the label's UI delegate.
1485
   *
1486
   * @return The label's UI delegate.
1487
   */
1488
  public TextUI getUI()
1489
  {
1490
    return (TextUI) ui;
1491
  }
1492
 
1493
  /**
1494
   * This method sets the label's UI delegate.
1495
   *
1496
   * @param newUI The label's UI delegate.
1497
   */
1498
  public void setUI(TextUI newUI)
1499
  {
1500
    super.setUI(newUI);
1501
  }
1502
 
1503
  /**
1504
   * This method resets the label's UI delegate to the default UI for the
1505
   * current look and feel.
1506
   */
1507
  public void updateUI()
1508
  {
1509
    setUI((TextUI) UIManager.getUI(this));
1510
  }
1511
 
1512
  public Dimension getPreferredScrollableViewportSize()
1513
  {
1514
    return getPreferredSize();
1515
  }
1516
 
1517
  public int getScrollableUnitIncrement(Rectangle visible, int orientation,
1518
                                        int direction)
1519
  {
1520
    // We return 1/10 of the visible area as documented in Sun's API docs.
1521
    if (orientation == SwingConstants.HORIZONTAL)
1522
      return visible.width / 10;
1523
    else if (orientation == SwingConstants.VERTICAL)
1524
      return visible.height / 10;
1525
    else
1526
      throw new IllegalArgumentException("orientation must be either "
1527
                                      + "javax.swing.SwingConstants.VERTICAL "
1528
                                      + "or "
1529
                                      + "javax.swing.SwingConstants.HORIZONTAL"
1530
                                         );
1531
  }
1532
 
1533
  public int getScrollableBlockIncrement(Rectangle visible, int orientation,
1534
                                         int direction)
1535
  {
1536
    // We return the whole visible area as documented in Sun's API docs.
1537
    if (orientation == SwingConstants.HORIZONTAL)
1538
      return visible.width;
1539
    else if (orientation == SwingConstants.VERTICAL)
1540
      return visible.height;
1541
    else
1542
      throw new IllegalArgumentException("orientation must be either "
1543
                                      + "javax.swing.SwingConstants.VERTICAL "
1544
                                      + "or "
1545
                                      + "javax.swing.SwingConstants.HORIZONTAL"
1546
                                         );
1547
  }
1548
 
1549
  /**
1550
   * Checks whether this text component it editable.
1551
   *
1552
   * @return true if editable, false otherwise
1553
   */
1554
  public boolean isEditable()
1555
  {
1556
    return editable;
1557
  }
1558
 
1559
  /**
1560
   * Enables/disabled this text component's editability.
1561
   *
1562
   * @param newValue true to make it editable, false otherwise.
1563
   */
1564
  public void setEditable(boolean newValue)
1565
  {
1566
    if (editable == newValue)
1567
      return;
1568
 
1569
    boolean oldValue = editable;
1570
    editable = newValue;
1571
    firePropertyChange("editable", oldValue, newValue);
1572
  }
1573
 
1574
  /**
1575
   * The <code>Caret</code> object used in this text component.
1576
   *
1577
   * @return the caret object
1578
   */
1579
  public Caret getCaret()
1580
  {
1581
    return caret;
1582
  }
1583
 
1584
  /**
1585
   * Sets a new <code>Caret</code> for this text component.
1586
   *
1587
   * @param newCaret the new <code>Caret</code> to set
1588
   */
1589
  public void setCaret(Caret newCaret)
1590
  {
1591
    if (caret != null)
1592
      caret.deinstall(this);
1593
 
1594
    Caret oldCaret = caret;
1595
    caret = newCaret;
1596
 
1597
    if (caret != null)
1598
      caret.install(this);
1599
 
1600
    firePropertyChange("caret", oldCaret, newCaret);
1601
  }
1602
 
1603
  public Color getCaretColor()
1604
  {
1605
    return caretColor;
1606
  }
1607
 
1608
  public void setCaretColor(Color newColor)
1609
  {
1610
    Color oldCaretColor = caretColor;
1611
    caretColor = newColor;
1612
    firePropertyChange("caretColor", oldCaretColor, newColor);
1613
  }
1614
 
1615
  public Color getDisabledTextColor()
1616
  {
1617
    return disabledTextColor;
1618
  }
1619
 
1620
  public void setDisabledTextColor(Color newColor)
1621
  {
1622
    Color oldColor = disabledTextColor;
1623
    disabledTextColor = newColor;
1624
    firePropertyChange("disabledTextColor", oldColor, newColor);
1625
  }
1626
 
1627
  public Color getSelectedTextColor()
1628
  {
1629
    return selectedTextColor;
1630
  }
1631
 
1632
  public void setSelectedTextColor(Color newColor)
1633
  {
1634
    Color oldColor = selectedTextColor;
1635
    selectedTextColor = newColor;
1636
    firePropertyChange("selectedTextColor", oldColor, newColor);
1637
  }
1638
 
1639
  public Color getSelectionColor()
1640
  {
1641
    return selectionColor;
1642
  }
1643
 
1644
  public void setSelectionColor(Color newColor)
1645
  {
1646
    Color oldColor = selectionColor;
1647
    selectionColor = newColor;
1648
    firePropertyChange("selectionColor", oldColor, newColor);
1649
  }
1650
 
1651
  /**
1652
   * Retrisves the current caret position.
1653
   *
1654
   * @return the current position
1655
   */
1656
  public int getCaretPosition()
1657
  {
1658
    return caret.getDot();
1659
  }
1660
 
1661
  /**
1662
   * Sets the caret to a new position.
1663
   *
1664
   * @param position the new position
1665
   */
1666
  public void setCaretPosition(int position)
1667
  {
1668
    if (doc == null)
1669
      return;
1670
 
1671
    if (position < 0 || position > doc.getLength())
1672
      throw new IllegalArgumentException();
1673
 
1674
    caret.setDot(position);
1675
  }
1676
 
1677
  /**
1678
   * Moves the caret to a given position. This selects the text between
1679
   * the old and the new position of the caret.
1680
   */
1681
  public void moveCaretPosition(int position)
1682
  {
1683
    if (doc == null)
1684
      return;
1685
 
1686
    if (position < 0 || position > doc.getLength())
1687
      throw new IllegalArgumentException();
1688
 
1689
    caret.moveDot(position);
1690
  }
1691
 
1692
  public Highlighter getHighlighter()
1693
  {
1694
    return highlighter;
1695
  }
1696
 
1697
  public void setHighlighter(Highlighter newHighlighter)
1698
  {
1699
    if (highlighter != null)
1700
      highlighter.deinstall(this);
1701
 
1702
    Highlighter oldHighlighter = highlighter;
1703
    highlighter = newHighlighter;
1704
 
1705
    if (highlighter != null)
1706
      highlighter.install(this);
1707
 
1708
    firePropertyChange("highlighter", oldHighlighter, newHighlighter);
1709
  }
1710
 
1711
  /**
1712
   * Returns the start postion of the currently selected text.
1713
   *
1714
   * @return the start postion
1715
   */
1716
  public int getSelectionStart()
1717
  {
1718
    return Math.min(caret.getDot(), caret.getMark());
1719
  }
1720
 
1721
  /**
1722
   * Selects the text from the given postion to the selection end position.
1723
   *
1724
   * @param start the start positon of the selected text.
1725
   */
1726
  public void setSelectionStart(int start)
1727
  {
1728
    select(start, getSelectionEnd());
1729
  }
1730
 
1731
  /**
1732
   * Returns the end postion of the currently selected text.
1733
   *
1734
   * @return the end postion
1735
   */
1736
  public int getSelectionEnd()
1737
  {
1738
    return Math.max(caret.getDot(), caret.getMark());
1739
  }
1740
 
1741
  /**
1742
   * Selects the text from the selection start postion to the given position.
1743
   *
1744
   * @param end the end positon of the selected text.
1745
   */
1746
  public void setSelectionEnd(int end)
1747
  {
1748
    select(getSelectionStart(), end);
1749
  }
1750
 
1751
  /**
1752
   * Selects a part of the content of the text component.
1753
   *
1754
   * @param start the start position of the selected text
1755
   * @param end the end position of the selected text
1756
   */
1757
  public void select(int start, int end)
1758
  {
1759
    int length = doc.getLength();
1760
 
1761
    start = Math.max(start, 0);
1762
    start = Math.min(start, length);
1763
 
1764
    end = Math.max(end, start);
1765
    end = Math.min(end, length);
1766
 
1767
    setCaretPosition(start);
1768
    moveCaretPosition(end);
1769
  }
1770
 
1771
  /**
1772
   * Selects the whole content of the text component.
1773
   */
1774
  public void selectAll()
1775
  {
1776
    select(0, doc.getLength());
1777
  }
1778
 
1779
  public synchronized void replaceSelection(String content)
1780
  {
1781
    int dot = caret.getDot();
1782
    int mark = caret.getMark();
1783
 
1784
    // If content is empty delete selection.
1785
    if (content == null)
1786
      {
1787
        caret.setDot(dot);
1788
        return;
1789
      }
1790
 
1791
    try
1792
      {
1793
        int start = getSelectionStart();
1794
        int end = getSelectionEnd();
1795
 
1796
        // Remove selected text.
1797
        if (dot != mark)
1798
          doc.remove(start, end - start);
1799
 
1800
        // Insert new text.
1801
        doc.insertString(start, content, null);
1802
 
1803
        // Set dot to new position,
1804
        dot = start + content.length();
1805
        setCaretPosition(dot);
1806
 
1807
        // and update it's magic position.
1808
        caret.setMagicCaretPosition(modelToView(dot).getLocation());
1809
      }
1810
    catch (BadLocationException e)
1811
      {
1812
        // This should never happen.
1813
      }
1814
  }
1815
 
1816
  public boolean getScrollableTracksViewportHeight()
1817
  {
1818
    if (getParent() instanceof JViewport)
1819
      return getParent().getHeight() > getPreferredSize().height;
1820
 
1821
    return false;
1822
  }
1823
 
1824
  public boolean getScrollableTracksViewportWidth()
1825
  {
1826
    boolean res = false;
1827
    Container c = getParent();
1828
    if (c instanceof JViewport)
1829
      res = ((JViewport) c).getExtentSize().width > getPreferredSize().width;
1830
 
1831
    return res;
1832
  }
1833
 
1834
  /**
1835
   * Adds a <code>CaretListener</code> object to this text component.
1836
   *
1837
   * @param listener the listener to add
1838
   */
1839
  public void addCaretListener(CaretListener listener)
1840
  {
1841
    listenerList.add(CaretListener.class, listener);
1842
  }
1843
 
1844
  /**
1845
   * Removed a <code>CaretListener</code> object from this text component.
1846
   *
1847
   * @param listener the listener to remove
1848
   */
1849
  public void removeCaretListener(CaretListener listener)
1850
  {
1851
    listenerList.remove(CaretListener.class, listener);
1852
  }
1853
 
1854
  /**
1855
   * Returns all added <code>CaretListener</code> objects.
1856
   *
1857
   * @return an array of listeners
1858
   */
1859
  public CaretListener[] getCaretListeners()
1860
  {
1861
    return (CaretListener[]) getListeners(CaretListener.class);
1862
  }
1863
 
1864
  /**
1865
   * Notifies all registered <code>CaretListener</code> objects that the caret
1866
   * was updated.
1867
   *
1868
   * @param event the event to send
1869
   */
1870
  protected void fireCaretUpdate(CaretEvent event)
1871
  {
1872
    CaretListener[] listeners = getCaretListeners();
1873
 
1874
    for (int index = 0; index < listeners.length; ++index)
1875
      listeners[index].caretUpdate(event);
1876
  }
1877
 
1878
  /**
1879
   * Adds an <code>InputListener</code> object to this text component.
1880
   *
1881
   * @param listener the listener to add
1882
   */
1883
  public void addInputMethodListener(InputMethodListener listener)
1884
  {
1885
    listenerList.add(InputMethodListener.class, listener);
1886
  }
1887
 
1888
  /**
1889
   * Removes an <code>InputListener</code> object from this text component.
1890
   *
1891
   * @param listener the listener to remove
1892
   */
1893
  public void removeInputMethodListener(InputMethodListener listener)
1894
  {
1895
    listenerList.remove(InputMethodListener.class, listener);
1896
  }
1897
 
1898
  /**
1899
   * Returns all added <code>InputMethodListener</code> objects.
1900
   *
1901
   * @return an array of listeners
1902
   */
1903
  public InputMethodListener[] getInputMethodListeners()
1904
  {
1905
    return (InputMethodListener[]) getListeners(InputMethodListener.class);
1906
  }
1907
 
1908
  public Rectangle modelToView(int position) throws BadLocationException
1909
  {
1910
    return getUI().modelToView(this, position);
1911
  }
1912
 
1913
  public boolean getDragEnabled()
1914
  {
1915
    return dragEnabled;
1916
  }
1917
 
1918
  public void setDragEnabled(boolean enabled)
1919
  {
1920
    dragEnabled = enabled;
1921
  }
1922
 
1923
  public int viewToModel(Point pt)
1924
  {
1925
    return getUI().viewToModel(this, pt);
1926
  }
1927
 
1928
  public void copy()
1929
  {
1930
    if (isEnabled())
1931
    doTransferAction("copy", TransferHandler.getCopyAction());
1932
  }
1933
 
1934
  public void cut()
1935
  {
1936
    if (editable && isEnabled())
1937
      doTransferAction("cut", TransferHandler.getCutAction());
1938
  }
1939
 
1940
  public void paste()
1941
  {
1942
    if (editable && isEnabled())
1943
      doTransferAction("paste", TransferHandler.getPasteAction());
1944
  }
1945
 
1946
  private void doTransferAction(String name, Action action)
1947
  {
1948
    // Install default TransferHandler if none set.
1949
    if (getTransferHandler() == null)
1950
      {
1951
        if (defaultTransferHandler == null)
1952
          defaultTransferHandler = new DefaultTransferHandler();
1953
 
1954
        setTransferHandler(defaultTransferHandler);
1955
      }
1956
 
1957
    // Perform action.
1958
    ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
1959
                                        action.getValue(Action.NAME).toString());
1960
    action.actionPerformed(event);
1961
  }
1962
 
1963
  public void setFocusAccelerator(char newKey)
1964
  {
1965
    if (focusAccelerator == newKey)
1966
      return;
1967
 
1968
    char oldKey = focusAccelerator;
1969
    focusAccelerator = newKey;
1970
    firePropertyChange(FOCUS_ACCELERATOR_KEY, oldKey, newKey);
1971
  }
1972
 
1973
  public char getFocusAccelerator()
1974
  {
1975
    return focusAccelerator;
1976
  }
1977
 
1978
  /**
1979
   * @since 1.4
1980
   */
1981
  public NavigationFilter getNavigationFilter()
1982
  {
1983
    return navigationFilter;
1984
  }
1985
 
1986
  /**
1987
   * @since 1.4
1988
   */
1989
  public void setNavigationFilter(NavigationFilter filter)
1990
  {
1991
    navigationFilter = filter;
1992
  }
1993
 
1994
  /**
1995
   * Read and set the content this component. If not overridden, the
1996
   * method reads the component content as a plain text.
1997
   *
1998
   * The second parameter of this method describes the input stream. It can
1999
   * be String, URL, File and so on. If not null, this object is added to
2000
   * the properties of the associated document under the key
2001
   * {@link Document#StreamDescriptionProperty}.
2002
   *
2003
   * @param input an input stream to read from.
2004
   * @param streamDescription an object, describing the stream.
2005
   *
2006
   * @throws IOException if the reader throws it.
2007
   *
2008
   * @see #getDocument()
2009
   * @see Document#getProperty(Object)
2010
   */
2011
  public void read(Reader input, Object streamDescription)
2012
            throws IOException
2013
  {
2014
    if (streamDescription != null)
2015
      {
2016
        Document d = getDocument();
2017
        if (d != null)
2018
          d.putProperty(Document.StreamDescriptionProperty, streamDescription);
2019
      }
2020
 
2021
    CPStringBuilder b = new CPStringBuilder();
2022
    int c;
2023
 
2024
    // Read till -1 (EOF).
2025
    while ((c = input.read()) >= 0)
2026
      b.append((char) c);
2027
 
2028
    setText(b.toString());
2029
  }
2030
 
2031
  /**
2032
   * Write the content of this component to the given stream. If not
2033
   * overridden, the method writes the component content as a plain text.
2034
   *
2035
   * @param output the writer to write into.
2036
   *
2037
   * @throws IOException if the writer throws it.
2038
   */
2039
  public void write(Writer output)
2040
             throws IOException
2041
  {
2042
    output.write(getText());
2043
  }
2044
 
2045
  /**
2046
   * Returns the tooltip text for this text component for the given mouse
2047
   * event. This forwards the call to
2048
   * {@link TextUI#getToolTipText(JTextComponent, Point)}.
2049
   *
2050
   * @param ev the mouse event
2051
   *
2052
   * @return the tooltip text for this text component for the given mouse
2053
   *         event
2054
   */
2055
  public String getToolTipText(MouseEvent ev)
2056
  {
2057
    return getUI().getToolTipText(this, ev.getPoint());
2058
  }
2059
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.