/* * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package swingjs.plaf; import swingjs.JSToolkit; import swingjs.api.DOMNode; import swingjs.api.JQueryObject; import swingjs.api.JSFunction; import jsjava.awt.Dimension; import jsjava.awt.Insets; import jsjava.awt.LayoutManager; import jsjava.awt.event.ActionEvent; import jsjavax.swing.AbstractAction; import jsjavax.swing.Action; import jsjavax.swing.ActionMap; import jsjavax.swing.InputMap; import jsjavax.swing.JComponent; import jsjavax.swing.SwingUtilities; import jsjavax.swing.UIManager; import jsjavax.swing.plaf.ActionMapUIResource; import jsjavax.swing.plaf.ComponentUI; import jsjavax.swing.plaf.InputMapUIResource; import jsjavax.swing.plaf.TextUI; import jsjavax.swing.plaf.UIResource; import jsjavax.swing.text.Caret; import jsjavax.swing.text.DefaultEditorKit; import jsjavax.swing.text.EditorKit; import jsjavax.swing.text.JTextComponent; import jsjavax.swing.text.TextAction; //import jsjava.awt.KeyboardFocusManager; //import jsjava.awt.datatransfer.DataFlavor; //import jsjava.awt.datatransfer.Transferable; //import jsjava.awt.datatransfer.UnsupportedFlavorException; //import jsjava.awt.im.InputContext; //import jsjava.io.IOException; //import jsjava.io.InputStream; //import jsjava.io.Reader; //import jsjava.io.StringBufferInputStream; //import jsjava.io.StringReader; //import jsjava.io.StringWriter; //import jsjavax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag; /** *

* Basis of a text components look-and-feel. This provides the basic editor view * and controller services that may be useful when creating a look-and-feel for * an extension of JTextComponent. *

* Most state is held in the associated JTextComponent as bound * properties, and the UI installs default values for the various properties. * This default will install something for all of the properties. Typically, a * LAF implementation will do more however. At a minimum, a LAF would generally * install key bindings. *

* This class also provides some concurrency support if the * Document associated with the JTextComponent is a subclass of * AbstractDocument. Access to the View (or View hierarchy) is * serialized between any thread mutating the model and the Swing event thread * (which is expected to render, do model/view coordinate translation, etc). * Any access to the root view should first * acquire a read-lock on the AbstractDocument and release that lock * in a finally block. *

* An important method to define is the {@link #getPropertyPrefix} method which * is used as the basis of the keys used to fetch defaults from the UIManager. * The string should reflect the type of TextUI (eg. TextField, TextArea, etc) * without the particular LAF part of the name (eg Metal, Motif, etc). *

* To build a view of the model, one of the following strategies can be * employed. *

    *
  1. * One strategy is to simply redefine the ViewFactory interface in the UI. By * default, this UI itself acts as the factory for View implementations. This is * useful for simple factories. To do this reimplement the {@link #create} * method. *
  2. * A common strategy for creating more complex types of documents is to have the * EditorKit implementation return a factory. Since the EditorKit ties all of * the pieces necessary to maintain a type of document, the factory is typically * an important part of that and should be produced by the EditorKit * implementation. *
*

* Warning: Serialized objects of this class will not be * compatible with future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running the * same version of Swing. As of 1.4, support for long term storage of all * JavaBeansTM has been added to the * java.beans package. Please see {@link jsjava.beans.XMLEncoder}. * * @author Timothy Prinzing * @author Shannon Hickey (drag and drop) */ public abstract class JSTextUI extends JSComponentUI {// implements {ViewFactory // { @SuppressWarnings("unused") protected void setFocusable() { JQueryObject node = $(focusNode); Object me = this; /** * @j2sNative * * node.focus(function() {me.notifyFocus(true)}); * node.blur(function() {me.notifyFocus(false)}); */ {} } protected String getComponentText() { return currentText = ((JTextComponent) c).getText(); } protected void bindKeys(DOMNode domNode) { JSFunction f = null; JSEventHandler me = this; if (!((JTextComponent) c).isEditable()) return; /** * @j2sNative * * f = function(event) { me.handleJSEvent(me.domNode, 401, event) * } */ { System.out.println(me); } $(domNode).bind("keydown keypress keyup", f); // TODO Auto-generated method stub } /** * Initializes component properties, e.g. font, foreground, background, caret * color, selection color, selected text color, disabled text color, and * border color. The font, foreground, and background properties are only set * if their current value is either null or a UIResource, other properties are * set if the current value is null. * * @see #uninstallDefaults * @see #installUI */ protected void installDefaults() { // String prefix = getPropertyPrefix(); // Font f = editor.getFont(); // if ((f == null) || (f instanceof UIResource)) { // editor.setFont(UIManager.getFont(prefix + ".font")); // } // // Color bg = editor.getBackground(); // if ((bg == null) || (bg instanceof UIResource)) { // editor.setBackground(UIManager.getColor(prefix + ".background")); // } // // Color fg = editor.getForeground(); // if ((fg == null) || (fg instanceof UIResource)) { // editor.setForeground(UIManager.getColor(prefix + ".foreground")); // } // // Color color = editor.getCaretColor(); // if ((color == null) || (color instanceof UIResource)) { // editor.setCaretColor(UIManager.getColor(prefix + ".caretForeground")); // } // // Color s = editor.getSelectionColor(); // if ((s == null) || (s instanceof UIResource)) { // editor.setSelectionColor(UIManager.getColor(prefix + // ".selectionBackground")); // } // // Color sfg = editor.getSelectedTextColor(); // if ((sfg == null) || (sfg instanceof UIResource)) { // editor.setSelectedTextColor(UIManager.getColor(prefix + // ".selectionForeground")); // } // // Color dfg = editor.getDisabledTextColor(); // if ((dfg == null) || (dfg instanceof UIResource)) { // editor.setDisabledTextColor(UIManager.getColor(prefix + // ".inactiveForeground")); // } // // Border b = editor.getBorder(); // if ((b == null) || (b instanceof UIResource)) { // editor.setBorder(UIManager.getBorder(prefix + ".border")); // } // // Insets margin = editor.getMargin(); // if (margin == null || margin instanceof UIResource) { // editor.setMargin(UIManager.getInsets(prefix + ".margin")); // } // // updateCursor(); } private void installDefaults2() { // editor.addMouseListener(dragListener); // editor.addMouseMotionListener(dragListener); // // String prefix = getPropertyPrefix(); Caret caret = editor.getCaret(); if (caret == null || caret instanceof UIResource) { editor.setCaret(new JSCaret()); } // // Highlighter highlighter = editor.getHighlighter(); // if (highlighter == null || highlighter instanceof UIResource) { // editor.setHighlighter(createHighlighter()); // } // // TransferHandler th = editor.getTransferHandler(); // if (th == null || th instanceof UIResource) { // editor.setTransferHandler(getTransferHandler()); // } } /** * called by JmolCore.js * * @return handled */ public boolean handleJSEvent(Object target, int eventType, Object jQueryEvent) { System.out.println("Handling for " + id + " " + eventType + " " + jQueryEvent); return updateHandler.handleJSEvent(this, eventType, jQueryEvent); } /** * Sets the component properties that haven't been explicitly overridden to * null. A property is considered overridden if its current value is not a * UIResource. * * @see #installDefaults * @see #uninstallUI */ protected void uninstallDefaults() { // editor.removeMouseListener(dragListener); // editor.removeMouseMotionListener(dragListener); // if (editor.getCaretColor() instanceof UIResource) { editor.setCaretColor(null); } if (editor.getSelectionColor() instanceof UIResource) { editor.setSelectionColor(null); } if (editor.getDisabledTextColor() instanceof UIResource) { editor.setDisabledTextColor(null); } if (editor.getSelectedTextColor() instanceof UIResource) { editor.setSelectedTextColor(null); } if (editor.getBorder() instanceof UIResource) { editor.setBorder(null); } if (editor.getMargin() instanceof UIResource) { editor.setMargin(null); } // if (editor.getCaret() instanceof UIResource) { // editor.setCaret(null); // } // // if (editor.getHighlighter() instanceof UIResource) { // editor.setHighlighter(null); // } // // if (editor.getTransferHandler() instanceof UIResource) { // editor.setTransferHandler(null); // } // // if (editor.getCursor() instanceof UIResource) { // editor.setCursor(null); // } } protected void installKeyboardActions() { // backward compatibility support... keymaps for the UI // are now installed in the more friendly input map. // editor.setKeymap(createKeymap()); InputMap km = getInputMap(); if (km != null) { SwingUtilities.replaceUIInputMap(editor, JComponent.WHEN_FOCUSED, km); } ActionMap map = getActionMap(); if (map != null) { SwingUtilities.replaceUIActionMap(editor, map); } // updateFocusAcceleratorBinding(false); } /** * Get the InputMap to use for the UI. */ InputMap getInputMap() { InputMap map = new InputMapUIResource(); // InputMap shared = // (InputMap)DefaultLookup.get(editor, this, // getPropertyPrefix() + ".focusInputMap"); // if (shared != null) { // map.setParent(shared); // } return map; } // /** // * Invoked when the focus accelerator changes, this will update the // * key bindings as necessary. // */ // void updateFocusAcceleratorBinding(boolean changed) { // char accelerator = editor.getFocusAccelerator(); // // if (changed || accelerator != '\0') { // InputMap km = SwingUtilities.getUIInputMap // (editor, JComponent.WHEN_IN_FOCUSED_WINDOW); // // if (km == null && accelerator != '\0') { // km = new ComponentInputMapUIResource(editor); // SwingUtilities.replaceUIInputMap(editor, JComponent. // WHEN_IN_FOCUSED_WINDOW, km); // ActionMap am = getActionMap(); // SwingUtilities.replaceUIActionMap(editor, am); // } // if (km != null) { // km.clear(); // if (accelerator != '\0') { // km.put(KeyStroke.getKeyStroke(accelerator, // ActionEvent.ALT_MASK), // "requestFocus"); // } // } // } // } // // // /** // * Invoked when editable property is changed. // * // * removing 'TAB' and 'SHIFT-TAB' from traversalKeysSet in case // * editor is editable // * adding 'TAB' and 'SHIFT-TAB' to traversalKeysSet in case // * editor is non editable // */ // // void updateFocusTraversalKeys() { // /* // * Fix for 4514331 Non-editable JTextArea and similar // * should allow Tab to keyboard - accessibility // */ // EditorKit editorKit = getEditorKit(editor); // if ( editorKit != null // && editorKit instanceof DefaultEditorKit) { // Set storedForwardTraversalKeys = editor. // getFocusTraversalKeys(KeyboardFocusManager. // FORWARD_TRAVERSAL_KEYS); // Set storedBackwardTraversalKeys = editor. // getFocusTraversalKeys(KeyboardFocusManager. // BACKWARD_TRAVERSAL_KEYS); // Set forwardTraversalKeys = // new HashSet(storedForwardTraversalKeys); // Set backwardTraversalKeys = // new HashSet(storedBackwardTraversalKeys); // if (editor.isEditable()) { // forwardTraversalKeys. // remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); // backwardTraversalKeys. // remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, // InputEvent.SHIFT_MASK)); // } else { // forwardTraversalKeys.add(KeyStroke. // getKeyStroke(KeyEvent.VK_TAB, 0)); // backwardTraversalKeys. // add(KeyStroke. // getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK)); // } // LookAndFeel.installProperty(editor, // "focusTraversalKeysForward", // forwardTraversalKeys); // LookAndFeel.installProperty(editor, // "focusTraversalKeysBackward", // backwardTraversalKeys); // } // // } // /** // * As needed updates cursor for the target editor. // */ // private void updateCursor() { // if ((! editor.isCursorSet()) // || editor.getCursor() instanceof UIResource) { // Cursor cursor = (editor.isEditable()) ? textCursor : null; // editor.setCursor(cursor); // } // } // // /** // * Returns the TransferHandler that will be installed if // * their isn't one installed on the JTextComponent. // */ // TransferHandler getTransferHandler() { // return defaultTransferHandler; // } // /** * Fetch an action map to use. */ ActionMap getActionMap() { String mapName = classID + ".actionMap"; ActionMap map = (ActionMap) UIManager.get(mapName); if (map == null) { map = createActionMap(); if (map != null) { UIManager.getLookAndFeelDefaults().put(mapName, map); } } return map; } // ActionMap componentMap = new ActionMapUIResource(); // componentMap.put("requestFocus", new FocusAction()); // /* // * fix for bug 4515750 // * JTextField & non-editable JTextArea bind return key - default btn not // accessible // * // * Wrap the return action so that it is only enabled when the // * component is editable. This allows the default button to be // * processed when the text component has focus and isn't editable. // * // */ // if (getEditorKit(editor) instanceof DefaultEditorKit) { // if (map != null) { // Object obj = map.get(DefaultEditorKit.insertBreakAction); // if (obj != null // && obj instanceof DefaultEditorKit.InsertBreakAction) { // Action action = new TextActionWrapper((TextAction)obj); // componentMap.put(action.getValue(Action.NAME),action); // } // } // } // if (map != null) { // componentMap.setParent(map); // } // return componentMap; // } // /** * Create a default action map. This is basically the set of actions found * exported by the component. */ /** * @return */ ActionMap createActionMap() { ActionMap map = new ActionMapUIResource(); Action[] actions = editor.getActions();//defaultKit.getActions(); // SwingJS was editor.getEditorKit().getActions() // System.out.println("building map for UI: " + getPropertyPrefix()); int n = actions.length; for (int i = 0; i < n; i++) { Action a = actions[i]; map.put(a.getValue(Action.NAME), a); // System.out.println(" " + a.getValue(Action.NAME)); } // map.put(TransferHandler.getCutAction().getValue(Action.NAME), // TransferHandler.getCutAction()); // map.put(TransferHandler.getCopyAction().getValue(Action.NAME), // TransferHandler.getCopyAction()); // map.put(TransferHandler.getPasteAction().getValue(Action.NAME), // TransferHandler.getPasteAction()); return map; } protected void uninstallKeyboardActions() { editor.setKeymap(null); SwingUtilities.replaceUIInputMap(editor, JComponent.WHEN_IN_FOCUSED_WINDOW, null); SwingUtilities.replaceUIActionMap(editor, null); } // /** // * Paints a background for the view. This will only be // * called if isOpaque() on the associated component is // * true. The default is to paint the background color // * of the component. // * // * @param g the graphics context // */ // protected void paintBackground(Graphics g) { // g.setColor(editor.getBackground()); // g.fillRect(0, 0, editor.getWidth(), editor.getHeight()); // } // /** * Fetches the text component associated with this UI implementation. This * will be null until the ui has been installed. * * @return the editor component */ protected final JTextComponent getComponent() { return editor; } // /** // * Flags model changes. // * This is called whenever the model has changed. // * It is implemented to rebuild the view hierarchy // * to represent the default root element of the // * associated model. // */ // protected void modelChanged() { // // create a view hierarchy // ViewFactory f = rootView.getViewFactory(); // Document doc = editor.getDocument(); // Element elem = doc.getDefaultRootElement(); // setView(f.create(elem)); // } // // /** // * Sets the current root of the view hierarchy and calls invalidate(). // * If there were any child components, they will be removed (i.e. // * there are assumed to have come from components embedded in views). // * // * @param v the root view // */ // protected final void setView(View v) { // rootView.setView(v); // painted = false; // editor.revalidate(); // editor.repaint(); // } // // /** // * Paints the interface safely with a guarantee that // * the model won't change from the view of this thread. // * This does the following things, rendering from // * back to front. // *

    // *
  1. // * If the component is marked as opaque, the background // * is painted in the current background color of the // * component. // *
  2. // * The highlights (if any) are painted. // *
  3. // * The view hierarchy is painted. // *
  4. // * The caret is painted. // *
// * // * @param g the graphics context // */ // protected void paintSafely(Graphics g) { // painted = true; // Highlighter highlighter = editor.getHighlighter(); // Caret caret = editor.getCaret(); // // // paint the background // if (editor.isOpaque()) { // paintBackground(g); // } // // // paint the highlights // if (highlighter != null) { // highlighter.paint(g); // } // // // paint the view hierarchy // Rectangle alloc = getVisibleEditorRect(); // if (alloc != null) { // rootView.paint(g, alloc); // } // // // paint the caret // if (caret != null) { // caret.paint(g); // } // // if (dropCaret != null) { // dropCaret.paint(g); // } // } // --- ComponentUI methods -------------------------------------------- TextListener updateHandler; /** * Installs the UI for a component. This does the following things. *
    *
  1. * Set the associated component to opaque (can be changed easily by a subclass * or on JTextComponent directly), which is the most common case. This will * cause the component's background color to be painted. *
  2. * Install the default caret and highlighter into the associated component. *
  3. * Attach to the editor and model. If there is no model, a default one is * created. *
  4. * create the view factory and the view hierarchy used to represent the model. *
* * @param c * the editor component * @see ComponentUI#installUI */ protected void installJSUI() { editor = (JTextComponent) c; updateHandler = new TextListener(this, editor); // install defaults installDefaults(); installDefaults2(); // // This is a workaround as these should not override what synth has // // set them to // if (!(this instanceof sun.swing.plaf.synth.SynthUI)){ // // common case is background painted... this can // // easily be changed by subclasses or from outside // // of the component. // LookAndFeel.installProperty(editor, "opaque", Boolean.TRUE); // LookAndFeel.installProperty(editor, "autoscrolls", Boolean.TRUE); // } // // attach to the model and editor // Document doc = editor.getDocument(); // if (doc == null) { // // no model, create a default one. This will // // fire a notification to the updateHandler // // which takes care of the rest. // editor.setDocument(getEditorKit(editor).createDefaultDocument()); // } else { // // doc.addDocumentListener(updateHandler); // // modelChanged(); // } // install keymap installListeners(editor); installKeyboardActions(); // LayoutManager oldLayout = editor.getLayout(); // if ((oldLayout == null) || (oldLayout instanceof UIResource)) { // // by default, use default LayoutManger implementation that // // will position the components associated with a View object. // editor.setLayout(updateHandler); // } // // updateBackground(editor); } /** * Deinstalls the UI for a component. This removes the listeners, uninstalls * the highlighter, removes views, and nulls out the keymap. * * @param c * the editor component * @see ComponentUI#uninstallUI */ public void uninstallJSUI() { // detach from the model // editor.removePropertyChangeListener(updateHandler); // editor.getDocument().removeDocumentListener(updateHandler); // view part // painted = false; uninstallDefaults(); // rootView.setView(null); c.removeAll(); LayoutManager lm = c.getLayout(); if (lm instanceof UIResource) { c.setLayout(null); } // controller part uninstallKeyboardActions(); uninstallListeners(editor); editor = null; updateHandler = null; } protected void installListeners(JTextComponent b) { TextListener listener = updateHandler; b.addMouseListener(listener); b.addMouseMotionListener(listener); b.addFocusListener(listener); b.addPropertyChangeListener(listener); // SwingJS there won't be a document yet; this is in constructor // b.getDocument().addDocumentListener(listener); } protected void uninstallListeners(JTextComponent b) { TextListener listener = updateHandler; b.removeMouseListener(listener); b.removeMouseMotionListener(listener); b.removeFocusListener(listener); b.removePropertyChangeListener(listener); b.getDocument().removeDocumentListener(listener); } // /** // * Superclass paints background in an uncontrollable way // * (i.e. one might want an image tiled into the background). // * To prevent this from happening twice, this method is // * reimplemented to simply paint. // *

// * NOTE: Superclass is also not thread-safe in // * it's rendering of the background, although that's not // * an issue with the default rendering. // */ // public void update(Graphics g, JComponent c) { // paint(g, c); // } // // /** // * Paints the interface. This is routed to the // * paintSafely method under the guarantee that // * the model won't change from the view of this thread // * while it's rendering (if the associated model is // * derived from AbstractDocument). This enables the // * model to potentially be updated asynchronously. // * // * @param g the graphics context // * @param c the editor component // */ // public final void paint(Graphics g, JComponent c) { // if ((rootView.getViewCount() > 0) && (rootView.getView(0) != null)) { // Document doc = editor.getDocument(); // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { // paintSafely(g); // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } // } // } // /** // * Gets the preferred size for the editor component. If the component // * has been given a size prior to receiving this request, it will // * set the size of the view hierarchy to reflect the size of the component // * before requesting the preferred size of the view hierarchy. This // * allows formatted views to format to the current component size before // * answering the request. Other views don't care about currently formatted // * size and give the same answer either way. // * // * @param c the editor component // * @return the size // */ // public Dimension getPreferredSize(JComponent c) { // Dimension d = c.getSize(); // // Document doc = editor.getDocument(); // // Insets i = c.getInsets(); // // // // if (doc instanceof AbstractDocument) { // // ((AbstractDocument)doc).readLock(); // // } // // try { // // if ((d.width > (i.left + i.right)) && (d.height > (i.top + i.bottom))) { // // rootView.setSize(d.width - i.left - i.right, d.height - i.top - // i.bottom); // // } // // else if (d.width == 0 && d.height == 0) { // // // Probably haven't been layed out yet, force some sort of // // // initial sizing. // // rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); // // } // // d.width = (int) Math.min((long) rootView.getPreferredSpan(View.X_AXIS) + // // (long) i.left + (long) i.right, Integer.MAX_VALUE); // // d.height = (int) Math.min((long) rootView.getPreferredSpan(View.Y_AXIS) // + // // (long) i.top + (long) i.bottom, Integer.MAX_VALUE); // // } finally { // // if (doc instanceof AbstractDocument) { // // ((AbstractDocument)doc).readUnlock(); // // } // // } // return d; // } /** * Gets the minimum size for the editor component. * * @param c * the editor component * @return the size */ public Dimension getMinimumSize(JComponent c) { Dimension d = getPreferredSize();// new Dimension(); // Document doc = editor.getDocument(); Insets i = c.getInsets(); // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { d.width += i.left + i.right; d.height += i.top + i.bottom; // d.width = (int) rootView.getMinimumSpan(View.X_AXIS) + i.left + i.right; // d.height = (int) rootView.getMinimumSpan(View.Y_AXIS) + i.top + i.bottom; // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } return d; } /** * Gets the maximum size for the editor component. * * @param c * the editor component * @return the size */ public Dimension getMaximumSize(JComponent c) { // SwingJS TODO return getMinimumSize(c); // Document doc = editor.getDocument(); // Insets i = c.getInsets(); // Dimension d = new Dimension(); // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { // d.width = (int) Math.min((long) rootView.getMaximumSpan(View.X_AXIS) + // (long) i.left + (long) i.right, Integer.MAX_VALUE); // d.height = (int) Math.min((long) rootView.getMaximumSpan(View.Y_AXIS) + // (long) i.top + (long) i.bottom, Integer.MAX_VALUE); // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } // return d; } // ---- TextUI methods ------------------------------------------- // // /** // * Gets the allocation to give the root View. Due // * to an unfortunate set of historical events this // * method is inappropriately named. The Rectangle // * returned has nothing to do with visibility. // * The component must have a non-zero positive size for // * this translation to be computed. // * // * @return the bounding box for the root view // */ // protected Rectangle getVisibleEditorRect() { // Rectangle alloc = editor.getBounds(); // if ((alloc.width > 0) && (alloc.height > 0)) { // alloc.x = alloc.y = 0; // Insets insets = editor.getInsets(); // alloc.x += insets.left; // alloc.y += insets.top; // alloc.width -= insets.left + insets.right; // alloc.height -= insets.top + insets.bottom; // return alloc; // } // return null; // } // // /** // * Converts the given location in the model to a place in // * the view coordinate system. // * The component must have a non-zero positive size for // * this translation to be computed. // * // * @param tc the text component for which this UI is installed // * @param pos the local location in the model to translate >= 0 // * @return the coordinates as a rectangle, null if the model is not painted // * @exception BadLocationException if the given position does not // * represent a valid location in the associated document // * @see TextUI#modelToView // */ // public Rectangle modelToView(JTextComponent tc, int pos) throws // BadLocationException { // return modelToView(tc, pos, Position.Bias.Forward); // } // // /** // * Converts the given location in the model to a place in // * the view coordinate system. // * The component must have a non-zero positive size for // * this translation to be computed. // * // * @param tc the text component for which this UI is installed // * @param pos the local location in the model to translate >= 0 // * @return the coordinates as a rectangle, null if the model is not painted // * @exception BadLocationException if the given position does not // * represent a valid location in the associated document // * @see TextUI#modelToView // */ // public Rectangle modelToView(JTextComponent tc, int pos, Position.Bias // bias) throws BadLocationException { // Document doc = editor.getDocument(); // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { // Rectangle alloc = getVisibleEditorRect(); // if (alloc != null) { // rootView.setSize(alloc.width, alloc.height); // Shape s = rootView.modelToView(pos, alloc, bias); // if (s != null) { // return s.getBounds(); // } // } // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } // return null; // } // // /** // * Converts the given place in the view coordinate system // * to the nearest representative location in the model. // * The component must have a non-zero positive size for // * this translation to be computed. // * // * @param tc the text component for which this UI is installed // * @param pt the location in the view to translate. This // * should be in the same coordinate system as the mouse events. // * @return the offset from the start of the document >= 0, // * -1 if not painted // * @see TextUI#viewToModel // */ // public int viewToModel(JTextComponent tc, Point pt) { // return viewToModel(tc, pt, discardBias); // } // // /** // * Converts the given place in the view coordinate system // * to the nearest representative location in the model. // * The component must have a non-zero positive size for // * this translation to be computed. // * // * @param tc the text component for which this UI is installed // * @param pt the location in the view to translate. This // * should be in the same coordinate system as the mouse events. // * @return the offset from the start of the document >= 0, // * -1 if the component doesn't yet have a positive size. // * @see TextUI#viewToModel // */ // public int viewToModel(JTextComponent tc, Point pt, // Position.Bias[] biasReturn) { // int offs = -1; // Document doc = editor.getDocument(); // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { // Rectangle alloc = getVisibleEditorRect(); // if (alloc != null) { // rootView.setSize(alloc.width, alloc.height); // offs = rootView.viewToModel(pt.x, pt.y, alloc, biasReturn); // } // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } // return offs; // } // /** // * {@inheritDoc} // */ // public int getNextVisualPositionFrom(JTextComponent t, int pos, // Position.Bias b, int direction, Position.Bias[] biasRet) // throws BadLocationException{ // Document doc = editor.getDocument(); // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { // if (painted) { // Rectangle alloc = getVisibleEditorRect(); // if (alloc != null) { // rootView.setSize(alloc.width, alloc.height); // } // return rootView.getNextVisualPositionFrom(pos, b, alloc, direction, // biasRet); // } // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } // return -1; // } // // /** // * Causes the portion of the view responsible for the // * given part of the model to be repainted. Does nothing if // * the view is not currently painted. // * // * @param tc the text component for which this UI is installed // * @param p0 the beginning of the range >= 0 // * @param p1 the end of the range >= p0 // * @see TextUI#damageRange // */ // public void damageRange(JTextComponent tc, int p0, int p1) { // damageRange(tc, p0, p1, Position.Bias.Forward, Position.Bias.Backward); // } // // /** // * Causes the portion of the view responsible for the // * given part of the model to be repainted. // * // * @param p0 the beginning of the range >= 0 // * @param p1 the end of the range >= p0 // */ // public void damageRange(JTextComponent t, int p0, int p1, // Position.Bias p0Bias, Position.Bias p1Bias) { // if (painted) { // Rectangle alloc = getVisibleEditorRect(); // if (alloc != null) { // Document doc = t.getDocument(); // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { // rootView.setSize(alloc.width, alloc.height); // Shape toDamage = rootView.modelToView(p0, p0Bias, // p1, p1Bias, alloc); // Rectangle rect = (toDamage instanceof Rectangle) ? // (Rectangle)toDamage : toDamage.getBounds(); // editor.repaint(rect.x, rect.y, rect.width, rect.height); // } catch (BadLocationException e) { // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } // } // } // } /** * Fetches the EditorKit for the UI. * * @param tc * the text component for which this UI is installed * @return the editor capabilities * @see TextUI#getEditorKit */ public EditorKit getEditorKit(JTextComponent tc) { return defaultKit; } // /** // * Fetches a View with the allocation of the associated // * text component (i.e. the root of the hierarchy) that // * can be traversed to determine how the model is being // * represented spatially. // *

// * NOTE:The View hierarchy can // * be traversed from the root view, and other things // * can be done as well. Things done in this way cannot // * be protected like simple method calls through the TextUI. // * Therefore, proper operation in the presence of concurrency // * must be arranged by any logic that calls this method! // * // * // * @param tc the text component for which this UI is installed // * @return the view // * @see TextUI#getRootView // */ // public View getRootView(JTextComponent tc) { // return rootView; // } // /** // * Returns the string to be used as the tooltip at the passed in location. // * This forwards the method onto the root View. // * // * @see jsjavax.swing.text.JTextComponent#getToolTipText // * @see jsjavax.swing.text.View#getToolTipText // * @since 1.4 // */ // public String getToolTipText(JTextComponent t, Point pt) { // if (!painted) { // return null; // } // Document doc = editor.getDocument(); // String tt = null; // Rectangle alloc = getVisibleEditorRect(); // // if (alloc != null) { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { // tt = rootView.getToolTipText(pt.x, pt.y, alloc); // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } // } // return tt; // } // // --- ViewFactory methods ------------------------------ // // /** // * Creates a view for an element. // * If a subclass wishes to directly implement the factory // * producing the view(s), it should reimplement this // * method. By default it simply returns null indicating // * it is unable to represent the element. // * // * @param elem the element // * @return the view // */ // public View create(Element elem) { // return null; // } // // /** // * Creates a view for an element. // * If a subclass wishes to directly implement the factory // * producing the view(s), it should reimplement this // * method. By default it simply returns null indicating // * it is unable to represent the part of the element. // * // * @param elem the element // * @param p0 the starting offset >= 0 // * @param p1 the ending offset >= p0 // * @return the view // */ // public View create(Element elem, int p0, int p1) { // return null; // } // // public static class BasicCaret extends DefaultCaret implements UIResource // {} // // public static class BasicHighlighter extends DefaultHighlighter implements // UIResource {} // // static class BasicCursor extends Cursor implements UIResource { // BasicCursor(int type) { // super(type); // } // // BasicCursor(String name) { // super(name); // } // } // // private static BasicCursor textCursor = new // BasicCursor(Cursor.TEXT_CURSOR); // ----- member variables --------------------------------------- private static final EditorKit defaultKit = new DefaultEditorKit(); transient JTextComponent editor; protected boolean editable = true; // transient boolean painted; // transient RootView rootView = new RootView(); // transient UpdateHandler updateHandler = new UpdateHandler(); // private static final TransferHandler defaultTransferHandler = new // TextTransferHandler(); // private final DragListener dragListener = getDragListener(); // private static final Position.Bias[] discardBias = new Position.Bias[1]; // private DefaultCaret dropCaret; // /** // * Root view that acts as a gateway between the component // * and the View hierarchy. // */ // class RootView extends View { // // RootView() { // super(null); // } // // void setView(View v) { // View oldView = view; // view = null; // if (oldView != null) { // // get rid of back reference so that the old // // hierarchy can be garbage collected. // oldView.setParent(null); // } // if (v != null) { // v.setParent(this); // } // view = v; // } // // /** // * Fetches the attributes to use when rendering. At the root // * level there are no attributes. If an attribute is resolved // * up the view hierarchy this is the end of the line. // */ // public AttributeSet getAttributes() { // return null; // } // // /** // * Determines the preferred span for this view along an axis. // * // * @param axis may be either X_AXIS or Y_AXIS // * @return the span the view would like to be rendered into. // * Typically the view is told to render into the span // * that is returned, although there is no guarantee. // * The parent may choose to resize or break the view. // */ // public float getPreferredSpan(int axis) { // if (view != null) { // return view.getPreferredSpan(axis); // } // return 10; // } // // /** // * Determines the minimum span for this view along an axis. // * // * @param axis may be either X_AXIS or Y_AXIS // * @return the span the view would like to be rendered into. // * Typically the view is told to render into the span // * that is returned, although there is no guarantee. // * The parent may choose to resize or break the view. // */ // public float getMinimumSpan(int axis) { // if (view != null) { // return view.getMinimumSpan(axis); // } // return 10; // } // // /** // * Determines the maximum span for this view along an axis. // * // * @param axis may be either X_AXIS or Y_AXIS // * @return the span the view would like to be rendered into. // * Typically the view is told to render into the span // * that is returned, although there is no guarantee. // * The parent may choose to resize or break the view. // */ // public float getMaximumSpan(int axis) { // return Integer.MAX_VALUE; // } // // /** // * Specifies that a preference has changed. // * Child views can call this on the parent to indicate that // * the preference has changed. The root view routes this to // * invalidate on the hosting component. // *

// * This can be called on a different thread from the // * event dispatching thread and is basically unsafe to // * propagate into the component. To make this safe, // * the operation is transferred over to the event dispatching // * thread for completion. It is a design goal that all view // * methods be safe to call without concern for concurrency, // * and this behavior helps make that true. // * // * @param child the child view // * @param width true if the width preference has changed // * @param height true if the height preference has changed // */ // public void preferenceChanged(View child, boolean width, boolean height) { // editor.revalidate(); // } // // /** // * Determines the desired alignment for this view along an axis. // * // * @param axis may be either X_AXIS or Y_AXIS // * @return the desired alignment, where 0.0 indicates the origin // * and 1.0 the full span away from the origin // */ // public float getAlignment(int axis) { // if (view != null) { // return view.getAlignment(axis); // } // return 0; // } // // /** // * Renders the view. // * // * @param g the graphics context // * @param allocation the region to render into // */ // public void paint(Graphics g, Shape allocation) { // if (view != null) { // Rectangle alloc = (allocation instanceof Rectangle) ? // (Rectangle)allocation : allocation.getBounds(); // setSize(alloc.width, alloc.height); // view.paint(g, allocation); // } // } // // /** // * Sets the view parent. // * // * @param parent the parent view // */ // public void setParent(View parent) { // throw new Error("Can't set parent on root view"); // } // // /** // * Returns the number of views in this view. Since // * this view simply wraps the root of the view hierarchy // * it has exactly one child. // * // * @return the number of views // * @see #getView // */ // public int getViewCount() { // return 1; // } // // /** // * Gets the n-th view in this container. // * // * @param n the number of the view to get // * @return the view // */ // public View getView(int n) { // return view; // } // // /** // * Returns the child view index representing the given position in // * the model. This is implemented to return the index of the only // * child. // * // * @param pos the position >= 0 // * @return index of the view representing the given position, or // * -1 if no view represents that position // * @since 1.3 // */ // public int getViewIndex(int pos, Position.Bias b) { // return 0; // } // // /** // * Fetches the allocation for the given child view. // * This enables finding out where various views // * are located, without assuming the views store // * their location. This returns the given allocation // * since this view simply acts as a gateway between // * the view hierarchy and the associated component. // * // * @param index the index of the child // * @param a the allocation to this view. // * @return the allocation to the child // */ // public Shape getChildAllocation(int index, Shape a) { // return a; // } // // /** // * Provides a mapping from the document model coordinate space // * to the coordinate space of the view mapped to it. // * // * @param pos the position to convert // * @param a the allocated region to render into // * @return the bounding box of the given position // */ // public Shape modelToView(int pos, Shape a, Position.Bias b) throws // BadLocationException { // if (view != null) { // return view.modelToView(pos, a, b); // } // return null; // } // // /** // * Provides a mapping from the document model coordinate space // * to the coordinate space of the view mapped to it. // * // * @param p0 the position to convert >= 0 // * @param b0 the bias toward the previous character or the // * next character represented by p0, in case the // * position is a boundary of two views. // * @param p1 the position to convert >= 0 // * @param b1 the bias toward the previous character or the // * next character represented by p1, in case the // * position is a boundary of two views. // * @param a the allocated region to render into // * @return the bounding box of the given position is returned // * @exception BadLocationException if the given position does // * not represent a valid location in the associated document // * @exception IllegalArgumentException for an invalid bias argument // * @see View#viewToModel // */ // public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias // b1, Shape a) throws BadLocationException { // if (view != null) { // return view.modelToView(p0, b0, p1, b1, a); // } // return null; // } // // /** // * Provides a mapping from the view coordinate space to the logical // * coordinate space of the model. // * // * @param x x coordinate of the view location to convert // * @param y y coordinate of the view location to convert // * @param a the allocated region to render into // * @return the location within the model that best represents the // * given point in the view // */ // public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { // if (view != null) { // int retValue = view.viewToModel(x, y, a, bias); // return retValue; // } // return -1; // } // // /** // * Provides a way to determine the next visually represented model // * location that one might place a caret. Some views may not be visible, // * they might not be in the same order found in the model, or they just // * might not allow access to some of the locations in the model. // * // * @param pos the position to convert >= 0 // * @param a the allocated region to render into // * @param direction the direction from the current position that can // * be thought of as the arrow keys typically found on a keyboard. // * This may be SwingConstants.WEST, SwingConstants.EAST, // * SwingConstants.NORTH, or SwingConstants.SOUTH. // * @return the location within the model that best represents the next // * location visual position. // * @exception BadLocationException // * @exception IllegalArgumentException for an invalid direction // */ // public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, // int direction, // Position.Bias[] biasRet) // throws BadLocationException { // if( view != null ) { // int nextPos = view.getNextVisualPositionFrom(pos, b, a, // direction, biasRet); // if(nextPos != -1) { // pos = nextPos; // } // else { // biasRet[0] = b; // } // } // return pos; // } // // /** // * Gives notification that something was inserted into the document // * in a location that this view is responsible for. // * // * @param e the change information from the associated document // * @param a the current allocation of the view // * @param f the factory to use to rebuild if the view has children // */ // public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) { // if (view != null) { // view.insertUpdate(e, a, f); // } // } // // /** // * Gives notification that something was removed from the document // * in a location that this view is responsible for. // * // * @param e the change information from the associated document // * @param a the current allocation of the view // * @param f the factory to use to rebuild if the view has children // */ // public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { // if (view != null) { // view.removeUpdate(e, a, f); // } // } // // /** // * Gives notification from the document that attributes were changed // * in a location that this view is responsible for. // * // * @param e the change information from the associated document // * @param a the current allocation of the view // * @param f the factory to use to rebuild if the view has children // */ // public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { // if (view != null) { // view.changedUpdate(e, a, f); // } // } // // /** // * Returns the document model underlying the view. // * // * @return the model // */ // public Document getDocument() { // return editor.getDocument(); // } // // /** // * Returns the starting offset into the model for this view. // * // * @return the starting offset // */ // public int getStartOffset() { // if (view != null) { // return view.getStartOffset(); // } // return getElement().getStartOffset(); // } // // /** // * Returns the ending offset into the model for this view. // * // * @return the ending offset // */ // public int getEndOffset() { // if (view != null) { // return view.getEndOffset(); // } // return getElement().getEndOffset(); // } // // /** // * Gets the element that this view is mapped to. // * // * @return the view // */ // public Element getElement() { // if (view != null) { // return view.getElement(); // } // return editor.getDocument().getDefaultRootElement(); // } // // /** // * Breaks this view on the given axis at the given length. // * // * @param axis may be either X_AXIS or Y_AXIS // * @param len specifies where a break is desired in the span // * @param the current allocation of the view // * @return the fragment of the view that represents the given span // * if the view can be broken, otherwise null // */ // public View breakView(int axis, float len, Shape a) { // throw new Error("Can't break root view"); // } // // /** // * Determines the resizability of the view along the // * given axis. A value of 0 or less is not resizable. // * // * @param axis may be either X_AXIS or Y_AXIS // * @return the weight // */ // public int getResizeWeight(int axis) { // if (view != null) { // return view.getResizeWeight(axis); // } // return 0; // } // // /** // * Sets the view size. // * // * @param width the width // * @param height the height // */ // public void setSize(float width, float height) { // if (view != null) { // view.setSize(width, height); // } // } // // /** // * Fetches the container hosting the view. This is useful for // * things like scheduling a repaint, finding out the host // * components font, etc. The default implementation // * of this is to forward the query to the parent view. // * // * @return the container // */ // public Container getContainer() { // return editor; // } // // /** // * Fetches the factory to be used for building the // * various view fragments that make up the view that // * represents the model. This is what determines // * how the model will be represented. This is implemented // * to fetch the factory provided by the associated // * EditorKit unless that is null, in which case this // * simply returns the BasicTextUI itself which allows // * subclasses to implement a simple factory directly without // * creating extra objects. // * // * @return the factory // */ // public ViewFactory getViewFactory() { // EditorKit kit = getEditorKit(editor); // ViewFactory f = kit.getViewFactory(); // if (f != null) { // return f; // } // return BasicTextUI.this; // } // // private View view; // // } // /** // * Handles updates from various places. If the model is changed, // * this class unregisters as a listener to the old model and // * registers with the new model. If the document model changes, // * the change is forwarded to the root view. If the focus // * accelerator changes, a new keystroke is registered to request // * focus. // */ // class UpdateHandler implements PropertyChangeListener, DocumentListener, // LayoutManager2, UIResource { // // // --- PropertyChangeListener methods ----------------------- // // /** // * This method gets called when a bound property is changed. // * We are looking for document changes on the editor. // */ // public final void propertyChange(PropertyChangeEvent evt) { // Object oldValue = evt.getOldValue(); // Object newValue = evt.getNewValue(); // String propertyName = evt.getPropertyName(); // if ((oldValue instanceof Document) || (newValue instanceof Document)) { // if (oldValue != null) { // ((Document)oldValue).removeDocumentListener(this); // i18nView = false; // } // if (newValue != null) { // ((Document)newValue).addDocumentListener(this); // if ("document" == propertyName) { // setView(null); // BasicTextUI.this.propertyChange(evt); // modelChanged(); // return; // } // } // modelChanged(); // } // if ("focusAccelerator" == propertyName) { // updateFocusAcceleratorBinding(true); // } else if ("componentOrientation" == propertyName) { // // Changes in ComponentOrientation require the views to be // // rebuilt. // modelChanged(); // } else if ("font" == propertyName) { // modelChanged(); // } else if ("dropLocation" == propertyName) { // dropIndexChanged(); // } else if ("editable" == propertyName) { // updateCursor(); // modelChanged(); // } // BasicTextUI.this.propertyChange(evt); // } // // private void dropIndexChanged() { // if (editor.getDropMode() == DropMode.USE_SELECTION) { // return; // } // // JTextComponent.DropLocation dropLocation = editor.getDropLocation(); // // if (dropLocation == null) { // if (dropCaret != null) { // dropCaret.deinstall(editor); // editor.repaint(dropCaret); // dropCaret = null; // } // } else { // if (dropCaret == null) { // dropCaret = new BasicCaret(); // dropCaret.install(editor); // dropCaret.setVisible(true); // } // // dropCaret.setDot(dropLocation.getIndex(), // dropLocation.getBias()); // } // } // // // --- DocumentListener methods ----------------------- // // /** // * The insert notification. Gets sent to the root of the view structure // * that represents the portion of the model being represented by the // * editor. The factory is added as an argument to the update so that // * the views can update themselves in a dynamic (not hardcoded) way. // * // * @param e The change notification from the currently associated // * document. // * @see DocumentListener#insertUpdate // */ // public final void insertUpdate(DocumentEvent e) { // Document doc = e.getDocument(); // Object o = doc.getProperty("i18n"); // if (o instanceof Boolean) { // Boolean i18nFlag = (Boolean) o; // if (i18nFlag.booleanValue() != i18nView) { // // i18n flag changed, rebuild the view // i18nView = i18nFlag.booleanValue(); // modelChanged(); // return; // } // } // // // normal insert update // Rectangle alloc = (painted) ? getVisibleEditorRect() : null; // rootView.insertUpdate(e, alloc, rootView.getViewFactory()); // } // // /** // * The remove notification. Gets sent to the root of the view structure // * that represents the portion of the model being represented by the // * editor. The factory is added as an argument to the update so that // * the views can update themselves in a dynamic (not hardcoded) way. // * // * @param e The change notification from the currently associated // * document. // * @see DocumentListener#removeUpdate // */ // public final void removeUpdate(DocumentEvent e) { // Rectangle alloc = (painted) ? getVisibleEditorRect() : null; // rootView.removeUpdate(e, alloc, rootView.getViewFactory()); // } // // /** // * The change notification. Gets sent to the root of the view structure // * that represents the portion of the model being represented by the // * editor. The factory is added as an argument to the update so that // * the views can update themselves in a dynamic (not hardcoded) way. // * // * @param e The change notification from the currently associated // * document. // * @see DocumentListener#changeUpdate // */ // public final void changedUpdate(DocumentEvent e) { // Rectangle alloc = (painted) ? getVisibleEditorRect() : null; // rootView.changedUpdate(e, alloc, rootView.getViewFactory()); // } // // // --- LayoutManager2 methods -------------------------------- // // /** // * Adds the specified component with the specified name to // * the layout. // * @param name the component name // * @param comp the component to be added // */ // public void addLayoutComponent(String name, Component comp) { // // not supported // } // // /** // * Removes the specified component from the layout. // * @param comp the component to be removed // */ // public void removeLayoutComponent(Component comp) { // if (constraints != null) { // // remove the constraint record // constraints.remove(comp); // } // } // // /** // * Calculates the preferred size dimensions for the specified // * panel given the components in the specified parent container. // * @param parent the component to be laid out // * // * @see #minimumLayoutSize // */ // public Dimension preferredLayoutSize(Container parent) { // // should not be called (JComponent uses UI instead) // return null; // } // // /** // * Calculates the minimum size dimensions for the specified // * panel given the components in the specified parent container. // * @param parent the component to be laid out // * @see #preferredLayoutSize // */ // public Dimension minimumLayoutSize(Container parent) { // // should not be called (JComponent uses UI instead) // return null; // } // // /** // * Lays out the container in the specified panel. This is // * implemented to position all components that were added // * with a View object as a constraint. The current allocation // * of the associated View is used as the location of the // * component. // *

// * A read-lock is acquired on the document to prevent the // * view tree from being modified while the layout process // * is active. // * // * @param parent the component which needs to be laid out // */ // public void layoutContainer(Container parent) { // if ((constraints != null) && (! constraints.isEmpty())) { // Rectangle alloc = getVisibleEditorRect(); // if (alloc != null) { // Document doc = editor.getDocument(); // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readLock(); // } // try { // rootView.setSize(alloc.width, alloc.height); // Enumeration components = constraints.keys(); // while (components.hasMoreElements()) { // Component comp = (Component) components.nextElement(); // View v = (View) constraints.get(comp); // Shape ca = calculateViewPosition(alloc, v); // if (ca != null) { // Rectangle compAlloc = (ca instanceof Rectangle) ? // (Rectangle) ca : ca.getBounds(); // comp.setBounds(compAlloc); // } // } // } finally { // if (doc instanceof AbstractDocument) { // ((AbstractDocument)doc).readUnlock(); // } // } // } // } // } // // /** // * Find the Shape representing the given view. // */ // Shape calculateViewPosition(Shape alloc, View v) { // int pos = v.getStartOffset(); // View child = null; // for (View parent = rootView; (parent != null) && (parent != v); parent = // child) { // int index = parent.getViewIndex(pos, Position.Bias.Forward); // alloc = parent.getChildAllocation(index, alloc); // child = parent.getView(index); // } // return (child != null) ? alloc : null; // } // // /** // * Adds the specified component to the layout, using the specified // * constraint object. We only store those components that were added // * with a constraint that is of type View. // * // * @param comp the component to be added // * @param constraint where/how the component is added to the layout. // */ // public void addLayoutComponent(Component comp, Object constraint) { // if (constraint instanceof View) { // if (constraints == null) { // constraints = new Hashtable(7); // } // constraints.put(comp, constraint); // } // } // // /** // * Returns the maximum size of this component. // * @see jsjava.awt.Component#getMinimumSize() // * @see jsjava.awt.Component#getPreferredSize() // * @see LayoutManager // */ // public Dimension maximumLayoutSize(Container target) { // // should not be called (JComponent uses UI instead) // return null; // } // // /** // * Returns the alignment along the x axis. This specifies how // * the component would like to be aligned relative to other // * components. The value should be a number between 0 and 1 // * where 0 represents alignment along the origin, 1 is aligned // * the furthest away from the origin, 0.5 is centered, etc. // */ // public float getLayoutAlignmentX(Container target) { // return 0.5f; // } // // /** // * Returns the alignment along the y axis. This specifies how // * the component would like to be aligned relative to other // * components. The value should be a number between 0 and 1 // * where 0 represents alignment along the origin, 1 is aligned // * the furthest away from the origin, 0.5 is centered, etc. // */ // public float getLayoutAlignmentY(Container target) { // return 0.5f; // } // // /** // * Invalidates the layout, indicating that if the layout manager // * has cached information it should be discarded. // */ // public void invalidateLayout(Container target) { // } // // /** // * The "layout constraints" for the LayoutManager2 implementation. // * These are View objects for those components that are represented // * by a View in the View tree. // */ // private Hashtable constraints; // // private boolean i18nView = false; // } /** * Wrapper for text actions to return isEnabled false in case editor is non * editable */ class TextActionWrapper extends TextAction { public TextActionWrapper(TextAction action) { super((String) action.getValue(Action.NAME)); this.action = action; } /** * The operation to perform when this action is triggered. * * @param e * the action event */ public void actionPerformed(ActionEvent e) { action.actionPerformed(e); } public boolean isEnabled() { return (editor == null || editor.isEditable()) ? action.isEnabled() : false; } TextAction action = null; } /** * Registered in the ActionMap. */ class FocusAction extends AbstractAction { public void actionPerformed(ActionEvent e) { editor.requestFocus(); } public boolean isEnabled() { return editor.isEditable(); } } boolean handleEnter(int eventType) { return false; } String bgcolor0; public void setEditable(boolean editable) { this.editable = editable; if (domNode == null) return; if (c.isBackgroundSet()) bgcolor0 = JSToolkit.getCSSColor(c.getBackground()); if (editable) { domNode.removeAttribute("readOnly"); if (bgcolor0 != null) DOMNode.setStyles(domNode, "background-color", bgcolor0); } else { DOMNode.setAttr(domNode, "readOnly", "true"); if (c.isBackgroundSet()) { bgcolor0 = JSToolkit.getCSSColor(c.getBackground()); } else { if (bgcolor0 == null) bgcolor0 = domNode.getStyle("background-color"); } DOMNode.setStyles(domNode, "background-color", "rgba(0,0,0,0)"); } } // private static DragListener getDragListener() { // synchronized(DragListener.class) { // DragListener listener = // (DragListener)AppContext.getAppContext(). // get(DragListener.class); // // if (listener == null) { // listener = new DragListener(); // AppContext.getAppContext().put(DragListener.class, listener); // } // // return listener; // } // } // // /** // * Listens for mouse events for the purposes of detecting drag gestures. // * BasicTextUI will maintain one of these per AppContext. // */ // static class DragListener extends MouseInputAdapter // implements BeforeDrag { // // private boolean dragStarted; // // public void dragStarting(MouseEvent me) { // dragStarted = true; // } // // public void mousePressed(MouseEvent e) { // JTextComponent c = (JTextComponent)e.getSource(); // if (c.getDragEnabled()) { // dragStarted = false; // if (isDragPossible(e) && DragRecognitionSupport.mousePressed(e)) { // e.consume(); // } // } // } // // public void mouseReleased(MouseEvent e) { // JTextComponent c = (JTextComponent)e.getSource(); // if (c.getDragEnabled()) { // if (dragStarted) { // e.consume(); // } // // DragRecognitionSupport.mouseReleased(e); // } // } // // public void mouseDragged(MouseEvent e) { // JTextComponent c = (JTextComponent)e.getSource(); // if (c.getDragEnabled()) { // if (dragStarted || DragRecognitionSupport.mouseDragged(e, this)) { // e.consume(); // } // } // } // // /** // * Determines if the following are true: // *

// */ // protected boolean isDragPossible(MouseEvent e) { // JTextComponent c = (JTextComponent)e.getSource(); // if (c.isEnabled()) { // Caret caret = c.getCaret(); // int dot = caret.getDot(); // int mark = caret.getMark(); // if (dot != mark) { // Point p = new Point(e.getX(), e.getY()); // int pos = c.viewToModel(p); // // int p0 = Math.min(dot, mark); // int p1 = Math.max(dot, mark); // if ((pos >= p0) && (pos < p1)) { // return true; // } // } // } // return false; // } // } // static class TextTransferHandler extends TransferHandler implements // UIResource { // // private JTextComponent exportComp; // private boolean shouldRemove; // private int p0; // private int p1; // // /** // * Whether or not this is a drop using // * DropMode.INSERT. // */ // private boolean modeBetween = false; // // /** // * Whether or not this is a drop. // */ // private boolean isDrop = false; // // /** // * The drop action. // */ // private int dropAction = MOVE; // // /** // * The drop bias. // */ // private Position.Bias dropBias; // // /** // * Try to find a flavor that can be used to import a Transferable. // * The set of usable flavors are tried in the following order: // *
    // *
  1. First, an attempt is made to find a flavor matching the content type // * of the EditorKit for the component. // *
  2. Second, an attempt to find a text/plain flavor is made. // *
  3. Third, an attempt to find a flavor representing a String reference // * in the same VM is made. // *
  4. Lastly, DataFlavor.stringFlavor is searched for. // *
// */ // protected DataFlavor getImportFlavor(DataFlavor[] flavors, JTextComponent // c) { // DataFlavor plainFlavor = null; // DataFlavor refFlavor = null; // DataFlavor stringFlavor = null; // // if (c instanceof JEditorPane) { // for (int i = 0; i < flavors.length; i++) { // String mime = flavors[i].getMimeType(); // if (mime.startsWith(((JEditorPane)c).getEditorKit().getContentType())) { // return flavors[i]; // } else if (plainFlavor == null && mime.startsWith("text/plain")) { // plainFlavor = flavors[i]; // } else if (refFlavor == null && // mime.startsWith("application/x-java-jvm-local-objectref") // && flavors[i].getRepresentationClass() == jsjava.lang.String.class) { // refFlavor = flavors[i]; // } else if (stringFlavor == null && // flavors[i].equals(DataFlavor.stringFlavor)) { // stringFlavor = flavors[i]; // } // } // if (plainFlavor != null) { // return plainFlavor; // } else if (refFlavor != null) { // return refFlavor; // } else if (stringFlavor != null) { // return stringFlavor; // } // return null; // } // // // for (int i = 0; i < flavors.length; i++) { // String mime = flavors[i].getMimeType(); // if (mime.startsWith("text/plain")) { // return flavors[i]; // } else if (refFlavor == null && // mime.startsWith("application/x-java-jvm-local-objectref") // && flavors[i].getRepresentationClass() == jsjava.lang.String.class) { // refFlavor = flavors[i]; // } else if (stringFlavor == null && // flavors[i].equals(DataFlavor.stringFlavor)) { // stringFlavor = flavors[i]; // } // } // if (refFlavor != null) { // return refFlavor; // } else if (stringFlavor != null) { // return stringFlavor; // } // return null; // } // // /** // * Import the given stream data into the text component. // */ // protected void handleReaderImport(Reader in, JTextComponent c, boolean // useRead) // throws BadLocationException, IOException { // if (useRead) { // int startPosition = c.getSelectionStart(); // int endPosition = c.getSelectionEnd(); // int length = endPosition - startPosition; // EditorKit kit = c.getUI().getEditorKit(c); // Document doc = c.getDocument(); // if (length > 0) { // doc.remove(startPosition, length); // } // kit.read(in, doc, startPosition); // } else { // char[] buff = new char[1024]; // int nch; // boolean lastWasCR = false; // int last; // StringBuffer sbuff = null; // // // Read in a block at a time, mapping \r\n to \n, as well as single // // \r to \n. // while ((nch = in.read(buff, 0, buff.length)) != -1) { // if (sbuff == null) { // sbuff = new StringBuffer(nch); // } // last = 0; // for(int counter = 0; counter < nch; counter++) { // switch(buff[counter]) { // case '\r': // if (lastWasCR) { // if (counter == 0) { // sbuff.append('\n'); // } else { // buff[counter - 1] = '\n'; // } // } else { // lastWasCR = true; // } // break; // case '\n': // if (lastWasCR) { // if (counter > (last + 1)) { // sbuff.append(buff, last, counter - last - 1); // } // // else nothing to do, can skip \r, next write will // // write \n // lastWasCR = false; // last = counter; // } // break; // default: // if (lastWasCR) { // if (counter == 0) { // sbuff.append('\n'); // } else { // buff[counter - 1] = '\n'; // } // lastWasCR = false; // } // break; // } // } // if (last < nch) { // if (lastWasCR) { // if (last < (nch - 1)) { // sbuff.append(buff, last, nch - last - 1); // } // } else { // sbuff.append(buff, last, nch - last); // } // } // } // if (lastWasCR) { // sbuff.append('\n'); // } // c.replaceSelection(sbuff != null ? sbuff.toString() : ""); // } // } // // // --- TransferHandler methods ------------------------------------ // // /** // * This is the type of transfer actions supported by the source. Some models // are // * not mutable, so a transfer operation of COPY only should // * be advertised in that case. // * // * @param c The component holding the data to be transfered. This // * argument is provided to enable sharing of TransferHandlers by // * multiple components. // * @return This is implemented to return NONE if the component is a // JPasswordField // * since exporting data via user gestures is not allowed. If the text // component is // * editable, COPY_OR_MOVE is returned, otherwise just COPY is allowed. // */ // public int getSourceActions(JComponent c) { // if (c instanceof JPasswordField && // c.getClientProperty("JPasswordField.cutCopyAllowed") != // Boolean.TRUE) { // return NONE; // } // // return ((JTextComponent)c).isEditable() ? COPY_OR_MOVE : COPY; // } // // /** // * Create a Transferable to use as the source for a data transfer. // * // * @param comp The component holding the data to be transfered. This // * argument is provided to enable sharing of TransferHandlers by // * multiple components. // * @return The representation of the data to be transfered. // * // */ // protected Transferable createTransferable(JComponent comp) { // exportComp = (JTextComponent)comp; // shouldRemove = true; // p0 = exportComp.getSelectionStart(); // p1 = exportComp.getSelectionEnd(); // return (p0 != p1) ? (new TextTransferable(exportComp, p0, p1)) : null; // } // // /** // * This method is called after data has been exported. This method should // remove // * the data that was transfered if the action was MOVE. // * // * @param source The component that was the source of the data. // * @param data The data that was transferred or possibly null // * if the action is NONE. // * @param action The actual action that was performed. // */ // protected void exportDone(JComponent source, Transferable data, int action) // { // // only remove the text if shouldRemove has not been set to // // false by importData and only if the action is a move // if (shouldRemove && action == MOVE) { // TextTransferable t = (TextTransferable)data; // t.removeText(); // } // // exportComp = null; // } // // public boolean importData(TransferSupport support) { // isDrop = support.isDrop(); // // if (isDrop) { // modeBetween = // ((JTextComponent)support.getComponent()).getDropMode() == DropMode.INSERT; // // dropBias = // ((JTextComponent.DropLocation)support.getDropLocation()).getBias(); // // dropAction = support.getDropAction(); // } // // try { // return super.importData(support); // } finally { // isDrop = false; // modeBetween = false; // dropBias = null; // dropAction = MOVE; // } // } // // /** // * This method causes a transfer to a component from a clipboard or a // * DND drop operation. The Transferable represents the data to be // * imported into the component. // * // * @param comp The component to receive the transfer. This // * argument is provided to enable sharing of TransferHandlers by // * multiple components. // * @param t The data to import // * @return true if the data was inserted into the component, false // otherwise. // */ // public boolean importData(JComponent comp, Transferable t) { // JTextComponent c = (JTextComponent)comp; // // int pos = modeBetween // ? ((JTextComponent.DropLocation)c.getDropLocation()).getIndex() // : c.getCaretPosition(); // // // if we are importing to the same component that we exported from // // then don't actually do anything if the drop location is inside // // the drag location and set shouldRemove to false so that exportDone // // knows not to remove any data // if (dropAction == MOVE && c == exportComp && pos >= p0 && pos <= p1) { // shouldRemove = false; // return true; // } // // boolean imported = false; // DataFlavor importFlavor = getImportFlavor(t.getTransferDataFlavors(), c); // if (importFlavor != null) { // try { // boolean useRead = false; // if (comp instanceof JEditorPane) { // JEditorPane ep = (JEditorPane)comp; // if (!ep.getContentType().startsWith("text/plain") && // importFlavor.getMimeType().startsWith(ep.getContentType())) { // useRead = true; // } // } // InputContext ic = c.getInputContext(); // if (ic != null) { // ic.endComposition(); // } // Reader r = importFlavor.getReaderForText(t); // // if (modeBetween) { // Caret caret = c.getCaret(); // if (caret instanceof DefaultCaret) { // ((DefaultCaret)caret).setDot(pos, dropBias); // } else { // c.setCaretPosition(pos); // } // } // // handleReaderImport(r, c, useRead); // // if (isDrop) { // c.requestFocus(); // Caret caret = c.getCaret(); // if (caret instanceof DefaultCaret) { // int newPos = caret.getDot(); // Position.Bias newBias = ((DefaultCaret)caret).getDotBias(); // // ((DefaultCaret)caret).setDot(pos, dropBias); // ((DefaultCaret)caret).moveDot(newPos, newBias); // } else { // c.select(pos, c.getCaretPosition()); // } // } // // imported = true; // } catch (UnsupportedFlavorException ufe) { // } catch (BadLocationException ble) { // } catch (IOException ioe) { // } // } // return imported; // } // // /** // * This method indicates if a component would accept an import of the given // * set of data flavors prior to actually attempting to import it. // * // * @param comp The component to receive the transfer. This // * argument is provided to enable sharing of TransferHandlers by // * multiple components. // * @param flavors The data formats available // * @return true if the data can be inserted into the component, false // otherwise. // */ // public boolean canImport(JComponent comp, DataFlavor[] flavors) { // JTextComponent c = (JTextComponent)comp; // if (!(c.isEditable() && c.isEnabled())) { // return false; // } // return (getImportFlavor(flavors, c) != null); // } // // /** // * A possible implementation of the Transferable interface // * for text components. For a JEditorPane with a rich set // * of EditorKit implementations, conversions could be made // * giving a wider set of formats. This is implemented to // * offer up only the active content type and text/plain // * (if that is not the active format) since that can be // * extracted from other formats. // */ // static class TextTransferable extends BasicTransferable { // // TextTransferable(JTextComponent c, int start, int end) { // super(null, null); // // this.c = c; // // Document doc = c.getDocument(); // // try { // p0 = doc.createPosition(start); // p1 = doc.createPosition(end); // // plainData = c.getSelectedText(); // // if (c instanceof JEditorPane) { // JEditorPane ep = (JEditorPane)c; // // mimeType = ep.getContentType(); // // if (mimeType.startsWith("text/plain")) { // return; // } // // StringWriter sw = new StringWriter(p1.getOffset() - p0.getOffset()); // ep.getEditorKit().write(sw, doc, p0.getOffset(), p1.getOffset() - // p0.getOffset()); // // if (mimeType.startsWith("text/html")) { // htmlData = sw.toString(); // } else { // richText = sw.toString(); // } // } // } catch (BadLocationException ble) { // } catch (IOException ioe) { // } // } // // void removeText() { // if ((p0 != null) && (p1 != null) && (p0.getOffset() != p1.getOffset())) { // try { // Document doc = c.getDocument(); // doc.remove(p0.getOffset(), p1.getOffset() - p0.getOffset()); // } catch (BadLocationException e) { // } // } // } // // // ---- EditorKit other than plain or HTML text ----------------------- // // /** // * If the EditorKit is not for text/plain or text/html, that format // * is supported through the "richer flavors" part of BasicTransferable. // */ // protected DataFlavor[] getRicherFlavors() { // if (richText == null) { // return null; // } // // try { // DataFlavor[] flavors = new DataFlavor[3]; // flavors[0] = new DataFlavor(mimeType + ";class=java.lang.String"); // flavors[1] = new DataFlavor(mimeType + ";class=java.io.Reader"); // flavors[2] = new DataFlavor(mimeType + // ";class=java.io.InputStream;charset=unicode"); // return flavors; // } catch (ClassNotFoundException cle) { // // fall through to unsupported (should not happen) // } // // return null; // } // // /** // * The only richer format supported is the file list flavor // */ // protected Object getRicherData(DataFlavor flavor) throws // UnsupportedFlavorException { // if (richText == null) { // return null; // } // // if (String.class.equals(flavor.getRepresentationClass())) { // return richText; // } else if (Reader.class.equals(flavor.getRepresentationClass())) { // return new StringReader(richText); // } else if (InputStream.class.equals(flavor.getRepresentationClass())) { // return new StringBufferInputStream(richText); // } // throw new UnsupportedFlavorException(flavor); // } // // Position p0; // Position p1; // String mimeType; // String richText; // JTextComponent c; // } // // } // /** // * Creates a new UI. // */ // public JSTextUI() { // // painted = false; // } // // /** // * Creates the object to use for a caret. By default an // * instance of BasicCaret is created. This method // * can be redefined to provide something else that implements // * the InputPosition interface or a subclass of JCaret. // * // * @return the caret object // */ // protected Caret createCaret() { // return new BasicCaret(); // } // // /** // * Creates the object to use for adding highlights. By default // * an instance of BasicHighlighter is created. This method // * can be redefined to provide something else that implements // * the Highlighter interface or a subclass of DefaultHighlighter. // * // * @return the highlighter // */ // protected Highlighter createHighlighter() { // return new BasicHighlighter(); // } // // /** // * Fetches the name of the keymap that will be installed/used // * by default for this UI. This is implemented to create a // * name based upon the classname. The name is the the name // * of the class with the package prefix removed. // * // * @return the name // */ // protected String getKeymapName() { // String nm = getClass().getName(); // int index = nm.lastIndexOf('.'); // if (index >= 0) { // nm = nm.substring(index+1, nm.length()); // } // return nm; // } // // /** // * Creates the keymap to use for the text component, and installs // * any necessary bindings into it. By default, the keymap is // * shared between all instances of this type of TextUI. The // * keymap has the name defined by the getKeymapName method. If the // * keymap is not found, then DEFAULT_KEYMAP from JTextComponent is used. // *

// * The set of bindings used to create the keymap is fetched // * from the UIManager using a key formed by combining the // * {@link #getPropertyPrefix} method // * and the string .keyBindings. The type is expected // * to be JTextComponent.KeyBinding[]. // * // * @return the keymap // * @see #getKeymapName // * @see jsjavax.swing.text.JTextComponent // */ // protected Keymap createKeymap() { // String nm = getKeymapName(); // Keymap map = JTextComponent.getKeymap(nm); // if (map == null) { // Keymap parent = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP); // map = JTextComponent.addKeymap(nm, parent); // String prefix = getPropertyPrefix(); // Object o = DefaultLookup.get(editor, this, // prefix + ".keyBindings"); // if ((o != null) && (o instanceof JTextComponent.KeyBinding[])) { // JTextComponent.KeyBinding[] bindings = (JTextComponent.KeyBinding[]) o; // JTextComponent.loadKeymap(map, bindings, getComponent().getActions()); // } // } // return map; // } // // /** // * This method gets called when a bound property is changed // * on the associated JTextComponent. This is a hook // * which UI implementations may change to reflect how the // * UI displays bound properties of JTextComponent subclasses. // * This is implemented to do nothing (i.e. the response to // * properties in JTextComponent itself are handled prior // * to calling this method). // * // * This implementation updates the background of the text // * component if the editable and/or enabled state changes. // * // * @param evt the property change event // */ // protected void propertyChange(PropertyChangeEvent evt) { // if (evt.getPropertyName().equals("editable") || // evt.getPropertyName().equals("enabled")) { // // updateBackground((JTextComponent)evt.getSource()); // } // } // // /** // * Updates the background of the text component based on whether the // * text component is editable and/or enabled. // * // * @param c the JTextComponent that needs its background color updated // */ // private void updateBackground(JTextComponent c) { // // This is a temporary workaround. // // This code does not correctly deal with Synth (Synth doesn't use // // properties like this), nor does it deal with the situation where // // the developer grabs the color from a JLabel and sets it as // // the background for a JTextArea in all look and feels. The problem // // scenario results if the Color obtained for the Label and TextArea // // is ==, which is the case for the windows look and feel. // // Until an appropriate solution is found, the code is being // // reverted to what it was before the original fix. // if (this instanceof sun.swing.plaf.synth.SynthUI || // (c instanceof JTextArea)) { // return; // } // Color background = c.getBackground(); // if (background instanceof UIResource) { // String prefix = getPropertyPrefix(); // // Color disabledBG = // DefaultLookup.getColor(c, this, prefix + ".disabledBackground", null); // Color inactiveBG = // DefaultLookup.getColor(c, this, prefix + ".inactiveBackground", null); // Color bg = // DefaultLookup.getColor(c, this, prefix + ".background", null); // // /* In an ideal situation, the following check would not be necessary // * and we would replace the color any time the previous color was a // * UIResouce. However, it turns out that there is existing code that // * uses the following inadvisable pattern to turn a text area into // * what appears to be a multi-line label: // * // * JLabel label = new JLabel(); // * JTextArea area = new JTextArea(); // * area.setBackground(label.getBackground()); // * area.setEditable(false); // * // * JLabel's default background is a UIResource. As such, just // * checking for UIResource would have us always changing the // * background away from what the developer wanted. // * // * Therefore, for JTextArea/JEditorPane, we'll additionally check // * that the color we're about to replace matches one that was // * installed by us from the UIDefaults. // */ // if ((c instanceof JTextArea || c instanceof JEditorPane) // && background != disabledBG // && background != inactiveBG // && background != bg) { // // return; // } // // Color newColor = null; // if (!c.isEnabled()) { // newColor = disabledBG; // } // if (newColor == null && !c.isEditable()) { // newColor = inactiveBG; // } // if (newColor == null) { // newColor = bg; // } // if (newColor != null && newColor != background) { // c.setBackground(newColor); // } // } // } // // /** // * Gets the name used as a key to look up properties through the // * UIManager. This is used as a prefix to all the standard // * text properties. // * // * @return the name // */ // protected abstract String getPropertyPrefix(); }