JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / site / j2s / swingjs / plaf / JSTextUI.java
1 /*
2  * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package swingjs.plaf;
26
27 import swingjs.JSToolkit;
28 import swingjs.api.DOMNode;
29 import swingjs.api.JQueryObject;
30 import swingjs.api.JSFunction;
31 import jsjava.awt.Dimension;
32 import jsjava.awt.Insets;
33 import jsjava.awt.LayoutManager;
34 import jsjava.awt.event.ActionEvent;
35 import jsjavax.swing.AbstractAction;
36 import jsjavax.swing.Action;
37 import jsjavax.swing.ActionMap;
38 import jsjavax.swing.InputMap;
39 import jsjavax.swing.JComponent;
40 import jsjavax.swing.SwingUtilities;
41 import jsjavax.swing.UIManager;
42 import jsjavax.swing.plaf.ActionMapUIResource;
43 import jsjavax.swing.plaf.ComponentUI;
44 import jsjavax.swing.plaf.InputMapUIResource;
45 import jsjavax.swing.plaf.TextUI;
46 import jsjavax.swing.plaf.UIResource;
47 import jsjavax.swing.text.Caret;
48 import jsjavax.swing.text.DefaultEditorKit;
49 import jsjavax.swing.text.EditorKit;
50 import jsjavax.swing.text.JTextComponent;
51 import jsjavax.swing.text.TextAction;
52 //import jsjava.awt.KeyboardFocusManager;
53 //import jsjava.awt.datatransfer.DataFlavor;
54 //import jsjava.awt.datatransfer.Transferable;
55 //import jsjava.awt.datatransfer.UnsupportedFlavorException;
56 //import jsjava.awt.im.InputContext;
57 //import jsjava.io.IOException;
58 //import jsjava.io.InputStream;
59 //import jsjava.io.Reader;
60 //import jsjava.io.StringBufferInputStream;
61 //import jsjava.io.StringReader;
62 //import jsjava.io.StringWriter;
63 //import jsjavax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag;
64
65 /**
66  * <p>
67  * Basis of a text components look-and-feel. This provides the basic editor view
68  * and controller services that may be useful when creating a look-and-feel for
69  * an extension of <code>JTextComponent</code>.
70  * <p>
71  * Most state is held in the associated <code>JTextComponent</code> as bound
72  * properties, and the UI installs default values for the various properties.
73  * This default will install something for all of the properties. Typically, a
74  * LAF implementation will do more however. At a minimum, a LAF would generally
75  * install key bindings.
76  * <p>
77  * This class also provides some concurrency support if the
78  * <code>Document</code> associated with the JTextComponent is a subclass of
79  * <code>AbstractDocument</code>. Access to the View (or View hierarchy) is
80  * serialized between any thread mutating the model and the Swing event thread
81  * (which is expected to render, do model/view coordinate translation, etc).
82  * <em>Any access to the root view should first
83  * acquire a read-lock on the AbstractDocument and release that lock
84  * in a finally block.</em>
85  * <p>
86  * An important method to define is the {@link #getPropertyPrefix} method which
87  * is used as the basis of the keys used to fetch defaults from the UIManager.
88  * The string should reflect the type of TextUI (eg. TextField, TextArea, etc)
89  * without the particular LAF part of the name (eg Metal, Motif, etc).
90  * <p>
91  * To build a view of the model, one of the following strategies can be
92  * employed.
93  * <ol>
94  * <li>
95  * One strategy is to simply redefine the ViewFactory interface in the UI. By
96  * default, this UI itself acts as the factory for View implementations. This is
97  * useful for simple factories. To do this reimplement the {@link #create}
98  * method.
99  * <li>
100  * A common strategy for creating more complex types of documents is to have the
101  * EditorKit implementation return a factory. Since the EditorKit ties all of
102  * the pieces necessary to maintain a type of document, the factory is typically
103  * an important part of that and should be produced by the EditorKit
104  * implementation.
105  * </ol>
106  * <p>
107  * <strong>Warning:</strong> Serialized objects of this class will not be
108  * compatible with future Swing releases. The current serialization support is
109  * appropriate for short term storage or RMI between applications running the
110  * same version of Swing. As of 1.4, support for long term storage of all
111  * JavaBeans<sup><font size="-2">TM</font></sup> has been added to the
112  * <code>java.beans</code> package. Please see {@link jsjava.beans.XMLEncoder}.
113  * 
114  * @author Timothy Prinzing
115  * @author Shannon Hickey (drag and drop)
116  */
117 public abstract class JSTextUI extends JSComponentUI {// implements {ViewFactory
118                                                                                                                                                                                                                         // {
119         @SuppressWarnings("unused")
120         protected void setFocusable() {
121                 JQueryObject node = $(focusNode);
122                 Object me = this;
123
124                 /**
125                  * @j2sNative
126                  * 
127                  * node.focus(function() {me.notifyFocus(true)});
128                  * node.blur(function() {me.notifyFocus(false)});
129                  */
130                 {}
131         }
132         
133
134         protected String getComponentText() {
135                 return currentText = ((JTextComponent) c).getText();
136         }
137
138         protected void bindKeys(DOMNode domNode) {
139                 JSFunction f = null;
140                 JSEventHandler me = this;
141                 if (!((JTextComponent) c).isEditable())
142                         return;
143                 /**
144                  * @j2sNative
145                  * 
146                  *            f = function(event) { me.handleJSEvent(me.domNode, 401, event)
147                  *            }
148                  */
149                 {
150                         System.out.println(me);
151                 }
152                 $(domNode).bind("keydown keypress keyup", f);
153
154                 // TODO Auto-generated method stub
155
156         }
157
158         /**
159          * Initializes component properties, e.g. font, foreground, background, caret
160          * color, selection color, selected text color, disabled text color, and
161          * border color. The font, foreground, and background properties are only set
162          * if their current value is either null or a UIResource, other properties are
163          * set if the current value is null.
164          * 
165          * @see #uninstallDefaults
166          * @see #installUI
167          */
168         protected void installDefaults() {
169                 // String prefix = getPropertyPrefix();
170                 // Font f = editor.getFont();
171                 // if ((f == null) || (f instanceof UIResource)) {
172                 // editor.setFont(UIManager.getFont(prefix + ".font"));
173                 // }
174                 //
175                 // Color bg = editor.getBackground();
176                 // if ((bg == null) || (bg instanceof UIResource)) {
177                 // editor.setBackground(UIManager.getColor(prefix + ".background"));
178                 // }
179                 //
180                 // Color fg = editor.getForeground();
181                 // if ((fg == null) || (fg instanceof UIResource)) {
182                 // editor.setForeground(UIManager.getColor(prefix + ".foreground"));
183                 // }
184                 //
185                 // Color color = editor.getCaretColor();
186                 // if ((color == null) || (color instanceof UIResource)) {
187                 // editor.setCaretColor(UIManager.getColor(prefix + ".caretForeground"));
188                 // }
189                 //
190                 // Color s = editor.getSelectionColor();
191                 // if ((s == null) || (s instanceof UIResource)) {
192                 // editor.setSelectionColor(UIManager.getColor(prefix +
193                 // ".selectionBackground"));
194                 // }
195                 //
196                 // Color sfg = editor.getSelectedTextColor();
197                 // if ((sfg == null) || (sfg instanceof UIResource)) {
198                 // editor.setSelectedTextColor(UIManager.getColor(prefix +
199                 // ".selectionForeground"));
200                 // }
201                 //
202                 // Color dfg = editor.getDisabledTextColor();
203                 // if ((dfg == null) || (dfg instanceof UIResource)) {
204                 // editor.setDisabledTextColor(UIManager.getColor(prefix +
205                 // ".inactiveForeground"));
206                 // }
207                 //
208                 // Border b = editor.getBorder();
209                 // if ((b == null) || (b instanceof UIResource)) {
210                 // editor.setBorder(UIManager.getBorder(prefix + ".border"));
211                 // }
212                 //
213                 // Insets margin = editor.getMargin();
214                 // if (margin == null || margin instanceof UIResource) {
215                 // editor.setMargin(UIManager.getInsets(prefix + ".margin"));
216                 // }
217                 //
218                 // updateCursor();
219         }
220
221         private void installDefaults2() {
222                 // editor.addMouseListener(dragListener);
223                 // editor.addMouseMotionListener(dragListener);
224                 //
225                 // String prefix = getPropertyPrefix();
226
227                 Caret caret = editor.getCaret();
228                 if (caret == null || caret instanceof UIResource) {
229                         editor.setCaret(new JSCaret());
230                 }
231                 //
232                 // Highlighter highlighter = editor.getHighlighter();
233                 // if (highlighter == null || highlighter instanceof UIResource) {
234                 // editor.setHighlighter(createHighlighter());
235                 // }
236                 //
237                 // TransferHandler th = editor.getTransferHandler();
238                 // if (th == null || th instanceof UIResource) {
239                 // editor.setTransferHandler(getTransferHandler());
240                 // }
241         }
242
243         /**
244          * called by JmolCore.js
245          * 
246          * @return handled
247          */
248         public boolean handleJSEvent(Object target, int eventType, Object jQueryEvent) {
249                 System.out.println("Handling for " + id + " " + eventType + " "
250                                 + jQueryEvent);
251                 return updateHandler.handleJSEvent(this, eventType, jQueryEvent);
252         }
253
254         /**
255          * Sets the component properties that haven't been explicitly overridden to
256          * null. A property is considered overridden if its current value is not a
257          * UIResource.
258          * 
259          * @see #installDefaults
260          * @see #uninstallUI
261          */
262         protected void uninstallDefaults() {
263                 // editor.removeMouseListener(dragListener);
264                 // editor.removeMouseMotionListener(dragListener);
265                 //
266                 if (editor.getCaretColor() instanceof UIResource) {
267                         editor.setCaretColor(null);
268                 }
269
270                 if (editor.getSelectionColor() instanceof UIResource) {
271                         editor.setSelectionColor(null);
272                 }
273
274                 if (editor.getDisabledTextColor() instanceof UIResource) {
275                         editor.setDisabledTextColor(null);
276                 }
277
278                 if (editor.getSelectedTextColor() instanceof UIResource) {
279                         editor.setSelectedTextColor(null);
280                 }
281
282                 if (editor.getBorder() instanceof UIResource) {
283                         editor.setBorder(null);
284                 }
285
286                 if (editor.getMargin() instanceof UIResource) {
287                         editor.setMargin(null);
288                 }
289
290                 // if (editor.getCaret() instanceof UIResource) {
291                 // editor.setCaret(null);
292                 // }
293                 //
294                 // if (editor.getHighlighter() instanceof UIResource) {
295                 // editor.setHighlighter(null);
296                 // }
297                 //
298                 // if (editor.getTransferHandler() instanceof UIResource) {
299                 // editor.setTransferHandler(null);
300                 // }
301                 //
302                 // if (editor.getCursor() instanceof UIResource) {
303                 // editor.setCursor(null);
304                 // }
305         }
306
307         protected void installKeyboardActions() {
308                 // backward compatibility support... keymaps for the UI
309                 // are now installed in the more friendly input map.
310                 // editor.setKeymap(createKeymap());
311
312                 InputMap km = getInputMap();
313                 if (km != null) {
314                         SwingUtilities.replaceUIInputMap(editor, JComponent.WHEN_FOCUSED, km);
315                 }
316
317                 ActionMap map = getActionMap();
318                 if (map != null) {
319                         SwingUtilities.replaceUIActionMap(editor, map);
320                 }
321
322                 // updateFocusAcceleratorBinding(false);
323         }
324
325         /**
326          * Get the InputMap to use for the UI.
327          */
328         InputMap getInputMap() {
329                 InputMap map = new InputMapUIResource();
330
331                 // InputMap shared =
332                 // (InputMap)DefaultLookup.get(editor, this,
333                 // getPropertyPrefix() + ".focusInputMap");
334                 // if (shared != null) {
335                 // map.setParent(shared);
336                 // }
337                 return map;
338         }
339
340         // /**
341         // * Invoked when the focus accelerator changes, this will update the
342         // * key bindings as necessary.
343         // */
344         // void updateFocusAcceleratorBinding(boolean changed) {
345         // char accelerator = editor.getFocusAccelerator();
346         //
347         // if (changed || accelerator != '\0') {
348         // InputMap km = SwingUtilities.getUIInputMap
349         // (editor, JComponent.WHEN_IN_FOCUSED_WINDOW);
350         //
351         // if (km == null && accelerator != '\0') {
352         // km = new ComponentInputMapUIResource(editor);
353         // SwingUtilities.replaceUIInputMap(editor, JComponent.
354         // WHEN_IN_FOCUSED_WINDOW, km);
355         // ActionMap am = getActionMap();
356         // SwingUtilities.replaceUIActionMap(editor, am);
357         // }
358         // if (km != null) {
359         // km.clear();
360         // if (accelerator != '\0') {
361         // km.put(KeyStroke.getKeyStroke(accelerator,
362         // ActionEvent.ALT_MASK),
363         // "requestFocus");
364         // }
365         // }
366         // }
367         // }
368         //
369         //
370         // /**
371         // * Invoked when editable property is changed.
372         // *
373         // * removing 'TAB' and 'SHIFT-TAB' from traversalKeysSet in case
374         // * editor is editable
375         // * adding 'TAB' and 'SHIFT-TAB' to traversalKeysSet in case
376         // * editor is non editable
377         // */
378         //
379         // void updateFocusTraversalKeys() {
380         // /*
381         // * Fix for 4514331 Non-editable JTextArea and similar
382         // * should allow Tab to keyboard - accessibility
383         // */
384         // EditorKit editorKit = getEditorKit(editor);
385         // if ( editorKit != null
386         // && editorKit instanceof DefaultEditorKit) {
387         // Set storedForwardTraversalKeys = editor.
388         // getFocusTraversalKeys(KeyboardFocusManager.
389         // FORWARD_TRAVERSAL_KEYS);
390         // Set storedBackwardTraversalKeys = editor.
391         // getFocusTraversalKeys(KeyboardFocusManager.
392         // BACKWARD_TRAVERSAL_KEYS);
393         // Set forwardTraversalKeys =
394         // new HashSet(storedForwardTraversalKeys);
395         // Set backwardTraversalKeys =
396         // new HashSet(storedBackwardTraversalKeys);
397         // if (editor.isEditable()) {
398         // forwardTraversalKeys.
399         // remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
400         // backwardTraversalKeys.
401         // remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
402         // InputEvent.SHIFT_MASK));
403         // } else {
404         // forwardTraversalKeys.add(KeyStroke.
405         // getKeyStroke(KeyEvent.VK_TAB, 0));
406         // backwardTraversalKeys.
407         // add(KeyStroke.
408         // getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
409         // }
410         // LookAndFeel.installProperty(editor,
411         // "focusTraversalKeysForward",
412         // forwardTraversalKeys);
413         // LookAndFeel.installProperty(editor,
414         // "focusTraversalKeysBackward",
415         // backwardTraversalKeys);
416         // }
417         //
418         // }
419
420         // /**
421         // * As needed updates cursor for the target editor.
422         // */
423         // private void updateCursor() {
424         // if ((! editor.isCursorSet())
425         // || editor.getCursor() instanceof UIResource) {
426         // Cursor cursor = (editor.isEditable()) ? textCursor : null;
427         // editor.setCursor(cursor);
428         // }
429         // }
430         //
431         // /**
432         // * Returns the <code>TransferHandler</code> that will be installed if
433         // * their isn't one installed on the <code>JTextComponent</code>.
434         // */
435         // TransferHandler getTransferHandler() {
436         // return defaultTransferHandler;
437         // }
438         //
439         /**
440          * Fetch an action map to use.
441          */
442         ActionMap getActionMap() {
443                 String mapName = classID + ".actionMap";
444                 ActionMap map = (ActionMap) UIManager.get(mapName);
445                 if (map == null) {
446                         map = createActionMap();
447                         if (map != null) {
448                                 UIManager.getLookAndFeelDefaults().put(mapName, map); 
449                         }
450                 }
451                 return map;
452         }
453         // ActionMap componentMap = new ActionMapUIResource();
454         // componentMap.put("requestFocus", new FocusAction());
455         // /*
456         // * fix for bug 4515750
457         // * JTextField & non-editable JTextArea bind return key - default btn not
458         // accessible
459         // *
460         // * Wrap the return action so that it is only enabled when the
461         // * component is editable. This allows the default button to be
462         // * processed when the text component has focus and isn't editable.
463         // *
464         // */
465         // if (getEditorKit(editor) instanceof DefaultEditorKit) {
466         // if (map != null) {
467         // Object obj = map.get(DefaultEditorKit.insertBreakAction);
468         // if (obj != null
469         // && obj instanceof DefaultEditorKit.InsertBreakAction) {
470         // Action action = new TextActionWrapper((TextAction)obj);
471         // componentMap.put(action.getValue(Action.NAME),action);
472         // }
473         // }
474         // }
475         // if (map != null) {
476         // componentMap.setParent(map);
477         // }
478         // return componentMap;
479         // }
480         //
481         /**
482          * Create a default action map. This is basically the set of actions found
483          * exported by the component.
484          */
485         /**
486          * @return
487          */
488         ActionMap createActionMap() {
489                 ActionMap map = new ActionMapUIResource();
490                 Action[] actions = editor.getActions();//defaultKit.getActions(); // SwingJS was editor.getEditorKit().getActions()
491                 // System.out.println("building map for UI: " + getPropertyPrefix());
492                 int n = actions.length;
493                 for (int i = 0; i < n; i++) {
494                         Action a = actions[i];
495                         map.put(a.getValue(Action.NAME), a);
496                         // System.out.println("  " + a.getValue(Action.NAME));
497                 }
498                 // map.put(TransferHandler.getCutAction().getValue(Action.NAME),
499                 // TransferHandler.getCutAction());
500                 // map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
501                 // TransferHandler.getCopyAction());
502                 // map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
503                 // TransferHandler.getPasteAction());
504                 return map;
505         }
506
507         protected void uninstallKeyboardActions() {
508                 editor.setKeymap(null);
509                 SwingUtilities.replaceUIInputMap(editor, JComponent.WHEN_IN_FOCUSED_WINDOW,
510                                 null);
511                 SwingUtilities.replaceUIActionMap(editor, null);
512         }
513
514         // /**
515         // * Paints a background for the view. This will only be
516         // * called if isOpaque() on the associated component is
517         // * true. The default is to paint the background color
518         // * of the component.
519         // *
520         // * @param g the graphics context
521         // */
522         // protected void paintBackground(Graphics g) {
523         // g.setColor(editor.getBackground());
524         // g.fillRect(0, 0, editor.getWidth(), editor.getHeight());
525         // }
526         //
527         /**
528          * Fetches the text component associated with this UI implementation. This
529          * will be null until the ui has been installed.
530          * 
531          * @return the editor component
532          */
533         protected final JTextComponent getComponent() {
534                 return editor;
535         }
536
537         // /**
538         // * Flags model changes.
539         // * This is called whenever the model has changed.
540         // * It is implemented to rebuild the view hierarchy
541         // * to represent the default root element of the
542         // * associated model.
543         // */
544         // protected void modelChanged() {
545         // // create a view hierarchy
546         // ViewFactory f = rootView.getViewFactory();
547         // Document doc = editor.getDocument();
548         // Element elem = doc.getDefaultRootElement();
549         // setView(f.create(elem));
550         // }
551         //
552         // /**
553         // * Sets the current root of the view hierarchy and calls invalidate().
554         // * If there were any child components, they will be removed (i.e.
555         // * there are assumed to have come from components embedded in views).
556         // *
557         // * @param v the root view
558         // */
559         // protected final void setView(View v) {
560         // rootView.setView(v);
561         // painted = false;
562         // editor.revalidate();
563         // editor.repaint();
564         // }
565         //
566         // /**
567         // * Paints the interface safely with a guarantee that
568         // * the model won't change from the view of this thread.
569         // * This does the following things, rendering from
570         // * back to front.
571         // * <ol>
572         // * <li>
573         // * If the component is marked as opaque, the background
574         // * is painted in the current background color of the
575         // * component.
576         // * <li>
577         // * The highlights (if any) are painted.
578         // * <li>
579         // * The view hierarchy is painted.
580         // * <li>
581         // * The caret is painted.
582         // * </ol>
583         // *
584         // * @param g the graphics context
585         // */
586         // protected void paintSafely(Graphics g) {
587         // painted = true;
588         // Highlighter highlighter = editor.getHighlighter();
589         // Caret caret = editor.getCaret();
590         //
591         // // paint the background
592         // if (editor.isOpaque()) {
593         // paintBackground(g);
594         // }
595         //
596         // // paint the highlights
597         // if (highlighter != null) {
598         // highlighter.paint(g);
599         // }
600         //
601         // // paint the view hierarchy
602         // Rectangle alloc = getVisibleEditorRect();
603         // if (alloc != null) {
604         // rootView.paint(g, alloc);
605         // }
606         //
607         // // paint the caret
608         // if (caret != null) {
609         // caret.paint(g);
610         // }
611         //
612         // if (dropCaret != null) {
613         // dropCaret.paint(g);
614         // }
615         // }
616
617         // --- ComponentUI methods --------------------------------------------
618
619         TextListener updateHandler;
620
621         /**
622          * Installs the UI for a component. This does the following things.
623          * <ol>
624          * <li>
625          * Set the associated component to opaque (can be changed easily by a subclass
626          * or on JTextComponent directly), which is the most common case. This will
627          * cause the component's background color to be painted.
628          * <li>
629          * Install the default caret and highlighter into the associated component.
630          * <li>
631          * Attach to the editor and model. If there is no model, a default one is
632          * created.
633          * <li>
634          * create the view factory and the view hierarchy used to represent the model.
635          * </ol>
636          * 
637          * @param c
638          *          the editor component
639          * @see ComponentUI#installUI
640          */
641         protected void installJSUI() {
642                 editor = (JTextComponent) c;
643                 updateHandler = new TextListener(this, editor);
644
645                 // install defaults
646                 installDefaults();
647                 installDefaults2();
648
649                 // // This is a workaround as these should not override what synth has
650                 // // set them to
651                 // if (!(this instanceof sun.swing.plaf.synth.SynthUI)){
652                 // // common case is background painted... this can
653                 // // easily be changed by subclasses or from outside
654                 // // of the component.
655                 // LookAndFeel.installProperty(editor, "opaque", Boolean.TRUE);
656                 // LookAndFeel.installProperty(editor, "autoscrolls", Boolean.TRUE);
657                 // }
658                 //
659                 // attach to the model and editor
660                 // Document doc = editor.getDocument();
661                 // if (doc == null) {
662                 // // no model, create a default one. This will
663                 // // fire a notification to the updateHandler
664                 // // which takes care of the rest.
665                 // editor.setDocument(getEditorKit(editor).createDefaultDocument());
666                 // } else {
667                 // // doc.addDocumentListener(updateHandler);
668                 // // modelChanged();
669                 // }
670
671                 // install keymap
672                 installListeners(editor);
673                 installKeyboardActions();
674
675                 // LayoutManager oldLayout = editor.getLayout();
676                 // if ((oldLayout == null) || (oldLayout instanceof UIResource)) {
677                 // // by default, use default LayoutManger implementation that
678                 // // will position the components associated with a View object.
679                 // editor.setLayout(updateHandler);
680                 // }
681                 //
682                 // updateBackground(editor);
683         }
684
685         /**
686          * Deinstalls the UI for a component. This removes the listeners, uninstalls
687          * the highlighter, removes views, and nulls out the keymap.
688          * 
689          * @param c
690          *          the editor component
691          * @see ComponentUI#uninstallUI
692          */
693         public void uninstallJSUI() {
694                 // detach from the model
695                 // editor.removePropertyChangeListener(updateHandler);
696                 // editor.getDocument().removeDocumentListener(updateHandler);
697
698                 // view part
699                 // painted = false;
700                 uninstallDefaults();
701                 // rootView.setView(null);
702                 c.removeAll();
703                 LayoutManager lm = c.getLayout();
704                 if (lm instanceof UIResource) {
705                         c.setLayout(null);
706                 }
707
708                 // controller part
709                 uninstallKeyboardActions();
710                 uninstallListeners(editor);
711
712                 editor = null;
713                 updateHandler = null;
714         }
715
716         protected void installListeners(JTextComponent b) {
717                 TextListener listener = updateHandler;
718                 b.addMouseListener(listener);
719                 b.addMouseMotionListener(listener);
720                 b.addFocusListener(listener);
721                 b.addPropertyChangeListener(listener);
722                 // SwingJS there won't be a document yet; this is in constructor
723                 // b.getDocument().addDocumentListener(listener);
724         }
725
726         protected void uninstallListeners(JTextComponent b) {
727                 TextListener listener = updateHandler;
728                 b.removeMouseListener(listener);
729                 b.removeMouseMotionListener(listener);
730                 b.removeFocusListener(listener);
731                 b.removePropertyChangeListener(listener);
732                 b.getDocument().removeDocumentListener(listener);
733         }
734
735         // /**
736         // * Superclass paints background in an uncontrollable way
737         // * (i.e. one might want an image tiled into the background).
738         // * To prevent this from happening twice, this method is
739         // * reimplemented to simply paint.
740         // * <p>
741         // * <em>NOTE:</em> Superclass is also not thread-safe in
742         // * it's rendering of the background, although that's not
743         // * an issue with the default rendering.
744         // */
745         // public void update(Graphics g, JComponent c) {
746         // paint(g, c);
747         // }
748         //
749         // /**
750         // * Paints the interface. This is routed to the
751         // * paintSafely method under the guarantee that
752         // * the model won't change from the view of this thread
753         // * while it's rendering (if the associated model is
754         // * derived from AbstractDocument). This enables the
755         // * model to potentially be updated asynchronously.
756         // *
757         // * @param g the graphics context
758         // * @param c the editor component
759         // */
760         // public final void paint(Graphics g, JComponent c) {
761         // if ((rootView.getViewCount() > 0) && (rootView.getView(0) != null)) {
762         // Document doc = editor.getDocument();
763         // if (doc instanceof AbstractDocument) {
764         // ((AbstractDocument)doc).readLock();
765         // }
766         // try {
767         // paintSafely(g);
768         // } finally {
769         // if (doc instanceof AbstractDocument) {
770         // ((AbstractDocument)doc).readUnlock();
771         // }
772         // }
773         // }
774         // }
775
776         // /**
777         // * Gets the preferred size for the editor component. If the component
778         // * has been given a size prior to receiving this request, it will
779         // * set the size of the view hierarchy to reflect the size of the component
780         // * before requesting the preferred size of the view hierarchy. This
781         // * allows formatted views to format to the current component size before
782         // * answering the request. Other views don't care about currently formatted
783         // * size and give the same answer either way.
784         // *
785         // * @param c the editor component
786         // * @return the size
787         // */
788         // public Dimension getPreferredSize(JComponent c) {
789         // Dimension d = c.getSize();
790         // // Document doc = editor.getDocument();
791         // // Insets i = c.getInsets();
792         // //
793         // // if (doc instanceof AbstractDocument) {
794         // // ((AbstractDocument)doc).readLock();
795         // // }
796         // // try {
797         // // if ((d.width > (i.left + i.right)) && (d.height > (i.top + i.bottom))) {
798         // // rootView.setSize(d.width - i.left - i.right, d.height - i.top -
799         // i.bottom);
800         // // }
801         // // else if (d.width == 0 && d.height == 0) {
802         // // // Probably haven't been layed out yet, force some sort of
803         // // // initial sizing.
804         // // rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
805         // // }
806         // // d.width = (int) Math.min((long) rootView.getPreferredSpan(View.X_AXIS) +
807         // // (long) i.left + (long) i.right, Integer.MAX_VALUE);
808         // // d.height = (int) Math.min((long) rootView.getPreferredSpan(View.Y_AXIS)
809         // +
810         // // (long) i.top + (long) i.bottom, Integer.MAX_VALUE);
811         // // } finally {
812         // // if (doc instanceof AbstractDocument) {
813         // // ((AbstractDocument)doc).readUnlock();
814         // // }
815         // // }
816         // return d;
817         // }
818
819         /**
820          * Gets the minimum size for the editor component.
821          * 
822          * @param c
823          *          the editor component
824          * @return the size
825          */
826         public Dimension getMinimumSize(JComponent c) {
827                 Dimension d = getPreferredSize();// new Dimension();
828                 // Document doc = editor.getDocument();
829                 Insets i = c.getInsets();
830                 // if (doc instanceof AbstractDocument) {
831                 // ((AbstractDocument)doc).readLock();
832                 // }
833                 // try {
834
835                 d.width += i.left + i.right;
836                 d.height += i.top + i.bottom;
837
838                 // d.width = (int) rootView.getMinimumSpan(View.X_AXIS) + i.left + i.right;
839                 // d.height = (int) rootView.getMinimumSpan(View.Y_AXIS) + i.top + i.bottom;
840                 // } finally {
841                 // if (doc instanceof AbstractDocument) {
842                 // ((AbstractDocument)doc).readUnlock();
843                 // }
844                 // }
845                 return d;
846         }
847
848         /**
849          * Gets the maximum size for the editor component.
850          * 
851          * @param c
852          *          the editor component
853          * @return the size
854          */
855         public Dimension getMaximumSize(JComponent c) {
856                 // SwingJS TODO
857                 return getMinimumSize(c);
858
859                 // Document doc = editor.getDocument();
860                 // Insets i = c.getInsets();
861                 // Dimension d = new Dimension();
862                 // if (doc instanceof AbstractDocument) {
863                 // ((AbstractDocument)doc).readLock();
864                 // }
865                 // try {
866                 // d.width = (int) Math.min((long) rootView.getMaximumSpan(View.X_AXIS) +
867                 // (long) i.left + (long) i.right, Integer.MAX_VALUE);
868                 // d.height = (int) Math.min((long) rootView.getMaximumSpan(View.Y_AXIS) +
869                 // (long) i.top + (long) i.bottom, Integer.MAX_VALUE);
870                 // } finally {
871                 // if (doc instanceof AbstractDocument) {
872                 // ((AbstractDocument)doc).readUnlock();
873                 // }
874                 // }
875                 // return d;
876         }
877
878         // ---- TextUI methods -------------------------------------------
879
880         //
881         // /**
882         // * Gets the allocation to give the root View. Due
883         // * to an unfortunate set of historical events this
884         // * method is inappropriately named. The Rectangle
885         // * returned has nothing to do with visibility.
886         // * The component must have a non-zero positive size for
887         // * this translation to be computed.
888         // *
889         // * @return the bounding box for the root view
890         // */
891         // protected Rectangle getVisibleEditorRect() {
892         // Rectangle alloc = editor.getBounds();
893         // if ((alloc.width > 0) && (alloc.height > 0)) {
894         // alloc.x = alloc.y = 0;
895         // Insets insets = editor.getInsets();
896         // alloc.x += insets.left;
897         // alloc.y += insets.top;
898         // alloc.width -= insets.left + insets.right;
899         // alloc.height -= insets.top + insets.bottom;
900         // return alloc;
901         // }
902         // return null;
903         // }
904         //
905         // /**
906         // * Converts the given location in the model to a place in
907         // * the view coordinate system.
908         // * The component must have a non-zero positive size for
909         // * this translation to be computed.
910         // *
911         // * @param tc the text component for which this UI is installed
912         // * @param pos the local location in the model to translate >= 0
913         // * @return the coordinates as a rectangle, null if the model is not painted
914         // * @exception BadLocationException if the given position does not
915         // * represent a valid location in the associated document
916         // * @see TextUI#modelToView
917         // */
918         // public Rectangle modelToView(JTextComponent tc, int pos) throws
919         // BadLocationException {
920         // return modelToView(tc, pos, Position.Bias.Forward);
921         // }
922         //
923         // /**
924         // * Converts the given location in the model to a place in
925         // * the view coordinate system.
926         // * The component must have a non-zero positive size for
927         // * this translation to be computed.
928         // *
929         // * @param tc the text component for which this UI is installed
930         // * @param pos the local location in the model to translate >= 0
931         // * @return the coordinates as a rectangle, null if the model is not painted
932         // * @exception BadLocationException if the given position does not
933         // * represent a valid location in the associated document
934         // * @see TextUI#modelToView
935         // */
936         // public Rectangle modelToView(JTextComponent tc, int pos, Position.Bias
937         // bias) throws BadLocationException {
938         // Document doc = editor.getDocument();
939         // if (doc instanceof AbstractDocument) {
940         // ((AbstractDocument)doc).readLock();
941         // }
942         // try {
943         // Rectangle alloc = getVisibleEditorRect();
944         // if (alloc != null) {
945         // rootView.setSize(alloc.width, alloc.height);
946         // Shape s = rootView.modelToView(pos, alloc, bias);
947         // if (s != null) {
948         // return s.getBounds();
949         // }
950         // }
951         // } finally {
952         // if (doc instanceof AbstractDocument) {
953         // ((AbstractDocument)doc).readUnlock();
954         // }
955         // }
956         // return null;
957         // }
958         //
959         // /**
960         // * Converts the given place in the view coordinate system
961         // * to the nearest representative location in the model.
962         // * The component must have a non-zero positive size for
963         // * this translation to be computed.
964         // *
965         // * @param tc the text component for which this UI is installed
966         // * @param pt the location in the view to translate. This
967         // * should be in the same coordinate system as the mouse events.
968         // * @return the offset from the start of the document >= 0,
969         // * -1 if not painted
970         // * @see TextUI#viewToModel
971         // */
972         // public int viewToModel(JTextComponent tc, Point pt) {
973         // return viewToModel(tc, pt, discardBias);
974         // }
975         //
976         // /**
977         // * Converts the given place in the view coordinate system
978         // * to the nearest representative location in the model.
979         // * The component must have a non-zero positive size for
980         // * this translation to be computed.
981         // *
982         // * @param tc the text component for which this UI is installed
983         // * @param pt the location in the view to translate. This
984         // * should be in the same coordinate system as the mouse events.
985         // * @return the offset from the start of the document >= 0,
986         // * -1 if the component doesn't yet have a positive size.
987         // * @see TextUI#viewToModel
988         // */
989         // public int viewToModel(JTextComponent tc, Point pt,
990         // Position.Bias[] biasReturn) {
991         // int offs = -1;
992         // Document doc = editor.getDocument();
993         // if (doc instanceof AbstractDocument) {
994         // ((AbstractDocument)doc).readLock();
995         // }
996         // try {
997         // Rectangle alloc = getVisibleEditorRect();
998         // if (alloc != null) {
999         // rootView.setSize(alloc.width, alloc.height);
1000         // offs = rootView.viewToModel(pt.x, pt.y, alloc, biasReturn);
1001         // }
1002         // } finally {
1003         // if (doc instanceof AbstractDocument) {
1004         // ((AbstractDocument)doc).readUnlock();
1005         // }
1006         // }
1007         // return offs;
1008         // }
1009
1010         // /**
1011         // * {@inheritDoc}
1012         // */
1013         // public int getNextVisualPositionFrom(JTextComponent t, int pos,
1014         // Position.Bias b, int direction, Position.Bias[] biasRet)
1015         // throws BadLocationException{
1016         // Document doc = editor.getDocument();
1017         // if (doc instanceof AbstractDocument) {
1018         // ((AbstractDocument)doc).readLock();
1019         // }
1020         // try {
1021         // if (painted) {
1022         // Rectangle alloc = getVisibleEditorRect();
1023         // if (alloc != null) {
1024         // rootView.setSize(alloc.width, alloc.height);
1025         // }
1026         // return rootView.getNextVisualPositionFrom(pos, b, alloc, direction,
1027         // biasRet);
1028         // }
1029         // } finally {
1030         // if (doc instanceof AbstractDocument) {
1031         // ((AbstractDocument)doc).readUnlock();
1032         // }
1033         // }
1034         // return -1;
1035         // }
1036         //
1037         // /**
1038         // * Causes the portion of the view responsible for the
1039         // * given part of the model to be repainted. Does nothing if
1040         // * the view is not currently painted.
1041         // *
1042         // * @param tc the text component for which this UI is installed
1043         // * @param p0 the beginning of the range >= 0
1044         // * @param p1 the end of the range >= p0
1045         // * @see TextUI#damageRange
1046         // */
1047         // public void damageRange(JTextComponent tc, int p0, int p1) {
1048         // damageRange(tc, p0, p1, Position.Bias.Forward, Position.Bias.Backward);
1049         // }
1050         //
1051         // /**
1052         // * Causes the portion of the view responsible for the
1053         // * given part of the model to be repainted.
1054         // *
1055         // * @param p0 the beginning of the range >= 0
1056         // * @param p1 the end of the range >= p0
1057         // */
1058         // public void damageRange(JTextComponent t, int p0, int p1,
1059         // Position.Bias p0Bias, Position.Bias p1Bias) {
1060         // if (painted) {
1061         // Rectangle alloc = getVisibleEditorRect();
1062         // if (alloc != null) {
1063         // Document doc = t.getDocument();
1064         // if (doc instanceof AbstractDocument) {
1065         // ((AbstractDocument)doc).readLock();
1066         // }
1067         // try {
1068         // rootView.setSize(alloc.width, alloc.height);
1069         // Shape toDamage = rootView.modelToView(p0, p0Bias,
1070         // p1, p1Bias, alloc);
1071         // Rectangle rect = (toDamage instanceof Rectangle) ?
1072         // (Rectangle)toDamage : toDamage.getBounds();
1073         // editor.repaint(rect.x, rect.y, rect.width, rect.height);
1074         // } catch (BadLocationException e) {
1075         // } finally {
1076         // if (doc instanceof AbstractDocument) {
1077         // ((AbstractDocument)doc).readUnlock();
1078         // }
1079         // }
1080         // }
1081         // }
1082         // }
1083
1084         /**
1085          * Fetches the EditorKit for the UI.
1086          * 
1087          * @param tc
1088          *          the text component for which this UI is installed
1089          * @return the editor capabilities
1090          * @see TextUI#getEditorKit
1091          */
1092         public EditorKit getEditorKit(JTextComponent tc) {
1093                 return defaultKit;
1094         }
1095
1096         // /**
1097         // * Fetches a View with the allocation of the associated
1098         // * text component (i.e. the root of the hierarchy) that
1099         // * can be traversed to determine how the model is being
1100         // * represented spatially.
1101         // * <p>
1102         // * <font color=red><b>NOTE:</b>The View hierarchy can
1103         // * be traversed from the root view, and other things
1104         // * can be done as well. Things done in this way cannot
1105         // * be protected like simple method calls through the TextUI.
1106         // * Therefore, proper operation in the presence of concurrency
1107         // * must be arranged by any logic that calls this method!
1108         // * </font>
1109         // *
1110         // * @param tc the text component for which this UI is installed
1111         // * @return the view
1112         // * @see TextUI#getRootView
1113         // */
1114         // public View getRootView(JTextComponent tc) {
1115         // return rootView;
1116         // }
1117
1118         // /**
1119         // * Returns the string to be used as the tooltip at the passed in location.
1120         // * This forwards the method onto the root View.
1121         // *
1122         // * @see jsjavax.swing.text.JTextComponent#getToolTipText
1123         // * @see jsjavax.swing.text.View#getToolTipText
1124         // * @since 1.4
1125         // */
1126         // public String getToolTipText(JTextComponent t, Point pt) {
1127         // if (!painted) {
1128         // return null;
1129         // }
1130         // Document doc = editor.getDocument();
1131         // String tt = null;
1132         // Rectangle alloc = getVisibleEditorRect();
1133         //
1134         // if (alloc != null) {
1135         // if (doc instanceof AbstractDocument) {
1136         // ((AbstractDocument)doc).readLock();
1137         // }
1138         // try {
1139         // tt = rootView.getToolTipText(pt.x, pt.y, alloc);
1140         // } finally {
1141         // if (doc instanceof AbstractDocument) {
1142         // ((AbstractDocument)doc).readUnlock();
1143         // }
1144         // }
1145         // }
1146         // return tt;
1147         // }
1148         //
1149         // --- ViewFactory methods ------------------------------
1150         //
1151         // /**
1152         // * Creates a view for an element.
1153         // * If a subclass wishes to directly implement the factory
1154         // * producing the view(s), it should reimplement this
1155         // * method. By default it simply returns null indicating
1156         // * it is unable to represent the element.
1157         // *
1158         // * @param elem the element
1159         // * @return the view
1160         // */
1161         // public View create(Element elem) {
1162         // return null;
1163         // }
1164         //
1165         // /**
1166         // * Creates a view for an element.
1167         // * If a subclass wishes to directly implement the factory
1168         // * producing the view(s), it should reimplement this
1169         // * method. By default it simply returns null indicating
1170         // * it is unable to represent the part of the element.
1171         // *
1172         // * @param elem the element
1173         // * @param p0 the starting offset >= 0
1174         // * @param p1 the ending offset >= p0
1175         // * @return the view
1176         // */
1177         // public View create(Element elem, int p0, int p1) {
1178         // return null;
1179         // }
1180         //
1181         // public static class BasicCaret extends DefaultCaret implements UIResource
1182         // {}
1183         //
1184         // public static class BasicHighlighter extends DefaultHighlighter implements
1185         // UIResource {}
1186         //
1187         // static class BasicCursor extends Cursor implements UIResource {
1188         // BasicCursor(int type) {
1189         // super(type);
1190         // }
1191         //
1192         // BasicCursor(String name) {
1193         // super(name);
1194         // }
1195         // }
1196         //
1197         // private static BasicCursor textCursor = new
1198         // BasicCursor(Cursor.TEXT_CURSOR);
1199         // ----- member variables ---------------------------------------
1200
1201         private static final EditorKit defaultKit = new DefaultEditorKit();
1202         transient JTextComponent editor;
1203         protected boolean editable = true;
1204
1205         // transient boolean painted;
1206         // transient RootView rootView = new RootView();
1207         // transient UpdateHandler updateHandler = new UpdateHandler();
1208         // private static final TransferHandler defaultTransferHandler = new
1209         // TextTransferHandler();
1210         // private final DragListener dragListener = getDragListener();
1211         // private static final Position.Bias[] discardBias = new Position.Bias[1];
1212         // private DefaultCaret dropCaret;
1213
1214         // /**
1215         // * Root view that acts as a gateway between the component
1216         // * and the View hierarchy.
1217         // */
1218         // class RootView extends View {
1219         //
1220         // RootView() {
1221         // super(null);
1222         // }
1223         //
1224         // void setView(View v) {
1225         // View oldView = view;
1226         // view = null;
1227         // if (oldView != null) {
1228         // // get rid of back reference so that the old
1229         // // hierarchy can be garbage collected.
1230         // oldView.setParent(null);
1231         // }
1232         // if (v != null) {
1233         // v.setParent(this);
1234         // }
1235         // view = v;
1236         // }
1237         //
1238         // /**
1239         // * Fetches the attributes to use when rendering. At the root
1240         // * level there are no attributes. If an attribute is resolved
1241         // * up the view hierarchy this is the end of the line.
1242         // */
1243         // public AttributeSet getAttributes() {
1244         // return null;
1245         // }
1246         //
1247         // /**
1248         // * Determines the preferred span for this view along an axis.
1249         // *
1250         // * @param axis may be either X_AXIS or Y_AXIS
1251         // * @return the span the view would like to be rendered into.
1252         // * Typically the view is told to render into the span
1253         // * that is returned, although there is no guarantee.
1254         // * The parent may choose to resize or break the view.
1255         // */
1256         // public float getPreferredSpan(int axis) {
1257         // if (view != null) {
1258         // return view.getPreferredSpan(axis);
1259         // }
1260         // return 10;
1261         // }
1262         //
1263         // /**
1264         // * Determines the minimum span for this view along an axis.
1265         // *
1266         // * @param axis may be either X_AXIS or Y_AXIS
1267         // * @return the span the view would like to be rendered into.
1268         // * Typically the view is told to render into the span
1269         // * that is returned, although there is no guarantee.
1270         // * The parent may choose to resize or break the view.
1271         // */
1272         // public float getMinimumSpan(int axis) {
1273         // if (view != null) {
1274         // return view.getMinimumSpan(axis);
1275         // }
1276         // return 10;
1277         // }
1278         //
1279         // /**
1280         // * Determines the maximum span for this view along an axis.
1281         // *
1282         // * @param axis may be either X_AXIS or Y_AXIS
1283         // * @return the span the view would like to be rendered into.
1284         // * Typically the view is told to render into the span
1285         // * that is returned, although there is no guarantee.
1286         // * The parent may choose to resize or break the view.
1287         // */
1288         // public float getMaximumSpan(int axis) {
1289         // return Integer.MAX_VALUE;
1290         // }
1291         //
1292         // /**
1293         // * Specifies that a preference has changed.
1294         // * Child views can call this on the parent to indicate that
1295         // * the preference has changed. The root view routes this to
1296         // * invalidate on the hosting component.
1297         // * <p>
1298         // * This can be called on a different thread from the
1299         // * event dispatching thread and is basically unsafe to
1300         // * propagate into the component. To make this safe,
1301         // * the operation is transferred over to the event dispatching
1302         // * thread for completion. It is a design goal that all view
1303         // * methods be safe to call without concern for concurrency,
1304         // * and this behavior helps make that true.
1305         // *
1306         // * @param child the child view
1307         // * @param width true if the width preference has changed
1308         // * @param height true if the height preference has changed
1309         // */
1310         // public void preferenceChanged(View child, boolean width, boolean height) {
1311         // editor.revalidate();
1312         // }
1313         //
1314         // /**
1315         // * Determines the desired alignment for this view along an axis.
1316         // *
1317         // * @param axis may be either X_AXIS or Y_AXIS
1318         // * @return the desired alignment, where 0.0 indicates the origin
1319         // * and 1.0 the full span away from the origin
1320         // */
1321         // public float getAlignment(int axis) {
1322         // if (view != null) {
1323         // return view.getAlignment(axis);
1324         // }
1325         // return 0;
1326         // }
1327         //
1328         // /**
1329         // * Renders the view.
1330         // *
1331         // * @param g the graphics context
1332         // * @param allocation the region to render into
1333         // */
1334         // public void paint(Graphics g, Shape allocation) {
1335         // if (view != null) {
1336         // Rectangle alloc = (allocation instanceof Rectangle) ?
1337         // (Rectangle)allocation : allocation.getBounds();
1338         // setSize(alloc.width, alloc.height);
1339         // view.paint(g, allocation);
1340         // }
1341         // }
1342         //
1343         // /**
1344         // * Sets the view parent.
1345         // *
1346         // * @param parent the parent view
1347         // */
1348         // public void setParent(View parent) {
1349         // throw new Error("Can't set parent on root view");
1350         // }
1351         //
1352         // /**
1353         // * Returns the number of views in this view. Since
1354         // * this view simply wraps the root of the view hierarchy
1355         // * it has exactly one child.
1356         // *
1357         // * @return the number of views
1358         // * @see #getView
1359         // */
1360         // public int getViewCount() {
1361         // return 1;
1362         // }
1363         //
1364         // /**
1365         // * Gets the n-th view in this container.
1366         // *
1367         // * @param n the number of the view to get
1368         // * @return the view
1369         // */
1370         // public View getView(int n) {
1371         // return view;
1372         // }
1373         //
1374         // /**
1375         // * Returns the child view index representing the given position in
1376         // * the model. This is implemented to return the index of the only
1377         // * child.
1378         // *
1379         // * @param pos the position >= 0
1380         // * @return index of the view representing the given position, or
1381         // * -1 if no view represents that position
1382         // * @since 1.3
1383         // */
1384         // public int getViewIndex(int pos, Position.Bias b) {
1385         // return 0;
1386         // }
1387         //
1388         // /**
1389         // * Fetches the allocation for the given child view.
1390         // * This enables finding out where various views
1391         // * are located, without assuming the views store
1392         // * their location. This returns the given allocation
1393         // * since this view simply acts as a gateway between
1394         // * the view hierarchy and the associated component.
1395         // *
1396         // * @param index the index of the child
1397         // * @param a the allocation to this view.
1398         // * @return the allocation to the child
1399         // */
1400         // public Shape getChildAllocation(int index, Shape a) {
1401         // return a;
1402         // }
1403         //
1404         // /**
1405         // * Provides a mapping from the document model coordinate space
1406         // * to the coordinate space of the view mapped to it.
1407         // *
1408         // * @param pos the position to convert
1409         // * @param a the allocated region to render into
1410         // * @return the bounding box of the given position
1411         // */
1412         // public Shape modelToView(int pos, Shape a, Position.Bias b) throws
1413         // BadLocationException {
1414         // if (view != null) {
1415         // return view.modelToView(pos, a, b);
1416         // }
1417         // return null;
1418         // }
1419         //
1420         // /**
1421         // * Provides a mapping from the document model coordinate space
1422         // * to the coordinate space of the view mapped to it.
1423         // *
1424         // * @param p0 the position to convert >= 0
1425         // * @param b0 the bias toward the previous character or the
1426         // * next character represented by p0, in case the
1427         // * position is a boundary of two views.
1428         // * @param p1 the position to convert >= 0
1429         // * @param b1 the bias toward the previous character or the
1430         // * next character represented by p1, in case the
1431         // * position is a boundary of two views.
1432         // * @param a the allocated region to render into
1433         // * @return the bounding box of the given position is returned
1434         // * @exception BadLocationException if the given position does
1435         // * not represent a valid location in the associated document
1436         // * @exception IllegalArgumentException for an invalid bias argument
1437         // * @see View#viewToModel
1438         // */
1439         // public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias
1440         // b1, Shape a) throws BadLocationException {
1441         // if (view != null) {
1442         // return view.modelToView(p0, b0, p1, b1, a);
1443         // }
1444         // return null;
1445         // }
1446         //
1447         // /**
1448         // * Provides a mapping from the view coordinate space to the logical
1449         // * coordinate space of the model.
1450         // *
1451         // * @param x x coordinate of the view location to convert
1452         // * @param y y coordinate of the view location to convert
1453         // * @param a the allocated region to render into
1454         // * @return the location within the model that best represents the
1455         // * given point in the view
1456         // */
1457         // public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {
1458         // if (view != null) {
1459         // int retValue = view.viewToModel(x, y, a, bias);
1460         // return retValue;
1461         // }
1462         // return -1;
1463         // }
1464         //
1465         // /**
1466         // * Provides a way to determine the next visually represented model
1467         // * location that one might place a caret. Some views may not be visible,
1468         // * they might not be in the same order found in the model, or they just
1469         // * might not allow access to some of the locations in the model.
1470         // *
1471         // * @param pos the position to convert >= 0
1472         // * @param a the allocated region to render into
1473         // * @param direction the direction from the current position that can
1474         // * be thought of as the arrow keys typically found on a keyboard.
1475         // * This may be SwingConstants.WEST, SwingConstants.EAST,
1476         // * SwingConstants.NORTH, or SwingConstants.SOUTH.
1477         // * @return the location within the model that best represents the next
1478         // * location visual position.
1479         // * @exception BadLocationException
1480         // * @exception IllegalArgumentException for an invalid direction
1481         // */
1482         // public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
1483         // int direction,
1484         // Position.Bias[] biasRet)
1485         // throws BadLocationException {
1486         // if( view != null ) {
1487         // int nextPos = view.getNextVisualPositionFrom(pos, b, a,
1488         // direction, biasRet);
1489         // if(nextPos != -1) {
1490         // pos = nextPos;
1491         // }
1492         // else {
1493         // biasRet[0] = b;
1494         // }
1495         // }
1496         // return pos;
1497         // }
1498         //
1499         // /**
1500         // * Gives notification that something was inserted into the document
1501         // * in a location that this view is responsible for.
1502         // *
1503         // * @param e the change information from the associated document
1504         // * @param a the current allocation of the view
1505         // * @param f the factory to use to rebuild if the view has children
1506         // */
1507         // public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
1508         // if (view != null) {
1509         // view.insertUpdate(e, a, f);
1510         // }
1511         // }
1512         //
1513         // /**
1514         // * Gives notification that something was removed from the document
1515         // * in a location that this view is responsible for.
1516         // *
1517         // * @param e the change information from the associated document
1518         // * @param a the current allocation of the view
1519         // * @param f the factory to use to rebuild if the view has children
1520         // */
1521         // public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
1522         // if (view != null) {
1523         // view.removeUpdate(e, a, f);
1524         // }
1525         // }
1526         //
1527         // /**
1528         // * Gives notification from the document that attributes were changed
1529         // * in a location that this view is responsible for.
1530         // *
1531         // * @param e the change information from the associated document
1532         // * @param a the current allocation of the view
1533         // * @param f the factory to use to rebuild if the view has children
1534         // */
1535         // public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
1536         // if (view != null) {
1537         // view.changedUpdate(e, a, f);
1538         // }
1539         // }
1540         //
1541         // /**
1542         // * Returns the document model underlying the view.
1543         // *
1544         // * @return the model
1545         // */
1546         // public Document getDocument() {
1547         // return editor.getDocument();
1548         // }
1549         //
1550         // /**
1551         // * Returns the starting offset into the model for this view.
1552         // *
1553         // * @return the starting offset
1554         // */
1555         // public int getStartOffset() {
1556         // if (view != null) {
1557         // return view.getStartOffset();
1558         // }
1559         // return getElement().getStartOffset();
1560         // }
1561         //
1562         // /**
1563         // * Returns the ending offset into the model for this view.
1564         // *
1565         // * @return the ending offset
1566         // */
1567         // public int getEndOffset() {
1568         // if (view != null) {
1569         // return view.getEndOffset();
1570         // }
1571         // return getElement().getEndOffset();
1572         // }
1573         //
1574         // /**
1575         // * Gets the element that this view is mapped to.
1576         // *
1577         // * @return the view
1578         // */
1579         // public Element getElement() {
1580         // if (view != null) {
1581         // return view.getElement();
1582         // }
1583         // return editor.getDocument().getDefaultRootElement();
1584         // }
1585         //
1586         // /**
1587         // * Breaks this view on the given axis at the given length.
1588         // *
1589         // * @param axis may be either X_AXIS or Y_AXIS
1590         // * @param len specifies where a break is desired in the span
1591         // * @param the current allocation of the view
1592         // * @return the fragment of the view that represents the given span
1593         // * if the view can be broken, otherwise null
1594         // */
1595         // public View breakView(int axis, float len, Shape a) {
1596         // throw new Error("Can't break root view");
1597         // }
1598         //
1599         // /**
1600         // * Determines the resizability of the view along the
1601         // * given axis. A value of 0 or less is not resizable.
1602         // *
1603         // * @param axis may be either X_AXIS or Y_AXIS
1604         // * @return the weight
1605         // */
1606         // public int getResizeWeight(int axis) {
1607         // if (view != null) {
1608         // return view.getResizeWeight(axis);
1609         // }
1610         // return 0;
1611         // }
1612         //
1613         // /**
1614         // * Sets the view size.
1615         // *
1616         // * @param width the width
1617         // * @param height the height
1618         // */
1619         // public void setSize(float width, float height) {
1620         // if (view != null) {
1621         // view.setSize(width, height);
1622         // }
1623         // }
1624         //
1625         // /**
1626         // * Fetches the container hosting the view. This is useful for
1627         // * things like scheduling a repaint, finding out the host
1628         // * components font, etc. The default implementation
1629         // * of this is to forward the query to the parent view.
1630         // *
1631         // * @return the container
1632         // */
1633         // public Container getContainer() {
1634         // return editor;
1635         // }
1636         //
1637         // /**
1638         // * Fetches the factory to be used for building the
1639         // * various view fragments that make up the view that
1640         // * represents the model. This is what determines
1641         // * how the model will be represented. This is implemented
1642         // * to fetch the factory provided by the associated
1643         // * EditorKit unless that is null, in which case this
1644         // * simply returns the BasicTextUI itself which allows
1645         // * subclasses to implement a simple factory directly without
1646         // * creating extra objects.
1647         // *
1648         // * @return the factory
1649         // */
1650         // public ViewFactory getViewFactory() {
1651         // EditorKit kit = getEditorKit(editor);
1652         // ViewFactory f = kit.getViewFactory();
1653         // if (f != null) {
1654         // return f;
1655         // }
1656         // return BasicTextUI.this;
1657         // }
1658         //
1659         // private View view;
1660         //
1661         // }
1662
1663         // /**
1664         // * Handles updates from various places. If the model is changed,
1665         // * this class unregisters as a listener to the old model and
1666         // * registers with the new model. If the document model changes,
1667         // * the change is forwarded to the root view. If the focus
1668         // * accelerator changes, a new keystroke is registered to request
1669         // * focus.
1670         // */
1671         // class UpdateHandler implements PropertyChangeListener, DocumentListener,
1672         // LayoutManager2, UIResource {
1673         //
1674         // // --- PropertyChangeListener methods -----------------------
1675         //
1676         // /**
1677         // * This method gets called when a bound property is changed.
1678         // * We are looking for document changes on the editor.
1679         // */
1680         // public final void propertyChange(PropertyChangeEvent evt) {
1681         // Object oldValue = evt.getOldValue();
1682         // Object newValue = evt.getNewValue();
1683         // String propertyName = evt.getPropertyName();
1684         // if ((oldValue instanceof Document) || (newValue instanceof Document)) {
1685         // if (oldValue != null) {
1686         // ((Document)oldValue).removeDocumentListener(this);
1687         // i18nView = false;
1688         // }
1689         // if (newValue != null) {
1690         // ((Document)newValue).addDocumentListener(this);
1691         // if ("document" == propertyName) {
1692         // setView(null);
1693         // BasicTextUI.this.propertyChange(evt);
1694         // modelChanged();
1695         // return;
1696         // }
1697         // }
1698         // modelChanged();
1699         // }
1700         // if ("focusAccelerator" == propertyName) {
1701         // updateFocusAcceleratorBinding(true);
1702         // } else if ("componentOrientation" == propertyName) {
1703         // // Changes in ComponentOrientation require the views to be
1704         // // rebuilt.
1705         // modelChanged();
1706         // } else if ("font" == propertyName) {
1707         // modelChanged();
1708         // } else if ("dropLocation" == propertyName) {
1709         // dropIndexChanged();
1710         // } else if ("editable" == propertyName) {
1711         // updateCursor();
1712         // modelChanged();
1713         // }
1714         // BasicTextUI.this.propertyChange(evt);
1715         // }
1716         //
1717         // private void dropIndexChanged() {
1718         // if (editor.getDropMode() == DropMode.USE_SELECTION) {
1719         // return;
1720         // }
1721         //
1722         // JTextComponent.DropLocation dropLocation = editor.getDropLocation();
1723         //
1724         // if (dropLocation == null) {
1725         // if (dropCaret != null) {
1726         // dropCaret.deinstall(editor);
1727         // editor.repaint(dropCaret);
1728         // dropCaret = null;
1729         // }
1730         // } else {
1731         // if (dropCaret == null) {
1732         // dropCaret = new BasicCaret();
1733         // dropCaret.install(editor);
1734         // dropCaret.setVisible(true);
1735         // }
1736         //
1737         // dropCaret.setDot(dropLocation.getIndex(),
1738         // dropLocation.getBias());
1739         // }
1740         // }
1741         //
1742         // // --- DocumentListener methods -----------------------
1743         //
1744         // /**
1745         // * The insert notification. Gets sent to the root of the view structure
1746         // * that represents the portion of the model being represented by the
1747         // * editor. The factory is added as an argument to the update so that
1748         // * the views can update themselves in a dynamic (not hardcoded) way.
1749         // *
1750         // * @param e The change notification from the currently associated
1751         // * document.
1752         // * @see DocumentListener#insertUpdate
1753         // */
1754         // public final void insertUpdate(DocumentEvent e) {
1755         // Document doc = e.getDocument();
1756         // Object o = doc.getProperty("i18n");
1757         // if (o instanceof Boolean) {
1758         // Boolean i18nFlag = (Boolean) o;
1759         // if (i18nFlag.booleanValue() != i18nView) {
1760         // // i18n flag changed, rebuild the view
1761         // i18nView = i18nFlag.booleanValue();
1762         // modelChanged();
1763         // return;
1764         // }
1765         // }
1766         //
1767         // // normal insert update
1768         // Rectangle alloc = (painted) ? getVisibleEditorRect() : null;
1769         // rootView.insertUpdate(e, alloc, rootView.getViewFactory());
1770         // }
1771         //
1772         // /**
1773         // * The remove notification. Gets sent to the root of the view structure
1774         // * that represents the portion of the model being represented by the
1775         // * editor. The factory is added as an argument to the update so that
1776         // * the views can update themselves in a dynamic (not hardcoded) way.
1777         // *
1778         // * @param e The change notification from the currently associated
1779         // * document.
1780         // * @see DocumentListener#removeUpdate
1781         // */
1782         // public final void removeUpdate(DocumentEvent e) {
1783         // Rectangle alloc = (painted) ? getVisibleEditorRect() : null;
1784         // rootView.removeUpdate(e, alloc, rootView.getViewFactory());
1785         // }
1786         //
1787         // /**
1788         // * The change notification. Gets sent to the root of the view structure
1789         // * that represents the portion of the model being represented by the
1790         // * editor. The factory is added as an argument to the update so that
1791         // * the views can update themselves in a dynamic (not hardcoded) way.
1792         // *
1793         // * @param e The change notification from the currently associated
1794         // * document.
1795         // * @see DocumentListener#changeUpdate
1796         // */
1797         // public final void changedUpdate(DocumentEvent e) {
1798         // Rectangle alloc = (painted) ? getVisibleEditorRect() : null;
1799         // rootView.changedUpdate(e, alloc, rootView.getViewFactory());
1800         // }
1801         //
1802         // // --- LayoutManager2 methods --------------------------------
1803         //
1804         // /**
1805         // * Adds the specified component with the specified name to
1806         // * the layout.
1807         // * @param name the component name
1808         // * @param comp the component to be added
1809         // */
1810         // public void addLayoutComponent(String name, Component comp) {
1811         // // not supported
1812         // }
1813         //
1814         // /**
1815         // * Removes the specified component from the layout.
1816         // * @param comp the component to be removed
1817         // */
1818         // public void removeLayoutComponent(Component comp) {
1819         // if (constraints != null) {
1820         // // remove the constraint record
1821         // constraints.remove(comp);
1822         // }
1823         // }
1824         //
1825         // /**
1826         // * Calculates the preferred size dimensions for the specified
1827         // * panel given the components in the specified parent container.
1828         // * @param parent the component to be laid out
1829         // *
1830         // * @see #minimumLayoutSize
1831         // */
1832         // public Dimension preferredLayoutSize(Container parent) {
1833         // // should not be called (JComponent uses UI instead)
1834         // return null;
1835         // }
1836         //
1837         // /**
1838         // * Calculates the minimum size dimensions for the specified
1839         // * panel given the components in the specified parent container.
1840         // * @param parent the component to be laid out
1841         // * @see #preferredLayoutSize
1842         // */
1843         // public Dimension minimumLayoutSize(Container parent) {
1844         // // should not be called (JComponent uses UI instead)
1845         // return null;
1846         // }
1847         //
1848         // /**
1849         // * Lays out the container in the specified panel. This is
1850         // * implemented to position all components that were added
1851         // * with a View object as a constraint. The current allocation
1852         // * of the associated View is used as the location of the
1853         // * component.
1854         // * <p>
1855         // * A read-lock is acquired on the document to prevent the
1856         // * view tree from being modified while the layout process
1857         // * is active.
1858         // *
1859         // * @param parent the component which needs to be laid out
1860         // */
1861         // public void layoutContainer(Container parent) {
1862         // if ((constraints != null) && (! constraints.isEmpty())) {
1863         // Rectangle alloc = getVisibleEditorRect();
1864         // if (alloc != null) {
1865         // Document doc = editor.getDocument();
1866         // if (doc instanceof AbstractDocument) {
1867         // ((AbstractDocument)doc).readLock();
1868         // }
1869         // try {
1870         // rootView.setSize(alloc.width, alloc.height);
1871         // Enumeration components = constraints.keys();
1872         // while (components.hasMoreElements()) {
1873         // Component comp = (Component) components.nextElement();
1874         // View v = (View) constraints.get(comp);
1875         // Shape ca = calculateViewPosition(alloc, v);
1876         // if (ca != null) {
1877         // Rectangle compAlloc = (ca instanceof Rectangle) ?
1878         // (Rectangle) ca : ca.getBounds();
1879         // comp.setBounds(compAlloc);
1880         // }
1881         // }
1882         // } finally {
1883         // if (doc instanceof AbstractDocument) {
1884         // ((AbstractDocument)doc).readUnlock();
1885         // }
1886         // }
1887         // }
1888         // }
1889         // }
1890         //
1891         // /**
1892         // * Find the Shape representing the given view.
1893         // */
1894         // Shape calculateViewPosition(Shape alloc, View v) {
1895         // int pos = v.getStartOffset();
1896         // View child = null;
1897         // for (View parent = rootView; (parent != null) && (parent != v); parent =
1898         // child) {
1899         // int index = parent.getViewIndex(pos, Position.Bias.Forward);
1900         // alloc = parent.getChildAllocation(index, alloc);
1901         // child = parent.getView(index);
1902         // }
1903         // return (child != null) ? alloc : null;
1904         // }
1905         //
1906         // /**
1907         // * Adds the specified component to the layout, using the specified
1908         // * constraint object. We only store those components that were added
1909         // * with a constraint that is of type View.
1910         // *
1911         // * @param comp the component to be added
1912         // * @param constraint where/how the component is added to the layout.
1913         // */
1914         // public void addLayoutComponent(Component comp, Object constraint) {
1915         // if (constraint instanceof View) {
1916         // if (constraints == null) {
1917         // constraints = new Hashtable(7);
1918         // }
1919         // constraints.put(comp, constraint);
1920         // }
1921         // }
1922         //
1923         // /**
1924         // * Returns the maximum size of this component.
1925         // * @see jsjava.awt.Component#getMinimumSize()
1926         // * @see jsjava.awt.Component#getPreferredSize()
1927         // * @see LayoutManager
1928         // */
1929         // public Dimension maximumLayoutSize(Container target) {
1930         // // should not be called (JComponent uses UI instead)
1931         // return null;
1932         // }
1933         //
1934         // /**
1935         // * Returns the alignment along the x axis. This specifies how
1936         // * the component would like to be aligned relative to other
1937         // * components. The value should be a number between 0 and 1
1938         // * where 0 represents alignment along the origin, 1 is aligned
1939         // * the furthest away from the origin, 0.5 is centered, etc.
1940         // */
1941         // public float getLayoutAlignmentX(Container target) {
1942         // return 0.5f;
1943         // }
1944         //
1945         // /**
1946         // * Returns the alignment along the y axis. This specifies how
1947         // * the component would like to be aligned relative to other
1948         // * components. The value should be a number between 0 and 1
1949         // * where 0 represents alignment along the origin, 1 is aligned
1950         // * the furthest away from the origin, 0.5 is centered, etc.
1951         // */
1952         // public float getLayoutAlignmentY(Container target) {
1953         // return 0.5f;
1954         // }
1955         //
1956         // /**
1957         // * Invalidates the layout, indicating that if the layout manager
1958         // * has cached information it should be discarded.
1959         // */
1960         // public void invalidateLayout(Container target) {
1961         // }
1962         //
1963         // /**
1964         // * The "layout constraints" for the LayoutManager2 implementation.
1965         // * These are View objects for those components that are represented
1966         // * by a View in the View tree.
1967         // */
1968         // private Hashtable constraints;
1969         //
1970         // private boolean i18nView = false;
1971         // }
1972
1973         /**
1974          * Wrapper for text actions to return isEnabled false in case editor is non
1975          * editable
1976          */
1977         class TextActionWrapper extends TextAction {
1978                 public TextActionWrapper(TextAction action) {
1979                         super((String) action.getValue(Action.NAME));
1980                         this.action = action;
1981                 }
1982
1983                 /**
1984                  * The operation to perform when this action is triggered.
1985                  * 
1986                  * @param e
1987                  *          the action event
1988                  */
1989                 public void actionPerformed(ActionEvent e) {
1990                         action.actionPerformed(e);
1991                 }
1992
1993                 public boolean isEnabled() {
1994                         return (editor == null || editor.isEditable()) ? action.isEnabled()
1995                                         : false;
1996                 }
1997
1998                 TextAction action = null;
1999         }
2000
2001         /**
2002          * Registered in the ActionMap.
2003          */
2004         class FocusAction extends AbstractAction {
2005
2006                 public void actionPerformed(ActionEvent e) {
2007                         editor.requestFocus();
2008                 }
2009
2010                 public boolean isEnabled() {
2011                         return editor.isEditable();
2012                 }
2013         }
2014
2015         boolean handleEnter(int eventType) {
2016                 return false;
2017         }
2018
2019         String bgcolor0;
2020         
2021         public void setEditable(boolean editable) {
2022                 
2023                 this.editable = editable;
2024                 if (domNode == null)
2025                         return;
2026                 if (c.isBackgroundSet())
2027                         bgcolor0 = JSToolkit.getCSSColor(c.getBackground());
2028                 if (editable) {
2029                         domNode.removeAttribute("readOnly");
2030                         if (bgcolor0 != null)
2031                                 DOMNode.setStyles(domNode, "background-color", bgcolor0);
2032                 } else {
2033                         DOMNode.setAttr(domNode, "readOnly", "true");
2034                         if (c.isBackgroundSet()) {
2035                                 bgcolor0 = JSToolkit.getCSSColor(c.getBackground());
2036                         } else {
2037                                 if (bgcolor0 == null)
2038                                         bgcolor0 = domNode.getStyle("background-color");
2039                         }
2040                         DOMNode.setStyles(domNode, "background-color", "rgba(0,0,0,0)");
2041                 }
2042
2043         }
2044
2045         // private static DragListener getDragListener() {
2046         // synchronized(DragListener.class) {
2047         // DragListener listener =
2048         // (DragListener)AppContext.getAppContext().
2049         // get(DragListener.class);
2050         //
2051         // if (listener == null) {
2052         // listener = new DragListener();
2053         // AppContext.getAppContext().put(DragListener.class, listener);
2054         // }
2055         //
2056         // return listener;
2057         // }
2058         // }
2059         //
2060         // /**
2061         // * Listens for mouse events for the purposes of detecting drag gestures.
2062         // * BasicTextUI will maintain one of these per AppContext.
2063         // */
2064         // static class DragListener extends MouseInputAdapter
2065         // implements BeforeDrag {
2066         //
2067         // private boolean dragStarted;
2068         //
2069         // public void dragStarting(MouseEvent me) {
2070         // dragStarted = true;
2071         // }
2072         //
2073         // public void mousePressed(MouseEvent e) {
2074         // JTextComponent c = (JTextComponent)e.getSource();
2075         // if (c.getDragEnabled()) {
2076         // dragStarted = false;
2077         // if (isDragPossible(e) && DragRecognitionSupport.mousePressed(e)) {
2078         // e.consume();
2079         // }
2080         // }
2081         // }
2082         //
2083         // public void mouseReleased(MouseEvent e) {
2084         // JTextComponent c = (JTextComponent)e.getSource();
2085         // if (c.getDragEnabled()) {
2086         // if (dragStarted) {
2087         // e.consume();
2088         // }
2089         //
2090         // DragRecognitionSupport.mouseReleased(e);
2091         // }
2092         // }
2093         //
2094         // public void mouseDragged(MouseEvent e) {
2095         // JTextComponent c = (JTextComponent)e.getSource();
2096         // if (c.getDragEnabled()) {
2097         // if (dragStarted || DragRecognitionSupport.mouseDragged(e, this)) {
2098         // e.consume();
2099         // }
2100         // }
2101         // }
2102         //
2103         // /**
2104         // * Determines if the following are true:
2105         // * <ul>
2106         // * <li>the component is enabled
2107         // * <li>the press event is located over a selection
2108         // * </ul>
2109         // */
2110         // protected boolean isDragPossible(MouseEvent e) {
2111         // JTextComponent c = (JTextComponent)e.getSource();
2112         // if (c.isEnabled()) {
2113         // Caret caret = c.getCaret();
2114         // int dot = caret.getDot();
2115         // int mark = caret.getMark();
2116         // if (dot != mark) {
2117         // Point p = new Point(e.getX(), e.getY());
2118         // int pos = c.viewToModel(p);
2119         //
2120         // int p0 = Math.min(dot, mark);
2121         // int p1 = Math.max(dot, mark);
2122         // if ((pos >= p0) && (pos < p1)) {
2123         // return true;
2124         // }
2125         // }
2126         // }
2127         // return false;
2128         // }
2129         // }
2130
2131         // static class TextTransferHandler extends TransferHandler implements
2132         // UIResource {
2133         //
2134         // private JTextComponent exportComp;
2135         // private boolean shouldRemove;
2136         // private int p0;
2137         // private int p1;
2138         //
2139         // /**
2140         // * Whether or not this is a drop using
2141         // * <code>DropMode.INSERT</code>.
2142         // */
2143         // private boolean modeBetween = false;
2144         //
2145         // /**
2146         // * Whether or not this is a drop.
2147         // */
2148         // private boolean isDrop = false;
2149         //
2150         // /**
2151         // * The drop action.
2152         // */
2153         // private int dropAction = MOVE;
2154         //
2155         // /**
2156         // * The drop bias.
2157         // */
2158         // private Position.Bias dropBias;
2159         //
2160         // /**
2161         // * Try to find a flavor that can be used to import a Transferable.
2162         // * The set of usable flavors are tried in the following order:
2163         // * <ol>
2164         // * <li>First, an attempt is made to find a flavor matching the content type
2165         // * of the EditorKit for the component.
2166         // * <li>Second, an attempt to find a text/plain flavor is made.
2167         // * <li>Third, an attempt to find a flavor representing a String reference
2168         // * in the same VM is made.
2169         // * <li>Lastly, DataFlavor.stringFlavor is searched for.
2170         // * </ol>
2171         // */
2172         // protected DataFlavor getImportFlavor(DataFlavor[] flavors, JTextComponent
2173         // c) {
2174         // DataFlavor plainFlavor = null;
2175         // DataFlavor refFlavor = null;
2176         // DataFlavor stringFlavor = null;
2177         //
2178         // if (c instanceof JEditorPane) {
2179         // for (int i = 0; i < flavors.length; i++) {
2180         // String mime = flavors[i].getMimeType();
2181         // if (mime.startsWith(((JEditorPane)c).getEditorKit().getContentType())) {
2182         // return flavors[i];
2183         // } else if (plainFlavor == null && mime.startsWith("text/plain")) {
2184         // plainFlavor = flavors[i];
2185         // } else if (refFlavor == null &&
2186         // mime.startsWith("application/x-java-jvm-local-objectref")
2187         // && flavors[i].getRepresentationClass() == jsjava.lang.String.class) {
2188         // refFlavor = flavors[i];
2189         // } else if (stringFlavor == null &&
2190         // flavors[i].equals(DataFlavor.stringFlavor)) {
2191         // stringFlavor = flavors[i];
2192         // }
2193         // }
2194         // if (plainFlavor != null) {
2195         // return plainFlavor;
2196         // } else if (refFlavor != null) {
2197         // return refFlavor;
2198         // } else if (stringFlavor != null) {
2199         // return stringFlavor;
2200         // }
2201         // return null;
2202         // }
2203         //
2204         //
2205         // for (int i = 0; i < flavors.length; i++) {
2206         // String mime = flavors[i].getMimeType();
2207         // if (mime.startsWith("text/plain")) {
2208         // return flavors[i];
2209         // } else if (refFlavor == null &&
2210         // mime.startsWith("application/x-java-jvm-local-objectref")
2211         // && flavors[i].getRepresentationClass() == jsjava.lang.String.class) {
2212         // refFlavor = flavors[i];
2213         // } else if (stringFlavor == null &&
2214         // flavors[i].equals(DataFlavor.stringFlavor)) {
2215         // stringFlavor = flavors[i];
2216         // }
2217         // }
2218         // if (refFlavor != null) {
2219         // return refFlavor;
2220         // } else if (stringFlavor != null) {
2221         // return stringFlavor;
2222         // }
2223         // return null;
2224         // }
2225         //
2226         // /**
2227         // * Import the given stream data into the text component.
2228         // */
2229         // protected void handleReaderImport(Reader in, JTextComponent c, boolean
2230         // useRead)
2231         // throws BadLocationException, IOException {
2232         // if (useRead) {
2233         // int startPosition = c.getSelectionStart();
2234         // int endPosition = c.getSelectionEnd();
2235         // int length = endPosition - startPosition;
2236         // EditorKit kit = c.getUI().getEditorKit(c);
2237         // Document doc = c.getDocument();
2238         // if (length > 0) {
2239         // doc.remove(startPosition, length);
2240         // }
2241         // kit.read(in, doc, startPosition);
2242         // } else {
2243         // char[] buff = new char[1024];
2244         // int nch;
2245         // boolean lastWasCR = false;
2246         // int last;
2247         // StringBuffer sbuff = null;
2248         //
2249         // // Read in a block at a time, mapping \r\n to \n, as well as single
2250         // // \r to \n.
2251         // while ((nch = in.read(buff, 0, buff.length)) != -1) {
2252         // if (sbuff == null) {
2253         // sbuff = new StringBuffer(nch);
2254         // }
2255         // last = 0;
2256         // for(int counter = 0; counter < nch; counter++) {
2257         // switch(buff[counter]) {
2258         // case '\r':
2259         // if (lastWasCR) {
2260         // if (counter == 0) {
2261         // sbuff.append('\n');
2262         // } else {
2263         // buff[counter - 1] = '\n';
2264         // }
2265         // } else {
2266         // lastWasCR = true;
2267         // }
2268         // break;
2269         // case '\n':
2270         // if (lastWasCR) {
2271         // if (counter > (last + 1)) {
2272         // sbuff.append(buff, last, counter - last - 1);
2273         // }
2274         // // else nothing to do, can skip \r, next write will
2275         // // write \n
2276         // lastWasCR = false;
2277         // last = counter;
2278         // }
2279         // break;
2280         // default:
2281         // if (lastWasCR) {
2282         // if (counter == 0) {
2283         // sbuff.append('\n');
2284         // } else {
2285         // buff[counter - 1] = '\n';
2286         // }
2287         // lastWasCR = false;
2288         // }
2289         // break;
2290         // }
2291         // }
2292         // if (last < nch) {
2293         // if (lastWasCR) {
2294         // if (last < (nch - 1)) {
2295         // sbuff.append(buff, last, nch - last - 1);
2296         // }
2297         // } else {
2298         // sbuff.append(buff, last, nch - last);
2299         // }
2300         // }
2301         // }
2302         // if (lastWasCR) {
2303         // sbuff.append('\n');
2304         // }
2305         // c.replaceSelection(sbuff != null ? sbuff.toString() : "");
2306         // }
2307         // }
2308         //
2309         // // --- TransferHandler methods ------------------------------------
2310         //
2311         // /**
2312         // * This is the type of transfer actions supported by the source. Some models
2313         // are
2314         // * not mutable, so a transfer operation of COPY only should
2315         // * be advertised in that case.
2316         // *
2317         // * @param c The component holding the data to be transfered. This
2318         // * argument is provided to enable sharing of TransferHandlers by
2319         // * multiple components.
2320         // * @return This is implemented to return NONE if the component is a
2321         // JPasswordField
2322         // * since exporting data via user gestures is not allowed. If the text
2323         // component is
2324         // * editable, COPY_OR_MOVE is returned, otherwise just COPY is allowed.
2325         // */
2326         // public int getSourceActions(JComponent c) {
2327         // if (c instanceof JPasswordField &&
2328         // c.getClientProperty("JPasswordField.cutCopyAllowed") !=
2329         // Boolean.TRUE) {
2330         // return NONE;
2331         // }
2332         //
2333         // return ((JTextComponent)c).isEditable() ? COPY_OR_MOVE : COPY;
2334         // }
2335         //
2336         // /**
2337         // * Create a Transferable to use as the source for a data transfer.
2338         // *
2339         // * @param comp The component holding the data to be transfered. This
2340         // * argument is provided to enable sharing of TransferHandlers by
2341         // * multiple components.
2342         // * @return The representation of the data to be transfered.
2343         // *
2344         // */
2345         // protected Transferable createTransferable(JComponent comp) {
2346         // exportComp = (JTextComponent)comp;
2347         // shouldRemove = true;
2348         // p0 = exportComp.getSelectionStart();
2349         // p1 = exportComp.getSelectionEnd();
2350         // return (p0 != p1) ? (new TextTransferable(exportComp, p0, p1)) : null;
2351         // }
2352         //
2353         // /**
2354         // * This method is called after data has been exported. This method should
2355         // remove
2356         // * the data that was transfered if the action was MOVE.
2357         // *
2358         // * @param source The component that was the source of the data.
2359         // * @param data The data that was transferred or possibly null
2360         // * if the action is <code>NONE</code>.
2361         // * @param action The actual action that was performed.
2362         // */
2363         // protected void exportDone(JComponent source, Transferable data, int action)
2364         // {
2365         // // only remove the text if shouldRemove has not been set to
2366         // // false by importData and only if the action is a move
2367         // if (shouldRemove && action == MOVE) {
2368         // TextTransferable t = (TextTransferable)data;
2369         // t.removeText();
2370         // }
2371         //
2372         // exportComp = null;
2373         // }
2374         //
2375         // public boolean importData(TransferSupport support) {
2376         // isDrop = support.isDrop();
2377         //
2378         // if (isDrop) {
2379         // modeBetween =
2380         // ((JTextComponent)support.getComponent()).getDropMode() == DropMode.INSERT;
2381         //
2382         // dropBias =
2383         // ((JTextComponent.DropLocation)support.getDropLocation()).getBias();
2384         //
2385         // dropAction = support.getDropAction();
2386         // }
2387         //
2388         // try {
2389         // return super.importData(support);
2390         // } finally {
2391         // isDrop = false;
2392         // modeBetween = false;
2393         // dropBias = null;
2394         // dropAction = MOVE;
2395         // }
2396         // }
2397         //
2398         // /**
2399         // * This method causes a transfer to a component from a clipboard or a
2400         // * DND drop operation. The Transferable represents the data to be
2401         // * imported into the component.
2402         // *
2403         // * @param comp The component to receive the transfer. This
2404         // * argument is provided to enable sharing of TransferHandlers by
2405         // * multiple components.
2406         // * @param t The data to import
2407         // * @return true if the data was inserted into the component, false
2408         // otherwise.
2409         // */
2410         // public boolean importData(JComponent comp, Transferable t) {
2411         // JTextComponent c = (JTextComponent)comp;
2412         //
2413         // int pos = modeBetween
2414         // ? ((JTextComponent.DropLocation)c.getDropLocation()).getIndex()
2415         // : c.getCaretPosition();
2416         //
2417         // // if we are importing to the same component that we exported from
2418         // // then don't actually do anything if the drop location is inside
2419         // // the drag location and set shouldRemove to false so that exportDone
2420         // // knows not to remove any data
2421         // if (dropAction == MOVE && c == exportComp && pos >= p0 && pos <= p1) {
2422         // shouldRemove = false;
2423         // return true;
2424         // }
2425         //
2426         // boolean imported = false;
2427         // DataFlavor importFlavor = getImportFlavor(t.getTransferDataFlavors(), c);
2428         // if (importFlavor != null) {
2429         // try {
2430         // boolean useRead = false;
2431         // if (comp instanceof JEditorPane) {
2432         // JEditorPane ep = (JEditorPane)comp;
2433         // if (!ep.getContentType().startsWith("text/plain") &&
2434         // importFlavor.getMimeType().startsWith(ep.getContentType())) {
2435         // useRead = true;
2436         // }
2437         // }
2438         // InputContext ic = c.getInputContext();
2439         // if (ic != null) {
2440         // ic.endComposition();
2441         // }
2442         // Reader r = importFlavor.getReaderForText(t);
2443         //
2444         // if (modeBetween) {
2445         // Caret caret = c.getCaret();
2446         // if (caret instanceof DefaultCaret) {
2447         // ((DefaultCaret)caret).setDot(pos, dropBias);
2448         // } else {
2449         // c.setCaretPosition(pos);
2450         // }
2451         // }
2452         //
2453         // handleReaderImport(r, c, useRead);
2454         //
2455         // if (isDrop) {
2456         // c.requestFocus();
2457         // Caret caret = c.getCaret();
2458         // if (caret instanceof DefaultCaret) {
2459         // int newPos = caret.getDot();
2460         // Position.Bias newBias = ((DefaultCaret)caret).getDotBias();
2461         //
2462         // ((DefaultCaret)caret).setDot(pos, dropBias);
2463         // ((DefaultCaret)caret).moveDot(newPos, newBias);
2464         // } else {
2465         // c.select(pos, c.getCaretPosition());
2466         // }
2467         // }
2468         //
2469         // imported = true;
2470         // } catch (UnsupportedFlavorException ufe) {
2471         // } catch (BadLocationException ble) {
2472         // } catch (IOException ioe) {
2473         // }
2474         // }
2475         // return imported;
2476         // }
2477         //
2478         // /**
2479         // * This method indicates if a component would accept an import of the given
2480         // * set of data flavors prior to actually attempting to import it.
2481         // *
2482         // * @param comp The component to receive the transfer. This
2483         // * argument is provided to enable sharing of TransferHandlers by
2484         // * multiple components.
2485         // * @param flavors The data formats available
2486         // * @return true if the data can be inserted into the component, false
2487         // otherwise.
2488         // */
2489         // public boolean canImport(JComponent comp, DataFlavor[] flavors) {
2490         // JTextComponent c = (JTextComponent)comp;
2491         // if (!(c.isEditable() && c.isEnabled())) {
2492         // return false;
2493         // }
2494         // return (getImportFlavor(flavors, c) != null);
2495         // }
2496         //
2497         // /**
2498         // * A possible implementation of the Transferable interface
2499         // * for text components. For a JEditorPane with a rich set
2500         // * of EditorKit implementations, conversions could be made
2501         // * giving a wider set of formats. This is implemented to
2502         // * offer up only the active content type and text/plain
2503         // * (if that is not the active format) since that can be
2504         // * extracted from other formats.
2505         // */
2506         // static class TextTransferable extends BasicTransferable {
2507         //
2508         // TextTransferable(JTextComponent c, int start, int end) {
2509         // super(null, null);
2510         //
2511         // this.c = c;
2512         //
2513         // Document doc = c.getDocument();
2514         //
2515         // try {
2516         // p0 = doc.createPosition(start);
2517         // p1 = doc.createPosition(end);
2518         //
2519         // plainData = c.getSelectedText();
2520         //
2521         // if (c instanceof JEditorPane) {
2522         // JEditorPane ep = (JEditorPane)c;
2523         //
2524         // mimeType = ep.getContentType();
2525         //
2526         // if (mimeType.startsWith("text/plain")) {
2527         // return;
2528         // }
2529         //
2530         // StringWriter sw = new StringWriter(p1.getOffset() - p0.getOffset());
2531         // ep.getEditorKit().write(sw, doc, p0.getOffset(), p1.getOffset() -
2532         // p0.getOffset());
2533         //
2534         // if (mimeType.startsWith("text/html")) {
2535         // htmlData = sw.toString();
2536         // } else {
2537         // richText = sw.toString();
2538         // }
2539         // }
2540         // } catch (BadLocationException ble) {
2541         // } catch (IOException ioe) {
2542         // }
2543         // }
2544         //
2545         // void removeText() {
2546         // if ((p0 != null) && (p1 != null) && (p0.getOffset() != p1.getOffset())) {
2547         // try {
2548         // Document doc = c.getDocument();
2549         // doc.remove(p0.getOffset(), p1.getOffset() - p0.getOffset());
2550         // } catch (BadLocationException e) {
2551         // }
2552         // }
2553         // }
2554         //
2555         // // ---- EditorKit other than plain or HTML text -----------------------
2556         //
2557         // /**
2558         // * If the EditorKit is not for text/plain or text/html, that format
2559         // * is supported through the "richer flavors" part of BasicTransferable.
2560         // */
2561         // protected DataFlavor[] getRicherFlavors() {
2562         // if (richText == null) {
2563         // return null;
2564         // }
2565         //
2566         // try {
2567         // DataFlavor[] flavors = new DataFlavor[3];
2568         // flavors[0] = new DataFlavor(mimeType + ";class=java.lang.String");
2569         // flavors[1] = new DataFlavor(mimeType + ";class=java.io.Reader");
2570         // flavors[2] = new DataFlavor(mimeType +
2571         // ";class=java.io.InputStream;charset=unicode");
2572         // return flavors;
2573         // } catch (ClassNotFoundException cle) {
2574         // // fall through to unsupported (should not happen)
2575         // }
2576         //
2577         // return null;
2578         // }
2579         //
2580         // /**
2581         // * The only richer format supported is the file list flavor
2582         // */
2583         // protected Object getRicherData(DataFlavor flavor) throws
2584         // UnsupportedFlavorException {
2585         // if (richText == null) {
2586         // return null;
2587         // }
2588         //
2589         // if (String.class.equals(flavor.getRepresentationClass())) {
2590         // return richText;
2591         // } else if (Reader.class.equals(flavor.getRepresentationClass())) {
2592         // return new StringReader(richText);
2593         // } else if (InputStream.class.equals(flavor.getRepresentationClass())) {
2594         // return new StringBufferInputStream(richText);
2595         // }
2596         // throw new UnsupportedFlavorException(flavor);
2597         // }
2598         //
2599         // Position p0;
2600         // Position p1;
2601         // String mimeType;
2602         // String richText;
2603         // JTextComponent c;
2604         // }
2605         //
2606         // }
2607
2608         // /**
2609         // * Creates a new UI.
2610         // */
2611         // public JSTextUI() {
2612         // // painted = false;
2613         // }
2614         //
2615         // /**
2616         // * Creates the object to use for a caret. By default an
2617         // * instance of BasicCaret is created. This method
2618         // * can be redefined to provide something else that implements
2619         // * the InputPosition interface or a subclass of JCaret.
2620         // *
2621         // * @return the caret object
2622         // */
2623         // protected Caret createCaret() {
2624         // return new BasicCaret();
2625         // }
2626         //
2627         // /**
2628         // * Creates the object to use for adding highlights. By default
2629         // * an instance of BasicHighlighter is created. This method
2630         // * can be redefined to provide something else that implements
2631         // * the Highlighter interface or a subclass of DefaultHighlighter.
2632         // *
2633         // * @return the highlighter
2634         // */
2635         // protected Highlighter createHighlighter() {
2636         // return new BasicHighlighter();
2637         // }
2638         //
2639         // /**
2640         // * Fetches the name of the keymap that will be installed/used
2641         // * by default for this UI. This is implemented to create a
2642         // * name based upon the classname. The name is the the name
2643         // * of the class with the package prefix removed.
2644         // *
2645         // * @return the name
2646         // */
2647         // protected String getKeymapName() {
2648         // String nm = getClass().getName();
2649         // int index = nm.lastIndexOf('.');
2650         // if (index >= 0) {
2651         // nm = nm.substring(index+1, nm.length());
2652         // }
2653         // return nm;
2654         // }
2655         //
2656         // /**
2657         // * Creates the keymap to use for the text component, and installs
2658         // * any necessary bindings into it. By default, the keymap is
2659         // * shared between all instances of this type of TextUI. The
2660         // * keymap has the name defined by the getKeymapName method. If the
2661         // * keymap is not found, then DEFAULT_KEYMAP from JTextComponent is used.
2662         // * <p>
2663         // * The set of bindings used to create the keymap is fetched
2664         // * from the UIManager using a key formed by combining the
2665         // * {@link #getPropertyPrefix} method
2666         // * and the string <code>.keyBindings</code>. The type is expected
2667         // * to be <code>JTextComponent.KeyBinding[]</code>.
2668         // *
2669         // * @return the keymap
2670         // * @see #getKeymapName
2671         // * @see jsjavax.swing.text.JTextComponent
2672         // */
2673         // protected Keymap createKeymap() {
2674         // String nm = getKeymapName();
2675         // Keymap map = JTextComponent.getKeymap(nm);
2676         // if (map == null) {
2677         // Keymap parent = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
2678         // map = JTextComponent.addKeymap(nm, parent);
2679         // String prefix = getPropertyPrefix();
2680         // Object o = DefaultLookup.get(editor, this,
2681         // prefix + ".keyBindings");
2682         // if ((o != null) && (o instanceof JTextComponent.KeyBinding[])) {
2683         // JTextComponent.KeyBinding[] bindings = (JTextComponent.KeyBinding[]) o;
2684         // JTextComponent.loadKeymap(map, bindings, getComponent().getActions());
2685         // }
2686         // }
2687         // return map;
2688         // }
2689         //
2690         // /**
2691         // * This method gets called when a bound property is changed
2692         // * on the associated JTextComponent. This is a hook
2693         // * which UI implementations may change to reflect how the
2694         // * UI displays bound properties of JTextComponent subclasses.
2695         // * This is implemented to do nothing (i.e. the response to
2696         // * properties in JTextComponent itself are handled prior
2697         // * to calling this method).
2698         // *
2699         // * This implementation updates the background of the text
2700         // * component if the editable and/or enabled state changes.
2701         // *
2702         // * @param evt the property change event
2703         // */
2704         // protected void propertyChange(PropertyChangeEvent evt) {
2705         // if (evt.getPropertyName().equals("editable") ||
2706         // evt.getPropertyName().equals("enabled")) {
2707         //
2708         // updateBackground((JTextComponent)evt.getSource());
2709         // }
2710         // }
2711         //
2712         // /**
2713         // * Updates the background of the text component based on whether the
2714         // * text component is editable and/or enabled.
2715         // *
2716         // * @param c the JTextComponent that needs its background color updated
2717         // */
2718         // private void updateBackground(JTextComponent c) {
2719         // // This is a temporary workaround.
2720         // // This code does not correctly deal with Synth (Synth doesn't use
2721         // // properties like this), nor does it deal with the situation where
2722         // // the developer grabs the color from a JLabel and sets it as
2723         // // the background for a JTextArea in all look and feels. The problem
2724         // // scenario results if the Color obtained for the Label and TextArea
2725         // // is ==, which is the case for the windows look and feel.
2726         // // Until an appropriate solution is found, the code is being
2727         // // reverted to what it was before the original fix.
2728         // if (this instanceof sun.swing.plaf.synth.SynthUI ||
2729         // (c instanceof JTextArea)) {
2730         // return;
2731         // }
2732         // Color background = c.getBackground();
2733         // if (background instanceof UIResource) {
2734         // String prefix = getPropertyPrefix();
2735         //
2736         // Color disabledBG =
2737         // DefaultLookup.getColor(c, this, prefix + ".disabledBackground", null);
2738         // Color inactiveBG =
2739         // DefaultLookup.getColor(c, this, prefix + ".inactiveBackground", null);
2740         // Color bg =
2741         // DefaultLookup.getColor(c, this, prefix + ".background", null);
2742         //
2743         // /* In an ideal situation, the following check would not be necessary
2744         // * and we would replace the color any time the previous color was a
2745         // * UIResouce. However, it turns out that there is existing code that
2746         // * uses the following inadvisable pattern to turn a text area into
2747         // * what appears to be a multi-line label:
2748         // *
2749         // * JLabel label = new JLabel();
2750         // * JTextArea area = new JTextArea();
2751         // * area.setBackground(label.getBackground());
2752         // * area.setEditable(false);
2753         // *
2754         // * JLabel's default background is a UIResource. As such, just
2755         // * checking for UIResource would have us always changing the
2756         // * background away from what the developer wanted.
2757         // *
2758         // * Therefore, for JTextArea/JEditorPane, we'll additionally check
2759         // * that the color we're about to replace matches one that was
2760         // * installed by us from the UIDefaults.
2761         // */
2762         // if ((c instanceof JTextArea || c instanceof JEditorPane)
2763         // && background != disabledBG
2764         // && background != inactiveBG
2765         // && background != bg) {
2766         //
2767         // return;
2768         // }
2769         //
2770         // Color newColor = null;
2771         // if (!c.isEnabled()) {
2772         // newColor = disabledBG;
2773         // }
2774         // if (newColor == null && !c.isEditable()) {
2775         // newColor = inactiveBG;
2776         // }
2777         // if (newColor == null) {
2778         // newColor = bg;
2779         // }
2780         // if (newColor != null && newColor != background) {
2781         // c.setBackground(newColor);
2782         // }
2783         // }
2784         // }
2785         //
2786         // /**
2787         // * Gets the name used as a key to look up properties through the
2788         // * UIManager. This is used as a prefix to all the standard
2789         // * text properties.
2790         // *
2791         // * @return the name
2792         // */
2793         // protected abstract String getPropertyPrefix();
2794
2795 }