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-2006 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.form;
0043:
0044: import java.awt.*;
0045: import javax.swing.*;
0046: import javax.swing.border.Border;
0047: import java.util.*;
0048: import java.io.IOException;
0049: import java.util.logging.Level;
0050: import java.util.logging.Logger;
0051:
0052: import com.sun.source.tree.ClassTree;
0053: import com.sun.source.tree.Tree;
0054: import com.sun.source.util.TreePath;
0055: import javax.lang.model.element.Element;
0056: import javax.lang.model.element.TypeElement;
0057: import org.netbeans.api.java.source.CancellableTask;
0058: import org.netbeans.api.java.source.CompilationController;
0059: import org.netbeans.api.java.source.JavaSource;
0060:
0061: import org.openide.*;
0062: import org.openide.nodes.Node;
0063: import org.openide.util.Mutex;
0064: import org.openide.util.NbBundle;
0065: import org.openide.filesystems.FileObject;
0066:
0067: import org.netbeans.modules.form.layoutsupport.*;
0068: import org.netbeans.modules.form.layoutdesign.*;
0069: import org.netbeans.modules.form.layoutdesign.support.SwingLayoutBuilder;
0070: import org.netbeans.modules.form.editors2.BorderDesignSupport;
0071: import org.netbeans.modules.form.project.ClassSource;
0072: import org.netbeans.modules.form.project.ClassPathUtils;
0073:
0074: /**
0075: * This class represents an access point for adding new components to FormModel.
0076: * Its responsibility is to create new meta components (from provided bean
0077: * classes) and add them to the FormModel. In some cases, no new component is
0078: * created, just modified (e.g. when a border is applied). This class is
0079: * intended to process user actions, so all errors are caught and reported here.
0080: *
0081: * @author Tomas Pavek
0082: */
0083:
0084: public class MetaComponentCreator {
0085:
0086: private enum TargetType {
0087: LAYOUT, BORDER, MENU, VISUAL, OTHER
0088: }
0089:
0090: private enum ComponentType {
0091: NON_VISUAL, VISUAL, MENU
0092: }
0093:
0094: private static class TargetInfo {
0095: private TargetType targetType; // the way of adding/applying to the target component
0096: private ComponentType componentType; // type of metacomponent to be added/applied
0097: private RADComponent targetComponent; // actual target component (after adjustments)
0098: }
0099:
0100: private FormModel formModel;
0101:
0102: private RADVisualComponent preMetaComp;
0103: private LayoutComponent preLayoutComp;
0104:
0105: MetaComponentCreator(FormModel model) {
0106: formModel = model;
0107: }
0108:
0109: /** Creates and adds a new metacomponent to FormModel. The new component
0110: * is added to target component (if it is ComponentContainer).
0111: * @param classSource ClassSource describing the component class
0112: * @param constraints constraints object (for visual components only)
0113: * @param targetComp component into which the new component is added
0114: * @return the metacomponent if it was successfully created and added (all
0115: * errors are reported immediately)
0116: */
0117: public RADComponent createComponent(ClassSource classSource,
0118: RADComponent targetComp, Object constraints) {
0119: return createComponent(classSource, targetComp, constraints,
0120: true);
0121: }
0122:
0123: RADComponent createComponent(ClassSource classSource,
0124: RADComponent targetComp, Object constraints,
0125: boolean exactTargetMatch) {
0126: Class compClass = prepareClass(classSource);
0127: if (compClass == null)
0128: return null; // class loading failed
0129:
0130: return createAndAddComponent(compClass, targetComp,
0131: constraints, exactTargetMatch);
0132: }
0133:
0134: /** Creates a copy of a metacomponent and adds it to FormModel. The new
0135: * component is added or applied to the specified target component.
0136: * @param sourceComp component to be copied
0137: * @param targetComp target component (where the new component is added)
0138: * @return the component if it was successfully created and added (all
0139: * errors are reported immediately)
0140: */
0141: public RADComponent copyComponent(final RADComponent sourceComp,
0142: final RADComponent targetComp) {
0143: final TargetInfo target = getTargetInfo(sourceComp
0144: .getBeanClass(), targetComp, false, false);
0145: if (target == null) {
0146: return null;
0147: }
0148:
0149: try { // Look&Feel UI defaults remapping needed
0150: return (RADComponent) FormLAF.executeWithLookAndFeel(
0151: formModel, new Mutex.ExceptionAction() {
0152: public Object run() throws Exception {
0153: return copyComponent2(sourceComp, null,
0154: target);
0155: }
0156: });
0157: } catch (Exception ex) { // should not happen
0158: ErrorManager.getDefault().notify(
0159: ErrorManager.INFORMATIONAL, ex);
0160: return null;
0161: }
0162: }
0163:
0164: public boolean moveComponent(RADComponent metacomp,
0165: RADComponent targetComp) {
0166: TargetInfo target = getTargetInfo(metacomp.getBeanClass(),
0167: targetComp, false, false);
0168: if (target == null) {
0169: return false;
0170: }
0171:
0172: formModel.removeComponent(metacomp, false);
0173: return copyComponent2(metacomp, metacomp, target) != null;
0174: }
0175:
0176: public boolean addComponents(Collection<RADComponent> components,
0177: RADComponent targetComp) {
0178: for (RADComponent metacomp : components) {
0179: TargetInfo target = getTargetInfo(metacomp.getBeanClass(),
0180: targetComp, false, false);
0181: if (target == null) {
0182: return false;
0183: }
0184: copyComponent2(metacomp, metacomp, target);
0185: }
0186: return true;
0187: }
0188:
0189: public static boolean canAddComponent(Class beanClass,
0190: RADComponent targetComp) {
0191: TargetInfo target = getTargetInfo(beanClass, targetComp, false,
0192: false);
0193: return target != null
0194: && (target.targetType == TargetType.OTHER
0195: || target.targetType == TargetType.MENU || target.targetType == TargetType.VISUAL);
0196: }
0197:
0198: public static boolean canApplyComponent(Class beanClass,
0199: RADComponent targetComp) {
0200: TargetInfo target = getTargetInfo(beanClass, targetComp, false,
0201: false);
0202: return target != null
0203: && (target.targetType == TargetType.BORDER || target.targetType == TargetType.LAYOUT);
0204: }
0205:
0206: // --------
0207: // Visual component can be precreated before added to form to provide for
0208: // better visual feedback when being added. The precreated component may
0209: // end up as added or canceled. If it is added to the form (by the user),
0210: // addPrecreatedComponent methods gets called. If adding is canceled for
0211: // whatever reason, releasePrecreatedComponent is called.
0212:
0213: public RADVisualComponent precreateVisualComponent(
0214: ClassSource classSource) {
0215: final Class compClass = prepareClass(classSource);
0216:
0217: // no preview component if this is a window, applet, or not visual
0218: if (compClass == null
0219: || java.awt.Window.class.isAssignableFrom(compClass)
0220: || java.applet.Applet.class.isAssignableFrom(compClass)
0221: // JPopupMenu can't be used as a visual component (added to a container)
0222: || javax.swing.JPopupMenu.class
0223: .isAssignableFrom(compClass)
0224: || !FormUtils.isVisualizableClass(compClass)) {
0225: return null;
0226: }
0227:
0228: if (preMetaComp != null)
0229: releasePrecreatedComponent();
0230:
0231: try { // Look&Feel UI defaults remapping needed
0232: FormLAF.executeWithLookAndFeel(formModel,
0233: new Mutex.ExceptionAction() {
0234: public Object run() throws Exception {
0235: preMetaComp = createVisualComponent(compClass);
0236: return preMetaComp;
0237: }
0238: });
0239: return preMetaComp;
0240: } catch (Exception ex) { // should not happen
0241: ErrorManager.getDefault().notify(
0242: ErrorManager.INFORMATIONAL, ex);
0243: return null;
0244: }
0245: }
0246:
0247: public RADVisualComponent getPrecreatedMetaComponent() {
0248: return preMetaComp;
0249: }
0250:
0251: public LayoutComponent getPrecreatedLayoutComponent() {
0252: if (preMetaComp != null) {
0253: if (preLayoutComp == null) {
0254: preLayoutComp = createLayoutComponent(preMetaComp);
0255: }
0256: return preLayoutComp;
0257: }
0258: return null;
0259: }
0260:
0261: LayoutComponent createLayoutComponent(RADVisualComponent metacomp) {
0262: Dimension initialSize = prepareDefaultLayoutSize(
0263: (Component) metacomp.getBeanInstance(),
0264: metacomp instanceof RADVisualContainer);
0265: boolean isLayoutContainer = shouldBeLayoutContainer(metacomp);
0266: if (isLayoutContainer) {
0267: RADVisualContainer metacont = (RADVisualContainer) metacomp;
0268: Container cont = metacont.getContainerDelegate(metacont
0269: .getBeanInstance());
0270: if (initialSize == null) {
0271: initialSize = cont.getPreferredSize();
0272: }
0273: Insets insets = cont.getInsets();
0274: initialSize.width -= insets.left + insets.right;
0275: initialSize.height -= insets.top + insets.bottom;
0276: initialSize.width = Math.max(initialSize.width, 0); // Issue 83945
0277: initialSize.height = Math.max(initialSize.height, 0);
0278: }
0279: // test code logging - only for precreation
0280: if (metacomp == preMetaComp) {
0281: LayoutDesigner ld = FormEditor.getFormDesigner(formModel)
0282: .getLayoutDesigner();
0283: if ((ld != null) && ld.logTestCode()) {
0284: if (initialSize == null) {
0285: ld.testCode.add("lc = new LayoutComponent(\""
0286: + metacomp.getId() + "\", "
0287: + isLayoutContainer + ");"); //NOI18N
0288: } else {
0289: ld.testCode.add("lc = new LayoutComponent(\""
0290: + metacomp.getId() + "\", "
0291: + isLayoutContainer + ", "
0292: + //NOI18N
0293: initialSize.width + ", "
0294: + initialSize.height + ");"); //NOI18N
0295: }
0296: }
0297: }
0298: return initialSize == null ? new LayoutComponent(metacomp
0299: .getId(), isLayoutContainer) : new LayoutComponent(
0300: metacomp.getId(), isLayoutContainer, initialSize.width,
0301: initialSize.height);
0302: }
0303:
0304: static boolean shouldBeLayoutContainer(RADComponent metacomp) {
0305: return metacomp instanceof RADVisualContainer
0306: && ((RADVisualContainer) metacomp).getLayoutSupport() == null;
0307: }
0308:
0309: public boolean addPrecreatedComponent(RADComponent targetComp,
0310: Object constraints) {
0311: if (preMetaComp == null) {
0312: return false;
0313: }
0314: if (checkFormClass(preMetaComp.getBeanClass())) {
0315: TargetInfo target = getTargetInfo(preMetaComp
0316: .getBeanClass(), targetComp, true, true);
0317: if (target != null
0318: && (target.targetType == TargetType.VISUAL || target.targetType == TargetType.OTHER)) {
0319: addVisualComponent2(preMetaComp,
0320: target.targetComponent, constraints, true);
0321: ResourceSupport.switchComponentToResources(preMetaComp);
0322: }
0323: releasePrecreatedComponent();
0324: return true;
0325: } else {
0326: releasePrecreatedComponent();
0327: return false;
0328: }
0329: }
0330:
0331: void releasePrecreatedComponent() {
0332: if (preMetaComp != null) {
0333: preMetaComp = null;
0334: preLayoutComp = null;
0335: }
0336: }
0337:
0338: // --------
0339:
0340: private RADComponent createAndAddComponent(final Class compClass,
0341: final RADComponent targetComp, final Object constraints,
0342: boolean exactTargetMatch) {
0343: // check adding form class to itself
0344: if (!checkFormClass(compClass))
0345: return null;
0346:
0347: final TargetInfo target = getTargetInfo(compClass, targetComp,
0348: !exactTargetMatch, !exactTargetMatch);
0349: if (target == null) {
0350: return null;
0351: }
0352:
0353: try { // Look&Feel UI defaults remapping needed
0354: return (RADComponent) FormLAF.executeWithLookAndFeel(
0355: formModel, new Mutex.ExceptionAction() {
0356: public Object run() throws Exception {
0357: return createAndAddComponent2(compClass,
0358: target, constraints);
0359: }
0360: });
0361: } catch (Exception ex) { // should not happen
0362: ErrorManager.getDefault().notify(
0363: ErrorManager.INFORMATIONAL, ex);
0364: return null;
0365: }
0366: }
0367:
0368: private RADComponent createAndAddComponent2(Class compClass,
0369: TargetInfo target, Object constraints) {
0370: RADComponent targetComp = target.targetComponent;
0371:
0372: if (target.targetType == TargetType.LAYOUT) {
0373: return setContainerLayout(compClass, targetComp);
0374: }
0375:
0376: if (target.targetType == TargetType.BORDER) {
0377: return setComponentBorder(compClass, targetComp);
0378: }
0379:
0380: RADComponent newMetaComp = null;
0381:
0382: if (target.componentType == ComponentType.MENU) {
0383: newMetaComp = addMenuComponent(compClass, targetComp);
0384: } else if (target.componentType == ComponentType.VISUAL) {
0385: newMetaComp = addVisualComponent(compClass, targetComp,
0386: constraints);
0387: } else {
0388: newMetaComp = addOtherComponent(compClass, targetComp);
0389: }
0390:
0391: if (newMetaComp instanceof RADVisualComponent
0392: && !((RADVisualComponent) newMetaComp)
0393: .isMenuComponent()
0394: && (shouldBeLayoutContainer(targetComp) || (shouldBeLayoutContainer(newMetaComp)))) { // container with new layout...
0395: createAndAddLayoutComponent(
0396: (RADVisualComponent) newMetaComp,
0397: (RADVisualContainer) targetComp);
0398: }
0399:
0400: if (newMetaComp != null) {
0401: ResourceSupport.switchComponentToResources(newMetaComp);
0402: }
0403:
0404: return newMetaComp;
0405: }
0406:
0407: private void createAndAddLayoutComponent(
0408: RADVisualComponent radComp, RADVisualContainer targetCont) {
0409: LayoutComponent layoutComp = createLayoutComponent(radComp);
0410: String targetContId = shouldBeLayoutContainer(targetCont) ? targetCont
0411: .getId()
0412: : null;
0413:
0414: javax.swing.undo.UndoableEdit ue = formModel.getLayoutModel()
0415: .getUndoableEdit();
0416: boolean autoUndo = true;
0417: try {
0418: FormEditor.getFormDesigner(formModel).getLayoutDesigner()
0419: .addUnspecifiedComponent(layoutComp, targetContId);
0420: autoUndo = false;
0421: } finally {
0422: formModel.addUndoableEdit(ue);
0423: if (autoUndo) {
0424: formModel.forceUndoOfCompoundEdit();
0425: }
0426: }
0427: }
0428:
0429: private RADComponent copyComponent2(RADComponent sourceComp,
0430: RADComponent copiedComp, TargetInfo target) {
0431: RADComponent targetComp = target.targetComponent;
0432:
0433: // if layout or border is to be copied from a meta component, we just
0434: // apply the cloned instance, but don't copy the meta component
0435: if (target.targetType == TargetType.LAYOUT) {
0436: return copyAndApplyLayout(sourceComp, targetComp);
0437: }
0438:
0439: if (target.targetType == TargetType.BORDER) {
0440: return copyAndApplyBorder(sourceComp, targetComp);
0441: }
0442:
0443: // in other cases we need a copy of the source metacomponent
0444:
0445: if (sourceComp instanceof RADVisualComponent)
0446: LayoutSupportManager
0447: .storeConstraints((RADVisualComponent) sourceComp);
0448:
0449: boolean newlyAdded;
0450: if (copiedComp == null) { // copy the source metacomponent
0451: copiedComp = makeCopy(sourceComp);
0452: if (copiedComp == null) { // copying failed (for a mystic reason)
0453: return null;
0454: }
0455: ResourceSupport.switchComponentToResources(copiedComp);
0456: newlyAdded = true;
0457: } else {
0458: newlyAdded = false;
0459: }
0460:
0461: if (target.targetType == TargetType.MENU) {
0462: addMenuComponent(copiedComp, targetComp, newlyAdded);
0463: } else if (target.targetType == TargetType.VISUAL) {
0464: RADVisualComponent newVisual = (RADVisualComponent) copiedComp;
0465: Object constraints;
0466: if (targetComp != null) {
0467: RADVisualContainer targetCont = (RADVisualContainer) targetComp;
0468: LayoutSupportManager layoutSupport = targetCont
0469: .getLayoutSupport();
0470: if (layoutSupport == null) {
0471: constraints = null;
0472: } else {
0473: constraints = layoutSupport
0474: .getStoredConstraints(newVisual);
0475: }
0476: } else {
0477: constraints = null;
0478: }
0479: copiedComp = addVisualComponent2(newVisual, targetComp,
0480: constraints, newlyAdded);
0481: // might be null if layout support did not accept the component
0482: } else if (target.targetType == TargetType.OTHER) {
0483: addOtherComponent(copiedComp, targetComp, newlyAdded);
0484: }
0485:
0486: return copiedComp;
0487: }
0488:
0489: /**
0490: * This is a central place for deciding whether a bean can be added or
0491: * applied to given target component. It returns a TargetInfo object
0492: * representing the target operation and type of metacomponent to be
0493: * created, or null if the bean can't be used. Determining the target
0494: * placement is more strict for copy/cut/paste (paramaters canUseParent and
0495: * defaultToOthers set to false), and less strict for visual (drag&drop)
0496: * operations (canUseParent and defaultToOthers set to true). In the latter
0497: * case the actual target component can be different - it is returned in
0498: * the targetComponent field of TargetInfo.
0499: */
0500: private static TargetInfo getTargetInfo(Class beanClass,
0501: RADComponent targetComp, boolean canUseParent,
0502: boolean defaultToOthers) {
0503: TargetInfo target = new TargetInfo();
0504:
0505: if (targetComp != null) {
0506: if (LayoutSupportDelegate.class.isAssignableFrom(beanClass)
0507: || LayoutManager.class.isAssignableFrom(beanClass)) { // layout manager
0508: RADVisualContainer targetCont = getVisualContainer(
0509: targetComp, canUseParent);
0510: if (targetCont != null
0511: && !targetCont.hasDedicatedLayoutSupport()) {
0512: target.targetType = TargetType.LAYOUT;
0513: } else {
0514: return null;
0515: }
0516: } else if (Border.class.isAssignableFrom(beanClass)) { // border
0517: if (targetComp instanceof RADVisualComponent
0518: && JComponent.class.isAssignableFrom(targetComp
0519: .getBeanClass())) {
0520: target.targetType = TargetType.BORDER;
0521: } else {
0522: return null;
0523: }
0524: } else if (MenuComponent.class.isAssignableFrom(beanClass)
0525: || Separator.class.isAssignableFrom(beanClass)) {
0526: // AWT menu
0527: if (targetComp instanceof RADMenuComponent) {
0528: // adding to a menu
0529: if (((RADMenuComponent) targetComp)
0530: .canAddItem(beanClass)) {
0531: target.targetType = TargetType.MENU;
0532: } else {
0533: return null;
0534: }
0535: } else { // adding to a visual container?
0536: RADVisualContainer targetCont = getVisualContainer(
0537: targetComp, canUseParent);
0538: while (targetCont != null) {
0539: if (targetCont.getContainerMenu() != null) { // already has a menubar
0540: if (defaultToOthers) {
0541: targetCont = null;
0542: } else {
0543: return null;
0544: }
0545: } else if (targetCont.canHaveMenu(beanClass)) {
0546: target.targetType = TargetType.MENU;
0547: targetComp = targetCont;
0548: break;
0549: } else if (canUseParent) {
0550: targetCont = targetCont
0551: .getParentContainer();
0552: } else {
0553: targetCont = null;
0554: }
0555: }
0556: if (targetCont == null) {
0557: if (defaultToOthers
0558: && !Separator.class
0559: .isAssignableFrom(beanClass)) {
0560: targetComp = null; // will go to Other Components
0561: } else {
0562: return null;
0563: }
0564: }
0565: }
0566: } else if (FormUtils.isVisualizableClass(beanClass)) {
0567: // visual component
0568: if (targetComp != null
0569: && (java.awt.Window.class
0570: .isAssignableFrom(beanClass)
0571: || java.applet.Applet.class
0572: .isAssignableFrom(beanClass) || !java.awt.Component.class
0573: .isAssignableFrom(beanClass))) {
0574: // visual component that cna't have a parent
0575: if (defaultToOthers) {
0576: targetComp = null; // will go to Other Components
0577: } else {
0578: return null;
0579: }
0580: }
0581:
0582: RADVisualContainer targetCont = getVisualContainer(
0583: targetComp, canUseParent);
0584: while (targetCont != null) {
0585: if (targetCont.canAddComponent(beanClass)) {
0586: target.targetType = TargetType.VISUAL;
0587: targetComp = targetCont;
0588: break;
0589: } else if (canUseParent) {
0590: targetCont = targetCont.getParentContainer();
0591: } else {
0592: targetCont = null;
0593: }
0594: }
0595: if (targetCont == null) {
0596: if (defaultToOthers) {
0597: targetComp = null; // will go to Other Components
0598: } else {
0599: return null;
0600: }
0601: }
0602: }
0603: }
0604: if (targetComp == null) {
0605: target.targetType = TargetType.OTHER;
0606: }
0607: target.targetComponent = targetComp;
0608:
0609: if (MenuComponent.class.isAssignableFrom(beanClass)
0610: || Separator.class.isAssignableFrom(beanClass)) {
0611: target.componentType = ComponentType.MENU;
0612: } else if (FormUtils.isVisualizableClass(beanClass)) {
0613: target.componentType = ComponentType.VISUAL;
0614: } else {
0615: target.componentType = ComponentType.NON_VISUAL;
0616: }
0617:
0618: return target;
0619: }
0620:
0621: private static RADVisualContainer getVisualContainer(
0622: RADComponent targetComp, boolean canUseParent) {
0623: if (targetComp instanceof RADVisualContainer) {
0624: return (RADVisualContainer) targetComp;
0625: } else if (canUseParent
0626: && targetComp instanceof RADVisualComponent) {
0627: return (RADVisualContainer) targetComp.getParentComponent();
0628: } else {
0629: return null;
0630: }
0631: }
0632:
0633: static boolean isTransparentLayoutComponent(RADComponent metacomp) {
0634: return metacomp != null
0635: && metacomp.getBeanClass() == JScrollPane.class
0636: && metacomp.getAuxValue("autoScrollPane") != null; // NOI18N
0637: }
0638:
0639: // ---------
0640:
0641: private RADComponent makeCopy(RADComponent sourceComp/*, int targetPlacement*/) {
0642: RADComponent newComp;
0643:
0644: if (sourceComp instanceof RADVisualContainer) {
0645: newComp = new RADVisualContainer();
0646: } else if (sourceComp instanceof RADVisualComponent) {
0647: newComp = new RADVisualComponent();
0648: } else if (sourceComp instanceof RADMenuComponent) {
0649: newComp = new RADMenuComponent();
0650: } else if (sourceComp instanceof RADMenuItemComponent) {
0651: newComp = new RADMenuItemComponent();
0652: } else {
0653: newComp = new RADComponent();
0654: }
0655:
0656: newComp.initialize(formModel);
0657: if (sourceComp != sourceComp.getFormModel()
0658: .getTopRADComponent())
0659: newComp.setStoredName(sourceComp.getName());
0660:
0661: try {
0662: newComp.initInstance(sourceComp.getBeanClass());
0663: newComp.setInModel(true); // need code epxression created (issue 68897)
0664: } catch (Exception ex) { // this is rather unlikely to fail
0665: ErrorManager em = ErrorManager.getDefault();
0666: em.annotate(ex, FormUtils
0667: .getBundleString("MSG_ERR_CannotCopyInstance")); // NOI18N
0668: em.notify(ex);
0669: return null;
0670: }
0671:
0672: // 1st - copy subcomponents
0673: if (sourceComp instanceof ComponentContainer) {
0674: RADComponent[] sourceSubs = ((ComponentContainer) sourceComp)
0675: .getSubBeans();
0676: RADComponent[] newSubs = new RADComponent[sourceSubs.length];
0677:
0678: for (int i = 0; i < sourceSubs.length; i++) {
0679: RADComponent newSubComp = makeCopy(sourceSubs[i]);
0680: if (newSubComp == null)
0681: return null;
0682: newSubs[i] = newSubComp;
0683: }
0684:
0685: ((ComponentContainer) newComp).initSubComponents(newSubs);
0686:
0687: // 2nd - clone layout support
0688: if (sourceComp instanceof RADVisualContainer) {
0689: RADVisualComponent[] newComps = new RADVisualComponent[newSubs.length];
0690: System.arraycopy(newSubs, 0, newComps, 0,
0691: newSubs.length);
0692:
0693: LayoutSupportManager sourceLayout = ((RADVisualContainer) sourceComp)
0694: .getLayoutSupport();
0695:
0696: if (sourceLayout != null) {
0697: RADVisualContainer newCont = (RADVisualContainer) newComp;
0698: newCont.setOldLayoutSupport(true);
0699: newCont.getLayoutSupport().copyLayoutDelegateFrom(
0700: sourceLayout, newComps);
0701: } else {
0702: Map<String, String> sourceToTargetIds = new HashMap<String, String>(
0703: sourceSubs.length);
0704: for (int i = 0; i < sourceSubs.length; i++) {
0705: sourceToTargetIds.put(sourceSubs[i].getId(),
0706: newSubs[i].getId());
0707: }
0708: LayoutModel sourceLayoutModel = sourceComp
0709: .getFormModel().getLayoutModel();
0710: String sourceContainerId = sourceComp.getId();
0711: String targetContainerId = newComp.getId();
0712: formModel.getLayoutModel().copyContainerLayout(
0713: sourceLayoutModel, sourceContainerId,
0714: sourceToTargetIds, targetContainerId);
0715: }
0716: }
0717: }
0718:
0719: // 3rd - copy changed properties
0720: java.util.List<RADProperty> sourceList = new ArrayList<RADProperty>();
0721: java.util.List<String> namesList = new ArrayList<String>();
0722:
0723: Iterator<RADProperty> it = sourceComp
0724: .getBeanPropertiesIterator(
0725: ResourceSupport.COPIED_PROPERTY_FILTER, false);
0726: while (it.hasNext()) {
0727: RADProperty prop = it.next();
0728: sourceList.add(prop);
0729: namesList.add(prop.getName());
0730: }
0731:
0732: RADProperty[] sourceProps = new RADProperty[sourceList.size()];
0733: sourceList.toArray(sourceProps);
0734: String[] propNames = new String[namesList.size()];
0735: namesList.toArray(propNames);
0736: RADProperty[] newProps = newComp.getBeanProperties(propNames);
0737: int copyMode = FormUtils.DISABLE_CHANGE_FIRING;
0738: if (formModel == sourceComp.getFormModel())
0739: copyMode |= FormUtils.PASS_DESIGN_VALUES;
0740:
0741: FormUtils.copyProperties(sourceProps, newProps, copyMode);
0742:
0743: // hack for AWT menus - to update their Swing design parallels
0744: if (newComp instanceof RADMenuItemComponent)
0745: formModel.fireComponentPropertyChanged(newComp, null, null,
0746: null);
0747:
0748: // 4th - copy aux values
0749: Map<String, Object> auxValues = sourceComp.getAuxValues();
0750: if (auxValues != null) {
0751: for (Iterator<Map.Entry<String, Object>> it2 = auxValues
0752: .entrySet().iterator(); it2.hasNext();) {
0753: Map.Entry<String, Object> entry = it2.next();
0754: String auxName = entry.getKey();
0755: Object auxValue = entry.getValue();
0756: try {
0757: newComp.setAuxValue(auxName, FormUtils.cloneObject(
0758: auxValue, formModel));
0759: } catch (Exception e) {
0760: } // ignore problem with aux value
0761: }
0762: JavaCodeGenerator.setupComponentFromAuxValues(newComp);
0763: }
0764:
0765: // 5th - copy layout constraints
0766: if (sourceComp instanceof RADVisualComponent
0767: && newComp instanceof RADVisualComponent) {
0768: Map<String, LayoutConstraints> constraints = ((RADVisualComponent) sourceComp)
0769: .getConstraintsMap();
0770: Map<String, LayoutConstraints> newConstraints = new HashMap<String, LayoutConstraints>();
0771:
0772: for (Iterator<Map.Entry<String, LayoutConstraints>> it3 = constraints
0773: .entrySet().iterator(); it3.hasNext();) {
0774: Map.Entry<String, LayoutConstraints> entry = it3.next();
0775: String layoutClassName = entry.getKey();
0776: LayoutConstraints clonedConstr = entry.getValue()
0777: .cloneConstraints();
0778: newConstraints.put(layoutClassName, clonedConstr);
0779: }
0780: ((RADVisualComponent) newComp)
0781: .setConstraintsMap(newConstraints);
0782: }
0783:
0784: // 6th - copy events
0785: Event[] sourceEvents = sourceComp.getKnownEvents();
0786: String[] eventNames = new String[sourceEvents.length];
0787: String[][] eventHandlers = new String[sourceEvents.length][];
0788: for (int eventsIdx = 0; eventsIdx < sourceEvents.length; eventsIdx++) {
0789: eventNames[eventsIdx] = sourceEvents[eventsIdx].getName();
0790: eventHandlers[eventsIdx] = sourceEvents[eventsIdx]
0791: .getEventHandlers();
0792: }
0793:
0794: FormEvents formEvents = formModel.getFormEvents();
0795: Event[] targetEvents = newComp.getEvents(eventNames);
0796: for (int targetEventsIdx = 0; targetEventsIdx < targetEvents.length; targetEventsIdx++) {
0797:
0798: Event targetEvent = targetEvents[targetEventsIdx];
0799: if (targetEvent == null)
0800: continue; // [uknown event error - should be reported!]
0801:
0802: String[] handlers = eventHandlers[targetEventsIdx];
0803: for (int handlersIdx = 0; handlersIdx < handlers.length; handlersIdx++) {
0804: String newHandlerName;
0805: String oldHandlerName = handlers[handlersIdx];
0806: String sourceVariableName = sourceComp.getName();
0807: String targetVariableName = newComp.getName();
0808:
0809: int idx = oldHandlerName.indexOf(sourceVariableName);
0810: if (idx >= 0) {
0811: newHandlerName = oldHandlerName.substring(0, idx)
0812: + targetVariableName
0813: + oldHandlerName.substring(idx
0814: + sourceVariableName.length());
0815: } else {
0816: newHandlerName = targetVariableName
0817: + oldHandlerName;
0818: }
0819: newHandlerName = formEvents
0820: .findFreeHandlerName(newHandlerName);
0821:
0822: String bodyText = null;
0823: if (sourceComp.getFormModel() != formModel) {
0824: // copying to different form -> let's copy also the event handler content
0825: JavaCodeGenerator javaCodeGenerator = ((JavaCodeGenerator) FormEditor
0826: .getCodeGenerator(sourceComp.getFormModel()));
0827: bodyText = javaCodeGenerator
0828: .getEventHandlerText(oldHandlerName);
0829: }
0830:
0831: try {
0832: formEvents.attachEvent(targetEvent, newHandlerName,
0833: bodyText);
0834: } catch (IllegalArgumentException ex) {
0835: // [incompatible handler error - should be reported!]
0836: ex.printStackTrace();
0837: }
0838: }
0839: }
0840:
0841: return newComp;
0842: }
0843:
0844: // --------
0845:
0846: private RADComponent addVisualComponent(Class compClass,
0847: RADComponent targetComp, Object constraints) {
0848: RADVisualComponent newMetaComp = createVisualComponent(compClass);
0849:
0850: // Class beanClass = newMetaComp.getBeanClass();
0851: if (java.awt.Window.class.isAssignableFrom(compClass)
0852: || java.applet.Applet.class.isAssignableFrom(compClass))
0853: targetComp = null;
0854:
0855: return addVisualComponent2(newMetaComp, targetComp,
0856: constraints, true);
0857: }
0858:
0859: private RADVisualComponent createVisualComponent(Class compClass) {
0860: RADVisualComponent newMetaComp = null;
0861: RADVisualContainer newMetaCont = FormUtils
0862: .isContainer(compClass) ? new RADVisualContainer()
0863: : null;
0864:
0865: while (newMetaComp == null) {
0866: // initialize metacomponent and its bean instance
0867: newMetaComp = newMetaCont == null ? new RADVisualComponent()
0868: : newMetaCont;
0869:
0870: newMetaComp.initialize(formModel);
0871: if (!initComponentInstance(newMetaComp, compClass))
0872: return null; // failure (reported)
0873:
0874: if (newMetaCont == null)
0875: break; // not a container, the component is done
0876:
0877: // prepare layout support (the new component is a container)
0878: boolean knownLayout = false;
0879: Throwable layoutEx = null;
0880: try {
0881: newMetaCont.setOldLayoutSupport(true);
0882: LayoutSupportManager laysup = newMetaCont
0883: .getLayoutSupport();
0884: knownLayout = laysup
0885: .prepareLayoutDelegate(false, false);
0886:
0887: if ((knownLayout && !laysup.isDedicated()
0888: && !laysup.isSpecialLayout() && formModel
0889: .isFreeDesignDefaultLayout())
0890: || (!knownLayout && SwingLayoutBuilder
0891: .isRelevantContainer(laysup
0892: .getPrimaryContainerDelegate()))) { // general containers should use the new layout support when created
0893: newMetaCont.setOldLayoutSupport(false);
0894: FormEditor.updateProjectForNaturalLayout(formModel);
0895: knownLayout = true;
0896: }
0897: } catch (RuntimeException ex) { // silently ignore, try again as non-container
0898: ErrorManager.getDefault().notify(
0899: ErrorManager.INFORMATIONAL, ex);
0900: newMetaComp = null;
0901: newMetaCont = null;
0902: continue;
0903: } catch (Exception ex) {
0904: layoutEx = ex;
0905: } catch (LinkageError ex) {
0906: layoutEx = ex;
0907: }
0908:
0909: if (!knownLayout) {
0910: if (layoutEx == null) {
0911: // no LayoutSupportDelegate found for the container
0912: System.err
0913: .println("[WARNING] No layout support found for "
0914: + compClass.getName()); // NOI18N
0915: System.err
0916: .println(" Just a limited basic support will be used."); // NOI18N
0917: } else { // layout support initialization failed
0918: ErrorManager em = ErrorManager.getDefault();
0919: em
0920: .annotate(
0921: layoutEx,
0922: FormUtils
0923: .getBundleString("MSG_ERR_LayoutInitFailed2")); // NOI18N
0924: em.notify(layoutEx);
0925: }
0926:
0927: newMetaCont.getLayoutSupport()
0928: .setUnknownLayoutDelegate(false);
0929: }
0930: }
0931:
0932: newMetaComp.setStoredName(formModel.getCodeStructure()
0933: .getExternalVariableName(compClass, null, false));
0934:
0935: // for some components, we initialize their properties with some
0936: // non-default values e.g. a label on buttons, checkboxes
0937: return (RADVisualComponent) defaultVisualComponentInit(newMetaComp);
0938: }
0939:
0940: private RADVisualComponent addVisualComponent2(
0941: RADVisualComponent newMetaComp, RADComponent targetComp,
0942: Object constraints, boolean newlyAdded) {
0943: // Issue 65254: beware of nested JScrollPanes
0944: if ((targetComp != null)
0945: && JScrollPane.class.isAssignableFrom(targetComp
0946: .getBeanClass())) {
0947: Object bean = newMetaComp.getBeanInstance();
0948: if (bean instanceof JScrollPane) {
0949: if (newMetaComp.getAuxValue("autoScrollPane") != null) { // NOI18N
0950: RADVisualContainer metaCont = (RADVisualContainer) newMetaComp;
0951: newMetaComp = metaCont.getSubComponent(0);
0952: }
0953: }
0954: }
0955:
0956: // get parent container into which the new component will be added
0957: RADVisualContainer parentCont;
0958: if (targetComp != null) {
0959: parentCont = targetComp instanceof RADVisualContainer ? (RADVisualContainer) targetComp
0960: : (RADVisualContainer) targetComp
0961: .getParentComponent();
0962: } else
0963: parentCont = null;
0964:
0965: defaultTargetInit(newMetaComp, parentCont);
0966:
0967: // add the new metacomponent to the model
0968: if (parentCont != null) {
0969: try {
0970: formModel.addVisualComponent(newMetaComp, parentCont,
0971: constraints, newlyAdded);
0972: } catch (RuntimeException ex) {
0973: // LayoutSupportDelegate may not accept the component
0974: ErrorManager.getDefault().notify(
0975: ErrorManager.INFORMATIONAL, ex);
0976: return null;
0977: }
0978: } else
0979: formModel.addComponent(newMetaComp, null, newlyAdded);
0980:
0981: return newMetaComp;
0982: }
0983:
0984: private RADComponent addOtherComponent(Class compClass,
0985: RADComponent targetComp) {
0986: RADComponent newMetaComp = new RADComponent();
0987: newMetaComp.initialize(formModel);
0988: if (!initComponentInstance(newMetaComp, compClass))
0989: return null;
0990:
0991: addOtherComponent(newMetaComp, targetComp, true);
0992: return newMetaComp;
0993: }
0994:
0995: private void addOtherComponent(RADComponent newMetaComp,
0996: RADComponent targetComp, boolean newlyAdded) {
0997: ComponentContainer targetCont = targetComp instanceof ComponentContainer
0998: && !(targetComp instanceof RADVisualContainer)
0999: && !(targetComp instanceof RADMenuComponent) ? (ComponentContainer) targetComp
1000: : null;
1001:
1002: if (!newlyAdded && (newMetaComp instanceof RADVisualComponent)) {
1003: ((RADVisualComponent) newMetaComp)
1004: .resetConstraintsProperties();
1005: }
1006: formModel.addComponent(newMetaComp, targetCont, newlyAdded);
1007: }
1008:
1009: private RADComponent setContainerLayout(Class layoutClass,
1010: RADComponent targetComp) {
1011: // get container on which the layout is to be set
1012: RADVisualContainer metacont;
1013: if (targetComp instanceof RADVisualContainer)
1014: metacont = (RADVisualContainer) targetComp;
1015: else {
1016: metacont = (RADVisualContainer) targetComp
1017: .getParentComponent();
1018: if (metacont == null)
1019: return null;
1020: }
1021:
1022: LayoutSupportDelegate layoutDelegate = null;
1023: Throwable t = null;
1024: try {
1025: if (LayoutManager.class.isAssignableFrom(layoutClass)) {
1026: // LayoutManager -> find LayoutSupportDelegate for it
1027: layoutDelegate = LayoutSupportRegistry.getRegistry(
1028: formModel).createSupportForLayout(layoutClass);
1029: } else if (LayoutSupportDelegate.class
1030: .isAssignableFrom(layoutClass)) {
1031: // LayoutSupportDelegate -> use it directly
1032: layoutDelegate = LayoutSupportRegistry
1033: .createSupportInstance(layoutClass);
1034: }
1035: } catch (Exception ex) {
1036: t = ex;
1037: } catch (LinkageError ex) {
1038: t = ex;
1039: }
1040: if (t != null) {
1041: String msg = FormUtils.getFormattedBundleString(
1042: "FMT_ERR_LayoutInit", // NOI18N
1043: new Object[] { layoutClass.getName() });
1044:
1045: ErrorManager em = ErrorManager.getDefault();
1046: em.annotate(t, msg);
1047: em.notify(t);
1048: return null;
1049: }
1050:
1051: if (layoutDelegate == null) {
1052: DialogDisplayer.getDefault().notify(
1053: new NotifyDescriptor.Message(FormUtils
1054: .getFormattedBundleString(
1055: "FMT_ERR_LayoutNotFound", // NOI18N
1056: new Object[] { layoutClass
1057: .getName() }),
1058: NotifyDescriptor.WARNING_MESSAGE));
1059:
1060: return null;
1061: }
1062:
1063: try {
1064: formModel.setContainerLayout(metacont, layoutDelegate);
1065: } catch (Exception ex) {
1066: t = ex;
1067: } catch (LinkageError ex) {
1068: t = ex;
1069: }
1070: if (t != null) {
1071: String msg = FormUtils.getFormattedBundleString(
1072: "FMT_ERR_LayoutInit", // NOI18N
1073: new Object[] { layoutClass.getName() });
1074:
1075: ErrorManager em = ErrorManager.getDefault();
1076: em.annotate(t, msg);
1077: em.notify(t);
1078: return null;
1079: }
1080:
1081: return metacont;
1082: }
1083:
1084: private RADComponent copyAndApplyLayout(RADComponent sourceComp,
1085: RADComponent targetComp) {
1086: try {
1087: RADVisualContainer targetCont = (RADVisualContainer) setContainerLayout(
1088: sourceComp.getBeanClass(), targetComp);
1089:
1090: // copy properties additionally to handle design values
1091: Node.Property[] sourceProps = sourceComp
1092: .getKnownBeanProperties();
1093: Node.Property[] targetProps = targetCont.getLayoutSupport()
1094: .getAllProperties();
1095: int copyMode = FormUtils.CHANGED_ONLY
1096: | FormUtils.DISABLE_CHANGE_FIRING;
1097: if (formModel == sourceComp.getFormModel())
1098: copyMode |= FormUtils.PASS_DESIGN_VALUES;
1099:
1100: FormUtils
1101: .copyProperties(sourceProps, targetProps, copyMode);
1102: } catch (Exception ex) { // ignore
1103: ErrorManager.getDefault().notify(
1104: ErrorManager.INFORMATIONAL, ex);
1105: } catch (LinkageError ex) { // ignore
1106: ErrorManager.getDefault().notify(
1107: ErrorManager.INFORMATIONAL, ex);
1108: }
1109:
1110: return targetComp;
1111: }
1112:
1113: private RADComponent setComponentBorder(Class borderClass,
1114: RADComponent targetComp) {
1115: FormProperty prop = getBorderProperty(targetComp);
1116: if (prop == null)
1117: return null;
1118:
1119: try { // set border property
1120: Object border = CreationFactory.createInstance(borderClass);
1121: prop.setValue(border);
1122: } catch (Exception ex) {
1123: showInstErrorMessage(ex);
1124: return null;
1125: } catch (LinkageError ex) {
1126: showInstErrorMessage(ex);
1127: return null;
1128: }
1129:
1130: FormDesigner designer = FormEditor.getFormDesigner(formModel);
1131: if (designer != null)
1132: designer.setSelectedComponent(targetComp);
1133:
1134: return targetComp;
1135: }
1136:
1137: private void setComponentBorderProperty(Object borderInstance,
1138: RADComponent targetComp) {
1139: FormProperty prop = getBorderProperty(targetComp);
1140: if (prop == null)
1141: return;
1142:
1143: try { // set border property
1144: prop.setValue(borderInstance);
1145: } catch (Exception ex) { // should not happen
1146: ex.printStackTrace();
1147: return;
1148: }
1149:
1150: FormDesigner designer = FormEditor.getFormDesigner(formModel);
1151: if (designer != null)
1152: designer.setSelectedComponent(targetComp);
1153: }
1154:
1155: private RADComponent copyAndApplyBorder(RADComponent sourceComp,
1156: RADComponent targetComp) {
1157: try {
1158: Border borderInstance = (Border) sourceComp
1159: .createBeanInstance();
1160: BorderDesignSupport designBorder = new BorderDesignSupport(
1161: borderInstance);
1162:
1163: Node.Property[] sourceProps = sourceComp
1164: .getKnownBeanProperties();
1165: Node.Property[] targetProps = designBorder.getProperties();
1166: int copyMode = FormUtils.CHANGED_ONLY
1167: | FormUtils.DISABLE_CHANGE_FIRING;
1168: if (formModel == sourceComp.getFormModel())
1169: copyMode |= FormUtils.PASS_DESIGN_VALUES;
1170:
1171: FormUtils
1172: .copyProperties(sourceProps, targetProps, copyMode);
1173:
1174: setComponentBorderProperty(designBorder, targetComp);
1175: } catch (Exception ex) { // ignore
1176: ErrorManager.getDefault().notify(
1177: ErrorManager.INFORMATIONAL, ex);
1178: } catch (LinkageError ex) { // ignore
1179: ErrorManager.getDefault().notify(
1180: ErrorManager.INFORMATIONAL, ex);
1181: }
1182:
1183: return targetComp;
1184: }
1185:
1186: private FormProperty getBorderProperty(RADComponent targetComp) {
1187: FormProperty prop;
1188: if (JComponent.class
1189: .isAssignableFrom(targetComp.getBeanClass())
1190: && (prop = targetComp.getBeanProperty("border")) != null) // NOI18N
1191: return prop;
1192:
1193: DialogDisplayer.getDefault().notify(
1194: new NotifyDescriptor.Message(FormUtils
1195: .getBundleString("MSG_BorderNotApplicable"), // NOI18N
1196: NotifyDescriptor.INFORMATION_MESSAGE));
1197:
1198: return null;
1199: }
1200:
1201: private RADComponent addMenuComponent(Class compClass,
1202: RADComponent targetComp) {
1203: // create new metacomponent
1204: RADMenuComponent newMenuComp;
1205: RADMenuItemComponent newMenuItemComp;
1206: if ((RADMenuItemComponent.recognizeType(compClass) & RADMenuItemComponent.MASK_CONTAINER) != 0) {
1207: newMenuComp = new RADMenuComponent();
1208: newMenuItemComp = newMenuComp;
1209: } else {
1210: newMenuComp = null;
1211: newMenuItemComp = new RADMenuItemComponent();
1212: }
1213:
1214: newMenuItemComp.initialize(formModel);
1215: if (!initComponentInstance(newMenuItemComp, compClass))
1216: return null;
1217: if (newMenuComp != null)
1218: newMenuComp.initSubComponents(new RADComponent[0]);
1219:
1220: // set some initial label
1221: if (newMenuItemComp.getBeanInstance() instanceof MenuItem) {
1222: MenuItem menu = (MenuItem) newMenuItemComp
1223: .getBeanInstance();
1224: if ("".equals(menu.getLabel())) { // NOI18N
1225: String label;
1226: if (menu instanceof PopupMenu) {
1227: label = FormUtils
1228: .getBundleString("FMT_LAB_PopupMenu"); // NOI18N
1229: } else if (menu instanceof Menu) {
1230: label = FormUtils.getBundleString("FMT_LAB_Menu"); // NOI18N
1231: } else if (menu instanceof CheckboxMenuItem) {
1232: label = FormUtils
1233: .getBundleString("FMT_LAB_CheckboxMenuItem"); // NOI18N
1234: } else {
1235: label = FormUtils
1236: .getBundleString("FMT_LAB_MenuItem"); // NOI18N
1237: }
1238: RADProperty prop = newMenuItemComp
1239: .getBeanProperty("label"); // NOI18N
1240: try {
1241: prop.setChangeFiring(false);
1242: prop.setValue(label);
1243: prop.setChangeFiring(true);
1244: } catch (Exception e) { // never mind, ignore
1245: }
1246: }
1247: }
1248:
1249: addMenuComponent(newMenuItemComp, targetComp, true);
1250:
1251: // for added new menu bar we add one menu so it is not empty
1252: if (newMenuComp != null) {
1253: int type = newMenuComp.getMenuItemType();
1254: if (type == RADMenuItemComponent.T_MENUBAR) {
1255: org.openide.util.datatransfer.NewType[] newTypes = newMenuComp
1256: .getNewTypes();
1257: if (newTypes.length > 0) {
1258: try {
1259: newTypes[0].create();
1260: } catch (java.io.IOException e) {
1261: } // ignore
1262: }
1263: }
1264: }
1265:
1266: return newMenuItemComp;
1267: }
1268:
1269: private void addMenuComponent(RADComponent newMenuComp,
1270: RADComponent targetComp, boolean newlyAdded) {
1271: Class beanClass = newMenuComp.getBeanClass();
1272: ComponentContainer menuContainer = null;
1273:
1274: if (targetComp instanceof RADMenuComponent) {
1275: // adding to a menu
1276: if (newMenuComp instanceof RADMenuItemComponent
1277: && ((RADMenuComponent) targetComp)
1278: .canAddItem(beanClass))
1279: menuContainer = (ComponentContainer) targetComp;
1280: } else if (targetComp instanceof RADVisualComponent) {
1281: RADVisualContainer targetCont = targetComp instanceof RADVisualContainer ? (RADVisualContainer) targetComp
1282: : (RADVisualContainer) targetComp
1283: .getParentComponent();
1284:
1285: if (targetCont != null
1286: && targetCont.getContainerMenu() == null
1287: && targetCont.canHaveMenu(beanClass))
1288: menuContainer = targetCont;
1289: }
1290:
1291: formModel.addComponent(newMenuComp, menuContainer, newlyAdded);
1292: }
1293:
1294: // --------
1295:
1296: Class prepareClass(final ClassSource classSource) {
1297: if (!classSource.hasEntries()) { // Just some optimization
1298: return prepareClass0(classSource);
1299: } else {
1300: try {
1301: return (Class) FormLAF.executeWithLookAndFeel(
1302: formModel, new Mutex.ExceptionAction() {
1303: public Object run() throws Exception {
1304: Class clazz = prepareClass0(classSource);
1305: if (clazz != null) {
1306: // Force creation of the default instance in the correct L&F context
1307: BeanSupport
1308: .getDefaultInstance(clazz);
1309: }
1310: return clazz;
1311: }
1312: });
1313: } catch (Exception ex) {
1314: // should not happen
1315: ex.printStackTrace();
1316: return null;
1317: }
1318: }
1319: }
1320:
1321: private Class prepareClass0(ClassSource classSource) {
1322: Throwable error = null;
1323: FileObject formFile = FormEditor.getFormDataObject(formModel)
1324: .getFormFile();
1325: String className = classSource.getClassName();
1326: Class loadedClass = null;
1327: try {
1328: if (!ClassPathUtils.checkUserClass(className, formFile)) {
1329: if (ClassPathUtils.updateProject(formFile, classSource) == null) {
1330: return null;
1331: }
1332: if (FormLAF.inLAFBlock()) {
1333: // Force update to new class loader
1334: FormLAF.setUseDesignerDefaults(null);
1335: FormLAF.setUseDesignerDefaults(formModel);
1336: }
1337: }
1338: loadedClass = ClassPathUtils.loadClass(className, formFile);
1339: } catch (Exception ex) {
1340: error = ex;
1341: } catch (LinkageError ex) {
1342: error = ex;
1343: }
1344:
1345: if (loadedClass == null) {
1346: showClassLoadingErrorMessage(error, classSource);
1347: }
1348:
1349: return loadedClass;
1350: }
1351:
1352: private boolean checkFormClass(Class<?> compClass) {
1353: if (formModel.getFormBaseClass().isAssignableFrom(compClass)) {
1354: String formClassBinaryName = getClassBinaryName(FormEditor
1355: .getFormDataObject(formModel).getPrimaryFile());
1356:
1357: if (formClassBinaryName.equals(compClass.getName())) {
1358: DialogDisplayer
1359: .getDefault()
1360: .notify(
1361: new NotifyDescriptor.Message(
1362: FormUtils
1363: .getBundleString("MSG_ERR_CannotAddForm"), // NOI18N
1364: NotifyDescriptor.WARNING_MESSAGE));
1365: return false;
1366: }
1367: }
1368: return true;
1369: }
1370:
1371: private static String getClassBinaryName(final FileObject fo) {
1372: final String[] result = new String[1];
1373: JavaSource js = JavaSource.forFileObject(fo);
1374: try {
1375: js.runUserActionTask(
1376: new CancellableTask<CompilationController>() {
1377: public void cancel() {
1378: }
1379:
1380: public void run(CompilationController controller)
1381: throws Exception {
1382: controller
1383: .toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
1384: for (Tree t : controller
1385: .getCompilationUnit()
1386: .getTypeDecls()) {
1387: if (t.getKind() == Tree.Kind.CLASS
1388: && fo
1389: .getName()
1390: .equals(
1391: ((ClassTree) t)
1392: .getSimpleName()
1393: .toString())) {
1394: TreePath classTreePath = controller
1395: .getTrees()
1396: .getPath(
1397: controller
1398: .getCompilationUnit(),
1399: t);
1400: Element classElm = controller
1401: .getTrees().getElement(
1402: classTreePath);
1403: result[0] = classElm != null ? controller
1404: .getElements()
1405: .getBinaryName(
1406: (TypeElement) classElm)
1407: .toString()
1408: : ""; // NOI18N
1409: break;
1410: }
1411: }
1412: }
1413: }, true);
1414: } catch (IOException ex) {
1415: Logger.getLogger(MetaComponentCreator.class.getName()).log(
1416: Level.SEVERE, ex.getMessage(), ex);
1417: }
1418: return result[0];
1419: }
1420:
1421: private static void showClassLoadingErrorMessage(Throwable ex,
1422: ClassSource classSource) {
1423: ErrorManager em = ErrorManager.getDefault();
1424: String msg = FormUtils
1425: .getFormattedBundleString(
1426: "FMT_ERR_CannotLoadClass4", // NOI18N
1427: new Object[] {
1428: classSource.getClassName(),
1429: ClassPathUtils
1430: .getClassSourceDescription(classSource) });
1431: em.annotate(ex, msg);
1432: em.notify(ErrorManager.USER, ex); // Issue 65116 - don't show the exception to the user
1433: em.notify(ErrorManager.INFORMATIONAL, ex); // Make sure the exception is in the console and log file
1434: }
1435:
1436: private boolean initComponentInstance(RADComponent metacomp,
1437: Class<?> compClass) {
1438:
1439: try {
1440: metacomp.initInstance(compClass);
1441: } catch (Exception ex) {
1442: showInstErrorMessage(ex);
1443: return false;
1444: } catch (LinkageError ex) {
1445: showInstErrorMessage(ex);
1446: return false;
1447: }
1448: return true;
1449: }
1450:
1451: private static void showInstErrorMessage(Throwable ex) {
1452: ErrorManager em = ErrorManager.getDefault();
1453: em.annotate(ex, FormUtils
1454: .getBundleString("MSG_ERR_CannotInstantiate")); // NOI18N
1455: em.notify(ex);
1456: }
1457:
1458: // --------
1459: // default component initialization
1460:
1461: private RADComponent defaultVisualComponentInit(
1462: RADVisualComponent newMetaComp) {
1463: Object comp = newMetaComp.getBeanInstance();
1464: String varName = newMetaComp.getName();
1465: // Map of propertyNames -> propertyValues
1466: Map<String, Object> changes = new HashMap<String, Object>();
1467:
1468: if (comp instanceof JLabel) {
1469: if ("".equals(((JLabel) comp).getText())) { // NOI18N
1470: changes.put("text", varName); // NOI18N
1471: }
1472: } else if (comp instanceof JTextField) {
1473: if ("".equals(((JTextField) comp).getText())) { // NOI18N
1474: changes.put("text", varName); // NOI18N
1475: }
1476: } else if (comp instanceof JMenuItem) {
1477: if ("".equals(((JMenuItem) comp).getText())) { // NOI18N
1478: String value;
1479: if (comp instanceof JCheckBoxMenuItem) {
1480: value = FormUtils
1481: .getBundleString("FMT_LAB_JCheckBoxMenuItem"); // NOI18N
1482: } else if (comp instanceof JMenu) {
1483: value = FormUtils.getBundleString("FMT_LAB_JMenu"); // NOI18N
1484: } else if (comp instanceof JRadioButtonMenuItem) {
1485: value = FormUtils
1486: .getBundleString("FMT_LAB_JRadioButtonMenuItem"); // NOI18N
1487: } else {
1488: value = FormUtils
1489: .getBundleString("FMT_LAB_JMenuItem"); // NOI18N
1490: }
1491: changes.put("text", value); // NOI18N
1492: }
1493: if (comp instanceof JCheckBoxMenuItem) {
1494: changes.put("selected", new Boolean(true)); // NOI18N
1495: }
1496: if (comp instanceof JRadioButtonMenuItem) {
1497: changes.put("selected", new Boolean(true)); // NOI18N
1498: }
1499: } else if (comp instanceof AbstractButton) { // JButton, JToggleButton, JCheckBox, JRadioButton
1500: String txt = ((AbstractButton) comp).getText();
1501: if ((txt == null) || "".equals(txt)) { // NOI18N
1502: changes.put("text", varName); // NOI18N
1503: }
1504: // if (comp instanceof JCheckBox || comp instanceof JRadioButton) {
1505: // if (((JToggleButton)comp).getBorder() instanceof javax.swing.plaf.UIResource) {
1506: // changes.put("border", BorderFactory.createEmptyBorder()); // NOI18N
1507: // changes.put("margin", new Insets(0, 0, 0, 0)); // NOI18N
1508: // }
1509: // }
1510: } else if (comp instanceof JTable) {
1511: javax.swing.table.TableModel tm = ((JTable) comp)
1512: .getModel();
1513: if (tm == null
1514: || (tm.getClass().equals(
1515: javax.swing.table.DefaultTableModel.class)
1516: && tm.getRowCount() == 0 && tm
1517: .getColumnCount() == 0)) {
1518: String prefix = NbBundle.getMessage(
1519: MetaComponentCreator.class,
1520: "FMT_CreatorTableTitle"); // NOI18N
1521: prefix += ' ';
1522: Object propValue = new org.netbeans.modules.form.editors2.TableModelEditor.NbTableModel(
1523: new javax.swing.table.DefaultTableModel(
1524: new String[] { prefix + 1, prefix + 2,
1525: prefix + 3, prefix + 4 }, 4));
1526: changes.put("model", propValue); // NOI18N
1527: }
1528: } else if (comp instanceof JToolBar) {
1529: changes.put("rollover", true); // NOI18N
1530: } else if (comp instanceof JInternalFrame) {
1531: changes.put("visible", true); // NOI18N
1532: } else if (comp instanceof Button) {
1533: if ("".equals(((Button) comp).getLabel())) { // NOI18N
1534: changes.put("label", varName); // NOI18N
1535: }
1536: } else if (comp instanceof Checkbox) {
1537: if ("".equals(((Checkbox) comp).getLabel())) { // NOI18N
1538: changes.put("label", varName); // NOI18N
1539: }
1540: } else if (comp instanceof Label) {
1541: if ("".equals(((Label) comp).getText())) { // NOI18N
1542: changes.put("text", varName); // NOI18N
1543: }
1544: } else if (comp instanceof TextField) {
1545: if ("".equals(((TextField) comp).getText())) { // NOI18N
1546: changes.put("text", varName); // NOI18N
1547: }
1548: } else if (comp instanceof JComboBox) {
1549: ComboBoxModel model = ((JComboBox) comp).getModel();
1550: if ((model == null) || (model.getSize() == 0)) {
1551: String prefix = NbBundle.getMessage(
1552: MetaComponentCreator.class,
1553: "FMT_CreatorComboBoxItem"); // NOI18N
1554: prefix += ' ';
1555: Object propValue = new DefaultComboBoxModel(
1556: new String[] { prefix + 1, prefix + 2,
1557: prefix + 3, prefix + 4 });
1558: changes.put("model", propValue); // NOI18N
1559: }
1560:
1561: } else if (comp instanceof JList) {
1562: ListModel model = ((JList) comp).getModel();
1563: if ((model == null) || (model.getSize() == 0)) {
1564: String prefix = NbBundle.getMessage(
1565: MetaComponentCreator.class,
1566: "FMT_CreatorListItem"); // NOI18N
1567: prefix += ' ';
1568: DefaultListModel defaultModel = new DefaultListModel();
1569: for (int i = 1; i < 6; i++) {
1570: defaultModel.addElement(prefix + i); // NOI18N
1571: }
1572: changes.put("model", defaultModel); // NOI18N
1573: }
1574: } else if (comp instanceof JTextArea) {
1575: JTextArea textArea = (JTextArea) comp;
1576: if (textArea.getRows() == 0) {
1577: changes.put("rows", new Integer(5)); // NOI18N
1578: }
1579: if (textArea.getColumns() == 0) {
1580: changes.put("columns", new Integer(20)); // NOI18N
1581: }
1582: }
1583:
1584: Iterator iter = changes.entrySet().iterator();
1585: while (iter.hasNext()) {
1586: Map.Entry change = (Map.Entry) iter.next();
1587: String propName = (String) change.getKey();
1588: Object propValue = change.getValue();
1589: FormProperty prop = newMetaComp.getBeanProperty(propName);
1590: if (prop != null) {
1591: try {
1592: prop.setChangeFiring(false);
1593: prop.setValue(propValue);
1594: prop.setChangeFiring(true);
1595: } catch (Exception e) {
1596: } // never mind, ignore
1597: }
1598: }
1599:
1600: // more initial modifications...
1601: if (shouldEncloseByScrollPane(newMetaComp.getBeanInstance())) {
1602: // hack: automatically enclose some components into scroll pane
1603: // [PENDING check for undo/redo!]
1604: RADVisualContainer metaScroll = (RADVisualContainer) createVisualComponent(JScrollPane.class);
1605: // Mark this scroll pane as automatically created.
1606: // Some action (e.g. delete) behave differently on
1607: // components in such scroll panes.
1608: metaScroll.setAuxValue("autoScrollPane", Boolean.TRUE); // NOI18N
1609: metaScroll.add(newMetaComp);
1610: Container scroll = (Container) metaScroll.getBeanInstance();
1611: Component inScroll = (Component) newMetaComp
1612: .getBeanInstance();
1613: metaScroll.getLayoutSupport().addComponentsToContainer(
1614: scroll, scroll, new Component[] { inScroll }, 0);
1615: newMetaComp = metaScroll;
1616: } else if (newMetaComp instanceof RADVisualContainer
1617: && newMetaComp.getBeanInstance() instanceof JMenuBar) {
1618: // for menubars create initial menu [temporary?]
1619: RADVisualContainer menuCont = (RADVisualContainer) newMetaComp;
1620: Container menuBar = (Container) menuCont.getBeanInstance();
1621: RADVisualComponent menuComp = createVisualComponent(JMenu.class);
1622: try {
1623: menuComp
1624: .getBeanProperty("text")
1625: // NOI18N
1626: .setValue(
1627: FormUtils
1628: .getBundleString("CTL_DefaultFileMenu")); // NOI18N
1629: } catch (Exception ex) {
1630: }
1631: Component menu = (Component) menuComp.getBeanInstance();
1632: menuCont.add(menuComp);
1633: menuCont.getLayoutSupport().addComponentsToContainer(
1634: menuBar, menuBar, new Component[] { menu }, 0);
1635:
1636: menuComp = createVisualComponent(JMenu.class);
1637: try {
1638: menuComp
1639: .getBeanProperty("text")
1640: // NOI18N
1641: .setValue(
1642: FormUtils
1643: .getBundleString("CTL_DefaultEditMenu")); // NOI18N
1644: } catch (Exception ex) {
1645: }
1646: menu = (Component) menuComp.getBeanInstance();
1647: menuCont.add(menuComp);
1648: menuCont.getLayoutSupport().addComponentsToContainer(
1649: menuBar, menuBar, new Component[] { menu }, 1);
1650: }
1651:
1652: return newMetaComp;
1653: }
1654:
1655: private static boolean shouldEncloseByScrollPane(Object bean) {
1656: return (bean instanceof JList) || (bean instanceof JTable)
1657: || (bean instanceof JTree)
1658: || (bean instanceof JTextArea)
1659: || (bean instanceof JTextPane)
1660: || (bean instanceof JEditorPane);
1661: }
1662:
1663: /**
1664: * Initial setting for components that can't be done until knowing where
1665: * they are to be added to (type of target container). E.g. button
1666: * properties are adjusted when added to a toolbar.
1667: */
1668: private static void defaultTargetInit(RADComponent metacomp,
1669: RADComponent target) {
1670: Object targetComp = target != null ? target.getBeanInstance()
1671: : null;
1672:
1673: if (metacomp.getBeanClass().equals(JSeparator.class)
1674: && targetComp instanceof JToolBar) {
1675: // hack: change JSeparator to JToolBar.Separator
1676: try {
1677: metacomp.initInstance(JToolBar.Separator.class);
1678: } catch (Exception ex) {
1679: } // should not fail with JDK class
1680: return;
1681: }
1682:
1683: Object comp = metacomp.getBeanInstance();
1684: Map<String, Object> changes = null;
1685:
1686: if (comp instanceof AbstractButton
1687: && targetComp instanceof JToolBar) {
1688: if (changes == null) {
1689: changes = new HashMap<String, Object>();
1690: }
1691: changes.put("focusable", false); // NOI18N
1692: changes
1693: .put("horizontalTextPosition",
1694: SwingConstants.CENTER); // NOI18N
1695: changes.put("verticalTextPosition", SwingConstants.BOTTOM); // NOI18N
1696: }
1697:
1698: if (changes != null) {
1699: for (Map.Entry<String, Object> e : changes.entrySet()) {
1700: FormProperty prop = metacomp
1701: .getBeanProperty(e.getKey());
1702: if (prop != null) {
1703: try {
1704: prop.setChangeFiring(false);
1705: prop.setValue(e.getValue());
1706: prop.setChangeFiring(true);
1707: } catch (Exception ex) {
1708: } // never mind, ignore
1709: }
1710: }
1711: }
1712: }
1713:
1714: private Dimension prepareDefaultLayoutSize(Component comp,
1715: boolean isContainer) {
1716: int width = -1;
1717: int height = -1;
1718: if (comp instanceof JToolBar) {
1719: width = 100;
1720: height = 25;
1721: } else if (isContainer) {
1722: Dimension pref = comp.getPreferredSize();
1723: if (pref.width < 16 && pref.height < 12) {
1724: if (comp instanceof Window
1725: || comp instanceof java.applet.Applet) {
1726:
1727: width = 400;
1728: height = 300;
1729: } else {
1730: width = 100;
1731: height = 100;
1732: }
1733: } else {
1734: Dimension designerSize = FormEditor.getFormDesigner(
1735: formModel).getDesignerSize();
1736: if (pref.width > designerSize.width
1737: || pref.height > designerSize.height) {
1738: width = Math.min(pref.width,
1739: designerSize.width - 25);
1740: height = Math.min(pref.height,
1741: designerSize.height - 25);
1742: }
1743: }
1744: } else if (comp instanceof JSeparator) {
1745: width = 50;
1746: height = 10;
1747: }
1748:
1749: if (width < 0 || height < 0)
1750: return null;
1751:
1752: Dimension size = new Dimension(width, height);
1753: if (comp instanceof JComponent) {
1754: ((JComponent) comp).setPreferredSize(size);
1755: }
1756: return size;
1757: }
1758:
1759: }
|