0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.visualweb.designer;
0042:
0043: import java.awt.AWTKeyStroke;
0044: import java.awt.Color;
0045: import java.awt.Component;
0046: import java.awt.Dimension;
0047: import java.awt.Font;
0048: import java.awt.Graphics;
0049: import java.awt.Graphics2D;
0050: import java.awt.Insets;
0051: import java.awt.KeyboardFocusManager;
0052: import java.awt.Point;
0053: import java.awt.dnd.DropTarget;
0054: import java.awt.event.ActionEvent;
0055: import java.awt.event.InputEvent;
0056: import java.awt.event.KeyEvent;
0057: import java.awt.event.MouseEvent;
0058: import java.util.HashSet;
0059: import java.util.Set;
0060: import java.util.TooManyListenersException;
0061: import java.util.logging.Level;
0062: import java.util.logging.Logger;
0063:
0064: import javax.swing.AbstractAction;
0065: import javax.swing.Action;
0066: import javax.swing.ActionMap;
0067: import javax.swing.InputMap;
0068: import javax.swing.JComponent;
0069: import javax.swing.JViewport;
0070: import javax.swing.KeyStroke;
0071: import javax.swing.SwingConstants;
0072: import javax.swing.SwingUtilities;
0073: import javax.swing.TransferHandler;
0074: import javax.swing.UIManager;
0075: import javax.swing.border.Border;
0076: import javax.swing.plaf.ActionMapUIResource;
0077: import javax.swing.plaf.ComponentUI;
0078: import javax.swing.plaf.InputMapUIResource;
0079: import javax.swing.plaf.UIResource;
0080: import javax.swing.text.Keymap;
0081:
0082: import org.w3c.dom.Element;
0083:
0084: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition;
0085: import org.netbeans.modules.visualweb.css2.CssBox;
0086: import org.netbeans.modules.visualweb.css2.ModelViewMapper;
0087: import org.netbeans.modules.visualweb.css2.PageBox;
0088: import org.netbeans.modules.visualweb.text.DesignerPaneBase;
0089: import org.netbeans.modules.visualweb.text.DesignerPaneBaseUI;
0090:
0091: /**
0092: * Same as DesignerPaneUI, but rewritten to deal with Boxes directly.
0093: * Provides the look and feel for a DesignerPane.
0094: * Based -heavily- on BasicEditorPaneUI in javax.swing.
0095: */
0096: public class DesignerPaneUI extends DesignerPaneBaseUI {
0097: // private static final TransferHandler defaultTransferHandler = null; // = new TextTransferHandler();
0098: private static TextDropTargetListener defaultDropTargetListener = null;
0099: // private boolean deferred;
0100: private long prev1 = 0;
0101: private long prev2 = 0;
0102: private long prev3 = 0;
0103:
0104: // ----- member variables ---------------------------------------
0105: transient PageBox pageBox;
0106: transient DesignerPane editor;
0107: transient boolean painted;
0108:
0109: /**
0110: * Creates a new UI.
0111: */
0112: public DesignerPaneUI() {
0113: super ();
0114:
0115: painted = false;
0116: }
0117:
0118: // FROM BASICEDITORPANEUI:
0119:
0120: /**
0121: * Creates a UI for the DesignerPane.
0122: *
0123: * @param c the DesignerPane component
0124: * @return the UI
0125: */
0126: public static ComponentUI createUI(JComponent c) {
0127: return new DesignerPaneUI();
0128: }
0129:
0130: /** Return the initial containing block used by the editor */
0131: public PageBox getPageBox() {
0132: return pageBox;
0133: }
0134:
0135: /**
0136: * Fetches the name used as a key to lookup properties through the
0137: * UIManager. This is used as a prefix to all the standard
0138: * text properties.
0139: *
0140: * @return the name ("EditorPane")
0141: */
0142: protected String getPropertyPrefix() {
0143: // Not changed: we want to use the same colors etc.
0144: // as JEditorPane
0145: return "EditorPane";
0146: }
0147:
0148: /**
0149: * Fetch an action map to use. The map for a JEditorPane
0150: * is not shared because it changes with the EditorKit.
0151: */
0152: ActionMap getActionMap() {
0153: ActionMap am = new ActionMapUIResource();
0154: am.put("requestFocus", new FocusAction());
0155:
0156: Action[] actions = getComponent().getActions();
0157:
0158: if (actions != null) {
0159: addActions(am, actions);
0160: }
0161:
0162: am.put(TransferHandler.getCutAction().getValue(Action.NAME),
0163: TransferHandler.getCutAction());
0164: am.put(TransferHandler.getCopyAction().getValue(Action.NAME),
0165: TransferHandler.getCopyAction());
0166: am.put(TransferHandler.getPasteAction().getValue(Action.NAME),
0167: TransferHandler.getPasteAction());
0168:
0169: return am;
0170: }
0171:
0172: void removeActions(ActionMap map, Action[] actions) {
0173: if (DesignerUtils.DEBUG) {
0174: DesignerUtils.debugLog(getClass().getName()
0175: + ".removeActions(ActionMap, Action[])");
0176: }
0177: if (map == null) {
0178: throw (new IllegalArgumentException("Null action map."));
0179: }
0180: if (actions == null) {
0181: throw (new IllegalArgumentException("Null action array."));
0182: }
0183:
0184: int n = actions.length;
0185:
0186: for (int i = 0; i < n; i++) {
0187: Action a = actions[i];
0188: map.remove(a.getValue(Action.NAME));
0189: }
0190: }
0191:
0192: void addActions(ActionMap map, Action[] actions) {
0193: if (DesignerUtils.DEBUG) {
0194: DesignerUtils.debugLog(getClass().getName()
0195: + ".addActions(ActionMap, Action[])");
0196: }
0197: if (map == null) {
0198: throw (new IllegalArgumentException("Null action map."));
0199: }
0200: if (actions == null) {
0201: throw (new IllegalArgumentException("Null action array."));
0202: }
0203: int n = actions.length;
0204:
0205: for (int i = 0; i < n; i++) {
0206: Action a = actions[i];
0207: map.put(a.getValue(Action.NAME), a);
0208: }
0209: }
0210:
0211: // XXX Moved to DesignerPaneBaseUI
0212: // /**
0213: // * Creates the object to use for a caret. By default an
0214: // * instance of BasicCaret is created. This method
0215: // * can be redefined to provide something else that implements
0216: // * the InputPosition interface or a subclass of JCaret.
0217: // *
0218: // * @return the caret object
0219: // */
0220: // protected DesignerCaret createCaret() {
0221: // DesignerCaret caret = new DesignerCaret();
0222: //
0223: // String prefix = getPropertyPrefix();
0224: // Object o = UIManager.get(prefix + ".caretBlinkRate");
0225: //
0226: // if ((o != null) && (o instanceof Integer)) {
0227: // Integer rate = (Integer)o;
0228: // caret.setBlinkRate(rate.intValue());
0229: // }
0230: //
0231: // return caret;
0232: // }
0233:
0234: /**
0235: * Fetches the name of the keymap that will be installed/used
0236: * by default for this UI. This is implemented to create a
0237: * name based upon the classname. The name is the the name
0238: * of the class with the package prefix removed.
0239: *
0240: * @return the name
0241: */
0242: protected String getKeymapName() {
0243: String nm = getClass().getName();
0244: int index = nm.lastIndexOf('.');
0245:
0246: if (index >= 0) {
0247: nm = nm.substring(index + 1, nm.length());
0248: }
0249:
0250: return nm;
0251: }
0252:
0253: /**
0254: * Creates the keymap to use for the text component, and installs
0255: * any necessary bindings into it. By default, the keymap is
0256: * shared between all instances of this type of DesignerPaneBaseUI. The
0257: * keymap has the name defined by the getKeymapName method. If the
0258: * keymap is not found, then DEFAULT_KEYMAP from JTextComponent is used.
0259: * <p>
0260: * The set of bindings used to create the keymap is fetched
0261: * from the UIManager using a key formed by combining the
0262: * {@link #getPropertyPrefix} method
0263: * and the string <code>.keyBindings</code>. The type is expected
0264: * to be <code>JTextComponent.KeyBinding[]</code>.
0265: *
0266: * @return the keymap
0267: * @see #getKeymapName
0268: * @see com.sun.rave.text.JTextComponent
0269: */
0270: protected Keymap createKeymap() {
0271: String nm = getKeymapName();
0272: Keymap map = DesignerPaneBase.getKeymap(nm);
0273:
0274: if (map == null) {
0275: Keymap parent = DesignerPaneBase
0276: .getKeymap(DesignerPaneBase.DEFAULT_KEYMAP);
0277: map = DesignerPaneBase.addKeymap(nm, parent);
0278:
0279: String prefix = getPropertyPrefix();
0280: Object o = UIManager.get(prefix + ".keyBindings");
0281:
0282: if ((o != null)
0283: && (o instanceof DesignerPaneBase.KeyBinding[])) {
0284: DesignerPaneBase.KeyBinding[] bindings = (DesignerPaneBase.KeyBinding[]) o;
0285: DesignerPaneBase.loadKeymap(map, bindings,
0286: getComponent().getActions());
0287: }
0288: }
0289:
0290: return map;
0291: }
0292:
0293: // FROM BASICTEXTUI:
0294:
0295: /**
0296: * Initializes component properties, e.g. font, foreground,
0297: * background, caret color, selection color, selected text color,
0298: * disabled text color, and border color. The font, foreground, and
0299: * background properties are only set if their current value is either null
0300: * or a UIResource, other properties are set if the current
0301: * value is null.
0302: *
0303: * @see #uninstallDefaults
0304: * @see #installUI
0305: */
0306: protected void installDefaults() {
0307: // We don't support text dragging in the designer surface yet
0308: //editor.addMouseListener(defaultDragRecognizer);
0309: //editor.addMouseMotionListener(defaultDragRecognizer);
0310: WebForm form = editor.getWebForm();
0311: editor.addMouseListener(form.getManager().getMouseHandler());
0312: editor.addMouseMotionListener(form.getManager()
0313: .getMouseHandler());
0314:
0315: String prefix = getPropertyPrefix();
0316: Font f = editor.getFont();
0317:
0318: if ((f == null) || (f instanceof UIResource)) {
0319: editor.setFont(UIManager.getFont(prefix + ".font"));
0320: }
0321:
0322: Color bg = editor.getBackground();
0323:
0324: if ((bg == null) || (bg instanceof UIResource)) {
0325: editor.setBackground(UIManager.getColor(prefix
0326: + ".background"));
0327: }
0328:
0329: Color fg = editor.getForeground();
0330:
0331: if ((fg == null) || (fg instanceof UIResource)) {
0332: editor.setForeground(UIManager.getColor(prefix
0333: + ".foreground"));
0334: }
0335:
0336: Color color = editor.getCaretColor();
0337:
0338: if ((color == null) || (color instanceof UIResource)) {
0339: editor.setCaretColor(UIManager.getColor(prefix
0340: + ".caretForeground"));
0341: }
0342:
0343: Color s = editor.getSelectionColor();
0344:
0345: if ((s == null) || (s instanceof UIResource)) {
0346: editor.setSelectionColor(UIManager.getColor(prefix
0347: + ".selectionBackground"));
0348: }
0349:
0350: Color sfg = editor.getSelectedTextColor();
0351:
0352: if ((sfg == null) || (sfg instanceof UIResource)) {
0353: editor.setSelectedTextColor(UIManager.getColor(prefix
0354: + ".selectionForeground"));
0355: }
0356:
0357: Border b = editor.getBorder();
0358:
0359: if ((b == null) || (b instanceof UIResource)) {
0360: editor.setBorder(UIManager.getBorder(prefix + ".border"));
0361: }
0362:
0363: /* Caret is only set when we go into flow mode editing
0364: DesignerCaret caret = editor.getCaret();
0365: if (caret == null || caret instanceof UIResource) {
0366: caret = createCaret();
0367: editor.setCaret(caret);
0368:
0369: Object o = UIManager.get(prefix + ".caretBlinkRate");
0370: if ((o != null) && (o instanceof Integer)) {
0371: Integer rate = (Integer) o;
0372: caret.setBlinkRate(rate.intValue());
0373: System.out.println("BLINK RATE WAS " + rate);
0374: }
0375: }
0376: */
0377: // TransferHandler th = editor.getTransferHandler();
0378: // if ((th == null) || th instanceof UIResource) {
0379: // editor.setTransferHandler(getTransferHandler());
0380: // editor.setTransferHandler(null);
0381: // }
0382: DropTarget dropTarget = editor.getDropTarget();
0383:
0384: // if (dropTarget instanceof UIResource) {
0385: if (dropTarget != null) {
0386: getDropTargetListener();
0387:
0388: try {
0389: dropTarget
0390: .addDropTargetListener(defaultDropTargetListener);
0391: } catch (TooManyListenersException ex) {
0392: // should not happen... swing drop target is multicast
0393: log(ex);
0394: }
0395: }
0396: }
0397:
0398: private TextDropTargetListener getDropTargetListener() {
0399: if (defaultDropTargetListener == null) {
0400: defaultDropTargetListener = new TextDropTargetListener();
0401: }
0402:
0403: return defaultDropTargetListener;
0404: }
0405:
0406: /**
0407: * Sets the component properties that haven't been explicitly overridden to
0408: * null. A property is considered overridden if its current value
0409: * is not a UIResource.
0410: *
0411: * @see #installDefaults
0412: * @see #uninstallUI
0413: */
0414: protected void uninstallDefaults() {
0415: //editor.removeMouseListener(defaultDragRecognizer);
0416: //editor.removeMouseMotionListener(defaultDragRecognizer);
0417: WebForm form = editor.getWebForm();
0418: editor.removeMouseListener(form.getManager().getMouseHandler());
0419: editor.removeMouseMotionListener(form.getManager()
0420: .getMouseHandler());
0421:
0422: if (editor.getCaretColor() instanceof UIResource) {
0423: editor.setCaretColor(null);
0424: }
0425:
0426: if (editor.getSelectionColor() instanceof UIResource) {
0427: editor.setSelectionColor(null);
0428: }
0429:
0430: if (editor.getSelectedTextColor() instanceof UIResource) {
0431: editor.setSelectedTextColor(null);
0432: }
0433:
0434: if (editor.getBorder() instanceof UIResource) {
0435: editor.setBorder(null);
0436: }
0437:
0438: // DesignerCaret is not UIResource instance.
0439: // if (editor.getCaret() instanceof UIResource) {
0440: // editor.setCaret(null);
0441: // }
0442:
0443: if (editor.getTransferHandler() instanceof UIResource) {
0444: editor.setTransferHandler(null);
0445: }
0446:
0447: // Unintall drop target listener too.
0448: DropTarget dropTarget = editor.getDropTarget();
0449: if (dropTarget != null && defaultDropTargetListener != null) {
0450: dropTarget
0451: .removeDropTargetListener(defaultDropTargetListener);
0452: }
0453: }
0454:
0455: /**
0456: * Installs listeners for the UI.
0457: */
0458: protected void installListeners() {
0459: }
0460:
0461: /**
0462: * Uninstalls listeners for the UI.
0463: */
0464: protected void uninstallListeners() {
0465: }
0466:
0467: protected void installKeyboardActions() {
0468: // backward compatibility support... keymaps for the UI
0469: // are now installed in the more friendly input map.
0470: editor.setKeymap(createKeymap());
0471:
0472: InputMap km = getInputMap();
0473:
0474: if (km != null) {
0475: SwingUtilities.replaceUIInputMap(editor,
0476: JComponent.WHEN_FOCUSED, km);
0477: }
0478:
0479: ActionMap map = getActionMap();
0480:
0481: if (map != null) {
0482: SwingUtilities.replaceUIActionMap(editor, map);
0483: }
0484:
0485: // XXX DesignerPaneUI.installKeyboardActions: TODO: updateFocusAcceleratorBinding
0486: //updateFocusAcceleratorBinding(false);
0487: }
0488:
0489: /**
0490: * Get the InputMap to use for the UI.
0491: */
0492: InputMap getInputMap() {
0493: InputMap map = new InputMapUIResource();
0494: InputMap shared = (InputMap) UIManager.get(getPropertyPrefix()
0495: + ".focusInputMap");
0496:
0497: if (shared != null) {
0498: map.setParent(shared);
0499: }
0500:
0501: return map;
0502: }
0503:
0504: /**
0505: * Invoked when the focus accelerator changes, this will update the
0506: * key bindings as necessary.
0507: */
0508:
0509: /*
0510: void updateFocusAcceleratorBinding(boolean changed) {
0511: char accelerator = editor.getFocusAccelerator();
0512:
0513: if (changed || accelerator != '\0') {
0514: InputMap km = SwingUtilities.getUIInputMap
0515: (editor, JComponent.WHEN_IN_FOCUSED_WINDOW);
0516:
0517: if (km == null && accelerator != '\0') {
0518: km = new ComponentInputMapUIResource(editor);
0519: SwingUtilities.replaceUIInputMap(editor, JComponent.
0520: WHEN_IN_FOCUSED_WINDOW, km);
0521: ActionMap am = getActionMap();
0522: SwingUtilities.replaceUIActionMap(editor, am);
0523: }
0524: if (km != null) {
0525: km.clear();
0526: if (accelerator != '\0') {
0527: km.put(KeyStroke.getKeyStroke(accelerator,
0528: ActionEvent.ALT_MASK),
0529: "requestFocus");
0530: }
0531: }
0532: }
0533: }
0534: */
0535:
0536: /**
0537: * Invoked when editable property is changed.
0538: *
0539: * removing 'TAB' and 'SHIFT-TAB' from traversalKeysSet in case
0540: * editor is editable
0541: * adding 'TAB' and 'SHIFT-TAB' to traversalKeysSet in case
0542: * editor is non editable
0543: */
0544: void updateFocusTraversalKeys() {
0545: /*
0546: * Fix for 4514331 Non-editable JTextArea and similar
0547: * should allow Tab to keyboard - accessibility
0548: */
0549: Set<? extends AWTKeyStroke> storedForwardTraversalKeys = editor
0550: .getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
0551: Set<? extends AWTKeyStroke> storedBackwardTraversalKeys = editor
0552: .getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
0553: Set<? extends AWTKeyStroke> forwardTraversalKeys = new HashSet<AWTKeyStroke>(
0554: storedForwardTraversalKeys);
0555: Set<? extends AWTKeyStroke> backwardTraversalKeys = new HashSet<AWTKeyStroke>(
0556: storedBackwardTraversalKeys);
0557:
0558: forwardTraversalKeys.remove(KeyStroke.getKeyStroke(
0559: KeyEvent.VK_TAB, 0));
0560: backwardTraversalKeys.remove(KeyStroke.getKeyStroke(
0561: KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
0562:
0563: editor.setFocusTraversalKeys(
0564: KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
0565: forwardTraversalKeys);
0566: editor.setFocusTraversalKeys(
0567: KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
0568: backwardTraversalKeys);
0569: }
0570:
0571: // /**
0572: // * Returns the <code>TransferHandler</code> that will be installed if
0573: // * their isn't one installed on the <code>JTextComponent</code>.
0574: // */
0575: // TransferHandler getTransferHandler() {
0576: // return defaultTransferHandler;
0577: // }
0578:
0579: /**
0580: * Create a default action map. This is basically the
0581: * set of actions found exported by the component.
0582: */
0583: ActionMap createActionMap() {
0584: ActionMap map = new ActionMapUIResource();
0585: Action[] actions = editor.getActions();
0586: int n = actions.length;
0587:
0588: for (int i = 0; i < n; i++) {
0589: Action a = actions[i];
0590: map.put(a.getValue(Action.NAME), a);
0591: }
0592:
0593: map.put(TransferHandler.getCutAction().getValue(Action.NAME),
0594: TransferHandler.getCutAction());
0595: map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
0596: TransferHandler.getCopyAction());
0597: map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
0598: TransferHandler.getPasteAction());
0599:
0600: return map;
0601: }
0602:
0603: protected void uninstallKeyboardActions() {
0604: editor.setKeymap(null);
0605: SwingUtilities.replaceUIInputMap(editor,
0606: JComponent.WHEN_IN_FOCUSED_WINDOW, null);
0607: SwingUtilities.replaceUIActionMap(editor, null);
0608: }
0609:
0610: /**
0611: * Fetches the text component associated with this
0612: * UI implementation. This will be null until
0613: * the ui has been installed.
0614: *
0615: * @return the editor component
0616: */
0617: protected final DesignerPaneBase getComponent() {
0618: return editor;
0619: }
0620:
0621: // /**
0622: // * I'm delaying model updates while the editor is not showing. Call the
0623: // * update method when the editor is made visible to update it with deferred
0624: // * changes
0625: // */
0626: // public void update() {
0627: // if (deferred) {
0628: // resetPageBox();
0629: // deferred = false;
0630: // }
0631: // }
0632:
0633: /**
0634: * Flags model changes.
0635: * This is called whenever the model has changed.
0636: * It is implemented to rebuild the view hierarchy
0637: * to represent the default root element of the
0638: * associated model.
0639: */
0640: /*protected*/public void /*modelChanged*/resetPageBox() {
0641: // if (!editor.isShowing() && pageBox != null) { // we need pagebox to get sizes
0642: // deferred = true;
0643: // return;
0644: // }
0645: WebForm webform = editor.getWebForm();
0646: Element elem = webform.getHtmlBody();
0647:
0648: if (elem == null) {
0649: // return;
0650: // XXX #6270621
0651: setPageBox(null);
0652: } else {
0653: setPageBox(PageBox.getPageBox(editor, webform, elem));
0654: }
0655:
0656: webform.getManager().setInsertBox(null, null);
0657: }
0658:
0659: /**
0660: * Sets the current root of the view hierarchy and calls invalidate().
0661: * If there were any child components, they will be removed (i.e.
0662: * there are assumed to have come from components embedded in views).
0663: *
0664: * @param v the root view
0665: */
0666: protected final void setPageBox(PageBox box) {
0667: if (DesignerUtils.DEBUG) {
0668: DesignerUtils.debugLog(getClass().getName()
0669: + ".setPageBox(PageBox)");
0670: }
0671: // XXX #6461287.
0672: // if(box == null) {
0673: // throw(new IllegalArgumentException("Null page box."));
0674: // }
0675:
0676: if (pageBox != null) {
0677: pageBox.boxRemoved();
0678: }
0679:
0680: //editor.removeAll();
0681: pageBox = box;
0682:
0683: updateViewport();
0684: painted = false;
0685:
0686: //editor.revalidate();
0687: editor.repaint();
0688:
0689: if (pageBox != null) {
0690: pageBox.boxAdded();
0691: }
0692: }
0693:
0694: /**
0695: * Paints the interface safely with a guarantee that
0696: * the model won't change from the view of this thread.
0697: * This does the following things, rendering from
0698: * back to front.
0699: * <ol>
0700: * <li>
0701: * If the component is marked as opaque, the background
0702: * is painted in the current background color of the
0703: * component.
0704: * <li>
0705: * The highlights (if any) are painted.
0706: * <li>
0707: * The box hierarchy is painted.
0708: * <li>
0709: * The caret is painted.
0710: * </ol>
0711: *
0712: * @param g the graphics context
0713: */
0714: protected void paintSafely(Graphics g) {
0715: painted = true;
0716:
0717: long start = 0;
0718:
0719: if (DesignerPane.DEBUG_REPAINT) {
0720: start = System.currentTimeMillis();
0721: }
0722:
0723: // paint the box hierarchy
0724: Graphics2D g2d = (Graphics2D) g;
0725:
0726: // Document doc = editor.getDocument();
0727: // WebForm webform = doc.getWebForm();
0728: WebForm webform = editor.getWebForm();
0729:
0730: g.getClipBounds(DesignerPane.clip);
0731: DesignerPane.clipBr.x = DesignerPane.clip.x
0732: + DesignerPane.clip.width;
0733: DesignerPane.clipBr.y = DesignerPane.clip.y
0734: + DesignerPane.clip.height;
0735:
0736: pageBox.paint(g2d);
0737:
0738: // Draw selection handles, marquee selection, etc.
0739: webform.getManager().paint(g2d);
0740:
0741: // paint the caret
0742: // DesignerCaret caret = editor.getCaret();
0743: //
0744: // if (caret != null) {
0745: // caret.paint(g);
0746: // }
0747: if (editor.hasCaret()) {
0748: editor.paintCaret(g);
0749: }
0750:
0751: if (DesignerPane.DEBUG_REPAINT) {
0752: long end = System.currentTimeMillis();
0753: long time = end - start;
0754: long avg = (time + prev1 + prev2 + prev3) / 4;
0755: System.out.println("Paint Hierarchy: = " + (end - start)
0756: + " ms" + "; average=" + avg + " and clip was "
0757: + DesignerPane.clip);
0758: prev3 = prev2;
0759: prev2 = prev1;
0760: prev1 = avg;
0761: }
0762: }
0763:
0764: // --- ComponentUI methods --------------------------------------------
0765:
0766: /**
0767: * Installs the UI for a component. This does the following
0768: * things.
0769: * <ol>
0770: * <li>
0771: * Set the associated component to opaque (can be changed
0772: * easily by a subclass or on JTextComponent directly),
0773: * which is the most common case. This will cause the
0774: * component's background color to be painted.
0775: * <li>
0776: * Install the default caret and highlighter into the
0777: * associated component.
0778: * <li>
0779: * Attach to the editor and model. If there is no
0780: * model, a default one is created.
0781: * <li>
0782: * create the the box hierarchy used to represent the model.
0783: * </ol>
0784: *
0785: * @param c the editor component
0786: * @see ComponentUI#installUI
0787: */
0788: public void installUI(JComponent c) {
0789: if (DesignerUtils.DEBUG) {
0790: DesignerUtils.debugLog(getClass().getName()
0791: + ".installUI(JComponent)");
0792: }
0793: if (c == null) {
0794: throw (new IllegalArgumentException("Null component."));
0795: }
0796: if (c instanceof DesignerPane) {
0797: editor = (DesignerPane) c;
0798:
0799: // install defaults
0800: installDefaults();
0801:
0802: // Don't paint backgrounds - views will do that so
0803: // don't waste time painting behind the views
0804: editor.setOpaque(false);
0805: editor.setAutoscrolls(true);
0806:
0807: // // attach to the model and editor
0808: // //editor.addPropertyChangeListener(updateHandler);
0809: //// Document doc = editor.getDocument();
0810: //
0811: //// if (doc == null) {
0812: //// // no model, create a default one. This will
0813: //// // fire a notification to the updateHandler
0814: //// // which takes care of the rest.
0815: //// Thread.dumpStack();
0816: //// throw new RuntimeException("Not yet implemented");
0817: ////
0818: //// //editor.setDocument(getEditorKit(editor).createDefaultDocument());
0819: //// } else {
0820: // resetPageBox();
0821: //// }
0822:
0823: // if (DesignerPane.debugclip) {
0824: // editor.addKeyListener(updateHandler);
0825: // }
0826: // install keymap
0827: installListeners();
0828: installKeyboardActions();
0829:
0830: // XXX This should no longer be necessary!
0831:
0832: /*
0833: LayoutManager oldLayout = editor.getLayout();
0834: if ((oldLayout == null) || (oldLayout instanceof UIResource)) {
0835: // by default, use default LayoutManger implementation that
0836: // will position the components associated with a View object.
0837: editor.setLayout(updateHandler);
0838: }
0839: */
0840: } else {
0841: throw new Error("DesignerPaneBaseUI needs DesignerPaneBase");
0842: }
0843: }
0844:
0845: /**
0846: * Deinstalls the UI for a component. This removes the listeners,
0847: * uninstalls the highlighter, removes views, and nulls out the keymap.
0848: *
0849: * @param c the editor component
0850: * @see ComponentUI#uninstallUI
0851: */
0852: public void uninstallUI(JComponent c) {
0853: if (DesignerUtils.DEBUG) {
0854: DesignerUtils.debugLog(getClass().getName()
0855: + ".uninstallUI(JComponent)");
0856: }
0857: if (c == null) {
0858: throw (new IllegalArgumentException("Null component."));
0859: }
0860:
0861: // detach from the model
0862: // if (DesignerPane.debugclip) {
0863: // editor.removeKeyListener(updateHandler);
0864: // }
0865: // view part
0866: painted = false;
0867: uninstallDefaults();
0868:
0869: /*
0870: c.removeAll();
0871: LayoutManager lm = c.getLayout();
0872: if (lm instanceof UIResource) {
0873: c.setLayout(null);
0874: }
0875: */
0876: // controller part
0877: uninstallKeyboardActions();
0878: uninstallListeners();
0879: }
0880:
0881: /**
0882: * Superclass paints background in an uncontrollable way
0883: * (i.e. one might want an image tiled into the background).
0884: * To prevent this from happening twice, this method is
0885: * reimplemented to simply paint.
0886: * <p>
0887: * <em>NOTE:</em> Superclass is also not thread-safe in
0888: * it's rendering of the background, although that's not
0889: * an issue with the default rendering.
0890: */
0891: public void update(Graphics g, JComponent c) {
0892: paint(g, c);
0893: }
0894:
0895: /**
0896: * Paints the interface. This is routed to the
0897: * paintSafely method under the guarantee that
0898: * the model won't change from the view of this thread
0899: * while it's rendering (if the associated model is
0900: * derived from AbstractDocument). This enables the
0901: * model to potentially be updated asynchronously.
0902: *
0903: * @param g the graphics context
0904: * @param c the editor component
0905: */
0906: public final void paint(Graphics g, JComponent c) {
0907: if (pageBox != null) {
0908: // Document doc = editor.getDocument();
0909: // WebForm webform = doc.getWebForm();
0910: WebForm webform = editor.getWebForm();
0911:
0912: // if (webform.getMarkup() == null) {
0913: // return;
0914: // }
0915: //
0916: // if (!webform.getModel().isValid()) {
0917: // return;
0918: // }
0919: // XXX Model validity shouldn't be checked here.
0920: // if (!webform.isModelValid()) {
0921: // return;
0922: // }
0923:
0924: // XXX There should be no locking here, the designer is not thread safe (it should run in AWT thread only).
0925: // // XXX Gotta lock using InsyncDocument instead!!!
0926: //// doc.readLock();
0927: // // XXX Why locking when painting??
0928: //// webform.getMarkup().readLock();
0929: // webform.readLock();
0930:
0931: try {
0932: paintSafely(g);
0933: } catch (Exception ex) {
0934: log(ex);
0935: // } finally {
0936: // // XXX Gotta unlock using InsyncDocument instead!!!
0937: // // IF YOU GET HERE DURING DEBUGGING you just stepped over
0938: // // an assertion that failed! Check console/log.
0939: //// doc.readUnlock();
0940: //// webform.getMarkup().readUnlock();
0941: // webform.readUnlock();
0942: }
0943: }
0944: }
0945:
0946: /**
0947: * Gets the preferred size for the editor component. If the component
0948: * has been given a size prior to receiving this request, it will
0949: * set the size of the box hierarchy to reflect the size of the component
0950: * before requesting the preferred size of the view hierarchy. This
0951: * allows formatted views to format to the current component size before
0952: * answering the request. Other views don't care about currently formatted
0953: * size and give the same answer either way.
0954: *
0955: * @param c the editor component
0956: * @return the size
0957: */
0958: public Dimension getPreferredSize(JComponent c) {
0959: if (DesignerUtils.DEBUG) {
0960: DesignerUtils.debugLog(getClass().getName()
0961: + ".getPreferredSize(JComponent)");
0962: }
0963: if (c == null) {
0964: throw (new IllegalArgumentException("Null component."));
0965: }
0966:
0967: // Document doc = editor.getDocument();
0968: Insets i = c.getInsets();
0969: Dimension d = c.getSize();
0970:
0971: // if ((pageBox == null) || (doc.getWebForm().getMarkup() == null)) {
0972: if (pageBox == null) {
0973: return d;
0974: }
0975:
0976: //System.out.println("DesignerPaneUI.getPreferredSize()");
0977: //System.out.println(" i=" + i);
0978: //System.out.println(" d=" + d);
0979: //System.out.println(" d.width=" + d.width);
0980: //System.out.println(" i.left=" + i.left);
0981: //System.out.println(" i.right=" + i.right);
0982: //System.out.println(" d.width-i.left-i.right=" + (d.width-i.left-i.right));
0983: // XXX There should be no locking here, the designer is not thread safe (it should run in AWT thread only).
0984: // // XXX Lock insync
0985: //// doc.readLock();
0986: // WebForm webform = editor.getWebForm();
0987: //// webform.getMarkup().readLock();
0988: // webform.readLock();
0989: //
0990: // try {
0991: if ((d.width > (i.left + i.right))
0992: && (d.height > (i.top + i.bottom))) {
0993: //System.out.println("SETTING SIZE first");
0994: pageBox.setSize(d.width - i.left - i.right, d.height
0995: - i.top - i.bottom);
0996: } else if ((d.width == 0) && (d.height == 0)) {
0997: //System.out.println("width=0 and height=0 - so setting to MAX_VALUE = " + Integer.MAX_VALUE);
0998: // Probably haven't been layed out yet, force some sort of
0999: // initial sizing.
1000: pageBox.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
1001:
1002: //pageBox.setSize(1024, 768);
1003: //pageBox.setSize(50,50);
1004: }
1005:
1006: d.width = (int) Math.min((long) pageBox
1007: .getPreferredSpan(CssBox.X_AXIS)
1008: + (long) i.left + (long) i.right, Integer.MAX_VALUE);
1009: d.height = (int) Math.min((long) pageBox
1010: .getPreferredSpan(CssBox.Y_AXIS)
1011: + (long) i.top + (long) i.bottom, Integer.MAX_VALUE);
1012:
1013: //System.out.println("Newly computed preferred span: " + d);
1014: // } finally {
1015: // // XXX Unlock insync
1016: //// doc.readUnlock();
1017: //// webform.getMarkup().readUnlock();
1018: // webform.readUnlock();
1019: // }
1020:
1021: return d;
1022: }
1023:
1024: /**
1025: * Gets the minimum size for the editor component.
1026: *
1027: * @param c the editor component
1028: * @return the size
1029: */
1030: public Dimension getMinimumSize(JComponent c) {
1031: if (DesignerUtils.DEBUG) {
1032: DesignerUtils.debugLog(getClass().getName()
1033: + ".getMinimumSize(JComponent)");
1034: }
1035: if (c == null) {
1036: throw (new IllegalArgumentException("Null component."));
1037: }
1038:
1039: // Document doc = editor.getDocument();
1040: Insets i = c.getInsets();
1041: Dimension d = new Dimension();
1042:
1043: // if ((pageBox == null) || (doc.getWebForm().getMarkup() == null)) {
1044: if (pageBox == null) {
1045: return d;
1046: }
1047:
1048: // XXX There should be no locking here, the designer is not thread safe (it should run in AWT thread only).
1049: // // XXX Lock insync
1050: //// doc.readLock();
1051: // WebForm webform = editor.getWebForm();
1052: //// webform.getMarkup().readLock();
1053: // webform.readLock();
1054: //
1055: // try {
1056: d.width = (int) pageBox.getMinimumSpan(CssBox.X_AXIS) + i.left
1057: + i.right;
1058: d.height = (int) pageBox.getMinimumSpan(CssBox.Y_AXIS) + i.top
1059: + i.bottom;
1060: // } finally {
1061: // // XXX Unlock insync
1062: //// doc.readUnlock();
1063: //// webform.getMarkup().readUnlock();
1064: // webform.readUnlock();
1065: // }
1066:
1067: return d;
1068: }
1069:
1070: /**
1071: * Gets the maximum size for the editor component.
1072: *
1073: * @param c the editor component
1074: * @return the size
1075: */
1076: public Dimension getMaximumSize(JComponent c) {
1077: if (DesignerUtils.DEBUG) {
1078: DesignerUtils.debugLog(getClass().getName()
1079: + ".getMaximumSize(JComponent)");
1080: }
1081: if (c == null) {
1082: throw (new IllegalArgumentException("Null component."));
1083: }
1084:
1085: // Document doc = editor.getDocument();
1086: Insets i = c.getInsets();
1087: Dimension d = new Dimension();
1088:
1089: // if ((pageBox == null) || (doc.getWebForm().getMarkup() == null)) {
1090: if (pageBox == null) {
1091: return d;
1092: }
1093:
1094: // XXX There should be no locking here, the designer is not thread safe (it should run in AWT thread only).
1095: // // XXX Lock insync
1096: //// doc.readLock();
1097: // WebForm webform = editor.getWebForm();
1098: //// webform.getMarkup().readLock();
1099: // webform.readLock();
1100: //
1101: // try {
1102: d.width = (int) Math.min((long) pageBox
1103: .getMaximumSpan(CssBox.X_AXIS)
1104: + (long) i.left + (long) i.right, Integer.MAX_VALUE);
1105: d.height = (int) Math.min((long) pageBox
1106: .getMaximumSpan(CssBox.Y_AXIS)
1107: + (long) i.top + (long) i.bottom, Integer.MAX_VALUE);
1108: // } finally {
1109: // // XXX Unlock insync
1110: //// doc.readUnlock();
1111: //// webform.getMarkup().readUnlock();
1112: // webform.readUnlock();
1113: // }
1114:
1115: return d;
1116: }
1117:
1118: // ---- DesignerPaneBaseUI methods -------------------------------------------
1119:
1120: // XXX Moved to WebForm.
1121: // /**
1122: // * Converts the given location in the model to a place in
1123: // * the view coordinate system.
1124: // * The component must have a non-zero positive size for
1125: // * this translation to be computed.
1126: // *
1127: // * @param tc the text component for which this UI is installed
1128: // * @param pos the local location in the model to translate >= 0
1129: // * @return the coordinates as a rectangle, null if the model is not painted
1130: // * @exception BadLocationException if the given position does not
1131: // * represent a valid location in the associated document
1132: // * @see DesignerPaneBaseUI#modelToView
1133: // */
1134: // public Rectangle modelToView(/*DesignerPaneBase tc,*/ Position pos) {
1135: // if(DesignerUtils.DEBUG) {
1136: // DesignerUtils.debugLog(getClass().getName() + ".modelToView(DesignerPaneBase, Position)");
1137: // }
1138: //// if(tc == null) {
1139: //// throw(new IllegalArgumentException("Null designer pane."));
1140: //// }
1141: // if(pos == null) {
1142: // throw(new IllegalArgumentException("Null position."));
1143: // }
1144: //
1145: // WebForm webform = editor.getWebForm();
1146: //
1147: //// if (!webform.getModel().isValid()) {
1148: // if (!webform.isModelValid()) {
1149: // return null;
1150: // }
1151: //
1152: //// Document doc = editor.getDocument();
1153: //
1154: // // XXX Lock insync
1155: //// doc.readLock();
1156: //// webform.getMarkup().readLock();
1157: // webform.readLock();
1158: //
1159: // try {
1160: //// return pageBox.modelToView(pos);
1161: // return ModelViewMapper.modelToView(pageBox, pos);
1162: // } finally {
1163: // // XXX Unlock insync
1164: //// doc.readUnlock();
1165: //// webform.getMarkup().readUnlock();
1166: // webform.readUnlock();
1167: // }
1168: // }
1169: //
1170: // /**
1171: // * Converts the given place in the view coordinate system
1172: // * to the nearest representative location in the model.
1173: // * The component must have a non-zero positive size for
1174: // * this translation to be computed.
1175: // *
1176: // * @param tc the text component for which this UI is installed
1177: // * @param pt the location in the view to translate. This
1178: // * should be in the same coordinate system as the mouse events.
1179: // * @return the offset from the start of the document >= 0,
1180: // * -1 if not painted
1181: // * @see DesignerPaneBaseUI#viewToModel
1182: // */
1183: // public Position viewToModel(DesignerPaneBase tc, Point pt) {
1184: // Position pos = Position.NONE;
1185: // Document doc = editor.getDocument();
1186: //
1187: // // XXX Lock insync
1188: //// doc.readLock();
1189: // WebForm webform = editor.getWebForm();
1190: //// webform.getMarkup().readLock();
1191: // webform.readLock();
1192: //
1193: // try {
1194: // pos = ModelViewMapper.viewToModel(doc.getWebForm(), pt.x, pt.y); //, alloc, biasReturn);
1195: //
1196: // // I'm now relying on clients to do this themselves!
1197: // //assert offs == Position.NONE || Position.isSourceNode(offs.getNode());
1198: // } finally {
1199: //// doc.readUnlock();
1200: //// webform.getMarkup().readUnlock();
1201: // webform.readUnlock();
1202: // }
1203: //
1204: // return pos;
1205: // }
1206:
1207: /**
1208: * Provides a way to determine the next visually represented model
1209: * location that one might place a caret. Some views may not be visible,
1210: * they might not be in the same order found in the model, or they just
1211: * might not allow access to some of the locations in the model.
1212: *
1213: * @param pos the position to convert >= 0
1214: * @param a the allocated region to render into
1215: * @param direction the direction from the current position that can
1216: * be thought of as the arrow keys typically found on a keyboard.
1217: * This may be SwingConstants.WEST, SwingConstants.EAST,
1218: * SwingConstants.NORTH, or SwingConstants.SOUTH.
1219: * @return the location within the model that best represents the next
1220: * location visual position.
1221: * @exception BadLocationException
1222: * @exception IllegalArgumentException for an invalid direction
1223: */
1224: // public Position getNextVisualPositionFrom(DesignerPaneBase t, Position pos, int direction) {
1225: public DomPosition getNextVisualPositionFrom(DesignerPaneBase t,
1226: DomPosition pos, int direction) {
1227: if (DesignerUtils.DEBUG) {
1228: DesignerUtils
1229: .debugLog(getClass().getName()
1230: + ".getNextVisualPositionFrom(DesignerPaneBase, Position, int)");
1231: }
1232: if (t == null) {
1233: throw (new IllegalArgumentException("Null designer pane."));
1234: }
1235: if (pos == null) {
1236: throw (new IllegalArgumentException("Null position."));
1237: }
1238:
1239: // Document doc = editor.getDocument();
1240:
1241: // XXX There should be no locking here, the designer is not thread safe (it should run in AWT thread only).
1242: // // XXX Lock insync
1243: //// doc.readLock();
1244: // WebForm webform = editor.getWebForm();
1245: //// webform.getMarkup().readLock();
1246: // webform.readLock();
1247: //
1248: // try {
1249: if (painted) {
1250: // ModelViewMapper mapper = doc.getWebForm().getMapper();
1251: WebForm webform = editor.getWebForm();
1252:
1253: switch (direction) {
1254: case SwingConstants.WEST:
1255: // return ModelViewMapper.computeArrowLeft(doc.getWebForm(), pos);
1256: return ModelViewMapper.computeArrowLeft(webform, pos);
1257: case SwingConstants.EAST:
1258: // return ModelViewMapper.computeArrowRight(doc.getWebForm(), pos);
1259: return ModelViewMapper.computeArrowRight(webform, pos);
1260: case SwingConstants.NORTH:
1261: // return ModelViewMapper.computeArrowUp(doc.getWebForm(), pos);
1262: return ModelViewMapper.computeArrowUp(webform, pos);
1263: case SwingConstants.SOUTH:
1264: // return ModelViewMapper.computeArrowDown(doc.getWebForm(), pos);
1265: return ModelViewMapper.computeArrowDown(webform, pos);
1266: }
1267:
1268: // return Position.NONE;
1269: return DomPosition.NONE;
1270: }
1271: // } finally {
1272: //// doc.readUnlock();
1273: //// webform.getMarkup().readUnlock();
1274: // webform.readUnlock();
1275: // }
1276:
1277: // return Position.NONE;
1278: return DomPosition.NONE;
1279: }
1280:
1281: /** Check the parent and see if we have a view port - if so, notify
1282: * the page box.
1283: */
1284: void updateViewport() {
1285: JViewport viewport = null;
1286: Component parent = editor.getParent();
1287:
1288: //System.out.println("updateViewport: Component parent=" + parent + " and it's an instanceof JViewport: " + (parent instanceof JViewport));
1289: if (parent instanceof JViewport) {
1290: viewport = (JViewport) parent;
1291:
1292: //System.out.println("--------------------------------------------------------------------------------\nFOUND VIEWPORT:" + viewport);
1293: }
1294:
1295: if (pageBox != null) {
1296: pageBox.setViewport(viewport);
1297: }
1298: }
1299:
1300: //private static final TextDragGestureRecognizer defaultDragRecognizer = new TextDragGestureRecognizer();
1301:
1302: /**
1303: * Registered in the ActionMap.
1304: */
1305: class FocusAction extends AbstractAction {
1306: public void actionPerformed(ActionEvent e) {
1307: editor.requestFocus();
1308: }
1309:
1310: public boolean isEnabled() {
1311: return true;
1312: }
1313: }
1314:
1315: /**
1316: * Drag gesture recognizer for text components.
1317: */
1318: static class TextDragGestureRecognizer extends
1319: BasicDragGestureRecognizer {
1320: /**
1321: * Determines if the following are true:
1322: * <ul>
1323: * <li>the press event is located over a selection
1324: * <li>the dragEnabled property is true
1325: * <li>A TranferHandler is installed
1326: * </ul>
1327: * <p>
1328: * This is implemented to check for a TransferHandler.
1329: * Subclasses should perform the remaining conditions.
1330: */
1331: protected boolean isDragPossible(MouseEvent e) {
1332: if (super .isDragPossible(e)) {
1333: DesignerPaneBase c = (DesignerPaneBase) this
1334: .getComponent(e);
1335:
1336: // DesignerCaret caret = c.getCaret();
1337: // if (caret == null) {
1338: // return false;
1339: // }
1340: if (!c.hasCaret()) {
1341: return false;
1342: }
1343:
1344: // Position dot = caret.getDot();
1345: // Position mark = caret.getMark();
1346: // DomPosition dot = caret.getDot();
1347: // DomPosition mark = caret.getMark();
1348: DomPosition dot = c.getCaretDot();
1349: DomPosition mark = c.getCaretMark();
1350:
1351: if (!dot.equals(mark)) {
1352: Point p = new Point(e.getX(), e.getY());
1353: // Position pos = c.viewToModel(p);
1354: WebForm webform = ((DesignerPane) c).getWebForm();
1355: // Position pos = webform.viewToModel(p);
1356: DomPosition pos = webform.viewToModel(p);
1357:
1358: if ((webform.getManager().getInlineEditor() == null)
1359: || !webform.getManager().getInlineEditor()
1360: .isDocumentEditor()) {
1361: boolean findNearest = !webform.isGridMode();
1362: // pos = DesignerUtils.checkPosition(pos, findNearest, /*webform*/webform.getManager().getInlineEditor());
1363: // pos = ModelViewMapper.findValidPosition(pos, findNearest, /*webform*/webform.getManager().getInlineEditor());
1364: pos = ModelViewMapper.findValidPosition(
1365: webform, pos, findNearest, /*webform*/
1366: webform.getManager().getInlineEditor());
1367: }
1368:
1369: // Position p0 = Position.first(dot, mark);
1370: // Position p1 = Position.last(dot, mark);
1371: DomPosition p0 = webform.first(dot, mark);
1372: DomPosition p1 = webform.last(dot, mark);
1373:
1374: if ((pos.isLaterThan(p0))
1375: && (pos.isStrictlyEarlierThan(p1))) {
1376: return true;
1377: }
1378: }
1379: }
1380:
1381: return false;
1382: }
1383: }
1384:
1385: /**
1386: * Show a caret under the nearest insert location. Returns the
1387: * nearest caret location, or Position.NONE if you're not over
1388: * a flow text area. Call with p = null to remove the caret
1389: * when done.
1390: */
1391:
1392: /*
1393: public Position showInsertionLocation(Point p) {
1394: TextDropTargetListener dropListener = getDropTargetListener();
1395: return dropListener.updateInsertionLocation(getComponent(), p);
1396: }
1397: */
1398:
1399: /**
1400: * A DropTargetListener to extend the default Swing handling of drop operations
1401: * by moving the caret to the nearest location to the mouse pointer.
1402: */
1403: static class TextDropTargetListener extends BasicDropTargetListener {
1404: // /**
1405: // * called to set the insertion location to match the current
1406: // * mouse pointer coordinates.
1407: // */
1408: // protected Position updateInsertionLocation(JComponent comp, Point p) {
1409: // // In grid mode, no visible caret
1410: // // J1 HACK: TODO - look up mode from DesignerPane instance instead
1411: // DesignerPane pane = (DesignerPane)comp;
1412: //// if (pane.getWebForm().isGridMode()) {
1413: //// // XXX what about scrolling view when you get near the bottom
1414: //// // or near the top?
1415: //// return Position.NONE;
1416: //// }
1417: // Position pos = Position.NONE;
1418: // if (p != null && Utilities.isCaretArea(pane.getWebForm(), p.x, p.y)) {
1419: // pos = pane.viewToModel(p);
1420: // WebForm webform = ((DesignerPane)comp).getWebForm();
1421: // if (webform.getSelection().getInlineEditor() == null ||
1422: // !webform.getSelection().getInlineEditor().isDocumentEditor()) {
1423: // boolean findNearest = !webform.isGridMode();
1424: // pos = Utilities.checkPosition(pos, findNearest, webformwebform.getManager().getInlineEditor());
1425: // }
1426: // }
1427: // if (pos != Position.NONE && FacesSupport.isBelowRendersChildren(pos)) {
1428: // pos = Position.NONE;
1429: // }
1430: // if (pos != Position.NONE) {
1431: // if (pane.getCaret() == null) {
1432: // DesignerCaret dc = pane.getPaneUI().createCaret();
1433: // pane.setCaret(dc);
1434: // }
1435: // pane.getCaret().setVisible(true);
1436: // pane.setCaretPosition(pos);
1437: // } else if (pane.getWebForm().getDocument().isGridMode()) {
1438: // if (pane.getCaret() != null) {
1439: // pane.setCaret(null);
1440: // }
1441: // }
1442: // return pos;
1443: // }
1444: // Position dot = Position.NONE; // XXX Shouldn't that be startPos instead?
1445: // Position mark = Position.NONE; // XXX Shouldn't that be startPos instead?
1446: DomPosition dot = DomPosition.NONE; // XXX Shouldn't that be startPos instead?
1447: DomPosition mark = DomPosition.NONE; // XXX Shouldn't that be startPos instead?
1448:
1449: boolean visible;
1450:
1451: /**
1452: * called to save the state of a component in case it needs to
1453: * be restored because a drop is not performed.
1454: * @todo Anything else we should do here for the designer?
1455: */
1456: protected void saveComponentState(JComponent comp) {
1457: DesignerPaneBase c = (DesignerPaneBase) comp;
1458: // DesignerCaret caret = c.getCaret();
1459: // if (caret != null) {
1460: // dot = caret.getDot();
1461: // mark = caret.getMark();
1462: // visible = caret.isVisible();
1463: // }
1464: if (c.hasCaret()) {
1465: dot = c.getCaretPosition();
1466: mark = c.getCaretMark();
1467: visible = c.isCaretVisible();
1468: }
1469:
1470: // In grid mode, no visible caret
1471: // J1 HACK: TODO - look up mode from DesignerPane instance instead
1472: DesignerPane pane = (DesignerPane) comp;
1473:
1474: // if ((caret != null) && !pane.getWebForm().isGridMode()) {
1475: // caret.setVisible(true);
1476: // }
1477: if (c.hasCaret() && !pane.getWebForm().isGridMode()) {
1478: c.setCaretVisible(true);
1479: }
1480: }
1481:
1482: /**
1483: * called to restore the state of a component
1484: * because a drop was not performed.
1485: */
1486: protected void restoreComponentState(JComponent comp) {
1487: DesignerPaneBase c = (DesignerPaneBase) comp;
1488: // DesignerCaret caret = c.getCaret();
1489: // if (caret != null) {
1490: // caret.setDot(mark);
1491: // caret.moveDot(dot);
1492: // caret.setVisible(visible);
1493: // }
1494: if (c.hasCaret()) {
1495: c.setCaretDot(mark);
1496: c.moveCaretDot(dot);
1497: c.setCaretVisible(visible);
1498: }
1499: }
1500:
1501: /**
1502: * called to restore the state of a component
1503: * because a drop was performed.
1504: */
1505: protected void restoreComponentStateForDrop(JComponent comp) {
1506: DesignerPaneBase c = (DesignerPaneBase) comp;
1507: // DesignerCaret caret = c.getCaret();
1508: // if (caret != null) {
1509: // caret.setVisible(visible);
1510: // }
1511: if (c.hasCaret()) {
1512: c.setCaretVisible(visible);
1513: }
1514: }
1515: }
1516:
1517: private static void log(Exception ex) {
1518: Logger logger = getLogger();
1519: logger.log(Level.INFO, null, ex);
1520: }
1521:
1522: private static Logger getLogger() {
1523: return Logger.getLogger(DesignerPaneUI.class.getName());
1524: }
1525: }
|