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.jsf;
0043:
0044: import java.awt.EventQueue;
0045: import java.util.Arrays;
0046: import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
0047: import org.netbeans.modules.visualweb.api.designer.cssengine.CssValue;
0048: import org.netbeans.modules.visualweb.api.designer.cssengine.StyleData;
0049: import org.netbeans.modules.visualweb.api.designer.cssengine.XhtmlCss;
0050: import org.netbeans.modules.visualweb.api.designer.markup.MarkupService;
0051: import org.netbeans.modules.visualweb.api.designerapi.DesignTimeTransferDataCreator;
0052: import org.netbeans.modules.visualweb.designer.html.HtmlAttribute;
0053: import org.netbeans.modules.visualweb.designer.html.HtmlTag;
0054: import com.sun.rave.designtime.BeanCreateInfo;
0055: import com.sun.rave.designtime.BeanCreateInfoSet;
0056: import com.sun.rave.designtime.DesignBean;
0057: import com.sun.rave.designtime.DesignInfo;
0058: import com.sun.rave.designtime.DesignProject;
0059: import com.sun.rave.designtime.DesignProperty;
0060: import com.sun.rave.designtime.DisplayItem;
0061: import com.sun.rave.designtime.Result;
0062: import com.sun.rave.designtime.markup.MarkupDesignBean;
0063: import com.sun.rave.designtime.markup.MarkupMouseRegion;
0064: import com.sun.rave.designtime.markup.MarkupPosition;
0065: import java.awt.Component;
0066: import org.netbeans.modules.visualweb.insync.InSyncServiceProvider;
0067: import org.netbeans.modules.visualweb.insync.ResultHandler;
0068: import org.netbeans.modules.visualweb.insync.UndoEvent;
0069: import org.netbeans.modules.visualweb.insync.Util;
0070: import org.netbeans.modules.visualweb.insync.beans.Bean;
0071: import org.netbeans.modules.visualweb.insync.faces.HtmlBean;
0072: import org.netbeans.modules.visualweb.insync.faces.MarkupBean;
0073: import org.netbeans.modules.visualweb.insync.live.LiveUnit;
0074: import org.netbeans.modules.visualweb.insync.markup.MarkupUnit;
0075: import org.netbeans.modules.visualweb.insync.models.FacesModel;
0076: import org.netbeans.modules.visualweb.project.jsf.api.Importable;
0077: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectUtils;
0078: import org.netbeans.modules.visualweb.xhtml.Frame;
0079: import org.netbeans.modules.visualweb.xhtml.FramesetFrameset;
0080: import java.awt.Dialog;
0081: import java.awt.Dimension;
0082: import java.awt.GridBagConstraints;
0083: import java.awt.GridBagLayout;
0084: import java.awt.Insets;
0085: import java.awt.Point;
0086: import java.awt.Toolkit;
0087: import java.awt.datatransfer.DataFlavor;
0088: import java.awt.datatransfer.Transferable;
0089: import java.awt.datatransfer.UnsupportedFlavorException;
0090: import java.awt.dnd.DnDConstants;
0091: import java.beans.PropertyChangeListener;
0092: import java.beans.PropertyChangeSupport;
0093: import java.io.File;
0094: import java.io.IOException;
0095: import java.net.MalformedURLException;
0096: import java.net.URI;
0097: import java.net.URL;
0098: import java.util.ArrayList;
0099: import java.util.Enumeration;
0100: import java.util.Iterator;
0101: import java.util.List;
0102: import java.util.StringTokenizer;
0103: import java.util.logging.Level;
0104: import java.util.logging.Logger;
0105: import javax.swing.ButtonGroup;
0106: import javax.swing.FocusManager;
0107: import javax.swing.JComponent;
0108: import javax.swing.JLabel;
0109: import javax.swing.JPanel;
0110: import javax.swing.JRadioButton;
0111: import javax.swing.SwingUtilities;
0112: import javax.swing.text.JTextComponent;
0113: import org.netbeans.api.project.FileOwnerQuery;
0114: import org.netbeans.api.project.Project;
0115: import org.netbeans.modules.j2ee.deployment.devmodules.api.J2eeModule;
0116: import org.netbeans.modules.visualweb.api.designer.Designer;
0117: import org.netbeans.modules.visualweb.api.designer.Designer.Box;
0118: import org.netbeans.modules.visualweb.designer.jsf.ui.JsfTopComponent;
0119: import org.netbeans.modules.visualweb.insync.faces.FacesPageUnit;
0120: import org.netbeans.modules.visualweb.propertyeditors.UrlPropertyEditor;
0121: import org.openide.DialogDescriptor;
0122: import org.openide.DialogDisplayer;
0123: import org.openide.ErrorManager;
0124: import org.openide.NotifyDescriptor;
0125: import org.openide.filesystems.FileObject;
0126: import org.openide.filesystems.FileStateInvalidException;
0127: import org.openide.filesystems.FileUtil;
0128: import org.openide.loaders.DataObject;
0129: import org.openide.util.Lookup;
0130: import org.openide.util.NbBundle;
0131: import org.w3c.dom.Element;
0132: import org.w3c.dom.Node;
0133: import org.w3c.dom.NodeList;
0134: import org.w3c.dom.Text;
0135:
0136: /**
0137: * Support of DnD for <code>FacesModel</code>.
0138: *
0139: * XXX Originaly in the designer, then moved into insync, and then into designer/jsf.
0140: *
0141: * @author Peter Zavadsky
0142: * @author Tor Norbye (old original code)
0143: */
0144: class FacesDndSupport {
0145:
0146: // /** XXX Copy from designer/CssBox. Solve it better way. */
0147: // private static final int CSS_AUTO = Integer.MAX_VALUE - 1;
0148:
0149: // XXX Copy from designer/DndHandler.
0150: private static final int DROP_ABOVE = -1;
0151: private static final int DROP_CENTER = 0;
0152: private static final int DROP_BELOW = 1;
0153:
0154: // XXX Copy from designer/DndHandler.
0155: /** State indicating that a drop is not allowed */
0156: public static final int DROP_DENIED = 0;
0157: /** State indicating that the drop is allowed and will cause a link */
0158: public static final int DROP_PARENTED = 1;
0159: /** State indicating that the drop is allowed and the bean will be
0160: * parented by one of the beans under the cursor */
0161: public static final int DROP_LINKED = 2;
0162:
0163: /** Directory prefix under the project root to place the web folder */
0164: private static final String WEB = "web"; // NOI18N
0165: /** Directory prefix under the web folder root to place the resource files */
0166: private static final String RESOURCES = "/resources/"; // NOI18N
0167:
0168: private final JsfForm jsfForm;
0169: // // XXX TODO Get rid of this.
0170: // private final FacesModel facesModel;
0171:
0172: private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(
0173: this );
0174:
0175: /**
0176: * Used during an importBean: set to the bean to select when
0177: * we're done processing. Different methods override which
0178: * item should be selected.
0179: */
0180: private DesignBean select; // have we found a target to select?
0181:
0182: /** Creates a new instance of FacesDnDSupport */
0183: public FacesDndSupport(JsfForm jsfForm) {
0184: if (jsfForm == null) {
0185: throw new NullPointerException(
0186: "Null argument is not allowed."); // NOI18N
0187: }
0188: this .jsfForm = jsfForm;
0189: // this.facesModel = facesModel;
0190: // this.facesModel = jsfForm.getFacesModel();
0191: }
0192:
0193: /**
0194: * XXX The JComponent has to be replaced by element. so it is possible
0195: * to react exactly.
0196: *
0197: * This method indicates if a component would accept an import of the given
0198: * set of data flavors prior to actually attempting to import it.
0199: *
0200: * @param comp The component to receive the transfer. This
0201: * argument is provided to enable sharing of TransferHandlers by
0202: * multiple components.
0203: * @param flavors The data formats available
0204: * @return true if the data can be inserted into the component, false otherwise.
0205: */
0206: public boolean canImport(JComponent comp, DataFlavor[] flavors,
0207: Transferable transferable) {
0208: // TODO Moving to NB winsys
0209: // Ensure that the toolbox, if in auto-hide mode, hides such that
0210: // the entire drawing canvas is visible and usable as a drop location
0211: // WindowManager.getDefault().clearOverlappedWindow();
0212:
0213: // //the following assert is changed by an if statement
0214: // //assert comp == webform.getPane();
0215: // if(DesignerUtils.DEBUG) {
0216: // DesignerUtils.debugLog(getClass().getName() + ".canImport(JComponent, DataFlavor[])");
0217: // }
0218: // if(comp != webform.getPane()) {
0219: // throw(new IllegalArgumentException("Wrong component."));
0220: // }
0221: // if(flavors == null) {
0222: // throw(new IllegalArgumentException("Null transferable."));
0223: // }
0224:
0225: // DesignerPane is always enabled and editable
0226: //DesignerPane c = webform.getPane();
0227: //if (!(c.isEditable() && c.isEnabled())) {
0228: // return false;
0229: //}
0230: // boolean canImport = getImportFlavor(flavors) != null;
0231: boolean canImport = getImportFlavor(flavors, null) != null;
0232:
0233: return canImport;
0234: }
0235:
0236: /**
0237: * XXX This method is a consequence of not having swing component tree
0238: * corresponding to css boxes,
0239: * that's why we can't get in TransferHander.canImport(JComponent, DataFlavor[])
0240: * the notion above which jsf component the drag/drop is.
0241: * It needs to be changed later, or at least hacked here. For that reason
0242: * this method usage is not sufficient for correct evaluation.
0243: *
0244: * Try to find a flavor that can be used to import a Transferable.
0245: * The set of usable flavors are tried in the following order:
0246: * <ol>
0247: * <li>First, an attempt is made to find a flavor matching the content type
0248: * of the EditorKit for the component.
0249: * <li>Second, an attempt to find a text/plain flavor is made.
0250: * <li>Third, an attempt to find a flavor representing a String reference
0251: * in the same VM is made.
0252: * <li>Lastly, DataFlavor.stringFlavor is searched for.
0253: * </ol>
0254: */
0255: public static DataFlavor getImportFlavor(DataFlavor[] flavors) {
0256: return getImportFlavor(flavors, null);
0257: }
0258:
0259: private static DataFlavor getImportFlavor(DataFlavor[] flavors,
0260: Transferable transferable) {
0261: DataFlavor plainFlavor = null;
0262: DataFlavor refFlavor = null;
0263: DataFlavor stringFlavor = null;
0264: DataFlavor listFlavor = null;
0265:
0266: for (int i = 0; i < flavors.length; i++) {
0267: String mime = flavors[i].getMimeType();
0268: Class<?> clz = flavors[i].getRepresentationClass();
0269:
0270: if (clz.isAssignableFrom(DisplayItem.class)) {
0271: return flavors[i];
0272: }
0273:
0274: if (clz == DesignBean.class) {
0275: return flavors[i];
0276: }
0277:
0278: if (clz.isAssignableFrom(List.class)) {
0279: // We don't know what's in the list, and can't look until
0280: // we have a transferable... but it looks promising so
0281: // defer decision
0282: listFlavor = flavors[i];
0283: }
0284:
0285: if (clz.isAssignableFrom(org.openide.nodes.Node.class)) {
0286: listFlavor = flavors[i];
0287: } // TODO: check for org.openide.util.datatransfer.MultiTransferObject
0288:
0289: if ((plainFlavor == null) && mime.startsWith("text/plain")) {
0290: plainFlavor = flavors[i];
0291: } else if ((refFlavor == null)
0292: && mime
0293: .startsWith("application/x-java-jvm-local-objectref")
0294: && (flavors[i].getRepresentationClass() == java.lang.String.class)) {
0295: refFlavor = flavors[i];
0296: } else if ((stringFlavor == null)
0297: && flavors[i].equals(DataFlavor.stringFlavor)) {
0298: stringFlavor = flavors[i];
0299: }
0300:
0301: // XXX
0302: if (refFlavor == null
0303: && mime.startsWith("application/x-creator-")) { // NOI18N
0304: refFlavor = flavors[i];
0305: }
0306:
0307: }
0308:
0309: if (refFlavor != null) {
0310: return refFlavor;
0311: } else if (listFlavor != null) {
0312: return listFlavor;
0313: } else if (stringFlavor != null) {
0314: return stringFlavor;
0315: } else if (plainFlavor != null) {
0316: return plainFlavor;
0317: }
0318:
0319: return null;
0320: }
0321:
0322: private/*public*/boolean importData(Designer designer,
0323: JComponent comp, Transferable t, /*Object transferData,*/
0324: Dimension dropSize, Location location, /*CoordinateTranslator coordinateTranslator,*/
0325: UpdateSuspender updateSuspender, int dropAction) {
0326: Object transferData = null;
0327: try {
0328: // DataFlavor importFlavor = webform.getImportFlavor(t.getTransferDataFlavors());
0329: DataFlavor importFlavor = getImportFlavor(t
0330: .getTransferDataFlavors());
0331:
0332: if (importFlavor == null) {
0333: ErrorManager
0334: .getDefault()
0335: .notify(
0336: ErrorManager.INFORMATIONAL,
0337: new IllegalStateException(
0338: "Unusable transfer flavors "
0339: + Arrays
0340: .asList(t
0341: .getTransferDataFlavors()))); // NOI18N
0342:
0343: return false;
0344: }
0345:
0346: // XXX What was before in SelectionTopComp.
0347: if (importFlavor.getMimeType().startsWith(
0348: "application/x-creator-")) { // NOI18N
0349: // /*return*/ webform.tcImportComponentData(comp, t);
0350: return importComponentData(designer, comp, t, location
0351: .getCoordinates());
0352: } // TEMP
0353:
0354: Class rc = importFlavor.getRepresentationClass();
0355:
0356: transferData = t.getTransferData(importFlavor);
0357:
0358: if (rc == String.class) {
0359: // XXX #6332049 When in inline editing we shouldn't steal the paste
0360: // (at least for the JTextComponent's.
0361: // This is just a workaround, it shouldn't be done this way.
0362: // actions should be created based on context (and inline editing
0363: // context is diff from the designer pane one).
0364: // if(webform.getManager().isInlineEditing()) {
0365: if (designer.isInlineEditing()) {
0366: Component focusOwner = FocusManager
0367: .getCurrentManager().getFocusOwner();
0368: if (focusOwner instanceof JTextComponent) {
0369: JTextComponent textComp = (JTextComponent) focusOwner;
0370: textComp.paste();
0371: return true;
0372: }
0373: }
0374:
0375: // XXX Flowlayout mode?
0376: // if (webform.getPane().getCaret() != null) {
0377: // if (webform.getPane().hasCaret()) {
0378: if (designer.hasPaneCaret()) {
0379: // webform.getPane().getCaret().replaceSelection((String)transferData);
0380: // webform.getPane().replaceSelection((String)transferData);
0381: jsfForm.getDomDocumentImpl().insertString(designer,
0382: designer.getPaneCaretRange(),
0383: (String) transferData);
0384: return true;
0385: }
0386: }
0387:
0388: if (!isValidTransferData(t, transferData)) {
0389: return false;
0390: }
0391:
0392: // LiveUnit unit = facesModel.getLiveUnit();
0393: LiveUnit unit = jsfForm.getLiveUnit();
0394: if (unit == null) {
0395: NotifyDescriptor d = new NotifyDescriptor.Message(
0396: NbBundle.getMessage(FacesDndSupport.class,
0397: "TXT_NoHtmlDrops"),
0398: NotifyDescriptor.WARNING_MESSAGE);
0399: DialogDisplayer.getDefault().notify(d);
0400: // dropSize = null;
0401: // insertPos = Position.NONE;
0402: // dropPoint = null;
0403:
0404: // clearDropMatch();
0405:
0406: return false;
0407: }
0408:
0409: // wrap process in a try to allow cleanup in the finally
0410: try {
0411: comp.setCursor(org.openide.util.Utilities
0412: .createProgressCursor(comp));
0413:
0414: // XXX TEMP First give the chance to the provider.
0415: // Later move it after the default behaviour.
0416: DesignTimeTransferDataCreator dataCreator = (DesignTimeTransferDataCreator) Lookup
0417: .getDefault().lookup(
0418: DesignTimeTransferDataCreator.class);
0419: if (dataCreator != null) {
0420: DisplayItem displayItem = dataCreator
0421: .getDisplayItem(t);
0422: if (displayItem != null) {
0423: transferData = displayItem;
0424: }
0425: }
0426:
0427: // if we are importing to the same component that we exported from then don't actually do
0428: // anything if the drop location is inside the drag location and set shouldRemove to false
0429: // so that exportDone knows not to remove any data
0430: if (transferData instanceof DisplayItem) {
0431: // Create a new type
0432: DisplayItem item = (DisplayItem) transferData;
0433:
0434: // Location location = computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
0435: // Todo: pass in a set instead
0436: // doImportItem(item, null, DROP_CENTER, null, null, location);
0437: return importBean(designer,
0438: new DisplayItem[] { item }, null,
0439: DROP_CENTER, null, null, location, /*coordinateTranslator,*/
0440: updateSuspender);
0441: } else if (transferData instanceof DesignBean[]) {
0442: DesignBean[] beans = (DesignBean[]) transferData;
0443: // Location location =
0444: // computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
0445: // DesignBean droppee = location.droppee;
0446: //
0447: // if (droppee != null) {
0448: // Location location2 =
0449: // computePositions(droppee, DROP_CENTER, null, null, null, false);
0450: // doBindOrMoveItems(dropAction, beans, t, droppee, DROP_CENTER, null, location2);
0451: // }
0452:
0453: DesignBean droppee = location.getDroppee();
0454: if (droppee != null) {
0455: // location = computePositions(droppee1, DROP_CENTER, null, null, null, false);
0456: // location = computeLocationForBean(droppee, DROP_CENTER, null, null, dropSize, facesModel);
0457: location = computeLocationForBean(droppee,
0458: DROP_CENTER, null, null, dropSize,
0459: jsfForm);
0460: return doBindOrMoveItems(dropAction, beans, t,
0461: droppee, DROP_CENTER, null, location, /*coordinateTranslator,*/
0462: updateSuspender);
0463: }
0464: return false;
0465: } else if (transferData instanceof org.openide.nodes.Node) {
0466: org.openide.nodes.Node node = (org.openide.nodes.Node) transferData;
0467: DataObject dobj = (DataObject) node
0468: .getCookie(DataObject.class);
0469:
0470: if (dobj != null) {
0471: FileObject fo = dobj.getPrimaryFile();
0472: // String rel = DesignerUtils.getPageRelativePath(webform, fo);
0473: // String rel = getPageRelativePath(facesModel.getProject(), fo);
0474: String rel = getPageRelativePath(jsfForm
0475: .getProject(), fo);
0476:
0477: Project fileProject = FileOwnerQuery
0478: .getOwner(fo);
0479:
0480: // if (fileProject != facesModel.getProject()) {
0481: if (fileProject != jsfForm.getProject()) {
0482: // Import file into our project first
0483: // FileObject webitem = facesModel.getMarkupFile();
0484: FileObject webitem = jsfForm
0485: .getMarkupFile();
0486:
0487: try {
0488: if (isImage(fo.getExt())
0489: || isStylesheet(fo.getExt())) {
0490: // Import web context relative rather than file relative
0491: // DesignProject project = facesModel.getLiveUnit().getProject();
0492: DesignProject project = jsfForm
0493: .getLiveUnit().getProject();
0494: File file = FileUtil.toFile(fo);
0495: URL url = file.toURI().toURL();
0496: rel = RESOURCES
0497: + UrlPropertyEditor
0498: .encodeUrl(file
0499: .getName());
0500: project.addResource(url, new URI(
0501: WEB + rel));
0502: } else {
0503: URL url = fo.getURL();
0504: rel = JsfProjectUtils.addResource(
0505: webitem, url, true);
0506: }
0507: } catch (FileStateInvalidException fse) {
0508: ErrorManager.getDefault().notify(fse);
0509: }
0510: }
0511:
0512: if (isImage(fo.getExt())) {
0513: // Location location =
0514: // computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
0515: return importImage(designer, rel, location, /*coordinateTranslator,*/
0516: updateSuspender);
0517: } else if (isStylesheet(fo.getExt())) {
0518: return importStylesheet(rel);
0519: }
0520:
0521: //} else if (node instanceof org.netbeans.modules.properties.KeyNode) {
0522: // // Compute the value binding expression:
0523: // // #{bundle.key}
0524: // // But I need to ensure that the bundle file is included somewhere in
0525: // // the page, and use the variable in the above.
0526: // // The key can be found from this node via a cookie, but it looks like
0527: // // the properties code is using old-style openide.src api calls, so
0528: // // I'd hate to include it.
0529: }
0530: } else if (transferData instanceof File) {
0531: File f = (File) transferData;
0532: // Location location = computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
0533: return importFile(designer, f, /*null,*/location, /*coordinateTranslator,*/
0534: updateSuspender);
0535: } else if (transferData instanceof String) {
0536: String s = (String) transferData;
0537:
0538: boolean success = false;
0539: // XXX Try to extract files from the string (flavor used when DnD e.g. from desktop, it doesn't look correct).
0540: File[] files = extractFilesFromString(s);
0541: if (files != null) {
0542: for (int i = 0; i < files.length; i++) {
0543: File file = files[i];
0544: boolean imported = importFile(designer,
0545: file, /*null,*/location, /*coordinateTranslator,*/
0546: updateSuspender);
0547: if (imported) {
0548: success = true;
0549: }
0550: }
0551: return success;
0552: } else {
0553: // XXX Why?
0554: s = Util.truncateString(s, 600);
0555: // Location location =
0556: // computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
0557: return importString(designer, s, location, /*coordinateTranslator,*/
0558: updateSuspender);
0559: }
0560: } else if (transferData instanceof List) {
0561: // TODO: place this under a single undo unit?
0562: List list = (List) transferData;
0563: Iterator it = list.iterator();
0564:
0565: boolean success = false;
0566: // JPanel panel = null;
0567: // XXX
0568: importFilePanel = null;
0569: while (it.hasNext()) {
0570: Object o = it.next();
0571:
0572: if (o instanceof File) {
0573: File f = (File) o;
0574: // Location location = computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
0575: // panel = importFile(designer, f, /*panel,*/ location, /*coordinateTranslator,*/ updateSuspender);
0576: boolean imported = importFile(designer, f, /*panel,*/
0577: location, /*coordinateTranslator,*/
0578: updateSuspender);
0579: if (imported) {
0580: success = true;
0581: }
0582: }
0583: }
0584: // XXX
0585: importFilePanel = null;
0586: return success;
0587: } else {
0588: // assert false : transferData;
0589: return false;
0590: }
0591: } catch (Exception e) {
0592: ErrorManager.getDefault().notify(
0593: ErrorManager.INFORMATIONAL, e);
0594:
0595: return false;
0596: } finally {
0597: if (comp != null) {
0598: comp.setCursor(null);
0599: }
0600: // dropSize = null;
0601: // insertPos = Position.NONE;
0602: // dropPoint = null;
0603:
0604: // clearDropMatch();
0605: }
0606:
0607: } catch (Exception ex) {
0608: ErrorManager.getDefault().notify(
0609: ErrorManager.INFORMATIONAL, ex);
0610: return false;
0611: }
0612:
0613: return false;
0614: }
0615:
0616: /**
0617: * @param beans An empty list into which the created beans will be added, or null
0618: * if caller is not interested in the result
0619: * @return true iff the bean palette item was inserted successfully
0620: */
0621: private boolean importBean(Designer designer, DisplayItem[] items,
0622: DesignBean origParent, int nodePos, String facet,
0623: List<DesignBean> createdBeans, Location location, /*CoordinateTranslator coordinateTranslator,*/
0624: UpdateSuspender updateSuspender) throws IOException {
0625: // if(DesignerUtils.DEBUG) {
0626: // DesignerUtils.debugLog(getClass().getName() + ".importBean(DisplayItem[], DesignBean, int, String, List)");
0627: // }
0628: if (items == null) {
0629: throw (new IllegalArgumentException("Null items array."));
0630: }
0631: select = null;
0632:
0633: // Location location =
0634: // computePositions(origParent, nodePos, facet, getDropPoint(), insertPos, true);
0635:
0636: // It's a app outline drag: either move or link. Don't involve
0637: // the transfer handler.
0638: String[] classes = getClasses(items);
0639:
0640: if (classes != null) {
0641: DesignBean[] beans = null;
0642: boolean searchUp = true;
0643:
0644: // Can always "move" from the palette - it's an implied copy.
0645: // The explorer drag & drop is a bit weird about this - they
0646: // only pass "move" as the valid operation, not copy.
0647: int action = DnDConstants.ACTION_MOVE;
0648:
0649: if (location.getDroppee() == null) {
0650: // MarkupBean bean = facesModel.getFacesUnit().getDefaultParent();
0651: MarkupBean bean = jsfForm.getFacesPageUnit()
0652: .getDefaultParent();
0653:
0654: if (bean != null) {
0655: if (!(location instanceof LocationImpl)) {
0656: location = new LocationImpl(location);
0657: }
0658: // ((LocationImpl)location).droppee = facesModel.getLiveUnit().getDesignBean(bean);
0659: ((LocationImpl) location).droppee = jsfForm
0660: .getLiveUnit().getDesignBean(bean);
0661: }
0662: }
0663:
0664: int allowed = computeActions(location.getDroppee(),
0665: classes, beans, action, searchUp, nodePos);
0666:
0667: if (allowed == DnDConstants.ACTION_NONE) {
0668: return false;
0669: }
0670: }
0671:
0672: // Document document = webform.getDocument();
0673: List<DisplayItem> beanItems = new ArrayList<DisplayItem>(); // HACK remove after TP
0674:
0675: String description = NbBundle.getMessage(FacesDndSupport.class,
0676: (items.length > 1) ? "LBL_DropComponents"
0677: : "LBL_DropComponent"); // NOI18N
0678: // UndoEvent undoEvent = facesModel.writeLock(description);
0679: UndoEvent undoEvent = jsfForm.writeLock(description);
0680:
0681: // Don't want BeanPaletteItem.beanCreated; only want the
0682: // set operation. For now the dataconnectivity module relies on
0683: // this to name the instances, so we've gotta honor it.
0684: try {
0685: // String description =
0686: // NbBundle.getMessage(DndHandler.class,
0687: // (items.length > 1) ? "DropComponents" : "DropComponent"); // NOI18N
0688: // document.writeLock(description);
0689:
0690: List<DesignBean> beans = createBeans(designer, location,
0691: items, beanItems, /*coordinateTranslator,*/
0692: updateSuspender);
0693:
0694: if (beans.isEmpty()) {
0695: return false;
0696: }
0697:
0698: if (createdBeans != null) {
0699: createdBeans.addAll(beans);
0700: }
0701:
0702: beansCreated(beans, beanItems);
0703:
0704: processLinks(location.getDroppeeElement(), null, beans,
0705: false, true, false, updateSuspender);
0706: // Util.customizeCreation(beans.toArray(new DesignBean[beans.size()]), facesModel);
0707: jsfForm.customizeCreation(beans
0708: .toArray(new DesignBean[beans.size()]));
0709:
0710: //// selectBean(select);
0711: //// webform.getSelection().selectBean(select);
0712: // fireSelectedDesignBeanChanged(select);
0713: // select = null;
0714: //
0715: //// inlineEdit(beans);
0716: //// webform.getManager().inlineEdit(beans);
0717: // fireInlineEdit((DesignBean[])beans.toArray(new DesignBean[beans.size()]));
0718: notifyBeansDesigner((DesignBean[]) beans
0719: .toArray(new DesignBean[beans.size()]), select);
0720: select = null;
0721:
0722: // Try to activate the designer surface! requestActive() isn't
0723: // enough -- gotta force the multiview container to be activated
0724: // and the right tab fronted!
0725: } finally {
0726: // document.writeUnlock();
0727: // facesModel.writeUnlock(undoEvent);
0728: jsfForm.writeUnlock(undoEvent);
0729: }
0730:
0731: return true;
0732: }
0733:
0734: // XXX This is a hacky method giving info back to designer, this needs to be done differently.
0735: public void notifyBeansDesigner(DesignBean[] designBeans,
0736: DesignBean select) {
0737: fireSelectedDesignBeanChanged(select);
0738: fireInlineEdit(designBeans);
0739: }
0740:
0741: private void beansCreated(List<DesignBean> beans,
0742: List<DisplayItem> beanItems) {
0743: int n = beans.size();
0744:
0745: for (int i = 0; i < n; i++) {
0746: DesignBean lb = beans.get(i);
0747:
0748: try {
0749: // facesModel.beanCreated(lb);
0750: jsfForm.designBeanCreated(lb);
0751: } catch (Exception e) {
0752: ErrorManager.getDefault().notify(e);
0753: }
0754: }
0755:
0756: for (int i = 0; i < n; i++) {
0757: DisplayItem item = beanItems.get(i);
0758:
0759: if (item == null) {
0760: continue;
0761: }
0762:
0763: // // Customize creation if requested by the component
0764: // BeanCreateInfo bci = item.getBeanCreateInfo();
0765: // BeanCreateInfoSet bcis = item.getBeanCreateInfoSet();
0766: //
0767: // if ((bci == null) && (bcis == null)) {
0768: // continue;
0769: // }
0770: //
0771: // // At most one of the above should be set...
0772: // assert !((bci != null) && (bcis != null));
0773:
0774: // Multiple beans could have been created from this item....
0775: // check that and process them
0776: if (item instanceof BeanCreateInfoSet) {
0777: BeanCreateInfoSet bcis = (BeanCreateInfoSet) item;
0778: // I don't want to rely on bcis.getBeanClassNames().length because one or more
0779: // beans could have failed to have been created (missing class, or
0780: // designtime canCreate returned false, etc.) - which would lead to
0781: // getting out of sync.
0782: // So instead I count by checking for identical BeanCreateItems
0783: // in subsequent beanItems entries
0784: List<DesignBean> list = new ArrayList<DesignBean>();
0785:
0786: for (int j = i; j < n; j++) {
0787: if (beanItems.get(j) == item) {
0788: list.add(beans.get(j));
0789: }
0790: }
0791:
0792: if (list.size() > 0) {
0793: i += (list.size() - 1);
0794:
0795: DesignBean[] createdBeans = list
0796: .toArray(new DesignBean[list.size()]);
0797: Result result = bcis
0798: .beansCreatedSetup(createdBeans);
0799: // ResultHandler.handleResult(result, facesModel);
0800: jsfForm.handleResult(result);
0801: }
0802: } else if (item instanceof BeanCreateInfo) {
0803: BeanCreateInfo bci = (BeanCreateInfo) item;
0804: DesignBean bean = beans.get(i);
0805: Result result = bci.beanCreatedSetup(bean);
0806: // ResultHandler.handleResult(result, facesModel);
0807: jsfForm.handleResult(result);
0808: } else {
0809: ErrorManager.getDefault().notify(
0810: ErrorManager.INFORMATIONAL,
0811: new IllegalStateException("Invalid item="
0812: + item)); // NOI18N
0813: }
0814: }
0815: }
0816:
0817: /**
0818: * Multi-function method dealing with link handling for components.
0819: * I used to have separate methods which accomplished various aspects of link
0820: * handling, but these would vary slightly in how they handled certain aspects
0821: * and as a result inconsistent handling would result. Thus, all the logic is handled
0822: * by the same method -- both "previewing" what links are available as well as actually
0823: * handling the linking. The flags control the behaviors.
0824: *
0825: * @param origElement The first/innermost element to start with when searching
0826: * the bean hierarchy for DesignBean and MarkupMouseRegions willing to link
0827: * the given beans or bean classes.
0828: * @param classes Array of classes to be checked for link eligibility. This is
0829: * separate from beans because we often want to check if linking is possible
0830: * before we actually have created beans -- such as when we're about to
0831: * drag & drop. Obviously in this case we can't perform linking. This
0832: * parameter can be null but then beans must not be null.
0833: * @param beans Can be null, but if not, should correspond exactly to the classes
0834: * parameter -- same length, same order, etc. This list must be specified
0835: * if handleLinks is true; you can't link on just class names.
0836: * @param selectFirst If set, don't ask the user which target to use if there are multiple
0837: * possibilities; just pick the first one. If not set, all eligible link handlers
0838: * in the parent chain up from the original element will be checked, and if more than
0839: * one is willing to link, the user will be presented with a list and asked to choose.
0840: * @param handleLinks If true, actually perform the linking.
0841: * @param showLinkTarget If true, highlihght the link target and region. Also sets the
0842: * recentDropTarget field.
0843: * @return DROP_DENIED if no beans/classes were linkable for any mouse regions or
0844: * DesignBeans; otherwise returns DROP_LINKED. If showLinkTarget is set, recentDropTarget
0845: * will be set to the most recent such eligible DesignBean.
0846: */
0847: public int processLinks(Element origElement, Class[] classes,
0848: List beans, boolean selectFirst, // if there are multiple hits; if not ask user
0849: boolean handleLinks, // actually do linking
0850: boolean showLinkTarget, UpdateSuspender updateSuspender) {
0851:
0852: // ErrorManager.getDefault().getInstance(DesignerUtils.class.getName()).isLoggable(ErrorManager.INFORMATIONAL);
0853: // if(DesignerUtils.DEBUG) {
0854: // DesignerUtils.debugLog(getClass().getName() + ".processLinks(Element, Class[], ArrayList, boolean, boolean, boolean)");
0855: // }
0856: if ((classes == null && beans == null)
0857: || (classes != null && beans != null && beans.size() != classes.length)) {
0858: throw (new IllegalArgumentException(
0859: "One of the classes array or beans list must not be null. If both are not null, than the length of them must be the same."));
0860: }
0861:
0862: int dropType = DROP_DENIED;
0863: int n;
0864:
0865: if (classes != null) {
0866: n = classes.length;
0867: } else {
0868: //the assert below would hide the NPE - better have NPE if not IllegalArgumentException
0869: //assert beans != null;
0870: n = beans.size();
0871: }
0872:
0873: //the assertion below does not give anything (see the if above).
0874: //assert (beans != null) || (classes != null);
0875: //the assertion below should be replaced by an if statement, so that the check happens even if
0876: //the asserions are turned off (see the if block above)
0877: //assert (beans == null) || (classes == null) || (beans.size() == classes.length);
0878:
0879: for (int i = 0; i < n; i++) {
0880: // XXX Incorrect code.
0881: List<Object> candidates = new ArrayList<Object>(n);
0882: Class clz;
0883: DesignBean lb = null;
0884:
0885: if (beans != null) {
0886: lb = (DesignBean) beans.get(i);
0887: }
0888:
0889: if (classes != null) {
0890: clz = classes[i];
0891: } else {
0892: clz = ((DesignBean) beans.get(i)).getInstance()
0893: .getClass();
0894: }
0895:
0896: try {
0897: // See if this new bean should be wired to the bean we
0898: // dropped on (or some container up the parent chain that
0899: // can handle the bean drop)
0900: DesignBean prev = null;
0901:
0902: for (Element element = origElement; element != null; element = getParent(element)) {
0903: // DesignBean droppee = element.getDesignBean();
0904: DesignBean droppee = InSyncServiceProvider.get()
0905: .getMarkupDesignBeanForElement(element);
0906:
0907: if (droppee == null) {
0908: continue;
0909: }
0910:
0911: // MarkupMouseRegion region = element.getMarkupMouseRegion();
0912: MarkupMouseRegion region = InSyncServiceProvider
0913: .get().getMarkupMouseRegionForElement(
0914: element);
0915:
0916: if ((region != null)
0917: && region.acceptLink(droppee, lb, clz)) {
0918: if (!candidates.contains(element)) {
0919: candidates.add(element);
0920: }
0921: }
0922:
0923: if (prev == droppee) {
0924: continue;
0925: }
0926:
0927: prev = droppee;
0928:
0929: DesignInfo dbi = droppee.getDesignInfo();
0930:
0931: if ((dbi != null)
0932: && dbi.acceptLink(droppee, lb, clz)) {
0933: if (!candidates.contains(droppee)
0934: && ((beans == null) || !beans
0935: .contains(droppee))) {
0936: candidates.add(droppee);
0937: }
0938: }
0939: }
0940: } catch (Exception e) {
0941: ErrorManager.getDefault().notify(e);
0942: }
0943:
0944: if (candidates.size() == 0) {
0945: continue;
0946: }
0947:
0948: dropType = DROP_LINKED;
0949:
0950: // Store either the chosen DesignBean, or the chosen MarkupMouseRegion.
0951: // However, we'll need both the region and the corresponding bean, so
0952: // store the element instead which will point to both.
0953: Object selected = null;
0954:
0955: if (selectFirst || (candidates.size() == 1)) {
0956: selected = candidates.get(0);
0957: } else {
0958: // Gotta ask the user
0959: // Code originally emitted by the form builder:
0960: JPanel panel = new JPanel(new GridBagLayout());
0961: GridBagConstraints gridBagConstraints;
0962: String labelDesc = NbBundle.getMessage(
0963: FacesDndSupport.class, "LBL_ChooseTargetLabel"); // NOI18N
0964: JLabel label = new JLabel(labelDesc);
0965: gridBagConstraints = new GridBagConstraints();
0966: gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
0967: gridBagConstraints.insets = new Insets(12, 12, 11, 11);
0968: gridBagConstraints.anchor = GridBagConstraints.WEST;
0969: gridBagConstraints.weightx = 1.0;
0970: panel.add(label, gridBagConstraints);
0971:
0972: ButtonGroup buttonGroup = new ButtonGroup();
0973:
0974: // Iterate reverse order since list was generates from the leaf
0975: // up the parent chain, and I want to display outermost parents first
0976: for (int j = candidates.size() - 1; j >= 0; j--) {
0977: String name = "";
0978: Object next = candidates.get(j);
0979:
0980: if (next instanceof DesignBean) {
0981: DesignBean dlb = (DesignBean) next;
0982: name = dlb.getInstanceName();
0983: // Bug Fix: 6477496 Do not show the component description in the dialog
0984: // BeanInfo bi = dlb.getBeanInfo();
0985: //
0986: // if (bi != null) {
0987: // BeanDescriptor bd = bi.getBeanDescriptor();
0988: //
0989: // if (bd != null) {
0990: // String desc = bd.getShortDescription();
0991: //
0992: // if (desc == null) {
0993: // desc = bd.getDisplayName();
0994: //
0995: // if (desc == null) {
0996: // desc = "";
0997: // }
0998: // }
0999: //
1000: // name =
1001: // NbBundle.getMessage(FacesDnDSupport.class, "TXT_TargetDescriptor", // NOI18N
1002: // name, desc);
1003: // }
1004: // }
1005: } else {
1006: // assert next instanceof RaveElement;
1007: if (!(next instanceof Element)) {
1008: ErrorManager.getDefault().notify(
1009: ErrorManager.INFORMATIONAL,
1010: new IllegalStateException(
1011: "Object is expected to be of Element type, object="
1012: + next)); // NOI18N
1013: }
1014:
1015: // RaveElement element = (RaveElement)next;
1016: // MarkupMouseRegion region = element.getMarkupMouseRegion();
1017: Element element = (Element) next;
1018: MarkupMouseRegion region = InSyncServiceProvider
1019: .get().getMarkupMouseRegionForElement(
1020: element);
1021: assert region != null;
1022:
1023: name = region.getDisplayName();
1024: // Bug Fix: 6477496 Do not show the component description in the dialog
1025: // if ((region.getDescription() != null) &&
1026: // (region.getDescription().length() > 0)) {
1027: // name = NbBundle.getMessage(FacesDnDSupport.class, "TXT_TargetDescriptor", // NOI18N
1028: // region.getDisplayName(), region.getDescription());
1029: // } else {
1030: // name = region.getDisplayName();
1031: // }
1032: }
1033:
1034: JRadioButton radioButton = new JRadioButton(name);
1035:
1036: if (j == (candidates.size() - 1)) {
1037: radioButton.setSelected(true);
1038: }
1039:
1040: radioButton.putClientProperty("liveBean", next); // NOI18N
1041: buttonGroup.add(radioButton);
1042:
1043: if (next == origElement
1044: || next == InSyncServiceProvider.get()
1045: .getMarkupDesignBeanForElement(
1046: origElement)) {
1047: // #6315394 Preselect the original drop target.
1048: radioButton.setSelected(true);
1049: }
1050:
1051: gridBagConstraints = new GridBagConstraints();
1052: gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
1053: gridBagConstraints.insets = new Insets(0, 12, 0, 11);
1054: gridBagConstraints.anchor = GridBagConstraints.WEST;
1055: panel.add(radioButton, gridBagConstraints);
1056: }
1057:
1058: JPanel filler = new JPanel();
1059: gridBagConstraints = new GridBagConstraints();
1060: gridBagConstraints.weighty = 1.0;
1061: panel.add(filler, gridBagConstraints);
1062:
1063: String title = NbBundle.getMessage(
1064: FacesDndSupport.class, "LBL_ChooseTarget"); // NOI18N
1065: DialogDescriptor dlg = new DialogDescriptor(panel,
1066: title, true, DialogDescriptor.OK_CANCEL_OPTION,
1067: DialogDescriptor.OK_OPTION,
1068: DialogDescriptor.DEFAULT_ALIGN,
1069: // DialogDescriptor.BOTTOM_ALIGN,
1070: null, //new HelpCtx("choose_target"), // NOI18N
1071: null);
1072:
1073: Dialog dialog = DialogDisplayer.getDefault()
1074: .createDialog(dlg);
1075: // dialog.show();
1076: dialog.setVisible(true);
1077:
1078: if (dlg.getValue().equals(DialogDescriptor.OK_OPTION)) {
1079: Enumeration enm = buttonGroup.getElements();
1080:
1081: while (enm.hasMoreElements()) {
1082: JRadioButton button = (JRadioButton) enm
1083: .nextElement();
1084:
1085: if (button.isSelected()) {
1086: selected = button
1087: .getClientProperty("liveBean"); // NOI18N
1088:
1089: break;
1090: }
1091: }
1092: } // else: Cancel, or Esc: do nothing; selected will stay null
1093: }
1094:
1095: if (showLinkTarget) {
1096: if (selected instanceof DesignBean) {
1097: DesignBean droppee = (DesignBean) selected;
1098:
1099: if (droppee instanceof MarkupDesignBean) {
1100: // recentDropTarget = (MarkupDesignBean)droppee;
1101: // showDropMatch(recentDropTarget, null, DROP_LINKED);
1102: fireDropTargetChanged(
1103: (MarkupDesignBean) droppee, null,
1104: DROP_LINKED);
1105: }
1106: } else {
1107: // assert selected instanceof RaveElement;
1108: if (!(selected instanceof Element)) {
1109: ErrorManager.getDefault().notify(
1110: ErrorManager.INFORMATIONAL,
1111: new IllegalStateException(
1112: "Object is expected to be of Element type, object="
1113: + selected)); // NOI18N
1114: }
1115:
1116: // RaveElement element = (RaveElement)selected;
1117: // DesignBean droppee = element.getDesignBean();
1118: Element element = (Element) selected;
1119: DesignBean droppee = InSyncServiceProvider.get()
1120: .getMarkupDesignBeanForElement(element);
1121:
1122: if (droppee instanceof MarkupDesignBean) {
1123: // recentDropTarget = (MarkupDesignBean)droppee;
1124: //// showDropMatch(recentDropTarget, element.getMarkupMouseRegion(), DROP_LINKED);
1125: // showDropMatch(recentDropTarget,
1126: // InSyncServiceProvider.get().getMarkupMouseRegionForElement(element),
1127: // DROP_LINKED);
1128: // fireDropTargetChanged((MarkupDesignBean)droppee, InSyncServiceProvider.get().getMarkupMouseRegionForElement(element), DROP_LINKED);
1129: fireDropTargetChanged(
1130: (MarkupDesignBean) droppee, element,
1131: DROP_LINKED);
1132: }
1133: }
1134: }
1135:
1136: if ((selected == null) || !handleLinks || (beans == null)) {
1137: return dropType;
1138: }
1139:
1140: // Document document = webform.getDocument();
1141:
1142: String description = NbBundle.getMessage(
1143: FacesDndSupport.class, "LBL_LinkComponent"); // NOI18N
1144: // UndoEvent undoEvent = facesModel.writeLock(description);
1145: UndoEvent undoEvent = jsfForm.writeLock(description);
1146: try {
1147: // String description = NbBundle.getMessage(DndHandler.class, "LinkComponent"); // NOI18N
1148: // document.writeLock(description);
1149:
1150: lb = (DesignBean) beans.get(i);
1151:
1152: try {
1153: // If you drop on an existing component, see if they
1154: // can be wired together
1155: // Try to bind the two together - for example, if you
1156: // drop a RowSet on a bean that has a RowSet property,
1157: // the RowSet property is bound to this particular
1158: // RowSet.
1159: if (selected instanceof DesignBean) {
1160: DesignBean droppee = (DesignBean) selected;
1161: assert droppee.getDesignInfo().acceptLink(
1162: droppee, lb,
1163: lb.getInstance().getClass());
1164:
1165: MarkupDesignBean mbean = null;
1166:
1167: if (droppee instanceof MarkupDesignBean) {
1168: // link beans might perform lots and lots of
1169: // updates on the element - that's the case
1170: // for the data grid when you bind a table
1171: // to it for example. So batch up all these
1172: // modifications into a single change event
1173: // on the top level element.
1174: mbean = (MarkupDesignBean) droppee;
1175: // webform.getDomSynchronizer().setUpdatesSuspended(mbean, true);
1176: // webform.setUpdatesSuspended(mbean, true);
1177: updateSuspender.setSuspended(mbean, true);
1178: }
1179:
1180: try {
1181: // facesModel.linkBeans(droppee, lb);
1182: jsfForm.linkDesignBeans(droppee, lb);
1183: } finally {
1184: if (mbean != null) {
1185: // Process queued up changes
1186: // webform.getDomSynchronizer().setUpdatesSuspended(mbean, false);
1187: // webform.setUpdatesSuspended(mbean, false);
1188: updateSuspender.setSuspended(mbean,
1189: false);
1190: }
1191: }
1192:
1193: // The target bean should be selected instead of
1194: // the droppee!
1195: select = droppee;
1196: } else {
1197: // assert selected instanceof RaveElement;
1198: if (!(selected instanceof Element)) {
1199: ErrorManager.getDefault().notify(
1200: ErrorManager.INFORMATIONAL,
1201: new IllegalStateException(
1202: "Object is expected to be of Element type, object="
1203: + selected)); // NOI18N
1204: }
1205:
1206: // RaveElement element = (RaveElement)selected;
1207: // MarkupMouseRegion region = element.getMarkupMouseRegion();
1208: Element element = (Element) selected;
1209: MarkupMouseRegion region = InSyncServiceProvider
1210: .get().getMarkupMouseRegionForElement(
1211: element);
1212: assert region != null;
1213:
1214: // DesignBean droppee = element.getDesignBean();
1215: DesignBean droppee = InSyncServiceProvider
1216: .get().getMarkupDesignBeanForElement(
1217: element);
1218: assert droppee != null;
1219: assert region.acceptLink(droppee, lb, clz);
1220:
1221: MarkupDesignBean mbean = null;
1222:
1223: if (droppee instanceof MarkupDesignBean) {
1224: mbean = (MarkupDesignBean) droppee;
1225: // webform.getDomSynchronizer().setUpdatesSuspended(mbean, true);
1226: // webform.setUpdatesSuspended(mbean, true);
1227: updateSuspender.setSuspended(mbean, true);
1228: }
1229:
1230: try {
1231: Result r = region.linkBeans(droppee, lb);
1232: // ResultHandler.handleResult(r, facesModel);
1233: jsfForm.handleResult(r);
1234: } finally {
1235: if (mbean != null) {
1236: // webform.getDomSynchronizer().setUpdatesSuspended(mbean, false);
1237: // webform.setUpdatesSuspended(mbean, false);
1238: updateSuspender.setSuspended(mbean,
1239: false);
1240: }
1241: }
1242: }
1243: } catch (Exception e) {
1244: ErrorManager.getDefault().notify(e);
1245: }
1246: } finally {
1247: // document.writeUnlock();
1248: // facesModel.writeUnlock(undoEvent);
1249: jsfForm.writeUnlock(undoEvent);
1250: }
1251: }
1252:
1253: return dropType;
1254: }
1255:
1256: public void addPropertyChangeListener(PropertyChangeListener l) {
1257: propertyChangeSupport.addPropertyChangeListener(l);
1258: }
1259:
1260: public void removePropertyChangeListener(PropertyChangeListener l) {
1261: propertyChangeSupport.removePropertyChangeListener(l);
1262: }
1263:
1264: public static final String PROPERTY_DROP_TARGET = "dropTarget"; // NOI18N
1265: public static final String PROPERTY_SELECTED_DESIGN_BEAN = "selectedDesignBean"; // NOI18N
1266: public static final String PROPERTY_REFRESH = "refresh";
1267: public static final String PROPERTY_INLINE_EDIT = "inlineEdit"; // NOI18N
1268:
1269: // private void fireDropTargetChanged(MarkupDesignBean markupDesignBean, MarkupMouseRegion markupMouseRegion, int dropType) {
1270: // propertyChangeSupport.firePropertyChange(PROPERTY_DROP_TARGET, null, new DropInfo(markupDesignBean, markupMouseRegion, dropType)); // NOI18N
1271: private void fireDropTargetChanged(
1272: final MarkupDesignBean markupDesignBean,
1273: final Element regionElement, final int dropType) {
1274: // XXX It happens the model is not updated yet (source-rendered elements link)! (See scheduling in DomSynchronizer)
1275: EventQueue.invokeLater(new Runnable() {
1276: public void run() {
1277: propertyChangeSupport.firePropertyChange(
1278: PROPERTY_DROP_TARGET, null, new DropInfo(
1279: markupDesignBean, regionElement,
1280: dropType)); // NOI18N
1281: }
1282: });
1283: }
1284:
1285: private void fireSelectedDesignBeanChanged(final DesignBean selected) {
1286: // XXX It happens the model is not updated yet (source-rendered elements link)! (See scheduling in DomSynchronizer)
1287: EventQueue.invokeLater(new Runnable() {
1288: public void run() {
1289: propertyChangeSupport.firePropertyChange(
1290: PROPERTY_SELECTED_DESIGN_BEAN, null, selected);
1291: }
1292: });
1293: }
1294:
1295: /*private*/public void fireRefreshNeeded(final boolean refreshAll) {
1296: // XXX It happens the model is not updated yet (source-rendered elements link)! (See scheduling in DomSynchronizer)
1297: EventQueue.invokeLater(new Runnable() {
1298: public void run() {
1299: propertyChangeSupport.firePropertyChange(
1300: PROPERTY_REFRESH, !refreshAll, refreshAll);
1301: }
1302: });
1303: }
1304:
1305: private void fireInlineEdit(final DesignBean[] designBeans) {
1306: // XXX It happens the model is not updated yet (source-rendered elements link)! (See scheduling in DomSynchronizer)
1307: EventQueue.invokeLater(new Runnable() {
1308: public void run() {
1309: propertyChangeSupport.firePropertyChange(
1310: PROPERTY_INLINE_EDIT, null, designBeans);
1311: }
1312: });
1313: }
1314:
1315: // XXX Moved into insync/Util.
1316: // public void customizeCreation(List beans) {
1317: // int n = beans.size();
1318: //
1319: // for (int i = 0; i < n; i++) {
1320: // DesignBean lb = (DesignBean)beans.get(i);
1321: // DesignInfo lbi = lb.getDesignInfo();
1322: //
1323: // if (lbi != null) {
1324: // Customizer2 customizer = null; //lbi.getCreateCustomizer(lb);
1325: //
1326: // if (customizer != null) {
1327: // CustomizerDisplayer lcd =
1328: // new CustomizerDisplayer(lb, customizer, customizer.getHelpKey(), facesModel);
1329: // lcd.show();
1330: // }
1331: // }
1332: // }
1333: // }
1334:
1335: public String[] getClasses(DisplayItem[] items) {
1336: List<String> list = new ArrayList<String>(items.length);
1337:
1338: for (DisplayItem item : items) {
1339: if (item instanceof BeanCreateInfo) {
1340: BeanCreateInfo beanCreateInfo = ((BeanCreateInfo) item);
1341: String className = beanCreateInfo.getBeanClassName();
1342: if (className == null) {
1343: // #112454 Bad impl of BeanCreateInfo.
1344: info(new IllegalArgumentException(
1345: "Bad implementation of BeanCreateInfo, "
1346: + "it returns null bean class name, "
1347: + "beanCreateInfo="
1348: + beanCreateInfo)); // NOI18N
1349: } else {
1350: list.add(className);
1351: }
1352: } else if (item instanceof BeanCreateInfoSet) {
1353: BeanCreateInfoSet beanCreateInfoSet = ((BeanCreateInfoSet) item);
1354: String[] cls = beanCreateInfoSet.getBeanClassNames();
1355: if (cls == null) {
1356: // #112454 Bad impl of BeanCreateInfoSet.
1357: info(new IllegalArgumentException(
1358: "Bad implementation of BeanCreatInfoSet, "
1359: + "it returns null array of bean class names, "
1360: + "beanCreateInfoSet="
1361: + beanCreateInfoSet)); // NOI18N
1362: } else {
1363: for (int k = 0; k < cls.length; k++) {
1364: String className = cls[k];
1365: if (className == null) {
1366: // #112454 Bad impl of BeanCreateImplSet.
1367: info(new IllegalArgumentException(
1368: "Bad implementation of BeanCreatInfoSet, "
1369: + "it returns null(s) in array of bean class names, "
1370: + "beanCreateInfoSet="
1371: + beanCreateInfoSet
1372: + ", beanClasses="
1373: + Arrays.asList(cls))); // NOI18N
1374: } else {
1375: list.add(cls[k]);
1376: }
1377: }
1378: }
1379: } else {
1380: ErrorManager.getDefault().notify(
1381: ErrorManager.INFORMATIONAL,
1382: new IllegalStateException("Illegal item="
1383: + item)); // NOI18N
1384: }
1385: }
1386:
1387: return list.toArray(new String[list.size()]);
1388: }
1389:
1390: private List<DesignBean> createBeans(
1391: Designer designer,
1392: Location location,
1393: DisplayItem[] items,
1394: List<DisplayItem> beanItems,
1395: /*CoordinateTranslator coordinateTranslator,*/UpdateSuspender updateSuspender)
1396: throws IOException {
1397: DesignBean droppee = location.getDroppee();
1398: MarkupPosition position = location.getPos();
1399: String facet = location.getFacet();
1400:
1401: List<DesignBean> created = new ArrayList<DesignBean>(
1402: 2 * items.length); // slop for BeanCreateInfoSets
1403:
1404: for (int i = 0; i < items.length; i++) {
1405:
1406: // if (!(items[i] instanceof BeanPaletteItem)) {
1407: // importItem(items[i], null, DROP_CENTER, null, null);
1408: //
1409: // continue;
1410: // }
1411:
1412: DisplayItem item = (DisplayItem) items[i];
1413:
1414: // <change>
1415: // XXX There is a need to get class name even from the bean create info set.
1416: // String className = item.getBeanClassName();
1417: // ====
1418: String className = null;
1419: // </change>
1420:
1421: // // Customize creation if requested by the component
1422: // BeanCreateInfo bci = item.getBeanCreateInfo();
1423: // BeanCreateInfoSet bcis = item.getBeanCreateInfoSet();
1424:
1425: // // At most one of the above should be set...
1426: // assert !((bci != null) && (bcis != null));
1427:
1428: String[] classes = null;
1429: int current = 0;
1430: int max = 0;
1431:
1432: if (item instanceof BeanCreateInfoSet) {
1433: BeanCreateInfoSet bcis = (BeanCreateInfoSet) item;
1434: // Set us up for multiple bean creation
1435: classes = bcis.getBeanClassNames();
1436: max = classes.length;
1437: } else if (item instanceof BeanCreateInfo) {
1438: className = ((BeanCreateInfo) item).getBeanClassName();
1439: } else {
1440: ErrorManager.getDefault().notify(
1441: ErrorManager.INFORMATIONAL,
1442: new IllegalStateException("Illegal item="
1443: + item)); // NOI18N
1444: continue;
1445: }
1446:
1447: do {
1448: // If we're creating multiple beans from a BeanCreateInfoSet
1449: // fetch the next class name
1450: if (current < max) {
1451: className = classes[current++];
1452: }
1453:
1454: // DesignBean parent = Util.findParent(className, droppee, position.getUnderParent(), true, facesModel);
1455: DesignBean parent = jsfForm.findParent(className,
1456: droppee, position.getUnderParent(), true);
1457:
1458: if (parent != null) {
1459: boolean droppingOnFrameset = parent.getInstance() instanceof FramesetFrameset;
1460: boolean droppingOnFrame = parent.getInstance() instanceof Frame;
1461:
1462: if (droppingOnFrameset || droppingOnFrame) {
1463: // if (!(droppingOnFrameset && (className.equals(HtmlBean.PACKAGE+"Frame") ||
1464: // className.equals(HtmlBean.PACKAGE+"FramesetFrameset")))) { // NOI18N
1465: if (!(droppingOnFrameset && (className
1466: .equals(Frame.class.getName()) || className
1467: .equals(Frame.class.getName())))) {
1468: NotifyDescriptor d = new NotifyDescriptor.Message(
1469: NbBundle.getMessage(
1470: FacesDndSupport.class,
1471: "TXT_NoFrameDrops", item
1472: .getDisplayName()),
1473: NotifyDescriptor.WARNING_MESSAGE);
1474: DialogDisplayer.getDefault().notify(d);
1475:
1476: continue;
1477: }
1478: }
1479: }
1480:
1481: // Native method - is this result cached?
1482: //if (className.equals(Jsp_Directive_Include.class.getName())) {
1483: String savedClass = null;
1484:
1485: if (className.equals(HtmlBean.PACKAGE
1486: + "Jsp_Directive_Include")) { // NOI18N
1487:
1488: // You're dropping a jsp:directive.include box. These cannot
1489: // be CSS positioned (e.g. dropped at a particular pixel
1490: // location over a grid layout area) - because this directive
1491: // does not have a style attribute, and Jasper will scream
1492: // bloody murder if we put it in.
1493: // So instead we drop a <div>, and place the jsp directive
1494: // inside it.
1495: // I wanted to solve this more cleanly: If you're dropping
1496: // a visual component and it doesn't have a "style" property,
1497: // it doesn't support positioning, so apply the above
1498: // <div>-wrapping trick. However, while I can check if a
1499: // component about to be dropped has a style property through
1500: // the beaninfo, I can't tell if it's a visual component
1501: // or not until it's actually instantiated (via
1502: // DesignBean.isVisualBean()) - so I can't do it this way or
1503: // suddenly e.g. rowset beans would be parented by <div> since
1504: // they don't have a style attribute.... So for now
1505: // it's just a special case check for the one known visual
1506: // component that doesn't have a style attribute.
1507: //if (getDropPoint() != null && insertPos == null) {
1508: savedClass = className;
1509:
1510: // XXX Why not Div.class.getName() ?
1511: className = HtmlBean.PACKAGE + "Div"; // NOI18N
1512:
1513: //}
1514: // Comment on above: we now ALWAYS want to insert a div, since
1515: // even in flow context you want a div which specifies
1516: // "position: relative" in order to ensure that absolutely
1517: // positioned children within the fragment are relative
1518: // to the jsp's top level corner, not the current viewport
1519: // or absolutely positioned -ancestor- of the jsp include
1520: // box.
1521: }
1522:
1523: // Adjust position, in case we're default inserting it
1524: // If we're default-positioin inserting into a form or body,
1525: // and it ends with a <br>, insert the new component before
1526: // the <br> so that it doesn't create a new line.
1527: if ((parent == null)
1528: && ((position == null) || ((position
1529: .getUnderParent() == null) && (position
1530: .getBeforeSibling() == null)))) {
1531: // See if I have a Br
1532: // MarkupBean formBean = facesModel.getFacesUnit().getDefaultParent();
1533: MarkupBean formBean = jsfForm.getFacesPageUnit()
1534: .getDefaultParent();
1535:
1536: if (formBean != null) {
1537: Bean[] children = formBean.getChildren();
1538:
1539: if ((children != null) && (children.length > 0)) {
1540: Bean b = children[children.length - 1];
1541:
1542: if (b instanceof MarkupBean) {
1543: MarkupBean mb = (MarkupBean) b;
1544:
1545: if ((mb.getElement() != null)
1546: && mb
1547: .getElement()
1548: .getTagName()
1549: .equals(HtmlTag.BR.name)) {
1550: position = new MarkupPosition(
1551: formBean.getElement(), mb
1552: .getElement());
1553: }
1554: }
1555: }
1556: }
1557: }
1558:
1559: DesignBean bean = createBean(className, parent,
1560: position, facet);
1561: select = bean;
1562:
1563: if (bean != null) {
1564: created.add(bean);
1565: beanItems.add(items[i]);
1566: }
1567:
1568: if (bean instanceof MarkupDesignBean) {
1569: MarkupDesignBean mbean = (MarkupDesignBean) bean;
1570: positionBean(designer, mbean, parent, mbean
1571: .getElement(), location, /*coordinateTranslator,*/
1572: updateSuspender);
1573:
1574: if ((savedClass != null) && bean.isContainer()) {
1575: DesignBean child = createBean(savedClass, bean,
1576: null, null);
1577:
1578: if (child != null) {
1579: created.add(child);
1580:
1581: // Ensure that the two lists are kept in sync
1582: beanItems.add(null);
1583:
1584: // #104792 To select the fragment not the added surrounding div.
1585: select = child;
1586: }
1587:
1588: // If inserted in flow, put a <div> with relative
1589: // positioning around it to ensure that absolutely
1590: // positioned children in the div are absolute relative
1591: // to the jsp box, not whatever outer container is
1592: // establishing the current absolute positions
1593: // if (insertPos != Position.NONE) {
1594: // if (!Util.isGridMode(facesModel)) {
1595: if (!jsfForm.isGridMode()) {
1596: DesignProperty styleProp = bean
1597: .getProperty("style"); // NOI18N
1598:
1599: if (styleProp != null) {
1600: String mods = "position: relative"; // NOI18N
1601: String style = (String) styleProp
1602: .getValue();
1603:
1604: if ((style != null)
1605: && (style.length() > 0)) {
1606: styleProp.setValue(style + "; "
1607: + mods);
1608: } else {
1609: styleProp.setValue(mods);
1610: }
1611: }
1612: }
1613:
1614: /*
1615: DesignProperty styleProp = bean.getProperty("style"); // NOI18N
1616: if (styleProp != null) {
1617: String mods = "overflow: hidden; width: 240px"; // NOI18N
1618: String style = (String)styleProp.getValue();
1619: if (style != null && style.length() > 0) {
1620: styleProp.setValue(style + "; " + mods);
1621: } else {
1622: styleProp.setValue(mods);
1623: }
1624: }
1625: */
1626: }
1627: }
1628: } while (current < max);
1629: }
1630:
1631: // XXX This is cleared anyway.
1632: // insertPos = Position.NONE;
1633:
1634: //facesUnit.setInsertBefore(null);
1635: return created;
1636: }
1637:
1638: private DesignBean createBean(String className, DesignBean parent,
1639: com.sun.rave.designtime.Position pos, String facet) {
1640: // LiveUnit unit = facesModel.getLiveUnit();
1641: LiveUnit unit = jsfForm.getLiveUnit();
1642:
1643: if (parent != null) {
1644: // It's possible that we're adding to a unit other than
1645: // the web form one -- such as a Session Bean unit for
1646: // a rowset
1647: unit = (LiveUnit) parent.getDesignContext();
1648:
1649: // Ensure that the MarkupPosition is correct
1650: if (pos instanceof MarkupPosition) {
1651: MarkupPosition markupPos = (MarkupPosition) pos;
1652:
1653: // if (markupPos.getUnderParent() instanceof RaveElement) {
1654: // RaveElement parentElement = (RaveElement)markupPos.getUnderParent();
1655: if (markupPos.getUnderParent() instanceof Element) {
1656: Element parentElement = (Element) markupPos
1657: .getUnderParent();
1658:
1659: // while (parentElement.getDesignBean() != parent) {
1660: while (InSyncServiceProvider.get()
1661: .getMarkupDesignBeanForElement(
1662: parentElement) != parent) {
1663: // if (parentElement.getParentNode() instanceof RaveElement) {
1664: // parentElement = (RaveElement)parentElement.getParentNode();
1665: if (parentElement.getParentNode() instanceof Element) {
1666: parentElement = (Element) parentElement
1667: .getParentNode();
1668: } else {
1669: break;
1670: }
1671: }
1672:
1673: if ((parentElement != null)
1674: && (parentElement != markupPos
1675: .getUnderParent())) {
1676: // The parent DesignBean is for a higher-up element. This can happen
1677: // when the acceptChild/acceptParent calls force parenting up higher
1678: // in the chain.
1679: pos = new MarkupPosition(parentElement, null);
1680: }
1681: }
1682: }
1683: }
1684:
1685: if (facet != null) {
1686: return unit.createFacet(facet, className, parent);
1687: }
1688:
1689: return unit.createBean(className, parent, pos);
1690: }
1691:
1692: /** Set the absolute position of the component. **/
1693: private void positionBean(Designer designer, MarkupDesignBean lb,
1694: DesignBean origParent, Element element, Location location, /*CoordinateTranslator coordinateTranslator,*/
1695: UpdateSuspender updateSuspender) {
1696: // TODO - transfer this logic to computePositions
1697: if ((location.getCoordinates() == null) || (element == null)) {
1698: return;
1699: }
1700:
1701: DesignBean parent = origParent;
1702:
1703: // Only position beans dropped on a grid area or a form
1704: boolean grid = false;
1705:
1706: // XXX TODO: transfer this logic into Utilities instead and make
1707: // sure we do it the same way everywhere!
1708: if (element.getParentNode() instanceof Element) {
1709: Element pe = (Element) element.getParentNode();
1710:
1711: if (pe.getTagName().equals(HtmlTag.FSUBVIEW.name)
1712: && pe.getParentNode() instanceof Element) {
1713: pe = (Element) pe.getParentNode();
1714: }
1715:
1716: // The component may -render- a -rave-layout setting,
1717: // so look in the rendered HTML for the layout setting
1718: // rather than in the JSP DOM
1719: // RaveElement rendered = ((RaveElement)pe).getRendered();
1720: Element rendered = MarkupService
1721: .getRenderedElementForElement(pe);
1722: if (rendered != null) {
1723: pe = rendered;
1724: }
1725:
1726: // Value val = CssLookup.getValue(pe, XhtmlCss.RAVELAYOUT_INDEX);
1727: CssValue cssValue = CssProvider.getEngineService()
1728: .getComputedValueForElement(pe,
1729: XhtmlCss.RAVELAYOUT_INDEX);
1730:
1731: // if (val == CssValueConstants.GRID_VALUE) {
1732: if (CssProvider.getValueService().isGridValue(cssValue)) {
1733: grid = true;
1734: } else if (pe.getTagName().endsWith(HtmlTag.FORM.name)) { // h:form too
1735: pe = (Element) pe.getParentNode();
1736: // val = CssLookup.getValue(pe, XhtmlCss.RAVELAYOUT_INDEX);
1737: CssValue cssValue2 = CssProvider.getEngineService()
1738: .getComputedValueForElement(pe,
1739: XhtmlCss.RAVELAYOUT_INDEX);
1740:
1741: // if (val == CssValueConstants.GRID_VALUE) {
1742: if (CssProvider.getValueService()
1743: .isGridValue(cssValue2)) {
1744: grid = true;
1745: }
1746: }
1747: }
1748:
1749: // if (((parent == null) || grid || Util.isFormBean(facesModel, parent))) {
1750: if (((parent == null) || grid || jsfForm
1751: .isFormDesignBean(parent))) {
1752: // GridHandler gm = GridHandler.getInstance();
1753: // setInitialPosition(designer, facesModel, lb, element, location.getCoordinates(), location.getSize(), /*coordinateTranslator,*/ updateSuspender);
1754: setInitialPosition(designer, lb, element, location
1755: .getCoordinates(), location.getSize(), /*coordinateTranslator,*/
1756: updateSuspender);
1757: select = lb;
1758: }
1759: }
1760:
1761: /**
1762: * Set the initial position for a given component.
1763: * It is assumed that the bean does not already have an associated position.
1764: *
1765: * @param editor The designer pane containing the element
1766: * @param element The element we want to set a style attribute for
1767: * @param pos The point where we want the element positioned. If null,
1768: * this method has no effect.
1769: * @param size The size to assign to the component. If null, don't set a
1770: * size, use the intrinsic size.
1771: */
1772: private static void setInitialPosition(
1773: Designer designer, /*FacesModel facesModel,*/
1774: MarkupDesignBean bean,
1775: Element element,
1776: Point pos,
1777: Dimension size,
1778: /*CoordinateTranslator coordinateTranslator,*/UpdateSuspender updateSuspender) {
1779: if (pos == null) {
1780: return;
1781: }
1782:
1783: DesignProperty styleProp = bean.getProperty("style"); // NOI18N
1784:
1785: if (styleProp == null) {
1786: // No style property - can't set position!!
1787: return;
1788: }
1789:
1790: String style = (String) styleProp.getValue();
1791: StringBuffer sb = new StringBuffer();
1792:
1793: if ((style != null) && (style.length() > 0)) {
1794: sb.append(style);
1795: sb.append("; ");
1796: }
1797:
1798: // Locate a grid layout parent
1799: // Document doc = editor.getDocument();
1800: // WebForm webform = doc.getWebForm();
1801: // XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
1802:
1803: // // This model should already be locked when we attempt to do this
1804: // assert facesModel.isWriteLocked();
1805:
1806: int x = pos.x;
1807: int y = pos.y;
1808:
1809: // GridHandler gridHandler = GridHandler.getInstance();
1810: // See if we should translate the coordinates
1811: if (element.getParentNode() instanceof Element) {
1812: Element parent = (Element) element.getParentNode();
1813: // CssBox parentBox = CssBox.getBox(parent);
1814: //
1815: // if (parentBox != null) {
1816: // // Translate coordinates from absolute/viewport
1817: // // to absolute coordinates relative to the target
1818: // // grid container
1819: //// Point p = translateCoordinates(parentBox, x, y);
1820: // Point p = gridHandler.translateCoordinates(parentBox, x, y);
1821: // x = p.x;
1822: // y = p.y;
1823: // }
1824: // Point point = gridHandler.translateCoordinates(parent, x, y);
1825: // Point point = coordinateTranslator.translateCoordinates(parent, x, y);
1826: Point point = translateCoordinates(designer, parent, x, y);
1827: x = point.x;
1828: y = point.y;
1829: }
1830:
1831: // x = snapX(x);
1832: // y = snapY(y);
1833: // x = gridHandler.snapX(x);
1834: // y = gridHandler.snapY(y);
1835: // x = coordinateTranslator.snapX(x);
1836: // y = coordinateTranslator.snapY(y);
1837: x = designer.snapX(x, null);
1838: y = designer.snapY(y, null);
1839:
1840: // prevent multiple updates for the same element - only need a single refresh
1841: try {
1842: // webform.getDomSynchronizer().setUpdatesSuspended(bean, true);
1843: // webform.setUpdatesSuspended(bean, true);
1844: updateSuspender.setSuspended(bean, true);
1845:
1846: // TODO: Find the -rendered- element; I have to look up margins on it
1847: // since it could come from style classes. For example, for a Braveheart
1848: // button, if I have a CSS rule .Btn2 { margin: 200px } I won't find
1849: // this style looking at the JSP element (ui:button) I need to do lookup
1850: // on the rendered <input class="Btn2" ...> element.
1851: // The "top" and "left" properties are relative to the margin edge of the
1852: // component yet the position is specified relative to the border (visible) area
1853: // int leftMargin = CssLookup.getLength(element, XhtmlCss.MARGIN_LEFT_INDEX);
1854: // int topMargin = CssLookup.getLength(element, XhtmlCss.MARGIN_TOP_INDEX);
1855: int leftMargin = CssProvider.getValueService()
1856: .getCssLength(element, XhtmlCss.MARGIN_LEFT_INDEX);
1857: int topMargin = CssProvider.getValueService().getCssLength(
1858: element, XhtmlCss.MARGIN_TOP_INDEX);
1859: x -= leftMargin;
1860: y -= topMargin;
1861:
1862: List set = new ArrayList(5);
1863: List remove = new ArrayList(3);
1864:
1865: sb.append("position: absolute; ");
1866: sb.append("left: ");
1867: sb.append(Integer.toString(x));
1868: sb.append("px; ");
1869: sb.append("top: ");
1870: sb.append(Integer.toString(y));
1871: sb.append("px");
1872:
1873: if (size != null) {
1874: if (!Util.setDesignProperty(bean, HtmlAttribute.WIDTH,
1875: size.width)) {
1876: sb.append("; width: ");
1877: sb.append(Integer.toString(size.width));
1878: sb.append("px"); // NOI18N
1879: } else {
1880: // Do I need to try to delete the width from the existing value string?
1881: // The only way this could get here is if the component has had a chance
1882: // to set widths/sizes with the create customizers
1883: }
1884:
1885: if (!Util.setDesignProperty(bean, HtmlAttribute.HEIGHT,
1886: size.height)) {
1887: sb.append("; height: ");
1888: sb.append(Integer.toString(size.height));
1889: sb.append("px"); // NOI18N
1890: } else {
1891: // Do I need to try to delete the width from the existing value string?
1892: // The only way this could get here is if the component has had a chance
1893: // to set widths/sizes with the create customizers
1894: }
1895: }
1896:
1897: styleProp.setValue(sb.toString());
1898: } finally {
1899: // webform.getDomSynchronizer().setUpdatesSuspended(bean, false);
1900: // webform.setUpdatesSuspended(bean, false);
1901: updateSuspender.setSuspended(bean, false);
1902: }
1903: }
1904:
1905: // XXX Moved from designer/../GridHandler.
1906: private static Point translateCoordinates(Designer designer,
1907: Element parent, int x, int y) {
1908: // CssBox parentBox = CssBox.getBox(parent);
1909: // CssBox parentBox = webForm.findCssBoxForElement(parent);
1910: Box parentBox = designer.findBoxForElement(parent);
1911:
1912: if (parentBox != null) {
1913: // Translate coordinates from absolute/viewport
1914: // to absolute coordinates relative to the target
1915: // grid container
1916: // Point p = translateCoordinates(parentBox, x, y);
1917: // return translateCoordinates(parentBox, x, y);
1918: return JsfSupportUtilities.translateCoordinates(parentBox,
1919: x, y);
1920: }
1921:
1922: return new Point(x, y);
1923: }
1924:
1925: // Moved to Util.
1926: // /** Attempt to set the given attribute on the bean to the given length
1927: // * and return true iff it succeeds.
1928: // */
1929: // public /*private*/ static boolean setDesignProperty(DesignBean bean, String attribute, int length) {
1930: // DesignProperty prop = bean.getProperty(attribute);
1931: //
1932: // if (prop != null) {
1933: // PropertyDescriptor desc = prop.getPropertyDescriptor();
1934: // Class clz = desc.getPropertyType();
1935: //
1936: // // I can do == instead of isAssignableFrom because
1937: // // both String and Integer are final!
1938: // if (clz == String.class) {
1939: // prop.setValue(Integer.toString(length));
1940: //
1941: // return true;
1942: // } else if (clz == Integer.TYPE) {
1943: // prop.setValue(new Integer(length));
1944: //
1945: // return true;
1946: // }
1947: // }
1948: //
1949: // return false;
1950: // }
1951:
1952: private boolean doBindOrMoveItems(int dropAction,
1953: DesignBean[] beans, Transferable t, DesignBean dropNode,
1954: int nodePos, String facet, Location location, /*CoordinateTranslator coordinateTranslator,*/
1955: UpdateSuspender updateSuspender) {
1956: // if(DesignerUtils.DEBUG) {
1957: // DesignerUtils.debugLog(getClass().getName() + ".bindOrMoveItems(int, DesignBean[], Transferable, DesignBean, int, String)");
1958: // }
1959: if (t == null) {
1960: throw (new IllegalArgumentException("Null transferable."));
1961: }
1962: if ((beans == null) || (beans.length == 0)) {
1963: return false;
1964: }
1965:
1966: // It's a app outline drag: either move or link. Don't involve
1967: // the transfer handler.
1968: int allowed = computeActions(dropNode, t, false, nodePos);
1969:
1970: if (allowed == DnDConstants.ACTION_NONE) {
1971: return false;
1972: }
1973:
1974: if (dropAction == DnDConstants.ACTION_COPY) {
1975: // LiveUnit unit = facesModel.getLiveUnit();
1976: LiveUnit unit = jsfForm.getLiveUnit();
1977: Transferable newTransferable = unit.copyBeans(beans);
1978:
1979: if (newTransferable == null) {
1980: return false;
1981: }
1982:
1983: // Location location =
1984: // computePositions((DesignBean)dropNode, nodePos, facet, null, null, false);
1985: DesignBean parent = location.getDroppee();
1986: pasteBeans(/*webform,*/t, parent, location.getPos(), null, /*coordinateTranslator,*/
1987: updateSuspender);
1988:
1989: return true;
1990: } else if (nodePos != DROP_CENTER) {
1991: // MOVE: fall through to handle
1992: } else if ((dropAction == DnDConstants.ACTION_LINK)
1993: || ((dropAction == DnDConstants.ACTION_MOVE) && ((allowed & DnDConstants.ACTION_LINK) != 0))) {
1994: // LINK
1995: // (We treat a move when link is permitted as a link since move
1996: // is where you haven't selected any modifier keys so
1997: // it's the mode where we make a best guess as to what
1998: // you want. It would be better if we had a modifier key
1999: // to let the user FORCE move though. Perhaps we should rethink
2000: // this since there IS a modifier key for link (ctrl-shift).
2001: List<DesignBean> list = new ArrayList<DesignBean>(
2002: beans.length);
2003:
2004: for (int i = 0; i < beans.length; i++) {
2005: list.add(beans[i]);
2006: }
2007:
2008: assert nodePos == DROP_CENTER;
2009: handleLinks((DesignBean) dropNode, list, updateSuspender);
2010:
2011: return true;
2012: } else if ((dropAction & DnDConstants.ACTION_MOVE) != 0) {
2013: // MOVE: fall through to handle
2014: }
2015:
2016: // Move
2017: // Location location =
2018: // computePositions((DesignBean)dropNode, nodePos, facet, null, null, false);
2019: DesignBean parent = location.getDroppee();
2020: moveBeans(/*webform,*/beans, parent, location.getPos(),
2021: updateSuspender);
2022: return true;
2023: }
2024:
2025: public int computeActions(DesignBean droppee,
2026: Transferable transferable) {
2027: return computeActions(droppee, transferable, false, DROP_CENTER);
2028: }
2029:
2030: /** Figure out which kind of action we can do for the given
2031: * transferable over the given droppee.
2032: *
2033: * @param droppee The target component
2034: * @param transferable The transferable being considered dropped
2035: * or linked on the droppee. If it references multiple
2036: * components, it will set the allowable action union of
2037: * all the components.
2038: * @param searchUp If true, you are permitted to search upwards
2039: * as well.
2040: */
2041: private int computeActions(DesignBean droppee,
2042: Transferable transferable, boolean searchUp, int nodePos) {
2043: // if(DesignerUtils.DEBUG) {
2044: // DesignerUtils.debugLog(getClass().getName() + ".computeActions(DesignBean, Transferable, boolean, int)");
2045: // }
2046: if (transferable == null) {
2047: throw (new IllegalArgumentException("Null transferable."));
2048: }
2049: int action = DnDConstants.ACTION_NONE;
2050: String[] classes = null;
2051: DesignBean[] beans = null;
2052: DataFlavor[] flavors = transferable.getTransferDataFlavors();
2053:
2054: for (int j = 0; j < flavors.length; j++) {
2055: Class clz = flavors[j].getRepresentationClass();
2056:
2057: if (clz == DisplayItem.class) {
2058: // Can always "move" from the palette - it's an implied copy.
2059: // The explorer drag & drop is a bit weird about this - they
2060: // only pass "move" as the valid operation, not copy.
2061: action |= DnDConstants.ACTION_MOVE;
2062:
2063: Object data;
2064:
2065: try {
2066: data = transferable.getTransferData(flavors[j]);
2067: } catch (Exception e) {
2068: ErrorManager.getDefault().notify(e);
2069:
2070: return action;
2071: }
2072:
2073: if (!(data instanceof DisplayItem)) {
2074: ErrorManager.getDefault().notify(
2075: ErrorManager.INFORMATIONAL,
2076: new IllegalStateException(
2077: "Invalid DisplayItem transfer data: "
2078: + data)); // NOI18N
2079:
2080: return action;
2081: }
2082:
2083: List list = new ArrayList();
2084: DisplayItem item = (DisplayItem) data;
2085:
2086: if (item instanceof BeanCreateInfo) {
2087: BeanCreateInfo bci = (BeanCreateInfo) item;
2088: classes = new String[] { bci.getBeanClassName() };
2089: } else if (item instanceof BeanCreateInfoSet) {
2090: BeanCreateInfoSet bcis = (BeanCreateInfoSet) item;
2091: classes = bcis.getBeanClassNames();
2092: } else {
2093: ErrorManager.getDefault().notify(
2094: ErrorManager.INFORMATIONAL,
2095: new IllegalStateException("Illegal item="
2096: + item)); // NOI18N
2097: }
2098:
2099: break;
2100: } else if (clz == DesignBean.class) {
2101: Object data;
2102:
2103: try {
2104: data = transferable.getTransferData(flavors[j]);
2105: } catch (IOException ex) {
2106: ErrorManager.getDefault().notify(ex);
2107:
2108: return action;
2109: } catch (UnsupportedFlavorException ex) {
2110: ErrorManager.getDefault().notify(ex);
2111:
2112: return action;
2113: }
2114:
2115: if ((data != null) && data instanceof DesignBean[]) {
2116: beans = (DesignBean[]) data;
2117:
2118: if (beans == null) {
2119: return action;
2120: }
2121:
2122: classes = new String[beans.length];
2123:
2124: for (int i = 0; i < beans.length; i++) {
2125: classes[i] = beans[i].getInstance().getClass()
2126: .getName();
2127: }
2128:
2129: // See if we can move these beans. We can move if the
2130: // parent target location is not a child of any of the beans,
2131: // or the beans themselves
2132: boolean cannot = false;
2133:
2134: for (int i = 0; i < beans.length; i++) {
2135: DesignBean d = droppee;
2136:
2137: while (d != null) {
2138: if (d == beans[i]) {
2139: cannot = true;
2140:
2141: break;
2142: }
2143:
2144: d = d.getBeanParent();
2145: }
2146: }
2147:
2148: if (!cannot) {
2149: action |= DnDConstants.ACTION_MOVE;
2150: }
2151:
2152: break;
2153: }
2154: } else if (clz == LiveUnit.ClipImage.class) {
2155: Object data;
2156:
2157: try {
2158: data = transferable.getTransferData(flavors[j]);
2159: } catch (Exception e) {
2160: ErrorManager.getDefault().notify(e);
2161:
2162: return action;
2163: }
2164:
2165: if (!(data instanceof LiveUnit.ClipImage)) {
2166: ErrorManager.getDefault().log(
2167: "Invalid LiveUnit.ClipImage transfer data: "
2168: + data);
2169:
2170: return action;
2171: }
2172:
2173: LiveUnit.ClipImage luc = (LiveUnit.ClipImage) data;
2174: classes = luc.getTypes();
2175: }
2176: }
2177:
2178: if (classes == null) {
2179: return action;
2180: }
2181:
2182: return computeActions(droppee, classes, beans, action,
2183: searchUp, nodePos);
2184: }
2185:
2186: private int computeActions(DesignBean origDroppee,
2187: String[] classes, DesignBean[] beans, int action,
2188: boolean searchUp, int nodePos) {
2189: DesignBean droppee = null;
2190:
2191: if (nodePos == DROP_CENTER) { // Can only link if pointing at a node
2192: linkCheckFinished: for (int i = 0; i < classes.length; i++) {
2193: try {
2194: // Class clz = facesModel.getFacesUnit().getBeanClass(classes[i]);
2195: Class clz = jsfForm.getFacesPageUnit()
2196: .getBeanClass(classes[i]);
2197: DesignBean lb = null;
2198:
2199: if (beans != null) {
2200: lb = beans[i];
2201: }
2202:
2203: droppee = origDroppee;
2204:
2205: for (droppee = origDroppee; droppee != null; droppee = droppee
2206: .getBeanParent()) {
2207: // Prevent self-linking
2208: if (beans != null) {
2209: boolean same = false;
2210:
2211: for (int j = 0; j < beans.length; j++) {
2212: if (droppee == beans[j]) {
2213: same = true;
2214:
2215: break;
2216: }
2217: }
2218:
2219: if (same) {
2220: if (!searchUp) {
2221: break;
2222: } else {
2223: continue;
2224: }
2225: }
2226: }
2227:
2228: DesignInfo dbi = droppee.getDesignInfo();
2229:
2230: if ((dbi != null)
2231: && dbi.acceptLink(droppee, lb, clz)) {
2232: action |= DnDConstants.ACTION_LINK;
2233:
2234: break linkCheckFinished;
2235: }
2236:
2237: if (!searchUp) {
2238: break;
2239: }
2240: }
2241: } catch (Exception e) {
2242: ErrorManager.getDefault().notify(e);
2243: }
2244: }
2245: } else {
2246: // For pos=ABOVE or BELOW, the passed in node points to the specific
2247: // node -sibling-, but we want the parent
2248: origDroppee = origDroppee.getBeanParent();
2249: }
2250:
2251: // See if any of the droppee parents accept the new item as a
2252: // child
2253: for (int i = 0; i < classes.length; i++) {
2254: // DesignBean parent = Util.findParent(classes[i], origDroppee, null, searchUp, facesModel);
2255: DesignBean parent = jsfForm.findParent(classes[i],
2256: origDroppee, null, searchUp);
2257:
2258: if (parent != null) {
2259: action |= DnDConstants.ACTION_COPY;
2260:
2261: break;
2262: } else {
2263: action &= ~DnDConstants.ACTION_MOVE;
2264:
2265: break;
2266: }
2267: }
2268:
2269: return action;
2270: }
2271:
2272: // Moved to Util.
2273: // public /*private*/ DesignBean findParent(String className, DesignBean droppee, Node parentNode,
2274: // boolean searchUp) {
2275: // if (isGridMode() && (droppee == null) && (facesModel.getLiveUnit() != null)) {
2276: // MarkupBean bean = facesModel.getFacesUnit().getDefaultParent();
2277: //
2278: // if (bean != null) {
2279: // droppee = facesModel.getLiveUnit().getDesignBean(bean);
2280: // }
2281: // }
2282: //
2283: // DesignBean parent = droppee;
2284: //
2285: // if (searchUp) {
2286: // for (; (parent != null) && !parent.isContainer(); parent = parent.getBeanParent()) {
2287: // ;
2288: // }
2289: // }
2290: //
2291: // LiveUnit unit = facesModel.getLiveUnit();
2292: //
2293: // if (searchUp) {
2294: // boolean isHtmlBean =
2295: // className.startsWith(HtmlBean.PACKAGE) &&
2296: // // f:verbatim is explicitly allowed where jsf components can go
2297: // // XXX Why not F_Verbatim.class.getName() ?
2298: // !(HtmlBean.PACKAGE + "F_Verbatim").equals(className); // NOI18N
2299: //
2300: // if (isHtmlBean) {
2301: // // We can't drop anywhere below a "renders children" JSF
2302: // // component
2303: // parent = findHtmlContainer(parent);
2304: // }
2305: // }
2306: //
2307: // // Validate the parent: walk up the parent chain until you find
2308: // // a parent which will accept the child.
2309: // for (; parent != null; parent = parent.getBeanParent()) {
2310: // if (unit.canCreateBean(className, parent, null)) {
2311: // // Found it
2312: // break;
2313: // }
2314: //
2315: // if (!searchUp) {
2316: // return null;
2317: // }
2318: // }
2319: //
2320: // if ((parent == null) && (parentNode != null)) {
2321: // // Adjust hierarchy: we should pass in a parent
2322: // // pointer based on where we are: locate the closest
2323: // // jsf parent above
2324: // Node n = parentNode;
2325: // MarkupBean mb = null;
2326: //
2327: // while (n != null) {
2328: // if (n instanceof Element) {
2329: // Element e = (Element)n;
2330: //// mb = FacesSupport.getMarkupBean(webform.getDocument(), e);
2331: // mb = getMarkupBean(facesModel, e);
2332: //
2333: // if (mb != null) {
2334: // break;
2335: // }
2336: // }
2337: //
2338: // n = n.getParentNode();
2339: // }
2340: //
2341: // if (mb != null) {
2342: // DesignBean lmb = facesModel.getLiveUnit().getDesignBean(mb);
2343: //
2344: // if (lmb.isContainer()) {
2345: // parent = lmb;
2346: // }
2347: // }
2348: //
2349: // if (parent == null) {
2350: // parent = facesModel.getRootBean();
2351: // }
2352: // }
2353: //
2354: // return parent;
2355: // }
2356:
2357: // Moved to Util.
2358: // /**
2359: // * Return true if this document is in "grid mode" (objects
2360: // * should be positioned by absolute coordinates instead of in
2361: // * "flow" order.
2362: // *
2363: // * @return true iff the document should be in grid mode
2364: // */
2365: // private boolean isGridMode() {
2366: // Element b = facesModel.getHtmlBody();
2367: //
2368: // if (b == null) {
2369: // return false;
2370: // }
2371: //
2372: //// Value val = CssLookup.getValue(b, XhtmlCss.RAVELAYOUT_INDEX);
2373: // CssValue cssValue = CssProvider.getEngineService().getComputedValueForElement(b, XhtmlCss.RAVELAYOUT_INDEX);
2374: //
2375: //// return val == CssValueConstants.GRID_VALUE;
2376: // return CssProvider.getValueService().isGridValue(cssValue);
2377: // }
2378:
2379: /** Handle links where the target is a possibly nonvisual bean so has no element */
2380: public void handleLinks(DesignBean droppee, List beans,
2381: UpdateSuspender updateSuspender) {
2382: // Document document = webform.getDocument();
2383:
2384: int n = beans.size();
2385: String description = NbBundle.getMessage(FacesDndSupport.class,
2386: (n > 1) ? "LBL_LinkComponents" : "LBL_LinkComponent"); // NOI18N
2387: // UndoEvent undoEvent = facesModel.writeLock(description);
2388: UndoEvent undoEvent = jsfForm.writeLock(description);
2389: try {
2390: // int n = beans.size();
2391: // String description =
2392: // NbBundle.getMessage(DndHandler.class, (n > 1) ? "LinkComponents" : "LinkComponent"); // NOI18N
2393: // document.writeLock(description);
2394:
2395: for (int i = 0; i < n; i++) {
2396: DesignBean lb = (DesignBean) beans.get(i);
2397:
2398: try {
2399: // If you drop on an existing component, see if they
2400: // can be wired together
2401: // Try to bind the two together - for example, if you
2402: // drop a RowSet on a bean that has a RowSet property,
2403: // the RowSet property is bound to this particular
2404: // RowSet.
2405: DesignInfo dbi = droppee.getDesignInfo();
2406: boolean canLink = (dbi != null)
2407: && dbi.acceptLink(droppee, lb, lb
2408: .getInstance().getClass());
2409:
2410: if (canLink) {
2411: MarkupDesignBean mbean = null;
2412:
2413: if (droppee instanceof MarkupDesignBean) {
2414: // link beans might perform lots and lots of
2415: // updates on the element - that's the case
2416: // for the data grid when you bind a table
2417: // to it for example. So batch up all these
2418: // modifications into a single change event
2419: // on the top level element.
2420: mbean = (MarkupDesignBean) droppee;
2421: // webform.getDomSynchronizer().setUpdatesSuspended(mbean, true);
2422: // webform.setUpdatesSuspended(mbean, true);
2423: updateSuspender.setSuspended(mbean, true);
2424: }
2425:
2426: try {
2427: // facesModel.linkBeans(droppee, lb);
2428: jsfForm.linkDesignBeans(droppee, lb);
2429: } finally {
2430: if (mbean != null) {
2431: // Process queued up changes
2432: // webform.getDomSynchronizer().setUpdatesSuspended(mbean, false);
2433: // webform.setUpdatesSuspended(mbean, false);
2434: updateSuspender.setSuspended(mbean,
2435: false);
2436: }
2437: }
2438:
2439: // The target bean should be selected instead of
2440: // the droppee!
2441: select = droppee;
2442: }
2443: } catch (Exception e) {
2444: ErrorManager.getDefault().notify(e);
2445: }
2446: }
2447: } finally {
2448: // document.writeUnlock();
2449: // facesModel.writeUnlock(undoEvent);
2450: jsfForm.writeUnlock(undoEvent);
2451: }
2452: }
2453:
2454: /**
2455: * Move the given beans to the given parent and markup position.
2456: */
2457: public/*private*//*static*/void moveBeans(
2458: /*WebForm webform,*/DesignBean[] beans, DesignBean parent,
2459: MarkupPosition pos, UpdateSuspender updateSuspender) {
2460: if ((beans == null) || (beans.length == 0)) {
2461: return;
2462: }
2463:
2464: // Document document = null;
2465: //
2466: // if (webform != null) {
2467: // // XXX what about locking on java-only buffers? (SessionBean1 etc.)
2468: // document = webform.getDocument();
2469: // }
2470: // FacesModel facesModel = webform == null ? null : webform.getModel();
2471:
2472: LiveUnit lu = (LiveUnit) beans[0].getDesignContext();
2473:
2474: UndoEvent undoEvent;
2475: // if (facesModel != null) {
2476: if (jsfForm != null) {
2477: String description = NbBundle.getMessage(
2478: FacesDndSupport.class,
2479: (beans.length > 1) ? "LBL_MoveComponents" // NOI18N
2480: : "LBL_MoveComponent"); // NOI18N
2481: // undoEvent = facesModel.writeLock(description);
2482: undoEvent = jsfForm.writeLock(description);
2483: } else {
2484: undoEvent = null; // No undo event
2485: lu.writeLock(undoEvent);
2486: }
2487:
2488: try {
2489: // if (document != null) {
2490: // String description =
2491: // NbBundle.getMessage(SelectionTopComp.class,
2492: // (beans.length > 1) ? "MoveComponents" // NOI18N
2493: // : "MoveComponent"); // NOI18N
2494: // document.writeLock(description);
2495: // } else {
2496: // lu.writeLock(null); // No undo event
2497: // }
2498:
2499: // Decide whether we need to strip out position coordinates
2500: // from the beans being moved
2501: boolean stripPos = !isGridContext(parent, pos);
2502:
2503: for (int i = 0; i < beans.length; i++) {
2504: if (!(beans[i] instanceof MarkupDesignBean)) {
2505: continue;
2506: }
2507:
2508: MarkupDesignBean bean = (MarkupDesignBean) beans[i];
2509:
2510: if (stripPos) {
2511: Element e = bean.getElement();
2512:
2513: try {
2514: // webform.getDomSynchronizer().setUpdatesSuspended(bean, true);
2515: // webform.setUpdatesSuspended(bean, true);
2516: if (updateSuspender != null) {
2517: updateSuspender.setSuspended(bean, true);
2518: }
2519:
2520: // CssLookup.removeLocalStyleValue(e, XhtmlCss.POSITION_INDEX);
2521: // CssLookup.removeLocalStyleValue(e, XhtmlCss.LEFT_INDEX);
2522: // CssLookup.removeLocalStyleValue(e, XhtmlCss.TOP_INDEX);
2523: Util.removeLocalStyleValueForElement(e,
2524: XhtmlCss.POSITION_INDEX);
2525: Util.removeLocalStyleValueForElement(e,
2526: XhtmlCss.LEFT_INDEX);
2527: Util.removeLocalStyleValueForElement(e,
2528: XhtmlCss.TOP_INDEX);
2529: } finally {
2530: // webform.getDomSynchronizer().setUpdatesSuspended(bean, false);
2531: // webform.setUpdatesSuspended(bean, false);
2532: if (updateSuspender != null) {
2533: updateSuspender.setSuspended(bean, false);
2534: }
2535: }
2536: }
2537:
2538: lu.moveBean(bean, parent, pos);
2539: }
2540: } finally {
2541: // if (document != null) {
2542: // document.writeUnlock();
2543: // } else {
2544: // lu.writeUnlock(null);
2545: // }
2546: // if (facesModel != null) {
2547: // facesModel.writeUnlock(undoEvent);
2548: if (jsfForm != null) {
2549: jsfForm.writeUnlock(undoEvent);
2550: } else {
2551: lu.writeUnlock(undoEvent);
2552: }
2553: }
2554: }
2555:
2556: private boolean importImage(Designer designer, final File file,
2557: Location location, /*CoordinateTranslator coordinateTranslator,*/
2558: UpdateSuspender updateSuspender) {
2559: try {
2560: URL url = file.toURI().toURL();
2561:
2562: // Import web context relative rather than file relative
2563: //FileObject webitem = webform.getDataObject().getPrimaryFile();
2564: //String local = JsfProjectHelper.addResource(webitem, url, true);
2565: // DesignProject project = facesModel.getLiveUnit().getProject();
2566: DesignProject project = jsfForm.getLiveUnit().getProject();
2567: String local = RESOURCES
2568: + UrlPropertyEditor.encodeUrl(file.getName());
2569: project.addResource(url, new URI(WEB + local));
2570:
2571: return importImage(designer, local, location, /*coordinateTranslator,*/
2572: updateSuspender);
2573: } catch (Exception ex) {
2574: ErrorManager.getDefault().notify(ex);
2575: }
2576: return false;
2577: }
2578:
2579: private boolean importImage(Designer designer, final String local,
2580: Location location, /*CoordinateTranslator coordinateTranslator,*/
2581: UpdateSuspender updateSuspender) {
2582: // Import the file.
2583: // If it's an image, just create an image component for it
2584: // and drop it on the page. (If there are multiple images,
2585: // don't position them. This will happen automatically
2586: // because we will clear the position after the first dropped
2587: // image.)
2588: // If it's a stylesheet, add it as a stylesheet.
2589: // Otherwise consult the import mechanism (e.g. for html,
2590: // jsp, and friends).
2591: // For image I still need the position, so delay slightly.
2592: // Location location =
2593: // computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
2594: DesignBean droppee = location.getDroppee();
2595: // Document document = webform.getDocument();
2596:
2597: String description = NbBundle.getMessage(FacesDndSupport.class,
2598: "LBL_DropComponent"); // NOI18N
2599: // UndoEvent undoEvent = facesModel.writeLock(description);
2600: UndoEvent undoEvent = jsfForm.writeLock(description);
2601: try {
2602: // String description = NbBundle.getMessage(DndHandler.class, "DropComponent"); // NOI18N
2603: // document.writeLock(description);
2604:
2605: String className;
2606: String propertyName;
2607:
2608: // XXX This should be decided by the parent bean.
2609: // I.e. appropriate api is missing.
2610: // if (DesignerUtils.isBraveheartPage(webform.getJspDom())) {
2611: // XXX This shouldn't be here resolved, but in parent bean.
2612: // if (InSyncServiceProvider.get().isWoodstockPage(facesModel.getJspDom())) {
2613: if (InSyncServiceProvider.get().isWoodstockPage(
2614: jsfForm.getJspDom())) {
2615: // Use woodstock ImageComponent component
2616: className = com.sun.webui.jsf.component.ImageComponent.class
2617: .getName(); // NOI18N
2618: propertyName = "url";
2619: // } else if (InSyncServiceProvider.get().isBraveheartPage(facesModel.getJspDom())) {
2620: } else if (InSyncServiceProvider.get().isBraveheartPage(
2621: jsfForm.getJspDom())) {
2622: className = com.sun.rave.web.ui.component.ImageComponent.class
2623: .getName(); // NOI18N
2624: propertyName = "url";
2625: } else {
2626: className = javax.faces.component.html.HtmlGraphicImage.class
2627: .getName(); // NOI18N
2628: propertyName = "value";
2629: }
2630:
2631: // DesignBean parent = Util.findParent(className, droppee, location.getPos().getUnderParent(), true, facesModel);
2632: DesignBean parent = jsfForm.findParent(className, droppee,
2633: location.getPos().getUnderParent(), true);
2634: DesignBean bean = createBean(className, parent, location
2635: .getPos(), null);
2636: select = bean;
2637:
2638: if (bean instanceof MarkupDesignBean) {
2639: MarkupDesignBean mbean = (MarkupDesignBean) bean;
2640: positionBean(designer, mbean, parent, mbean
2641: .getElement(), location, /*coordinateTranslator,*/
2642: updateSuspender);
2643: }
2644:
2645: // selectBean(select);
2646: // webform.getSelection().selectBean(select);
2647: fireSelectedDesignBeanChanged(select);
2648: select = null;
2649:
2650: DesignProperty prop = bean.getProperty(propertyName);
2651:
2652: if (prop != null) {
2653: prop.setValue(local);
2654: }
2655:
2656: //inlineEdit(beans);
2657: } finally {
2658: // document.writeUnlock();
2659: // facesModel.writeUnlock(undoEvent);
2660: jsfForm.writeUnlock(undoEvent);
2661: }
2662: return true;
2663: }
2664:
2665: private boolean importStylesheet(final File file) {
2666: try {
2667: URL url = file.toURI().toURL();
2668:
2669: // Import web context relative rather than file relative
2670: //FileObject webitem = webform.getDataObject().getPrimaryFile();
2671: //String local = JsfProjectHelper.addResource(webitem, url, true);
2672: // DesignProject project = facesModel.getLiveUnit().getProject();
2673: DesignProject project = jsfForm.getLiveUnit().getProject();
2674: String local = RESOURCES
2675: + UrlPropertyEditor.encodeUrl(file.getName());
2676: project.addResource(url, new URI(WEB + local));
2677:
2678: return importStylesheet(local);
2679: } catch (Exception ex) {
2680: ErrorManager.getDefault().notify(ex);
2681: }
2682: return false;
2683: }
2684:
2685: private boolean importStylesheet(final String local) {
2686: // Document document = webform.getDocument();
2687:
2688: //ArrayList beanItems = new ArrayList();
2689: String description = NbBundle.getMessage(FacesDndSupport.class,
2690: "LBL_DropComponent"); // NOI18N
2691: // UndoEvent undoEvent = facesModel.writeLock(description);
2692: UndoEvent undoEvent = jsfForm.writeLock(description);
2693: try {
2694: // String description = NbBundle.getMessage(DndHandler.class, "DropComponent"); // NOI18N
2695: // document.writeLock(description);
2696:
2697: // Add stylesheet link
2698: // org.w3c.dom.Document dom = facesModel.getJspDom();
2699: org.w3c.dom.Document dom = jsfForm.getJspDom();
2700: Element root = dom.getDocumentElement();
2701: // MarkupUnit markup = facesModel.getMarkupUnit();
2702: MarkupUnit markup = jsfForm.getMarkupUnit();
2703: Element html = markup.findHtmlTag(root);
2704: DesignBean bean = null;
2705:
2706: if (html == null) {
2707: DesignBean uihead = null;
2708: // LiveUnit lu = facesModel.getLiveUnit();
2709: LiveUnit lu = jsfForm.getLiveUnit();
2710: DesignBean[] heads = null;
2711:
2712: // Project project = facesModel.getProject();
2713: Project project = jsfForm.getProject();
2714: if (project != null) {
2715: if (J2eeModule.JAVA_EE_5.equals(JsfProjectUtils
2716: .getJ2eePlatformVersion(project))) {
2717: // JSF 1.2 - hence use woodstock Head component
2718: heads = lu
2719: .getBeansOfType(com.sun.webui.jsf.component.Head.class);
2720: } else {
2721: // JSF 1.1
2722: heads = lu
2723: .getBeansOfType(com.sun.rave.web.ui.component.Head.class);
2724: }
2725: }
2726:
2727: if ((heads != null) && (heads.length > 0)) {
2728: uihead = heads[0];
2729:
2730: if (uihead != null) {
2731: if (J2eeModule.JAVA_EE_5.equals(JsfProjectUtils
2732: .getJ2eePlatformVersion(project))) {
2733: // JSF 1.2 - hence woodstock Link component
2734: bean = lu
2735: .createBean(
2736: com.sun.webui.jsf.component.Link.class
2737: .getName(),
2738: uihead,
2739: new com.sun.rave.designtime.Position()); // NOI18N
2740: bean.getProperty("url").setValue(local); // NOI18N
2741: } else {
2742: // No stylesheet link exists - add one
2743: // XXX TODO get rid of using xhtml directly,
2744: // it should be shielded by api.
2745: bean = lu
2746: .createBean(
2747: com.sun.rave.web.ui.component.Link.class
2748: .getName(),
2749: uihead,
2750: new com.sun.rave.designtime.Position()); // NOI18N
2751: bean.getProperty("url").setValue(local); // NOI18N
2752: }
2753: }
2754: }
2755: } else {
2756: // Gotta replace with HtmlTag.LINK.name
2757: Element head = Util.findChild(HtmlTag.HEAD.name, html,
2758: false);
2759: // XXX TODO get rid of using xhtml directly,
2760: // it should be shielded by api.
2761: bean = /*webform.getDocument().*/createBean(
2762: org.netbeans.modules.visualweb.xhtml.Link.class
2763: .getName(), head, null);
2764: bean.getProperty("href").setValue(local); // NOI18N
2765: }
2766:
2767: if (bean == null) {
2768: return false;
2769: }
2770:
2771: bean.getProperty("rel").setValue("stylesheet"); // NOI18N
2772: bean.getProperty("type").setValue("text/css"); // NOI18N
2773: } finally {
2774: // document.writeUnlock();
2775: // facesModel.writeUnlock(undoEvent);
2776: jsfForm.writeUnlock(undoEvent);
2777: }
2778:
2779: // webform.refresh(true);
2780: fireRefreshNeeded(true);
2781: return true;
2782: }
2783:
2784: // XXX
2785: private JPanel importFilePanel;
2786:
2787: private boolean importFile(Designer designer, final File f, /*JPanel panel,*/
2788: Location location, /*CoordinateTranslator coordinateTranslator,*/
2789: UpdateSuspender updateSuspender) {
2790: if (f.exists()) {
2791: String name = f.getName();
2792: String extension = name
2793: .substring(name.lastIndexOf(".") + 1); // NOI18N
2794: // Project project = facesModel.getProject();
2795: Project project = jsfForm.getProject();
2796:
2797: // XXX #95601 Skip the file if it is already inside the project.
2798: if (FileOwnerQuery.getOwner(f.toURI()) == project) {
2799: // return panel;
2800: return true;
2801: }
2802:
2803: //String mime = FileUtil.getMIMEType(extension);
2804: // They've only registered gif and jpg so not a big deal
2805: if (/*DesignerUtils.*/isImage(extension)) {
2806: // Location location =
2807: // computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
2808: importImage(designer, f, location, /*coordinateTranslator,*/
2809: updateSuspender);
2810:
2811: // return panel;
2812: return true;
2813: } else if (/*DesignerUtils.*/isStylesheet(extension)) {
2814: importStylesheet(f);
2815:
2816: // return panel;
2817: return true;
2818: }
2819:
2820: // <dep> XXX Getting rid of dep on project/importpage.
2821: // TODO There should be a better API created.
2822: // panel = PageImport.importRandomFile(project, f, extension, panel);
2823: // ====
2824: Lookup l = Lookup.getDefault();
2825: Lookup.Template<Importable.PageImportable> template = new Lookup.Template<Importable.PageImportable>(
2826: Importable.PageImportable.class);
2827: Iterator<? extends Importable.PageImportable> it = l
2828: .lookup(template).allInstances().iterator();
2829: while (it.hasNext()) {
2830: Importable.PageImportable pageImportable = it.next();
2831: // panel = pageImportable.importRandomFile(project, f, extension, panel);
2832: importFilePanel = pageImportable.importRandomFile(
2833: project, f, extension, importFilePanel);
2834: break;
2835: }
2836: // </dep>
2837:
2838: // if (panel == null) {
2839: if (importFilePanel == null) {
2840: // JsfProjectUtils.importFile(facesModel.getProject(), f);
2841: JsfProjectUtils.importFile(jsfForm.getProject(), f);
2842: }
2843: }
2844:
2845: // return panel;
2846: return false;
2847: }
2848:
2849: private/*public*/boolean importString(Designer designer,
2850: String string, Location location, /*CoordinateTranslator coordinateTranslator,*/
2851: UpdateSuspender updateSuspender) {
2852: // Import the string as part of an output text component
2853: // Location location =
2854: // computePositions(null, DROP_CENTER, null, getDropPoint(), insertPos, true);
2855: DesignBean droppee = location.getDroppee();
2856:
2857: // Document document = webform.getDocument();
2858:
2859: String description = NbBundle.getMessage(FacesDndSupport.class,
2860: "LBL_DropComponent"); // NOI18N
2861: // UndoEvent undoEvent = facesModel.writeLock(description);
2862: UndoEvent undoEvent = jsfForm.writeLock(description);
2863: try {
2864: // String description = NbBundle.getMessage(DndHandler.class, "DropComponent"); // NOI18N
2865: // document.writeLock(description);
2866:
2867: String className;
2868: String propertyName;
2869:
2870: // XXX This should be decided by the parent bean.
2871: // I.e. appropriate api is missing.
2872: // if (DesignerUtils.isBraveheartPage(webform.getJspDom())) {
2873: // XXX This shouldn't be here resolved, but in parent bean.
2874: // if (InSyncServiceProvider.get().isWoodstockPage(facesModel.getJspDom())) {
2875: if (InSyncServiceProvider.get().isWoodstockPage(
2876: jsfForm.getJspDom())) {
2877: // JSF 1.2 - hence use woodstock StaticText component
2878: className = com.sun.webui.jsf.component.StaticText.class
2879: .getName(); // NOI18N
2880: propertyName = "text";
2881: // } else if (InSyncServiceProvider.get().isBraveheartPage(facesModel.getJspDom())) {
2882: } else if (InSyncServiceProvider.get().isBraveheartPage(
2883: jsfForm.getJspDom())) {
2884: className = com.sun.rave.web.ui.component.StaticText.class
2885: .getName(); // NOI18N
2886: propertyName = "text";
2887: } else {
2888: className = javax.faces.component.html.HtmlOutputText.class
2889: .getName(); // NOI18N
2890: propertyName = "value";
2891: }
2892:
2893: // DesignBean parent = Util.findParent(className, droppee, location.getPos().getUnderParent(), true, facesModel);
2894: DesignBean parent = jsfForm.findParent(className, droppee,
2895: location.getPos().getUnderParent(), true);
2896: DesignBean bean = createBean(className, parent, location
2897: .getPos(), null);
2898: select = bean;
2899:
2900: if (bean instanceof MarkupDesignBean) {
2901: MarkupDesignBean mbean = (MarkupDesignBean) bean;
2902: positionBean(designer, mbean, parent, mbean
2903: .getElement(), location, /*coordinateTranslator,*/
2904: updateSuspender);
2905: }
2906:
2907: // selectBean(select);
2908: // webform.getSelection().selectBean(select);
2909: fireSelectedDesignBeanChanged(select);
2910: select = null;
2911:
2912: DesignProperty prop = bean.getProperty(propertyName);
2913:
2914: if (prop != null) {
2915: // Clean up string a little
2916: // TODO - should I look for <HTML> markup and if so unset the escape property?
2917: string = string.replace('\n', ' ');
2918: string = string.replace('\r', ' ');
2919: prop.setValue(string);
2920: }
2921:
2922: //inlineEdit(beans);
2923: } finally {
2924: // document.writeUnlock();
2925: // facesModel.writeUnlock(undoEvent);
2926: jsfForm.writeUnlock(undoEvent);
2927: }
2928: return true;
2929: }
2930:
2931: /** Create a new bean of the given type, positioned below parent
2932: * before the given node. Returns the created element. */
2933: private DesignBean createBean(String className, Node parent,
2934: Node before) {
2935: MarkupPosition pos = new MarkupPosition(parent, before);
2936: DesignBean parentBean = /*FacesSupport.*/Util
2937: .findParentBean(parent);
2938: // LiveUnit unit = facesModel.getLiveUnit();
2939: LiveUnit unit = jsfForm.getLiveUnit();
2940: DesignBean bean = unit.createBean(className, parentBean, pos);
2941:
2942: return bean;
2943: }
2944:
2945: // Moved to Util.
2946: // /** Given a node, return the nearest DesignBean that "contains" it */
2947: // public /*private*/ static DesignBean findParentBean(Node node) {
2948: // while (node != null) {
2949: //// if (node instanceof RaveElement) {
2950: //// RaveElement element = (RaveElement)node;
2951: // if (node instanceof Element) {
2952: // Element element = (Element)node;
2953: //
2954: //// if (element.getDesignBean() != null) {
2955: //// return element.getDesignBean();
2956: //// }
2957: // MarkupDesignBean markupDesignBean = InSyncServiceProvider.get().getMarkupDesignBeanForElement(element);
2958: // if (markupDesignBean != null) {
2959: // return markupDesignBean;
2960: // }
2961: // }
2962: //
2963: // node = node.getParentNode();
2964: // }
2965: //
2966: // return null;
2967: // }
2968:
2969: // private static Location computeLocationForBean(DesignBean bean, int where, String facet, Point canvasPos, Dimension dropSize, FacesModel facesModel) {
2970: private static Location computeLocationForBean(DesignBean bean,
2971: int where, String facet, Point canvasPos,
2972: Dimension dropSize, JsfForm jsfForm) {
2973: if (bean == null) {
2974: throw new NullPointerException("Bean can't be null!"); // NOI18N
2975: }
2976:
2977: LocationImpl location = new LocationImpl();
2978: location.facet = facet;
2979: location.coordinates = canvasPos;
2980: // location.size = getDropSize();
2981: location.size = dropSize;
2982:
2983: if ((bean != null) && !LiveUnit.isCssPositionable(bean)) {
2984: location.coordinates = null;
2985: }
2986:
2987: DesignBean parent = null;
2988: Node under = null;
2989: Node before = null;
2990:
2991: Element element = null;
2992:
2993: if (bean != null) {
2994: element = Util.getElement(bean);
2995:
2996: // No, can still reposition these guys.
2997: //if (element == null) {
2998: // bean = null;
2999: //}
3000: location.droppeeElement = element;
3001: }
3002:
3003: //location.droppeeChosen = true;
3004: if (where == DROP_CENTER) { // child of bean
3005: parent = bean;
3006: under = element;
3007: before = null;
3008: } else if (where == DROP_ABOVE) { // before bean
3009: parent = bean.getBeanParent();
3010: before = element;
3011:
3012: if (element != null) {
3013: under = element.getParentNode();
3014: } else { // after bean
3015: under = null;
3016: }
3017: } else {
3018: parent = bean.getBeanParent();
3019: assert where == DROP_BELOW;
3020: before = null;
3021:
3022: for (int i = 0, n = parent.getChildBeanCount(); i < (n - 1); i++) {
3023: if (parent.getChildBean(i) == bean) {
3024: DesignBean next = parent.getChildBean(i + 1);
3025: Element nextElement = Util.getElement(next);
3026: before = nextElement;
3027:
3028: break;
3029: }
3030: }
3031:
3032: if (element != null) {
3033: under = element.getParentNode();
3034: } else { // after bean
3035: under = null;
3036: }
3037: }
3038:
3039: location.droppee = parent;
3040:
3041: // If default-positioning, try to place the component before the <br/>, if
3042: // the the br is the last element under the default parent.
3043: if ((under == null) && (before == null)) {
3044: if (parent == null) {
3045: // Element parentElement = facesModel.getFacesUnit().getDefaultParent().getElement();
3046: Element parentElement = jsfForm.getFacesPageUnit()
3047: .getDefaultParent().getElement();
3048: parent = MarkupUnit
3049: .getMarkupDesignBeanForElement(parentElement);
3050: }
3051: location.pos = getDefaultMarkupPositionUnderParent(parent /*, facesModel*/);
3052: } else {
3053: location.pos = new MarkupPosition(under, before);
3054: }
3055:
3056: return location;
3057: }
3058:
3059: public/*private*/static MarkupPosition getDefaultMarkupPositionUnderParent(
3060: DesignBean parent /*, FacesModel facesModel*/) {
3061: Node under = null;
3062: Node before = null;
3063: if ((parent != null) && parent instanceof MarkupDesignBean) {
3064: under = ((MarkupDesignBean) parent).getElement();
3065: }
3066:
3067: // if (under == null) {
3068: //// under = webform.getModel().getFacesUnit().getDefaultParent().getElement();
3069: // under = facesModel.getFacesUnit().getDefaultParent().getElement();
3070: // }
3071:
3072: if (under != null) {
3073: NodeList children = under.getChildNodes();
3074:
3075: if (children.getLength() > 0) {
3076: Node last = children.item(children.getLength() - 1);
3077:
3078: while (last != null) {
3079: if ((last.getNodeType() != Node.TEXT_NODE)
3080: || !JsfSupportUtilities.onlyWhitespace(last
3081: .getNodeValue())) {
3082: break;
3083: }
3084:
3085: last = last.getPreviousSibling();
3086: }
3087:
3088: if ((last != null)
3089: && (last.getNodeType() == Node.ELEMENT_NODE)
3090: && last.getNodeName().equals(HtmlTag.BR.name)) {
3091: before = last;
3092: }
3093: }
3094: }
3095:
3096: return new MarkupPosition(under, before);
3097: }
3098:
3099: // XXX Moved to JsfSupportUtilities.
3100: // /** Return true iff the string contains only whitespace */
3101: // private static boolean onlyWhitespace(String s) {
3102: //// if(DEBUG) {
3103: //// debugLog(DesignerUtils.class.getName() + ".onlyWhitespace(String)");
3104: //// }
3105: // if(s == null) {
3106: // return true;
3107: // }
3108: // int n = s.length();
3109: //
3110: // for (int i = 0; i < n; i++) {
3111: // char c = s.charAt(i);
3112: //
3113: // /* See the "empty-cells" documentation in CSS2.1 for example:
3114: // * it sounds like only SOME of the whitespace characters are
3115: // * truly considered ignorable whitespace: \r, \n, \t, and space.
3116: // * So do something more clever in some of these cases.
3117: // */
3118: // if (!Character.isWhitespace(c)) {
3119: // return false;
3120: // }
3121: // }
3122: //
3123: // return true;
3124: // }
3125:
3126: /** Return the relative path of the given GenericItem to the page folder */
3127: private static String getPageRelativePath(Project project,
3128: FileObject fo) {
3129: FileObject webroot;
3130: webroot = JsfProjectUtils.getDocumentRoot(project);
3131:
3132: String rootName = webroot.getPath();
3133: String fileName = fo.getPath();
3134:
3135: if (fileName.startsWith(rootName)) {
3136: return fileName.substring(rootName.length());
3137: }
3138:
3139: return null;
3140: }
3141:
3142: /** Return true if the extension indicates that this is an image */
3143: public static boolean isImage(String extension) {
3144: return (extension.equalsIgnoreCase("jpg") || // NOI18N
3145: extension.equalsIgnoreCase("gif") || // NOI18N
3146: extension.equalsIgnoreCase("png") || // NOI18N
3147: extension.equalsIgnoreCase("jpeg")); // NOI18N
3148: }
3149:
3150: public static boolean isStylesheet(String extension) {
3151: return extension.equalsIgnoreCase("css"); // NOI18N
3152: }
3153:
3154: /** Tries to extract files from the string. Only if all tokens
3155: * (delimited by the default delimiter except the space char) mean file, otherwise null is returned.
3156: * @return Array of files or <code>null</code> */
3157: private static File[] extractFilesFromString(String string) {
3158: List<File> files = new ArrayList<File>();
3159: // XXX Do not use space as delimiter (the file name might contain it).
3160: StringTokenizer st = new StringTokenizer(string, "\t\n\r\f"); // NOI18N
3161: while (st.hasMoreTokens()) {
3162: String s = st.nextToken();
3163: File file = extractFileFromString(s);
3164: if (file == null) {
3165: // All tokens have to be files, otherwise don't extract any.
3166: return null;
3167: }
3168: files.add(file);
3169: }
3170: return files.toArray(new File[files.size()]);
3171: }
3172:
3173: private static File extractFileFromString(String string) {
3174: // We don't know if the String passed in to us represents
3175: // an actual String, or a pointer to an actual file
3176: // on disk. (For example, some operating systems where you
3177: // drag an image file from the desktop and drop it on Creator
3178: // will pass in e.g. "file:/users/home/image.gif".
3179: // In this case we should detect that we're really dealing
3180: // with a path, not a literal String.
3181: // To do that, we do an -experimental- URL parse, and if
3182: // it suceeds, we assume we're dealing with a path, otherwise
3183: // it's a plain string.
3184: try {
3185: // Try to construct a URL; if it's a url do a file
3186: // import of that file
3187: String urlString = string.trim();
3188: URL url = new URL(urlString);
3189: urlString = url.toExternalForm();
3190:
3191: // looks like an okay url
3192: if (url.getProtocol().equals("file")) { // NOI18N
3193:
3194: // <markup_separation>
3195: // String filename = MarkupUnit.fromURL(urlString);
3196: // ====
3197: String filename = InSyncServiceProvider.get().fromURL(
3198: urlString);
3199: // </markup_separation>
3200:
3201: if (filename != urlString) {
3202: File file = new File(filename);
3203:
3204: if (file.exists()) {
3205: return file;
3206: }
3207:
3208: // fall through for normal string handling
3209: }
3210: }
3211: } catch (MalformedURLException mue) {
3212: // It's just normal text; fall through
3213: // NOTE: This is not an error condition!! We don't know that
3214: // the string reprents a URL - it was just a hypothesis we're
3215: // testing! When this fails we know that the hypothesis
3216: // was wrong.
3217: }
3218:
3219: return null;
3220: }
3221:
3222: // Moved to Util.
3223: // /** Strip the given string to the given maximum length of
3224: // * characters. If the string is not that long, just return
3225: // * it. If it needs to be truncated, truncate it and append
3226: // * "...". maxLength must be at least 4. */
3227: // public static String truncateString(String s, int maxLength) {
3228: // assert maxLength >= 4;
3229: //
3230: //// if(DEBUG) {
3231: //// debugLog(DesignerUtils.class.getName() + ".truncateString(String, int)");
3232: //// }
3233: // if(s == null) {
3234: // throw(new IllegalArgumentException("Null string to truncate."));// NOI18N
3235: // }
3236: //
3237: // if (s.length() > maxLength) {
3238: // // Should "..." be localizable?
3239: // return s.substring(0, maxLength - 3) + "...";
3240: // } else {
3241: // return s;
3242: // }
3243: // }
3244:
3245: // Moved to Util.
3246: // /**
3247: // * Return the element for the live bean. May be null, for non faces beans for example.
3248: // */
3249: // private static Element getElement(DesignBean lb) {
3250: // if (lb instanceof MarkupDesignBean) {
3251: // return ((MarkupDesignBean)lb).getElement();
3252: // } else {
3253: // return null;
3254: // }
3255: // }
3256:
3257: // Moved to Util.
3258: // /**
3259: // * Find the nearest DesignBean container that allows html children.
3260: // * This will typically be the parent you pass in, but if there
3261: // * are any beans up in the hierarchy that renders their own
3262: // * children, then the outermost such parent's parent will be used,
3263: // * since "renders children" jsf components cannot contain markup.
3264: // */
3265: // public static DesignBean findHtmlContainer(DesignBean parent) {
3266: // DesignBean curr = parent;
3267: //
3268: // for (; curr != null; curr = curr.getBeanParent()) {
3269: // if (curr.getInstance() instanceof F_Verbatim) {
3270: // // If you have a verbatim, we're okay to add html comps below it
3271: // return parent;
3272: // }
3273: //
3274: // if (curr.getInstance() instanceof UIComponent) {
3275: // // XXX Maybe now, whitin insync one could provide a better check for the classloader.
3276: //
3277: // // Need to set the Thread's context classloader to be the Project's ClassLoader.
3278: // ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
3279: // try {
3280: // Thread.currentThread().setContextClassLoader(InSyncServiceProvider.get().getContextClassLoader(curr));
3281: // if (((UIComponent)curr.getInstance()).getRendersChildren()) {
3282: // parent = curr.getBeanParent();
3283: //
3284: // // Can't break here - there could be an outer
3285: // // renders-children parent
3286: // }
3287: // } finally {
3288: // Thread.currentThread().setContextClassLoader(oldContextClassLoader);
3289: // }
3290: // }
3291: // }
3292: //
3293: // return parent;
3294: // }
3295:
3296: // Moved to Util.
3297: // /**
3298: // * Given an element which possibly maps to a markup bean, return the corresponding bean.
3299: // */
3300: // private static MarkupBean getMarkupBean(FacesModel model, Element elem) {
3301: //// FacesModel model = doc.getWebForm().getModel();
3302: //
3303: // if (model == null) { // testsuite
3304: //
3305: // return null;
3306: // }
3307: //
3308: // FacesPageUnit facesunit = model.getFacesUnit();
3309: // MarkupBean bean = null;
3310: //
3311: // if (facesunit != null) {
3312: // bean = facesunit.getMarkupBean(elem);
3313: //
3314: // // Find component for this element:
3315: // }
3316: //
3317: // return bean;
3318: // }
3319:
3320: /** Paste the beans in the given transferable to the given parent
3321: * and markup position.
3322: */
3323: public/*static*/DesignBean[] pasteBeans(
3324: /*WebForm webform,*/Transferable t, DesignBean parent,
3325: MarkupPosition pos, Point location, /*CoordinateTranslator coordinateTranslator,*/
3326: UpdateSuspender updateSuspender) {
3327: // Make sure we're allowed to paste to the given parent.
3328: // Arguably, I should not be enabling the paste action when the selected parent
3329: // is "selected", but the parent used is computed very dynamically, so
3330: // doing something like this would require recomputing the Paste state
3331: // every pixel the mouse moves over the designer canvas. Instead we try
3332: // to move the parent up until we find a suitable parent.
3333: while (parent != null) {
3334: // DndHandler dndHandler = webform.getPane().getDndHandler();
3335: int allowed = computeActions(parent, t, false, DROP_CENTER);
3336:
3337: if ((allowed & DnDConstants.ACTION_COPY_OR_MOVE) != 0) {
3338: break;
3339: }
3340:
3341: parent = parent.getBeanParent();
3342: pos = null; // no longer valid - just use insync defaults
3343: }
3344:
3345: if (parent == null) {
3346: // XXX #110353 There is no rendered component corresponding to the fragment root?!
3347: // Hacking the problem here so it works like before.
3348: LiveUnit liveUnit = jsfForm.getLiveUnit();
3349: FacesPageUnit facesPageUnit = jsfForm.getFacesPageUnit();
3350: parent = liveUnit == null || facesPageUnit == null ? null
3351: : liveUnit.getDesignBean(facesPageUnit
3352: .getDefaultParent());
3353:
3354: if (parent == null) {
3355: // No valid parent found.
3356: Toolkit.getDefaultToolkit().beep();
3357: return null;
3358: }
3359: }
3360:
3361: // Document document = null;
3362:
3363: //LiveUnit unit = (LiveUnit)parent.getDesignContext();
3364: // LiveUnit unit = facesModel.getLiveUnit();
3365: LiveUnit unit = jsfForm.getLiveUnit();
3366:
3367: String description = NbBundle.getMessage(FacesDndSupport.class,
3368: "LBL_Paste"); // NOI18N
3369: // UndoEvent undoEvent = facesModel.writeLock(description);
3370: UndoEvent undoEvent = jsfForm.writeLock(description);
3371: try {
3372: // document = webform.getDocument();
3373: //
3374: // //document.setAutoIgnore(true);
3375: // String description = NbBundle.getMessage(SelectionTopComp.class, "Paste"); // NOI18N
3376: // document.writeLock(description);
3377:
3378: DesignBean[] beans = unit.pasteBeans(t, parent, pos);
3379:
3380: if (beans == null) {
3381: return null;
3382: }
3383:
3384: // Decide whether we need to strip out position coordinates
3385: // from the beans being moved
3386: boolean needPos = true;
3387:
3388: if (parent != null) {
3389: needPos = isGridContext(parent, pos);
3390:
3391: if (!needPos) {
3392: location = null;
3393: }
3394: }
3395:
3396: // Determine if the destination is a grid area
3397: if (location != null) {
3398: // // Snap
3399: // GridHandler gh = GridHandler.getInstance();
3400: //
3401: // if (gh.snap()) {
3402: // // TODO - compute the right target box here
3403: //// CssBox gridBox = null;
3404: // location.x = gh.snapX(location.x, null);
3405: // location.y = gh.snapY(location.y, null);
3406: // }
3407: // The location was snapped before.
3408: // if (coordinateTranslator != null) {
3409: // location.x = coordinateTranslator.snapX(location.x);
3410: // location.y = coordinateTranslator.snapY(location.y);
3411: // }
3412:
3413: // Position elements
3414: Point topLeft = getTopLeft(beans);
3415:
3416: for (int i = 0; i < beans.length; i++) {
3417: if (!(beans[i] instanceof MarkupDesignBean)) {
3418: continue;
3419: }
3420:
3421: MarkupDesignBean bean = (MarkupDesignBean) beans[i];
3422:
3423: // XXX I need to do this on the -rendered- element!
3424: Element element = bean.getElement();
3425: assert element != null;
3426:
3427: try {
3428: // webform.getDomSynchronizer().setUpdatesSuspended(bean, true);
3429: // webform.setUpdatesSuspended(bean, true);
3430: if (updateSuspender != null) {
3431: updateSuspender.setSuspended(bean, true);
3432: }
3433:
3434: if (!needPos) {
3435: // XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
3436: List<StyleData> remove = new ArrayList<StyleData>(
3437: 5);
3438: remove.add(new StyleData(
3439: XhtmlCss.POSITION_INDEX));
3440: remove.add(new StyleData(
3441: XhtmlCss.LEFT_INDEX));
3442: remove
3443: .add(new StyleData(
3444: XhtmlCss.TOP_INDEX));
3445: remove.add(new StyleData(
3446: XhtmlCss.RIGHT_INDEX));
3447: remove.add(new StyleData(
3448: XhtmlCss.BOTTOM_INDEX));
3449: // <removing design bean manipulation in engine>
3450: // engine.updateLocalStyleValues((RaveElement)element, null, remove);
3451: // ====
3452: Util.updateLocalStyleValuesForElement(
3453: element, null,
3454: remove.toArray(new StyleData[remove
3455: .size()]));
3456: // </removing design bean manipulation in engine>
3457:
3458: continue;
3459: }
3460:
3461: List<StyleData> set = new ArrayList<StyleData>(
3462: 5);
3463: List<StyleData> remove = new ArrayList<StyleData>(
3464: 5);
3465: // Value val = CssLookup.getValue(element, XhtmlCss.POSITION_INDEX);
3466: CssValue cssValue = CssProvider
3467: .getEngineService()
3468: .getComputedValueForElement(element,
3469: XhtmlCss.POSITION_INDEX);
3470:
3471: // if ((val == CssValueConstants.ABSOLUTE_VALUE) ||
3472: // (val == CssValueConstants.RELATIVE_VALUE) ||
3473: // (val == CssValueConstants.FIXED_VALUE)) {
3474: if (CssProvider.getValueService()
3475: .isAbsoluteValue(cssValue)
3476: || CssProvider.getValueService()
3477: .isRelativeValue(cssValue)
3478: || CssProvider.getValueService()
3479: .isFixedValue(cssValue)) {
3480: // int top = CssLookup.getLength(element, XhtmlCss.TOP_INDEX);
3481: // int left = CssLookup.getLength(element, XhtmlCss.LEFT_INDEX);
3482: int top = CssProvider.getValueService()
3483: .getCssLength(element,
3484: XhtmlCss.TOP_INDEX);
3485: int left = CssProvider.getValueService()
3486: .getCssLength(element,
3487: XhtmlCss.LEFT_INDEX);
3488:
3489: if ((top != CssValue.AUTO)
3490: || (left != CssValue.AUTO)) {
3491: if (left == CssValue.AUTO) {
3492: left = 0;
3493: }
3494:
3495: if (top == CssValue.AUTO) {
3496: top = 0;
3497: }
3498:
3499: left = (location.x + left) - topLeft.x;
3500: top = (location.y + top) - topLeft.y;
3501:
3502: set.add(new StyleData(
3503: XhtmlCss.TOP_INDEX, Integer
3504: .toString(top)
3505: + "px")); // NOI18N
3506: set.add(new StyleData(
3507: XhtmlCss.LEFT_INDEX, Integer
3508: .toString(left)
3509: + "px")); // NOI18N
3510: } else {
3511: set.add(new StyleData(
3512: XhtmlCss.LEFT_INDEX, Integer
3513: .toString(location.x)
3514: + "px")); // NOI18N
3515: set.add(new StyleData(
3516: XhtmlCss.TOP_INDEX, Integer
3517: .toString(location.y)
3518: + "px")); // NOI18N
3519: }
3520: } else {
3521: set.add(new StyleData(
3522: XhtmlCss.POSITION_INDEX,
3523: // CssConstants.CSS_ABSOLUTE_VALUE)); // NOI18N
3524: CssProvider.getValueService()
3525: .getAbsoluteValue()));
3526: set
3527: .add(new StyleData(
3528: XhtmlCss.LEFT_INDEX,
3529: Integer
3530: .toString(location.x)
3531: + "px")); // NOI18N
3532: set
3533: .add(new StyleData(
3534: XhtmlCss.TOP_INDEX,
3535: Integer
3536: .toString(location.y)
3537: + "px")); // NOI18N
3538: }
3539:
3540: remove.add(new StyleData(XhtmlCss.RIGHT_INDEX));
3541: remove
3542: .add(new StyleData(
3543: XhtmlCss.BOTTOM_INDEX));
3544:
3545: // XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
3546: // <removing design bean manipulation in engine>
3547: // engine.updateLocalStyleValues((RaveElement)element, set, remove);
3548: // ====
3549: Util.updateLocalStyleValuesForElement(element,
3550: set.toArray(new StyleData[set.size()]),
3551: remove.toArray(new StyleData[remove
3552: .size()]));
3553: // </removing design bean manipulation in engine>
3554: } finally {
3555: // webform.getDomSynchronizer().setUpdatesSuspended(bean, false);
3556: // webform.setUpdatesSuspended(bean, false);
3557: if (updateSuspender != null) {
3558: updateSuspender.setSuspended(bean, false);
3559: }
3560: }
3561: }
3562: } else if (needPos) {
3563: // We're over a grid area but don't have a specified position;
3564: // leave existing positions in the pasted components alone
3565: // but don't create new positions to assign to other components.
3566: // This means that if you cut a component and then paste it
3567: // it will appear in the place it was before cutting it.
3568: } else {
3569: // Flow area: remove absolute positions for all children
3570: for (int i = 0; i < beans.length; i++) {
3571: if (!(beans[i] instanceof MarkupDesignBean)) {
3572: // Not a visual component
3573: continue;
3574: }
3575:
3576: MarkupDesignBean bean = (MarkupDesignBean) beans[i];
3577: Element element = bean.getElement();
3578:
3579: try {
3580: // webform.getDomSynchronizer().setUpdatesSuspended(bean, true);
3581: // webform.setUpdatesSuspended(bean, true);
3582: if (updateSuspender != null) {
3583: updateSuspender.setSuspended(bean, true);
3584: }
3585:
3586: // CssLookup.removeLocalStyleValue(element, XhtmlCss.POSITION_INDEX);
3587: // CssLookup.removeLocalStyleValue(element, XhtmlCss.LEFT_INDEX);
3588: // CssLookup.removeLocalStyleValue(element, XhtmlCss.TOP_INDEX);
3589: Util.removeLocalStyleValueForElement(element,
3590: XhtmlCss.POSITION_INDEX);
3591: Util.removeLocalStyleValueForElement(element,
3592: XhtmlCss.LEFT_INDEX);
3593: Util.removeLocalStyleValueForElement(element,
3594: XhtmlCss.TOP_INDEX);
3595: } finally {
3596: // webform.getDomSynchronizer().setUpdatesSuspended(bean, false);
3597: // webform.setUpdatesSuspended(bean, false);
3598: if (updateSuspender != null) {
3599: updateSuspender.setSuspended(bean, false);
3600: }
3601: }
3602: }
3603: }
3604:
3605: return beans;
3606: } finally {
3607: // document.writeUnlock();
3608: // facesModel.writeUnlock(undoEvent);
3609: jsfForm.writeUnlock(undoEvent);
3610: }
3611: }
3612:
3613: /** Compute the leftmost and topmost positions among the given beans
3614: */
3615: private static Point getTopLeft(DesignBean[] beans) {
3616: int minLeft = Integer.MAX_VALUE;
3617: int minTop = Integer.MAX_VALUE;
3618:
3619: for (int i = 0; i < beans.length; i++) {
3620: Element element = Util.getElement(beans[i]);
3621:
3622: if (element == null) {
3623: // Not a visual component
3624: continue;
3625: }
3626:
3627: // Value val = CssLookup.getValue(element, XhtmlCss.POSITION_INDEX);
3628: CssValue cssValue = CssProvider.getEngineService()
3629: .getComputedValueForElement(element,
3630: XhtmlCss.POSITION_INDEX);
3631:
3632: // if ((val == CssValueConstants.ABSOLUTE_VALUE) ||
3633: // (val == CssValueConstants.RELATIVE_VALUE) ||
3634: // (val == CssValueConstants.FIXED_VALUE)) {
3635: if (CssProvider.getValueService().isAbsoluteValue(cssValue)
3636: || CssProvider.getValueService().isRelativeValue(
3637: cssValue)
3638: || CssProvider.getValueService().isFixedValue(
3639: cssValue)) {
3640: // int top = CssLookup.getLength(element, XhtmlCss.TOP_INDEX);
3641: // int left = CssLookup.getLength(element, XhtmlCss.LEFT_INDEX);
3642: int top = CssProvider.getValueService().getCssLength(
3643: element, XhtmlCss.TOP_INDEX);
3644: int left = CssProvider.getValueService().getCssLength(
3645: element, XhtmlCss.LEFT_INDEX);
3646:
3647: if ((top != CssValue.AUTO) || (left != CssValue.AUTO)) {
3648: if (left == CssValue.AUTO) {
3649: left = 0;
3650: }
3651:
3652: if (top == CssValue.AUTO) {
3653: top = 0;
3654: }
3655:
3656: if (top < minTop) {
3657: minTop = top;
3658: }
3659:
3660: if (left < minLeft) {
3661: minLeft = left;
3662: }
3663: }
3664: }
3665: }
3666:
3667: return new Point(minLeft, minTop);
3668: }
3669:
3670: /**
3671: * Report whether the given position is in grid context
3672: */
3673: private static boolean isGridContext(DesignBean parent,
3674: MarkupPosition pos) {
3675: if (parent.getInstance() instanceof javax.faces.component.UIForm
3676: || parent.getInstance() instanceof org.netbeans.modules.visualweb.xhtml.Form) {
3677: // Look at its parent
3678: parent = parent.getBeanParent();
3679:
3680: if (parent == null) {
3681: return false;
3682: }
3683: }
3684:
3685: Element element = Util.getElement(parent);
3686:
3687: if (element == null) {
3688: return false;
3689: }
3690:
3691: // Value val = CssLookup.getValue(element, XhtmlCss.RAVELAYOUT_INDEX);
3692: CssValue cssValue = CssProvider.getEngineService()
3693: .getComputedValueForElement(element,
3694: XhtmlCss.RAVELAYOUT_INDEX);
3695:
3696: // return val == CssValueConstants.GRID_VALUE;
3697: return CssProvider.getValueService().isGridValue(cssValue);
3698: }
3699:
3700: // /** XXX Provides the auto value as <code>AUTO</code>, revise that, it looks very dangerous. */
3701: // private static int getCssLength(Element element, int property) {
3702: //// Value val = getValue(element, property);
3703: // CssValue cssValue = CssProvider.getEngineService().getComputedValueForElement(element, property);
3704: //// if (val == CssValueConstants.AUTO_VALUE) {
3705: // if (CssProvider.getValueService().isAutoValue(cssValue)) {
3706: // return CSS_AUTO;
3707: // }
3708: //
3709: //// return (int)val.getFloatValue();
3710: // return (int)cssValue.getFloatValue();
3711: // }
3712:
3713: // Moved to Util.
3714: // /**
3715: // * Return true iff the given DesignBean is the form bean for this form OR THE LIVE BEAN CONTAINER,
3716: // * since it acts like the form bean in many ways (not draggable, not deletable, etc.)
3717: // */
3718: // private static boolean isFormBean(FacesModel facesModel, DesignBean bean) {
3719: //// FacesModel model = webform.getModel();
3720: //
3721: // if (bean == facesModel.getRootBean()) {
3722: // return true;
3723: // }
3724: //
3725: // FacesPageUnit facesUnit = facesModel.getFacesUnit();
3726: // MarkupBean formBean = facesUnit.getDefaultParent();
3727: //
3728: // return getFacesBean(bean) == formBean;
3729: // }
3730: //
3731: // /**
3732: // * Return the FacesBean for the live bean. May be null, for non faces live beans.
3733: // *
3734: // * @param lb The live bean to get the faces bean for. May be null.
3735: // * @return the FacesBean corresponding to the live bean, or null.
3736: // */
3737: // private static FacesBean getFacesBean(DesignBean lb) {
3738: // if (!(lb instanceof BeansDesignBean)) {
3739: // return null;
3740: // }
3741: //
3742: // Bean b = ((BeansDesignBean)lb).getBean();
3743: //
3744: // if (b instanceof FacesBean) {
3745: // return (FacesBean)b;
3746: // }
3747: //
3748: // return null;
3749: // }
3750:
3751: // Moved to Util.
3752: // /**
3753: // * Return true iff the given DesignBean is the body bean, or the form bean, OR THE LIVE BEAN
3754: // * CONTAINER. These beans have special behavior since they are not draggable, not deletable,
3755: // * etc.
3756: // * TODO Move this into insync.
3757: // * @todo Prevent deletion of f:subview in page fragments!
3758: // */
3759: // public static boolean isSpecialBean(/*WebForm webform,*/ DesignBean bean) {
3760: //// FacesModel model = webform.getModel();
3761: // if (bean == null) {
3762: // // XXX Log NPE?
3763: // return false;
3764: // }
3765: // DesignContext context = bean.getDesignContext();
3766: // // XXX Casting is error-prone.
3767: // FacesModel model = ((LiveUnit)context).getModel();
3768: //
3769: // if (bean == model.getRootBean()) {
3770: // return true;
3771: // }
3772: //
3773: // FacesPageUnit facesUnit = model.getFacesUnit();
3774: //
3775: // if (facesUnit != null) {
3776: // MarkupBean formBean = facesUnit.getDefaultParent();
3777: // MarkupBean markup = getMarkupBean(bean);
3778: //
3779: // if (markup == null) {
3780: // return false;
3781: // }
3782: //
3783: // if (markup == formBean) {
3784: // return true;
3785: // }
3786: //
3787: //// RaveElement e = (RaveElement)markup.getElement();
3788: //// if (e.getRendered() != null) {
3789: //// e = (RaveElement)e.getRendered();
3790: // Element e = markup.getElement();
3791: // Element rendered = MarkupService.getRenderedElementForElement(e);
3792: // if (rendered != null) {
3793: // e = rendered;
3794: //
3795: // // Anything from the body or up is special -- cannot be removed
3796: //// Node curr = webform.getBody();
3797: // Node curr = InSyncServiceProvider.get().getHtmlBodyForMarkupFile(model.getMarkupFile());
3798: //
3799: // while (curr != null) {
3800: // if (curr == e) {
3801: // return true;
3802: // }
3803: //
3804: // curr = curr.getParentNode();
3805: // }
3806: // } else {
3807: // // Anything from the body or up is special -- cannot be removed
3808: //// Node curr = webform.getBody().getSource();
3809: // Element body = InSyncServiceProvider.get().getHtmlBodyForMarkupFile(model.getMarkupFile());
3810: // Node curr = MarkupService.getSourceElementForElement(body);
3811: //
3812: // while (curr != null) {
3813: // if (curr == e) {
3814: // return true;
3815: // }
3816: //
3817: // curr = curr.getParentNode();
3818: // }
3819: // }
3820: // }
3821: //
3822: // return false;
3823: // }
3824:
3825: // Moved to Util.
3826: // /**
3827: // * Return the MarkupBean for the live bean. May be null, for non markup live beans.
3828: // *
3829: // * @param lb The live bean to get the faces bean for. May be null.
3830: // * @return the MarkupBean corresponding to the live bean, or null.
3831: // */
3832: // public static MarkupBean getMarkupBean(DesignBean lb) {
3833: // if (!(lb instanceof BeansDesignBean)) {
3834: // return null;
3835: // }
3836: //
3837: // Bean b = ((BeansDesignBean)lb).getBean();
3838: //
3839: // if (b instanceof MarkupBean) {
3840: // return (MarkupBean)b;
3841: // }
3842: //
3843: // return null;
3844: // }
3845:
3846: /**
3847: * Return the parent element of the given element. Takes DocumentFragments
3848: * etc. into consideration. Returns null when there is no such parent.
3849: */
3850: private static Element getParent(Element element) {
3851: // if (element.getStyleParent() != null) {
3852: // return (RaveElement)element.getStyleParent();
3853: // if (element instanceof CSSEngine.StyleElementLink
3854: // && ((CSSEngine.StyleElementLink)element).getStyleParent() != null) {
3855: // return (RaveElement)((CSSEngine.StyleElementLink)element).getStyleParent();
3856: Element styleParent = CssProvider.getEngineService()
3857: .getStyleParentForElement(element);
3858: if (styleParent != null) {
3859: return styleParent;
3860: } else if ((element.getParentNode() != null)
3861: && (element.getParentNode().getNodeType() == Node.ELEMENT_NODE)) {
3862: return (Element) element.getParentNode();
3863: } else {
3864: return null;
3865: }
3866: }
3867:
3868: private/*public*/static Location computeLocationForPositions(
3869: String facet, Point canvasPos, Node documentPosNode,
3870: int documentPosOffset, Dimension dropSize, boolean isGrid,
3871: Element droppeeElement, DesignBean droppeeBean, /*WebForm webform*/
3872: DesignBean defaultParentBean) {
3873: LocationImpl location = new LocationImpl();
3874: location.facet = facet;
3875: location.coordinates = canvasPos;
3876: // location.size = getDropSize();
3877: location.size = dropSize;
3878:
3879: DesignBean parent = null;
3880: Node under = null;
3881: Node before = null;
3882:
3883: Element element = null;
3884:
3885: if (documentPosNode != null) {
3886: // XXX TODO: split text nodes!
3887: if (documentPosNode instanceof Text) {
3888: if (documentPosOffset == 0) {
3889: before = documentPosNode;
3890: under = before.getParentNode();
3891: } else {
3892: Text txt = (Text) documentPosNode;
3893:
3894: if (documentPosOffset < txt.getLength()) {
3895: before = txt.splitText(documentPosOffset);
3896: under = before.getParentNode();
3897: } else {
3898: before = txt.getNextSibling();
3899: under = txt.getParentNode();
3900: }
3901: }
3902: } else {
3903: int offset = documentPosOffset;
3904:
3905: if (offset < documentPosNode.getChildNodes()
3906: .getLength()) {
3907: under = documentPosNode;
3908: before = under.getChildNodes().item(offset);
3909: } else {
3910: // Just append - but we don't have an api for that (can only set "before")
3911: // so create a new blank text node as a hook
3912: // XXX should I really mutate the document here?
3913: // That doesn't sound right...
3914: under = documentPosNode;
3915:
3916: // XXX Manipulation of the doc may not be done here.
3917: // Text txt = webform.getJspDom().createTextNode(" "); // NOI18N
3918: Text txt = under.getOwnerDocument().createTextNode(
3919: " "); // NOI18N
3920: under.appendChild(txt);
3921: before = txt;
3922: }
3923: }
3924:
3925: if (parent == null) {
3926: Node n = under;
3927:
3928: // while (n instanceof RaveElement) {
3929: // RaveElement xel = (RaveElement)n;
3930: while (n instanceof Element) {
3931: Element xel = (Element) n;
3932:
3933: // if (xel.getDesignBean() != null) {
3934: // DesignBean lbean = (DesignBean)xel.getDesignBean();
3935: // DesignBean lbean = InSyncService.getProvider().getMarkupDesignBeanForElement(xel);
3936: DesignBean lbean = MarkupUnit
3937: .getMarkupDesignBeanForElement(xel);
3938: if (lbean != null) {
3939: if (lbean.isContainer()) {
3940: parent = lbean;
3941:
3942: break;
3943: }
3944: }
3945:
3946: n = n.getParentNode();
3947: }
3948: }
3949:
3950: //!CQ: facesUnit.setInsertBefore(before);
3951: // determine the integer offset of the before node within its parent
3952: if ((under != null)
3953: && (under.getNodeType() == Node.ELEMENT_NODE)) {
3954: location.droppeeElement = (Element) under;
3955: }
3956: } else if (canvasPos != null) {
3957: // What position should we assign here??? For now, nothing.
3958: // Let insync pick a position. The exact location in the source
3959: // where the tag is inserted isn't very important since we're
3960: // absolute positioning anyway.
3961: under = null;
3962: before = null;
3963:
3964: // CssBox box = webform.getMapper().findBox(canvasPos.x, canvasPos.y);
3965: // CssBox box = ModelViewMapper.findBox(webform.getPane().getPageBox(), canvasPos.x, canvasPos.y);
3966: //
3967: // // In flow mode, don't do absolute positioning, ever, unless we're in
3968: // // a grid positioning area
3969: // if (!webform.isGridMode() && ((box == null) || !box.isGrid())) {
3970: // location.coordinates = null;
3971: // }
3972: //
3973: // location.droppeeElement = box.getElement();
3974: // parent = getDroppee(box);
3975: if (!isGrid) {
3976: location.coordinates = null;
3977: }
3978: location.droppeeElement = droppeeElement;
3979: parent = droppeeBean;
3980: }
3981:
3982: // else {
3983: // // No position specified. In this case send just nulls
3984: // // to insync and let insync figure it out. It will insert
3985: // // the component most likely as a child of the form component.
3986: // }
3987:
3988: location.droppee = parent;
3989:
3990: // If default-positioning, try to place the component before the <br/>, if
3991: // the the br is the last element under the default parent.
3992: if ((under == null) && (before == null)) {
3993: if (parent == null) {
3994: // parent = webform.getDefaultParentBean();
3995: parent = defaultParentBean;
3996: }
3997: location.pos = getDefaultMarkupPositionUnderParent(parent/*, webform*/);
3998: } else {
3999: location.pos = new MarkupPosition(under, before);
4000: }
4001:
4002: return location;
4003:
4004: }
4005:
4006: public void importString(Designer designer, String string,
4007: Point canvasPos, Node documentPosNode,
4008: int documentPosOffset, Dimension dropSize, boolean isGrid,
4009: Element droppeeElement, DesignBean droppeeBean,
4010: DesignBean defaultParent, /*CoordinateTranslator coordinateTranslator,*/
4011: UpdateSuspender updateSuspender) {
4012: Location location = computeLocationForPositions(null,
4013: canvasPos, documentPosNode, documentPosOffset,
4014: dropSize, isGrid, droppeeElement, droppeeBean,
4015: defaultParent);
4016: importString(designer, string, location, /*coordinateTranslator,*/
4017: updateSuspender);
4018: }
4019:
4020: public boolean importData(Designer designer, JComponent comp,
4021: Transferable t, /*Object transferData,*/Point canvasPos,
4022: Node documentPosNode, int documentPosOffset,
4023: Dimension dropSize, boolean isGrid, Element droppeeElement,
4024: DesignBean droppeeBean, DesignBean defaultParent, /*CoordinateTranslator coordinateTranslator,*/
4025: UpdateSuspender updateSuspender, int dropAction) {
4026: Location location = computeLocationForPositions(null,
4027: canvasPos, documentPosNode, documentPosOffset,
4028: dropSize, isGrid, droppeeElement, droppeeBean,
4029: defaultParent);
4030: return importData(designer, comp, t, /*transferData,*/
4031: dropSize, location, /*coordinateTranslator,*/
4032: updateSuspender, dropAction);
4033: }
4034:
4035: private static boolean isValidTransferData(Transferable t,
4036: Object transferData) {
4037: DataFlavor importFlavor = getImportFlavor(t
4038: .getTransferDataFlavors());
4039: if (importFlavor == null) {
4040: ErrorManager
4041: .getDefault()
4042: .notify(
4043: ErrorManager.INFORMATIONAL,
4044: new IllegalStateException(
4045: "Unusable transfer flavors "
4046: + Arrays
4047: .asList(t
4048: .getTransferDataFlavors()))); // NOI18N
4049:
4050: return false;
4051: }
4052:
4053: Class<?> rc = importFlavor.getRepresentationClass();
4054: try {
4055: if (rc == DisplayItem.class) {
4056: // Create a new type
4057: transferData = t.getTransferData(importFlavor);
4058:
4059: if (!(transferData instanceof DisplayItem)) {
4060: ErrorManager.getDefault().notify(
4061: ErrorManager.INFORMATIONAL,
4062: new IllegalStateException(
4063: "Invalid transfer data="
4064: + transferData));
4065:
4066: return false;
4067: }
4068: } else if (rc == DesignBean.class) {
4069: transferData = t.getTransferData(importFlavor);
4070:
4071: if (!(transferData instanceof DesignBean[])) {
4072: ErrorManager.getDefault().notify(
4073: ErrorManager.INFORMATIONAL,
4074: new IllegalStateException(
4075: "Invalid transfer data="
4076: + transferData));
4077:
4078: return false;
4079: }
4080: } else if (rc.isAssignableFrom(List.class)) {
4081: transferData = t.getTransferData(importFlavor);
4082:
4083: if (!(transferData instanceof List)) {
4084: ErrorManager.getDefault().notify(
4085: ErrorManager.INFORMATIONAL,
4086: new IllegalStateException(
4087: "Invalid transfer data="
4088: + transferData));
4089:
4090: return false;
4091: }
4092: } else if (rc
4093: .isAssignableFrom(org.openide.nodes.Node.class)) {
4094: transferData = t.getTransferData(importFlavor);
4095:
4096: if (!(transferData instanceof org.openide.nodes.Node)) {
4097: ErrorManager.getDefault().notify(
4098: ErrorManager.INFORMATIONAL,
4099: new IllegalStateException(
4100: "Invalid transfer data="
4101: + transferData));
4102:
4103: return false;
4104: }
4105: }
4106: } catch (UnsupportedFlavorException ex) {
4107: ErrorManager.getDefault().notify(
4108: ErrorManager.INFORMATIONAL, ex);
4109: return false;
4110: } catch (IOException ex) {
4111: ErrorManager.getDefault().notify(
4112: ErrorManager.INFORMATIONAL, ex);
4113: return false;
4114: }
4115:
4116: return true;
4117: }
4118:
4119: public interface Location {
4120: public DesignBean getDroppee();
4121:
4122: public String getFacet();
4123:
4124: public Element getDroppeeElement();
4125:
4126: public MarkupPosition getPos();
4127:
4128: public Point getCoordinates();
4129:
4130: public Dimension getSize();
4131: } // End of Location.
4132:
4133: private static class LocationImpl implements Location {
4134: private DesignBean droppee;
4135: private String facet;
4136: private Element droppeeElement;
4137: private MarkupPosition pos;
4138: private Point coordinates;
4139: private Dimension size;
4140:
4141: public LocationImpl() {
4142: }
4143:
4144: public LocationImpl(Location location) {
4145: this .droppee = location.getDroppee();
4146: this .facet = location.getFacet();
4147: this .droppeeElement = location.getDroppeeElement();
4148: this .pos = location.getPos();
4149: this .coordinates = location.getCoordinates();
4150: this .size = location.getSize();
4151: }
4152:
4153: public DesignBean getDroppee() {
4154: return droppee;
4155: }
4156:
4157: public String getFacet() {
4158: return facet;
4159: }
4160:
4161: public Element getDroppeeElement() {
4162: return droppeeElement;
4163: }
4164:
4165: public MarkupPosition getPos() {
4166: return pos;
4167: }
4168:
4169: public Point getCoordinates() {
4170: return coordinates;
4171: }
4172:
4173: public Dimension getSize() {
4174: return size;
4175: }
4176: } // End of LocationImpl.
4177:
4178: // public interface CoordinateTranslator {
4179: // public Point translateCoordinates(Element parent, int x, int y);
4180: // public int snapX(int x);
4181: // public int snapY(int y);
4182: // } // End of CoordinateTranslator.
4183:
4184: public interface UpdateSuspender {
4185: public void setSuspended(MarkupDesignBean markupDesignBean,
4186: boolean suspend);
4187: } // End of UpdateSuspender.
4188:
4189: public static class DropInfo {
4190: private MarkupDesignBean markupDesignBean;
4191: // private MarkupMouseRegion markupMouseRegion;
4192: private Element regionElement;
4193: private int dropType;
4194:
4195: // public DropInfo(MarkupDesignBean markupDesignBean, MarkupMouseRegion markupMouseRegion, int dropType) {
4196: public DropInfo(MarkupDesignBean markupDesignBean,
4197: Element regionElement, int dropType) {
4198: this .markupDesignBean = markupDesignBean;
4199: // this.markupMouseRegion = markupMouseRegion;
4200: this .regionElement = regionElement;
4201: this .dropType = dropType;
4202: }
4203:
4204: public MarkupDesignBean getMarkupDesignBean() {
4205: return markupDesignBean;
4206: }
4207:
4208: // public MarkupMouseRegion getMarkupMouseRegion() {
4209: // return markupMouseRegion;
4210: // }
4211: public Element getRegionElement() {
4212: return regionElement;
4213: }
4214:
4215: public int getDropType() {
4216: return dropType;
4217: }
4218: } // End of DropInfo.
4219:
4220: private boolean importComponentData(Designer designer,
4221: JComponent comp, Transferable t, Point dropPoint) {
4222: // JsfMultiViewElement jsfMultiViewElement = JsfForm.findJsfMultiViewElementForDesigner(designer);
4223: // if (jsfMultiViewElement == null) {
4224: // return false;
4225: // }
4226:
4227: JsfTopComponent jsfTopComponent;
4228:
4229: if (comp instanceof JsfTopComponent) {
4230: jsfTopComponent = (JsfTopComponent) comp;
4231: } else {
4232: jsfTopComponent = (JsfTopComponent) SwingUtilities
4233: .getAncestorOfClass(JsfTopComponent.class, comp);
4234: }
4235:
4236: if (jsfTopComponent == null) {
4237: // XXX
4238: return false;
4239: }
4240:
4241: // XXX This shouldn't be needed here again (it was already processed before - see call stack).
4242: // DesignBean parent = selectionTopComp.getPasteParent();
4243: Element parentComponentRootElement = jsfTopComponent
4244: .getPasteParentComponent();
4245: // MarkupPosition pos = selectionTopComp.getPasteMarkupPosition();
4246: // Point location = jsfTopComponent.getPastePosition();
4247: // Point location = designer.getPastePoint();
4248: Point location = dropPoint;
4249:
4250: // DesignBean[] beans = selectionTopComp.pasteBeans(webform, t, parent, pos, location);
4251: // Element[] componentRootElements = SelectionTopComp.pasteComponents(webform, t, parentComponentRootElement, location);
4252:
4253: if (location != null) {
4254: // GridHandler gridHandler = webform.getGridHandler();
4255: // location.x = gridHandler.snapX(location.x);
4256: // location.y = gridHandler.snapY(location.y);
4257: location.x = designer.snapX(location.x, null);
4258: location.y = designer.snapY(location.y, null);
4259: }
4260: // Element[] componentRootElements = webform.pasteComponents(t, parentComponentRootElement, location);
4261: // Element[] componentRootElements = pasteComponents(t, parentComponentRootElement, location, jsfForm.getUpdateSuspender());
4262: pasteComponents(jsfTopComponent, t, parentComponentRootElement,
4263: location, jsfForm.getUpdateSuspender());
4264:
4265: //// if ((beans != null) && (beans.length > 0)) {
4266: //// selectionTopComp.selectBeans(beans);
4267: //// }
4268: // if (componentRootElements.length > 0) {
4269: //// selectionTopComp.selectComponents(componentRootElements);
4270: // jsfTopComponent.selectComponents(componentRootElements);
4271: // }
4272: return true;
4273:
4274: }
4275:
4276: private/*public Element[]*/void pasteComponents(
4277: final JsfTopComponent jsfTopComponent, Transferable t,
4278: Element parentComponentRootElement, Point location,
4279: UpdateSuspender updateSuspender) {
4280: MarkupDesignBean parent = MarkupUnit
4281: .getMarkupDesignBeanForElement(parentComponentRootElement);
4282: final DesignBean[] designBeans = pasteBeans(t, parent, null,
4283: location, /*jsfForm.getUpdateSuspender()*/
4284: updateSuspender);
4285:
4286: if (designBeans == null) {
4287: // return new Element[0];
4288: return;
4289: }
4290:
4291: // XXX #105306 It needs to be invoked later (see also fireSelectedDesignBean);
4292: EventQueue.invokeLater(new Runnable() {
4293: public void run() {
4294: List<Element> elements = new ArrayList<Element>();
4295: for (DesignBean designBean : designBeans) {
4296: if (designBean instanceof MarkupDesignBean) {
4297: Element element = JsfSupportUtilities
4298: .getComponentRootElementForMarkupDesignBean((MarkupDesignBean) designBean);
4299: if (element != null) {
4300: elements.add(element);
4301: }
4302: }
4303: }
4304: if (elements.size() > 0) {
4305: jsfTopComponent.selectComponents(elements
4306: .toArray(new Element[elements.size()]));
4307: }
4308: }
4309: });
4310: // if (designBeans.length > 0) {
4311: // fireSelectedDesignBeanChanged(designBeans);
4312: // }
4313: }
4314:
4315: private static Logger getLogger() {
4316: return Logger.getLogger(FacesDndSupport.class.getName());
4317: }
4318:
4319: private static void info(Exception ex) {
4320: getLogger().log(Level.INFO, null, ex);
4321: }
4322: }
|