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 java.lang.reflect.Method;
0046: import javax.swing.*;
0047: import java.util.*;
0048: import java.util.logging.Level;
0049: import java.util.logging.Logger;
0050:
0051: import org.jdesktop.beansbinding.BindingGroup;
0052:
0053: import org.openide.ErrorManager;
0054:
0055: import org.netbeans.modules.form.fakepeer.FakePeerSupport;
0056: import org.netbeans.modules.form.layoutsupport.*;
0057: import org.netbeans.modules.form.layoutdesign.support.SwingLayoutBuilder;
0058:
0059: /**
0060: * This class replicates (clones) the reference instances from meta-components
0061: * of a form. This way an equal and independent hierarchy of real instances is
0062: * built. Components cloned this way are used in the ComponentLayer presenting
0063: * the form in designer, or by the TestAction. Thanks to mapping from meta
0064: * components to clones (and viceversa), effective incremental updates of
0065: * changes from metadata are possible.
0066: * Note: After updating replicated components, revalidate() and repaint()
0067: * should be called on the top component.
0068: *
0069: * @author Tomas Pavek
0070: */
0071:
0072: public class VisualReplicator {
0073:
0074: private RADComponent topMetaComponent;
0075:
0076: private Map<String, Object> idToClone = new HashMap<String, Object>();
0077: private Map<Object, String> cloneToId = new HashMap<Object, String>();
0078:
0079: private Map<String, SwingLayoutBuilder> layoutBuilders = new HashMap<String, SwingLayoutBuilder>();
0080:
0081: private BindingGroup bindingGroup;
0082: private BindingDesignSupport bindingSupport;
0083:
0084: private boolean designRestrictions;
0085:
0086: private ViewConverter[] converters;
0087:
0088: // ---------
0089:
0090: public VisualReplicator(boolean designRestrictions,
0091: ViewConverter[] converters,
0092: BindingDesignSupport bindingSupport) {
0093: this .designRestrictions = designRestrictions;
0094: this .converters = converters;
0095: this .bindingSupport = bindingSupport;
0096: }
0097:
0098: // ---------
0099: // mapping
0100:
0101: public Object getClonedComponent(RADComponent metacomp) {
0102: return metacomp != null ? idToClone.get(metacomp.getId())
0103: : null;
0104: }
0105:
0106: public Object getClonedComponent(String id) {
0107: return idToClone.get(id);
0108: }
0109:
0110: public String getClonedComponentId(Object component) {
0111: return cloneToId.get(component);
0112: }
0113:
0114: public Map<String, Object> getMapToClones() {
0115: return Collections.unmodifiableMap(idToClone);
0116: }
0117:
0118: // ---------
0119:
0120: private FormModel getFormModel() {
0121: return getTopMetaComponent().getFormModel();
0122: }
0123:
0124: SwingLayoutBuilder getLayoutBuilder(String containerId) {
0125: SwingLayoutBuilder builder = layoutBuilders.get(containerId);
0126: if (builder == null) {
0127: RADVisualContainer metacont = (RADVisualContainer) getFormModel()
0128: .getMetaComponent(containerId);
0129: Container cont = (Container) getClonedComponent(containerId);
0130: Container contDelegate = metacont
0131: .getContainerDelegate(cont);
0132:
0133: builder = new SwingLayoutBuilder(getFormModel()
0134: .getLayoutModel(), contDelegate, containerId,
0135: getDesignRestrictions());
0136: layoutBuilders.put(containerId, builder);
0137: }
0138: return builder;
0139: }
0140:
0141: private BindingGroup getBindingGroup() {
0142: if (bindingGroup == null) {
0143: bindingGroup = new BindingGroup();
0144: bindingGroup.bind();
0145: }
0146: return bindingGroup;
0147: }
0148:
0149: // ---------
0150: // getters & setters
0151:
0152: public RADComponent getTopMetaComponent() {
0153: return topMetaComponent;
0154: }
0155:
0156: public void setTopMetaComponent(RADComponent metacomponent) {
0157: topMetaComponent = metacomponent;
0158: idToClone.clear();
0159: cloneToId.clear();
0160: layoutBuilders.clear();
0161: bindingGroup = null;
0162: }
0163:
0164: public boolean getDesignRestrictions() {
0165: return designRestrictions;
0166: }
0167:
0168: // --------
0169: // executive public methods
0170:
0171: public Object createClone() {
0172: return createClone(getTopMetaComponent());
0173: }
0174:
0175: public Object createClone(RADComponent metacomp) {
0176: if (metacomp == null)
0177: return null;
0178:
0179: Object clone;
0180: java.util.List<RADProperty> relativeProperties = new ArrayList<RADProperty>();
0181:
0182: try {
0183: // clone the whole visual hierarchy recursively
0184: clone = cloneComponent(metacomp, relativeProperties);
0185:
0186: // set relative properties additionally
0187: if (!relativeProperties.isEmpty())
0188: copyRelativeProperties(relativeProperties);
0189:
0190: Map<String, Object> mapToClones = new HashMap<String, Object>(
0191: getMapToClones());
0192: FormModel formModel = getFormModel();
0193: Set<Map.Entry<String, Object>> entries = mapToClones
0194: .entrySet();
0195: for (Map.Entry<String, Object> entry : entries) {
0196: String id = entry.getKey();
0197: Object comp = entry.getValue();
0198: RADComponent rc = formModel.getMetaComponent(id);
0199: if (rc != null
0200: && (comp == null || !rc.getBeanClass()
0201: .isAssignableFrom(comp.getClass()))) {
0202: // was converted
0203: entry.setValue(rc.getBeanInstance());
0204: }
0205: }
0206: BindingGroup group = getBindingGroup();
0207: boolean restrictions = getDesignRestrictions();
0208: for (String id : mapToClones.keySet()) {
0209: RADComponent rc = formModel.getMetaComponent(id);
0210: if (rc != null) {
0211: if (restrictions) { // this is an updated view (designer)
0212: bindingSupport.establishUpdatedBindings(rc,
0213: false, mapToClones, group, false);
0214: // BindingDesignSupport will unbind and remove these bindings
0215: // automatically if user removes a binding or whole component
0216: } else { // this is a one-off view (preview)
0217: BindingDesignSupport.establishOneOffBindings(
0218: rc, false, mapToClones, group);
0219: }
0220: }
0221: }
0222: } catch (Exception ex) {
0223: ErrorManager.getDefault().notify(
0224: ErrorManager.INFORMATIONAL, ex);
0225: clone = null;
0226: }
0227:
0228: return clone;
0229: }
0230:
0231: public void reorderComponents(ComponentContainer metacont) {
0232: if (metacont instanceof RADVisualContainer) {
0233: updateContainerLayout((RADVisualContainer) metacont);
0234: } else if (metacont instanceof RADMenuComponent) { // AWT menu
0235: // using Swing equivalents of AWT menus for visualization in designer...
0236: Object menu = getClonedComponent((RADComponent) metacont);
0237: if (menu instanceof Container) {
0238: Container cont = (Container) menu;
0239: cont.removeAll();
0240: for (RADComponent metacomp : ((RADMenuComponent) metacont)
0241: .getSubBeans()) {
0242: addToMenu(cont, getClonedComponent(metacomp));
0243: }
0244: }
0245: }
0246: }
0247:
0248: public void updateContainerLayout(RADVisualContainer metacont) {
0249: Container cont = (Container) getClonedComponent(metacont);
0250: if (cont == null) // The container is not cloned by the replicator
0251: return; // see issue 63654
0252: Container contDelegate = metacont.getContainerDelegate(cont);
0253: LayoutSupportManager laysup = metacont.getLayoutSupport();
0254: SwingLayoutBuilder layoutBuilder;
0255:
0256: // clear the container first before setting/changing the layout
0257: if (laysup != null) { // old layout support
0258: layoutBuilder = null;
0259: layoutBuilders.remove(metacont.getId());
0260: laysup.clearContainer(cont, contDelegate);
0261: } else { // new layout support
0262: layoutBuilder = getLayoutBuilder(metacont.getId());
0263: layoutBuilder.clearContainer();
0264: }
0265:
0266: // update visual components
0267: RADVisualComponent[] metacomps = metacont.getSubComponents();
0268: Component[] comps = new Component[metacomps.length];
0269: String[] compIds = new String[metacomps.length];
0270:
0271: for (int i = 0; i < metacomps.length; i++) {
0272: RADVisualComponent metacomp = metacomps[i];
0273:
0274: Component comp = (Component) getClonedComponent(metacomp);
0275: if (comp == null)
0276: comp = (Component) createClone(metacomp);
0277: else {
0278: if (comp.getParent() != null)
0279: comp.getParent().remove(comp);
0280: }
0281:
0282: // make the component visible according to the explicitly set property
0283: // or component's original visibility
0284: Boolean visible = null;
0285: RADProperty visibilityProp = metacomp.getPropertyByName(
0286: "visible", RADProperty.class, false); // NOI18N
0287: if (visibilityProp != null && visibilityProp.isChanged()) {
0288: Object value;
0289: try {
0290: value = visibilityProp.getRealValue();
0291: } catch (Exception ex) { // should not happen
0292: value = null;
0293: }
0294: if (value instanceof Boolean)
0295: visible = (Boolean) value;
0296: }
0297: if (visible == null) {
0298: Component defaultComp = (Component) BeanSupport
0299: .getDefaultInstance(comp.getClass());
0300: if (defaultComp != null)
0301: visible = defaultComp.isVisible() ? Boolean.TRUE
0302: : Boolean.FALSE;
0303: }
0304: if (visible != null) {
0305: comp.setVisible(visible.booleanValue());
0306: }
0307:
0308: // re-attach fake peer
0309: FakePeerSupport.attachFakePeer(comp);
0310: if (comp instanceof Container)
0311: FakePeerSupport
0312: .attachFakePeerRecursively((Container) comp);
0313:
0314: comps[i] = comp;
0315: compIds[i] = metacomp.getId();
0316: }
0317:
0318: // set the layout and re-add the components
0319: if (laysup != null) { // old layout support
0320: laysup.setLayoutToContainer(cont, contDelegate);
0321: if (comps.length > 0)
0322: laysup.addComponentsToContainer(cont, contDelegate,
0323: comps, 0);
0324: laysup.arrangeContainer(cont, contDelegate);
0325: } else { // new layout support
0326: // Re-attach fake peers
0327: contDelegate.removeAll();
0328: for (int i = 0; i < comps.length; i++) {
0329: FakePeerSupport.attachFakePeer(comps[i]);
0330: if (comps[i] instanceof Container)
0331: FakePeerSupport
0332: .attachFakePeerRecursively((Container) comps[i]);
0333: }
0334:
0335: setupContainerLayout(layoutBuilder, comps, compIds);
0336: }
0337: }
0338:
0339: public void updateAddedComponents(ComponentContainer metacont) {
0340: Container container = null;
0341: if (metacont instanceof RADComponent) {
0342: Object contClone = getClonedComponent((RADComponent) metacont);
0343: if (contClone instanceof Container) {
0344: if (metacont instanceof RADVisualContainer) {
0345: RADVisualContainer visualMetaCont = (RADVisualContainer) metacont;
0346: if (visualMetaCont.getLayoutSupport() == null) {
0347: // don't try incremental update with new layout support
0348: updateContainerLayout(visualMetaCont);
0349: // layout is built, but we continue to also add e.g. menu bar
0350: }
0351: container = visualMetaCont
0352: .getContainerDelegate((Container) contClone);
0353: } else
0354: container = (Container) contClone;
0355: }
0356: }
0357:
0358: RADComponent[] subComps = metacont.getSubBeans();
0359: for (int i = 0; i < subComps.length; i++) {
0360: Object compClone = getClonedComponent(subComps[i]);
0361: if (compClone == null)
0362: addComponent(subComps[i]);
0363: else if (compClone instanceof Component) {
0364: Container cloneCont = ((Component) compClone)
0365: .getParent();
0366: if (cloneCont != container
0367: && cloneToId.get(cloneCont) != null)
0368: return; // the clone is placed in another container in
0369: } // replicator, there's going to be another update
0370: }
0371: }
0372:
0373: // for adding just one component, for adding more components use
0374: // updateAddedComponents
0375: public void addComponent(RADComponent metacomp) {
0376: if (metacomp == null)
0377: return;
0378: if (getClonedComponent(metacomp) != null)
0379: return;
0380:
0381: if (metacomp instanceof RADVisualComponent) {
0382: Object clone = createClone(metacomp);
0383: if (!(clone instanceof Component))
0384: return;
0385:
0386: RADVisualContainer metacont = (RADVisualContainer) metacomp
0387: .getParentComponent();
0388: Container cont = (Container) getClonedComponent(metacont);
0389: if (metacomp == metacont.getContainerMenu()) {
0390: setContainerMenu(cont, clone);
0391: } else if (metacont.isMenuTypeComponent()) {
0392: addToMenu(cont, clone);
0393: } else {
0394: LayoutSupportManager laysup = metacont
0395: .getLayoutSupport();
0396: if (laysup != null) { // old layout support
0397: if (cont == null)
0398: return;
0399: Container contDelegate = metacont
0400: .getContainerDelegate(cont);
0401: laysup.addComponentsToContainer(cont, contDelegate,
0402: new Component[] { (Component) clone },
0403: ((RADVisualComponent) metacomp)
0404: .getComponentIndex());
0405: laysup.arrangeContainer(cont, contDelegate);
0406: }
0407: // else { // new layout support
0408: // getLayoutBuilder(metacont.getId()).addComponentsToContainer(
0409: // new Component[] { (Component) clone },
0410: // new String[] { metacomp.getId() } );
0411: // }
0412: }
0413: } else if (metacomp instanceof RADMenuItemComponent) {
0414: Object clone = createClone(metacomp);
0415:
0416: RADComponent menuCont = metacomp.getParentComponent();
0417: if (menuCont == null)
0418: return; // should not happen
0419:
0420: Object cont = getClonedComponent(menuCont);
0421: if (menuCont instanceof RADVisualContainer)
0422: setContainerMenu((Container) cont, clone);
0423: else
0424: addToMenu(cont, clone);
0425: }
0426: }
0427:
0428: public void removeComponent(RADComponent metacomp,
0429: ComponentContainer metacont) {
0430: if (metacomp == null)
0431: return;
0432:
0433: Object clone = getClonedComponent(metacomp);
0434: if (clone == null)
0435: return;
0436:
0437: if (clone instanceof JMenuBar) { // JMenuBar meta component was removed
0438: // reset JMenuBar in JRootPane
0439: Container menuParent = ((Component) clone).getParent();
0440: Container cont = menuParent;
0441: while (cont != null && !(cont instanceof JRootPane))
0442: cont = cont.getParent();
0443:
0444: if (cont != null)
0445: ((JRootPane) cont).setJMenuBar(null);
0446: else if (menuParent != null)
0447: menuParent.remove((Component) clone);
0448: else
0449: return;
0450: } else if (clone instanceof Component) { // visual meta component was removed
0451: Component comp = (Component) clone;
0452: // do we know the parent container of the removed meta component?
0453: RADVisualContainer parentCont = metacont instanceof RADVisualContainer ? (RADVisualContainer) metacont
0454: : null;
0455: Container cont = parentCont != null ? (Container) getClonedComponent(parentCont)
0456: : null;
0457:
0458: if (cont == null) {
0459: // we don't know the meta container (layout support), so will
0460: // just simply remove the component from its parent
0461: if (comp.getParent() != null)
0462: comp.getParent().remove(comp);
0463: } else { // let the layout support remove the visual component
0464: Container contDelegate = parentCont
0465: .getContainerDelegate(cont);
0466: LayoutSupportManager laysup = parentCont
0467: .getLayoutSupport();
0468: if (laysup != null) { // old layout support
0469: if (!laysup.removeComponentFromContainer(cont,
0470: contDelegate, comp)) { // layout delegate cannot remove individual components,
0471: // we must clear the container and add the components again
0472: laysup.clearContainer(cont, contDelegate);
0473:
0474: RADVisualComponent[] metacomps = parentCont
0475: .getSubComponents();
0476: if (metacomps.length > 0) {
0477: // we assume the metacomponent is already removed
0478: Component[] comps = new Component[metacomps.length];
0479: for (int i = 0; i < metacomps.length; i++) {
0480: comp = (Component) getClonedComponent(metacomps[i]);
0481: // becaues the components were removed, we must
0482: // re-attach their fake peers (if needed)
0483: FakePeerSupport.attachFakePeer(comp);
0484: if (comp instanceof Container)
0485: FakePeerSupport
0486: .attachFakePeerRecursively((Container) comp);
0487: comps[i] = comp;
0488: }
0489: laysup.addComponentsToContainer(cont,
0490: contDelegate, comps, 0);
0491: }
0492: }
0493: } else { // new layout support
0494: // Re-attach fake peers
0495: contDelegate.removeAll();
0496: RADVisualComponent[] metacomps = parentCont
0497: .getSubComponents();
0498: for (int i = 0; i < metacomps.length; i++) {
0499: Component component = (Component) getClonedComponent(metacomps[i]);
0500: FakePeerSupport.attachFakePeer(component);
0501: if (component instanceof Container)
0502: FakePeerSupport
0503: .attachFakePeerRecursively((Container) component);
0504: }
0505:
0506: getLayoutBuilder(parentCont.getId())
0507: .removeComponentsFromContainer(
0508: new Component[] { comp },
0509: new String[] { metacomp.getId() });
0510: }
0511: }
0512: // fallback - workaround for issue 118019, for example
0513: if (comp.getParent() != null) {
0514: comp.getParent().remove(comp);
0515: }
0516: } else if (clone instanceof MenuComponent) { // AWT menu
0517: MenuComponent menuComp = (MenuComponent) clone;
0518: MenuContainer menuCont = menuComp.getParent();
0519: if (menuCont != null)
0520: menuCont.remove(menuComp);
0521: else
0522: return;
0523: }
0524:
0525: removeMapping(metacomp);
0526: }
0527:
0528: public void updateComponentProperty(RADProperty property) {
0529: if (property == null)
0530: return;
0531:
0532: RADComponent metacomp = property.getRADComponent();
0533:
0534: // target component of the property
0535: Object targetComp = getClonedComponent(metacomp);
0536: if (targetComp == null)
0537: return;
0538:
0539: // Scrollbar hack - to change some properties of AWT Scrollbar we
0540: // must create a new instance of Scrollbar (peer must be recreated)
0541: // [maybe this should be done for all AWT components]
0542: if (targetComp instanceof java.awt.Scrollbar) {
0543: // remove the component and add a new clone
0544: removeComponent(metacomp, null);
0545: addComponent(metacomp);
0546: return;
0547: }
0548:
0549: // keep double buffering turned off for JComponent in fake peer container
0550: // and also keep debugGraphicsOptions turned off
0551: if (targetComp instanceof JComponent && getDesignRestrictions() // & ATTACH_FAKE_PEERS) != 0
0552: && (("doubleBuffered".equals(property.getName()) // NOI18N
0553: && hasAwtParent(metacomp)) || "debugGraphicsOptions"
0554: .equals(property.getName()))) // NOI18N
0555: return;
0556:
0557: // Mnemonics support - start -
0558: if ("text".equals(property.getName()) // NOI18N
0559: && (targetComp instanceof AbstractButton || targetComp instanceof JLabel)
0560: && JavaCodeGenerator.isUsingMnemonics(property
0561: .getRADComponent())) {
0562: try {
0563: String str = (String) property.getRealValue();
0564: if (targetComp instanceof JLabel)
0565: org.openide.awt.Mnemonics.setLocalizedText(
0566: (JLabel) targetComp, str);
0567: else
0568: org.openide.awt.Mnemonics.setLocalizedText(
0569: (AbstractButton) targetComp, str);
0570: return;
0571: } catch (Exception ex) {
0572: } // ignore and continue
0573: }
0574: // Mnemonics support - end -
0575:
0576: Method writeMethod = FormUtils.getPropertyWriteMethod(property,
0577: targetComp.getClass());
0578: if (writeMethod == null)
0579: return;
0580:
0581: try {
0582: Object value = property.getValue();
0583: RADComponent valueComp;
0584: if (value instanceof RADComponent.ComponentReference) {
0585: valueComp = ((RADComponent.ComponentReference) value)
0586: .getComponent();
0587: } else if (FormUtils.isRelativeConnectionValue(value)) {
0588: valueComp = ((RADConnectionPropertyEditor.RADConnectionDesignValue) value)
0589: .getRADComponent();
0590: } else {
0591: valueComp = null;
0592: }
0593:
0594: Object clonedValue;
0595: if (valueComp != null) {
0596: // the value is another component (relative property)
0597: Object clonedComp = getClonedComponent(valueComp);
0598: if (clonedComp == null) { // there's no cloned instance yet
0599: clonedComp = createClone(valueComp);
0600: }
0601: if (value instanceof RADConnectionPropertyEditor.RADConnectionDesignValue) {
0602: clonedValue = ((RADConnectionPropertyEditor.RADConnectionDesignValue) value)
0603: .getValueForBean(clonedComp);
0604: } else {
0605: clonedValue = clonedComp;
0606: }
0607: } else { // this is not a relative property (another component)
0608: clonedValue = null;
0609: if (value instanceof FormDesignValue) {
0610: clonedValue = ((FormDesignValue) value)
0611: .getDesignValue(targetComp);
0612: }
0613: if (clonedValue == null) {
0614: Object realValue = property.getRealValue();
0615: if (realValue == FormDesignValue.IGNORED_VALUE) {
0616: return; // ignore the value, as it is not a real value
0617: }
0618: clonedValue = FormUtils.cloneObject(realValue,
0619: property.getPropertyContext()
0620: .getFormModel());
0621: }
0622: }
0623:
0624: writeMethod
0625: .invoke(targetComp, new Object[] { clonedValue });
0626:
0627: if (targetComp instanceof Component) {
0628: ((Component) targetComp).invalidate();
0629: }
0630: } catch (CloneNotSupportedException ex) { // ignore cloning failure
0631: } catch (Exception ex) {
0632: Logger.getLogger(VisualReplicator.class.getName()).log(
0633: Level.INFO, null, ex); // NOI18N
0634: }
0635: }
0636:
0637: public void updateBinding(MetaBinding newBinding) {
0638: if (newBinding != null && bindingSupport != null) {
0639: RADComponent metaTarget = newBinding.getTarget();
0640: // Converted components may not have the right properties to bind to
0641: Object target = isConverted(metaTarget) ? metaTarget
0642: .getBeanInstance() : getClonedComponent(metaTarget);
0643: if (target != null) {
0644: RADComponent metaSource = newBinding.getSource();
0645: Object source = isConverted(metaSource) ? metaSource
0646: .getBeanInstance()
0647: : getClonedComponent(metaSource);
0648: if (source == null) // source not cloned - let's use the bean instance directly
0649: source = newBinding.getSource().getBeanInstance();
0650: bindingSupport.addBinding(newBinding, source, target,
0651: getBindingGroup(), false);
0652: }
0653: }
0654: }
0655:
0656: // ---------
0657: // executive private methods
0658:
0659: // recursive method
0660: private Object cloneComponent(RADComponent metacomp,
0661: java.util.List<RADProperty> relativeProperties)
0662: throws Exception {
0663: Object clone = null; // cloned instance to return
0664: Object compClone = null; // clone of the component itself, might be "inside"
0665: // the returned clone - e.g. JPanel enclosed in JFrame by a converter
0666:
0667: for (ViewConverter converter : converters) {
0668: ViewConverter.Convert convert = converter.convert(metacomp
0669: .getBeanInstance(),
0670: metacomp == getTopMetaComponent(),
0671: getDesignRestrictions());
0672: if (convert != null) {
0673: clone = convert.getConverted();
0674: compClone = convert.getEnclosed();
0675:
0676: Iterator<RADProperty> applyProperties;
0677: if (clone instanceof Window) { // some properties should not be set to Window, e.g. visible
0678: applyProperties = metacomp
0679: .getBeanPropertiesIterator(
0680: new FormProperty.Filter() {
0681: public boolean accept(
0682: FormProperty property) {
0683: return !"visible"
0684: .equals(property
0685: .getName()); // NOI18N
0686: }
0687: }, false);
0688: } else {
0689: applyProperties = Arrays.asList(
0690: metacomp.getKnownBeanProperties())
0691: .iterator();
0692: }
0693: FormUtils.copyPropertiesToBean(applyProperties,
0694: compClone != null ? compClone : clone,
0695: relativeProperties);
0696: break;
0697: }
0698: }
0699:
0700: if (clone == null) { // no converter applied, clone the standard way
0701: clone = metacomp.cloneBeanInstance(relativeProperties);
0702: }
0703:
0704: if (clone == null) {
0705: return null;
0706: }
0707:
0708: if (compClone == null) {
0709: compClone = clone;
0710: }
0711:
0712: idToClone.put(metacomp.getId(), compClone);
0713: cloneToId.put(compClone, metacomp.getId());
0714:
0715: if (compClone instanceof java.beans.DesignMode) {
0716: ((java.beans.DesignMode) compClone)
0717: .setDesignTime(getDesignRestrictions());
0718: }
0719:
0720: if (metacomp instanceof RADVisualContainer) {
0721: RADVisualContainer metacont = (RADVisualContainer) metacomp;
0722: final Container cont = (Container) compClone;
0723: final Container contDelegate = metacont
0724: .getContainerDelegate(cont);
0725:
0726: // clone menu
0727: if (metacont.getContainerMenu() != null) {
0728: Object menu = cloneComponent(metacont
0729: .getContainerMenu(), relativeProperties);
0730: setContainerMenu(cont, menu);
0731: }
0732:
0733: // clone subcomponents
0734: RADVisualComponent[] metacomps = metacont
0735: .getSubComponents();
0736: final Component[] comps = new Component[metacomps.length];
0737: String[] compIds = new String[metacomps.length];
0738: for (int i = 0; i < metacomps.length; i++) {
0739: RADComponent sub = metacomps[i];
0740: Component subClone = (Component) getClonedComponent(sub);
0741: if (subClone == null) {
0742: subClone = (Component) cloneComponent(sub,
0743: relativeProperties);
0744: }
0745: comps[i] = subClone;
0746: compIds[i] = sub.getId();
0747: }
0748:
0749: if (metacont.isMenuTypeComponent()) {
0750: for (Component comp : comps) {
0751: addToMenu(cont, comp);
0752: }
0753: } else { // set layout
0754: final LayoutSupportManager laysup = metacont
0755: .getLayoutSupport();
0756: if (laysup != null) { // old layout support
0757: laysup.setLayoutToContainer(cont, contDelegate);
0758: if (comps.length > 0) { // add cloned subcomponents to container
0759: laysup.addComponentsToContainer(cont,
0760: contDelegate, comps, 0);
0761: }
0762: laysup.arrangeContainer(cont, contDelegate);
0763: } else { // new layout support
0764: setupContainerLayout(getLayoutBuilder(metacont
0765: .getId()), comps, compIds);
0766: }
0767: }
0768: } else if (metacomp instanceof RADMenuComponent) {
0769: RADComponent[] metacomps = ((RADMenuComponent) metacomp)
0770: .getSubBeans();
0771: for (int i = 0; i < metacomps.length; i++) {
0772: RADComponent sub = metacomps[i];
0773: Object menuItem = getClonedComponent(sub);
0774: if (menuItem == null) {
0775: menuItem = cloneComponent(
0776: (RADMenuItemComponent) sub,
0777: relativeProperties);
0778: }
0779: addToMenu(compClone, menuItem);
0780: }
0781: }
0782:
0783: if (clone instanceof Component && getDesignRestrictions()) {
0784: FakePeerSupport.attachFakePeer((Component) clone);
0785: if (clone instanceof Container)
0786: FakePeerSupport
0787: .attachFakePeerRecursively((Container) clone);
0788:
0789: if (clone instanceof JComponent) {
0790: // turn off double buffering for JComponent in fake peer container
0791: if (hasAwtParent(metacomp))
0792: setDoubleBufferedRecursively((JComponent) clone,
0793: false);
0794: // make sure debug graphics options is turned off
0795: ((JComponent) clone)
0796: .setDebugGraphicsOptions(DebugGraphics.NONE_OPTION);
0797: }
0798: disableFocusing((Component) clone);
0799:
0800: // patch for JDK 1.4 - hide glass pane of JInternalFrame
0801: if (clone instanceof JInternalFrame)
0802: ((JInternalFrame) clone).getGlassPane().setVisible(
0803: false);
0804: }
0805:
0806: // Mnemonics support - start -
0807: if ((clone instanceof AbstractButton || clone instanceof JLabel)
0808: && JavaCodeGenerator.isUsingMnemonics(metacomp)) {
0809: FormProperty prop = metacomp.getBeanProperty("text"); // NOI18N
0810: if (prop != null && prop.isChanged()) {
0811: try {
0812: String str = (String) prop.getRealValue();
0813: if (clone instanceof JLabel)
0814: org.openide.awt.Mnemonics.setLocalizedText(
0815: (JLabel) clone, str);
0816: else
0817: org.openide.awt.Mnemonics.setLocalizedText(
0818: (AbstractButton) clone, str);
0819: } catch (Exception ex) {
0820: } // ignore
0821: }
0822: }
0823: // Mnemonics support - end -
0824:
0825: return clone;
0826: }
0827:
0828: private boolean isConverted(RADComponent metacomp) {
0829: Object comp = getClonedComponent(metacomp);
0830: return comp != null
0831: && !metacomp.getBeanClass().isAssignableFrom(
0832: comp.getClass());
0833: }
0834:
0835: private void setupContainerLayout(SwingLayoutBuilder layoutBuilder,
0836: Component[] comps, String[] compIds) {
0837: Throwable th = null;
0838: try {
0839: layoutBuilder.setupContainerLayout(comps, compIds);
0840: } catch (Exception ex) {
0841: th = ex;
0842: } catch (Error err) {
0843: th = err;
0844: }
0845: if (th != null) {
0846: ErrorManager.getDefault().notify(th);
0847: getFormModel().forceUndoOfCompoundEdit();
0848: }
0849: }
0850:
0851: private static void disableFocusing(Component comp) {
0852: comp.setFocusable(false);
0853: if (comp instanceof Container) {
0854: Container cont = (Container) comp;
0855: for (int i = 0, n = cont.getComponentCount(); i < n; i++)
0856: disableFocusing(cont.getComponent(i));
0857: }
0858: }
0859:
0860: private static void setContainerMenu(Container cont, Object menu) {
0861: if (cont instanceof RootPaneContainer) {
0862: if (menu instanceof JMenuBar)
0863: ((RootPaneContainer) cont).getRootPane().setJMenuBar(
0864: (JMenuBar) menu);
0865: } else if (cont instanceof JRootPane) {
0866: if (menu instanceof JMenuBar)
0867: ((JRootPane) cont).setJMenuBar((JMenuBar) menu);
0868: } else if (cont instanceof Frame) {
0869: if (menu instanceof MenuBar)
0870: ((Frame) cont).setMenuBar((MenuBar) menu);
0871: }
0872: }
0873:
0874: private static void addToMenu(Object menu, Object menuItem) {
0875: if (menu instanceof JMenuBar) {
0876: ((JMenuBar) menu).add((JMenu) menuItem);
0877: } else if (menu instanceof JMenu) {
0878: if (menuItem instanceof JMenuItem)
0879: ((JMenu) menu).add((JMenuItem) menuItem);
0880: else
0881: ((JMenu) menu).addSeparator();
0882: } else if (menu instanceof MenuBar) {
0883: ((MenuBar) menu).add((Menu) menuItem);
0884: } else if (menu instanceof Menu) {
0885: if (menuItem instanceof MenuItem)
0886: ((Menu) menu).add((MenuItem) menuItem);
0887: else
0888: ((Menu) menu).addSeparator();
0889: }
0890: }
0891:
0892: // mapping of AWT menu component to a Swing equivalent
0893: private static Class convertMenuClassToSwing(Class menuClass) {
0894: if (MenuBar.class.isAssignableFrom(menuClass))
0895: return JMenuBar.class;
0896: if (PopupMenu.class.isAssignableFrom(menuClass))
0897: return JPopupMenu.class;
0898: if (Menu.class.isAssignableFrom(menuClass))
0899: return JMenu.class;
0900: if (CheckboxMenuItem.class.isAssignableFrom(menuClass))
0901: return JCheckBoxMenuItem.class;
0902: if (MenuItem.class.isAssignableFrom(menuClass))
0903: return JMenuItem.class;
0904:
0905: return menuClass;
0906: }
0907:
0908: private static boolean hasAwtParent(RADComponent metacomp) {
0909: RADComponent parent = metacomp.getParentComponent();
0910: while (parent != null) {
0911: Class beanClass = parent.getBeanClass();
0912: if (Component.class.isAssignableFrom(beanClass)
0913: && !JComponent.class.isAssignableFrom(beanClass)
0914: && !RootPaneContainer.class
0915: .isAssignableFrom(beanClass)) { // this is AWT component
0916: return true;
0917: }
0918:
0919: parent = parent.getParentComponent();
0920: }
0921: return false;
0922: }
0923:
0924: private static void setDoubleBufferedRecursively(
0925: JComponent component, boolean value) {
0926: component.setDoubleBuffered(value);
0927: Component[] subcomps = component.getComponents();
0928: for (int i = 0; i < subcomps.length; i++)
0929: if (subcomps[i] instanceof JComponent)
0930: setDoubleBufferedRecursively((JComponent) subcomps[i],
0931: value);
0932: }
0933:
0934: // -------
0935:
0936: // method for setting "relative" component properties additionaly
0937: private void copyRelativeProperties(
0938: java.util.List<RADProperty> relativeProperties) {
0939: for (int i = 0; i < relativeProperties.size(); i++) {
0940: RADProperty property = relativeProperties.get(i);
0941: try {
0942: Object value = property.getValue();
0943: RADComponent valueComp;
0944: if (value instanceof RADComponent.ComponentReference) {
0945: valueComp = ((RADComponent.ComponentReference) value)
0946: .getComponent();
0947: } else if (FormUtils.isRelativeConnectionValue(value)) {
0948: valueComp = ((RADConnectionPropertyEditor.RADConnectionDesignValue) value)
0949: .getRADComponent();
0950: } else {
0951: valueComp = null;
0952: }
0953:
0954: if (valueComp != null) {
0955: // the value is another component (relative property)
0956: Object clonedComp = getClonedComponent(valueComp);
0957: if (clonedComp == null) { // there's no cloned instance yet
0958: clonedComp = cloneComponent(valueComp,
0959: relativeProperties);
0960: }
0961: Object clonedValue;
0962: if (value instanceof RADConnectionPropertyEditor.RADConnectionDesignValue) {
0963: clonedValue = ((RADConnectionPropertyEditor.RADConnectionDesignValue) value)
0964: .getValueForBean(clonedComp);
0965: } else {
0966: clonedValue = clonedComp;
0967: }
0968:
0969: // target component of the property
0970: Object targetComp = getClonedComponent(property
0971: .getRADComponent());
0972:
0973: Method writeMethod = FormUtils
0974: .getPropertyWriteMethod(property,
0975: targetComp.getClass());
0976: if (writeMethod != null) {
0977: writeMethod.invoke(targetComp,
0978: new Object[] { clonedValue });
0979: } else if (clonedValue instanceof ButtonGroup
0980: && targetComp instanceof AbstractButton) { // special case - add button to button group
0981: ((ButtonGroup) clonedValue)
0982: .remove((AbstractButton) targetComp);
0983: ((ButtonGroup) clonedValue)
0984: .add((AbstractButton) targetComp);
0985: }
0986: }
0987: } catch (Exception ex) {
0988: } // should not happen, ignore
0989: }
0990: }
0991:
0992: private void removeMapping(RADComponent metacomp) {
0993: Object comp = idToClone.remove(metacomp.getId());
0994: if (comp != null)
0995: cloneToId.remove(comp);
0996:
0997: if (metacomp instanceof ComponentContainer) {
0998: layoutBuilders.remove(metacomp.getId());
0999: RADComponent[] subcomps = ((ComponentContainer) metacomp)
1000: .getSubBeans();
1001: for (int i = 0; i < subcomps.length; i++)
1002: removeMapping(subcomps[i]);
1003: }
1004: }
1005:
1006: // -----
1007:
1008: public static class DefaultConverter implements ViewConverter {
1009: public Convert convert(Object component, boolean root,
1010: boolean designRestrictions) {
1011: Class compClass = component.getClass();
1012: Class convClass = null;
1013: if (designRestrictions) { // convert windows and AWT menus for design view
1014: if ((RootPaneContainer.class
1015: .isAssignableFrom(compClass) && Window.class
1016: .isAssignableFrom(compClass))
1017: || Frame.class.isAssignableFrom(compClass)) {
1018: convClass = JRootPane.class;
1019: } else if (Window.class.isAssignableFrom(compClass)
1020: || java.applet.Applet.class
1021: .isAssignableFrom(compClass)) {
1022: convClass = Panel.class;
1023: } else if (MenuComponent.class
1024: .isAssignableFrom(compClass)) {
1025: convClass = convertMenuClassToSwing(compClass);
1026: }
1027: } else if (root) { // need to enclose in JFrame/Frame for preview
1028: if (RootPaneContainer.class.isAssignableFrom(compClass)
1029: || JComponent.class.isAssignableFrom(compClass)) { // Swing
1030: if (!JFrame.class.isAssignableFrom(compClass)) {
1031: convClass = JFrame.class;
1032: }
1033: } else if (Component.class.isAssignableFrom(compClass)) { // AWT
1034: if (!Frame.class.isAssignableFrom(compClass)) {
1035: convClass = Frame.class;
1036: }
1037: }
1038: }
1039: if (convClass == null) {
1040: return null; // no conversion needed
1041: }
1042:
1043: try {
1044: Component converted = (Component) CreationFactory
1045: .createDefaultInstance(convClass);
1046: Component enclosed = null;
1047:
1048: if (converted instanceof JFrame) {
1049: if (JComponent.class.isAssignableFrom(compClass)
1050: && !RootPaneContainer.class
1051: .isAssignableFrom(compClass)) {
1052: // JComponent but not JInternalFrame
1053: enclosed = (Component) CreationFactory
1054: .createDefaultInstance(compClass);
1055: ((JFrame) converted).getContentPane().add(
1056: enclosed);
1057: }
1058: } else if (converted instanceof JRootPane) { // RootPaneContainer or Frame converted to JRootPane
1059: Container contentCont = (Container) CreationFactory
1060: .createDefaultInstance(RootPaneContainer.class
1061: .isAssignableFrom(compClass) ? JPanel.class
1062: : Panel.class);
1063: ((JRootPane) converted).setContentPane(contentCont);
1064: } else if (MenuItem.class.isAssignableFrom(compClass)) { // converted AWT menu
1065: ((JMenuItem) converted)
1066: .setText(((MenuItem) component).getLabel());
1067: ((JMenuItem) converted)
1068: .setFont(((MenuItem) component).getFont());
1069: }
1070:
1071: return new ConvertResult(converted, enclosed);
1072: } catch (Exception ex) { // some instance creation failed, very unlikely to happen
1073: Logger.getLogger(VisualReplicator.class.getName()).log(
1074: Level.INFO, null, ex);
1075: return null;
1076: }
1077: }
1078:
1079: public boolean canVisualize(Class componentClass) {
1080: return false; // not able to visualize non-visual components
1081: // AWT menus are converted, but never used as the root in the design view
1082: }
1083: }
1084:
1085: private static class ConvertResult implements ViewConverter.Convert {
1086: private Object converted;
1087: private Object enclosed;
1088:
1089: ConvertResult(Object converted, Object enclosed) {
1090: this .converted = converted;
1091: this .enclosed = enclosed;
1092: }
1093:
1094: public Object getConverted() {
1095: return converted;
1096: }
1097:
1098: public Object getEnclosed() {
1099: return enclosed;
1100: }
1101: }
1102: }
|