0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.visualweb.insync.live;
0042:
0043: import org.netbeans.modules.visualweb.api.designer.markup.MarkupService;
0044: import org.netbeans.modules.visualweb.api.designerapi.DesignTimeTransferDataCreator;
0045: import org.netbeans.modules.visualweb.designer.html.HtmlAttribute;
0046: import org.netbeans.modules.visualweb.designer.html.HtmlTag;
0047: import com.sun.rave.designtime.markup.MarkupDesignBean;
0048: import com.sun.rave.designtime.markup.MarkupPosition;
0049: import org.netbeans.modules.visualweb.extension.openide.loaders.SystemFileSystemSupport;
0050: import org.netbeans.modules.visualweb.insync.ResultHandler;
0051: import org.netbeans.modules.visualweb.insync.UndoEvent;
0052: import org.netbeans.modules.visualweb.insync.Util;
0053: import org.netbeans.modules.visualweb.insync.beans.BeansUnit;
0054: import org.netbeans.modules.visualweb.insync.faces.FacesBean;
0055: import org.netbeans.modules.visualweb.insync.faces.MarkupBean;
0056: import org.netbeans.modules.visualweb.insync.models.FacesModel;
0057: import java.awt.EventQueue;
0058: import java.awt.Image;
0059: import java.awt.datatransfer.DataFlavor;
0060: import java.awt.datatransfer.Transferable;
0061: import java.awt.datatransfer.UnsupportedFlavorException;
0062: import java.beans.BeanDescriptor;
0063: import java.beans.BeanInfo;
0064: import java.beans.Customizer;
0065: import java.beans.EventSetDescriptor;
0066: import java.beans.PropertyDescriptor;
0067: import java.beans.PropertyEditor;
0068: import java.beans.PropertyEditorManager;
0069: import java.io.IOException;
0070: import java.lang.ref.SoftReference;
0071: import java.util.ArrayList;
0072: import java.util.Arrays;
0073: import java.util.Collections;
0074: import java.util.Iterator;
0075: import java.util.LinkedList;
0076: import java.util.List;
0077: import java.util.Map;
0078: import java.util.WeakHashMap;
0079:
0080: import javax.sql.RowSet;
0081: import javax.swing.Action;
0082: import javax.swing.ImageIcon;
0083: import javax.swing.SwingUtilities;
0084: import org.openide.ErrorManager;
0085: import javax.swing.event.ChangeListener;
0086:
0087: import org.openide.actions.CopyAction;
0088: import org.openide.actions.CutAction;
0089: import org.openide.actions.PasteAction;
0090: import org.openide.awt.UndoRedo;
0091: import org.openide.filesystems.FileObject; // XXX Not a NB cookie, can't use.
0092: //import org.openide.cookies.UndoRedoCookie;
0093: import org.openide.loaders.DataObject;
0094: import org.openide.loaders.DataObjectNotFoundException;
0095: import org.openide.nodes.AbstractNode;
0096: import org.openide.nodes.Children;
0097: import org.openide.nodes.Index;
0098: import org.openide.nodes.Node;
0099: import org.openide.nodes.Sheet;
0100: import org.openide.nodes.Sheet.Set;
0101: import org.openide.util.HelpCtx;
0102: import org.openide.util.Lookup;
0103: import org.openide.util.NbBundle;
0104: import org.openide.util.WeakListeners;
0105: import org.openide.util.actions.SystemAction;
0106: import org.openide.util.datatransfer.NewType;
0107: import org.openide.util.datatransfer.ExTransferable;
0108: import org.openide.util.datatransfer.PasteType;
0109:
0110: import com.sun.rave.designtime.BeanCreateInfo;
0111: import com.sun.rave.designtime.BeanCreateInfoSet;
0112: import com.sun.rave.designtime.CategoryDescriptor;
0113: import com.sun.rave.designtime.Constants;
0114: import com.sun.rave.designtime.Customizer2;
0115: import com.sun.rave.designtime.DesignBean;
0116: import com.sun.rave.designtime.DesignContext;
0117: import com.sun.rave.designtime.DesignEvent;
0118: import com.sun.rave.designtime.DesignInfo;
0119: import com.sun.rave.designtime.DesignProperty;
0120: import com.sun.rave.designtime.DisplayItem;
0121: import com.sun.rave.designtime.EventDescriptor;
0122: import com.sun.rave.designtime.Position;
0123: import com.sun.rave.designtime.Result;
0124: import com.sun.rave.designtime.event.DesignBeanListener;
0125: import com.sun.rave.designtime.event.DesignContextListener;
0126: import com.sun.rave.designtime.faces.FacesBindingPropertyEditor;
0127: import com.sun.rave.designtime.markup.AttributePropertyEditor;
0128: import java.util.logging.Level;
0129: import java.util.logging.LogRecord;
0130: import java.util.logging.Logger;
0131: import org.netbeans.modules.visualweb.extension.openide.util.Trace;
0132: import org.netbeans.modules.visualweb.insync.Unit;
0133: import org.netbeans.modules.visualweb.propertyeditors.binding.ValueBindingAttributePropertyEditor;
0134: import org.netbeans.modules.visualweb.propertyeditors.binding.ValueBindingPropertyEditor;
0135: import org.openide.util.lookup.Lookups;
0136: import org.openide.util.lookup.ProxyLookup;
0137: import org.w3c.dom.Element;
0138:
0139: /**
0140: * The netbeans node associated with a live bean, either a container or a leaf
0141: *
0142: * @author Carl Quinn
0143: */
0144: public class DesignBeanNode extends AbstractNode implements
0145: DesignBeanListener {
0146:
0147: final protected DesignBean liveBean;
0148: protected Class customizer;
0149: protected Customizer2 liveCustomizer;
0150: protected DataObject dataObject;
0151:
0152: /** Name of property set for general properties */
0153: final static public String GENERAL = "General"; // NOI18N
0154: final static public String GENERAL_HINT = "GeneralHint"; // NOI18N
0155: final static public String EVENTS = "Events"; // NOI18N
0156: final static public String EVENTS_HINT = "EventsHint"; // NOI18N
0157:
0158: //Name of property id
0159: final static public String PROPERTY_ID = "id"; // NOI18N
0160: //Display name of property id is different to list it at the top
0161: final static public String PROPERTY_ID_DISPLAY = NbBundle
0162: .getMessage(DesignBeanNode.class, "LBL_Id"); // NOI18N
0163:
0164: // Memory leak probing
0165: private static final Logger TIMERS = Logger
0166: .getLogger("TIMER.visualweb"); // NOI18N
0167:
0168: private final DesignContextListener designContextListener = new DesignBeanNodeDesignContextListener(
0169: this );
0170:
0171: static DesignBeanNode getInstance(DesignBean liveBean) {
0172: Children kids = liveBean.isContainer() ? new BeanChildren(
0173: liveBean) : Children.LEAF;
0174:
0175: List fixedLookupItems = new ArrayList();
0176: fixedLookupItems.add(liveBean);
0177:
0178: if (kids instanceof Index
0179: && liveBean instanceof MarkupDesignBean) {
0180: // Allow reordering of children for MarkupDesignBeans only
0181: // Add DesignBean
0182: fixedLookupItems.add(kids);
0183: }
0184:
0185: // Add also undo redo manager into lookup so it can be retrieved in outline top comp.
0186: UndoRedo undoRedo;
0187: DesignContext designContext = liveBean.getDesignContext();
0188: if (designContext instanceof LiveUnit) {
0189: FacesModel facesModel = ((LiveUnit) designContext)
0190: .getModel();
0191: if (facesModel != null) {
0192: undoRedo = facesModel.getUndoManager();
0193: } else {
0194: undoRedo = null;
0195: }
0196: } else {
0197: undoRedo = null;
0198: }
0199: if (undoRedo != null) {
0200: fixedLookupItems.add(undoRedo);
0201: }
0202:
0203: Lookup fixedLookup = Lookups.fixed(fixedLookupItems.toArray());
0204:
0205: return new DesignBeanNode(liveBean, kids, fixedLookup,
0206: new DesignBeanNodeLookup());
0207: }
0208:
0209: /** Adding the <code>Designean</code> to the lookup.
0210: * @see org.openide.nodes.Node(Children, Lookup) */
0211: private DesignBeanNode(DesignBean liveBean, Children children,
0212: Lookup fixedLookup,
0213: DesignBeanNodeLookup designBeanNodeLookup) {
0214: super (children, new ProxyLookup(new Lookup[] { fixedLookup,
0215: designBeanNodeLookup }));
0216:
0217: if (TIMERS.isLoggable(Level.FINER)) {
0218: LogRecord rec = new LogRecord(Level.FINER, "DesignBeanNode"); // NOI18N
0219: rec.setParameters(new Object[] { this });
0220: TIMERS.log(rec);
0221: }
0222:
0223: // XXX To init the lookup with the node, see DesignBeanNodeLookup.
0224: designBeanNodeLookup.setNode(this );
0225:
0226: this .liveBean = liveBean;
0227:
0228: if (!getRegisteredCustomizer())
0229: getInfoCustomizer();
0230:
0231: assert Trace.trace("insync.live", "LBN lb:" + liveBean
0232: + " bi:" + liveBean.getBeanInfo() + " cu:" + customizer
0233: + " lc:" + liveCustomizer);
0234:
0235: initDefaultIconBase();
0236: initHelpCtx();
0237: liveBean.addDesignBeanListener(this );
0238: // XXX #6484230 One needs to listen on design context as well, to catch rename events.
0239: DesignContext designContext = liveBean.getDesignContext();
0240: if (designContext != null) {
0241: designContext
0242: .addDesignContextListener((DesignContextListener) WeakListeners
0243: .create(DesignContextListener.class,
0244: designContextListener,
0245: designContext));
0246: }
0247:
0248: setDataObject(retrieveJspDataObject(liveBean));
0249:
0250: // XXX #6473798 Sets non-null programatic name.
0251: // There should be some better way then toString().
0252: setName(liveBean.toString());
0253:
0254: updateToolTip();
0255: }
0256:
0257: private void initDefaultIconBase() {
0258: // XXX Better design the nodes provided for specific beans (see e.g. the DataObject vs. DataNode).
0259: if (liveBean instanceof SourceLiveRoot) {
0260: // Root icon.
0261: if (Util.isPageRootContainerDesignBean(liveBean)) {
0262: setIconBaseWithExtension("org/netbeans/modules/visualweb/insync/live/defaultPageRoot.png"); // NOI18N
0263: } else {
0264: setIconBaseWithExtension("org/netbeans/modules/visualweb/insync/live/defaultBeanRoot.png"); // NOI18N
0265: }
0266: } else if (liveBean instanceof MarkupDesignBean
0267: && ((MarkupDesignBean) liveBean).getElement() != null) {
0268: // Tag icon.
0269: setIconBaseWithExtension("org/netbeans/modules/visualweb/insync/live/defaultTag.png"); // NOI18N
0270: } else {
0271: // Bean icon.
0272: setIconBaseWithExtension("org/netbeans/modules/visualweb/insync/live/defaultBean.gif"); // NOI18N
0273: }
0274: }
0275:
0276: /**
0277: * help related stuff -- context help
0278: */
0279: private String helpKey;
0280: private String propertiesHelpKey;
0281:
0282: private void initHelpCtx() {
0283: helpKey = (String) liveBean.getBeanInfo().getBeanDescriptor()
0284: .getValue(Constants.BeanDescriptor.HELP_KEY);
0285: propertiesHelpKey = (String) liveBean.getBeanInfo()
0286: .getBeanDescriptor().getValue(
0287: Constants.BeanDescriptor.PROPERTIES_HELP_KEY);
0288:
0289: // #6472652 Fallback for the markup beans.
0290: if (liveBean instanceof MarkupDesignBean
0291: || Util.isPageRootContainerDesignBean(liveBean)) {
0292: // XXX This is not wanted for the fix.
0293: // if (helpKey == null) {
0294: // helpKey = "projrave_ui_elements_page"; // NOI18N
0295: // }
0296: if (propertiesHelpKey == null) {
0297: propertiesHelpKey = "projrave_ui_elements_propsheets_page_props"; // NOI18N
0298: }
0299: }
0300:
0301: if (propertiesHelpKey != null) {
0302: setValue("propertiesHelpID", propertiesHelpKey); // NOI18N
0303: }
0304: }
0305:
0306: public HelpCtx getHelpCtx() {
0307: return helpKey != null ? new HelpCtx(helpKey) : null;
0308: }
0309:
0310: /**
0311: *
0312: */
0313: private boolean getRegisteredCustomizer() {
0314: String classname;
0315: DesignInfo lbi = liveBean.getDesignInfo();
0316: BeanInfo bi = liveBean.getBeanInfo();
0317: if (lbi != null) {
0318: classname = lbi.getBeanClass().getName();
0319: } else {
0320: if (bi != null)
0321: classname = bi.getBeanDescriptor().getBeanClass()
0322: .getName();
0323: else
0324: classname = liveBean.getInstance().getClass().getName();
0325: }
0326: liveCustomizer = LiveUnit.getCustomizer(classname);
0327:
0328: assert Trace.trace("insync.live", "LBN.RC lbi:" + lbi + " bi:"
0329: + bi + " classname:" + classname + " lc:"
0330: + liveCustomizer);
0331:
0332: return liveCustomizer != null;
0333: }
0334:
0335: Customizer2 getCustomizer2() {
0336: return liveCustomizer;
0337: }
0338:
0339: /**
0340: *
0341: */
0342: private void getInfoCustomizer() {
0343: BeanDescriptor bd = liveBean.getBeanInfo().getBeanDescriptor();
0344: if (bd != null) {
0345: customizer = bd.getCustomizerClass();
0346: if (customizer != null) {
0347: if (Customizer2.class.isAssignableFrom(customizer)) {
0348: try {
0349: liveCustomizer = (Customizer2) customizer
0350: .newInstance();
0351: } catch (Exception e) {
0352: }
0353: }
0354: if (!Customizer.class.isAssignableFrom(customizer))
0355: customizer = null; // not a valid Customizer, throw away ref
0356: }
0357: }
0358: }
0359:
0360: /**
0361: * Get a cookie. Call super first, but if null, delegate to
0362: * the associated data object (if any). The delegated to data object
0363: * is generally the file representing the container for the bean.
0364: */
0365: public Node.Cookie getCookie(Class cl) {
0366: Node.Cookie c = super .getCookie(cl);
0367: if (c != null)
0368: return c;
0369:
0370: // XXX Just a hack for the rare cases the dataObject was not available at the beginning.
0371: // Rather the (faces)model should fire changes about file changes (if there are any).
0372: if (dataObject == null) {
0373: setDataObject(retrieveJspDataObject(liveBean));
0374: }
0375:
0376: if (dataObject != null)
0377: return dataObject.getCookie(cl);
0378:
0379: return null;
0380: }
0381:
0382: /**
0383: * Set a data object to associate this node with. Whenever the node is asked for a cookie it
0384: * doesn't hold, it will delegate the question to the associated data object.
0385: * <p>
0386: * NOTE: the caller MUST call setDataObject(null) on this node when done
0387: * with it to free up resources!
0388: * @param dataObject the data object to associate with the node
0389: */
0390: private void setDataObject(DataObject dataObject) {
0391: if (this .dataObject != dataObject) {
0392: // if (this.dataObject != null)
0393: // this.dataObject.removePropertyChangeListener(pListener);
0394:
0395: this .dataObject = dataObject;
0396:
0397: if (this .dataObject != null) {
0398: pListener = new PListener();
0399: this .dataObject.addPropertyChangeListener(WeakListeners
0400: .propertyChange(pListener, this .dataObject));
0401: } else {
0402: pListener = null;
0403: }
0404: }
0405: }
0406:
0407: private static DataObject retrieveJspDataObject(
0408: DesignBean designBean) {
0409: DesignContext designContext = designBean.getDesignContext();
0410: if (designContext instanceof LiveUnit) {
0411: FacesModel facesModel = ((LiveUnit) designContext)
0412: .getModel();
0413: if (facesModel == null) {
0414: return null;
0415: }
0416:
0417: FileObject jspFileObject = facesModel.getMarkupFile();
0418: if (jspFileObject == null) {
0419: return null;
0420: }
0421:
0422: try {
0423: return DataObject.find(jspFileObject);
0424: } catch (DataObjectNotFoundException ex) {
0425: ErrorManager.getDefault().notify(
0426: ErrorManager.INFORMATIONAL, ex);
0427: }
0428: }
0429:
0430: return null;
0431: }
0432:
0433: // #5042202 Node delegating cookie has to also propagate the cookie change events
0434: // in order for the dependant cookie actions (other observers) are working correctly.
0435: private java.beans.PropertyChangeListener pListener;
0436:
0437: private class PListener implements
0438: java.beans.PropertyChangeListener {
0439: public void propertyChange(java.beans.PropertyChangeEvent evt) {
0440: if (DataObject.PROP_COOKIE.equals(evt.getPropertyName())
0441: && dataObject == evt.getSource())
0442: fireCookieChange();
0443: }
0444: }
0445:
0446: public boolean canRename() {
0447: return false;
0448: }
0449:
0450: public boolean canDestroy() {
0451: return !Util.isSpecialBean(liveBean)
0452: && !isHeadDesignBean(liveBean);
0453: }
0454:
0455: public void destroy() throws IOException {
0456: // Do not explicitelly remove the node, the node structure will be update
0457: // based on model changes.
0458: // super.destroy();
0459:
0460: // XXX #6475512 Insync works in AWT only (which wrong, but that how it is),
0461: // and DeleteAction is asynchronous - see DeleteAction.asynchronous method.
0462: EventQueue.invokeLater(new Runnable() {
0463: public void run() {
0464: try {
0465: doDestroy();
0466: } catch (IOException ex) {
0467: ErrorManager.getDefault().notify(ex);
0468: }
0469: }
0470: });
0471: }
0472:
0473: private void doDestroy() throws IOException {
0474: LiveUnit liveUnit = (LiveUnit) liveBean.getDesignContext();
0475: UndoEvent undoEvent = liveUnit.getModel().writeLock("destroy"); // TODO I18N
0476: try {
0477: liveUnit.deleteBean(liveBean);
0478: } finally {
0479: liveUnit.getModel().writeUnlock(undoEvent);
0480: }
0481: }
0482:
0483: public PasteType getDropType(Transferable t, int action, int index) {
0484: PasteType pasteType = super .getDropType(t, action, index);
0485: if (pasteType instanceof BeanCreateInfoPasteType) {
0486: ((BeanCreateInfoPasteType) pasteType).setIndex(index);
0487: } else if (pasteType instanceof BeanCreateInfoSetPasteType) {
0488: ((BeanCreateInfoSetPasteType) pasteType).setIndex(index);
0489: }
0490: return pasteType;
0491: }
0492:
0493: /**
0494: * Can this node be copied?
0495: *
0496: * @return <code>true</code>
0497: */
0498: public boolean canCopy() {
0499: return !Util.isSpecialBean(liveBean);
0500: }
0501:
0502: public Transferable clipboardCopy() throws IOException {
0503: if (Util.isSpecialBean(liveBean)) {
0504: return null;
0505: }
0506:
0507: Transferable deflt = super .clipboardCopy();
0508: ExTransferable enriched = ExTransferable.create(deflt);
0509: enriched.put((ExTransferable.Single) ((LiveUnit) liveBean
0510: .getDesignContext())
0511: .copyBeans(new DesignBean[] { liveBean }));
0512: return enriched;
0513: }
0514:
0515: /**
0516: * Can this node be cut?
0517: *
0518: * @return <code>false</code>
0519: */
0520: public boolean canCut() {
0521: return !Util.isSpecialBean(liveBean);
0522: }
0523:
0524: static final String CutFlavorMime = "application/x-creator-components;class="
0525: + //NOI18N
0526: DesignBeanNode.class.getName();
0527:
0528: static final DataFlavor cutFlavor = new DataFlavor(CutFlavorMime,
0529: NbBundle.getMessage(DesignBeanNode.class, "CutComponents")); //NOI18N
0530:
0531: public Transferable clipboardCut() throws IOException {
0532: if (Util.isSpecialBean(liveBean)) {
0533: return null;
0534: }
0535:
0536: Transferable deflt = super .clipboardCut();
0537: ExTransferable enriched = ExTransferable.create(deflt);
0538: ExTransferable.Single cutEnriched = new ExTransferable.Single(
0539: cutFlavor) {
0540: public Object getData() {
0541: return DesignBeanNode.this ;
0542: }
0543: };
0544: enriched.put(cutEnriched);
0545: return enriched;
0546: }
0547:
0548: private static boolean isAncestorOf(
0549: DesignBean possibleAncestorDesignBean,
0550: DesignBean possibleDescendentDesignBean) {
0551: if (possibleAncestorDesignBean == null
0552: || possibleDescendentDesignBean == null) {
0553: return false;
0554: }
0555: for (DesignBean parentDesignBean = possibleDescendentDesignBean
0556: .getBeanParent(); parentDesignBean != null; parentDesignBean = parentDesignBean
0557: .getBeanParent()) {
0558: if (possibleAncestorDesignBean == parentDesignBean) {
0559: return true;
0560: }
0561: }
0562: return false;
0563: }
0564:
0565: DataFlavor displayItemDataFlavor = new DataFlavor(
0566: DataFlavor.javaJVMLocalObjectMimeType + "; class="
0567: + DisplayItem.class.getName(), // NOI18N
0568: "DISPLAY_ITEM_HUMAN_NAME"); // NOI18N
0569:
0570: static DesignTimeTransferDataCreator dataCreator = (DesignTimeTransferDataCreator) Lookup
0571: .getDefault().lookup(DesignTimeTransferDataCreator.class);
0572:
0573: /** Don't allow pastes
0574: */
0575: protected void createPasteTypes(Transferable t, List s) {
0576: super .createPasteTypes(t, s);
0577: DesignContext designContext = liveBean.getDesignContext();
0578: LiveUnit liveUnit = (LiveUnit) designContext;
0579: if (liveUnit.getBeansUnit() == null) {
0580: // This can happens when the leaked DesignBeanNode's get called called by the Netbeans APIs
0581: // for updating the status of Paste action
0582: return;
0583: }
0584: if (t.isDataFlavorSupported(LiveUnit.flavor)) {
0585: try {
0586: LiveUnit.ClipImage clipImage = (LiveUnit.ClipImage) t
0587: .getTransferData(LiveUnit.flavor);
0588: boolean paste = true;
0589: String[] childBeanClassNames = clipImage.getTypes();
0590: for (int i = 0; i < childBeanClassNames.length; i++) {
0591: String childBeanClassName = childBeanClassNames[i];
0592: Class childBeanClass;
0593: childBeanClass = liveUnit.getBeansUnit()
0594: .getBeanClass(childBeanClassName);
0595: DesignInfo liveBeanDesignInfo = liveBean
0596: .getDesignInfo();
0597: if ((liveBeanDesignInfo != null && liveBeanDesignInfo
0598: .acceptLink(liveBean, null, childBeanClass))
0599: || designContext.canCreateBean(
0600: childBeanClassName, liveBean, null)) {
0601: // OK
0602: } else {
0603: paste = false;
0604: break;
0605: }
0606: }
0607: if (paste) {
0608: PasteType pasteType = new ClipImagePasteType(t);
0609: s.add(pasteType);
0610: }
0611: } catch (UnsupportedFlavorException e) {
0612: ErrorManager.getDefault().notify(
0613: ErrorManager.INFORMATIONAL, e);
0614: } catch (IOException e) {
0615: ErrorManager.getDefault().notify(
0616: ErrorManager.INFORMATIONAL, e);
0617: } catch (ClassNotFoundException e) {
0618: // Ignore
0619: // This exception may be thrown if the user has copied a DesignBean
0620: // from a different Visual Web project
0621: }
0622: } else if (t.isDataFlavorSupported(cutFlavor)) {
0623: try {
0624: DesignBeanNode designBeanNode = (DesignBeanNode) t
0625: .getTransferData(cutFlavor);
0626: DesignBean cutBean = designBeanNode.getDesignBean();
0627: if (cutBean == liveBean
0628: || isAncestorOf(cutBean, liveBean)
0629: || !liveUnit.canMoveBean(cutBean, liveBean,
0630: new MarkupPosition(-1))) {
0631: return;
0632: }
0633: PasteType pasteType = new CutDesignBeanPasteType(t);
0634: s.add(pasteType);
0635: } catch (UnsupportedFlavorException e) {
0636: ErrorManager.getDefault().notify(
0637: ErrorManager.INFORMATIONAL, e);
0638: } catch (IOException e) {
0639: ErrorManager.getDefault().notify(
0640: ErrorManager.INFORMATIONAL, e);
0641: }
0642: } else if (t.isDataFlavorSupported(displayItemDataFlavor)) {
0643: // XXX #6470368 Checking whether it can paste.
0644: if (liveUnit != null && liveUnit.getModel() != null) {
0645: try {
0646: DisplayItem displayItem = (DisplayItem) t
0647: .getTransferData(displayItemDataFlavor);
0648: if (displayItem instanceof BeanCreateInfo) {
0649: BeanCreateInfo beanCreateInfo = (BeanCreateInfo) displayItem;
0650: String childBeanClassName = beanCreateInfo
0651: .getBeanClassName();
0652: Class childBeanClass;
0653: try {
0654: childBeanClass = liveUnit.getBeansUnit()
0655: .getBeanClass(childBeanClassName);
0656: DesignInfo liveBeanDesignInfo = liveBean
0657: .getDesignInfo();
0658: if ((liveBeanDesignInfo != null && liveBeanDesignInfo
0659: .acceptLink(liveBean, null,
0660: childBeanClass))
0661: || designContext.canCreateBean(
0662: childBeanClassName,
0663: liveBean, null)) {
0664: PasteType pasteType = new BeanCreateInfoPasteType(
0665: beanCreateInfo);
0666: s.add(pasteType);
0667: }
0668: } catch (ClassNotFoundException e) {
0669: ErrorManager.getDefault().notify(
0670: ErrorManager.INFORMATIONAL, e);
0671: }
0672: } else if (displayItem instanceof BeanCreateInfoSet) {
0673: BeanCreateInfoSet beanCreateInfoSet = (BeanCreateInfoSet) displayItem;
0674: PasteType pasteType = new BeanCreateInfoSetPasteType(
0675: beanCreateInfoSet);
0676: s.add(pasteType);
0677: }
0678: } catch (UnsupportedFlavorException e) {
0679: ErrorManager.getDefault().notify(
0680: ErrorManager.INFORMATIONAL, e);
0681: } catch (IOException e) {
0682: ErrorManager.getDefault().notify(
0683: ErrorManager.INFORMATIONAL, e);
0684: }
0685: }
0686: } else {
0687: // XXX #6470368 Checking whether it can paste.
0688: if (liveUnit != null && liveUnit.getModel() != null) {
0689: if (dataCreator != null) {
0690: DisplayItem displayItem = dataCreator
0691: .getDisplayItem(t);
0692: if (displayItem != null) {
0693: if (displayItem instanceof BeanCreateInfo) {
0694: BeanCreateInfo beanCreateInfo = (BeanCreateInfo) displayItem;
0695: String childBeanClassName = beanCreateInfo
0696: .getBeanClassName();
0697: Class childBeanClass;
0698: try {
0699: childBeanClass = liveUnit
0700: .getBeansUnit().getBeanClass(
0701: childBeanClassName);
0702: DesignInfo liveBeanDesignInfo = liveBean
0703: .getDesignInfo();
0704: if ((liveBeanDesignInfo != null && liveBeanDesignInfo
0705: .acceptLink(liveBean, null,
0706: childBeanClass))
0707: || designContext.canCreateBean(
0708: childBeanClassName,
0709: liveBean, null)) {
0710: PasteType pasteType = new BeanCreateInfoPasteType(
0711: beanCreateInfo);
0712: s.add(pasteType);
0713: }
0714: } catch (ClassNotFoundException e) {
0715: ErrorManager.getDefault().notify(
0716: ErrorManager.INFORMATIONAL, e);
0717: }
0718: } else if (displayItem instanceof BeanCreateInfoSet) {
0719: BeanCreateInfoSet beanCreateInfoSet = (BeanCreateInfoSet) displayItem;
0720: PasteType pasteType = new BeanCreateInfoSetPasteType(
0721: beanCreateInfoSet);
0722: s.add(pasteType);
0723: }
0724: }
0725: }
0726: }
0727: }
0728: }
0729:
0730: private class ClipImagePasteType extends PasteType {
0731: private final Transferable t;
0732:
0733: public ClipImagePasteType(Transferable t) {
0734: this .t = t;
0735: }
0736:
0737: public Transferable paste() throws IOException {
0738: EventQueue.invokeLater(new Runnable() {
0739: public void run() {
0740: ((LiveUnit) liveBean.getDesignContext())
0741: .pasteBeans(t, liveBean, null);
0742: }
0743: });
0744: return null;
0745: }
0746: }
0747:
0748: private class CutDesignBeanPasteType extends PasteType {
0749: private final Transferable t;
0750:
0751: public CutDesignBeanPasteType(Transferable t) {
0752: this .t = t;
0753: }
0754:
0755: public Transferable paste() throws IOException {
0756: try {
0757: DesignBeanNode designBeanNode = (DesignBeanNode) t
0758: .getTransferData(cutFlavor);
0759: Transferable t = ((LiveUnit) designBeanNode
0760: .getDesignBean().getDesignContext())
0761: .copyBeans(new DesignBean[] { designBeanNode
0762: .getDesignBean() });
0763: LiveUnit liveUnit = ((LiveUnit) liveBean
0764: .getDesignContext());
0765: String description = NbBundle.getMessage(
0766: DesignBeanNode.class, "PasteBean"); //NOI18N
0767: UndoEvent event = liveUnit.getModel().writeLock(
0768: description);
0769: try {
0770: // liveUnit.getModel().getDnDSupport().moveBeans(new DesignBean[] {designBeanNode.getDesignBean()}, liveBean, new MarkupPosition(-1), null);
0771: liveUnit.getModel().getJsfSupport().moveBeans(
0772: new DesignBean[] { designBeanNode
0773: .getDesignBean() }, liveBean);
0774: } finally {
0775: liveUnit.getModel().writeUnlock(event);
0776: }
0777: return ExTransferable.EMPTY;
0778: } catch (UnsupportedFlavorException e) {
0779: ErrorManager.getDefault().notify(
0780: ErrorManager.INFORMATIONAL, e);
0781: }
0782: return null;
0783: }
0784: }
0785:
0786: private class BeanCreateInfoPasteType extends PasteType {
0787: private final BeanCreateInfo beanCreateInfo;
0788: private int index = -1;
0789:
0790: public BeanCreateInfoPasteType(BeanCreateInfo beanCreateInfo) {
0791: this (beanCreateInfo, -1);
0792: }
0793:
0794: public BeanCreateInfoPasteType(BeanCreateInfo beanCreateInfo,
0795: int index) {
0796: this .beanCreateInfo = beanCreateInfo;
0797: this .index = index;
0798: }
0799:
0800: void setIndex(int index) {
0801: this .index = index;
0802: }
0803:
0804: public Transferable paste() throws IOException {
0805: Result result = null;
0806: DesignContext designContext = liveBean.getDesignContext();
0807: LiveUnit liveUnit = (LiveUnit) designContext;
0808: String childBeanClassName = beanCreateInfo
0809: .getBeanClassName();
0810: Class childBeanClass;
0811: try {
0812: childBeanClass = liveUnit.getBeansUnit().getBeanClass(
0813: childBeanClassName);
0814: DesignInfo liveBeanDesignInfo = liveBean
0815: .getDesignInfo();
0816: if (liveBeanDesignInfo != null
0817: && liveBeanDesignInfo.acceptLink(liveBean,
0818: null, childBeanClass)) {
0819: String description = NbBundle.getMessage(
0820: DesignBeanNode.class, "LinkBean"); //NOI18N
0821: UndoEvent event = liveUnit.getModel().writeLock(
0822: description);
0823: try {
0824: DesignBean childBean = designContext
0825: .createBean(childBeanClassName, null,
0826: null);
0827: if (childBean != null) {
0828: result = liveBeanDesignInfo.linkBeans(
0829: liveBean, childBean);
0830: ResultHandler.handleResult(result, liveUnit
0831: .getModel());
0832: }
0833: } finally {
0834: liveUnit.getModel().writeUnlock(event);
0835: }
0836: } else if (designContext.canCreateBean(
0837: childBeanClassName, liveBean, null)) {
0838: String description = NbBundle.getMessage(
0839: DesignBeanNode.class, "CreateBean"); //NOI18N
0840: UndoEvent event = liveUnit.getModel().writeLock(
0841: description);
0842: try {
0843: Position position = null;
0844: if (index >= 0
0845: && index <= liveBean
0846: .getChildBeanCount()) {
0847: if (index == liveBean.getChildBeanCount()) {
0848: position = new MarkupPosition(-1);
0849: } else {
0850: DesignBean childDesignBean = liveBean
0851: .getChildBean(index);
0852: if (childDesignBean instanceof MarkupDesignBean) {
0853: position = new MarkupPosition(
0854: index,
0855: ((MarkupDesignBean) childDesignBean)
0856: .getElement());
0857: } else {
0858: position = new MarkupPosition(index);
0859: }
0860: }
0861: }
0862:
0863: DesignBean childBean = designContext
0864: .createBean(childBeanClassName,
0865: liveBean, position);
0866: if (childBean != null) {
0867: DesignInfo childBeanDesignInfo = childBean
0868: .getDesignInfo();
0869: if (childBeanDesignInfo != null) {
0870: result = childBeanDesignInfo
0871: .beanCreatedSetup(childBean);
0872: ResultHandler.handleResult(result,
0873: liveUnit.getModel());
0874: }
0875: }
0876: } finally {
0877: liveUnit.getModel().writeUnlock(event);
0878: }
0879: }
0880: } catch (ClassNotFoundException e) {
0881: ErrorManager.getDefault().notify(
0882: ErrorManager.INFORMATIONAL, e);
0883: }
0884:
0885: return ExTransferable.EMPTY;
0886: }
0887: }
0888:
0889: private class BeanCreateInfoSetPasteType extends PasteType {
0890: private final BeanCreateInfoSet beanCreateInfoSet;
0891: private int index = -1;
0892:
0893: public BeanCreateInfoSetPasteType(
0894: BeanCreateInfoSet beanCreateInfoSet) {
0895: this (beanCreateInfoSet, -1);
0896: }
0897:
0898: public BeanCreateInfoSetPasteType(
0899: BeanCreateInfoSet beanCreateInfoSet, int index) {
0900: this .beanCreateInfoSet = beanCreateInfoSet;
0901: this .index = index;
0902: }
0903:
0904: void setIndex(int index) {
0905: this .index = index;
0906: }
0907:
0908: public Transferable paste() throws IOException {
0909: Result result = null;
0910: DesignContext designContext = liveBean.getDesignContext();
0911: LiveUnit liveUnit = (LiveUnit) designContext;
0912: String[] childBeanClassNames = beanCreateInfoSet
0913: .getBeanClassNames();
0914: // TODO deal with all classes
0915: if (childBeanClassNames != null
0916: && childBeanClassNames.length > 0) {
0917: String childBeanClassName = childBeanClassNames[0];
0918: Class childBeanClass;
0919: try {
0920: childBeanClass = liveUnit.getBeansUnit()
0921: .getBeanClass(childBeanClassName);
0922: DesignInfo liveBeanDesignInfo = liveBean
0923: .getDesignInfo();
0924: if (liveBeanDesignInfo != null
0925: && liveBeanDesignInfo.acceptLink(liveBean,
0926: null, childBeanClass)) {
0927: String description = NbBundle.getMessage(
0928: DesignBeanNode.class, "LinkBean"); //NOI18N
0929: UndoEvent event = liveUnit.getModel()
0930: .writeLock(description);
0931: try {
0932: DesignBean childBean = designContext
0933: .createBean(childBeanClassName,
0934: null, null);
0935: if (childBean != null) {
0936: result = beanCreateInfoSet
0937: .beansCreatedSetup(new DesignBean[] { childBean });
0938: ResultHandler.handleResult(result,
0939: liveUnit.getModel());
0940: DesignInfo childBeanDesignInfo = childBean
0941: .getDesignInfo();
0942: if (childBeanDesignInfo != null) {
0943: result = childBeanDesignInfo
0944: .beanCreatedSetup(childBean);
0945: ResultHandler.handleResult(result,
0946: liveUnit.getModel());
0947: }
0948: liveBeanDesignInfo.linkBeans(liveBean,
0949: childBean);
0950: }
0951: } finally {
0952: liveUnit.getModel().writeUnlock(event);
0953: }
0954: } else if (designContext.canCreateBean(
0955: childBeanClassName, liveBean, null)) {
0956: String description = NbBundle.getMessage(
0957: DesignBeanNode.class, "CreateBean"); //NOI18N
0958: UndoEvent event = liveUnit.getModel()
0959: .writeLock(description);
0960: try {
0961: Position position = null;
0962: if (index >= 0
0963: && index <= liveBean
0964: .getChildBeanCount()) {
0965: if (index == liveBean
0966: .getChildBeanCount()) {
0967: position = new MarkupPosition(-1);
0968: } else {
0969: DesignBean childDesignBean = liveBean
0970: .getChildBean(index);
0971: if (childDesignBean instanceof MarkupDesignBean) {
0972: position = new MarkupPosition(
0973: index,
0974: ((MarkupDesignBean) childDesignBean)
0975: .getElement());
0976: } else {
0977: position = new MarkupPosition(
0978: index);
0979: }
0980: }
0981: }
0982: DesignBean childBean = designContext
0983: .createBean(childBeanClassName,
0984: liveBean, position);
0985: if (childBean != null) {
0986: result = beanCreateInfoSet
0987: .beansCreatedSetup(new DesignBean[] { childBean });
0988: ResultHandler.handleResult(result,
0989: liveUnit.getModel());
0990: DesignInfo childBeanDesignInfo = childBean
0991: .getDesignInfo();
0992: if (childBeanDesignInfo != null) {
0993: result = childBeanDesignInfo
0994: .beanCreatedSetup(childBean);
0995: ResultHandler.handleResult(result,
0996: liveUnit.getModel());
0997: }
0998: }
0999: } finally {
1000: liveUnit.getModel().writeUnlock(event);
1001: }
1002: }
1003: } catch (ClassNotFoundException e) {
1004: ErrorManager.getDefault().notify(
1005: ErrorManager.INFORMATIONAL, e);
1006: }
1007: }
1008: return ExTransferable.EMPTY;
1009: }
1010: }
1011:
1012: /** Return the live bean that this node is representing
1013: */
1014: public DesignBean getDesignBean() {
1015: return liveBean;
1016: }
1017:
1018: // /** XXX Bad design. Getter shouldn't be overriden, instead there should be listening on changes
1019: // * of the bean name, but they are missing. */
1020: // public final String getName() {
1021: // return liveBean.getInstanceName();
1022: // }
1023:
1024: /** XXX Bad design. Getter shouldn't be overriden, instead there should be listening on changes
1025: * of the bean name, but they are missing.
1026: *
1027: * The nodes should display the component name. This ensures that when you're looking at the
1028: * node in the tray for example (an explorer which shows the node names) you see the instance
1029: * name.)
1030: */
1031: public final String getDisplayName() {
1032: // if the project is closing/closed return null
1033: if (((LiveUnit) liveBean.getDesignContext()).getModel() == null) {
1034: return null;
1035: }
1036: String instanceName = liveBean.getInstanceName();
1037: if (instanceName == null) {
1038: instanceName = NbBundle.getMessage(DesignBeanNode.class,
1039: "LBL_InvalidDisplayName", liveBean);
1040: }
1041:
1042: String defaultPropertyName = getDefaultPropertyDisplayName(liveBean);
1043: if (defaultPropertyName == null) {
1044: return instanceName;
1045: } else {
1046: return instanceName + ":" + defaultPropertyName; // NOI18N
1047: }
1048: }
1049:
1050: private void updateToolTip() {
1051: if (liveBean instanceof SourceLiveRoot) {
1052: DesignContext designContext = liveBean.getDesignContext();
1053: if (designContext != null) {
1054: setShortDescription(designContext.getDisplayName()
1055: + " (" + getScopeLabel(designContext) + ")"); // NOI18N
1056: }
1057: } else {
1058: BeanInfo bi = liveBean.getBeanInfo();
1059: if (bi != null) {
1060: setShortDescription(liveBean.getInstanceName()
1061: + " ("
1062: + getFormattedClassName(bi.getBeanDescriptor()
1063: .getBeanClass()) + ")"); // NOI18N
1064: }
1065: }
1066: }
1067:
1068: private static String getScopeLabel(DesignContext designContext) {
1069: return (String) designContext
1070: .getContextData(Constants.ContextData.SCOPE);
1071: }
1072:
1073: private static String getFormattedClassName(Class clazz) {
1074: if (clazz.isArray()) {
1075: return getFormattedClassName(clazz.getComponentType())
1076: + "[]"; // NOI18N
1077: } else {
1078: String fullName = clazz.getName();
1079: int lastDot = fullName.lastIndexOf('.'); // NOI18N
1080: if (lastDot > -1 && fullName.length() > lastDot) {
1081: return fullName.substring(lastDot + 1);
1082: } else {
1083: return fullName;
1084: }
1085: }
1086: }
1087:
1088: /** XXX Copied from OutlineTreeRenderer. */
1089: private static String getDefaultPropertyDisplayName(DesignBean bean) {
1090: BeanInfo bi = bean.getBeanInfo();
1091: // label = bean.getInstanceName();
1092:
1093: // Add in the default property's value if applicable
1094: int defaultProp = bi.getDefaultPropertyIndex();
1095: String beanClassName = bi.getBeanDescriptor().getBeanClass()
1096: .getName();
1097: if (beanClassName
1098: .startsWith("com.sun.sql.rowset.CachedRowSetXImpl")) {
1099: // If the bean is of type CachedRowSet then get the SQL command and display as part of label text (bug#6332976)
1100: // XXX PeterZ this is a hack and may not be efficient, revisit after Thresher (Winston)
1101: // The correct solution is to have a BeanInfo for com.sun.sql.rowset.CachedRowSetXImpl and set the default
1102: // property as "command"
1103: PropertyDescriptor[] pds = bi.getPropertyDescriptors();
1104: for (int i = 0; pds != null && i < pds.length; i++) {
1105: if (pds[i].getName().equals("command")) {
1106: String s = getDefaultPropertyValue(bean, pds[i]);
1107: if (s != null) {
1108: // XXX Should the format be localizable?
1109: // label = label + ": " + s;
1110: return s;
1111: }
1112: }
1113: }
1114: } else if (defaultProp != -1) {
1115: PropertyDescriptor defProp = bi.getPropertyDescriptors()[defaultProp];
1116: String s = getDefaultPropertyValue(bean, defProp);
1117:
1118: if (s != null) {
1119: // XXX Should the format be localizable?
1120: // label = label + ": " + s;
1121: return s;
1122: }
1123: } else {
1124: // Could use this instead:
1125: //if (FacesSupport.isXhtmlComponent(bean)) {
1126: // But we want the MarkupBean anyway
1127: // MarkupBean mb = FacesSupport.getMarkupBean(bean);
1128: MarkupBean mb = Util.getMarkupBean(bean);
1129:
1130: if ((mb != null) && !(mb instanceof FacesBean)) {
1131: String id = mb.getElement().getAttribute(
1132: HtmlAttribute.ID);
1133:
1134: if (id.length() == 0) {
1135: id = mb.getElement().getAttribute(
1136: HtmlAttribute.NAME);
1137: }
1138:
1139: if (id.length() > 0) {
1140: // label = label + ": " + id;
1141: return id;
1142: }
1143: }
1144: }
1145: return null;
1146: }
1147:
1148: /** XXX Copied from OutlineTreeRenderer. */
1149: private static String getDefaultPropertyValue(DesignBean bean,
1150: PropertyDescriptor defProp) {
1151: // Boolean properties are not interesting but it turns
1152: // out rowsets have autoCommit (a boolean property) as
1153: // a default so they all show up as personRowset: false
1154: // etc -- we don't want to see booleans appended
1155: if (defProp.getPropertyType() == Boolean.TYPE) {
1156: return null;
1157: }
1158:
1159: DesignProperty prop = bean.getProperty(defProp.getName());
1160:
1161: if (prop == null) {
1162: return null;
1163: }
1164:
1165: String s = prop.getValueSource();
1166:
1167: if ((s == null) || (s.length() == 0)) {
1168: return null;
1169: }
1170:
1171: if (/*FacesSupport.*/isValueBindingExpression(s, false)) {
1172: return null;
1173: }
1174:
1175: // // I probably SHOULDN'T truncate when we're showing
1176: // // outputlink urls!
1177: // int slash = s.lastIndexOf('/');
1178: //
1179: // if (slash != -1) {
1180: // s = s.substring(slash + 1);
1181: // }
1182:
1183: // // Truncate long strings
1184: // s = DesignerUtils.truncateString(s, 30);
1185: // s = Util.truncateString(s, 30);
1186:
1187: return s;
1188: }
1189:
1190: /** XXX Copied from designer/FacesSupport.
1191: *
1192: * Return true if the given String represents a value binding expression.
1193: * @param s The string to check
1194: * @param containsOk Iff true, consider a String which has a value binding
1195: * expression embedded anywhere as a value binding expression. For example,
1196: * "You are #{Session1.age} years old" will return true for this method
1197: * if containsOk is set, and false otherwise. If false, only consider
1198: * Strings that begin with a value binding expression as being
1199: * a value binding expression.
1200: * @return True iff the given expression is a value binding expression
1201: * according to the type indicated by containsOk.
1202: */
1203: public static boolean isValueBindingExpression(String s,
1204: boolean containsOk) {
1205: assert s != null;
1206:
1207: // TODO: Use
1208: // ((FacesDesignProperty)designProperty).isBound()
1209: // instead - so change to passing in a DesignProperty etc.
1210: if (containsOk) {
1211: return s.indexOf("#{") != -1; // NOI18N
1212: } else {
1213: return s.startsWith("#{"); // NOI18N
1214: }
1215: }
1216:
1217: // XXX TODO Figure out a better way then overriding this getter method.
1218: public Image getIcon(int type) {
1219: Image img = liveBean.getBeanInfo().getIcon(type);
1220: if (img == null) {
1221: img = super .getIcon(type); // Falls back to default icon.
1222: }
1223: return img;
1224: }
1225:
1226: // XXX TODO Figure out a better way then overriding this getter method.
1227: public Image getOpenedIcon(int type) {
1228: return getIcon(type);
1229: }
1230:
1231: // <actions from layers>
1232: // protected SystemAction[] systemActions;
1233: // </actions from layers>
1234:
1235: public Action[] getActions(boolean context) {
1236: // <actions from layers>
1237: // if (context) {
1238: // return super.getActions(context);
1239: // }
1240: // if (systemActions == null) {
1241: //
1242: // ArrayList actions = new ArrayList(20);
1243: //
1244: // /* !#@#!@#!@#! The NetBeans Action system only allows
1245: // action singletons - which means I can't do adapter classes
1246: // that store state about what they're delegating to!
1247: //
1248: // // Add actions specified by the live bean info, if any
1249: // DesignInfo lbi = liveBean.getDesignInfo();
1250: // if (lbi != null) {
1251: // DisplayAction[] context = lbi.getContextItems(liveBean);
1252: // for (int i = 0; i < context.length; i++) {
1253: // DisplayAction action = context[i];
1254: // if (action instanceof DisplayActionSet) {
1255: // DisplayActionSet actionSet = (DisplayActionSet)action;
1256: // if (actionSet.isPopup()) {
1257: // // Pullright
1258: // actions.add(new PullrightAdapter(actionSet, this));
1259: // } else {
1260: // // It's a "flat" action - just insert its
1261: // // children inline. I'm assuming that you
1262: // // wouldn't have a flat DisplayActionSet
1263: // // inside another flat DisplayActionSet - XXX check
1264: // // with Joe if that's a valid assumption (seems
1265: // // reasonable to me - why would you "nest" inline
1266: // // groups?), if not I've gotta recurse here.
1267: // addSeparator(actions);
1268: // DisplayAction[] subitems = actionSet.getDisplayActions();
1269: // for (int j = 0; j < subitems.length; j++) {
1270: // DisplayAction subitem = subitems[j];
1271: // if (subitem instanceof DisplayActionSet) {
1272: // DisplayActionSet das = (DisplayActionSet)subitem;
1273: // assert das.isPopup();
1274: // actions.add(new PullrightAdapter(das, this));
1275: // } else {
1276: // actions.add(new DisplayActionAdapter(subitem));
1277: // }
1278: // }
1279: // addSeparator(actions);
1280: // }
1281: // } else {
1282: // actions.add(new DisplayActionAdapter(action));
1283: // }
1284: // }
1285: // }
1286: // addSeparator(actions);
1287: // */
1288: //
1289: // if (liveCustomizer != null) {
1290: // actions.add(SystemAction.get(CustomizeAction.class));
1291: // actions.add(null);
1292: // }
1293: // // TODO Disable these actions until such time as they can be implemented, see bug #6337233
1294: // // Using extra local in case we add some additional rules :)
1295: // boolean addCutCopyPasteActions = true;
1296: // if (liveBean.getInstance() instanceof RowSet) {
1297: // addCutCopyPasteActions = false;
1298: // }
1299: // if (addCutCopyPasteActions) {
1300: // actions.add(SystemAction.get(CutAction.class));
1301: // actions.add(SystemAction.get(CopyAction.class));
1302: // actions.add(SystemAction.get(PasteAction.class));
1303: // }
1304: // actions.add(SystemAction.get(DeleteAction.class));
1305: // systemActions = (SystemAction[])actions.toArray(new SystemAction[actions.size()]);
1306: // }
1307: // return systemActions;
1308: // ====
1309: // return SystemFileSystemSupport.getActions(PATH_DESIGN_BEAN_NODES_ACTIONS);
1310: List actions = new ArrayList(Arrays
1311: .asList(SystemFileSystemSupport
1312: .getActions(PATH_DESIGN_BEAN_NODES_ACTIONS)));
1313:
1314: // XXX #94118 Bad diffing the actions for various nodes.
1315: if (!Util.isPageRootContainerDesignBean(liveBean)) {
1316: for (Iterator it = actions.iterator(); it.hasNext();) {
1317: Action action = (Action) it.next();
1318: if (action != null
1319: && action.getValue(ACTION_KEY_PAGE_BEAN_ONLY) == Boolean.TRUE) {
1320: it.remove();
1321: }
1322: }
1323: }
1324:
1325: // XXX Suspicious postprocessing.
1326: // TODO Rather provide different subclasses of the node, handling different instances.
1327: // or better make some node providers for corresponding beans,
1328: // reading each from different action folder.
1329: if (liveCustomizer == null) {
1330: actions.remove(SystemAction.get(CustomizeAction.class));
1331: }
1332:
1333: boolean addCutCopyPasteActions;
1334: if (liveBean.getInstance() instanceof RowSet) {
1335: addCutCopyPasteActions = false;
1336: } else {
1337: addCutCopyPasteActions = true;
1338: }
1339: if (!addCutCopyPasteActions) {
1340: actions.remove(SystemAction.get(CutAction.class));
1341: actions.remove(SystemAction.get(CopyAction.class));
1342: actions.remove(SystemAction.get(PasteAction.class));
1343: }
1344:
1345: return (Action[]) actions.toArray(new Action[actions.size()]);
1346: // </actions from layers>
1347: }
1348:
1349: /** XXX #94118 Hack to differenciate the presence of the actions in the popup.
1350: * There should be different types for the different nodes. */
1351: public final static String ACTION_KEY_PAGE_BEAN_ONLY = "actionKeyPageBeanOnly"; // NOI18N
1352:
1353: public Action getPreferredAction() {
1354: // #6465174 Make customize action the preferred one if is present.
1355: Action[] actions = getActions(false);
1356: Action customizeAction = SystemAction
1357: .get(CustomizeAction.class);
1358: List actionList = Arrays.asList(actions);
1359: if (actionList.contains(customizeAction)) {
1360: return customizeAction;
1361: } else {
1362: for (Iterator it = actionList.iterator(); it.hasNext();) {
1363: Action action = (Action) it.next();
1364: if (action != null) {
1365: return action;
1366: }
1367: }
1368: }
1369: return super .getPreferredAction();
1370: }
1371:
1372: // <actions from layers>
1373: /** Path to the action folder in the system file system. */
1374: private static final String PATH_DESIGN_BEAN_NODES_ACTIONS = "DesignBeanNodes/application/x-designtime/Actions"; // NOI18N
1375:
1376: /** Interface to retrieve the actions. */
1377: interface ActionProvider {
1378: Action[] getActions();
1379: }
1380:
1381: // </actions from layers>
1382:
1383: /**
1384: * If the bean has a Customizer2, invoke it; otherwise, do nothing.
1385: */
1386: public void invokeCustomizer() {
1387: if (liveCustomizer != null)
1388: liveCustomizer.getCustomizerPanel(liveBean);
1389: }
1390:
1391: public String toString() {
1392: return super .toString() + "[liveBean=" + liveBean + "]"; // NOI18N
1393: }
1394:
1395: /**
1396: * Small class to implement a Node.Property for a DesignBeans's instanceName (id)
1397: */
1398: public static class IdLink extends Node.Property {
1399: DesignBean bean;
1400:
1401: IdLink(DesignBean bean) {
1402: super (String.class);
1403: this .bean = bean;
1404: setName(PROPERTY_ID);
1405: setDisplayName(PROPERTY_ID_DISPLAY);
1406: // search for property descriptor for id property's and use the info
1407: PropertyDescriptor[] propertyDescriptors = bean
1408: .getBeanInfo().getPropertyDescriptors();
1409: for (int i = 0; i < propertyDescriptors.length; i++) {
1410: PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
1411: if (propertyDescriptor.getName().equals(PROPERTY_ID)) {
1412: // the following code is similar to the one in PropLink inner class
1413: setDisplayName(propertyDescriptor.getName());
1414: Class propType = propertyDescriptor
1415: .getPropertyType();
1416: String typeName = propType != null ? propType
1417: .getName() : "";
1418: if (typeName.lastIndexOf(".") > -1)
1419: typeName = typeName.substring(typeName
1420: .lastIndexOf(".") + 1);
1421: String sdesc = propertyDescriptor
1422: .getShortDescription();
1423: setValue("originalShortDescription", sdesc); // NOI18N
1424: setShortDescription(""
1425: + propertyDescriptor.getDisplayName()
1426: + " (" + typeName + ") \n" + sdesc); // NOI18N
1427: break;
1428: }
1429: }
1430: }
1431:
1432: public boolean canRead() {
1433: return true;
1434: }
1435:
1436: public Object getValue() {
1437: return bean.getInstanceName();
1438: }
1439:
1440: public boolean canWrite() {
1441: if (((LiveUnit) bean.getDesignContext()).getState() == Unit.State.BUSTED) {
1442: return false;
1443: }
1444: return bean.canSetInstanceName();
1445: }
1446:
1447: public void setValue(Object val) {
1448: bean.setInstanceName((String) val, true); // enable auto numbering
1449: }
1450:
1451: public boolean supportsDefaultValue() {
1452: return false;
1453: }
1454:
1455: public void restoreDefaultValue() {
1456: }
1457:
1458: public boolean isDefaultValue() {
1459: return false;
1460: }
1461:
1462: public String toString() {
1463: return "[IL name:" + getName() + " value:" + getValue()
1464: + "]";
1465: }
1466: }
1467:
1468: /**
1469: * Small class to implement a Node.Property for a DesignProperty
1470: */
1471: public static class PropLink extends Node.Property {
1472: DesignProperty property;
1473: PropertyDescriptor desc;
1474:
1475: public DesignProperty getDesignProperty() {
1476: return property;
1477: }
1478:
1479: PropLink(DesignProperty property) {
1480: super (property.getPropertyDescriptor().getPropertyType());
1481: this .property = property;
1482: this .desc = property.getPropertyDescriptor();
1483: setName(desc.getName());
1484: setDisplayName(desc.getName());
1485: Class propType = desc.getPropertyType();
1486: String typeName = propType != null ? propType.getName()
1487: : "";
1488: if (typeName.lastIndexOf(".") > -1)
1489: typeName = typeName
1490: .substring(typeName.lastIndexOf(".") + 1);
1491: String sdesc = desc.getShortDescription();
1492: // EAT: Needed by some property editors
1493: setValue("originalShortDescription", sdesc); // NOI18N
1494: // EAT: Need to escape the descriptions
1495: // This is done in a couple of lcass, we should REALLY put this type of code
1496: // in one place. Another location this is done is com.sun.rave.toolbox.PaletteItemButton.initialize()
1497: setShortDescription("" + desc.getDisplayName() + " ("
1498: + typeName + ") \n" + sdesc);
1499: setExpert(desc.isExpert());
1500: setHidden(desc.isHidden());
1501: setPreferred(desc.isPreferred());
1502: }
1503:
1504: public boolean canRead() {
1505: return desc.getReadMethod() != null;
1506: }
1507:
1508: public Object getValue() {
1509: return property.getValue();
1510: }
1511:
1512: public boolean canWrite() {
1513: if (((LiveUnit) property.getDesignBean().getDesignContext())
1514: .getState() == Unit.State.BUSTED) {
1515: return false;
1516: }
1517: return desc.getWriteMethod() != null;
1518: }
1519:
1520: public void setValue(Object val) {
1521: //System.err.println("PL.setValue val:" + val + " => this:" + this);
1522: property.setValue(val);
1523: }
1524:
1525: public boolean supportsDefaultValue() {
1526: return canRead() && canWrite();
1527: }
1528:
1529: public void restoreDefaultValue() {
1530: property.unset();
1531: }
1532:
1533: public boolean isDefaultValue() {
1534: return !property.isModified();
1535: }
1536:
1537: public String getHtmlDisplayName() {
1538: if (isDefaultValue()) {
1539: return null;
1540: } else {
1541: return "<b>" + getDisplayName(); // NOI18N
1542: }
1543: }
1544:
1545: //Soft caching of property editor references to improve JTable
1546: //property sheet performance
1547: SoftReference propertyEditorRef = null;
1548:
1549: public PropertyEditor getPropertyEditor() {
1550: PropertyEditor propertyEditor = null;
1551:
1552: if (propertyEditorRef != null) {
1553: propertyEditor = (PropertyEditor) propertyEditorRef
1554: .get();
1555: }
1556:
1557: if (propertyEditor == null) {
1558: propertyEditor = ((BeansDesignProperty) property)
1559: .getPropertyEditor();
1560: // Is this a FacesDesignProperty i.e. a bindable property
1561: if (property instanceof FacesDesignProperty) {
1562: if (propertyEditor instanceof FacesBindingPropertyEditor) {
1563: // The property editor knows how to deal with FacesDesignProperty so just return it.
1564: //
1565: } else if (propertyEditor instanceof AttributePropertyEditor) {
1566: // The property editor is a editor for markup attributes. Wrap it in a special value binding property editor which knows how to deal with markup attributes.
1567: ValueBindingAttributePropertyEditor valueBindingAttributePropertyEditor = new ValueBindingAttributePropertyEditor(
1568: (AttributePropertyEditor) propertyEditor);
1569: valueBindingAttributePropertyEditor
1570: .setDesignProperty(property);
1571: propertyEditor = valueBindingAttributePropertyEditor;
1572: } else {
1573: // Wrap the property editor in a special value binding property editor.
1574: ValueBindingPropertyEditor valueBindingPropertyEditor = new ValueBindingPropertyEditor(
1575: propertyEditor);
1576: valueBindingPropertyEditor
1577: .setDesignProperty(property);
1578: propertyEditor = valueBindingPropertyEditor;
1579: }
1580: }
1581: }
1582:
1583: propertyEditorRef = new SoftReference(propertyEditor);
1584: return propertyEditor;
1585: }
1586:
1587: public String toString() {
1588: return "[PL name:" + getName() + " type:" + getValueType()
1589: + " value:" + getValue() + "]";
1590: }
1591:
1592: private static final ImageIcon BOUND_ICON = new ImageIcon(
1593: PropLink.class.getResource("bound.png"));
1594:
1595: // EAT: I talked to Joe about this and he did not like it, BUT I need it in order to
1596: // have some of the values set on the property being linked? to be passed through
1597: public Object getValue(String attributeName) {
1598: Object result = super .getValue(attributeName);
1599: // Did super return anything?
1600: if (result == null) {
1601: // Is this a FacesDesignProperty
1602: if (property instanceof FacesDesignProperty) {
1603: if ("changeImmediate".equals(attributeName)) {
1604: // For facesDesignProperties the ValueBindingPropertyEditor wraps the propertye descriptor returned PropertyEditor.
1605: // Update the property value when the user clicks OK button in the CustomEditor dialog.
1606: return Boolean.FALSE;
1607: }
1608: // Is the property bound?
1609: if (((FacesDesignProperty) property).isBound()) {
1610: // If the property editor is not an instance of FacesBindingPropertyEditor then
1611: // show special icon and disallow in place editing. If the property editor is
1612: // an instance of FacesBindingPropertyEditor then let it deal with the property sheet
1613: if (!(((BeansDesignProperty) property)
1614: .getPropertyEditor() instanceof FacesBindingPropertyEditor)) {
1615: // Is the Property Sheet asking for valueIcon?
1616: if ("valueIcon".equals(attributeName)) {
1617: // return bound icon
1618: return BOUND_ICON;
1619: } else
1620: // Is the Property Sheet asking for canEditAsText for inline editing?
1621: if ("tooltip".equals(attributeName)) {
1622: // Prevent inline editing
1623: return ((FacesDesignProperty) property)
1624: .getValueSource();
1625: } else
1626: // Is the Property Sheet asking for canEditAsText for inline editing?
1627: if ("canEditAsText".equals(attributeName)) {
1628: // Prevent inline editing
1629: return Boolean.FALSE;
1630: }
1631: }
1632: }
1633: }
1634: }
1635: if (result == null
1636: && property.getPropertyDescriptor() != null)
1637: result = property.getPropertyDescriptor().getValue(
1638: attributeName);
1639: return result;
1640: }
1641: }
1642:
1643: /**
1644: * Small class to implement a Node.Property given a DesignProperty,.
1645: */
1646: public static class EventLink extends Node.Property {
1647: DesignEvent event;
1648: EventDescriptor desc;
1649: EventPropertyEditor editor;
1650:
1651: EventLink(DesignEvent event) {
1652: super (String.class);
1653: this .event = event;
1654: this .desc = event.getEventDescriptor();
1655: EventSetDescriptor esd = desc.getEventSetDescriptor();
1656: String name = desc.getName();
1657: String displayName = desc.getDisplayName();
1658: String shortDescription = desc.getShortDescription();
1659: if (esd != null) {
1660: if (esd.getName() != null)
1661: name = esd.getName();
1662: if (esd.getDisplayName() != null)
1663: displayName = esd.getDisplayName();
1664: if (esd.getShortDescription() != null)
1665: // TODO - Use Entities.escape()
1666: shortDescription = displayName + " - \n"
1667: + esd.getShortDescription();
1668: }
1669: setName(name);
1670: setDisplayName(name);
1671: setShortDescription(shortDescription);
1672: setExpert(desc.isExpert());
1673: setHidden(desc.isHidden());
1674: setPreferred(desc.isPreferred());
1675: }
1676:
1677: public boolean canRead() {
1678: return true;
1679: }
1680:
1681: public Object getValue() {
1682: return event.getHandlerName();
1683: }
1684:
1685: public boolean canWrite() {
1686: return true;
1687: }
1688:
1689: public void setValue(Object val) {
1690: if (val != null && !(val instanceof String))
1691: throw new IllegalArgumentException();
1692: event.setHandlerName((String) val);
1693: }
1694:
1695: public boolean supportsDefaultValue() {
1696: return true; //!CQ ? revert()/isModified()
1697: }
1698:
1699: public void restoreDefaultValue() {
1700: event.removeHandler();
1701: }
1702:
1703: public boolean isDefaultValue() {
1704: return !event.isHandled();
1705: }
1706:
1707: public PropertyEditor getPropertyEditor() {
1708: if (event instanceof BeansDesignEvent) {
1709: if (editor == null)
1710: editor = new EventPropertyEditor(
1711: (BeansDesignEvent) event);
1712: return editor;
1713: }
1714: return PropertyEditorManager.findEditor(String.class);
1715: }
1716:
1717: public String toString() {
1718: return "[EL name:" + getName() + " type:" + getValueType()
1719: + " value:" + getValue() + "]";
1720: }
1721: }
1722:
1723: /*
1724: * @see com.sun.rave.designtime.DesignBeanListener#beanContextActivated(com.sun.rave.designtime.DesignBean)
1725: */
1726: public void beanContextActivated(DesignBean designBean) {
1727: }
1728:
1729: /*
1730: * @see com.sun.rave.designtime.DesignBeanListener#beanContextDeactivated(com.sun.rave.designtime.DesignBean)
1731: */
1732: public void beanContextDeactivated(DesignBean designBean) {
1733: }
1734:
1735: /*
1736: * @see com.sun.rave.designtime.DesignBeanListener#instanceNameChanged(com.sun.rave.designtime.DesignBean, java.lang.String)
1737: */
1738: public void instanceNameChanged(DesignBean designBean,
1739: String oldInstanceName) {
1740: }
1741:
1742: /*
1743: * @see com.sun.rave.designtime.DesignBeanListener#beanChanged(com.sun.rave.designtime.DesignBean)
1744: */
1745: public void beanChanged(final DesignBean bean) {
1746: niceFirePropertyChange(PROPERTY_ID, null, bean
1747: .getInstanceName());
1748: //fix 5055048 Setting id on a tray component does not change identifier in the tray
1749: displayNameChanged();
1750: }
1751:
1752: private void displayNameChanged() {
1753: final DesignBean bean = liveBean;
1754: if (bean == null) {
1755: return;
1756: }
1757: if (SwingUtilities.isEventDispatchThread()) {
1758: fireDisplayNameChange(null, bean.getInstanceName());
1759: } else {
1760: SwingUtilities.invokeLater(new Runnable() {
1761: public void run() {
1762: fireDisplayNameChange(null, bean.getInstanceName());
1763: }
1764: });
1765: }
1766: }
1767:
1768: /*
1769: * @see com.sun.rave.designtime.DesignBeanListener#propertyChanged(com.sun.rave.designtime.DesignProperty)
1770: */
1771: public void propertyChanged(DesignProperty prop, Object oldValue) {
1772: niceFirePropertyChange(prop.getPropertyDescriptor().getName(),
1773: oldValue, prop.getValue());
1774: displayNameChanged();
1775: }
1776:
1777: /*
1778: * @see com.sun.rave.designtime.DesignBeanListener#eventChanged(com.sun.rave.designtime.DesignEvent)
1779: */
1780: public void eventChanged(DesignEvent event) {
1781: niceFirePropertyChange(event.getEventDescriptor()
1782: .getDisplayName(), null, event.getHandlerName());
1783: }
1784:
1785: /**
1786: * Fire a propertychange event, making sure it is delivered in the Swing event dispatch thread
1787: * so that NB doesn't FREAK out.
1788: *
1789: * @param name
1790: * @param o
1791: * @param n
1792: */
1793: protected void niceFirePropertyChange(final String name,
1794: final Object o, final Object n) {
1795: if (SwingUtilities.isEventDispatchThread()) {
1796: firePropertyChange(name, o, n);
1797: } else {
1798: SwingUtilities.invokeLater(new Runnable() {
1799: public void run() {
1800: try {
1801: firePropertyChange(name, o, n);
1802: } catch (Exception e) {
1803: //ErrorManager.getDefault().notify(e);
1804: }
1805: }
1806: });
1807: }
1808: }
1809:
1810: /**
1811: *
1812: */
1813: protected Set getSheetSet(Sheet sheet, String name, String descr) {
1814: Set ss = sheet.get(name);
1815: if (ss == null) {
1816: ss = new Sheet.Set();
1817: ss.setName(name);
1818: ss.setDisplayName(name);
1819: //ss.setExpert();
1820: // would like to set default expanded state too...
1821: if (descr != null)
1822: ss.setShortDescription(descr);
1823: sheet.put(ss);
1824: }
1825: return ss;
1826: }
1827:
1828: /**
1829: * Creates properties.
1830: */
1831: protected Sheet createSheet() {
1832: Sheet sheet = Sheet.createDefault();
1833: Set general = getSheetSet(sheet, NbBundle.getMessage(
1834: DesignBeanNode.class, GENERAL), NbBundle.getMessage(
1835: DesignBeanNode.class, GENERAL_HINT));
1836:
1837: IdLink il = new IdLink(liveBean);
1838: general.put(il);
1839:
1840: // prepopulate the sheet-set list from the beandescriptor categories
1841: Object catlistO = liveBean.getBeanInfo().getBeanDescriptor()
1842: .getValue("propertyCategories"); //NOI18N
1843: if (catlistO instanceof CategoryDescriptor[]) {
1844: CategoryDescriptor[] catlist = (CategoryDescriptor[]) catlistO;
1845: for (int i = 0; i < catlist.length; i++)
1846: getSheetSet(sheet, catlist[i].getName(), catlist[i]
1847: .getShortDescription());
1848: }
1849:
1850: // Create property links for all properties in the live bean
1851: DesignProperty[] props = liveBean.getProperties();
1852: assert Trace.trace("insync.live", "LBN.createSheet for "
1853: + liveBean + " w/ " + props.length + " props"); //NOI18N
1854:
1855: for (int i = 0; i < props.length; i++) {
1856: PropertyDescriptor pd = props[i].getPropertyDescriptor();
1857: if (pd.isHidden()) // XXX Why not?|| pd.getName().equals(PROPERTY_ID))
1858: continue;
1859:
1860: PropLink pl = new PropLink(props[i]);
1861: Object catO = pd.getValue("category"); //NOI18N
1862: if (catO instanceof CategoryDescriptor) {
1863: CategoryDescriptor cat = (CategoryDescriptor) catO;
1864: Set ss = getSheetSet(sheet, cat.getName(), cat
1865: .getShortDescription());
1866: ss.put(pl);
1867: } else {
1868: general.put(pl);
1869: }
1870: //assert Trace.trace("insync.live", " " + pl + " => " + props[i]);
1871: }
1872:
1873: // Create event links for all events in the live bean
1874: Set ess = getSheetSet(sheet, NbBundle.getMessage(
1875: DesignBeanNode.class, EVENTS), NbBundle.getMessage(
1876: DesignBeanNode.class, EVENTS_HINT));
1877:
1878: DesignEvent[] events = liveBean.getEvents();
1879: assert Trace.trace("insync.live", "LBN.createSheet for "
1880: + liveBean + " w/ " + events.length + " events"); //NOI18N
1881:
1882: for (int i = 0; i < events.length; i++) {
1883: EventDescriptor ed = events[i].getEventDescriptor();
1884: if (ed.isHidden()
1885: || (ed.getEventSetDescriptor() != null && ed
1886: .getEventSetDescriptor().isHidden()))
1887: continue;
1888:
1889: EventLink el = new EventLink(events[i]);
1890: ess.put(el);
1891: assert Trace.trace("insync.live", " " + el + " => "
1892: + events[i]); //NOI18N
1893: }
1894:
1895: // XXX If the bean represents the root container for Page, add some fake properties.
1896: if (Util.isPageRootContainerDesignBean(liveBean)) {
1897: DesignBeanNodeHelper.addFakePageProperties(sheet, liveBean);
1898: }
1899:
1900: return sheet;
1901: }
1902:
1903: public NewType[] getNewTypes() {
1904: return createNewTypes(liveBean);
1905: }
1906:
1907: private static NewType[] createNewTypes(DesignBean designBean) {
1908: if (designBean instanceof SourceLiveRoot) {
1909: return createRootNewTypes(designBean);
1910: }
1911:
1912: return createDefaultNewTypes(designBean);
1913: }
1914:
1915: // XXX NB #84384 Caching the new types for the java data object, for better result, see below.
1916: private static final Map javaDataObject2newTypes = new WeakHashMap();
1917:
1918: // XXX #6448518 Very hacky method to retrieve the new types
1919: // from java | class | bean patterns node, and passing them here
1920: // to fake the old functionality.
1921: private static NewType[] createRootNewTypes(DesignBean designBean) {
1922: DesignContext designContext = designBean.getDesignContext();
1923: if (designContext == null) {
1924: return new NewType[0];
1925: }
1926:
1927: FacesModel facesModel = ((LiveUnit) designContext).getModel();
1928: if (facesModel == null) {
1929: return new NewType[0];
1930: }
1931:
1932: FileObject javaFileObject = facesModel.getJavaFile();
1933: if (javaFileObject == null) {
1934: return new NewType[0];
1935: }
1936:
1937: DataObject javaDataObject;
1938: try {
1939: javaDataObject = DataObject.find(javaFileObject);
1940: } catch (DataObjectNotFoundException ex) {
1941: ErrorManager.getDefault().notify(
1942: ErrorManager.INFORMATIONAL, ex);
1943: return new NewType[0];
1944: }
1945: if (javaDataObject == null) {
1946: return new NewType[0];
1947: }
1948:
1949: synchronized (javaDataObject2newTypes) {
1950: NewType[] newTypes = (NewType[]) javaDataObject2newTypes
1951: .get(javaDataObject);
1952: if (newTypes != null) {
1953: return newTypes;
1954: }
1955: }
1956:
1957: Node javaNode = javaDataObject.getNodeDelegate();
1958: // // XXX NB #84384 Horrible hack: This needs to be here to spawn the process to init the nodes,
1959: // // in order bypass the temporary Please wait... nodes.
1960: // // Also we hope that the process (running in parallel RP), will be posted
1961: // // on time, so it is running when we ask for findChild, see below, (which waits for it).
1962: // // This is still not working 100%.
1963: // // See NB sources: java/src/../SourceChildren.
1964: // javaNode.getChildren().getNodes(true);
1965: // invokeAddNotifyOnChildren(javaNode.getChildren());
1966:
1967: NewType[] javaTypes = javaNode.getNewTypes();
1968: List typesJava = new ArrayList();
1969: for (int i = 0; i < javaTypes.length; i++) {
1970: if (i == 0 || i == 2) { // 1st and 3rd
1971: typesJava.add(javaTypes[i]);
1972: }
1973: }
1974:
1975: String designBeanName = designBean.getInstanceName();
1976: if (designBeanName == null) {
1977: return new NewType[0];
1978: }
1979: Node javaClassNode = javaNode.getChildren().findChild(
1980: designBeanName);
1981: if (javaClassNode == null) {
1982: return new NewType[0];
1983: }
1984:
1985: Node[] classChildren = javaClassNode.getChildren().getNodes(
1986: true);
1987: // XXX The last is the bean property node.
1988: Node beanNode = classChildren == null
1989: || classChildren.length == 0 ? null
1990: : classChildren[classChildren.length - 1];
1991: if (beanNode == null) {
1992: return new NewType[0];
1993: }
1994:
1995: List types = new ArrayList();
1996: // XXX Take only first two (supposing property and indexed property).
1997: NewType[] beanTypes = beanNode.getNewTypes();
1998: for (int i = 0; i < beanTypes.length; i++) {
1999: types.add(beanTypes[i]);
2000: if (i == 1) { // Add first 2 only.
2001: break;
2002: }
2003: }
2004: types.addAll(typesJava);
2005:
2006: NewType[] newTypes = (NewType[]) types
2007: .toArray(new NewType[types.size()]);
2008: synchronized (javaDataObject2newTypes) {
2009: javaDataObject2newTypes.put(javaDataObject, newTypes);
2010: }
2011: return newTypes;
2012: }
2013:
2014: // // XXX Using reflection for the hack, to spawn the process of initing the child nodes.
2015: // private static void invokeAddNotifyOnChildren(Children children) {
2016: // try {
2017: // Method method = Children.class.getDeclaredMethod("addNotify", new Class[0]); // NOI18N
2018: // method.setAccessible(true);
2019: // method.invoke(children, new Object[0]);
2020: // } catch (SecurityException ex) {
2021: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
2022: // } catch (NoSuchMethodException ex) {
2023: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
2024: // } catch (IllegalArgumentException ex) {
2025: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
2026: // } catch (IllegalAccessException ex) {
2027: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
2028: // } catch (InvocationTargetException ex) {
2029: // ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
2030: // }
2031: // }
2032:
2033: private static NewType[] createDefaultNewTypes(DesignBean designBean) {
2034: String[] preferredChildren;
2035: BeanDescriptor bd = designBean.getBeanInfo()
2036: .getBeanDescriptor();
2037: if (bd != null) {
2038: preferredChildren = (String[]) bd
2039: .getValue(Constants.BeanDescriptor.PREFERRED_CHILD_TYPES);
2040: } else {
2041: preferredChildren = new String[0];
2042: }
2043:
2044: // XXX Why the api returns null instead of empty array?
2045: if (preferredChildren == null) {
2046: return new NewType[0];
2047: }
2048:
2049: List newTypes = new ArrayList();
2050: for (int i = 0; i < preferredChildren.length; i++) {
2051: newTypes.add(new DesignBeanNewType(designBean,
2052: preferredChildren[i]));
2053:
2054: // if (preferredChildren.length == 1) {
2055: // // Add a single inline item
2056: // String className = preferredChildren[0];
2057: // String displayName = getBeanDisplayName(className);
2058: //
2059: // if (displayName != null) {
2060: // String label =
2061: // NbBundle.getMessage(DesignerActions.class, "AddOneItem", displayName);
2062: // JMenuItem item = new JMenuItem(label);
2063: // item.putClientProperty(CHILD_PROP, className);
2064: // item.addActionListener(new AddItemHandler(bean));
2065: //
2066: // //menu.add(item);
2067: // addItem = item; // Added in the middle of the bean-specific menus
2068: // }
2069: // } else {
2070: // // Pullright
2071: // JMenu submenu =
2072: // new JMenu(NbBundle.getMessage(SelectionManager.class, "AddItem")); // NOI18N
2073: // submenu.putClientProperty(BEAN_PROP, bean);
2074: //
2075: // //menu.add(submenu);
2076: // addItem = submenu; // Added in the middle of the bean-specific menus
2077: // submenu.addMenuListener(this); // submenu contents created dynamically
2078: // }
2079: }
2080:
2081: return (NewType[]) newTypes
2082: .toArray(new NewType[newTypes.size()]);
2083: }
2084:
2085: private static class DesignBeanNewType extends NewType {
2086: private final DesignBean parent;
2087: private final String className;
2088:
2089: public DesignBeanNewType(DesignBean parent, String className) {
2090: this .parent = parent;
2091: this .className = className;
2092: }
2093:
2094: public void create() throws IOException {
2095: LiveUnit liveUnit = (LiveUnit) parent.getDesignContext();
2096: if (liveUnit == null) {
2097: ErrorManager.getDefault()
2098: .notify(
2099: ErrorManager.INFORMATIONAL,
2100: new NullPointerException(
2101: "No LiveUnit for designBean="
2102: + parent)); // NOI18N
2103: return;
2104: }
2105: FacesModel facesModel = liveUnit.getModel();
2106: UndoEvent undoEvent = facesModel.writeLock(getName());
2107: try {
2108: DesignBean bean = liveUnit.createBean(className,
2109: parent, null);
2110:
2111: if (bean != null) {
2112: try {
2113: facesModel.beanCreated(bean);
2114: } catch (Exception e) {
2115: // XXX Why is catching Exception, just following the old hacky code.
2116: e.printStackTrace();
2117: }
2118: }
2119:
2120: // List beans = new ArrayList(1);
2121: // beans.add(bean);
2122: DesignBean[] beans = new DesignBean[] { bean };
2123:
2124: // DndHandler dnd = webform.getPane().getDndHandler();
2125: // dnd.customizeCreation(beans);
2126: Util.customizeCreation(beans, facesModel);
2127: //// dnd.selectBean(bean);
2128: // webform.getSelection().selectBean(bean);
2129: //// dnd.inlineEdit(beans);
2130: // webform.getManager().inlineEdit(beans);
2131:
2132: // facesModel.getDnDSupport().notifyBeansDesigner(beans, bean);
2133: facesModel.getJsfSupport().selectAndInlineEdit(beans,
2134: bean);
2135: } finally {
2136: // doc.writeUnlock();
2137: facesModel.writeUnlock(undoEvent);
2138: }
2139: }
2140:
2141: public String getName() {
2142: LiveUnit unit = (LiveUnit) parent.getDesignContext();
2143: return getBeanDisplayName(unit, className);
2144: }
2145: } // End of DesignBeanNewType.
2146:
2147: private static String getBeanDisplayName(LiveUnit unit,
2148: String className) {
2149: BeansUnit sourceUnit = unit.getSourceUnit();
2150: try {
2151: Class beanClass = sourceUnit.getBeanClass(className);
2152: BeanInfo beanInfo = BeansUnit.getBeanInfo(beanClass, unit
2153: .getModel().getFacesModelSet()
2154: .getProjectClassLoader());
2155:
2156: if (beanInfo != null) {
2157: BeanDescriptor bds = beanInfo.getBeanDescriptor();
2158:
2159: if (bds != null) {
2160: String displayName = bds.getDisplayName();
2161:
2162: return displayName;
2163: }
2164: }
2165: } catch (ClassNotFoundException ex) {
2166: ErrorManager.getDefault().notify(
2167: ErrorManager.INFORMATIONAL, ex);
2168: }
2169:
2170: return null;
2171: }
2172:
2173: /**
2174: * Children object for a list of live beans
2175: */
2176: public static class BeanChildren extends Children.Keys implements
2177: DesignContextListener, Index {
2178:
2179: /** Permits changing order of children. */
2180: private Index indexSupport;
2181:
2182: /** Optional holder for the keys, to be used when changing them dynamically. */
2183: protected DesignBean parent;
2184:
2185: public BeanChildren(DesignBean parent) {
2186: this .parent = parent;
2187: indexSupport = new IndexSupport();
2188: }
2189:
2190: protected void refreshKeys() {
2191: DesignBean[] lbeans = parent.getChildBeans();
2192: if (lbeans == null || lbeans.length == 0) {
2193: setKeys(Collections.EMPTY_SET);
2194: return;
2195: }
2196:
2197: List myKeys = new LinkedList();
2198: assert Trace.trace("insync.live",
2199: "LBN.refreshKeys refreshing keys for "
2200: + lbeans.length + " beans");
2201: for (int i = 0; i < lbeans.length; i++) {
2202: assert Trace.trace("insync.live", " bean:"
2203: + lbeans[i]);
2204: myKeys.add(lbeans[i]);
2205: }
2206: setKeys(myKeys);
2207: }
2208:
2209: /**
2210: * Called when the parent node is expanded; now we need to create nodes for the children.
2211: */
2212: protected void addNotify() {
2213: assert Trace.trace("insync.live", "LBN.addNotify");
2214: super .addNotify();
2215: // Bug Fix# 125961 Use weak listener
2216: DesignContextListener weakDesignContextListener = WeakListeners
2217: .create(DesignContextListener.class, this , parent
2218: .getDesignContext());
2219: parent.getDesignContext().addDesignContextListener(
2220: weakDesignContextListener);
2221: refreshKeys();
2222: }
2223:
2224: /**
2225: * Called when the parent node is collapsed: cleanup
2226: */
2227: protected void removeNotify() {
2228: assert Trace.trace("insync.live", "LBN.removeNotify");
2229: setKeys(Collections.EMPTY_SET);
2230: super .removeNotify();
2231: }
2232:
2233: /**
2234: * Create nodes for the specified key object
2235: */
2236: protected Node[] createNodes(Object key) {
2237: DesignBean lbean = (DesignBean) key;
2238: Node node = ((SourceDesignBean) lbean).getNode();
2239: return new Node[] { node };
2240: }
2241:
2242: /** Reacts to changes */
2243:
2244: public void beanContextActivated(DesignBean designBean) {
2245: }
2246:
2247: public void beanContextDeactivated(DesignBean designBean) {
2248: }
2249:
2250: public void instanceNameChanged(DesignBean designBean,
2251: String oldInstanceName) {
2252: }
2253:
2254: public void beanChanged(DesignBean lbean) {
2255: assert Trace.trace("insync.live", "LBN.beanChanged "
2256: + lbean);
2257: if (lbean.getBeanParent() == parent)
2258: refreshKeys();
2259: }
2260:
2261: public void propertyChanged(DesignProperty prop, Object oldValue) {
2262: }
2263:
2264: public void eventChanged(DesignEvent event) {
2265: }
2266:
2267: public void contextActivated(DesignContext context) {
2268: }
2269:
2270: public void contextDeactivated(DesignContext context) {
2271: }
2272:
2273: public void contextChanged(DesignContext context) {
2274: refreshKeys();
2275: }
2276:
2277: public void beanCreated(DesignBean lbean) {
2278: assert Trace.trace("insync.live", "LBN.beanCreated "
2279: + lbean);
2280: if (lbean.getBeanParent() == parent)
2281: refreshKeys();
2282: }
2283:
2284: public void beanMoved(DesignBean lbean, DesignBean oldParent,
2285: Position pos) {
2286: assert Trace.trace("insync.live", "LBN.beanMoved " + lbean);
2287: if (lbean.getBeanParent() == parent || oldParent == parent) {
2288: // #6480729 First refresh the old parent to get rid of the moved node.
2289: refreshKeysForDesignBean(oldParent);
2290: refreshKeys();
2291: }
2292: }
2293:
2294: private static void refreshKeysForDesignBean(
2295: DesignBean designBean) {
2296: if (designBean instanceof SourceDesignBean) {
2297: DesignBeanNode designBeanNode = ((SourceDesignBean) designBean)
2298: .getNode();
2299: Children children = designBeanNode.getChildren();
2300: if (children instanceof BeanChildren) {
2301: ((BeanChildren) children).refreshKeys();
2302: }
2303: }
2304: }
2305:
2306: public void beanDeleted(DesignBean lbean) {
2307: assert Trace.trace("insync.live", "LBN.beanDeleted "
2308: + lbean);
2309: if (lbean.getBeanParent() == parent)
2310: refreshKeys();
2311: }
2312:
2313: public void addChangeListener(ChangeListener l) {
2314: indexSupport.addChangeListener(l);
2315: }
2316:
2317: public void removeChangeListener(ChangeListener l) {
2318: indexSupport.removeChangeListener(l);
2319: }
2320:
2321: public void exchange(int x, int y) {
2322: indexSupport.exchange(x, y);
2323: }
2324:
2325: public int indexOf(Node node) {
2326: return indexSupport.indexOf(node);
2327: }
2328:
2329: public void moveUp(int i) {
2330: indexSupport.moveUp(i);
2331: }
2332:
2333: public void moveDown(int i) {
2334: indexSupport.moveDown(i);
2335: }
2336:
2337: public void move(int x, int y) {
2338: indexSupport.move(x, y);
2339: }
2340:
2341: public void reorder() {
2342: indexSupport.reorder();
2343: }
2344:
2345: public void reorder(int[] i) {
2346: indexSupport.reorder(i);
2347: }
2348:
2349: /**
2350: * Allows re-ordering of the child nodes.
2351: */
2352: private class IndexSupport extends Index.Support {
2353:
2354: public void reorder(final int[] perm) {
2355: // Call the reorder on EQT later so that the Explorer Nodes get a chance to adjust
2356: // after insertion
2357: SwingUtilities.invokeLater(new Runnable() {
2358: public void run() {
2359: ((LiveUnit) parent.getDesignContext())
2360: .reorderBeanChidren(parent, perm);
2361: }
2362: });
2363: }
2364:
2365: public int getNodesCount() {
2366: return BeanChildren.this .getNodesCount();
2367: }
2368:
2369: public Node[] getNodes() {
2370: return BeanChildren.this .getNodes();
2371: }
2372: }
2373: }
2374:
2375: /** Determines whether the <code>DesignBean</code> represents head element. */
2376: private static boolean isHeadDesignBean(DesignBean designBean) {
2377: if (designBean == null) {
2378: return false;
2379: }
2380:
2381: MarkupBean markup = Util.getMarkupBean(designBean);
2382: if (markup == null) {
2383: return false;
2384: }
2385:
2386: Element element = markup.getElement();
2387: Element rendered = MarkupService
2388: .getRenderedElementForElement(element);
2389: if (rendered == null) {
2390: return false;
2391: }
2392:
2393: return HtmlTag.HEAD.getTagName().equals(rendered.getTagName());
2394: }
2395:
2396: private static class DesignBeanNodeDesignContextListener implements
2397: DesignContextListener {
2398: private final DesignBeanNode designBeanNode;
2399:
2400: public DesignBeanNodeDesignContextListener(
2401: DesignBeanNode designBeanNode) {
2402: this .designBeanNode = designBeanNode;
2403: }
2404:
2405: public void contextActivated(DesignContext designContext) {
2406: }
2407:
2408: public void contextDeactivated(DesignContext designContext) {
2409: }
2410:
2411: public void contextChanged(DesignContext designContext) {
2412: designBeanNode.displayNameChanged();
2413: }
2414:
2415: public void beanCreated(DesignBean designBean) {
2416: }
2417:
2418: public void beanDeleted(DesignBean designBean) {
2419: }
2420:
2421: public void beanMoved(DesignBean designBean,
2422: DesignBean designBean0, Position position) {
2423: }
2424:
2425: public void beanContextActivated(DesignBean designBean) {
2426: }
2427:
2428: public void beanContextDeactivated(DesignBean designBean) {
2429: }
2430:
2431: public void instanceNameChanged(DesignBean designBean,
2432: String string) {
2433: }
2434:
2435: public void beanChanged(DesignBean designBean) {
2436: }
2437:
2438: public void propertyChanged(DesignProperty designProperty,
2439: Object object) {
2440: }
2441:
2442: public void eventChanged(DesignEvent designEvent) {
2443: }
2444: } // End of DesingBeanNodeDesignContextListener.
2445: }
|