0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: /**
0018: * @author Evgeniya G. Maenkova
0019: * @version $Revision$
0020: */package javax.swing.plaf.basic;
0021:
0022: import java.awt.AWTKeyStroke;
0023: import java.awt.Color;
0024: import java.awt.Dimension;
0025: import java.awt.Graphics;
0026: import java.awt.Insets;
0027: import java.awt.KeyboardFocusManager;
0028: import java.awt.Point;
0029: import java.awt.Rectangle;
0030: import java.awt.Shape;
0031: import java.awt.datatransfer.Clipboard;
0032: import java.awt.datatransfer.DataFlavor;
0033: import java.awt.datatransfer.Transferable;
0034: import java.awt.dnd.DropTargetDragEvent;
0035: import java.awt.dnd.DropTargetDropEvent;
0036: import java.awt.dnd.DropTargetEvent;
0037: import java.awt.dnd.DropTargetListener;
0038: import java.awt.event.ActionEvent;
0039: import java.awt.event.InputEvent;
0040: import java.awt.event.KeyEvent;
0041: import java.awt.event.MouseEvent;
0042: import java.beans.PropertyChangeEvent;
0043: import java.beans.PropertyChangeListener;
0044: import java.util.LinkedHashSet;
0045: import java.util.Set;
0046:
0047: import javax.swing.Action;
0048: import javax.swing.ActionMap;
0049: import javax.swing.InputMap;
0050: import javax.swing.JComponent;
0051: import javax.swing.JEditorPane;
0052: import javax.swing.KeyStroke;
0053: import javax.swing.LookAndFeel;
0054: import javax.swing.SwingUtilities;
0055: import javax.swing.TransferHandler;
0056: import javax.swing.UIDefaults;
0057: import javax.swing.UIManager;
0058: import javax.swing.event.DocumentEvent;
0059: import javax.swing.event.DocumentListener;
0060: import javax.swing.event.MouseInputAdapter;
0061: import javax.swing.plaf.ActionMapUIResource;
0062: import javax.swing.plaf.ComponentInputMapUIResource;
0063: import javax.swing.plaf.InputMapUIResource;
0064: import javax.swing.plaf.TextUI;
0065: import javax.swing.plaf.UIResource;
0066: import javax.swing.text.AbstractDocument;
0067: import javax.swing.text.BadLocationException;
0068: import javax.swing.text.Caret;
0069: import javax.swing.text.DefaultCaret;
0070: import javax.swing.text.DefaultEditorKit;
0071: import javax.swing.text.DefaultHighlighter;
0072: import javax.swing.text.Document;
0073: import javax.swing.text.EditorKit;
0074: import javax.swing.text.Element;
0075: import javax.swing.text.Highlighter;
0076: import javax.swing.text.JTextComponent;
0077: import javax.swing.text.Keymap;
0078: import javax.swing.text.Position;
0079: import javax.swing.text.TextAction;
0080: import javax.swing.text.View;
0081: import javax.swing.text.ViewFactory;
0082:
0083: import org.apache.harmony.awt.text.RootViewContext;
0084: import org.apache.harmony.awt.text.TextFactory;
0085: import org.apache.harmony.awt.text.TextUtils;
0086: import org.apache.harmony.x.swing.StringConstants;
0087: import org.apache.harmony.x.swing.Utilities;
0088: import org.apache.harmony.x.swing.internal.nls.Messages;
0089:
0090: public abstract class BasicTextUI extends TextUI implements ViewFactory {
0091:
0092: public static class BasicCaret extends DefaultCaret implements
0093: UIResource {
0094: public BasicCaret() {
0095: super ();
0096: }
0097: }
0098:
0099: public static class BasicHighlighter extends DefaultHighlighter
0100: implements UIResource {
0101: public BasicHighlighter() {
0102: super ();
0103: }
0104: }
0105:
0106: // Text Component, concerned with this BasicTextUI
0107: private JTextComponent component;
0108:
0109: // Editor Kit for all components excluding JTextPane and JEditorPane
0110: private static final EditorKit EDITOR_KIT = new DefaultEditorKit();
0111:
0112: // The Parent of all view Hierarchy. In never changes. When document
0113: // changes,
0114: // a child of rootView will be replaced only.
0115: private RootViewContext rootViewContext;
0116:
0117: // PropertyChangeListener, DocumentListener
0118: private Listener listener = new Listener();
0119:
0120: // Document, concerned with this BasicTextUI (component.getDocument)
0121: private Document document;
0122:
0123: // Simple TransferHandler to support cut, copy, paste operations
0124: private static TransferHandler transferHandler;
0125:
0126: // This flag is used in paintSafely, modelToView, viewToModel methods.
0127: private boolean isActive = false;
0128:
0129: // This flag is used in Listener.InsertUpdate method. It need not to lock
0130: // document in DocumentListener. Then modelChanged method defines, it need
0131: // to lock document or not
0132: private boolean needLock = true;
0133:
0134: // if document i18n property changes, then ViewHierarchy must be rebuild.
0135: private boolean i18nProperty = false;
0136:
0137: // Action to request focus on Text Component (support FocusAcceleratorKey
0138: //on JTextComponent).
0139: private final Action focusAction = new RequestFocusAction();
0140:
0141: // Key for FOCUS_ACTION in ActionMap
0142: private static final String FOCUS_ACTION_NAME = "request-focus";
0143:
0144: // Flag is used in UpdateFocus AcceleratorKey method
0145: private char lastFocusAccelerator = '\0';
0146:
0147: //Listener for drop target
0148: private DropListener dropListener;
0149:
0150: //Initiator for DnD
0151: private GestureRecognizer gestureRecognizer;
0152:
0153: private final RootViewContext.ViewFactoryGetter viewFactoryGetter = new RootViewContext.ViewFactoryGetter() {
0154:
0155: public ViewFactory getViewFactory() {
0156: ViewFactory viewFactory = getEditorKit(component)
0157: .getViewFactory();
0158: return (viewFactory == null) ? BasicTextUI.this
0159: : viewFactory;
0160: }
0161: };
0162:
0163: /**
0164: * Action to request focus on Text Component, concerned with this
0165: * BasicTextUI
0166: */
0167: private class RequestFocusAction extends TextAction {
0168: public RequestFocusAction() {
0169: super (FOCUS_ACTION_NAME);
0170: }
0171:
0172: public void actionPerformed(final ActionEvent e) {
0173: JTextComponent jtc = null;
0174: if (e != null && e.getSource() != null) {
0175: jtc = (JTextComponent) e.getSource();
0176: }
0177: if (jtc != null) {
0178: jtc.requestFocusInWindow();
0179: }
0180: }
0181: }
0182:
0183: /**
0184: * Transfer Handler to support basic transfer operation. It need to redefine
0185: * javax.swing.TransferHandler because it doesn't support required
0186: * operations. See java.beans (Introspector, BeanInfo,...)
0187: */
0188: private static class TextTransferHandler extends TransferHandler
0189: implements UIResource {
0190: boolean isDrag = false;
0191:
0192: public boolean canImport(final JComponent comp,
0193: final DataFlavor[] dataFlavor) {
0194: //Note: temporary solution
0195: return true; //super.canImport(arg0, arg1);
0196: }
0197:
0198: public void exportToClipboard(final JComponent c,
0199: final Clipboard clip, final int action) {
0200: TextUtils.exportToClipboard(TextUtils.getTextKit(c), clip,
0201: action);
0202: }
0203:
0204: public boolean importData(final JComponent c,
0205: final Transferable t) {
0206: if (isDrag || !(c instanceof JTextComponent)) {
0207: return false;
0208: }
0209: return TextUtils.importData(TextUtils.getTextKit(c), t);
0210: }
0211:
0212: protected void exportDone(final JComponent c,
0213: final Transferable data, final int action) {
0214: isDrag = false;
0215: TextUtils.exportDone(TextUtils.getTextKit(c), data, action);
0216: }
0217:
0218: protected Transferable createTransferable(final JComponent c) {
0219: return TextUtils
0220: .createTransferable(TextUtils.getTextKit(c));
0221: }
0222:
0223: public int getSourceActions(final JComponent c) {
0224: return TextUtils.getSourceActions(TextUtils.getTextKit(c));
0225: }
0226:
0227: public void exportAsDrag(final JComponent comp,
0228: final InputEvent ie, final int action) {
0229: isDrag = true;
0230: super .exportAsDrag(comp, ie, action);
0231: }
0232: }
0233:
0234: private class Listener implements DocumentListener,
0235: PropertyChangeListener {
0236: /**
0237: * Call rootView.changeUpdate
0238: */
0239: public void changedUpdate(final DocumentEvent e) {
0240: getRootView().changedUpdate(e, getVisibleEditorRect(),
0241: getRootView().getViewFactory());
0242: }
0243:
0244: /**
0245: * If "i18n" property of document is changed call modelChanged.
0246: * Otherwise, call rooView.insertUpdate
0247: */
0248: public void insertUpdate(final DocumentEvent e) {
0249: boolean currentI18nProperty = ((Boolean) document
0250: .getProperty(StringConstants.BIDI_PROPERTY))
0251: .booleanValue();
0252: if (currentI18nProperty && !i18nProperty) {
0253: needLock = false;
0254: modelChanged();
0255: needLock = true;
0256: i18nProperty = true;
0257: } else {
0258: getRootView().insertUpdate(e, getVisibleEditorRect(),
0259: getRootView().getViewFactory());
0260: }
0261: }
0262:
0263: /**
0264: * Call rootView.removeUpdate
0265: */
0266: public void removeUpdate(final DocumentEvent e) {
0267: getRootView().removeUpdate(e, getVisibleEditorRect(),
0268: getRootView().getViewFactory());
0269: }
0270:
0271: /**
0272: * If document is changed on Text Component, handle this event. In
0273: * particular remove DocumentListener from old document, add Document
0274: * Listener to new document, Rebuild view hierarchy. If
0275: * "componentOrientaion" property is changes, call modelChanged. If
0276: * JTextComponent.FOCUS_ACCELERATOR_KEY property is changes, call
0277: * private method UpdateFocusAcceleratorBinding (to reflect changes on
0278: * InputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)). Call propertyChange
0279: * method.
0280: */
0281: public void propertyChange(final PropertyChangeEvent e) {
0282: String name = e.getPropertyName();
0283: if (StringConstants.TEXT_COMPONENT_DOCUMENT_PROPERTY
0284: .equals(name)) {
0285: if (document != null) {
0286: document.removeDocumentListener(listener);
0287: }
0288: Object doc = e.getNewValue();
0289: if (doc != null) {
0290: setDocument((Document) doc);
0291: document.addDocumentListener(listener);
0292: modelChanged();
0293: }
0294: } else if (StringConstants.COMPONENT_ORIENTATION
0295: .equals(name)) {
0296: modelChanged();
0297:
0298: } else if (JTextComponent.FOCUS_ACCELERATOR_KEY
0299: .equals(name)) {
0300: lastFocusAccelerator = ((Character) e.getOldValue())
0301: .charValue();
0302: updateFocusAcceleratorBinding(true);
0303: }
0304: propertyChangeImpl(e);
0305: BasicTextUI.this .propertyChange(e);
0306: }
0307: }
0308:
0309: /*
0310: * Performs drop, instances of this class are added to
0311: * component.getDropTarget()
0312: */
0313: final class DropListener implements DropTargetListener {
0314: String str = null;
0315:
0316: int start = 0;
0317:
0318: int end = 0;
0319:
0320: JTextComponent textComponent;
0321:
0322: public void dragEnter(final DropTargetDragEvent e) {
0323: }
0324:
0325: public void dragExit(final DropTargetEvent e) {
0326: }
0327:
0328: public void dragOver(final DropTargetDragEvent e) {
0329: /*
0330: * Component comp = e.getDropTargetContext().getComponent(); if
0331: * (comp == null || ! (comp instanceof JTextComponent)) return;
0332: * textComponent = (JTextComponent)comp; Transferable t =
0333: * e.getTransferable(); start = textComponent.getSelectionStart();
0334: * end = textComponent.getSelectionEnd(); try { str = (String) t
0335: * .getTransferData(DataFlavor.stringFlavor); } catch (final
0336: * UnsupportedFlavorException ufe) { } catch (final IOException
0337: * ioe) {}
0338: */
0339: }
0340:
0341: public void dropActionChanged(final DropTargetDragEvent arg0) {
0342: }
0343:
0344: public void drop(final DropTargetDropEvent e) {
0345: int length = end - start;
0346: int insertPosition = textComponent.viewToModel(e
0347: .getLocation());
0348: try {
0349: textComponent.getDocument().remove(start, length);
0350: if (insertPosition > end) {
0351: insertPosition -= length;
0352: } else {
0353: if (insertPosition >= start) {
0354: insertPosition = start;
0355: }
0356: }
0357: textComponent.getDocument().insertString(
0358: insertPosition, str, null);
0359: textComponent.replaceSelection("");
0360: textComponent.setCaretPosition(insertPosition + length);
0361:
0362: } catch (final BadLocationException ex) {
0363: }
0364: e.dropComplete(true);
0365: }
0366: }
0367:
0368: /*
0369: * Initiates DnD, instances of this class are added to current component
0370: */
0371: final class GestureRecognizer extends MouseInputAdapter {
0372: boolean wasMousePressed = false;
0373:
0374: public void mousePressed(final MouseEvent arg0) {
0375: String selectedText = component.getSelectedText();
0376: if (selectedText != null && selectedText != ""
0377: && component.getDragEnabled()) {
0378: wasMousePressed = true;
0379: }
0380: }
0381:
0382: public void mouseDragged(final MouseEvent me) {
0383: if (wasMousePressed) {
0384: wasMousePressed = false;
0385: component.getTransferHandler().exportAsDrag(component,
0386: me, TransferHandler.MOVE);
0387: }
0388: }
0389: }
0390:
0391: /**
0392: * Creates parent of all view hierarchy.
0393: */
0394: public BasicTextUI() {
0395: initRootViewContext(null);
0396: dropListener = new DropListener();
0397: gestureRecognizer = new GestureRecognizer();
0398: }
0399:
0400: public View create(final Element elem) {
0401: return null;
0402: }
0403:
0404: public View create(final Element elem, final int p0, final int p1) {
0405: return null;
0406: }
0407:
0408: protected Caret createCaret() {
0409: return new BasicCaret();
0410: }
0411:
0412: protected Highlighter createHighlighter() {
0413: return new BasicHighlighter();
0414: }
0415:
0416: protected Keymap createKeymap() {
0417: String name = getKeymapName();
0418: Keymap keymap = JTextComponent.getKeymap(name);
0419: if (keymap == null) {
0420: keymap = JTextComponent.addKeymap(name, JTextComponent
0421: .getKeymap(JTextComponent.DEFAULT_KEYMAP));
0422: }
0423: Object bindings = UIManager.get(addPrefix(".keyBindings"));
0424: if (bindings != null) {
0425: JTextComponent.loadKeymap(keymap,
0426: (JTextComponent.KeyBinding[]) bindings, component
0427: .getActions());
0428: }
0429: return keymap;
0430: }
0431:
0432: public void damageRange(final JTextComponent c, final int p0,
0433: final int p1) {
0434: damageRange(c, p0, p1, Position.Bias.Forward,
0435: Position.Bias.Forward);
0436: }
0437:
0438: /**
0439: * Calculates rectangle(r, for example), corresponding these position and
0440: * biases. Then call component.repaint(r.x, r.y, r.width, r.height)
0441: */
0442: public void damageRange(final JTextComponent c, final int p0,
0443: final int p1, final Position.Bias b1, final Position.Bias b2) {
0444: Shape shape = null;
0445: try {
0446: shape = getRootView().modelToView(p0, b1, p1, b2,
0447: getVisibleEditorRect());
0448: } catch (final BadLocationException e) {
0449: }
0450: Rectangle rect;
0451: if (shape != null) {
0452: rect = shape.getBounds();
0453: component.repaint(rect.x, rect.y, rect.width, rect.height);
0454: }
0455: }
0456:
0457: protected final JTextComponent getComponent() {
0458: return component;
0459: }
0460:
0461: /**
0462: * Always returns DefaultEditorKit
0463: */
0464: public EditorKit getEditorKit(final JTextComponent comp) {
0465: return EDITOR_KIT;
0466: }
0467:
0468: protected String getKeymapName() {
0469: String className = getClass().getName();
0470: final int lastDot = className.lastIndexOf('.');
0471: return className.substring(lastDot + 1);
0472: }
0473:
0474: public Dimension getMaximumSize(final JComponent c) {
0475: //See description for getRootView().getMaximumSpan
0476: return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
0477: }
0478:
0479: /**
0480: * Uses getMinimumSpan of View Hierarchy and getInsets of TextComponent
0481: */
0482: public Dimension getMinimumSize(final JComponent c) {
0483: Insets insets = c.getInsets();
0484: int minX = TextUtils.getHrzInsets(insets)
0485: + (int) getRootView().getMinimumSpan(View.X_AXIS);
0486: int minY = TextUtils.getVrtInsets(insets)
0487: + (int) getRootView().getMinimumSpan(View.Y_AXIS);
0488: return new Dimension(minX, minY);
0489: }
0490:
0491: /**
0492: * Calls getNextVisualPosition on root view. If root view returns -1, then
0493: * this method will return p0 and biasRet[0] will be the same as bias
0494: */
0495: public int getNextVisualPositionFrom(final JTextComponent c,
0496: final int p0, final Position.Bias bias, final int p1,
0497: final Position.Bias[] biasRet) throws BadLocationException {
0498:
0499: int pos = getRootView().getNextVisualPositionFrom(p0, bias,
0500: getVisibleEditorRect(), p1, biasRet);
0501: if (pos == -1) {
0502: pos = p0;
0503: biasRet[0] = bias;
0504: }
0505: return pos;
0506: }
0507:
0508: /**
0509: * Uses getPrefferedSpan of View Hierarchy and getInsets of TextComponent
0510: */
0511: public Dimension getPreferredSize(final JComponent c) {
0512: Insets insets = c.getInsets();
0513: int prefX = TextUtils.getHrzInsets(insets)
0514: + (int) getRootView().getPreferredSpan(View.X_AXIS);
0515: int prefY = TextUtils.getVrtInsets(insets)
0516: + (int) getRootView().getPreferredSpan(View.Y_AXIS);
0517: return new Dimension(prefX, prefY);
0518: }
0519:
0520: protected abstract String getPropertyPrefix();
0521:
0522: public View getRootView(final JTextComponent c) {
0523: return getRootView();
0524: }
0525:
0526: public String getToolTipText(final JTextComponent c, final Point p) {
0527: Rectangle r = getVisibleEditorRect();
0528: return (r != null) ? getRootView().getToolTipText(p.x, p.y, r)
0529: : null;
0530: }
0531:
0532: private TransferHandler getTransferHandler() {
0533: if (transferHandler == null) {
0534: transferHandler = new TextTransferHandler();
0535: }
0536: return transferHandler;
0537: }
0538:
0539: /**
0540: * Returns, component getSize, excluding insets.
0541: */
0542: protected Rectangle getVisibleEditorRect() {
0543: return TextUtils.getEditorRect(component);
0544: }
0545:
0546: final String addPrefix(final String property) {
0547: return getPropertyPrefix() + property;
0548: }
0549:
0550: protected void installDefaults() {
0551: LookAndFeel.installColorsAndFont(component,
0552: addPrefix(".background"), addPrefix(".foreground"),
0553: addPrefix(".font"));
0554: if (Utilities.isUIResource(component.getBorder())) {
0555: component.setBorder(UIManager
0556: .getBorder(addPrefix(".border")));
0557: }
0558: if (Utilities.isUIResource(component.getMargin())) {
0559: component.setMargin(UIManager
0560: .getInsets(addPrefix(".margin")));
0561: }
0562: //RI 6251901. Documentation error
0563: if (Utilities.isUIResource(component.getCaretColor())) {
0564: component.setCaretColor(UIManager
0565: .getColor(addPrefix(".caretForeground")));
0566: }
0567:
0568: if (Utilities.isUIResource(component.getSelectionColor())) {
0569: component.setSelectionColor(UIManager
0570: .getColor(addPrefix(".selectionBackground")));
0571: }
0572:
0573: if (Utilities.isUIResource(component.getSelectedTextColor())) {
0574: component.setSelectedTextColor(UIManager
0575: .getColor(addPrefix(".selectionForeground")));
0576: }
0577:
0578: if (Utilities.isUIResource(component.getDisabledTextColor())) {
0579: component.setDisabledTextColor(UIManager
0580: .getColor(addPrefix(".inactiveForeground")));
0581: }
0582: }
0583:
0584: final Set<AWTKeyStroke> getDefaultFocusTraversalKeys(final int mode) {
0585: Set<AWTKeyStroke> result = component
0586: .getFocusTraversalKeys(mode);
0587:
0588: if (result == null) {
0589: result = new LinkedHashSet<AWTKeyStroke>();
0590: if (mode == KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS) {
0591: result.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
0592: InputEvent.CTRL_DOWN_MASK));
0593: } else {
0594: result.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
0595: InputEvent.CTRL_DOWN_MASK
0596: | InputEvent.SHIFT_DOWN_MASK));
0597: }
0598: } else {
0599: result = new LinkedHashSet<AWTKeyStroke>(result);
0600: }
0601:
0602: return result;
0603: }
0604:
0605: void updateFocusTraversalKeys() {
0606: if (component == null) {
0607: return;
0608: }
0609: Set<AWTKeyStroke> forwardFocusTraversalKeys = getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
0610: Set<AWTKeyStroke> backwardFocusTraversalKeys = getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
0611: KeyStroke tabPressed = KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
0612: 0);
0613: KeyStroke shiftTabPressed = KeyStroke.getKeyStroke(
0614: KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK);
0615:
0616: if (component.isEditable()) {
0617: forwardFocusTraversalKeys.remove(tabPressed);
0618: backwardFocusTraversalKeys.remove(shiftTabPressed);
0619: } else {
0620: if (!forwardFocusTraversalKeys.contains(tabPressed)) {
0621: forwardFocusTraversalKeys.add(tabPressed);
0622: }
0623: if (!forwardFocusTraversalKeys.contains(shiftTabPressed)) {
0624: backwardFocusTraversalKeys.add(shiftTabPressed);
0625: }
0626: }
0627:
0628: component.setFocusTraversalKeys(
0629: KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
0630: forwardFocusTraversalKeys);
0631: component.setFocusTraversalKeys(
0632: KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
0633: backwardFocusTraversalKeys);
0634: }
0635:
0636: final void installUIInputMap() {
0637: String propertyName = addPrefix(".focusInputMap");
0638: InputMapUIResource inputMap1 = new InputMapUIResource();
0639: InputMapUIResource inputMap2 = (InputMapUIResource) UIManager
0640: .get(propertyName);
0641: inputMap1.setParent(inputMap2);
0642: SwingUtilities.replaceUIInputMap(component,
0643: JComponent.WHEN_FOCUSED, inputMap1);
0644: }
0645:
0646: final void putActionToActionMap(final Action a, final ActionMap map) {
0647: Object name = a.getValue(Action.NAME);
0648: map.put(name, a);
0649: }
0650:
0651: final void installUIActionMap() {
0652: UIDefaults uiDefaults = UIManager.getLookAndFeelDefaults();
0653: String propertyName = getPropertyPrefix() + ".actionMap";
0654: ActionMap actionMap1 = new ActionMapUIResource();
0655: putActionToActionMap(focusAction, actionMap1);
0656: Object actionMap2 = uiDefaults.get(propertyName);
0657: if (actionMap2 == null) {
0658: ActionMapUIResource map = new ActionMapUIResource();
0659: Action[] actions = component.getActions();
0660: for (int i = 0; i < actions.length; i++) {
0661: putActionToActionMap(actions[i], map);
0662: }
0663: putActionToActionMap(TransferHandler.getPasteAction(), map);
0664: putActionToActionMap(TransferHandler.getCutAction(), map);
0665: putActionToActionMap(TransferHandler.getCopyAction(), map);
0666:
0667: actionMap2 = map;
0668: if (!(component instanceof JEditorPane)) {
0669: uiDefaults.put(propertyName, map);
0670: }
0671: }
0672: actionMap1.setParent((ActionMap) actionMap2);
0673: SwingUtilities.replaceUIActionMap(component, actionMap1);
0674: }
0675:
0676: /**
0677: * Sets InputMap(JComponent.WHEN_FOCUSED), ActionMap, Keymap on
0678: * TextComponent.
0679: *
0680: */
0681: protected void installKeyboardActions() {
0682: installUIActionMap();
0683: installUIInputMap();
0684: Keymap keymap = createKeymap();
0685: component.setKeymap(keymap);
0686: }
0687:
0688: protected void installListeners() {
0689: }
0690:
0691: public void installUI(final JComponent c) {
0692: if (!(c instanceof JTextComponent)) {
0693: throw new Error(Messages.getString("swing.B1")); //$NON-NLS-1$
0694: }
0695:
0696: super .installUI(c);
0697:
0698: setComponent((JTextComponent) c);
0699:
0700: installDefaults();
0701: LookAndFeel.installProperty(component,
0702: StringConstants.OPAQUE_PROPERTY, Boolean.TRUE);
0703:
0704: if (Utilities.isUIResource(component.getCaret())) {
0705: Caret caret = createCaret();
0706: component.setCaret(caret);
0707: caret.setBlinkRate(UIManager.getInt(getPropertyPrefix()
0708: + ".caretBlinkRate"));
0709: }
0710:
0711: if (Utilities.isUIResource(component.getHighlighter())) {
0712: component.setHighlighter(createHighlighter());
0713: }
0714:
0715: if (Utilities.isUIResource(component.getTransferHandler())) {
0716: component.setTransferHandler(getTransferHandler());
0717: }
0718:
0719: if (component.getDocument() == null) {
0720: setDocument(getEditorKit(component).createDefaultDocument());
0721: component.setDocument(document);
0722: } else {
0723: setDocument(component.getDocument());
0724: }
0725:
0726: modelChanged();
0727:
0728: ((AbstractDocument) component.getDocument())
0729: .addDocumentListener(listener);
0730: component.addPropertyChangeListener(listener);
0731: JTextComponent.addKeymap(getKeymapName(), JTextComponent
0732: .getKeymap(JTextComponent.DEFAULT_KEYMAP));
0733:
0734: installListeners();
0735:
0736: installKeyboardActions();
0737:
0738: isActive = true;
0739: component.setAutoscrolls(true);
0740: updateFocusAcceleratorBinding(true);
0741:
0742: //DnD support
0743: // java.awt.Component doesn't support DnD
0744: /*
0745: * try { component.getDropTarget().addDropTargetListener(dropListener);
0746: * } catch (final TooManyListenersException e){}
0747: */
0748: component.addMouseListener(gestureRecognizer);
0749: component.addMouseMotionListener(gestureRecognizer);
0750: updateFocusTraversalKeys();
0751: }
0752:
0753: /**
0754: * Rebuilts view hierarchy.
0755: *
0756: */
0757: protected void modelChanged() {
0758: final Document doc = document;
0759:
0760: if (needLock) {
0761: readLock(doc);
0762: }
0763: try {
0764: setDocument(document);
0765: View view = getRootView().getViewFactory().create(
0766: document.getDefaultRootElement());
0767: setView(view);
0768: setViewSize();
0769: } finally {
0770: if (needLock) {
0771: readUnlock(doc);
0772: }
0773: }
0774: if (component != null) {
0775: component.repaint();
0776: }
0777: }
0778:
0779: public Rectangle modelToView(final JTextComponent c, final int p)
0780: throws BadLocationException {
0781: return modelToView(c, p, Position.Bias.Forward);
0782: }
0783:
0784: public Rectangle modelToView(final JTextComponent comp,
0785: final int p, final Position.Bias b)
0786: throws BadLocationException {
0787: final Document doc = document;
0788:
0789: readLock(doc);
0790: try {
0791: Rectangle r = null;
0792: if (isActive) {
0793: Rectangle rect = getVisibleEditorRect();
0794: if (rect != null) {
0795: getRootView().setSize(rect.width, rect.height);
0796: Shape shape = getRootView().modelToView(p, rect, b);
0797: if (shape != null) {
0798: r = shape.getBounds();
0799: }
0800: }
0801: }
0802: return r;
0803: } finally {
0804: readUnlock(doc);
0805: }
0806: }
0807:
0808: public final void paint(final Graphics g, final JComponent c) {
0809: //super.paint(g, c);//???
0810: paintSafely(g);
0811: }
0812:
0813: protected void paintBackground(final Graphics g) {
0814: Color color = component.getBackground();
0815: if (color != null) {
0816: g.setColor(color);
0817: }
0818: Rectangle rect = getVisibleEditorRect();
0819: if (rect != null) {
0820: g.fillRect(rect.x, rect.y, rect.width, rect.height);
0821: }
0822: }
0823:
0824: protected void paintSafely(final Graphics g) {
0825: if (!isActive) {
0826: return;
0827: }
0828:
0829: final Document doc = document;
0830:
0831: readLock(doc);
0832: try {
0833: Highlighter highlighter = component.getHighlighter();
0834: Caret caret = component.getCaret();
0835: if (component.isOpaque()) {
0836: paintBackground(g);
0837: }
0838: if (highlighter != null) {
0839: highlighter.paint(g);
0840: }
0841: Rectangle visibleRect = getVisibleEditorRect();
0842: if (visibleRect != null) {
0843: getRootView().setSize(visibleRect.width,
0844: visibleRect.height);
0845: getRootView().paint(g, visibleRect);
0846: }
0847: caret.paint(g);
0848: } finally {
0849: readUnlock(doc);
0850: }
0851: }
0852:
0853: void propertyChangeImpl(final PropertyChangeEvent e) {
0854: if (org.apache.harmony.x.swing.StringConstants.EDITABLE_PROPERTY_CHANGED
0855: .equals(e.getPropertyName())
0856: && !e.getOldValue().equals(e.getNewValue())) {
0857: updateFocusTraversalKeys();
0858: }
0859: }
0860:
0861: protected void propertyChange(final PropertyChangeEvent e) {
0862: }
0863:
0864: /**
0865: * Replaces child of the root view
0866: */
0867: protected final void setView(final View v) {
0868: component.removeAll();
0869: if (v != null) {
0870: getRootView().append(v);
0871: }
0872: if (component != null) {
0873: component.invalidate();
0874: }
0875: }
0876:
0877: protected void uninstallDefaults() {
0878: if (Utilities.isUIResource(component.getForeground())) {
0879: component.setForeground(null);
0880: }
0881:
0882: if (Utilities.isUIResource(component.getBackground())) {
0883: component.setBackground(null);
0884: }
0885:
0886: if (Utilities.isUIResource(component.getFont())) {
0887: component.setFont(null);
0888: }
0889:
0890: if (Utilities.isUIResource(component.getBorder())) {
0891: component.setBorder(null);
0892: }
0893:
0894: if (Utilities.isUIResource(component.getMargin())) {
0895: component.setMargin(null);
0896: }
0897:
0898: if (Utilities.isUIResource(component.getCaretColor())) {
0899: component.setCaretColor(null);
0900: }
0901:
0902: if (Utilities.isUIResource(component.getSelectionColor())) {
0903: component.setSelectionColor(null);
0904: }
0905:
0906: if (Utilities.isUIResource(component.getSelectedTextColor())) {
0907: component.setSelectedTextColor(null);
0908: }
0909:
0910: if (Utilities.isUIResource(component.getDisabledTextColor())) {
0911: component.setDisabledTextColor(null);
0912: }
0913: }
0914:
0915: /**
0916: * Sets ActionMap and Keymap of TextComponent to null.
0917: *
0918: */
0919: protected void uninstallKeyboardActions() {
0920: component.setKeymap(null);
0921: SwingUtilities.replaceUIActionMap(component, null);
0922: }
0923:
0924: protected void uninstallListeners() {
0925: }
0926:
0927: public void uninstallUI(final JComponent c) {
0928: if (component != c) {
0929: return;
0930: }
0931: isActive = false;
0932: super .uninstallUI(c);
0933:
0934: if (Utilities.isUIResource(component.getCaret())) {
0935: component.setCaret(null);
0936: }
0937:
0938: if (Utilities.isUIResource(component.getHighlighter())) {
0939: component.setHighlighter(null);
0940: }
0941:
0942: uninstallDefaults();
0943: uninstallKeyboardActions();
0944: uninstallListeners();
0945: ((AbstractDocument) component.getDocument())
0946: .removeDocumentListener(listener);
0947: component.removePropertyChangeListener(listener);
0948:
0949: //DnD support
0950: //java.awt.Component doesn't support DnD
0951: /*
0952: * component.getDropTarget().removeDropTargetListener(dropListener);
0953: */
0954: component.removeMouseListener(gestureRecognizer);
0955: component.removeMouseMotionListener(gestureRecognizer);
0956:
0957: setComponent(null);
0958: }
0959:
0960: public void update(final Graphics g, final JComponent c) {
0961: super .update(g, c);
0962: }
0963:
0964: final void updateFocusAcceleratorBinding(final boolean changed) {
0965: if (!changed) {
0966: return;
0967: }
0968: char accelerator = component.getFocusAccelerator();
0969: InputMap im = SwingUtilities.getUIInputMap(component,
0970: JComponent.WHEN_IN_FOCUSED_WINDOW);
0971: boolean wasInputMap = (im != null);
0972: boolean needToRemove = (lastFocusAccelerator != '\0');
0973: boolean needToAdd = (accelerator != '\0');
0974: if (needToAdd) {
0975: if (needToRemove && wasInputMap) {
0976: im.remove(KeyStroke.getKeyStroke(lastFocusAccelerator,
0977: InputEvent.ALT_DOWN_MASK));
0978: } else if (!wasInputMap) {
0979: im = new ComponentInputMapUIResource(component);
0980: im.put(KeyStroke.getKeyStroke(accelerator,
0981: InputEvent.ALT_DOWN_MASK), FOCUS_ACTION_NAME);
0982: if (!wasInputMap) {
0983: SwingUtilities.replaceUIInputMap(component,
0984: JComponent.WHEN_IN_FOCUSED_WINDOW, im);
0985: }
0986:
0987: } else if (wasInputMap) {
0988: im.remove(KeyStroke.getKeyStroke(lastFocusAccelerator,
0989: InputEvent.ALT_DOWN_MASK));
0990: }
0991: }
0992: }
0993:
0994: public int viewToModel(final JTextComponent c, final Point p) {
0995: return viewToModel(c, p, new Position.Bias[1]);
0996: }
0997:
0998: public int viewToModel(final JTextComponent c, final Point p,
0999: final Position.Bias[] b) {
1000: return getRootView().viewToModel(p.x, p.y,
1001: getVisibleEditorRect(), b);
1002: }
1003:
1004: private void setViewSize() {
1005: Rectangle rect = getVisibleEditorRect();
1006: if (rect != null) {
1007: getRootView().setSize(rect.width, rect.height);
1008: }
1009: }
1010:
1011: private void readLock(final Document doc) {
1012: if (doc instanceof AbstractDocument) {
1013: ((AbstractDocument) doc).readLock();
1014: }
1015: }
1016:
1017: private void readUnlock(final Document doc) {
1018: if (doc instanceof AbstractDocument) {
1019: ((AbstractDocument) doc).readUnlock();
1020: }
1021: }
1022:
1023: final boolean getI18nProperty() {
1024: return document == null ? false : ((Boolean) document
1025: .getProperty(StringConstants.BIDI_PROPERTY))
1026: .booleanValue();
1027: }
1028:
1029: private View getRootView() {
1030: return rootViewContext.getView();
1031: }
1032:
1033: private void setDocument(final Document document) {
1034: this .document = document;
1035: rootViewContext.setDocument(document);
1036: }
1037:
1038: private void setComponent(final JTextComponent component) {
1039: this .component = component;
1040: rootViewContext.setComponent(component);
1041: }
1042:
1043: private void initRootViewContext(final Element elem) {
1044: rootViewContext = TextFactory.getTextFactory().createRootView(
1045: elem);
1046: rootViewContext.setViewFactoryGetter(viewFactoryGetter);
1047: setComponent(component);
1048: setDocument(document);
1049: }
1050: }
|