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:
0042: package org.netbeans.modules.visualweb.designer;
0043:
0044: import java.awt.BasicStroke;
0045: import java.awt.Cursor;
0046: import java.awt.Dimension;
0047: import java.awt.FontMetrics;
0048: import java.awt.Graphics2D;
0049: import java.awt.Image;
0050: import java.awt.Point;
0051: import java.awt.Rectangle;
0052: import java.awt.Stroke;
0053: import java.awt.event.ActionEvent;
0054: import java.awt.event.ActionListener;
0055: import java.awt.geom.AffineTransform;
0056: import java.util.ArrayList;
0057: import java.util.HashSet;
0058: import java.util.Iterator;
0059: import java.util.List;
0060: import java.util.Set;
0061: import javax.swing.JViewport;
0062: import javax.swing.SwingUtilities;
0063: import javax.swing.Timer;
0064: import org.netbeans.modules.visualweb.api.designer.Designer;
0065: import org.netbeans.modules.visualweb.api.designer.Designer.Box;
0066: import org.netbeans.modules.visualweb.api.designer.Designer.DesignerEvent;
0067:
0068: import org.netbeans.modules.visualweb.api.designer.DomProviderService.ResizeConstraint;
0069: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition;
0070: import org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition.Bias;
0071: import org.netbeans.modules.visualweb.css2.BoxType;
0072: import org.netbeans.modules.visualweb.css2.CssBox;
0073: import org.netbeans.modules.visualweb.css2.ExternalDocumentBox;
0074: import org.netbeans.modules.visualweb.css2.ModelViewMapper;
0075: import org.netbeans.modules.visualweb.css2.PageBox;
0076: import org.netbeans.modules.visualweb.designer.html.HtmlTag;
0077:
0078: import org.openide.ErrorManager;
0079: import org.openide.nodes.Node;
0080:
0081: import org.w3c.dom.Element;
0082:
0083: /**
0084: * This class is the central point for handling selections, mouse interactions,
0085: * keyboard interactions, etc., with the page editor / the WYSIWYG designer.
0086: * It for example listens to mouse events and decides whether this translates
0087: * into a change in selected components, or a drag of a component, etc.
0088: *
0089: * <p>
0090: * This class manages selections in the page designer.
0091: *
0092: * <p>
0093: * @todo Rename this class to "InteractionManager", formalize the remaining interactions
0094: * that aren't using the Interaction interface yet (like InlineEditors, selection cycling),
0095: * pull the selection-set specific code into a separate SelectionHandler (set & painter),
0096: * pull the utility methods into the Utilities class.
0097: * @todo Handle getComponentBounds replacement to getComponentRectangles
0098: * later! And speed up caching of component rectangle list!
0099: * @todo Get rid of all traces of "View" in the selection handling!
0100: * @todo Remove the inlineEditor (finish it) if the user deletes a component! Even via the
0101: * app outline! (perhaps only if it's the component we're inline editing or some child of it)
0102: * <p>
0103: *
0104: * @author Tor Norbye
0105: */
0106: public class SelectionManager {
0107: // The source file is organized into groups of related functionality:
0108: // mouse handling, painting, selection manipulation, etc.
0109: // Please keep this in mind when editing the file - don't just add
0110: // methods at the end of the file for example.
0111: private static final int NODE_REFRESH_DELAY = 300; // ms
0112:
0113: // Dreamweaver-like hierarchy bar
0114: static final boolean PAINT_SELECTION_HIERARCHY = System
0115: .getProperty("designer.paintSelHierarchy") != null; // NOI18N
0116:
0117: /** Width/height of the selection handles - these are drawn at
0118: * all four corners and the middle of all four edges */
0119: private static final int BARSIZE = 5;
0120: private static final int SELECTIONVIEW_LEFT = 1;
0121: private BasicStroke selStroke;
0122: private final WebForm webform;
0123: // private DocumentComp documentComponent = null;
0124:
0125: // /** Set of selected objects. Contains FormObjects only. */
0126: // private Set<FormObject> selected = new HashSet<FormObject>();
0127:
0128: // private final Set<SelectedComponent> selectedComponents = new HashSet<SelectedComponent>();
0129: private final List<SelectedComponent> selectedComponents = new ArrayList<SelectedComponent>();
0130:
0131: // /** The "primary" selected object - e.g. you may have selected
0132: // 10 components, but the most recently clicked one is the
0133: // primary item. Right clicking on an item makes it the primary. */
0134: // private MarkupDesignBean primary = null;
0135: // /** Previous selection, in case new selected item is an ancestor
0136: // * of the previously selected item
0137: // */
0138: // private MarkupDesignBean leaf = null;
0139: /** The "primary" selected object - e.g. you may have selected
0140: 10 components, but the most recently clicked one is the
0141: primary item. Right clicking on an item makes it the primary. */
0142: private Element primary = null;
0143: /** Previous selection, in case new selected item is an ancestor
0144: * of the previously selected item
0145: */
0146: private Element leaf = null;
0147:
0148: private AffineTransform transform = new AffineTransform();
0149: private boolean paintBeanIcon = false;
0150: int selectionViewPos = Integer.MAX_VALUE;
0151: private Timer refreshTimer;
0152:
0153: // private Node[] prevNodes = null;
0154:
0155: // /** When set, ignore selection requests */
0156: // private boolean ignoreSelection;
0157:
0158: SelectionManager(WebForm webform) {
0159: this .webform = webform;
0160:
0161: webform.getPane();
0162: }
0163:
0164: /** Clear out the selection - after this has run,
0165: * no components are selected
0166: * @param update If true, update property sheets etc. to reflect
0167: * the new selection.
0168: */
0169: public void clearSelection(boolean update) {
0170: selectionViewPos = Integer.MAX_VALUE;
0171: leaf = null;
0172:
0173: // if ((selected == null) || (selected.size() == 0)) {
0174: if (selectedComponents.isEmpty()) {
0175: if (update) { // XXX why are we doing this? It should already be correct
0176: // updateSelection();
0177: updateNodes();
0178:
0179: // is a repaint needed?
0180: }
0181:
0182: return;
0183: }
0184:
0185: // selected = new HashSet<FormObject>();
0186: selectedComponents.clear();
0187:
0188: primary = null;
0189:
0190: if (update) {
0191: // updateSelection();
0192: updateNodes();
0193: // webform.getTopComponent().disableCutCopyDelete(); // not true for paste
0194: // webform.tcDisableCutCopyDelete();
0195: webform.getPane().repaint();
0196: }
0197: }
0198:
0199: /** XXX Altered copy of clear selection, to immediatelly update the nodes.
0200: * FIXME Get rid of the delayed node updates. */
0201: public void clearSelectionImmediate() {
0202: selectionViewPos = Integer.MAX_VALUE;
0203: leaf = null;
0204:
0205: // if ((selected == null) || (selected.size() == 0)) {
0206: if (selectedComponents.isEmpty()) {
0207: // XXX why are we doing this? It should already be correct
0208: updateSelectionImmediate();
0209:
0210: // is a repaint needed?
0211: return;
0212: }
0213:
0214: // selected = new HashSet<FormObject>();
0215: selectedComponents.clear();
0216: primary = null;
0217:
0218: updateSelectionImmediate();
0219: // webform.getTopComponent().disableCutCopyDelete(); // not true for paste
0220: // webform.tcDisableCutCopyDelete();
0221: webform.getPane().repaint();
0222: }
0223:
0224: // /** Update IDE to visually reflect the current selection */
0225: // public void updateSelection() {
0226: // updateNodes();
0227: //
0228: //// updateSelectionInOldOutline();
0229: // }
0230:
0231: public void updateSelectionImmediate() {
0232: updateNodesImmediate();
0233:
0234: // updateSelectionInOldOutline();
0235: }
0236:
0237: // // XXX Get rid of this method after getting rid of old outline.
0238: // private void updateSelectionInOldOutline() {
0239: // // Sync document outline view
0240: // if ((selected == null) || (selected.size() == 0)) {
0241: //// OutlineTopComp.getInstance().selectBeans(null);
0242: // } else {
0243: // DesignBean[] lbs = new DesignBean[selected.size()];
0244: // Iterator it = selected.iterator();
0245: // int index = 0;
0246: //
0247: // while (it.hasNext()) {
0248: // FormObject fob = (FormObject)it.next();
0249: // lbs[index++] = fob.component;
0250: // }
0251: //
0252: // try {
0253: // ignoreSelection = true;
0254: //// OutlineTopComp.getInstance().selectBeans(lbs);
0255: // } finally {
0256: // ignoreSelection = false;
0257: // }
0258: // }
0259: //
0260: // // TODO: Move enable/disable cut,copy,delete into this method!
0261: // }
0262:
0263: /** Synchronize the selection with the model. This should be called
0264: * when DesignBeans may have changed underneath us, for example because
0265: * the user modified the backing file, and it's reparsed by insync.
0266: * At this point the DesignBeans we're pointing to in our selection set
0267: * may be stale, so for each selected bean check if it's still live
0268: * and if not, find its new representative if any.
0269: * @param update If true, update property sheets etc. to reflect
0270: * the new selection.
0271: */
0272: public void syncSelection(boolean update) {
0273: // if ((selected == null) || (selected.size() == 0)) {
0274: if (selectedComponents.isEmpty()) {
0275: return;
0276: }
0277:
0278: leaf = null;
0279: selectionViewPos = Integer.MAX_VALUE;
0280: primary = null;
0281:
0282: // LiveUnit unit = webform.getModel().getLiveUnit();
0283:
0284: // Iterator it = selected.iterator();
0285: // List<FormObject> remove = new ArrayList<FormObject>();
0286:
0287: // while (it.hasNext()) {
0288: // FormObject fo = (FormObject)it.next();
0289: // for (FormObject fo : selected) {
0290: //
0291: // if (fo.component != null) {
0292: // // Gotta find the new DesignBean for bean fo.component
0293: // MarkupDesignBean oldBean = fo.component;
0294: // // XXX Big architectural flaw, the model itself is not consistent (doesn't fire changes about itself),
0295: // // one needs to get 'newer' beans from the 'old' ones.
0296: // // TODO find out better solution.
0297: //// fo.component = (MarkupDesignBean)unit.getBeanEquivalentTo(oldBean);
0298: // fo.component = webform.getMarkupDesignBeanEquivalentTo(oldBean);
0299: //
0300: // if (fo.component == null) {
0301: // remove.add(fo);
0302: // }
0303: // }
0304: // }
0305:
0306: List<SelectedComponent> remove = new ArrayList<SelectedComponent>();
0307: for (SelectedComponent sc : selectedComponents) {
0308: if (sc.componentRootElement != null) {
0309: // Gotta find the new DesignBean for bean fo.component
0310: Element oldComponentRootElement = sc.componentRootElement;
0311: // XXX Big architectural flaw, the model itself is not consistent (doesn't fire changes about itself),
0312: // one needs to get 'newer' beans from the 'old' ones.
0313: // TODO find out better solution.
0314: // fo.component = (MarkupDesignBean)unit.getBeanEquivalentTo(oldBean);
0315: sc.componentRootElement = webform
0316: .getComponentRootElementEquivalentTo(oldComponentRootElement);
0317:
0318: if (sc.componentRootElement == null) {
0319: remove.add(sc);
0320: }
0321: }
0322: }
0323:
0324: // Remove the items in the selection hashmap that we couldn't find
0325: // a new DesignBean for. Not done during the iteration since it confuses
0326: // the iterator.
0327: // it = remove.iterator();
0328: //
0329: // while (it.hasNext()) {
0330: // for (FormObject fo : remove) {
0331: //// FormObject fo = (FormObject)it.next();
0332: // selected.remove(fo);
0333: // }
0334: for (SelectedComponent sc : remove) {
0335: selectedComponents.remove(sc);
0336: }
0337:
0338: webform.getPane().repaint(); // XXX should this only be done for update=true?
0339:
0340: if (update) {
0341: // updateSelection();
0342: updateNodes();
0343:
0344: // XXX why are we disabling cut copy paste? That depends on the
0345: // selection, doesn't it?
0346: // webform.getTopComponent().disableCutCopyDelete(); // not true for paste
0347: // webform.tcDisableCutCopyDelete();
0348: }
0349: }
0350:
0351: // /** After a sync, try to position the caret close to where it was,
0352: // * and if not, hide the caret
0353: // * Hmmmmmm shouldn't hide the caret in flow mode!
0354: // */
0355: // public void syncCaret() {
0356: // // Fix the caret
0357: // DesignerCaret dc = webform.getPane().getCaret();
0358: //
0359: // if ((dc != null) && (dc.getDot() != Position.NONE)) {
0360: // /*
0361: // LiveUnit unit = webform.getModel().getLiveUnit();
0362: // org.w3c.dom.Node n = dc.getDot().getNode();
0363: // Element newElement = null;
0364: // while (n != null) {
0365: // if (n instanceof XhtmlElement) {
0366: // XhtmlElement e = (XhtmlElement)n;
0367: // if (e.getDesignBean() != null) {
0368: // DesignBean newBean = unit.getBeanByName(e.getDesignBean().getInstanceName());
0369: // if (newBean != null) {
0370: // newElement = FacesSupport.getElement(newBean);
0371: // break;
0372: // }
0373: // }
0374: // }
0375: // n = n.getParentNode();
0376: // }
0377: // if (newElement != null) {
0378: // Position newPos = webform.getMapper().
0379: // // Can't do this because this will update the range
0380: // // in two steps, and as soon as one of the end points
0381: // // is in a different
0382: // //getPane().setCaretPosition(newPos);
0383: //
0384: // dc = getPane().getPaneUI().createCaret();
0385: // getPane().setCaret(dc);
0386: // getPane().setCaretPosition(newPos);
0387: // } else if (!webform.getDocument().isGridMode()) {
0388: // getPane().showCaretAtBeginning();
0389: // } else {
0390: // getPane().setCaret(null);
0391: // }
0392: // */
0393: //
0394: // // DONE IN PAGEBOX.layout!
0395: // // dc.setDot(Position.NONE); // Ensure range gets detached since we could be in a new DOM
0396: // // getPane().showCaretAtBeginning();
0397: // }
0398: // }
0399:
0400: /** Add the given view/component to the selection.
0401: * @param update If true, update property sheets etc. to reflect
0402: * the new selection.
0403: */
0404: public void addSelected(
0405: /*MarkupDesignBean component*/Element componentRootElement,
0406: boolean update) {
0407: // boolean wasEmpty = ((selected == null) || (selected.size() == 0));
0408: boolean wasEmpty = selectedComponents.isEmpty();
0409: // FormObject fo = new FormObject();
0410: // fo.component = component;
0411: SelectedComponent sc = new SelectedComponent();
0412: sc.componentRootElement = componentRootElement;
0413:
0414: // primary = component;
0415: primary = sc.componentRootElement;
0416:
0417: // if (fo.component == null) {
0418: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL,
0419: // new NullPointerException("MarkupDesignBean is null!")); // NOI18N
0420: // }
0421: if (sc.componentRootElement == null) {
0422: ErrorManager.getDefault().notify(
0423: ErrorManager.INFORMATIONAL,
0424: new NullPointerException(
0425: "ComponentRootElement is null!")); // NOI18N
0426: }
0427:
0428: // fo.resizeConstraints = Resizer.getResizeConstraints(webform, component);
0429: sc.resizeConstraints = Resizer.getResizeConstraints(webform,
0430: componentRootElement);
0431:
0432: // selected.add(fo);
0433: // leaf = fo.component;
0434: if (!selectedComponents.contains(sc)) {
0435: selectedComponents.add(sc);
0436: }
0437: // leaf = component;
0438: leaf = sc.componentRootElement;
0439:
0440: if (update) {
0441: // updateSelection();
0442: updateNodes();
0443: }
0444:
0445: if (wasEmpty) {
0446: // Enable Cut, Copy, Delete
0447: // webform.getTopComponent().enableCutCopyDelete();
0448: // webform.tcEnableCutCopyDelete();
0449: }
0450: }
0451:
0452: /** Set the selection to the given component.
0453: * Attempt to preserve the current component as a leaf, provided
0454: * the new component to be selected is an ancestor of the current leaf.
0455: */
0456: public void setSelected(
0457: /*MarkupDesignBean component*/Element componentRootElement,
0458: boolean update) {
0459: // MarkupDesignBean oldLeaf = leaf;
0460: // primary = component;
0461: Element oldLeaf = leaf;
0462: primary = componentRootElement;
0463:
0464: clearSelection(false);
0465: // addSelected(component, update);
0466: addSelected(componentRootElement, update);
0467:
0468: // Is the new component an ancestor of the old leaf?
0469: // MarkupDesignBean component = WebForm.getDomProviderService().getMarkupDesignBeanForElement(componentRootElement);
0470: if (PAINT_SELECTION_HIERARCHY) {
0471: // DesignBean curr = oldLeaf;
0472: // DesignBean curr = WebForm.getDomProviderService().getMarkupDesignBeanForElement(oldLeaf);
0473: Element curr = oldLeaf;
0474:
0475: while (curr != null) {
0476: // if (component == curr) {
0477: if (componentRootElement == curr) {
0478: // Yes!
0479: leaf = oldLeaf;
0480:
0481: return;
0482: }
0483:
0484: // curr = curr.getBeanParent();
0485: curr = webform.getDomProviderService()
0486: .getParentComponent(curr);
0487: }
0488:
0489: // No. This is the new leaf.
0490: // assert leaf == component;
0491: // if (leaf != WebForm.getDomProviderService().getComponentRootElementForMarkupDesignBean(component)) {
0492: if (leaf != componentRootElement) {
0493: ErrorManager.getDefault().notify(
0494: ErrorManager.INFORMATIONAL,
0495: new IllegalStateException(
0496: "Leaf is different from expected, leaf="
0497: + leaf + ", expected="
0498: + componentRootElement)); // NOI18N
0499: }
0500: }
0501: }
0502:
0503: /** Remove the given view/component from the selection.
0504: * @param update If true, update property sheets etc. to reflect
0505: * the new selection.
0506: */
0507: public void removeSelected(
0508: /*MarkupDesignBean component*/Element componentRootElement,
0509: boolean update) {
0510: // boolean wasEmpty = ((selected == null) || (selected.size() == 0));
0511: boolean wasEmpty = selectedComponents.isEmpty();
0512:
0513: if (!wasEmpty) {
0514: // Iterator it = selected.iterator();
0515: //
0516: // while (it.hasNext()) {
0517: // FormObject fo = (FormObject)it.next();
0518: // for (FormObject fo : selected) {
0519: //
0520: // if (fo.component == component) {
0521: // selected.remove(fo);
0522: //
0523: // break;
0524: // }
0525: // }
0526: for (SelectedComponent sc : selectedComponents) {
0527: if (sc.componentRootElement == componentRootElement) {
0528: selectedComponents.remove(sc);
0529: break;
0530: }
0531: }
0532: }
0533:
0534: // if (component == primary) {
0535: if (componentRootElement == primary) {
0536: primary = null;
0537:
0538: // if (selected.size() > 1) {
0539: if (selectedComponents.size() > 1) {
0540: pickPrimary();
0541: }
0542: }
0543:
0544: if (update) {
0545: // updateSelection();
0546: updateNodes();
0547: }
0548:
0549: // if (wasEmpty && (selected.size() == 0)) { // removed last component
0550: if (wasEmpty && selectedComponents.isEmpty()) { // removed last component
0551: // webform.getTopComponent().disableCutCopyDelete(); // not true for paste
0552: // webform.tcDisableCutCopyDelete();
0553: }
0554: }
0555:
0556: /** Return true iff the given view is in the set of selected views.
0557: @param component The view to check. May not be null.
0558: @return true iff the component is currently selected.
0559: */
0560: public boolean isSelected(
0561: /*DesignBean component*/Element componentRootElement) {
0562: // if ((selected == null) || (selected.size() == 0)) {
0563: if (componentRootElement == null
0564: || selectedComponents.isEmpty()) {
0565: return false;
0566: }
0567:
0568: // Iterator it = selected.iterator();
0569: //
0570: // while (it.hasNext()) {
0571: // FormObject fo = (FormObject)it.next();
0572: // for (FormObject fo : selected) {
0573: // if (fo.component == component) {
0574: // return true;
0575: // }
0576: // }
0577: for (SelectedComponent sc : selectedComponents) {
0578: if (sc.componentRootElement == componentRootElement) {
0579: return true;
0580: }
0581: }
0582:
0583: return false;
0584: }
0585:
0586: /** Return true iff the given view is in the set of selected views
0587: * or is a child of a selected view.
0588: * @param box The box to check. May not be null.
0589: * @return true iff the box or one of its ancestors is currently selected.
0590: */
0591: public boolean isBelowSelected(CssBox box) {
0592: if (box.getBoxType() == BoxType.TEXT) {
0593: box = box.getParent();
0594: }
0595:
0596: // if ((box.getDesignBean() != null) && isSelected(box.getDesignBean())) {
0597: // MarkupDesignBean markupDesignBean = CssBox.getMarkupDesignBeanForCssBox(box);
0598: // if ((markupDesignBean != null) && isSelected(markupDesignBean)) {
0599: Element componentRootElement = CssBox
0600: .getElementForComponentRootCssBox(box);
0601: if (isSelected(componentRootElement)) {
0602: return true;
0603: }
0604:
0605: return getSelectedAncestor(box) != null;
0606: }
0607:
0608: /** Check to see if any ancestors of the given view (or the view
0609: * itself) is in the selection set, and if so, return it. This will
0610: * return the closest (e.g. furthest down the element tree) match.
0611: *
0612: * @param box The box to check. May not be null.
0613: * @return The selected view or ancestor of the box
0614: */
0615: public CssBox getSelectedAncestor(CssBox box) {
0616: if (box != null) {
0617: // Skip the immediate box
0618: box = box.getParent();
0619: }
0620:
0621: while (box != null) {
0622: // if ((box.getDesignBean() != null) && isSelected(box.getDesignBean())) {
0623: // MarkupDesignBean markupDesignBean = CssBox.getMarkupDesignBeanForCssBox(box);
0624: // if ((markupDesignBean != null) && isSelected(markupDesignBean)) {
0625: Element componentRootElement = CssBox
0626: .getElementForComponentRootCssBox(box);
0627: if (isSelected(componentRootElement)) {
0628: return box;
0629: }
0630:
0631: box = box.getParent();
0632: }
0633:
0634: return null;
0635: }
0636:
0637: /** Return the first container component found in the selection.
0638: * If no direct selected component is a container, return the first
0639: * container ancestor for the first selected item.
0640: */
0641: public/*DesignBean*/Element getSelectedContainer() {
0642: // Iterator it = selected.iterator();
0643: //
0644: // while (it.hasNext()) {
0645: // FormObject fo = (FormObject)it.next();
0646: // for (FormObject fo : selected) {
0647: // DesignBean lb = fo.component;
0648: //
0649: // if (lb.isContainer()) {
0650: // return lb;
0651: // }
0652: // }
0653: for (SelectedComponent sc : selectedComponents) {
0654: // DesignBean lb = WebForm.getDomProviderService().getMarkupDesignBeanForElement(sc.componentRootElement);
0655: // if (lb.isContainer()) {
0656: if (webform.getDomProviderService()
0657: .isContainerTypeComponent(sc.componentRootElement)) {
0658: // return lb;
0659: return sc.componentRootElement;
0660: }
0661: }
0662:
0663: // it = selected.iterator();
0664: //
0665: // while (it.hasNext()) {
0666: // FormObject fo = (FormObject)it.next();
0667: // for (FormObject fo : selected) {
0668: // DesignBean lb = fo.component;
0669: //
0670: // if (lb.getBeanParent() != null) {
0671: // return lb.getBeanParent();
0672: // }
0673: // }
0674: for (SelectedComponent sc : selectedComponents) {
0675: // DesignBean lb = WebForm.getDomProviderService().getMarkupDesignBeanForElement(sc.componentRootElement);
0676: // if (lb.getBeanParent() != null) {
0677: Element parentComponentRootElement = webform
0678: .getDomProviderService().getParentComponent(
0679: sc.componentRootElement);
0680: if (parentComponentRootElement != null) {
0681: // return lb.getBeanParent();
0682: return parentComponentRootElement;
0683: }
0684: }
0685:
0686: return null;
0687: }
0688:
0689: /** Returned the first positioned element in the selection. Gets the component root element (rendered element). */
0690: Element getPositionElement() {
0691: // Iterator it = selected.iterator();
0692: //
0693: // while (it.hasNext()) {
0694: // FormObject fo = (FormObject)it.next();
0695: // for (FormObject fo : selected) {
0696: //// CssBox box = webform.getMapper().findBox(fo.component);
0697: // CssBox box = ModelViewMapper.findBox(webform.getPane().getPageBox(), fo.component);
0698: //
0699: // if ((box != null) && box.getBoxType().isPositioned()) {
0700: //// return box.getDesignBean().getElement();
0701: // // XXX Shouldn't be here the fo.component? See above.
0702: // return CssBox.getMarkupDesignBeanForCssBox(box).getElement();
0703: // }
0704: // }
0705: for (SelectedComponent sc : selectedComponents) {
0706: // CssBox box = webform.getMapper().findBox(fo.component);
0707: CssBox box = ModelViewMapper
0708: .findBoxForComponentRootElement(webform.getPane()
0709: .getPageBox(), sc.componentRootElement);
0710:
0711: if ((box != null) && box.getBoxType().isPositioned()) {
0712: // return box.getDesignBean().getElement();
0713: // XXX Shouldn't be here the fo.component? See above.
0714: // return CssBox.getMarkupDesignBeanForCssBox(box).getElement();
0715: return CssBox.getElementForComponentRootCssBox(box);
0716: }
0717: }
0718:
0719: return null;
0720: }
0721:
0722: /** Select all components on the designer surface (except components
0723: * that are children of other components, and except components that
0724: * are "special", such as Form/Body/Head/Html, etc.
0725: */
0726: public void selectAll() {
0727: //DesignBean root = webform.getModel().getRootBean();
0728: // RaveElement element = webform.getBody();
0729: Element element = webform.getHtmlBody();
0730: // DesignBean root = element.getDesignBean();
0731: // DesignBean root = InSyncService.getProvider().getMarkupDesignBeanForElement(element);
0732: // DesignBean root = WebForm.getDomProviderService().getMarkupDesignBeanForElement(element);
0733: //
0734: // if (root == null) {
0735: // return;
0736: // }
0737: if (element == null) {
0738: return;
0739: }
0740:
0741: // XXX #109439 The same components appeared more times in the selection.
0742: clearSelection(false);
0743:
0744: Element[] children = webform.getDomProviderService()
0745: .getChildComponents(element);
0746: // for (int i = 0, n = root.getChildBeanCount(); i < n; i++) {
0747: // DesignBean child = root.getChildBean(i);
0748: for (Element child : children) {
0749:
0750: // if (child instanceof MarkupDesignBean) {
0751: // selectAll((MarkupDesignBean)child);
0752: // selectAll(WebForm.getDomProviderService().getComponentRootElementForMarkupDesignBean((MarkupDesignBean)child));
0753: // }
0754: selectAll(child);
0755: }
0756:
0757: // // We should not select the two special <br> components that are added
0758: // // to flow-positioned documents: the last break in the form component,
0759: // // and the first br in the body component. These are there to ensure that
0760: // // there are caret-viable lines in the document.
0761: // if (!webform.isGridMode()) {
0762: //// if ((root.getChildBeanCount() > 0) &&
0763: //// ((MarkupDesignBean)root.getChildBean(0)).getElement().getTagName().equals(HtmlTag.BR.name)) {
0764: // if (children.length > 0 && HtmlTag.BR.name.equals(children[0].getTagName())) {
0765: //// removeSelected((MarkupDesignBean)root.getChildBean(0), false);
0766: //// removeSelected(WebForm.getDomProviderService().getComponentRootElementForMarkupDesignBean((MarkupDesignBean)root.getChildBean(0)), false);
0767: // removeSelected(children[0], false);
0768: // }
0769: //
0770: // // Look for last bean in the default parent
0771: //// MarkupDesignBean defaultBean =
0772: //// FacesSupport.getDesignBean(webform.getModel().getFacesUnit().getDefaultParent()
0773: //// .getElement());
0774: //// MarkupDesignBean defaultBean =
0775: ////// WebForm.getDomProviderService().getMarkupDesignBeanForElement(webform.getModel().getFacesUnit().getDefaultParent()
0776: ////// .getElement());
0777: //// WebForm.getDomProviderService().getMarkupDesignBeanForElement(
0778: //// webform.getDefaultParentMarkupBeanElement());
0779: //
0780: //// Element defaultElement = webform.getDefaultParentMarkupBeanElement();
0781: // Element defaultElement = webform.getDefaultParentComponent();
0782: //
0783: //// if (defaultBean != null) {
0784: //// int n = defaultBean.getChildBeanCount();
0785: ////
0786: //// if ((n > 0) &&
0787: //// ((MarkupDesignBean)defaultBean.getChildBean(n - 1)).getElement().getTagName()
0788: //// .equals(HtmlTag.BR.name)) {
0789: ////// removeSelected((MarkupDesignBean)defaultBean.getChildBean(n - 1), false);
0790: //// removeSelected(WebForm.getDomProviderService().getComponentRootElementForMarkupDesignBean((MarkupDesignBean)defaultBean.getChildBean(n - 1)), false);
0791: //// }
0792: //// }
0793: // if (defaultElement != null) {
0794: // Element[] defaultElementChildren = WebForm.getDomProviderService().getChildComponents(defaultElement);
0795: // int n = defaultElementChildren.length;
0796: // if ((n > 0) && HtmlTag.BR.name.equals(defaultElementChildren[n-1].getTagName())) {
0797: // removeSelected(defaultElementChildren[n - 1], false);
0798: // }
0799: // }
0800: // }
0801: if (!webform.isGridMode()) {
0802: // XXX Just the same what did the original code, but without JSF specific API.
0803: if (!selectedComponents.isEmpty()) {
0804: Element firstSelectedComponent = selectedComponents
0805: .get(0).componentRootElement;
0806: Element lastSelectedComponent = selectedComponents
0807: .get(selectedComponents.size() - 1).componentRootElement;
0808: if (firstSelectedComponent != null
0809: && HtmlTag.BR.name
0810: .equals(firstSelectedComponent
0811: .getTagName())) {
0812: removeSelected(firstSelectedComponent, false);
0813: }
0814: if (lastSelectedComponent != null
0815: && HtmlTag.BR.name.equals(lastSelectedComponent
0816: .getTagName())) {
0817: removeSelected(lastSelectedComponent, false);
0818: }
0819: }
0820: }
0821:
0822: // updateSelection();
0823: updateNodes();
0824:
0825: // if (selected.size() > 0) {
0826: if (!selectedComponents.isEmpty()) {
0827: // webform.getTopComponent().enableCutCopyDelete();
0828: // webform.tcEnableCutCopyDelete();
0829: }
0830:
0831: webform.getPane().repaint();
0832: }
0833:
0834: private void selectAll(
0835: /*MarkupDesignBean bean*/Element componentRootElement) {
0836: // if (!FacesSupport.isSpecialBean(/*webform, */bean)) {
0837: // if (!Util.isSpecialBean(bean)) {
0838: // MarkupDesignBean bean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(componentRootElement);
0839: if (!webform.getDomProviderService().isSpecialComponent(
0840: componentRootElement)) {
0841: // addSelected(bean, false);
0842: addSelected(componentRootElement, false);
0843: }
0844:
0845: // for (int i = 0, n = bean.getChildBeanCount(); i < n; i++) {
0846: // DesignBean child = bean.getChildBean(i);
0847: //
0848: // if (child instanceof MarkupDesignBean) {
0849: //// selectAll((MarkupDesignBean)child);
0850: // selectAll(WebForm.getDomProviderService().getComponentRootElementForMarkupDesignBean((MarkupDesignBean)child));
0851: // }
0852: // }
0853: Element[] children = webform.getDomProviderService()
0854: .getChildComponents(componentRootElement);
0855: for (Element child : children) {
0856: selectAll(child);
0857: }
0858: }
0859:
0860: /** Select all views that intersect the given bound rectangle.
0861: * @todo Decide if views should be entirely within the bounds, or
0862: * merely intersect the rectangle
0863: * @param pane Pane to look for selection in
0864: * @param bounds Bounds to scan within
0865: * @param exclusive If true, only include components that are fully
0866: * contained within the bounds. If false, include any
0867: * component that touches the bounds.
0868: * @todo Get rid of the pane parameter - it is redundant; should be webform.getPane()
0869: */
0870: public void selectComponentRectangle(Rectangle bounds,
0871: boolean contained) {
0872: List<Element> list = new ArrayList<Element>();
0873: DesignerPane pane = webform.getPane();
0874: selectViews(pane.getPageBox(), list, bounds, contained, 0);
0875:
0876: // Iterator it = list.iterator();
0877: clearSelection(false);
0878:
0879: // while (it.hasNext()) {
0880: // MarkupDesignBean component = (MarkupDesignBean)it.next();
0881: for (Element componentRootElement : list) {
0882: // addSelected(component, false);
0883: addSelected(componentRootElement, false);
0884:
0885: // The Marquee will call repaint
0886: }
0887:
0888: // updateSelection();
0889: updateNodes();
0890:
0891: // XXX do I need to go and set copy selection here?
0892: pane.repaint();
0893: }
0894:
0895: private static void selectViews(CssBox box, List<Element> matches,
0896: Rectangle bounds, boolean contained, int depth) {
0897: if (DesignerUtils.intersects(bounds, box.getAbsoluteX(), box
0898: .getAbsoluteY(), box.getWidth(), box.getHeight())) {
0899: // TODO - use DesignerCaret's _contains instead!
0900: if ((contained && bounds.contains(box.getAbsoluteX(), box
0901: .getAbsoluteY(), box.getWidth(), box.getHeight()))
0902: || (!contained && DesignerUtils.intersects(bounds,
0903: box.getAbsoluteX(), box.getAbsoluteY(), box
0904: .getWidth(), box.getHeight()))) {
0905: // if (box.getDesignBean() != null) {
0906: // matches.add(box.getDesignBean());
0907: // MarkupDesignBean markupDesignBean = CssBox.getMarkupDesignBeanForCssBox(box);
0908: // if (markupDesignBean != null) {
0909: // matches.add(markupDesignBean);
0910: // }
0911: Element componentRootElement = CssBox
0912: .getElementForComponentRootCssBox(box);
0913: if (componentRootElement != null) {
0914: matches.add(componentRootElement);
0915: }
0916: }
0917: }
0918:
0919: // XXX Should only have to do this for intersecting boxes!!!
0920: // (plus those intersecting with the -extents- of the box, e.g.
0921: // including absolutely positioned boxes!)
0922: for (int i = 0, n = box.getBoxCount(); i < n; i++) {
0923: CssBox child = box.getBox(i);
0924:
0925: if (child instanceof ExternalDocumentBox) {
0926: continue;
0927: }
0928:
0929: selectViews(child, matches, bounds, contained, depth + 1);
0930: }
0931: }
0932:
0933: /**
0934: * Focus the default property. Return false if no default property was
0935: * found, or if the property is read only, if no component is selected,
0936: * etc.
0937: * @todo check for readonly prop, and immediately sync prop sheet
0938: * to avoid delay problem!
0939: */
0940: public boolean focusDefaultProperty(ActionEvent event) {
0941: // if ((selected != null) && (selected.size() > 0)) {
0942: if (!selectedComponents.isEmpty()) {
0943: DesignerPane pane = webform.getPane();
0944: // ModelViewMapper mapper = webform.getMapper();
0945:
0946: // Find the first selected component that has a default
0947: // property or is inline editing capable
0948: // Iterator it = selected.iterator();
0949: //
0950: // while (it.hasNext()) {
0951: // FormObject fo = (FormObject)it.next();
0952: // for (FormObject fo : selected) {
0953: // DesignBean lb = fo.component;
0954: for (SelectedComponent sc : selectedComponents) {
0955: // if (lb instanceof MarkupDesignBean) {
0956: // MarkupDesignBean bean = (MarkupDesignBean)lb;
0957: // CssBox box = mapper.findBox(bean);
0958: CssBox box = ModelViewMapper
0959: .findBoxForComponentRootElement(webform
0960: .getPane().getPageBox(),
0961: sc.componentRootElement);
0962: // TODO - pass in keystroke too
0963: boolean inlineEdited =
0964: // webform.getManager().startInlineEditing(bean, null, box, true, false,
0965: webform.getManager().startInlineEditing(
0966: sc.componentRootElement, null, box, true,
0967: false, event.getActionCommand(), false);
0968: if (inlineEdited) {
0969: return true;
0970: }
0971: // }
0972:
0973: // DesignBean lb = WebForm.getDomProviderService().getMarkupDesignBeanForElement(sc.componentRootElement);
0974: // BeanInfo bi = lb.getBeanInfo();
0975: // if (bi != null) {
0976: // int defaultProp = bi.getDefaultPropertyIndex();
0977: //
0978: // if (defaultProp != -1) {
0979: if (webform.getDomProviderService().hasDefaultProperty(
0980: sc.componentRootElement)) {
0981: // FeatureDescriptor defProp = bi.getPropertyDescriptors()[defaultProp];
0982: //
0983: // // How do we launch the property sheet editing a
0984: // // particular property?
0985: // final JTable jt =
0986: //// org.netbeans.modules.visualweb.designer.DesignerUtils.findPropSheetTable(true, true);
0987: // findPropSheetTable(true, true);
0988: //
0989: // if (jt == null) {
0990: // return false;
0991: // }
0992: //
0993: // TableModel model = jt.getModel();
0994: //
0995: // // Set focus of jt?
0996: // for (int row = 0, n = model.getRowCount(); row < n; row++) {
0997: // Object o = model.getValueAt(row, 0);
0998: //
0999: // if (!(o instanceof FeatureDescriptor)) {
1000: // continue;
1001: // }
1002: //
1003: // FeatureDescriptor desc = (FeatureDescriptor)o;
1004: //
1005: // if (defProp.getName().equals(desc.getName())) {
1006: // // Edit the cell XXX only if readonly!
1007: // if (desc instanceof Node.Property) {
1008: // Node.Property prop = (Node.Property)desc;
1009: //
1010: // if (!prop.canWrite()) {
1011: // return false;
1012: // }
1013: // }
1014: //
1015: // final int r = row;
1016: // final String content = event.getActionCommand();
1017: // SwingUtilities.invokeLater(new Runnable() {
1018: // public void run() {
1019: // jt.editCellAt(r, 1, null);
1020: // jt.requestFocus();
1021: //
1022: // Object ce = jt.getCellEditor(r, 1);
1023: //
1024: // // Hack Alert: try to transfer the
1025: // // original keypress into the text field
1026: // Component comp =
1027: // getInplaceEditorComponentForSheetCellEditor(ce);
1028: //
1029: // if (comp instanceof javax.swing.text.JTextComponent) {
1030: // javax.swing.text.JTextComponent jtc =
1031: // (javax.swing.text.JTextComponent)comp;
1032: // jtc.replaceSelection(content);
1033: // }
1034: // }
1035: // });
1036: //
1037: // return true;
1038: // }
1039: // }
1040: return webform.getDomProviderService()
1041: .focusDefaultProperty(
1042: sc.componentRootElement,
1043: event.getActionCommand());
1044: } else {
1045: // Is it a MarkupBean that has a TextNode child?
1046: // (for example a <div> or a <table>. If so,
1047: // try to set the caret to the given position
1048: // and repeat the insert.)
1049: // Element element = FacesSupport.getElement(lb);
1050: // Element element = Util.getElement(lb);
1051: // Element element = WebForm.getDomProviderService().getElement(lb);
1052: Element element = webform.getDomProviderService()
1053: .getSourceElement(sc.componentRootElement);
1054:
1055: if (element != null) {
1056: // org.w3c.dom.Node text = DesignerUtils.findFirstTextChild(element);
1057: org.w3c.dom.Node text = findFirstTextChild(element);
1058:
1059: if (text != null) {
1060: // DesignerCaret dc = pane.getPaneUI().createCaret();
1061: // pane.setCaret(dc);
1062: pane.createCaret();
1063:
1064: // Position newPos = new Position(text, 0, Bias.FORWARD);
1065: // Position newPos = Position.create(text, 0, Bias.FORWARD);
1066: DomPosition newPos = webform
1067: .createDomPosition(text, 0,
1068: Bias.FORWARD);
1069:
1070: // pane.setCaretPosition(newPos);
1071: pane.setCaretDot(newPos);
1072:
1073: // Document doc = webform.getDocument();
1074:
1075: //// UndoEvent undoEvent = webform.getModel().writeLock(NbBundle.getMessage(DefaultKeyTypedAction.class,
1076: //// "InsertChar"));
1077: // DomProvider.WriteLock writeLock = webform.writeLock(NbBundle.getMessage(DefaultKeyTypedAction.class,
1078: // "InsertChar"));
1079: // try {
1080: // doc.writeLock(NbBundle.getMessage(DefaultKeyTypedAction.class,
1081: // "InsertChar"));
1082:
1083: final String content = event
1084: .getActionCommand();
1085: // pane.getCaret().replaceSelection(content);
1086: pane.replaceSelection(content);
1087: // } finally {
1088: //// doc.writeUnlock();
1089: //// webform.getModel().writeUnlock(undoEvent);
1090: // webform.writeUnlock(writeLock);
1091: // }
1092:
1093: return true;
1094: }
1095: }
1096: }
1097: // }
1098: }
1099: }
1100:
1101: return false;
1102: }
1103:
1104: // XXX Moved from DesignerUtils.
1105: /** Find the first TextNode child under this element, or null
1106: * if no such node is found.
1107: * @todo How do we avoid returning for example the blank
1108: * textnode between <table> and <tr> in a table? I want
1109: * the <td> !
1110: */
1111: private static org.w3c.dom.Node findFirstTextChild(
1112: org.w3c.dom.Node node) {
1113: // if(DEBUG) {
1114: // debugLog(DesignerUtils.class.getName() + ".findFirstTextChild(Node)");
1115: // }
1116: if (node == null) {
1117: return (null);
1118: }
1119: if ((node.getNodeType() == org.w3c.dom.Node.TEXT_NODE)
1120: || (node.getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE)) {
1121: return node;
1122: }
1123:
1124: org.w3c.dom.NodeList nl = node.getChildNodes();
1125:
1126: for (int i = 0, n = nl.getLength(); i < n; i++) {
1127: org.w3c.dom.Node result = findFirstTextChild(nl.item(i));
1128:
1129: if (result != null) {
1130: return result;
1131: }
1132: }
1133:
1134: return null;
1135: }
1136:
1137: // // XXX Moved from DesignerUtils.
1138: // /** Locate the JTable within the property sheet in the IDE.
1139: // * WARNING: Implementation hacks!
1140: // * @param focus If set, focus the top component
1141: // * @param visible If set, ensure the top component is fronted
1142: // */
1143: // private static JTable findPropSheetTable(boolean focus, boolean visible) {
1144: // WindowManager mgr = WindowManager.getDefault();
1145: // TopComponent properties = mgr.findTopComponent("properties"); // NOI18N
1146: //
1147: // if ((properties != null) && (visible || properties.isShowing())) {
1148: // if (focus) {
1149: // properties.requestActive();
1150: // }
1151: //
1152: // if (visible) {
1153: // properties.requestVisible();
1154: // }
1155: //
1156: // return findTable(properties);
1157: // }
1158: //
1159: // return null;
1160: // }
1161: //
1162: // /** Fish the given Container hierarchy for a JTable */
1163: // private static JTable findTable(Container c) {
1164: //// if(DEBUG) {
1165: //// debugLog(DesignerUtils.class.getName() + ".findTable(Container)");
1166: //// }
1167: // if(c == null) {
1168: // return(null);
1169: // }
1170: // if (c instanceof JTable) {
1171: // return (JTable)c;
1172: // }
1173: //
1174: // int n = c.getComponentCount();
1175: //
1176: // for (int i = 0; i < n; i++) {
1177: // Component comp = c.getComponent(i);
1178: //
1179: // if (comp instanceof JTable) {
1180: // return (JTable)comp;
1181: // }
1182: //
1183: // if (comp instanceof Container) {
1184: // JTable table = findTable((Container)comp);
1185: //
1186: // if (table != null) {
1187: // return table;
1188: // }
1189: // }
1190: // }
1191: //
1192: // return null;
1193: // }
1194: //
1195: // // XXX Using reflection, But it is still better than changing NB code
1196: // // The task from UI point of view looks very strange... why the text isn't inserted into the component, as user expect,
1197: // // but surprisinlgy the focus is moved into property sheet? That kind of solutions cause problems like this.
1198: // private static Component getInplaceEditorComponentForSheetCellEditor(Object ce) {
1199: // if (ce == null) {
1200: // return null;
1201: // }
1202: //
1203: // Object inplaceEditor;
1204: //
1205: // try {
1206: // ClassLoader cl =
1207: // org.openide.explorer.propertysheet.PropertySheet.class.getClassLoader();
1208: // Class sheetCellEditorClass =
1209: // Class.forName("org.openide.explorer.propertysheet.SheetCellEditor", true, cl); // NOI18N
1210: // java.lang.reflect.Method getInplaceEditorMethod =
1211: // sheetCellEditorClass.getDeclaredMethod("getInplaceEditor", new Class[0]); // NOI18N
1212: // getInplaceEditorMethod.setAccessible(true);
1213: // inplaceEditor = getInplaceEditorMethod.invoke(ce, new Object[0]);
1214: // } catch (ClassNotFoundException cnfe) {
1215: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, cnfe);
1216: // inplaceEditor = null;
1217: // } catch (NoSuchMethodException nsme) {
1218: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, nsme);
1219: // inplaceEditor = null;
1220: // } catch (IllegalAccessException iae) {
1221: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, iae);
1222: // inplaceEditor = null;
1223: // } catch (java.lang.reflect.InvocationTargetException ite) {
1224: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ite);
1225: // inplaceEditor = null;
1226: // }
1227: //
1228: // if (inplaceEditor instanceof org.openide.explorer.propertysheet.InplaceEditor) {
1229: // return ((org.openide.explorer.propertysheet.InplaceEditor)inplaceEditor).getComponent();
1230: // } else {
1231: // return null;
1232: // }
1233: // }
1234:
1235: /**
1236: * Determine if the given point overlaps a selection handle.
1237: * @param editor The editor whose selection we're checking
1238: * @param x The x coordinate of the position we want to check
1239: * @param y The y coordinate of the position we want to check
1240: * @return Cursor.DEFAULT_CURSOR if the given point (x,y) is not
1241: * over any of the selection handles drawn for the current selection.
1242: * If it is, return the right edge direction for the overlap.
1243: * If there are multiple overlapping selection handles, it's arbitrary
1244: * which one is chosen.
1245: * @see overSelection
1246: */
1247: public int getSelectionHandleDir(int x, int y, int maxWidth,
1248: int maxHeight) {
1249: // if ((selected != null) && (selected.size() > 0)) {
1250: // Iterator it = selected.iterator();
1251: //// ModelViewMapper mapper = webform.getMapper();
1252: //
1253: // while (it.hasNext()) {
1254: // FormObject fo = (FormObject)it.next();
1255: //
1256: // // XXX I should cache these!!!
1257: //// ArrayList rectangles = mapper.getComponentRectangles(fo.component);
1258: // List rectangles = ModelViewMapper.getComponentRectangles(webform.getPane().getPageBox(), fo.component);
1259: //
1260: // for (int i = 0; i < rectangles.size(); i++) {
1261: // int over =
1262: // overSelection(x, y, (Rectangle)rectangles.get(i), fo.resizeConstraints,
1263: // maxWidth, maxHeight);
1264: //
1265: // if (over != Cursor.DEFAULT_CURSOR) {
1266: // return over;
1267: // }
1268: // }
1269: // }
1270: // }
1271: for (SelectedComponent sc : selectedComponents) {
1272: // XXX I should cache these!!!
1273: // ArrayList rectangles = mapper.getComponentRectangles(fo.component);
1274: List rectangles = ModelViewMapper.getComponentRectangles(
1275: webform.getPane().getPageBox(),
1276: sc.componentRootElement);
1277: for (int i = 0; i < rectangles.size(); i++) {
1278: int over = overSelection(x, y, (Rectangle) rectangles
1279: .get(i), sc.resizeConstraints, maxWidth,
1280: maxHeight);
1281: if (over != Cursor.DEFAULT_CURSOR) {
1282: return over;
1283: }
1284: }
1285: }
1286:
1287: return Cursor.DEFAULT_CURSOR;
1288: }
1289:
1290: /**
1291: * Similar to getSelectionHandleDir, but returns the selected
1292: * object whose selection handles are pointed at, rather than the
1293: * selection handle direction.
1294: */
1295: public/*MarkupDesignBean*/Element getSelectionHandleView(int x,
1296: int y, int maxWidth, int maxHeight) {
1297: // if ((selected != null) && (selected.size() > 0)) {
1298: //// ModelViewMapper mapper = webform.getMapper();
1299: //
1300: // Iterator it = selected.iterator();
1301: //
1302: // while (it.hasNext()) {
1303: // FormObject fo = (FormObject)it.next();
1304: //// ArrayList rectangles = mapper.getComponentRectangles(fo.component);
1305: // List rectangles = ModelViewMapper.getComponentRectangles(webform.getPane().getPageBox(), fo.component);
1306: //
1307: // for (int i = 0; i < rectangles.size(); i++) {
1308: // int dir =
1309: // overSelection(x, y, (Rectangle)rectangles.get(i), fo.resizeConstraints,
1310: // maxWidth, maxHeight);
1311: //
1312: // if (dir != Cursor.DEFAULT_CURSOR) {
1313: // return fo.component;
1314: // }
1315: // }
1316: // }
1317: // }
1318: for (SelectedComponent sc : selectedComponents) {
1319: // ArrayList rectangles = mapper.getComponentRectangles(fo.component);
1320: List<Rectangle> rectangles = ModelViewMapper
1321: .getComponentRectangles(webform.getPane()
1322: .getPageBox(), sc.componentRootElement);
1323:
1324: for (Rectangle rectangle : rectangles) {
1325: int dir = overSelection(x, y, rectangle,
1326: sc.resizeConstraints, maxWidth, maxHeight);
1327: if (dir != Cursor.DEFAULT_CURSOR) {
1328: return sc.componentRootElement;
1329: }
1330: }
1331: }
1332:
1333: return null;
1334: }
1335:
1336: /**
1337: * Return true iff no components are selected
1338: */
1339: public boolean isSelectionEmpty() {
1340: // return (selected == null) || (selected.size() == 0);
1341: return selectedComponents.isEmpty();
1342: }
1343:
1344: /**
1345: * Report the number of selected items.
1346: * @return the number of selected items in the designer
1347: */
1348: public int getNumSelected() {
1349: // return (selected == null) ? 0 : selected.size();
1350: return selectedComponents.size();
1351: }
1352:
1353: /** Make a particular element selected
1354: */
1355: public void selectComponents(
1356: final/*DesignBean[] components*/Element[] componentRootElements,
1357: final boolean update) {
1358: // if (ignoreSelection) {
1359: // return;
1360: // }
1361:
1362: // Make sure the component is selected
1363: // Unfortunately we have to do this in a delay;
1364: // see Document.handleEvent for details (look near
1365: // DOM_NODE_INSERTED - and note that we're called
1366: // from DndHandler when components
1367: // are inserted)
1368: SwingUtilities.invokeLater(new Runnable() {
1369: public void run() {
1370: // assert components != null;
1371: //
1372: // clearSelection(false);
1373: //
1374: // for (int i = 0; i < components.length; i++) {
1375: // if (components[i] instanceof MarkupDesignBean) {
1376: //// addSelected((MarkupDesignBean)components[i], false);
1377: // addSelected(getComponentRootElementForMarkupDesignBean((MarkupDesignBean)components[i]), false);
1378: // }
1379: // }
1380:
1381: clearSelection(false);
1382:
1383: if (componentRootElements != null) {
1384: for (Element componentRootElement : componentRootElements) {
1385: if (componentRootElement != null) {
1386: addSelected(componentRootElement, false);
1387: }
1388: }
1389: }
1390:
1391: if (update) {
1392: // updateSelection();
1393: updateNodes();
1394: }
1395:
1396: DesignerPane dp = webform.getPane();
1397:
1398: // #6258586 NPE fix.
1399: if (dp != null) {
1400: dp.repaint(); // tray wants a repaint but no node update!!! update means node update!
1401: }
1402: }
1403: });
1404: }
1405:
1406: /** Increase the size of the given rectangle to accomodate
1407: * the selection handles. Typically used when computing dirty/repaint
1408: * rectangles
1409: * @todo Should probably be a static method
1410: */
1411: public void enlarge(Rectangle r) {
1412: r.x -= (BARSIZE + 1);
1413: r.y -= (BARSIZE + 1);
1414: r.width += ((2 * BARSIZE) + 2);
1415: r.height += ((2 * BARSIZE) + 2);
1416: }
1417:
1418: private BasicStroke getSelectionStroke() {
1419: if (selStroke == null) {
1420: int width = 1;
1421: selStroke = new BasicStroke((float) width,
1422: BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER,
1423: 10.0f,
1424: new float[] { 6 * width, (6 * width) + width },
1425: 0.0f);
1426: }
1427:
1428: return selStroke;
1429: }
1430:
1431: /** Draw selection rectangles around the currently selected views */
1432: public void paintSelection(Graphics2D g2d) {
1433: if (webform.getManager().isInlineEditing()) {
1434: return;
1435: }
1436:
1437: // if ((selected != null) && (selected.size() > 0)) {
1438: // boolean selectedMany = selected.size() > 1;
1439: if (!selectedComponents.isEmpty()) {
1440: // boolean selectedMany = selected.size() > 1;
1441: boolean selectedMany = selectedComponents.size() > 1;
1442: // ModelViewMapper mapper = webform.getMapper();
1443: ColorManager colors = webform.getColors();
1444:
1445: // Iterator it = selected.iterator();
1446: PageBox pageBox = webform.getPane().getPageBox();
1447: int maxWidth = pageBox.getWidth();
1448: int maxHeight = pageBox.getHeight();
1449:
1450: // while (it.hasNext()) {
1451: // FormObject fo = (FormObject)it.next();
1452: // for (FormObject fo : selected) {
1453: //
1454: // // XXX I should cache these!!!
1455: //// ArrayList rectangles = mapper.getComponentRectangles(fo.component);
1456: // List rectangles = ModelViewMapper.getComponentRectangles(pageBox, fo.component);
1457: //// Rectangle bounds = mapper.getComponentBounds(fo.component);
1458: // Rectangle bounds = ModelViewMapper.getComponentBounds(pageBox, fo.component);
1459:
1460: // XXX #95626 Hack (model might be changing underneath without proper notifications).
1461: // The elements might have been changed while the beans remain same.
1462: if (primary != null) {
1463: Element equivalentElement = webform
1464: .getComponentRootElementEquivalentTo(primary);
1465: if (equivalentElement != null
1466: && equivalentElement != primary) {
1467: primary = equivalentElement;
1468: }
1469: }
1470:
1471: for (SelectedComponent sc : selectedComponents) {
1472: // XXX #95626 Hack (model might be changing underneath without proper notifications).
1473: // The elements might have been changed while the beans remain same.
1474: Element equivalentElement = webform
1475: .getComponentRootElementEquivalentTo(sc.componentRootElement);
1476: if (equivalentElement != null
1477: && equivalentElement != sc.componentRootElement) {
1478: sc.componentRootElement = equivalentElement;
1479: }
1480:
1481: // XXX I should cache these!!!
1482: // ArrayList rectangles = mapper.getComponentRectangles(fo.component);
1483: List rectangles = ModelViewMapper
1484: .getComponentRectangles(pageBox,
1485: sc.componentRootElement);
1486: // Rectangle bounds = mapper.getComponentBounds(fo.component);
1487: Rectangle bounds = ModelViewMapper.getComponentBounds(
1488: pageBox, sc.componentRootElement);
1489:
1490: int n = rectangles.size();
1491:
1492: // Draw bounds rectangle if we have multiple rectangles?
1493: if (n > 0) {
1494: Rectangle r1 = (Rectangle) rectangles.get(0);
1495:
1496: if ((r1.x != bounds.x) || (r1.y != bounds.y)
1497: || (r1.width != bounds.width)
1498: || (r1.height != bounds.height)) {
1499: g2d.setColor(colors.selectionBoundsColor);
1500:
1501: Stroke oldStroke = g2d.getStroke();
1502: BasicStroke selStroke = getSelectionStroke();
1503: g2d.setStroke(selStroke);
1504: g2d.drawRect(bounds.x, bounds.y, bounds.width,
1505: bounds.height);
1506: g2d.setStroke(oldStroke);
1507: }
1508: }
1509:
1510: for (int i = 0; i < n; i++) {
1511: // paintSelected(g2d, selectedMany && (fo.component == primary),
1512: // (Rectangle)rectangles.get(i), fo.resizeConstraints, maxWidth, maxHeight);
1513: paintSelected(g2d, selectedMany
1514: && (sc.componentRootElement == primary),
1515: (Rectangle) rectangles.get(i),
1516: sc.resizeConstraints, maxWidth, maxHeight);
1517: }
1518: }
1519: }
1520: }
1521:
1522: /**
1523: * Draw selection for the given view.
1524: * @param g The graphics to draw with
1525: * @param insertMode If true, draw a thick insert-mode rectangle
1526: * around the selection
1527: * @param rect The selection rectangle
1528: * @param constraints Which sides are resizable
1529: */
1530: private void paintSelected(Graphics2D g2d, boolean isPrimary,
1531: Rectangle rect, /*int constraints,*/
1532: ResizeConstraint[] resizeConstraints, int maxWidth,
1533: int maxHeight) {
1534: int x = rect.x;
1535: int y = rect.y;
1536: int w = rect.width;
1537: int h = rect.height;
1538:
1539: if (x < (BARSIZE + 1)) {
1540: w -= ((BARSIZE + 1) - x);
1541: x = BARSIZE + 1;
1542: }
1543:
1544: if (y < (BARSIZE + 1)) {
1545: h -= ((BARSIZE + 1) - y);
1546: y = BARSIZE + 1;
1547: }
1548:
1549: if ((x + w + BARSIZE) > maxWidth) {
1550: w = maxWidth - BARSIZE - x;
1551: }
1552:
1553: if ((y + h + BARSIZE) > maxHeight) {
1554: h = maxHeight - BARSIZE - y;
1555: }
1556:
1557: int w2 = (w / 2) - (BARSIZE / 2);
1558: int h2 = (h / 2) - (BARSIZE / 2);
1559:
1560: //g2d.setColor(Marquee.marqueeColor); // TODO - make selectable
1561: //g2d.setXORMode(view.getContainer().getBackground());
1562: //g2d.setPaintMode(); // Just in case...
1563: // I've gotta clip! I'm drawing outside of the canvas on OSX!
1564: ColorManager colors = webform.getColors();
1565: g2d.setColor(colors.selectionColor); // TODO - make selectable
1566:
1567: g2d
1568: .drawRect(x - BARSIZE - 1, y - BARSIZE - 1, BARSIZE,
1569: BARSIZE);
1570: g2d.drawRect(x + w, y - BARSIZE - 1, BARSIZE, BARSIZE);
1571: g2d.drawRect(x + w, y + h, BARSIZE, BARSIZE);
1572: g2d.drawRect(x - BARSIZE - 1, y + h, BARSIZE, BARSIZE);
1573:
1574: // Middles
1575: // if ((constraints & Constants.ResizeConstraints.TOP) != 0) {
1576: if (Resizer.hasTopResizeConstraint(resizeConstraints)) {
1577: g2d.drawRect(x + w2, y - BARSIZE - 1, BARSIZE, BARSIZE); // top
1578: }
1579:
1580: // if ((constraints & Constants.ResizeConstraints.LEFT) != 0) {
1581: if (Resizer.hasLeftResizeConstraint(resizeConstraints)) {
1582: g2d.drawRect(x - BARSIZE - 1, y + h2, BARSIZE, BARSIZE); // left
1583: }
1584:
1585: // if ((constraints & Constants.ResizeConstraints.BOTTOM) != 0) {
1586: if (Resizer.hasBottomResizeConstraint(resizeConstraints)) {
1587: g2d.drawRect(x + w2, y + h, BARSIZE, BARSIZE); // bottom
1588: }
1589:
1590: // if ((constraints & Constants.ResizeConstraints.RIGHT) != 0) {
1591: if (Resizer.hasRightResizeConstraint(resizeConstraints)) {
1592: g2d.drawRect(x + w, y + h2, BARSIZE, BARSIZE); // right
1593: }
1594:
1595: // Reverse video within the outer rectangle to increase visibility
1596: // over areas different from the dominant background color
1597: g2d.setColor(colors.selectionColorReverse);
1598: g2d.drawRect(x - BARSIZE - 1 + 1, y - BARSIZE - 1 + 1,
1599: BARSIZE - 2, BARSIZE - 2);
1600: g2d.drawRect(x + w + 1, y - BARSIZE - 1 + 1, BARSIZE - 2,
1601: BARSIZE - 2);
1602: g2d.drawRect(x + w + 1, y + h + 1, BARSIZE - 2, BARSIZE - 2);
1603: g2d.drawRect(x - BARSIZE - 1 + 1, y + h + 1, BARSIZE - 2,
1604: BARSIZE - 2);
1605:
1606: // if ((constraints & Constants.ResizeConstraints.TOP) != 0) {
1607: if (Resizer.hasTopResizeConstraint(resizeConstraints)) {
1608: g2d.drawRect(x + w2 + 1, y - BARSIZE - 1 + 1, BARSIZE - 2,
1609: BARSIZE - 2); // top
1610: }
1611:
1612: // if ((constraints & Constants.ResizeConstraints.LEFT) != 0) {
1613: if (Resizer.hasLeftResizeConstraint(resizeConstraints)) {
1614: g2d.drawRect(x - BARSIZE - 1 + 1, y + h2 + 1, BARSIZE - 2,
1615: BARSIZE - 2); // left
1616: }
1617:
1618: // if ((constraints & Constants.ResizeConstraints.BOTTOM) != 0) {
1619: if (Resizer.hasBottomResizeConstraint(resizeConstraints)) {
1620: g2d.drawRect(x + w2 + 1, y + h + 1, BARSIZE - 2,
1621: BARSIZE - 2); // bottom
1622: }
1623:
1624: // if ((constraints & Constants.ResizeConstraints.RIGHT) != 0) {
1625: if (Resizer.hasRightResizeConstraint(resizeConstraints)) {
1626: g2d.drawRect(x + w + 1, y + h2 + 1, BARSIZE - 2,
1627: BARSIZE - 2); // right
1628: }
1629:
1630: if (isPrimary) {
1631: // Fill in the selection squares to indicate the primary
1632: // item. We only fill in the corners to make it stand out a
1633: // bit more.
1634: g2d.setColor(colors.primaryColor);
1635: g2d.fillRect(x - BARSIZE - 1 + 1, y - BARSIZE - 1 + 1,
1636: (BARSIZE + 1) - 2, (BARSIZE + 1) - 2);
1637: g2d.fillRect(x + w + 1, y - BARSIZE - 1 + 1,
1638: (BARSIZE + 1) - 2, (BARSIZE + 1) - 2);
1639: g2d.fillRect(x + w + 1, y + h + 1, (BARSIZE + 1) - 2,
1640: (BARSIZE + 1) - 2);
1641: g2d.fillRect(x - BARSIZE - 1 + 1, y + h + 1,
1642: (BARSIZE + 1) - 2, (BARSIZE + 1) - 2);
1643:
1644: // if ((constraints & Constants.ResizeConstraints.TOP) != 0) {
1645: if (Resizer.hasTopResizeConstraint(resizeConstraints)) {
1646: g2d.drawRect(x + w2 + 1, y - BARSIZE - 1 + 1,
1647: BARSIZE - 2, BARSIZE - 2); // top
1648: }
1649:
1650: // if ((constraints & Constants.ResizeConstraints.LEFT) != 0) {
1651: if (Resizer.hasLeftResizeConstraint(resizeConstraints)) {
1652: g2d.drawRect(x - BARSIZE - 1 + 1, y + h2 + 1,
1653: BARSIZE - 2, BARSIZE - 2); // left
1654: }
1655:
1656: // if ((constraints & Constants.ResizeConstraints.BOTTOM) != 0) {
1657: if (Resizer.hasBottomResizeConstraint(resizeConstraints)) {
1658: g2d.drawRect(x + w2 + 1, y + h + 1, BARSIZE - 2,
1659: BARSIZE - 2); // bottom
1660: }
1661:
1662: // if ((constraints & Constants.ResizeConstraints.RIGHT) != 0) {
1663: if (Resizer.hasRightResizeConstraint(resizeConstraints)) {
1664: g2d.drawRect(x + w + 1, y + h2 + 1, BARSIZE - 2,
1665: BARSIZE - 2); // right
1666: }
1667: }
1668:
1669: //g2d.setPaintMode();
1670: }
1671:
1672: /**
1673: * Draw selection for the given view.
1674: * @param g The graphics to draw with
1675: * @param insertMode If true, draw a thick insert-mode rectangle
1676: * around the selection
1677: * @param rect The selection rectangle
1678: * @param constraints Which sides are resizable
1679: */
1680: void paintInlineEditorBox(Graphics2D g2d, Rectangle rect) {
1681: int x = rect.x;
1682: int y = rect.y;
1683: int w = rect.width;
1684: int h = rect.height;
1685:
1686: if (x < (BARSIZE + 1)) {
1687: w -= ((BARSIZE + 1) - x);
1688: x = BARSIZE + 1;
1689: }
1690:
1691: if (y < (BARSIZE + 1)) {
1692: h -= ((BARSIZE + 1) - y);
1693: y = BARSIZE + 1;
1694: }
1695:
1696: PageBox pageBox = webform.getPane().getPageBox();
1697: int maxWidth = pageBox.getWidth();
1698: int maxHeight = pageBox.getHeight();
1699:
1700: if ((x + w + BARSIZE) > maxWidth) {
1701: w = maxWidth - BARSIZE - x;
1702: }
1703:
1704: if ((y + h + BARSIZE) > maxHeight) {
1705: h = maxHeight - BARSIZE - y;
1706: }
1707:
1708: //g2d.setColor(Marquee.marqueeColor); // TODO - make selectable
1709: //g2d.setXORMode(view.getContainer().getBackground());
1710: //g2d.setPaintMode(); // Just in case...
1711: // I've gotta clip! I'm drawing outside of the canvas on OSX!
1712: ColorManager colors = webform.getColors();
1713: g2d.setColor(colors.selectionColor); // TODO - make selectable
1714:
1715: g2d
1716: .drawRect(x - BARSIZE - 1, y - BARSIZE - 1, BARSIZE,
1717: BARSIZE);
1718: g2d.drawRect(x + w, y - BARSIZE - 1, BARSIZE, BARSIZE);
1719: g2d.drawRect(x + w, y + h, BARSIZE, BARSIZE);
1720: g2d.drawRect(x - BARSIZE - 1, y + h, BARSIZE, BARSIZE);
1721:
1722: // Reverse video within the outer rectangle to increase visibility
1723: // over areas different from the dominant background color
1724: g2d.setColor(colors.selectionColorReverse);
1725: g2d.drawRect(x - BARSIZE - 1 + 1, y - BARSIZE - 1 + 1,
1726: BARSIZE - 2, BARSIZE - 2);
1727: g2d.drawRect(x + w + 1, y - BARSIZE - 1 + 1, BARSIZE - 2,
1728: BARSIZE - 2);
1729: g2d.drawRect(x + w + 1, y + h + 1, BARSIZE - 2, BARSIZE - 2);
1730: g2d.drawRect(x - BARSIZE - 1 + 1, y + h + 1, BARSIZE - 2,
1731: BARSIZE - 2);
1732:
1733: // Solid text bars
1734: g2d.setColor(colors.insertColor); // TODO - make selectable
1735: g2d.fillRect(x + 1, y - BARSIZE - 1, w - 2, (BARSIZE + 1) - 1);
1736: g2d.fillRect(x + 1, y + h + 1, w - 2, (BARSIZE + 1) - 1);
1737: g2d.fillRect(x - BARSIZE - 1, y + 1, (BARSIZE + 1) - 1, h - 2);
1738: g2d.fillRect(x + w + 1, y + 1, (BARSIZE + 1) - 1, h - 2);
1739:
1740: //g2d.setPaintMode();
1741: }
1742:
1743: /** Check to see if the cursor position is over a selection rectangle.
1744: * This method is here next to the drawing routine since it's closely
1745: * tied to how the selection is rendered - it should be pixel accurate
1746: * about whether the given position is on top of a selection
1747: * handle bar.
1748: * @param px The x coordinate of the position we want to check
1749: * @param py The y coordinate of the position we want to check
1750: * @param rect The rectangle for a selected view/component
1751: * @param constraints Resizability constraints
1752: * @return An integer equal to either Cursor.DEFAULT_CURSOR if there
1753: * is no overlap, or Cursor.N_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR,
1754: * (etc. etc. for all the directions) to indicate that there is a match,
1755: * an in particular on which edge/corner. Thus, there is overlap
1756: * if return value is not equal to Cursor.DEFAULT_CURSOR, and the
1757: * specific return value can be used to for example pick an appropriate
1758: * Cursor to draw.
1759: */
1760: private int overSelection(int px, int py, Rectangle rect, /*int constraints,*/
1761: ResizeConstraint[] resizeConstraints, int maxWidth, int maxHeight) {
1762: if (py >= selectionViewPos) {
1763: return Cursor.DEFAULT_CURSOR;
1764: }
1765:
1766: int x = rect.x;
1767: int y = rect.y;
1768: int w = rect.width;
1769: int h = rect.height;
1770:
1771: if (x < (BARSIZE + 1)) {
1772: w -= ((BARSIZE + 1) - x);
1773: x = BARSIZE + 1;
1774: }
1775:
1776: if (y < (BARSIZE + 1)) {
1777: h -= ((BARSIZE + 1) - y);
1778: y = BARSIZE + 1;
1779: }
1780:
1781: // Quick elimination - not within the rectangle that surrounds the
1782: // view of width BARSIZE. This is true for most points in the canvas
1783: // so is a quick way to speed up the search
1784: if (px < (x - BARSIZE - 1)) {
1785: return Cursor.DEFAULT_CURSOR;
1786: }
1787:
1788: if (py < (y - BARSIZE - 1)) {
1789: return Cursor.DEFAULT_CURSOR;
1790: }
1791:
1792: if ((x + w + BARSIZE) > maxWidth) {
1793: w = maxWidth - BARSIZE - x;
1794: }
1795:
1796: if ((y + h + BARSIZE) > maxHeight) {
1797: h = maxHeight - BARSIZE - y;
1798: }
1799:
1800: if (px > (x + w + BARSIZE)) {
1801: return Cursor.DEFAULT_CURSOR;
1802: }
1803:
1804: if (py > (y + h + BARSIZE)) {
1805: return Cursor.DEFAULT_CURSOR;
1806: }
1807:
1808: // Okay, do some more fine tuned checking
1809: if (DesignerUtils.inside(px, py, x - BARSIZE - 1, y - BARSIZE
1810: - 1, BARSIZE, BARSIZE)) {
1811: // if ((constraints &
1812: // (Constants.ResizeConstraints.TOP | Constants.ResizeConstraints.LEFT)) == (Constants.ResizeConstraints.TOP |
1813: // Constants.ResizeConstraints.LEFT)) {
1814: if (Resizer.hasTopResizeConstraint(resizeConstraints)
1815: && Resizer
1816: .hasLeftResizeConstraint(resizeConstraints)) {
1817: return Cursor.NW_RESIZE_CURSOR;
1818: // } else if ((constraints & Constants.ResizeConstraints.TOP) != 0) {
1819: } else if (Resizer
1820: .hasTopResizeConstraint(resizeConstraints)) {
1821: return Cursor.N_RESIZE_CURSOR;
1822: // } else if ((constraints & Constants.ResizeConstraints.LEFT) != 0) {
1823: } else if (Resizer
1824: .hasLeftResizeConstraint(resizeConstraints)) {
1825: return Cursor.W_RESIZE_CURSOR;
1826: }
1827: }
1828:
1829: if (DesignerUtils.inside(px, py, x + w, y - BARSIZE - 1,
1830: BARSIZE, BARSIZE)) {
1831: // if ((constraints &
1832: // (Constants.ResizeConstraints.TOP | Constants.ResizeConstraints.RIGHT)) == (Constants.ResizeConstraints.TOP |
1833: // Constants.ResizeConstraints.RIGHT)) {
1834: if (Resizer.hasTopResizeConstraint(resizeConstraints)
1835: && Resizer
1836: .hasRightResizeConstraint(resizeConstraints)) {
1837: return Cursor.NE_RESIZE_CURSOR;
1838: // } else if ((constraints & Constants.ResizeConstraints.TOP) != 0) {
1839: } else if (Resizer
1840: .hasTopResizeConstraint(resizeConstraints)) {
1841: return Cursor.N_RESIZE_CURSOR;
1842: // } else if ((constraints & Constants.ResizeConstraints.RIGHT) != 0) {
1843: } else if (Resizer
1844: .hasRightResizeConstraint(resizeConstraints)) {
1845: return Cursor.E_RESIZE_CURSOR;
1846: }
1847: }
1848:
1849: if (DesignerUtils
1850: .inside(px, py, x + w, y + h, BARSIZE, BARSIZE)) {
1851: // if ((constraints &
1852: // (Constants.ResizeConstraints.BOTTOM | Constants.ResizeConstraints.RIGHT)) == (Constants.ResizeConstraints.BOTTOM |
1853: // Constants.ResizeConstraints.RIGHT)) {
1854: if (Resizer.hasBottomResizeConstraint(resizeConstraints)
1855: && Resizer
1856: .hasRightResizeConstraint(resizeConstraints)) {
1857: return Cursor.SE_RESIZE_CURSOR;
1858: // } else if ((constraints & Constants.ResizeConstraints.BOTTOM) != 0) {
1859: } else if (Resizer
1860: .hasBottomResizeConstraint(resizeConstraints)) {
1861: return Cursor.S_RESIZE_CURSOR;
1862: // } else if ((constraints & Constants.ResizeConstraints.RIGHT) != 0) {
1863: } else if (Resizer
1864: .hasRightResizeConstraint(resizeConstraints)) {
1865: return Cursor.E_RESIZE_CURSOR;
1866: }
1867: }
1868:
1869: if (DesignerUtils.inside(px, py, x - BARSIZE - 1, y + h,
1870: BARSIZE, BARSIZE)) {
1871: // if ((constraints &
1872: // (Constants.ResizeConstraints.BOTTOM | Constants.ResizeConstraints.LEFT)) == (Constants.ResizeConstraints.BOTTOM |
1873: // Constants.ResizeConstraints.LEFT)) {
1874: if (Resizer.hasBottomResizeConstraint(resizeConstraints)
1875: && Resizer
1876: .hasLeftResizeConstraint(resizeConstraints)) {
1877: return Cursor.SW_RESIZE_CURSOR;
1878: // } else if ((constraints & Constants.ResizeConstraints.BOTTOM) != 0) {
1879: } else if (Resizer
1880: .hasBottomResizeConstraint(resizeConstraints)) {
1881: return Cursor.S_RESIZE_CURSOR;
1882: // } else if ((constraints & Constants.ResizeConstraints.LEFT) != 0) {
1883: } else if (Resizer
1884: .hasLeftResizeConstraint(resizeConstraints)) {
1885: return Cursor.W_RESIZE_CURSOR;
1886: }
1887: }
1888:
1889: // In inline editing mode we can drag the border to start moving the component
1890: // PENDING: Look for a movable parent first to decide?
1891: // Or only do this for positioned components?
1892: if (webform.getManager().isInlineEditing()
1893: && DesignerUtils.inside(px, py, x - BARSIZE - 1, y
1894: - BARSIZE - 1, w + (2 * BARSIZE), h
1895: + (2 * BARSIZE))
1896: && !DesignerUtils.inside(px, py, x, y, w, h)) {
1897: return Cursor.MOVE_CURSOR;
1898: }
1899:
1900: int w2 = (w / 2) - (BARSIZE / 2);
1901: int h2 = (h / 2) - (BARSIZE / 2);
1902:
1903: // if ((constraints & Constants.ResizeConstraints.TOP) != 0) {
1904: if (Resizer.hasTopResizeConstraint(resizeConstraints)) {
1905: if (DesignerUtils.inside(px, py, (x + w2) - (BARSIZE / 2),
1906: y - BARSIZE - 1, BARSIZE, BARSIZE)) {
1907: return Cursor.N_RESIZE_CURSOR;
1908: }
1909: }
1910:
1911: // if ((constraints & Constants.ResizeConstraints.LEFT) != 0) {
1912: if (Resizer.hasLeftResizeConstraint(resizeConstraints)) {
1913: if (DesignerUtils.inside(px, py, x - BARSIZE - 1, (y + h2)
1914: - (BARSIZE / 2), BARSIZE, BARSIZE)) {
1915: return Cursor.W_RESIZE_CURSOR;
1916: }
1917: }
1918:
1919: // if ((constraints & Constants.ResizeConstraints.BOTTOM) != 0) {
1920: if (Resizer.hasBottomResizeConstraint(resizeConstraints)) {
1921: if (DesignerUtils.inside(px, py, (x + w2) - (BARSIZE / 2),
1922: y + h, BARSIZE, BARSIZE)) {
1923: return Cursor.S_RESIZE_CURSOR;
1924: }
1925: }
1926:
1927: // if ((constraints & Constants.ResizeConstraints.RIGHT) != 0) {
1928: if (Resizer.hasRightResizeConstraint(resizeConstraints)) {
1929: if (DesignerUtils.inside(px, py, x + w, (y + h2)
1930: - (BARSIZE / 2), BARSIZE, BARSIZE)) {
1931: return Cursor.E_RESIZE_CURSOR;
1932: }
1933: }
1934:
1935: return Cursor.DEFAULT_CURSOR;
1936: }
1937:
1938: // XXX HACKY CODE! Clean up once we agree on the UI & operation for this!
1939: public void paintSelHierarchy(Graphics2D g2d) {
1940: if (!PAINT_SELECTION_HIERARCHY) {
1941: return;
1942: }
1943:
1944: if (isSelectionEmpty()) {
1945: return;
1946: }
1947:
1948: PageBox pageBox = webform.getPane().getPageBox();
1949:
1950: if (pageBox == null) {
1951: return;
1952: }
1953:
1954: JViewport viewport = pageBox.getViewport();
1955: Dimension d = viewport.getExtentSize();
1956: Point p = viewport.getViewPosition();
1957: FontMetrics metrics = webform.getPane().getMetrics();
1958: FontMetrics boldMetrics = webform.getPane().getBoldMetrics();
1959:
1960: // Keep this positioning logic in sync with notifyScrolled!
1961: int h = metrics.getHeight() + 1;
1962: int x = SELECTIONVIEW_LEFT;
1963: int y = (p.y + d.height) - h;
1964: int yadj = (y + metrics.getHeight()) - metrics.getDescent();
1965: selectionViewPos = y;
1966:
1967: ColorManager colors = webform.getColors();
1968: g2d.setColor(colors.hierarchyBackgroundColor);
1969: g2d.fillRect(x, y, d.width, h);
1970: g2d.setColor(colors.hierarchyForegroundColor);
1971:
1972: // Draw for the first selected item
1973: // Iterator it = selected.iterator();
1974: // assert it.hasNext();
1975: //
1976: // FormObject fo = (FormObject)it.next();
1977: // MarkupDesignBean currentBean = fo.component;
1978: Iterator<SelectedComponent> it = selectedComponents.iterator();
1979: assert it.hasNext();
1980: SelectedComponent sc = it.next();
1981: // MarkupDesignBean currentBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(sc.componentRootElement);
1982:
1983: // MarkupDesignBean leafBean = leaf;
1984: // MarkupDesignBean leafBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(leaf);
1985:
1986: // if (leafBean == null) {
1987: // leafBean = currentBean;
1988: // }
1989: if (leaf == null) {
1990: leaf = sc.componentRootElement;
1991: }
1992:
1993: // paintOrSelectAncestor(g2d, metrics, boldMetrics, leafBean, x, y, yadj, currentBean, -1);
1994: paintOrSelectAncestor(g2d, metrics, boldMetrics, leaf, x, y,
1995: yadj, sc.componentRootElement, -1);
1996: }
1997:
1998: // XXX HACKY CODE! Clean up once we agree on the UI & operation for this!
1999: public void notifyScrolled() {
2000: if (!PAINT_SELECTION_HIERARCHY) {
2001: return;
2002: }
2003:
2004: // Gotta repaint to ensure that we place the selection
2005: // hierarchy view on the right line
2006: if (isSelectionEmpty()) {
2007: return;
2008: }
2009:
2010: PageBox pageBox = webform.getPane().getPageBox();
2011:
2012: if (pageBox == null) {
2013: return;
2014: }
2015:
2016: JViewport viewport = pageBox.getViewport();
2017: Point p = viewport.getViewPosition();
2018: Dimension d = viewport.getExtentSize();
2019: FontMetrics metrics = webform.getPane().getMetrics();
2020: int h = metrics.getHeight() + 1;
2021: int y = (p.y + d.height) - h;
2022:
2023: if (y != selectionViewPos) {
2024: webform.getPane().repaint();
2025: }
2026: }
2027:
2028: // XXX HACKY CODE! Clean up once we agree on the UI & operation for this!
2029: private int paintOrSelectAncestor(Graphics2D g2d,
2030: FontMetrics metrics, FontMetrics boldMetrics,
2031: Element componentRootElement, /*MarkupDesignBean bean,*/
2032: int x, int ytop, int y,
2033: Element selectedComponentRootElement, /*DesignBean selected,*/
2034: int target) {
2035: // if (bean.getBeanParent() instanceof MarkupDesignBean &&
2036: //// !FacesSupport.isSpecialBean(/*webform, */bean)) {
2037: //// !Util.isSpecialBean(bean)) {
2038: // !WebForm.getDomProviderService().isSpecialComponent(
2039: // WebForm.getDomProviderService().getComponentRootElementForMarkupDesignBean(bean))) {
2040: if (!webform.getDomProviderService().isSpecialComponent(
2041: componentRootElement)) {
2042: // x = paintOrSelectAncestor(g2d, metrics, boldMetrics,
2043: // (MarkupDesignBean)bean.getBeanParent(), x, ytop, y, selected, target);
2044: x = paintOrSelectAncestor(g2d, metrics, boldMetrics,
2045: webform.getDomProviderService().getParentComponent(
2046: componentRootElement), x, ytop, y,
2047: selectedComponentRootElement, target);
2048:
2049: if (x < 0) {
2050: return x;
2051: }
2052: }
2053:
2054: // String s = bean.getInstanceName();
2055: //
2056: // if (s == null) {
2057: // s = "<unknown>";
2058: // }
2059: //
2060: // if (x > SELECTIONVIEW_LEFT) {
2061: // s = "- " + bean.getInstanceName();
2062: // }
2063: String s = webform.getDomProviderService().getInstanceName(
2064: componentRootElement);
2065: if (s == null) {
2066: s = "<unknown>"; // TODO I18N
2067: }
2068:
2069: if (g2d != null) { // painting, not selecting
2070:
2071: // if (bean == selected) {
2072: if (componentRootElement == selectedComponentRootElement) {
2073: g2d.setFont(boldMetrics.getFont());
2074: } else {
2075: g2d.setFont(metrics.getFont());
2076: }
2077:
2078: // TODO - icon here?
2079: }
2080:
2081: if (paintBeanIcon) {
2082: // BeanInfo bi = bean.getBeanInfo();
2083: // Image icon = null;
2084: //
2085: // if (bi != null) {
2086: // icon = bi.getIcon(BeanInfo.ICON_COLOR_16x16);
2087: Image icon = webform.getDomProviderService().getIcon(
2088: componentRootElement);
2089:
2090: if (icon != null) {
2091: if (g2d != null) {
2092: float ix = (float) x;
2093: float iy = (float) ytop;
2094: transform.setToTranslation(ix, iy);
2095: g2d.drawImage(icon, transform, null);
2096: }
2097:
2098: x += (16 + 2); // spacing
2099: }
2100: // }
2101: }
2102:
2103: if (g2d != null) {
2104: g2d.drawString(s, x, y);
2105:
2106: // XXX restore font?
2107: }
2108:
2109: // if (bean == selected) {
2110: if (componentRootElement == selectedComponentRootElement) {
2111: x += boldMetrics.stringWidth(s);
2112: } else {
2113: x += metrics.stringWidth(s);
2114: }
2115:
2116: x += 5; // spacing
2117:
2118: if (g2d == null) {
2119: // See if we've gone past the x position where the user
2120: // clicked on a component, thus this must be the item we're
2121: // interested in
2122: if (x > target) {
2123: // setSelected(bean, true);
2124: setSelected(componentRootElement, true);
2125:
2126: return -1;
2127: }
2128: }
2129:
2130: return x;
2131: }
2132:
2133: // XXX HACKY CODE! Clean up once we agree on the UI & operation for this!
2134: void selectAncestor(int targetx, int targety) {
2135: if (isSelectionEmpty()) {
2136: return;
2137: }
2138:
2139: PageBox pageBox = webform.getPane().getPageBox();
2140:
2141: if (pageBox == null) {
2142: return;
2143: }
2144:
2145: FontMetrics metrics = webform.getPane().getMetrics();
2146: FontMetrics boldMetrics = webform.getPane().getBoldMetrics();
2147: int x = 1;
2148: int y = selectionViewPos;
2149: int yadj = (y + metrics.getHeight()) - metrics.getDescent();
2150: // Iterator it = selected.iterator();
2151: // assert it.hasNext();
2152: //
2153: // FormObject fo = (FormObject)it.next();
2154: // MarkupDesignBean currentBean = fo.component;
2155: Iterator<SelectedComponent> it = selectedComponents.iterator();
2156: assert it.hasNext();
2157: SelectedComponent sc = it.next();
2158: // MarkupDesignBean currentBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(sc.componentRootElement);
2159:
2160: // MarkupDesignBean leafBean = leaf;
2161: // MarkupDesignBean leafBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(leaf);
2162:
2163: // if (leafBean == null) {
2164: // leafBean = currentBean;
2165: // }
2166: if (leaf == null) {
2167: leaf = sc.componentRootElement;
2168: }
2169:
2170: // paintOrSelectAncestor(null, metrics, boldMetrics, leafBean, x, y, yadj, currentBean, targetx);
2171: paintOrSelectAncestor(null, metrics, boldMetrics, leaf, x, y,
2172: yadj, sc.componentRootElement, targetx);
2173: }
2174:
2175: /**
2176: * Set the activated nodes for the top component bound to this selection
2177: * manager to match the current component.
2178: * If there is a component (or multiple components) selected,
2179: * the nodes will reflect these components, otherwise a document node
2180: * is chosen.
2181: * @todo If the selection MATCHES what is already shown, don't do anything.
2182: */
2183: public void updateNodes() {
2184: /* No - this is too risky; for example, if you right click on
2185: a component it must be selected immediately (since the context
2186: menu is keyed off the activated nodes list). So I've gotta
2187: call updateNodesImmediate() in that case. Gotta think about
2188: this some more before doing it.
2189: */
2190: if (refreshTimer != null) {
2191: refreshTimer.stop();
2192: refreshTimer = null;
2193: }
2194:
2195: refreshTimer = new Timer(NODE_REFRESH_DELAY,
2196: new ActionListener() {
2197: public void actionPerformed(ActionEvent evt) {
2198: refreshTimer = null;
2199: updateNodesImmediate();
2200: }
2201: });
2202: refreshTimer.setRepeats(false);
2203: refreshTimer.setCoalesce(true);
2204: refreshTimer.start();
2205: }
2206:
2207: /** Return true iff there is a pending node update scheduled */
2208: public boolean isNodeUpdatePending() {
2209: return refreshTimer != null;
2210: }
2211:
2212: // private void releaseNodes() {
2213: // // There is most likely a better way to do this Tor, its to allow me to get further with
2214: // // leaks.
2215: // if (prevNodes != null) {
2216: //// // Ensure that the property change listeners are cleared out.
2217: //// // We could consider using weak listeners too.
2218: //// for (int i = 0; i < prevNodes.length; i++) {
2219: //// if (prevNodes[i] instanceof DesignBeanNode) {
2220: //// ((DesignBeanNode)prevNodes[i]).setDataObject(null);
2221: ////// } else if (prevNodes[i] instanceof DocumentCompNode) {
2222: ////// ((DocumentCompNode)prevNodes[i]).setDataObject(null);
2223: //// } else {
2224: //// ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL,
2225: //// new IllegalStateException("Not expected node=" + prevNodes[i])); // NOI18N
2226: //// }
2227: //// }
2228: //
2229: // prevNodes = null;
2230: // }
2231: // }
2232:
2233: /**
2234: * Same as {@link updateNodes} but this request is processed immediately/synchronously
2235: */
2236: public void updateNodesImmediate() {
2237: if (refreshTimer != null) {
2238: refreshTimer.stop();
2239: refreshTimer = null;
2240: }
2241:
2242: //// releaseNodes();
2243: //
2244: //// DataObject dobj = webform.getDataObject();
2245: //// DesignerTopComp topcomp = webform.getTopComponent();
2246: //
2247: //// // Ensure that the tray is no longer appearing selected
2248: //// topcomp.clearTraySelection();
2249: //
2250: //// if ((selected != null) && (selected.size() > 0)) {
2251: ////// Iterator it = selected.iterator();
2252: ////
2253: //// //Node[] nodes = new Node[selected.size()];
2254: //// ArrayList nodes = new ArrayList(selected.size());
2255: ////
2256: ////// while (it.hasNext()) {
2257: ////// FormObject fo = (FormObject)it.next();
2258: //// for (FormObject fo : selected) {
2259: //// DesignBean component = fo.component;
2260: // if (!selectedComponents.isEmpty()) {
2261: // //Node[] nodes = new Node[selected.size()];
2262: // List<Node> nodes = new ArrayList<Node>(selectedComponents.size());
2263: // for (SelectedComponent sc : selectedComponents) {
2264: //// DesignBean component = WebForm.getDomProviderService().getMarkupDesignBeanForElement(sc.componentRootElement);
2265: //// Node n = DesigntimeIdeBridgeProvider.getDefault().getNodeRepresentation(component);
2266: // Node n = WebForm.getDomProviderService().getNodeRepresentation(sc.componentRootElement);
2267: //// n.setDataObject(dobj);
2268: // nodes.add(n);
2269: // }
2270: //
2271: // Node[] nds = nodes.toArray(new Node[nodes.size()]);
2272: //
2273: //// if (topcomp.isShowing()) {
2274: //// topcomp.requestActive();
2275: //// }
2276: //
2277: //// DesignerUtils.setActivatedNodes(topcomp, nds);
2278: // webform.tcSetActivatedNodes(nds);
2279: //// prevNodes = nds;
2280: //
2281: // } else {
2282: //// <>
2283: //// Node[] nodes = new Node[1];
2284: ////
2285: //// if (documentComponent == null) {
2286: //// documentComponent = new DocumentComp(webform);
2287: //// } else {
2288: //// documentComponent.sync();
2289: //// }
2290: ////
2291: //// DocumentCompNode node = new DocumentCompNode(documentComponent, dobj);
2292: ////
2293: //// //node.setDataObject(dobj);
2294: //// nodes[0] = node;
2295: ////
2296: //// if (topcomp.isShowing()) {
2297: //// topcomp.requestActive();
2298: //// }
2299: ////
2300: //// DesignerUtils.setActivatedNodes(topcomp, nodes);
2301: //// prevNodes = nodes;
2302: //// ====
2303: // // XXX Ugly way of maintaining activated nodes.
2304: // // TODO Redesign activated nodes retrieval/setting.
2305: // Node[] nodes;
2306: //// FacesModel facesModel = webform.getModel();
2307: //// DesignBean rootBean = facesModel.getRootBean();
2308: //// if (rootBean == null) {
2309: //// // XXX If the model is busted then it is supposed to be OK, there is an error, see e.g. #6478860.
2310: //// if (!facesModel.isBusted()) {
2311: //// ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL,
2312: //// new IllegalStateException("Invalid FacesModel, it is not busted and its root design bean is null, facesModel=" + facesModel)); // NOI18N
2313: //// }
2314: //// nodes = new Node[0];
2315: //// } else {
2316: //// Node n = DesigntimeIdeBridgeProvider.getDefault().getNodeRepresentation(rootBean);
2317: ////// n.setDataObject(dobj);
2318: //// nodes = new Node[] {n};
2319: //// }
2320: // Node rootNode = webform.getRootBeanNode();
2321: // nodes = rootNode == null ? new Node[0] : new Node[] {rootNode};
2322: //
2323: //// DesignerUtils.setActivatedNodes(topcomp, nodes);
2324: // webform.tcSetActivatedNodes(nodes);
2325: //// // XXX Why is this here? Why it should get active based on node setting?
2326: //// if (topcomp.isShowing()) {
2327: //// topcomp.requestActive();
2328: //// }
2329: //// prevNodes = nodes;
2330: //// </>
2331: // }
2332: //
2333: // // XXX #101248 This seems to be needless.
2334: //// if(!webform.isGridMode()) {
2335: //// selectTextBetweenSelectedNodes();
2336: //// }
2337: webform
2338: .fireSelectionChanged(new SelectionDesignerEvent(
2339: webform));
2340: }
2341:
2342: private static class SelectionDesignerEvent implements
2343: DesignerEvent {
2344: private final WebForm webForm;
2345:
2346: public SelectionDesignerEvent(WebForm webForm) {
2347: this .webForm = webForm;
2348: }
2349:
2350: public Designer getDesigner() {
2351: return webForm;
2352: }
2353:
2354: public Box getBox() {
2355: return null;
2356: }
2357: } // End of SelectionDesignerEvent.
2358:
2359: // private void selectTextBetweenSelectedNodes() {
2360: //// Position start = null, end = null;
2361: // DomPosition start = null;
2362: // DomPosition end = null;
2363: //
2364: //// if ((selected != null) && (selected.size() > 0)) {
2365: ////// Iterator it = selected.iterator();
2366: //// Position startNode, endNode;
2367: ////// while (it.hasNext()) {
2368: ////// FormObject fo = (FormObject)it.next();
2369: //// for (FormObject fo : selected) {
2370: //// startNode = Position.create(fo.component.getElement(), false);
2371: // if (!selectedComponents.isEmpty()) {
2372: //// Position startNode, endNode;
2373: // DomPosition startNode;
2374: // DomPosition endNode;
2375: //
2376: // for (SelectedComponent sc : selectedComponents) {
2377: //// Element sourceElement = WebForm.getDomProviderService().getMarkupDesignBeanForElement(sc.componentRootElement).getElement();
2378: // Element sourceElement = WebForm.getDomProviderService().getSourceElement(sc.componentRootElement);
2379: //// startNode = Position.create(sourceElement, false);
2380: // startNode = webform.createDomPosition(sourceElement, false);
2381: //
2382: // if(start == null || startNode.isEarlierThan(start)) {
2383: // start = startNode;
2384: // }
2385: //// endNode = Position.create(fo.component.getElement(), true);
2386: //// endNode = Position.create(sourceElement, true);
2387: // endNode = webform.createDomPosition(sourceElement, true);
2388: //
2389: // if(end == null || end.isEarlierThan(endNode)) {
2390: // end = endNode;
2391: // }
2392: // }
2393: // } else {
2394: //// start = Position.NONE;
2395: //// end = Position.NONE;
2396: // start = DomPosition.NONE;
2397: // end = DomPosition.NONE;
2398: // }
2399: //// if(webform.getPane().getCaret() != null) {
2400: // if(webform.getPane().hasCaret()) {
2401: //// webform.getPane().getCaret().setDot(start);
2402: //// webform.getPane().getCaret().moveDot(end);
2403: // webform.getPane().setCaretDot(start);
2404: // webform.getPane().moveCaretDot(end);
2405: // }
2406: // }
2407:
2408: // /** Return set of currently selected nodes */
2409: // public Node[] getSelectedNodes() {
2410: // if (refreshTimer != null) {
2411: // // The nodes may not be current - there's a pending update. Cancel the
2412: // // update request and update the nodes immediately instead
2413: // refreshTimer.stop();
2414: // refreshTimer = null;
2415: // updateNodesImmediate();
2416: // }
2417: //
2418: //// return webform.getTopComponent().getActivatedNodes();
2419: // return webform.tcGetActivatedNodes();
2420: // }
2421:
2422: /** Return the primary selection, if any. The primary is the most recently
2423: * "touched" DesignBean in the selection. For example, if you swipe select
2424: * a set of 10 components and then right click on one of them, all are selected
2425: * but the clicked-on component is primary. Similarly, if you shift-click toggle
2426: * components in the selection, the most recently clicked component is primary.
2427: * This component is highlighted using a different color than the rest.
2428: */
2429: public/*MarkupDesignBean*/Element getPrimary() {
2430: return primary;
2431: // return WebForm.getDomProviderService().getMarkupDesignBeanForElement(primary);
2432: }
2433:
2434: /**
2435: * Choose a bean as the primary selection bean
2436: */
2437: public void setPrimary(/*MarkupDesignBean*/Element primary) {
2438: this .primary = primary;
2439: // this.primary = getComponentRootElementForMarkupDesignBean(primary);
2440: }
2441:
2442: /**
2443: * XXX Bad architecture.
2444: * TODO Get rid of this, and update the primary as selection changes.
2445: *
2446: * Ask the selection manager to pick a primary selection object, if it has
2447: * one or more selection objects but none designated as primary.
2448: * If one is already primary, it is kept as the primary.
2449: */
2450: public void pickPrimary() {
2451: if (primary == null) {
2452: // Iterator it = selected.iterator();
2453: // FormObject fob = (FormObject)it.next();
2454: // primary = fob.component;
2455: Iterator<SelectedComponent> it = selectedComponents
2456: .iterator();
2457: SelectedComponent sc = it.next();
2458: primary = sc.componentRootElement;
2459: }
2460: }
2461:
2462: // /**
2463: // * Return an iterator for iterating through the MarkupDesignBeans in the
2464: // * selection set.
2465: // */
2466: // public Iterator<MarkupDesignBean> iterator() {
2467: // return new BeanIterator();
2468: // }
2469:
2470: // public MarkupDesignBean[] getSelectedMarkupDesignBeans() {
2471: // List<MarkupDesignBean> markupDesignBeans = new ArrayList<MarkupDesignBean>();
2472: // for (Iterator<MarkupDesignBean> it = iterator(); it.hasNext(); ) {
2473: // MarkupDesignBean markupDesignBean = it.next();
2474: // if (markupDesignBean != null && !markupDesignBeans.contains(markupDesignBean)) {
2475: // markupDesignBeans.add(markupDesignBean);
2476: // }
2477: // }
2478: // return markupDesignBeans.toArray(new MarkupDesignBean[markupDesignBeans.size()]);
2479: // }
2480: public Element[] getSelectedComponentRootElements() {
2481: List<Element> componentRootElements = new ArrayList<Element>();
2482: List<SelectedComponent> scs = new ArrayList<SelectedComponent>(
2483: selectedComponents);
2484: for (SelectedComponent selectedComponent : scs) {
2485: if (selectedComponent == null) {
2486: continue;
2487: }
2488: Element componentRootElement = selectedComponent.componentRootElement;
2489: if (componentRootElement != null) {
2490: componentRootElements.add(componentRootElement);
2491: }
2492: }
2493: return componentRootElements
2494: .toArray(new Element[componentRootElements.size()]);
2495: }
2496:
2497: // --------------------------------------------------------------------
2498: // Selection Management: Deal with the selection-set
2499: // --------------------------------------------------------------------
2500: // The selection set consists of FormObjects, where each page object
2501: // represents a selectable object on the page (which may correspond
2502: // to toolbar components).
2503:
2504: // // TODO JSF specific, get rid of it, replace it with the latter.
2505: // /** Represents a "component" in the view. Not called component to avoid
2506: // * confusion with the component class of the actual component from the
2507: // * toolbar. This is simply a wrapper object used to hold information
2508: // * pertaining to selections etc. */
2509: // private static class FormObject { // TODO Rename SelectedComponent
2510: //
2511: // MarkupDesignBean component = null;
2512: //
2513: // /** Resizability of this component. A bit mask representing state
2514: // * according to Constants.ResizeConstraints. */
2515: // int resizeConstraints;
2516: // }
2517:
2518: // TODO This should replace the above usage.
2519: /** Represents a "component" in the view. Not called component to avoid
2520: * confusion with the component class of the actual component from the
2521: * toolbar. This is simply a wrapper object used to hold information
2522: * pertaining to selections etc. */
2523: private static class SelectedComponent {
2524: private Element componentRootElement;
2525: /** Resizability of this component. A bit mask representing state
2526: * according to Constants.ResizeConstraints. */
2527: // private int resizeConstraints;
2528: private ResizeConstraint[] resizeConstraints;
2529: } // End of SelectedComponent.
2530:
2531: // /** Iterator for iterating through the selection contents */
2532: // private class BeanIterator implements Iterator<MarkupDesignBean> {
2533: // private Iterator<SelectedComponent> iterator;
2534: //
2535: // private BeanIterator() {
2536: //// if ((selected != null) && (selected.size() > 0)) {
2537: //// iterator = selected.iterator();
2538: //// }
2539: // iterator = selectedComponents.iterator();
2540: // }
2541: //
2542: // public boolean hasNext() {
2543: // if (iterator != null) {
2544: // return iterator.hasNext();
2545: // } else {
2546: // return false;
2547: // }
2548: // }
2549: //
2550: // public MarkupDesignBean next() {
2551: //// FormObject fo = (FormObject)iterator.next();
2552: ////
2553: //// return fo.component;
2554: // SelectedComponent sc = iterator.next();
2555: // return WebForm.getDomProviderService().getMarkupDesignBeanForElement(sc.componentRootElement);
2556: // }
2557: //
2558: // public void remove() {
2559: // throw new UnsupportedOperationException();
2560: // }
2561: // }
2562:
2563: void selectBean(/*DesignBean select*/Element componentRootElement) {
2564: // // XXX SelectionManager properly dispatches to DesignerTopComp now
2565: // if (select != null) {
2566: //// if (DesignerTopComp.SHOW_TRAY && LiveUnit.isTrayBean(select)) {
2567: //// webform.getTopComponent().selectTrayBean(select);
2568: //// } else
2569: //// if (LiveUnit.isVisualBean(select)) {
2570: // selectComponents(new DesignBean[] { select }, true);
2571: //// } else {
2572: //// // Some non-tray, non-visual bean, such as a validator.
2573: //// // Simply show it as selected for now.
2574: //// webform.getTopComponent().selectNonTrayBeans(new DesignBean[] { select });
2575: //// }
2576: //
2577: // select = null;
2578: // }
2579: if (componentRootElement != null) {
2580: selectComponents(new Element[] { componentRootElement },
2581: true);
2582: }
2583: }
2584:
2585: // /** XXX Copied from DesignerActions. */
2586: // public static void selectParent(/*DesignBean designBean*/Element componentRootElement) {
2587: //// if (designBean == null) {
2588: //// return;
2589: //// }
2590: //// WebForm webform = WebForm.findWebFormForDesignContext(designBean.getDesignContext());
2591: //// if (webform == null) {
2592: //// return;
2593: //// }
2594: ////
2595: //// webform.getSelection().doSelectParent(designBean);
2596: // if (componentRootElement == null) {
2597: // return;
2598: // }
2599: // WebForm webform = WebForm.findWebFormForElement(componentRootElement);
2600: // if (webform == null) {
2601: // return;
2602: // }
2603: //
2604: // webform.getSelection().doSelectParent(componentRootElement);
2605: // }
2606: //
2607: // private void doSelectParent(/*DesignBean designBean*/Element componentRootElement) {
2608: // webform.getManager().finishInlineEditing(false);
2609: //
2610: //// SelectionManager sm = webform.getSelection();
2611: //
2612: //// DesignBean designBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(componentRootElement);
2613: //// if (designBean == null) {
2614: //// return;
2615: //// }
2616: // if (componentRootElement == null) {
2617: // return;
2618: // }
2619: //
2620: //// if (!canSelectParent(designBean)) {
2621: // if (!canSelectParent(componentRootElement)) {
2622: // if (!webform.isGridMode()) {
2623: // // in flow mode, allow you to escape your way to the top;
2624: // // clear selection and show document properties
2625: // clearSelection(true);
2626: // }
2627: //
2628: // return;
2629: // }
2630: //
2631: // // Find the closest selectable parent that is actually
2632: // // selectable!
2633: //// DesignBean parent = designBean.getBeanParent();
2634: // Element parentComponentRootElement = WebForm.getDomProviderService().getParentComponent(componentRootElement);
2635: //// ModelViewMapper mapper = webform.getMapper();
2636: //
2637: //// while (parent != null) {
2638: // while (parentComponentRootElement != null) {
2639: // // Find the visual (non-form, non-root) parent and select it
2640: //// Element element = FacesSupport.getElement(parent);
2641: //// Element element = Util.getElement(parent);
2642: //// Element element = WebForm.getDomProviderService().getElement(parent);
2643: // Element element = WebForm.getDomProviderService().getSourceElement(parentComponentRootElement);
2644: //
2645: // if (element != null) {
2646: //// CssBox box = mapper.findBox(element);
2647: // CssBox box = ModelViewMapper.findBox(webform.getPane().getPageBox(), element);
2648: //
2649: // if (box != null) {
2650: //// selectComponents(new DesignBean[] { parent }, true);
2651: //// if (parent instanceof MarkupDesignBean) {
2652: // selectComponents(new Element[] { parentComponentRootElement }, true);
2653: // break;
2654: //// }
2655: // }
2656: // }
2657: //
2658: //// parent = parent.getBeanParent();
2659: // parentComponentRootElement = WebForm.getDomProviderService().getParentComponent(parentComponentRootElement);
2660: // }
2661: // }
2662:
2663: void selectComponent(Element componentRootElement) {
2664: if (componentRootElement == null) {
2665: return;
2666: }
2667:
2668: CssBox box = ModelViewMapper.findBox(webform.getPane()
2669: .getPageBox(), componentRootElement);
2670: if (box != null) {
2671: selectComponents(new Element[] { componentRootElement },
2672: true);
2673: }
2674: }
2675:
2676: }
|