2 * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
\r
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
\r
5 * This code is free software; you can redistribute it and/or modify it
\r
6 * under the terms of the GNU General Public License version 2 only, as
\r
7 * published by the Free Software Foundation. Oracle designates this
\r
8 * particular file as subject to the "Classpath" exception as provided
\r
9 * by Oracle in the LICENSE file that accompanied this code.
\r
11 * This code is distributed in the hope that it will be useful, but WITHOUT
\r
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
\r
14 * version 2 for more details (a copy is included in the LICENSE file that
\r
15 * accompanied this code).
\r
17 * You should have received a copy of the GNU General Public License version
\r
18 * 2 along with this work; if not, write to the Free Software Foundation,
\r
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
\r
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
\r
22 * or visit www.oracle.com if you need additional information or have any
\r
25 package swingjs.plaf;
\r
27 import swingjs.JSToolkit;
\r
28 import swingjs.api.DOMNode;
\r
29 import swingjs.api.JQueryObject;
\r
30 import swingjs.api.JSFunction;
\r
31 import jsjava.awt.Dimension;
\r
32 import jsjava.awt.Insets;
\r
33 import jsjava.awt.LayoutManager;
\r
34 import jsjava.awt.event.ActionEvent;
\r
35 import jsjavax.swing.AbstractAction;
\r
36 import jsjavax.swing.Action;
\r
37 import jsjavax.swing.ActionMap;
\r
38 import jsjavax.swing.InputMap;
\r
39 import jsjavax.swing.JComponent;
\r
40 import jsjavax.swing.SwingUtilities;
\r
41 import jsjavax.swing.UIManager;
\r
42 import jsjavax.swing.plaf.ActionMapUIResource;
\r
43 import jsjavax.swing.plaf.ComponentUI;
\r
44 import jsjavax.swing.plaf.InputMapUIResource;
\r
45 import jsjavax.swing.plaf.TextUI;
\r
46 import jsjavax.swing.plaf.UIResource;
\r
47 import jsjavax.swing.text.Caret;
\r
48 import jsjavax.swing.text.DefaultEditorKit;
\r
49 import jsjavax.swing.text.EditorKit;
\r
50 import jsjavax.swing.text.JTextComponent;
\r
51 import jsjavax.swing.text.TextAction;
\r
52 //import jsjava.awt.KeyboardFocusManager;
\r
53 //import jsjava.awt.datatransfer.DataFlavor;
\r
54 //import jsjava.awt.datatransfer.Transferable;
\r
55 //import jsjava.awt.datatransfer.UnsupportedFlavorException;
\r
56 //import jsjava.awt.im.InputContext;
\r
57 //import jsjava.io.IOException;
\r
58 //import jsjava.io.InputStream;
\r
59 //import jsjava.io.Reader;
\r
60 //import jsjava.io.StringBufferInputStream;
\r
61 //import jsjava.io.StringReader;
\r
62 //import jsjava.io.StringWriter;
\r
63 //import jsjavax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag;
\r
67 * Basis of a text components look-and-feel. This provides the basic editor view
\r
68 * and controller services that may be useful when creating a look-and-feel for
\r
69 * an extension of <code>JTextComponent</code>.
\r
71 * Most state is held in the associated <code>JTextComponent</code> as bound
\r
72 * properties, and the UI installs default values for the various properties.
\r
73 * This default will install something for all of the properties. Typically, a
\r
74 * LAF implementation will do more however. At a minimum, a LAF would generally
\r
75 * install key bindings.
\r
77 * This class also provides some concurrency support if the
\r
78 * <code>Document</code> associated with the JTextComponent is a subclass of
\r
79 * <code>AbstractDocument</code>. Access to the View (or View hierarchy) is
\r
80 * serialized between any thread mutating the model and the Swing event thread
\r
81 * (which is expected to render, do model/view coordinate translation, etc).
\r
82 * <em>Any access to the root view should first
\r
83 * acquire a read-lock on the AbstractDocument and release that lock
\r
84 * in a finally block.</em>
\r
86 * An important method to define is the {@link #getPropertyPrefix} method which
\r
87 * is used as the basis of the keys used to fetch defaults from the UIManager.
\r
88 * The string should reflect the type of TextUI (eg. TextField, TextArea, etc)
\r
89 * without the particular LAF part of the name (eg Metal, Motif, etc).
\r
91 * To build a view of the model, one of the following strategies can be
\r
95 * One strategy is to simply redefine the ViewFactory interface in the UI. By
\r
96 * default, this UI itself acts as the factory for View implementations. This is
\r
97 * useful for simple factories. To do this reimplement the {@link #create}
\r
100 * A common strategy for creating more complex types of documents is to have the
\r
101 * EditorKit implementation return a factory. Since the EditorKit ties all of
\r
102 * the pieces necessary to maintain a type of document, the factory is typically
\r
103 * an important part of that and should be produced by the EditorKit
\r
107 * <strong>Warning:</strong> Serialized objects of this class will not be
\r
108 * compatible with future Swing releases. The current serialization support is
\r
109 * appropriate for short term storage or RMI between applications running the
\r
110 * same version of Swing. As of 1.4, support for long term storage of all
\r
111 * JavaBeans<sup><font size="-2">TM</font></sup> has been added to the
\r
112 * <code>java.beans</code> package. Please see {@link jsjava.beans.XMLEncoder}.
\r
114 * @author Timothy Prinzing
\r
115 * @author Shannon Hickey (drag and drop)
\r
117 public abstract class JSTextUI extends JSComponentUI {// implements {ViewFactory
\r
119 @SuppressWarnings("unused")
\r
120 protected void setFocusable() {
\r
121 JQueryObject node = $(focusNode);
\r
127 * node.focus(function() {me.notifyFocus(true)});
\r
128 * node.blur(function() {me.notifyFocus(false)});
\r
134 protected String getComponentText() {
\r
135 return currentText = ((JTextComponent) c).getText();
\r
138 protected void bindKeys(DOMNode domNode) {
\r
139 JSFunction f = null;
\r
140 JSEventHandler me = this;
\r
141 if (!((JTextComponent) c).isEditable())
\r
146 * f = function(event) { me.handleJSEvent(me.domNode, 401, event)
\r
150 System.out.println(me);
\r
152 $(domNode).bind("keydown keypress keyup", f);
\r
154 // TODO Auto-generated method stub
\r
159 * Initializes component properties, e.g. font, foreground, background, caret
\r
160 * color, selection color, selected text color, disabled text color, and
\r
161 * border color. The font, foreground, and background properties are only set
\r
162 * if their current value is either null or a UIResource, other properties are
\r
163 * set if the current value is null.
\r
165 * @see #uninstallDefaults
\r
168 protected void installDefaults() {
\r
169 // String prefix = getPropertyPrefix();
\r
170 // Font f = editor.getFont();
\r
171 // if ((f == null) || (f instanceof UIResource)) {
\r
172 // editor.setFont(UIManager.getFont(prefix + ".font"));
\r
175 // Color bg = editor.getBackground();
\r
176 // if ((bg == null) || (bg instanceof UIResource)) {
\r
177 // editor.setBackground(UIManager.getColor(prefix + ".background"));
\r
180 // Color fg = editor.getForeground();
\r
181 // if ((fg == null) || (fg instanceof UIResource)) {
\r
182 // editor.setForeground(UIManager.getColor(prefix + ".foreground"));
\r
185 // Color color = editor.getCaretColor();
\r
186 // if ((color == null) || (color instanceof UIResource)) {
\r
187 // editor.setCaretColor(UIManager.getColor(prefix + ".caretForeground"));
\r
190 // Color s = editor.getSelectionColor();
\r
191 // if ((s == null) || (s instanceof UIResource)) {
\r
192 // editor.setSelectionColor(UIManager.getColor(prefix +
\r
193 // ".selectionBackground"));
\r
196 // Color sfg = editor.getSelectedTextColor();
\r
197 // if ((sfg == null) || (sfg instanceof UIResource)) {
\r
198 // editor.setSelectedTextColor(UIManager.getColor(prefix +
\r
199 // ".selectionForeground"));
\r
202 // Color dfg = editor.getDisabledTextColor();
\r
203 // if ((dfg == null) || (dfg instanceof UIResource)) {
\r
204 // editor.setDisabledTextColor(UIManager.getColor(prefix +
\r
205 // ".inactiveForeground"));
\r
208 // Border b = editor.getBorder();
\r
209 // if ((b == null) || (b instanceof UIResource)) {
\r
210 // editor.setBorder(UIManager.getBorder(prefix + ".border"));
\r
213 // Insets margin = editor.getMargin();
\r
214 // if (margin == null || margin instanceof UIResource) {
\r
215 // editor.setMargin(UIManager.getInsets(prefix + ".margin"));
\r
221 private void installDefaults2() {
\r
222 // editor.addMouseListener(dragListener);
\r
223 // editor.addMouseMotionListener(dragListener);
\r
225 // String prefix = getPropertyPrefix();
\r
227 Caret caret = editor.getCaret();
\r
228 if (caret == null || caret instanceof UIResource) {
\r
229 editor.setCaret(new JSCaret());
\r
232 // Highlighter highlighter = editor.getHighlighter();
\r
233 // if (highlighter == null || highlighter instanceof UIResource) {
\r
234 // editor.setHighlighter(createHighlighter());
\r
237 // TransferHandler th = editor.getTransferHandler();
\r
238 // if (th == null || th instanceof UIResource) {
\r
239 // editor.setTransferHandler(getTransferHandler());
\r
244 * called by JmolCore.js
\r
248 public boolean handleJSEvent(Object target, int eventType, Object jQueryEvent) {
\r
249 System.out.println("Handling for " + id + " " + eventType + " "
\r
251 return updateHandler.handleJSEvent(this, eventType, jQueryEvent);
\r
255 * Sets the component properties that haven't been explicitly overridden to
\r
256 * null. A property is considered overridden if its current value is not a
\r
259 * @see #installDefaults
\r
260 * @see #uninstallUI
\r
262 protected void uninstallDefaults() {
\r
263 // editor.removeMouseListener(dragListener);
\r
264 // editor.removeMouseMotionListener(dragListener);
\r
266 if (editor.getCaretColor() instanceof UIResource) {
\r
267 editor.setCaretColor(null);
\r
270 if (editor.getSelectionColor() instanceof UIResource) {
\r
271 editor.setSelectionColor(null);
\r
274 if (editor.getDisabledTextColor() instanceof UIResource) {
\r
275 editor.setDisabledTextColor(null);
\r
278 if (editor.getSelectedTextColor() instanceof UIResource) {
\r
279 editor.setSelectedTextColor(null);
\r
282 if (editor.getBorder() instanceof UIResource) {
\r
283 editor.setBorder(null);
\r
286 if (editor.getMargin() instanceof UIResource) {
\r
287 editor.setMargin(null);
\r
290 // if (editor.getCaret() instanceof UIResource) {
\r
291 // editor.setCaret(null);
\r
294 // if (editor.getHighlighter() instanceof UIResource) {
\r
295 // editor.setHighlighter(null);
\r
298 // if (editor.getTransferHandler() instanceof UIResource) {
\r
299 // editor.setTransferHandler(null);
\r
302 // if (editor.getCursor() instanceof UIResource) {
\r
303 // editor.setCursor(null);
\r
307 protected void installKeyboardActions() {
\r
308 // backward compatibility support... keymaps for the UI
\r
309 // are now installed in the more friendly input map.
\r
310 // editor.setKeymap(createKeymap());
\r
312 InputMap km = getInputMap();
\r
314 SwingUtilities.replaceUIInputMap(editor, JComponent.WHEN_FOCUSED, km);
\r
317 ActionMap map = getActionMap();
\r
319 SwingUtilities.replaceUIActionMap(editor, map);
\r
322 // updateFocusAcceleratorBinding(false);
\r
326 * Get the InputMap to use for the UI.
\r
328 InputMap getInputMap() {
\r
329 InputMap map = new InputMapUIResource();
\r
331 // InputMap shared =
\r
332 // (InputMap)DefaultLookup.get(editor, this,
\r
333 // getPropertyPrefix() + ".focusInputMap");
\r
334 // if (shared != null) {
\r
335 // map.setParent(shared);
\r
341 // * Invoked when the focus accelerator changes, this will update the
\r
342 // * key bindings as necessary.
\r
344 // void updateFocusAcceleratorBinding(boolean changed) {
\r
345 // char accelerator = editor.getFocusAccelerator();
\r
347 // if (changed || accelerator != '\0') {
\r
348 // InputMap km = SwingUtilities.getUIInputMap
\r
349 // (editor, JComponent.WHEN_IN_FOCUSED_WINDOW);
\r
351 // if (km == null && accelerator != '\0') {
\r
352 // km = new ComponentInputMapUIResource(editor);
\r
353 // SwingUtilities.replaceUIInputMap(editor, JComponent.
\r
354 // WHEN_IN_FOCUSED_WINDOW, km);
\r
355 // ActionMap am = getActionMap();
\r
356 // SwingUtilities.replaceUIActionMap(editor, am);
\r
358 // if (km != null) {
\r
360 // if (accelerator != '\0') {
\r
361 // km.put(KeyStroke.getKeyStroke(accelerator,
\r
362 // ActionEvent.ALT_MASK),
\r
363 // "requestFocus");
\r
371 // * Invoked when editable property is changed.
\r
373 // * removing 'TAB' and 'SHIFT-TAB' from traversalKeysSet in case
\r
374 // * editor is editable
\r
375 // * adding 'TAB' and 'SHIFT-TAB' to traversalKeysSet in case
\r
376 // * editor is non editable
\r
379 // void updateFocusTraversalKeys() {
\r
381 // * Fix for 4514331 Non-editable JTextArea and similar
\r
382 // * should allow Tab to keyboard - accessibility
\r
384 // EditorKit editorKit = getEditorKit(editor);
\r
385 // if ( editorKit != null
\r
386 // && editorKit instanceof DefaultEditorKit) {
\r
387 // Set storedForwardTraversalKeys = editor.
\r
388 // getFocusTraversalKeys(KeyboardFocusManager.
\r
389 // FORWARD_TRAVERSAL_KEYS);
\r
390 // Set storedBackwardTraversalKeys = editor.
\r
391 // getFocusTraversalKeys(KeyboardFocusManager.
\r
392 // BACKWARD_TRAVERSAL_KEYS);
\r
393 // Set forwardTraversalKeys =
\r
394 // new HashSet(storedForwardTraversalKeys);
\r
395 // Set backwardTraversalKeys =
\r
396 // new HashSet(storedBackwardTraversalKeys);
\r
397 // if (editor.isEditable()) {
\r
398 // forwardTraversalKeys.
\r
399 // remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
\r
400 // backwardTraversalKeys.
\r
401 // remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
\r
402 // InputEvent.SHIFT_MASK));
\r
404 // forwardTraversalKeys.add(KeyStroke.
\r
405 // getKeyStroke(KeyEvent.VK_TAB, 0));
\r
406 // backwardTraversalKeys.
\r
408 // getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
\r
410 // LookAndFeel.installProperty(editor,
\r
411 // "focusTraversalKeysForward",
\r
412 // forwardTraversalKeys);
\r
413 // LookAndFeel.installProperty(editor,
\r
414 // "focusTraversalKeysBackward",
\r
415 // backwardTraversalKeys);
\r
421 // * As needed updates cursor for the target editor.
\r
423 // private void updateCursor() {
\r
424 // if ((! editor.isCursorSet())
\r
425 // || editor.getCursor() instanceof UIResource) {
\r
426 // Cursor cursor = (editor.isEditable()) ? textCursor : null;
\r
427 // editor.setCursor(cursor);
\r
432 // * Returns the <code>TransferHandler</code> that will be installed if
\r
433 // * their isn't one installed on the <code>JTextComponent</code>.
\r
435 // TransferHandler getTransferHandler() {
\r
436 // return defaultTransferHandler;
\r
440 * Fetch an action map to use.
\r
442 ActionMap getActionMap() {
\r
443 String mapName = classID + ".actionMap";
\r
444 ActionMap map = (ActionMap) UIManager.get(mapName);
\r
446 map = createActionMap();
\r
448 UIManager.getLookAndFeelDefaults().put(mapName, map);
\r
453 // ActionMap componentMap = new ActionMapUIResource();
\r
454 // componentMap.put("requestFocus", new FocusAction());
\r
456 // * fix for bug 4515750
\r
457 // * JTextField & non-editable JTextArea bind return key - default btn not
\r
460 // * Wrap the return action so that it is only enabled when the
\r
461 // * component is editable. This allows the default button to be
\r
462 // * processed when the text component has focus and isn't editable.
\r
465 // if (getEditorKit(editor) instanceof DefaultEditorKit) {
\r
466 // if (map != null) {
\r
467 // Object obj = map.get(DefaultEditorKit.insertBreakAction);
\r
469 // && obj instanceof DefaultEditorKit.InsertBreakAction) {
\r
470 // Action action = new TextActionWrapper((TextAction)obj);
\r
471 // componentMap.put(action.getValue(Action.NAME),action);
\r
475 // if (map != null) {
\r
476 // componentMap.setParent(map);
\r
478 // return componentMap;
\r
482 * Create a default action map. This is basically the set of actions found
\r
483 * exported by the component.
\r
488 ActionMap createActionMap() {
\r
489 ActionMap map = new ActionMapUIResource();
\r
490 Action[] actions = editor.getActions();//defaultKit.getActions(); // SwingJS was editor.getEditorKit().getActions()
\r
491 // System.out.println("building map for UI: " + getPropertyPrefix());
\r
492 int n = actions.length;
\r
493 for (int i = 0; i < n; i++) {
\r
494 Action a = actions[i];
\r
495 map.put(a.getValue(Action.NAME), a);
\r
496 // System.out.println(" " + a.getValue(Action.NAME));
\r
498 // map.put(TransferHandler.getCutAction().getValue(Action.NAME),
\r
499 // TransferHandler.getCutAction());
\r
500 // map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
\r
501 // TransferHandler.getCopyAction());
\r
502 // map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
\r
503 // TransferHandler.getPasteAction());
\r
507 protected void uninstallKeyboardActions() {
\r
508 editor.setKeymap(null);
\r
509 SwingUtilities.replaceUIInputMap(editor, JComponent.WHEN_IN_FOCUSED_WINDOW,
\r
511 SwingUtilities.replaceUIActionMap(editor, null);
\r
515 // * Paints a background for the view. This will only be
\r
516 // * called if isOpaque() on the associated component is
\r
517 // * true. The default is to paint the background color
\r
518 // * of the component.
\r
520 // * @param g the graphics context
\r
522 // protected void paintBackground(Graphics g) {
\r
523 // g.setColor(editor.getBackground());
\r
524 // g.fillRect(0, 0, editor.getWidth(), editor.getHeight());
\r
528 * Fetches the text component associated with this UI implementation. This
\r
529 * will be null until the ui has been installed.
\r
531 * @return the editor component
\r
533 protected final JTextComponent getComponent() {
\r
538 // * Flags model changes.
\r
539 // * This is called whenever the model has changed.
\r
540 // * It is implemented to rebuild the view hierarchy
\r
541 // * to represent the default root element of the
\r
542 // * associated model.
\r
544 // protected void modelChanged() {
\r
545 // // create a view hierarchy
\r
546 // ViewFactory f = rootView.getViewFactory();
\r
547 // Document doc = editor.getDocument();
\r
548 // Element elem = doc.getDefaultRootElement();
\r
549 // setView(f.create(elem));
\r
553 // * Sets the current root of the view hierarchy and calls invalidate().
\r
554 // * If there were any child components, they will be removed (i.e.
\r
555 // * there are assumed to have come from components embedded in views).
\r
557 // * @param v the root view
\r
559 // protected final void setView(View v) {
\r
560 // rootView.setView(v);
\r
561 // painted = false;
\r
562 // editor.revalidate();
\r
563 // editor.repaint();
\r
567 // * Paints the interface safely with a guarantee that
\r
568 // * the model won't change from the view of this thread.
\r
569 // * This does the following things, rendering from
\r
570 // * back to front.
\r
573 // * If the component is marked as opaque, the background
\r
574 // * is painted in the current background color of the
\r
577 // * The highlights (if any) are painted.
\r
579 // * The view hierarchy is painted.
\r
581 // * The caret is painted.
\r
584 // * @param g the graphics context
\r
586 // protected void paintSafely(Graphics g) {
\r
588 // Highlighter highlighter = editor.getHighlighter();
\r
589 // Caret caret = editor.getCaret();
\r
591 // // paint the background
\r
592 // if (editor.isOpaque()) {
\r
593 // paintBackground(g);
\r
596 // // paint the highlights
\r
597 // if (highlighter != null) {
\r
598 // highlighter.paint(g);
\r
601 // // paint the view hierarchy
\r
602 // Rectangle alloc = getVisibleEditorRect();
\r
603 // if (alloc != null) {
\r
604 // rootView.paint(g, alloc);
\r
607 // // paint the caret
\r
608 // if (caret != null) {
\r
612 // if (dropCaret != null) {
\r
613 // dropCaret.paint(g);
\r
617 // --- ComponentUI methods --------------------------------------------
\r
619 TextListener updateHandler;
\r
622 * Installs the UI for a component. This does the following things.
\r
625 * Set the associated component to opaque (can be changed easily by a subclass
\r
626 * or on JTextComponent directly), which is the most common case. This will
\r
627 * cause the component's background color to be painted.
\r
629 * Install the default caret and highlighter into the associated component.
\r
631 * Attach to the editor and model. If there is no model, a default one is
\r
634 * create the view factory and the view hierarchy used to represent the model.
\r
638 * the editor component
\r
639 * @see ComponentUI#installUI
\r
641 protected void installJSUI() {
\r
642 editor = (JTextComponent) c;
\r
643 updateHandler = new TextListener(this, editor);
\r
645 // install defaults
\r
647 installDefaults2();
\r
649 // // This is a workaround as these should not override what synth has
\r
651 // if (!(this instanceof sun.swing.plaf.synth.SynthUI)){
\r
652 // // common case is background painted... this can
\r
653 // // easily be changed by subclasses or from outside
\r
654 // // of the component.
\r
655 // LookAndFeel.installProperty(editor, "opaque", Boolean.TRUE);
\r
656 // LookAndFeel.installProperty(editor, "autoscrolls", Boolean.TRUE);
\r
659 // attach to the model and editor
\r
660 // Document doc = editor.getDocument();
\r
661 // if (doc == null) {
\r
662 // // no model, create a default one. This will
\r
663 // // fire a notification to the updateHandler
\r
664 // // which takes care of the rest.
\r
665 // editor.setDocument(getEditorKit(editor).createDefaultDocument());
\r
667 // // doc.addDocumentListener(updateHandler);
\r
668 // // modelChanged();
\r
672 installListeners(editor);
\r
673 installKeyboardActions();
\r
675 // LayoutManager oldLayout = editor.getLayout();
\r
676 // if ((oldLayout == null) || (oldLayout instanceof UIResource)) {
\r
677 // // by default, use default LayoutManger implementation that
\r
678 // // will position the components associated with a View object.
\r
679 // editor.setLayout(updateHandler);
\r
682 // updateBackground(editor);
\r
686 * Deinstalls the UI for a component. This removes the listeners, uninstalls
\r
687 * the highlighter, removes views, and nulls out the keymap.
\r
690 * the editor component
\r
691 * @see ComponentUI#uninstallUI
\r
693 public void uninstallJSUI() {
\r
694 // detach from the model
\r
695 // editor.removePropertyChangeListener(updateHandler);
\r
696 // editor.getDocument().removeDocumentListener(updateHandler);
\r
699 // painted = false;
\r
700 uninstallDefaults();
\r
701 // rootView.setView(null);
\r
703 LayoutManager lm = c.getLayout();
\r
704 if (lm instanceof UIResource) {
\r
709 uninstallKeyboardActions();
\r
710 uninstallListeners(editor);
\r
713 updateHandler = null;
\r
716 protected void installListeners(JTextComponent b) {
\r
717 TextListener listener = updateHandler;
\r
718 b.addMouseListener(listener);
\r
719 b.addMouseMotionListener(listener);
\r
720 b.addFocusListener(listener);
\r
721 b.addPropertyChangeListener(listener);
\r
722 // SwingJS there won't be a document yet; this is in constructor
\r
723 // b.getDocument().addDocumentListener(listener);
\r
726 protected void uninstallListeners(JTextComponent b) {
\r
727 TextListener listener = updateHandler;
\r
728 b.removeMouseListener(listener);
\r
729 b.removeMouseMotionListener(listener);
\r
730 b.removeFocusListener(listener);
\r
731 b.removePropertyChangeListener(listener);
\r
732 b.getDocument().removeDocumentListener(listener);
\r
736 // * Superclass paints background in an uncontrollable way
\r
737 // * (i.e. one might want an image tiled into the background).
\r
738 // * To prevent this from happening twice, this method is
\r
739 // * reimplemented to simply paint.
\r
741 // * <em>NOTE:</em> Superclass is also not thread-safe in
\r
742 // * it's rendering of the background, although that's not
\r
743 // * an issue with the default rendering.
\r
745 // public void update(Graphics g, JComponent c) {
\r
750 // * Paints the interface. This is routed to the
\r
751 // * paintSafely method under the guarantee that
\r
752 // * the model won't change from the view of this thread
\r
753 // * while it's rendering (if the associated model is
\r
754 // * derived from AbstractDocument). This enables the
\r
755 // * model to potentially be updated asynchronously.
\r
757 // * @param g the graphics context
\r
758 // * @param c the editor component
\r
760 // public final void paint(Graphics g, JComponent c) {
\r
761 // if ((rootView.getViewCount() > 0) && (rootView.getView(0) != null)) {
\r
762 // Document doc = editor.getDocument();
\r
763 // if (doc instanceof AbstractDocument) {
\r
764 // ((AbstractDocument)doc).readLock();
\r
769 // if (doc instanceof AbstractDocument) {
\r
770 // ((AbstractDocument)doc).readUnlock();
\r
777 // * Gets the preferred size for the editor component. If the component
\r
778 // * has been given a size prior to receiving this request, it will
\r
779 // * set the size of the view hierarchy to reflect the size of the component
\r
780 // * before requesting the preferred size of the view hierarchy. This
\r
781 // * allows formatted views to format to the current component size before
\r
782 // * answering the request. Other views don't care about currently formatted
\r
783 // * size and give the same answer either way.
\r
785 // * @param c the editor component
\r
786 // * @return the size
\r
788 // public Dimension getPreferredSize(JComponent c) {
\r
789 // Dimension d = c.getSize();
\r
790 // // Document doc = editor.getDocument();
\r
791 // // Insets i = c.getInsets();
\r
793 // // if (doc instanceof AbstractDocument) {
\r
794 // // ((AbstractDocument)doc).readLock();
\r
797 // // if ((d.width > (i.left + i.right)) && (d.height > (i.top + i.bottom))) {
\r
798 // // rootView.setSize(d.width - i.left - i.right, d.height - i.top -
\r
801 // // else if (d.width == 0 && d.height == 0) {
\r
802 // // // Probably haven't been layed out yet, force some sort of
\r
803 // // // initial sizing.
\r
804 // // rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
\r
806 // // d.width = (int) Math.min((long) rootView.getPreferredSpan(View.X_AXIS) +
\r
807 // // (long) i.left + (long) i.right, Integer.MAX_VALUE);
\r
808 // // d.height = (int) Math.min((long) rootView.getPreferredSpan(View.Y_AXIS)
\r
810 // // (long) i.top + (long) i.bottom, Integer.MAX_VALUE);
\r
812 // // if (doc instanceof AbstractDocument) {
\r
813 // // ((AbstractDocument)doc).readUnlock();
\r
820 * Gets the minimum size for the editor component.
\r
823 * the editor component
\r
826 public Dimension getMinimumSize(JComponent c) {
\r
827 Dimension d = getPreferredSize();// new Dimension();
\r
828 // Document doc = editor.getDocument();
\r
829 Insets i = c.getInsets();
\r
830 // if (doc instanceof AbstractDocument) {
\r
831 // ((AbstractDocument)doc).readLock();
\r
835 d.width += i.left + i.right;
\r
836 d.height += i.top + i.bottom;
\r
838 // d.width = (int) rootView.getMinimumSpan(View.X_AXIS) + i.left + i.right;
\r
839 // d.height = (int) rootView.getMinimumSpan(View.Y_AXIS) + i.top + i.bottom;
\r
841 // if (doc instanceof AbstractDocument) {
\r
842 // ((AbstractDocument)doc).readUnlock();
\r
849 * Gets the maximum size for the editor component.
\r
852 * the editor component
\r
855 public Dimension getMaximumSize(JComponent c) {
\r
857 return getMinimumSize(c);
\r
859 // Document doc = editor.getDocument();
\r
860 // Insets i = c.getInsets();
\r
861 // Dimension d = new Dimension();
\r
862 // if (doc instanceof AbstractDocument) {
\r
863 // ((AbstractDocument)doc).readLock();
\r
866 // d.width = (int) Math.min((long) rootView.getMaximumSpan(View.X_AXIS) +
\r
867 // (long) i.left + (long) i.right, Integer.MAX_VALUE);
\r
868 // d.height = (int) Math.min((long) rootView.getMaximumSpan(View.Y_AXIS) +
\r
869 // (long) i.top + (long) i.bottom, Integer.MAX_VALUE);
\r
871 // if (doc instanceof AbstractDocument) {
\r
872 // ((AbstractDocument)doc).readUnlock();
\r
878 // ---- TextUI methods -------------------------------------------
\r
882 // * Gets the allocation to give the root View. Due
\r
883 // * to an unfortunate set of historical events this
\r
884 // * method is inappropriately named. The Rectangle
\r
885 // * returned has nothing to do with visibility.
\r
886 // * The component must have a non-zero positive size for
\r
887 // * this translation to be computed.
\r
889 // * @return the bounding box for the root view
\r
891 // protected Rectangle getVisibleEditorRect() {
\r
892 // Rectangle alloc = editor.getBounds();
\r
893 // if ((alloc.width > 0) && (alloc.height > 0)) {
\r
894 // alloc.x = alloc.y = 0;
\r
895 // Insets insets = editor.getInsets();
\r
896 // alloc.x += insets.left;
\r
897 // alloc.y += insets.top;
\r
898 // alloc.width -= insets.left + insets.right;
\r
899 // alloc.height -= insets.top + insets.bottom;
\r
906 // * Converts the given location in the model to a place in
\r
907 // * the view coordinate system.
\r
908 // * The component must have a non-zero positive size for
\r
909 // * this translation to be computed.
\r
911 // * @param tc the text component for which this UI is installed
\r
912 // * @param pos the local location in the model to translate >= 0
\r
913 // * @return the coordinates as a rectangle, null if the model is not painted
\r
914 // * @exception BadLocationException if the given position does not
\r
915 // * represent a valid location in the associated document
\r
916 // * @see TextUI#modelToView
\r
918 // public Rectangle modelToView(JTextComponent tc, int pos) throws
\r
919 // BadLocationException {
\r
920 // return modelToView(tc, pos, Position.Bias.Forward);
\r
924 // * Converts the given location in the model to a place in
\r
925 // * the view coordinate system.
\r
926 // * The component must have a non-zero positive size for
\r
927 // * this translation to be computed.
\r
929 // * @param tc the text component for which this UI is installed
\r
930 // * @param pos the local location in the model to translate >= 0
\r
931 // * @return the coordinates as a rectangle, null if the model is not painted
\r
932 // * @exception BadLocationException if the given position does not
\r
933 // * represent a valid location in the associated document
\r
934 // * @see TextUI#modelToView
\r
936 // public Rectangle modelToView(JTextComponent tc, int pos, Position.Bias
\r
937 // bias) throws BadLocationException {
\r
938 // Document doc = editor.getDocument();
\r
939 // if (doc instanceof AbstractDocument) {
\r
940 // ((AbstractDocument)doc).readLock();
\r
943 // Rectangle alloc = getVisibleEditorRect();
\r
944 // if (alloc != null) {
\r
945 // rootView.setSize(alloc.width, alloc.height);
\r
946 // Shape s = rootView.modelToView(pos, alloc, bias);
\r
947 // if (s != null) {
\r
948 // return s.getBounds();
\r
952 // if (doc instanceof AbstractDocument) {
\r
953 // ((AbstractDocument)doc).readUnlock();
\r
960 // * Converts the given place in the view coordinate system
\r
961 // * to the nearest representative location in the model.
\r
962 // * The component must have a non-zero positive size for
\r
963 // * this translation to be computed.
\r
965 // * @param tc the text component for which this UI is installed
\r
966 // * @param pt the location in the view to translate. This
\r
967 // * should be in the same coordinate system as the mouse events.
\r
968 // * @return the offset from the start of the document >= 0,
\r
969 // * -1 if not painted
\r
970 // * @see TextUI#viewToModel
\r
972 // public int viewToModel(JTextComponent tc, Point pt) {
\r
973 // return viewToModel(tc, pt, discardBias);
\r
977 // * Converts the given place in the view coordinate system
\r
978 // * to the nearest representative location in the model.
\r
979 // * The component must have a non-zero positive size for
\r
980 // * this translation to be computed.
\r
982 // * @param tc the text component for which this UI is installed
\r
983 // * @param pt the location in the view to translate. This
\r
984 // * should be in the same coordinate system as the mouse events.
\r
985 // * @return the offset from the start of the document >= 0,
\r
986 // * -1 if the component doesn't yet have a positive size.
\r
987 // * @see TextUI#viewToModel
\r
989 // public int viewToModel(JTextComponent tc, Point pt,
\r
990 // Position.Bias[] biasReturn) {
\r
992 // Document doc = editor.getDocument();
\r
993 // if (doc instanceof AbstractDocument) {
\r
994 // ((AbstractDocument)doc).readLock();
\r
997 // Rectangle alloc = getVisibleEditorRect();
\r
998 // if (alloc != null) {
\r
999 // rootView.setSize(alloc.width, alloc.height);
\r
1000 // offs = rootView.viewToModel(pt.x, pt.y, alloc, biasReturn);
\r
1003 // if (doc instanceof AbstractDocument) {
\r
1004 // ((AbstractDocument)doc).readUnlock();
\r
1011 // * {@inheritDoc}
\r
1013 // public int getNextVisualPositionFrom(JTextComponent t, int pos,
\r
1014 // Position.Bias b, int direction, Position.Bias[] biasRet)
\r
1015 // throws BadLocationException{
\r
1016 // Document doc = editor.getDocument();
\r
1017 // if (doc instanceof AbstractDocument) {
\r
1018 // ((AbstractDocument)doc).readLock();
\r
1022 // Rectangle alloc = getVisibleEditorRect();
\r
1023 // if (alloc != null) {
\r
1024 // rootView.setSize(alloc.width, alloc.height);
\r
1026 // return rootView.getNextVisualPositionFrom(pos, b, alloc, direction,
\r
1030 // if (doc instanceof AbstractDocument) {
\r
1031 // ((AbstractDocument)doc).readUnlock();
\r
1038 // * Causes the portion of the view responsible for the
\r
1039 // * given part of the model to be repainted. Does nothing if
\r
1040 // * the view is not currently painted.
\r
1042 // * @param tc the text component for which this UI is installed
\r
1043 // * @param p0 the beginning of the range >= 0
\r
1044 // * @param p1 the end of the range >= p0
\r
1045 // * @see TextUI#damageRange
\r
1047 // public void damageRange(JTextComponent tc, int p0, int p1) {
\r
1048 // damageRange(tc, p0, p1, Position.Bias.Forward, Position.Bias.Backward);
\r
1052 // * Causes the portion of the view responsible for the
\r
1053 // * given part of the model to be repainted.
\r
1055 // * @param p0 the beginning of the range >= 0
\r
1056 // * @param p1 the end of the range >= p0
\r
1058 // public void damageRange(JTextComponent t, int p0, int p1,
\r
1059 // Position.Bias p0Bias, Position.Bias p1Bias) {
\r
1061 // Rectangle alloc = getVisibleEditorRect();
\r
1062 // if (alloc != null) {
\r
1063 // Document doc = t.getDocument();
\r
1064 // if (doc instanceof AbstractDocument) {
\r
1065 // ((AbstractDocument)doc).readLock();
\r
1068 // rootView.setSize(alloc.width, alloc.height);
\r
1069 // Shape toDamage = rootView.modelToView(p0, p0Bias,
\r
1070 // p1, p1Bias, alloc);
\r
1071 // Rectangle rect = (toDamage instanceof Rectangle) ?
\r
1072 // (Rectangle)toDamage : toDamage.getBounds();
\r
1073 // editor.repaint(rect.x, rect.y, rect.width, rect.height);
\r
1074 // } catch (BadLocationException e) {
\r
1076 // if (doc instanceof AbstractDocument) {
\r
1077 // ((AbstractDocument)doc).readUnlock();
\r
1085 * Fetches the EditorKit for the UI.
\r
1088 * the text component for which this UI is installed
\r
1089 * @return the editor capabilities
\r
1090 * @see TextUI#getEditorKit
\r
1092 public EditorKit getEditorKit(JTextComponent tc) {
\r
1093 return defaultKit;
\r
1097 // * Fetches a View with the allocation of the associated
\r
1098 // * text component (i.e. the root of the hierarchy) that
\r
1099 // * can be traversed to determine how the model is being
\r
1100 // * represented spatially.
\r
1102 // * <font color=red><b>NOTE:</b>The View hierarchy can
\r
1103 // * be traversed from the root view, and other things
\r
1104 // * can be done as well. Things done in this way cannot
\r
1105 // * be protected like simple method calls through the TextUI.
\r
1106 // * Therefore, proper operation in the presence of concurrency
\r
1107 // * must be arranged by any logic that calls this method!
\r
1110 // * @param tc the text component for which this UI is installed
\r
1111 // * @return the view
\r
1112 // * @see TextUI#getRootView
\r
1114 // public View getRootView(JTextComponent tc) {
\r
1115 // return rootView;
\r
1119 // * Returns the string to be used as the tooltip at the passed in location.
\r
1120 // * This forwards the method onto the root View.
\r
1122 // * @see jsjavax.swing.text.JTextComponent#getToolTipText
\r
1123 // * @see jsjavax.swing.text.View#getToolTipText
\r
1126 // public String getToolTipText(JTextComponent t, Point pt) {
\r
1127 // if (!painted) {
\r
1130 // Document doc = editor.getDocument();
\r
1131 // String tt = null;
\r
1132 // Rectangle alloc = getVisibleEditorRect();
\r
1134 // if (alloc != null) {
\r
1135 // if (doc instanceof AbstractDocument) {
\r
1136 // ((AbstractDocument)doc).readLock();
\r
1139 // tt = rootView.getToolTipText(pt.x, pt.y, alloc);
\r
1141 // if (doc instanceof AbstractDocument) {
\r
1142 // ((AbstractDocument)doc).readUnlock();
\r
1149 // --- ViewFactory methods ------------------------------
\r
1152 // * Creates a view for an element.
\r
1153 // * If a subclass wishes to directly implement the factory
\r
1154 // * producing the view(s), it should reimplement this
\r
1155 // * method. By default it simply returns null indicating
\r
1156 // * it is unable to represent the element.
\r
1158 // * @param elem the element
\r
1159 // * @return the view
\r
1161 // public View create(Element elem) {
\r
1166 // * Creates a view for an element.
\r
1167 // * If a subclass wishes to directly implement the factory
\r
1168 // * producing the view(s), it should reimplement this
\r
1169 // * method. By default it simply returns null indicating
\r
1170 // * it is unable to represent the part of the element.
\r
1172 // * @param elem the element
\r
1173 // * @param p0 the starting offset >= 0
\r
1174 // * @param p1 the ending offset >= p0
\r
1175 // * @return the view
\r
1177 // public View create(Element elem, int p0, int p1) {
\r
1181 // public static class BasicCaret extends DefaultCaret implements UIResource
\r
1184 // public static class BasicHighlighter extends DefaultHighlighter implements
\r
1187 // static class BasicCursor extends Cursor implements UIResource {
\r
1188 // BasicCursor(int type) {
\r
1192 // BasicCursor(String name) {
\r
1197 // private static BasicCursor textCursor = new
\r
1198 // BasicCursor(Cursor.TEXT_CURSOR);
\r
1199 // ----- member variables ---------------------------------------
\r
1201 private static final EditorKit defaultKit = new DefaultEditorKit();
\r
1202 transient JTextComponent editor;
\r
1203 protected boolean editable = true;
\r
1205 // transient boolean painted;
\r
1206 // transient RootView rootView = new RootView();
\r
1207 // transient UpdateHandler updateHandler = new UpdateHandler();
\r
1208 // private static final TransferHandler defaultTransferHandler = new
\r
1209 // TextTransferHandler();
\r
1210 // private final DragListener dragListener = getDragListener();
\r
1211 // private static final Position.Bias[] discardBias = new Position.Bias[1];
\r
1212 // private DefaultCaret dropCaret;
\r
1215 // * Root view that acts as a gateway between the component
\r
1216 // * and the View hierarchy.
\r
1218 // class RootView extends View {
\r
1224 // void setView(View v) {
\r
1225 // View oldView = view;
\r
1227 // if (oldView != null) {
\r
1228 // // get rid of back reference so that the old
\r
1229 // // hierarchy can be garbage collected.
\r
1230 // oldView.setParent(null);
\r
1232 // if (v != null) {
\r
1233 // v.setParent(this);
\r
1239 // * Fetches the attributes to use when rendering. At the root
\r
1240 // * level there are no attributes. If an attribute is resolved
\r
1241 // * up the view hierarchy this is the end of the line.
\r
1243 // public AttributeSet getAttributes() {
\r
1248 // * Determines the preferred span for this view along an axis.
\r
1250 // * @param axis may be either X_AXIS or Y_AXIS
\r
1251 // * @return the span the view would like to be rendered into.
\r
1252 // * Typically the view is told to render into the span
\r
1253 // * that is returned, although there is no guarantee.
\r
1254 // * The parent may choose to resize or break the view.
\r
1256 // public float getPreferredSpan(int axis) {
\r
1257 // if (view != null) {
\r
1258 // return view.getPreferredSpan(axis);
\r
1264 // * Determines the minimum span for this view along an axis.
\r
1266 // * @param axis may be either X_AXIS or Y_AXIS
\r
1267 // * @return the span the view would like to be rendered into.
\r
1268 // * Typically the view is told to render into the span
\r
1269 // * that is returned, although there is no guarantee.
\r
1270 // * The parent may choose to resize or break the view.
\r
1272 // public float getMinimumSpan(int axis) {
\r
1273 // if (view != null) {
\r
1274 // return view.getMinimumSpan(axis);
\r
1280 // * Determines the maximum span for this view along an axis.
\r
1282 // * @param axis may be either X_AXIS or Y_AXIS
\r
1283 // * @return the span the view would like to be rendered into.
\r
1284 // * Typically the view is told to render into the span
\r
1285 // * that is returned, although there is no guarantee.
\r
1286 // * The parent may choose to resize or break the view.
\r
1288 // public float getMaximumSpan(int axis) {
\r
1289 // return Integer.MAX_VALUE;
\r
1293 // * Specifies that a preference has changed.
\r
1294 // * Child views can call this on the parent to indicate that
\r
1295 // * the preference has changed. The root view routes this to
\r
1296 // * invalidate on the hosting component.
\r
1298 // * This can be called on a different thread from the
\r
1299 // * event dispatching thread and is basically unsafe to
\r
1300 // * propagate into the component. To make this safe,
\r
1301 // * the operation is transferred over to the event dispatching
\r
1302 // * thread for completion. It is a design goal that all view
\r
1303 // * methods be safe to call without concern for concurrency,
\r
1304 // * and this behavior helps make that true.
\r
1306 // * @param child the child view
\r
1307 // * @param width true if the width preference has changed
\r
1308 // * @param height true if the height preference has changed
\r
1310 // public void preferenceChanged(View child, boolean width, boolean height) {
\r
1311 // editor.revalidate();
\r
1315 // * Determines the desired alignment for this view along an axis.
\r
1317 // * @param axis may be either X_AXIS or Y_AXIS
\r
1318 // * @return the desired alignment, where 0.0 indicates the origin
\r
1319 // * and 1.0 the full span away from the origin
\r
1321 // public float getAlignment(int axis) {
\r
1322 // if (view != null) {
\r
1323 // return view.getAlignment(axis);
\r
1329 // * Renders the view.
\r
1331 // * @param g the graphics context
\r
1332 // * @param allocation the region to render into
\r
1334 // public void paint(Graphics g, Shape allocation) {
\r
1335 // if (view != null) {
\r
1336 // Rectangle alloc = (allocation instanceof Rectangle) ?
\r
1337 // (Rectangle)allocation : allocation.getBounds();
\r
1338 // setSize(alloc.width, alloc.height);
\r
1339 // view.paint(g, allocation);
\r
1344 // * Sets the view parent.
\r
1346 // * @param parent the parent view
\r
1348 // public void setParent(View parent) {
\r
1349 // throw new Error("Can't set parent on root view");
\r
1353 // * Returns the number of views in this view. Since
\r
1354 // * this view simply wraps the root of the view hierarchy
\r
1355 // * it has exactly one child.
\r
1357 // * @return the number of views
\r
1358 // * @see #getView
\r
1360 // public int getViewCount() {
\r
1365 // * Gets the n-th view in this container.
\r
1367 // * @param n the number of the view to get
\r
1368 // * @return the view
\r
1370 // public View getView(int n) {
\r
1375 // * Returns the child view index representing the given position in
\r
1376 // * the model. This is implemented to return the index of the only
\r
1379 // * @param pos the position >= 0
\r
1380 // * @return index of the view representing the given position, or
\r
1381 // * -1 if no view represents that position
\r
1384 // public int getViewIndex(int pos, Position.Bias b) {
\r
1389 // * Fetches the allocation for the given child view.
\r
1390 // * This enables finding out where various views
\r
1391 // * are located, without assuming the views store
\r
1392 // * their location. This returns the given allocation
\r
1393 // * since this view simply acts as a gateway between
\r
1394 // * the view hierarchy and the associated component.
\r
1396 // * @param index the index of the child
\r
1397 // * @param a the allocation to this view.
\r
1398 // * @return the allocation to the child
\r
1400 // public Shape getChildAllocation(int index, Shape a) {
\r
1405 // * Provides a mapping from the document model coordinate space
\r
1406 // * to the coordinate space of the view mapped to it.
\r
1408 // * @param pos the position to convert
\r
1409 // * @param a the allocated region to render into
\r
1410 // * @return the bounding box of the given position
\r
1412 // public Shape modelToView(int pos, Shape a, Position.Bias b) throws
\r
1413 // BadLocationException {
\r
1414 // if (view != null) {
\r
1415 // return view.modelToView(pos, a, b);
\r
1421 // * Provides a mapping from the document model coordinate space
\r
1422 // * to the coordinate space of the view mapped to it.
\r
1424 // * @param p0 the position to convert >= 0
\r
1425 // * @param b0 the bias toward the previous character or the
\r
1426 // * next character represented by p0, in case the
\r
1427 // * position is a boundary of two views.
\r
1428 // * @param p1 the position to convert >= 0
\r
1429 // * @param b1 the bias toward the previous character or the
\r
1430 // * next character represented by p1, in case the
\r
1431 // * position is a boundary of two views.
\r
1432 // * @param a the allocated region to render into
\r
1433 // * @return the bounding box of the given position is returned
\r
1434 // * @exception BadLocationException if the given position does
\r
1435 // * not represent a valid location in the associated document
\r
1436 // * @exception IllegalArgumentException for an invalid bias argument
\r
1437 // * @see View#viewToModel
\r
1439 // public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias
\r
1440 // b1, Shape a) throws BadLocationException {
\r
1441 // if (view != null) {
\r
1442 // return view.modelToView(p0, b0, p1, b1, a);
\r
1448 // * Provides a mapping from the view coordinate space to the logical
\r
1449 // * coordinate space of the model.
\r
1451 // * @param x x coordinate of the view location to convert
\r
1452 // * @param y y coordinate of the view location to convert
\r
1453 // * @param a the allocated region to render into
\r
1454 // * @return the location within the model that best represents the
\r
1455 // * given point in the view
\r
1457 // public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {
\r
1458 // if (view != null) {
\r
1459 // int retValue = view.viewToModel(x, y, a, bias);
\r
1460 // return retValue;
\r
1466 // * Provides a way to determine the next visually represented model
\r
1467 // * location that one might place a caret. Some views may not be visible,
\r
1468 // * they might not be in the same order found in the model, or they just
\r
1469 // * might not allow access to some of the locations in the model.
\r
1471 // * @param pos the position to convert >= 0
\r
1472 // * @param a the allocated region to render into
\r
1473 // * @param direction the direction from the current position that can
\r
1474 // * be thought of as the arrow keys typically found on a keyboard.
\r
1475 // * This may be SwingConstants.WEST, SwingConstants.EAST,
\r
1476 // * SwingConstants.NORTH, or SwingConstants.SOUTH.
\r
1477 // * @return the location within the model that best represents the next
\r
1478 // * location visual position.
\r
1479 // * @exception BadLocationException
\r
1480 // * @exception IllegalArgumentException for an invalid direction
\r
1482 // public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
\r
1484 // Position.Bias[] biasRet)
\r
1485 // throws BadLocationException {
\r
1486 // if( view != null ) {
\r
1487 // int nextPos = view.getNextVisualPositionFrom(pos, b, a,
\r
1488 // direction, biasRet);
\r
1489 // if(nextPos != -1) {
\r
1493 // biasRet[0] = b;
\r
1500 // * Gives notification that something was inserted into the document
\r
1501 // * in a location that this view is responsible for.
\r
1503 // * @param e the change information from the associated document
\r
1504 // * @param a the current allocation of the view
\r
1505 // * @param f the factory to use to rebuild if the view has children
\r
1507 // public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
\r
1508 // if (view != null) {
\r
1509 // view.insertUpdate(e, a, f);
\r
1514 // * Gives notification that something was removed from the document
\r
1515 // * in a location that this view is responsible for.
\r
1517 // * @param e the change information from the associated document
\r
1518 // * @param a the current allocation of the view
\r
1519 // * @param f the factory to use to rebuild if the view has children
\r
1521 // public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
\r
1522 // if (view != null) {
\r
1523 // view.removeUpdate(e, a, f);
\r
1528 // * Gives notification from the document that attributes were changed
\r
1529 // * in a location that this view is responsible for.
\r
1531 // * @param e the change information from the associated document
\r
1532 // * @param a the current allocation of the view
\r
1533 // * @param f the factory to use to rebuild if the view has children
\r
1535 // public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
\r
1536 // if (view != null) {
\r
1537 // view.changedUpdate(e, a, f);
\r
1542 // * Returns the document model underlying the view.
\r
1544 // * @return the model
\r
1546 // public Document getDocument() {
\r
1547 // return editor.getDocument();
\r
1551 // * Returns the starting offset into the model for this view.
\r
1553 // * @return the starting offset
\r
1555 // public int getStartOffset() {
\r
1556 // if (view != null) {
\r
1557 // return view.getStartOffset();
\r
1559 // return getElement().getStartOffset();
\r
1563 // * Returns the ending offset into the model for this view.
\r
1565 // * @return the ending offset
\r
1567 // public int getEndOffset() {
\r
1568 // if (view != null) {
\r
1569 // return view.getEndOffset();
\r
1571 // return getElement().getEndOffset();
\r
1575 // * Gets the element that this view is mapped to.
\r
1577 // * @return the view
\r
1579 // public Element getElement() {
\r
1580 // if (view != null) {
\r
1581 // return view.getElement();
\r
1583 // return editor.getDocument().getDefaultRootElement();
\r
1587 // * Breaks this view on the given axis at the given length.
\r
1589 // * @param axis may be either X_AXIS or Y_AXIS
\r
1590 // * @param len specifies where a break is desired in the span
\r
1591 // * @param the current allocation of the view
\r
1592 // * @return the fragment of the view that represents the given span
\r
1593 // * if the view can be broken, otherwise null
\r
1595 // public View breakView(int axis, float len, Shape a) {
\r
1596 // throw new Error("Can't break root view");
\r
1600 // * Determines the resizability of the view along the
\r
1601 // * given axis. A value of 0 or less is not resizable.
\r
1603 // * @param axis may be either X_AXIS or Y_AXIS
\r
1604 // * @return the weight
\r
1606 // public int getResizeWeight(int axis) {
\r
1607 // if (view != null) {
\r
1608 // return view.getResizeWeight(axis);
\r
1614 // * Sets the view size.
\r
1616 // * @param width the width
\r
1617 // * @param height the height
\r
1619 // public void setSize(float width, float height) {
\r
1620 // if (view != null) {
\r
1621 // view.setSize(width, height);
\r
1626 // * Fetches the container hosting the view. This is useful for
\r
1627 // * things like scheduling a repaint, finding out the host
\r
1628 // * components font, etc. The default implementation
\r
1629 // * of this is to forward the query to the parent view.
\r
1631 // * @return the container
\r
1633 // public Container getContainer() {
\r
1638 // * Fetches the factory to be used for building the
\r
1639 // * various view fragments that make up the view that
\r
1640 // * represents the model. This is what determines
\r
1641 // * how the model will be represented. This is implemented
\r
1642 // * to fetch the factory provided by the associated
\r
1643 // * EditorKit unless that is null, in which case this
\r
1644 // * simply returns the BasicTextUI itself which allows
\r
1645 // * subclasses to implement a simple factory directly without
\r
1646 // * creating extra objects.
\r
1648 // * @return the factory
\r
1650 // public ViewFactory getViewFactory() {
\r
1651 // EditorKit kit = getEditorKit(editor);
\r
1652 // ViewFactory f = kit.getViewFactory();
\r
1653 // if (f != null) {
\r
1656 // return BasicTextUI.this;
\r
1659 // private View view;
\r
1664 // * Handles updates from various places. If the model is changed,
\r
1665 // * this class unregisters as a listener to the old model and
\r
1666 // * registers with the new model. If the document model changes,
\r
1667 // * the change is forwarded to the root view. If the focus
\r
1668 // * accelerator changes, a new keystroke is registered to request
\r
1671 // class UpdateHandler implements PropertyChangeListener, DocumentListener,
\r
1672 // LayoutManager2, UIResource {
\r
1674 // // --- PropertyChangeListener methods -----------------------
\r
1677 // * This method gets called when a bound property is changed.
\r
1678 // * We are looking for document changes on the editor.
\r
1680 // public final void propertyChange(PropertyChangeEvent evt) {
\r
1681 // Object oldValue = evt.getOldValue();
\r
1682 // Object newValue = evt.getNewValue();
\r
1683 // String propertyName = evt.getPropertyName();
\r
1684 // if ((oldValue instanceof Document) || (newValue instanceof Document)) {
\r
1685 // if (oldValue != null) {
\r
1686 // ((Document)oldValue).removeDocumentListener(this);
\r
1687 // i18nView = false;
\r
1689 // if (newValue != null) {
\r
1690 // ((Document)newValue).addDocumentListener(this);
\r
1691 // if ("document" == propertyName) {
\r
1693 // BasicTextUI.this.propertyChange(evt);
\r
1694 // modelChanged();
\r
1698 // modelChanged();
\r
1700 // if ("focusAccelerator" == propertyName) {
\r
1701 // updateFocusAcceleratorBinding(true);
\r
1702 // } else if ("componentOrientation" == propertyName) {
\r
1703 // // Changes in ComponentOrientation require the views to be
\r
1705 // modelChanged();
\r
1706 // } else if ("font" == propertyName) {
\r
1707 // modelChanged();
\r
1708 // } else if ("dropLocation" == propertyName) {
\r
1709 // dropIndexChanged();
\r
1710 // } else if ("editable" == propertyName) {
\r
1711 // updateCursor();
\r
1712 // modelChanged();
\r
1714 // BasicTextUI.this.propertyChange(evt);
\r
1717 // private void dropIndexChanged() {
\r
1718 // if (editor.getDropMode() == DropMode.USE_SELECTION) {
\r
1722 // JTextComponent.DropLocation dropLocation = editor.getDropLocation();
\r
1724 // if (dropLocation == null) {
\r
1725 // if (dropCaret != null) {
\r
1726 // dropCaret.deinstall(editor);
\r
1727 // editor.repaint(dropCaret);
\r
1728 // dropCaret = null;
\r
1731 // if (dropCaret == null) {
\r
1732 // dropCaret = new BasicCaret();
\r
1733 // dropCaret.install(editor);
\r
1734 // dropCaret.setVisible(true);
\r
1737 // dropCaret.setDot(dropLocation.getIndex(),
\r
1738 // dropLocation.getBias());
\r
1742 // // --- DocumentListener methods -----------------------
\r
1745 // * The insert notification. Gets sent to the root of the view structure
\r
1746 // * that represents the portion of the model being represented by the
\r
1747 // * editor. The factory is added as an argument to the update so that
\r
1748 // * the views can update themselves in a dynamic (not hardcoded) way.
\r
1750 // * @param e The change notification from the currently associated
\r
1752 // * @see DocumentListener#insertUpdate
\r
1754 // public final void insertUpdate(DocumentEvent e) {
\r
1755 // Document doc = e.getDocument();
\r
1756 // Object o = doc.getProperty("i18n");
\r
1757 // if (o instanceof Boolean) {
\r
1758 // Boolean i18nFlag = (Boolean) o;
\r
1759 // if (i18nFlag.booleanValue() != i18nView) {
\r
1760 // // i18n flag changed, rebuild the view
\r
1761 // i18nView = i18nFlag.booleanValue();
\r
1762 // modelChanged();
\r
1767 // // normal insert update
\r
1768 // Rectangle alloc = (painted) ? getVisibleEditorRect() : null;
\r
1769 // rootView.insertUpdate(e, alloc, rootView.getViewFactory());
\r
1773 // * The remove notification. Gets sent to the root of the view structure
\r
1774 // * that represents the portion of the model being represented by the
\r
1775 // * editor. The factory is added as an argument to the update so that
\r
1776 // * the views can update themselves in a dynamic (not hardcoded) way.
\r
1778 // * @param e The change notification from the currently associated
\r
1780 // * @see DocumentListener#removeUpdate
\r
1782 // public final void removeUpdate(DocumentEvent e) {
\r
1783 // Rectangle alloc = (painted) ? getVisibleEditorRect() : null;
\r
1784 // rootView.removeUpdate(e, alloc, rootView.getViewFactory());
\r
1788 // * The change notification. Gets sent to the root of the view structure
\r
1789 // * that represents the portion of the model being represented by the
\r
1790 // * editor. The factory is added as an argument to the update so that
\r
1791 // * the views can update themselves in a dynamic (not hardcoded) way.
\r
1793 // * @param e The change notification from the currently associated
\r
1795 // * @see DocumentListener#changeUpdate
\r
1797 // public final void changedUpdate(DocumentEvent e) {
\r
1798 // Rectangle alloc = (painted) ? getVisibleEditorRect() : null;
\r
1799 // rootView.changedUpdate(e, alloc, rootView.getViewFactory());
\r
1802 // // --- LayoutManager2 methods --------------------------------
\r
1805 // * Adds the specified component with the specified name to
\r
1807 // * @param name the component name
\r
1808 // * @param comp the component to be added
\r
1810 // public void addLayoutComponent(String name, Component comp) {
\r
1811 // // not supported
\r
1815 // * Removes the specified component from the layout.
\r
1816 // * @param comp the component to be removed
\r
1818 // public void removeLayoutComponent(Component comp) {
\r
1819 // if (constraints != null) {
\r
1820 // // remove the constraint record
\r
1821 // constraints.remove(comp);
\r
1826 // * Calculates the preferred size dimensions for the specified
\r
1827 // * panel given the components in the specified parent container.
\r
1828 // * @param parent the component to be laid out
\r
1830 // * @see #minimumLayoutSize
\r
1832 // public Dimension preferredLayoutSize(Container parent) {
\r
1833 // // should not be called (JComponent uses UI instead)
\r
1838 // * Calculates the minimum size dimensions for the specified
\r
1839 // * panel given the components in the specified parent container.
\r
1840 // * @param parent the component to be laid out
\r
1841 // * @see #preferredLayoutSize
\r
1843 // public Dimension minimumLayoutSize(Container parent) {
\r
1844 // // should not be called (JComponent uses UI instead)
\r
1849 // * Lays out the container in the specified panel. This is
\r
1850 // * implemented to position all components that were added
\r
1851 // * with a View object as a constraint. The current allocation
\r
1852 // * of the associated View is used as the location of the
\r
1855 // * A read-lock is acquired on the document to prevent the
\r
1856 // * view tree from being modified while the layout process
\r
1859 // * @param parent the component which needs to be laid out
\r
1861 // public void layoutContainer(Container parent) {
\r
1862 // if ((constraints != null) && (! constraints.isEmpty())) {
\r
1863 // Rectangle alloc = getVisibleEditorRect();
\r
1864 // if (alloc != null) {
\r
1865 // Document doc = editor.getDocument();
\r
1866 // if (doc instanceof AbstractDocument) {
\r
1867 // ((AbstractDocument)doc).readLock();
\r
1870 // rootView.setSize(alloc.width, alloc.height);
\r
1871 // Enumeration components = constraints.keys();
\r
1872 // while (components.hasMoreElements()) {
\r
1873 // Component comp = (Component) components.nextElement();
\r
1874 // View v = (View) constraints.get(comp);
\r
1875 // Shape ca = calculateViewPosition(alloc, v);
\r
1876 // if (ca != null) {
\r
1877 // Rectangle compAlloc = (ca instanceof Rectangle) ?
\r
1878 // (Rectangle) ca : ca.getBounds();
\r
1879 // comp.setBounds(compAlloc);
\r
1883 // if (doc instanceof AbstractDocument) {
\r
1884 // ((AbstractDocument)doc).readUnlock();
\r
1892 // * Find the Shape representing the given view.
\r
1894 // Shape calculateViewPosition(Shape alloc, View v) {
\r
1895 // int pos = v.getStartOffset();
\r
1896 // View child = null;
\r
1897 // for (View parent = rootView; (parent != null) && (parent != v); parent =
\r
1899 // int index = parent.getViewIndex(pos, Position.Bias.Forward);
\r
1900 // alloc = parent.getChildAllocation(index, alloc);
\r
1901 // child = parent.getView(index);
\r
1903 // return (child != null) ? alloc : null;
\r
1907 // * Adds the specified component to the layout, using the specified
\r
1908 // * constraint object. We only store those components that were added
\r
1909 // * with a constraint that is of type View.
\r
1911 // * @param comp the component to be added
\r
1912 // * @param constraint where/how the component is added to the layout.
\r
1914 // public void addLayoutComponent(Component comp, Object constraint) {
\r
1915 // if (constraint instanceof View) {
\r
1916 // if (constraints == null) {
\r
1917 // constraints = new Hashtable(7);
\r
1919 // constraints.put(comp, constraint);
\r
1924 // * Returns the maximum size of this component.
\r
1925 // * @see jsjava.awt.Component#getMinimumSize()
\r
1926 // * @see jsjava.awt.Component#getPreferredSize()
\r
1927 // * @see LayoutManager
\r
1929 // public Dimension maximumLayoutSize(Container target) {
\r
1930 // // should not be called (JComponent uses UI instead)
\r
1935 // * Returns the alignment along the x axis. This specifies how
\r
1936 // * the component would like to be aligned relative to other
\r
1937 // * components. The value should be a number between 0 and 1
\r
1938 // * where 0 represents alignment along the origin, 1 is aligned
\r
1939 // * the furthest away from the origin, 0.5 is centered, etc.
\r
1941 // public float getLayoutAlignmentX(Container target) {
\r
1946 // * Returns the alignment along the y axis. This specifies how
\r
1947 // * the component would like to be aligned relative to other
\r
1948 // * components. The value should be a number between 0 and 1
\r
1949 // * where 0 represents alignment along the origin, 1 is aligned
\r
1950 // * the furthest away from the origin, 0.5 is centered, etc.
\r
1952 // public float getLayoutAlignmentY(Container target) {
\r
1957 // * Invalidates the layout, indicating that if the layout manager
\r
1958 // * has cached information it should be discarded.
\r
1960 // public void invalidateLayout(Container target) {
\r
1964 // * The "layout constraints" for the LayoutManager2 implementation.
\r
1965 // * These are View objects for those components that are represented
\r
1966 // * by a View in the View tree.
\r
1968 // private Hashtable constraints;
\r
1970 // private boolean i18nView = false;
\r
1974 * Wrapper for text actions to return isEnabled false in case editor is non
\r
1977 class TextActionWrapper extends TextAction {
\r
1978 public TextActionWrapper(TextAction action) {
\r
1979 super((String) action.getValue(Action.NAME));
\r
1980 this.action = action;
\r
1984 * The operation to perform when this action is triggered.
\r
1987 * the action event
\r
1989 public void actionPerformed(ActionEvent e) {
\r
1990 action.actionPerformed(e);
\r
1993 public boolean isEnabled() {
\r
1994 return (editor == null || editor.isEditable()) ? action.isEnabled()
\r
1998 TextAction action = null;
\r
2002 * Registered in the ActionMap.
\r
2004 class FocusAction extends AbstractAction {
\r
2006 public void actionPerformed(ActionEvent e) {
\r
2007 editor.requestFocus();
\r
2010 public boolean isEnabled() {
\r
2011 return editor.isEditable();
\r
2015 boolean handleEnter(int eventType) {
\r
2021 public void setEditable(boolean editable) {
\r
2023 this.editable = editable;
\r
2024 if (domNode == null)
\r
2026 if (c.isBackgroundSet())
\r
2027 bgcolor0 = JSToolkit.getCSSColor(c.getBackground());
\r
2029 domNode.removeAttribute("readOnly");
\r
2030 if (bgcolor0 != null)
\r
2031 DOMNode.setStyles(domNode, "background-color", bgcolor0);
\r
2033 DOMNode.setAttr(domNode, "readOnly", "true");
\r
2034 if (c.isBackgroundSet()) {
\r
2035 bgcolor0 = JSToolkit.getCSSColor(c.getBackground());
\r
2037 if (bgcolor0 == null)
\r
2038 bgcolor0 = domNode.getStyle("background-color");
\r
2040 DOMNode.setStyles(domNode, "background-color", "rgba(0,0,0,0)");
\r
2045 // private static DragListener getDragListener() {
\r
2046 // synchronized(DragListener.class) {
\r
2047 // DragListener listener =
\r
2048 // (DragListener)AppContext.getAppContext().
\r
2049 // get(DragListener.class);
\r
2051 // if (listener == null) {
\r
2052 // listener = new DragListener();
\r
2053 // AppContext.getAppContext().put(DragListener.class, listener);
\r
2056 // return listener;
\r
2061 // * Listens for mouse events for the purposes of detecting drag gestures.
\r
2062 // * BasicTextUI will maintain one of these per AppContext.
\r
2064 // static class DragListener extends MouseInputAdapter
\r
2065 // implements BeforeDrag {
\r
2067 // private boolean dragStarted;
\r
2069 // public void dragStarting(MouseEvent me) {
\r
2070 // dragStarted = true;
\r
2073 // public void mousePressed(MouseEvent e) {
\r
2074 // JTextComponent c = (JTextComponent)e.getSource();
\r
2075 // if (c.getDragEnabled()) {
\r
2076 // dragStarted = false;
\r
2077 // if (isDragPossible(e) && DragRecognitionSupport.mousePressed(e)) {
\r
2083 // public void mouseReleased(MouseEvent e) {
\r
2084 // JTextComponent c = (JTextComponent)e.getSource();
\r
2085 // if (c.getDragEnabled()) {
\r
2086 // if (dragStarted) {
\r
2090 // DragRecognitionSupport.mouseReleased(e);
\r
2094 // public void mouseDragged(MouseEvent e) {
\r
2095 // JTextComponent c = (JTextComponent)e.getSource();
\r
2096 // if (c.getDragEnabled()) {
\r
2097 // if (dragStarted || DragRecognitionSupport.mouseDragged(e, this)) {
\r
2104 // * Determines if the following are true:
\r
2106 // * <li>the component is enabled
\r
2107 // * <li>the press event is located over a selection
\r
2110 // protected boolean isDragPossible(MouseEvent e) {
\r
2111 // JTextComponent c = (JTextComponent)e.getSource();
\r
2112 // if (c.isEnabled()) {
\r
2113 // Caret caret = c.getCaret();
\r
2114 // int dot = caret.getDot();
\r
2115 // int mark = caret.getMark();
\r
2116 // if (dot != mark) {
\r
2117 // Point p = new Point(e.getX(), e.getY());
\r
2118 // int pos = c.viewToModel(p);
\r
2120 // int p0 = Math.min(dot, mark);
\r
2121 // int p1 = Math.max(dot, mark);
\r
2122 // if ((pos >= p0) && (pos < p1)) {
\r
2131 // static class TextTransferHandler extends TransferHandler implements
\r
2134 // private JTextComponent exportComp;
\r
2135 // private boolean shouldRemove;
\r
2136 // private int p0;
\r
2137 // private int p1;
\r
2140 // * Whether or not this is a drop using
\r
2141 // * <code>DropMode.INSERT</code>.
\r
2143 // private boolean modeBetween = false;
\r
2146 // * Whether or not this is a drop.
\r
2148 // private boolean isDrop = false;
\r
2151 // * The drop action.
\r
2153 // private int dropAction = MOVE;
\r
2156 // * The drop bias.
\r
2158 // private Position.Bias dropBias;
\r
2161 // * Try to find a flavor that can be used to import a Transferable.
\r
2162 // * The set of usable flavors are tried in the following order:
\r
2164 // * <li>First, an attempt is made to find a flavor matching the content type
\r
2165 // * of the EditorKit for the component.
\r
2166 // * <li>Second, an attempt to find a text/plain flavor is made.
\r
2167 // * <li>Third, an attempt to find a flavor representing a String reference
\r
2168 // * in the same VM is made.
\r
2169 // * <li>Lastly, DataFlavor.stringFlavor is searched for.
\r
2172 // protected DataFlavor getImportFlavor(DataFlavor[] flavors, JTextComponent
\r
2174 // DataFlavor plainFlavor = null;
\r
2175 // DataFlavor refFlavor = null;
\r
2176 // DataFlavor stringFlavor = null;
\r
2178 // if (c instanceof JEditorPane) {
\r
2179 // for (int i = 0; i < flavors.length; i++) {
\r
2180 // String mime = flavors[i].getMimeType();
\r
2181 // if (mime.startsWith(((JEditorPane)c).getEditorKit().getContentType())) {
\r
2182 // return flavors[i];
\r
2183 // } else if (plainFlavor == null && mime.startsWith("text/plain")) {
\r
2184 // plainFlavor = flavors[i];
\r
2185 // } else if (refFlavor == null &&
\r
2186 // mime.startsWith("application/x-java-jvm-local-objectref")
\r
2187 // && flavors[i].getRepresentationClass() == jsjava.lang.String.class) {
\r
2188 // refFlavor = flavors[i];
\r
2189 // } else if (stringFlavor == null &&
\r
2190 // flavors[i].equals(DataFlavor.stringFlavor)) {
\r
2191 // stringFlavor = flavors[i];
\r
2194 // if (plainFlavor != null) {
\r
2195 // return plainFlavor;
\r
2196 // } else if (refFlavor != null) {
\r
2197 // return refFlavor;
\r
2198 // } else if (stringFlavor != null) {
\r
2199 // return stringFlavor;
\r
2205 // for (int i = 0; i < flavors.length; i++) {
\r
2206 // String mime = flavors[i].getMimeType();
\r
2207 // if (mime.startsWith("text/plain")) {
\r
2208 // return flavors[i];
\r
2209 // } else if (refFlavor == null &&
\r
2210 // mime.startsWith("application/x-java-jvm-local-objectref")
\r
2211 // && flavors[i].getRepresentationClass() == jsjava.lang.String.class) {
\r
2212 // refFlavor = flavors[i];
\r
2213 // } else if (stringFlavor == null &&
\r
2214 // flavors[i].equals(DataFlavor.stringFlavor)) {
\r
2215 // stringFlavor = flavors[i];
\r
2218 // if (refFlavor != null) {
\r
2219 // return refFlavor;
\r
2220 // } else if (stringFlavor != null) {
\r
2221 // return stringFlavor;
\r
2227 // * Import the given stream data into the text component.
\r
2229 // protected void handleReaderImport(Reader in, JTextComponent c, boolean
\r
2231 // throws BadLocationException, IOException {
\r
2233 // int startPosition = c.getSelectionStart();
\r
2234 // int endPosition = c.getSelectionEnd();
\r
2235 // int length = endPosition - startPosition;
\r
2236 // EditorKit kit = c.getUI().getEditorKit(c);
\r
2237 // Document doc = c.getDocument();
\r
2238 // if (length > 0) {
\r
2239 // doc.remove(startPosition, length);
\r
2241 // kit.read(in, doc, startPosition);
\r
2243 // char[] buff = new char[1024];
\r
2245 // boolean lastWasCR = false;
\r
2247 // StringBuffer sbuff = null;
\r
2249 // // Read in a block at a time, mapping \r\n to \n, as well as single
\r
2251 // while ((nch = in.read(buff, 0, buff.length)) != -1) {
\r
2252 // if (sbuff == null) {
\r
2253 // sbuff = new StringBuffer(nch);
\r
2256 // for(int counter = 0; counter < nch; counter++) {
\r
2257 // switch(buff[counter]) {
\r
2259 // if (lastWasCR) {
\r
2260 // if (counter == 0) {
\r
2261 // sbuff.append('\n');
\r
2263 // buff[counter - 1] = '\n';
\r
2266 // lastWasCR = true;
\r
2270 // if (lastWasCR) {
\r
2271 // if (counter > (last + 1)) {
\r
2272 // sbuff.append(buff, last, counter - last - 1);
\r
2274 // // else nothing to do, can skip \r, next write will
\r
2276 // lastWasCR = false;
\r
2277 // last = counter;
\r
2281 // if (lastWasCR) {
\r
2282 // if (counter == 0) {
\r
2283 // sbuff.append('\n');
\r
2285 // buff[counter - 1] = '\n';
\r
2287 // lastWasCR = false;
\r
2292 // if (last < nch) {
\r
2293 // if (lastWasCR) {
\r
2294 // if (last < (nch - 1)) {
\r
2295 // sbuff.append(buff, last, nch - last - 1);
\r
2298 // sbuff.append(buff, last, nch - last);
\r
2302 // if (lastWasCR) {
\r
2303 // sbuff.append('\n');
\r
2305 // c.replaceSelection(sbuff != null ? sbuff.toString() : "");
\r
2309 // // --- TransferHandler methods ------------------------------------
\r
2312 // * This is the type of transfer actions supported by the source. Some models
\r
2314 // * not mutable, so a transfer operation of COPY only should
\r
2315 // * be advertised in that case.
\r
2317 // * @param c The component holding the data to be transfered. This
\r
2318 // * argument is provided to enable sharing of TransferHandlers by
\r
2319 // * multiple components.
\r
2320 // * @return This is implemented to return NONE if the component is a
\r
2322 // * since exporting data via user gestures is not allowed. If the text
\r
2324 // * editable, COPY_OR_MOVE is returned, otherwise just COPY is allowed.
\r
2326 // public int getSourceActions(JComponent c) {
\r
2327 // if (c instanceof JPasswordField &&
\r
2328 // c.getClientProperty("JPasswordField.cutCopyAllowed") !=
\r
2329 // Boolean.TRUE) {
\r
2333 // return ((JTextComponent)c).isEditable() ? COPY_OR_MOVE : COPY;
\r
2337 // * Create a Transferable to use as the source for a data transfer.
\r
2339 // * @param comp The component holding the data to be transfered. This
\r
2340 // * argument is provided to enable sharing of TransferHandlers by
\r
2341 // * multiple components.
\r
2342 // * @return The representation of the data to be transfered.
\r
2345 // protected Transferable createTransferable(JComponent comp) {
\r
2346 // exportComp = (JTextComponent)comp;
\r
2347 // shouldRemove = true;
\r
2348 // p0 = exportComp.getSelectionStart();
\r
2349 // p1 = exportComp.getSelectionEnd();
\r
2350 // return (p0 != p1) ? (new TextTransferable(exportComp, p0, p1)) : null;
\r
2354 // * This method is called after data has been exported. This method should
\r
2356 // * the data that was transfered if the action was MOVE.
\r
2358 // * @param source The component that was the source of the data.
\r
2359 // * @param data The data that was transferred or possibly null
\r
2360 // * if the action is <code>NONE</code>.
\r
2361 // * @param action The actual action that was performed.
\r
2363 // protected void exportDone(JComponent source, Transferable data, int action)
\r
2365 // // only remove the text if shouldRemove has not been set to
\r
2366 // // false by importData and only if the action is a move
\r
2367 // if (shouldRemove && action == MOVE) {
\r
2368 // TextTransferable t = (TextTransferable)data;
\r
2369 // t.removeText();
\r
2372 // exportComp = null;
\r
2375 // public boolean importData(TransferSupport support) {
\r
2376 // isDrop = support.isDrop();
\r
2380 // ((JTextComponent)support.getComponent()).getDropMode() == DropMode.INSERT;
\r
2383 // ((JTextComponent.DropLocation)support.getDropLocation()).getBias();
\r
2385 // dropAction = support.getDropAction();
\r
2389 // return super.importData(support);
\r
2391 // isDrop = false;
\r
2392 // modeBetween = false;
\r
2393 // dropBias = null;
\r
2394 // dropAction = MOVE;
\r
2399 // * This method causes a transfer to a component from a clipboard or a
\r
2400 // * DND drop operation. The Transferable represents the data to be
\r
2401 // * imported into the component.
\r
2403 // * @param comp The component to receive the transfer. This
\r
2404 // * argument is provided to enable sharing of TransferHandlers by
\r
2405 // * multiple components.
\r
2406 // * @param t The data to import
\r
2407 // * @return true if the data was inserted into the component, false
\r
2410 // public boolean importData(JComponent comp, Transferable t) {
\r
2411 // JTextComponent c = (JTextComponent)comp;
\r
2413 // int pos = modeBetween
\r
2414 // ? ((JTextComponent.DropLocation)c.getDropLocation()).getIndex()
\r
2415 // : c.getCaretPosition();
\r
2417 // // if we are importing to the same component that we exported from
\r
2418 // // then don't actually do anything if the drop location is inside
\r
2419 // // the drag location and set shouldRemove to false so that exportDone
\r
2420 // // knows not to remove any data
\r
2421 // if (dropAction == MOVE && c == exportComp && pos >= p0 && pos <= p1) {
\r
2422 // shouldRemove = false;
\r
2426 // boolean imported = false;
\r
2427 // DataFlavor importFlavor = getImportFlavor(t.getTransferDataFlavors(), c);
\r
2428 // if (importFlavor != null) {
\r
2430 // boolean useRead = false;
\r
2431 // if (comp instanceof JEditorPane) {
\r
2432 // JEditorPane ep = (JEditorPane)comp;
\r
2433 // if (!ep.getContentType().startsWith("text/plain") &&
\r
2434 // importFlavor.getMimeType().startsWith(ep.getContentType())) {
\r
2435 // useRead = true;
\r
2438 // InputContext ic = c.getInputContext();
\r
2439 // if (ic != null) {
\r
2440 // ic.endComposition();
\r
2442 // Reader r = importFlavor.getReaderForText(t);
\r
2444 // if (modeBetween) {
\r
2445 // Caret caret = c.getCaret();
\r
2446 // if (caret instanceof DefaultCaret) {
\r
2447 // ((DefaultCaret)caret).setDot(pos, dropBias);
\r
2449 // c.setCaretPosition(pos);
\r
2453 // handleReaderImport(r, c, useRead);
\r
2456 // c.requestFocus();
\r
2457 // Caret caret = c.getCaret();
\r
2458 // if (caret instanceof DefaultCaret) {
\r
2459 // int newPos = caret.getDot();
\r
2460 // Position.Bias newBias = ((DefaultCaret)caret).getDotBias();
\r
2462 // ((DefaultCaret)caret).setDot(pos, dropBias);
\r
2463 // ((DefaultCaret)caret).moveDot(newPos, newBias);
\r
2465 // c.select(pos, c.getCaretPosition());
\r
2469 // imported = true;
\r
2470 // } catch (UnsupportedFlavorException ufe) {
\r
2471 // } catch (BadLocationException ble) {
\r
2472 // } catch (IOException ioe) {
\r
2475 // return imported;
\r
2479 // * This method indicates if a component would accept an import of the given
\r
2480 // * set of data flavors prior to actually attempting to import it.
\r
2482 // * @param comp The component to receive the transfer. This
\r
2483 // * argument is provided to enable sharing of TransferHandlers by
\r
2484 // * multiple components.
\r
2485 // * @param flavors The data formats available
\r
2486 // * @return true if the data can be inserted into the component, false
\r
2489 // public boolean canImport(JComponent comp, DataFlavor[] flavors) {
\r
2490 // JTextComponent c = (JTextComponent)comp;
\r
2491 // if (!(c.isEditable() && c.isEnabled())) {
\r
2494 // return (getImportFlavor(flavors, c) != null);
\r
2498 // * A possible implementation of the Transferable interface
\r
2499 // * for text components. For a JEditorPane with a rich set
\r
2500 // * of EditorKit implementations, conversions could be made
\r
2501 // * giving a wider set of formats. This is implemented to
\r
2502 // * offer up only the active content type and text/plain
\r
2503 // * (if that is not the active format) since that can be
\r
2504 // * extracted from other formats.
\r
2506 // static class TextTransferable extends BasicTransferable {
\r
2508 // TextTransferable(JTextComponent c, int start, int end) {
\r
2509 // super(null, null);
\r
2513 // Document doc = c.getDocument();
\r
2516 // p0 = doc.createPosition(start);
\r
2517 // p1 = doc.createPosition(end);
\r
2519 // plainData = c.getSelectedText();
\r
2521 // if (c instanceof JEditorPane) {
\r
2522 // JEditorPane ep = (JEditorPane)c;
\r
2524 // mimeType = ep.getContentType();
\r
2526 // if (mimeType.startsWith("text/plain")) {
\r
2530 // StringWriter sw = new StringWriter(p1.getOffset() - p0.getOffset());
\r
2531 // ep.getEditorKit().write(sw, doc, p0.getOffset(), p1.getOffset() -
\r
2532 // p0.getOffset());
\r
2534 // if (mimeType.startsWith("text/html")) {
\r
2535 // htmlData = sw.toString();
\r
2537 // richText = sw.toString();
\r
2540 // } catch (BadLocationException ble) {
\r
2541 // } catch (IOException ioe) {
\r
2545 // void removeText() {
\r
2546 // if ((p0 != null) && (p1 != null) && (p0.getOffset() != p1.getOffset())) {
\r
2548 // Document doc = c.getDocument();
\r
2549 // doc.remove(p0.getOffset(), p1.getOffset() - p0.getOffset());
\r
2550 // } catch (BadLocationException e) {
\r
2555 // // ---- EditorKit other than plain or HTML text -----------------------
\r
2558 // * If the EditorKit is not for text/plain or text/html, that format
\r
2559 // * is supported through the "richer flavors" part of BasicTransferable.
\r
2561 // protected DataFlavor[] getRicherFlavors() {
\r
2562 // if (richText == null) {
\r
2567 // DataFlavor[] flavors = new DataFlavor[3];
\r
2568 // flavors[0] = new DataFlavor(mimeType + ";class=java.lang.String");
\r
2569 // flavors[1] = new DataFlavor(mimeType + ";class=java.io.Reader");
\r
2570 // flavors[2] = new DataFlavor(mimeType +
\r
2571 // ";class=java.io.InputStream;charset=unicode");
\r
2572 // return flavors;
\r
2573 // } catch (ClassNotFoundException cle) {
\r
2574 // // fall through to unsupported (should not happen)
\r
2581 // * The only richer format supported is the file list flavor
\r
2583 // protected Object getRicherData(DataFlavor flavor) throws
\r
2584 // UnsupportedFlavorException {
\r
2585 // if (richText == null) {
\r
2589 // if (String.class.equals(flavor.getRepresentationClass())) {
\r
2590 // return richText;
\r
2591 // } else if (Reader.class.equals(flavor.getRepresentationClass())) {
\r
2592 // return new StringReader(richText);
\r
2593 // } else if (InputStream.class.equals(flavor.getRepresentationClass())) {
\r
2594 // return new StringBufferInputStream(richText);
\r
2596 // throw new UnsupportedFlavorException(flavor);
\r
2601 // String mimeType;
\r
2602 // String richText;
\r
2603 // JTextComponent c;
\r
2609 // * Creates a new UI.
\r
2611 // public JSTextUI() {
\r
2612 // // painted = false;
\r
2616 // * Creates the object to use for a caret. By default an
\r
2617 // * instance of BasicCaret is created. This method
\r
2618 // * can be redefined to provide something else that implements
\r
2619 // * the InputPosition interface or a subclass of JCaret.
\r
2621 // * @return the caret object
\r
2623 // protected Caret createCaret() {
\r
2624 // return new BasicCaret();
\r
2628 // * Creates the object to use for adding highlights. By default
\r
2629 // * an instance of BasicHighlighter is created. This method
\r
2630 // * can be redefined to provide something else that implements
\r
2631 // * the Highlighter interface or a subclass of DefaultHighlighter.
\r
2633 // * @return the highlighter
\r
2635 // protected Highlighter createHighlighter() {
\r
2636 // return new BasicHighlighter();
\r
2640 // * Fetches the name of the keymap that will be installed/used
\r
2641 // * by default for this UI. This is implemented to create a
\r
2642 // * name based upon the classname. The name is the the name
\r
2643 // * of the class with the package prefix removed.
\r
2645 // * @return the name
\r
2647 // protected String getKeymapName() {
\r
2648 // String nm = getClass().getName();
\r
2649 // int index = nm.lastIndexOf('.');
\r
2650 // if (index >= 0) {
\r
2651 // nm = nm.substring(index+1, nm.length());
\r
2657 // * Creates the keymap to use for the text component, and installs
\r
2658 // * any necessary bindings into it. By default, the keymap is
\r
2659 // * shared between all instances of this type of TextUI. The
\r
2660 // * keymap has the name defined by the getKeymapName method. If the
\r
2661 // * keymap is not found, then DEFAULT_KEYMAP from JTextComponent is used.
\r
2663 // * The set of bindings used to create the keymap is fetched
\r
2664 // * from the UIManager using a key formed by combining the
\r
2665 // * {@link #getPropertyPrefix} method
\r
2666 // * and the string <code>.keyBindings</code>. The type is expected
\r
2667 // * to be <code>JTextComponent.KeyBinding[]</code>.
\r
2669 // * @return the keymap
\r
2670 // * @see #getKeymapName
\r
2671 // * @see jsjavax.swing.text.JTextComponent
\r
2673 // protected Keymap createKeymap() {
\r
2674 // String nm = getKeymapName();
\r
2675 // Keymap map = JTextComponent.getKeymap(nm);
\r
2676 // if (map == null) {
\r
2677 // Keymap parent = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
\r
2678 // map = JTextComponent.addKeymap(nm, parent);
\r
2679 // String prefix = getPropertyPrefix();
\r
2680 // Object o = DefaultLookup.get(editor, this,
\r
2681 // prefix + ".keyBindings");
\r
2682 // if ((o != null) && (o instanceof JTextComponent.KeyBinding[])) {
\r
2683 // JTextComponent.KeyBinding[] bindings = (JTextComponent.KeyBinding[]) o;
\r
2684 // JTextComponent.loadKeymap(map, bindings, getComponent().getActions());
\r
2691 // * This method gets called when a bound property is changed
\r
2692 // * on the associated JTextComponent. This is a hook
\r
2693 // * which UI implementations may change to reflect how the
\r
2694 // * UI displays bound properties of JTextComponent subclasses.
\r
2695 // * This is implemented to do nothing (i.e. the response to
\r
2696 // * properties in JTextComponent itself are handled prior
\r
2697 // * to calling this method).
\r
2699 // * This implementation updates the background of the text
\r
2700 // * component if the editable and/or enabled state changes.
\r
2702 // * @param evt the property change event
\r
2704 // protected void propertyChange(PropertyChangeEvent evt) {
\r
2705 // if (evt.getPropertyName().equals("editable") ||
\r
2706 // evt.getPropertyName().equals("enabled")) {
\r
2708 // updateBackground((JTextComponent)evt.getSource());
\r
2713 // * Updates the background of the text component based on whether the
\r
2714 // * text component is editable and/or enabled.
\r
2716 // * @param c the JTextComponent that needs its background color updated
\r
2718 // private void updateBackground(JTextComponent c) {
\r
2719 // // This is a temporary workaround.
\r
2720 // // This code does not correctly deal with Synth (Synth doesn't use
\r
2721 // // properties like this), nor does it deal with the situation where
\r
2722 // // the developer grabs the color from a JLabel and sets it as
\r
2723 // // the background for a JTextArea in all look and feels. The problem
\r
2724 // // scenario results if the Color obtained for the Label and TextArea
\r
2725 // // is ==, which is the case for the windows look and feel.
\r
2726 // // Until an appropriate solution is found, the code is being
\r
2727 // // reverted to what it was before the original fix.
\r
2728 // if (this instanceof sun.swing.plaf.synth.SynthUI ||
\r
2729 // (c instanceof JTextArea)) {
\r
2732 // Color background = c.getBackground();
\r
2733 // if (background instanceof UIResource) {
\r
2734 // String prefix = getPropertyPrefix();
\r
2736 // Color disabledBG =
\r
2737 // DefaultLookup.getColor(c, this, prefix + ".disabledBackground", null);
\r
2738 // Color inactiveBG =
\r
2739 // DefaultLookup.getColor(c, this, prefix + ".inactiveBackground", null);
\r
2741 // DefaultLookup.getColor(c, this, prefix + ".background", null);
\r
2743 // /* In an ideal situation, the following check would not be necessary
\r
2744 // * and we would replace the color any time the previous color was a
\r
2745 // * UIResouce. However, it turns out that there is existing code that
\r
2746 // * uses the following inadvisable pattern to turn a text area into
\r
2747 // * what appears to be a multi-line label:
\r
2749 // * JLabel label = new JLabel();
\r
2750 // * JTextArea area = new JTextArea();
\r
2751 // * area.setBackground(label.getBackground());
\r
2752 // * area.setEditable(false);
\r
2754 // * JLabel's default background is a UIResource. As such, just
\r
2755 // * checking for UIResource would have us always changing the
\r
2756 // * background away from what the developer wanted.
\r
2758 // * Therefore, for JTextArea/JEditorPane, we'll additionally check
\r
2759 // * that the color we're about to replace matches one that was
\r
2760 // * installed by us from the UIDefaults.
\r
2762 // if ((c instanceof JTextArea || c instanceof JEditorPane)
\r
2763 // && background != disabledBG
\r
2764 // && background != inactiveBG
\r
2765 // && background != bg) {
\r
2770 // Color newColor = null;
\r
2771 // if (!c.isEnabled()) {
\r
2772 // newColor = disabledBG;
\r
2774 // if (newColor == null && !c.isEditable()) {
\r
2775 // newColor = inactiveBG;
\r
2777 // if (newColor == null) {
\r
2780 // if (newColor != null && newColor != background) {
\r
2781 // c.setBackground(newColor);
\r
2787 // * Gets the name used as a key to look up properties through the
\r
2788 // * UIManager. This is used as a prefix to all the standard
\r
2789 // * text properties.
\r
2791 // * @return the name
\r
2793 // protected abstract String getPropertyPrefix();
\r