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.awt.event.KeyEvent;
0046: import java.beans.*;
0047: import java.io.*;
0048: import java.util.*;
0049: import java.lang.reflect.*;
0050: import java.util.List;
0051: import java.util.logging.Level;
0052: import java.util.logging.Logger;
0053: import javax.swing.Action;
0054: import javax.swing.DefaultComboBoxModel;
0055: import javax.swing.DefaultListModel;
0056: import javax.swing.JComponent;
0057: import javax.swing.KeyStroke;
0058: import javax.swing.ListModel;
0059: import javax.swing.border.TitledBorder;
0060: import javax.swing.plaf.ComponentUI;
0061: import javax.swing.text.Keymap;
0062: import javax.swing.undo.UndoManager;
0063: import org.netbeans.api.java.source.ui.DialogBinding;
0064: import org.netbeans.editor.ActionFactory;
0065: import org.netbeans.editor.BaseDocument;
0066: import org.netbeans.editor.EditorUI;
0067: import org.netbeans.editor.ext.ExtCaret;
0068:
0069: import org.openide.ErrorManager;
0070: import org.openide.util.*;
0071: import org.openide.nodes.Node;
0072: import org.openide.filesystems.FileObject;
0073: import org.netbeans.modules.form.project.ClassPathUtils;
0074: import org.openide.text.CloneableEditorSupport;
0075:
0076: /**
0077: * A class that contains utility methods for the formeditor.
0078: * @author Ian Formanek
0079: */
0080:
0081: public class FormUtils {
0082: public static final Logger LOGGER = Logger
0083: .getLogger("org.netbeans.modules.form"); // NOI18N
0084:
0085: // constants for CopyProperties method
0086: public static final int CHANGED_ONLY = 1;
0087: public static final int DISABLE_CHANGE_FIRING = 2;
0088: public static final int PASS_DESIGN_VALUES = 4;
0089: public static final int DONT_CLONE_VALUES = 8;
0090:
0091: private static final Object CLASS_EXACTLY = new Object();
0092: private static final Object CLASS_AND_SUBCLASSES = new Object();
0093: private static final Object CLASS_AND_SWING_SUBCLASSES = new Object();
0094:
0095: static final Object PROP_PREFERRED = new Object();
0096: static final Object PROP_NORMAL = new Object();
0097: static final Object PROP_EXPERT = new Object();
0098: static final Object PROP_HIDDEN = new Object();
0099:
0100: static final String PROP_REQUIRES_PARENT = "thisPropertyRequiresParent"; // NOI18N
0101: static final String PROP_REQUIRES_CHILDREN = "thisPropertyRequiresChildren"; // NOI18N
0102:
0103: /** Table defining categories of properties. It overrides original Swing
0104: * definition from beaninfo (which is often inadequate). */
0105: private static Object[][] propertyCategories = {
0106: { "java.awt.Component", CLASS_AND_SUBCLASSES, "locale",
0107: PROP_HIDDEN, "locationOnScreen", PROP_HIDDEN,
0108: "showing", PROP_HIDDEN },
0109: { "java.awt.Component", CLASS_AND_SWING_SUBCLASSES,
0110: "accessibleContext", PROP_HIDDEN, "components",
0111: PROP_HIDDEN, "containerListeners", PROP_HIDDEN,
0112: "focusTraversalPolicySet", PROP_HIDDEN,
0113: "focusCycleRootAncestor", PROP_HIDDEN,
0114: "focusOwner", PROP_HIDDEN },
0115: { "java.awt.Container", CLASS_AND_SUBCLASSES,
0116: "componentCount", PROP_HIDDEN, "layout",
0117: PROP_HIDDEN },
0118: { "javax.swing.JComponent", CLASS_AND_SUBCLASSES,
0119: "debugGraphicsOptions", PROP_EXPERT,
0120: "preferredSize", PROP_NORMAL, "componentPopupMenu",
0121: PROP_NORMAL, "actionMap", PROP_HIDDEN },
0122: { "javax.swing.JComponent", CLASS_AND_SWING_SUBCLASSES,
0123: "graphics", PROP_HIDDEN, "height", PROP_HIDDEN,
0124: "inputMap", PROP_HIDDEN, "maximumSizeSet",
0125: PROP_HIDDEN, "minimumSizeSet", PROP_HIDDEN,
0126: "preferredSizeSet", PROP_HIDDEN,
0127: "registeredKeyStrokes", PROP_HIDDEN, "rootPane",
0128: PROP_HIDDEN, "topLevelAncestor", PROP_HIDDEN,
0129: "validateRoot", PROP_HIDDEN, "visibleRect",
0130: PROP_HIDDEN, "width", PROP_HIDDEN, "x",
0131: PROP_HIDDEN, "y", PROP_HIDDEN, "ancestorListeners",
0132: PROP_HIDDEN, "propertyChangeListeners",
0133: PROP_HIDDEN, "vetoableChangeListeners",
0134: PROP_HIDDEN, "actionListeners", PROP_HIDDEN,
0135: "changeListeners", PROP_HIDDEN, "itemListeners",
0136: PROP_HIDDEN, "managingFocus", PROP_HIDDEN,
0137: "optimizedDrawingEnabled", PROP_HIDDEN,
0138: "paintingTile", PROP_HIDDEN },
0139: { "java.awt.Window", CLASS_AND_SWING_SUBCLASSES,
0140: "focusCycleRootAncestor", PROP_HIDDEN,
0141: "focusOwner", PROP_HIDDEN, "active", PROP_HIDDEN,
0142: "alignmentX", PROP_HIDDEN, "alignmentY",
0143: PROP_HIDDEN, "bufferStrategy", PROP_HIDDEN,
0144: "focused", PROP_HIDDEN, "graphicsConfiguration",
0145: PROP_HIDDEN, "mostRecentFocusOwner", PROP_HIDDEN,
0146: "inputContext", PROP_HIDDEN, "ownedWindows",
0147: PROP_HIDDEN, "owner", PROP_HIDDEN,
0148: "windowFocusListeners", PROP_HIDDEN,
0149: "windowListeners", PROP_HIDDEN,
0150: "windowStateListeners", PROP_HIDDEN,
0151: "warningString", PROP_HIDDEN, "toolkit",
0152: PROP_HIDDEN, "focusableWindow", PROP_HIDDEN,
0153: "locationRelativeTo", PROP_HIDDEN },
0154: { "javax.swing.text.JTextComponent", CLASS_AND_SUBCLASSES,
0155: "document", PROP_PREFERRED, "text", PROP_PREFERRED,
0156: "editable", PROP_PREFERRED, "disabledTextColor",
0157: PROP_NORMAL, "selectedTextColor", PROP_NORMAL,
0158: "selectionColor", PROP_NORMAL, "caretColor",
0159: PROP_NORMAL },
0160: { "javax.swing.text.JTextComponent",
0161: CLASS_AND_SWING_SUBCLASSES, "actions", PROP_HIDDEN,
0162: "caretListeners", PROP_HIDDEN,
0163: "inputMethodRequests", PROP_HIDDEN },
0164: { "javax.swing.JTextField", CLASS_AND_SUBCLASSES,
0165: "columns", PROP_PREFERRED },
0166: { "javax.swing.JTextField", CLASS_AND_SWING_SUBCLASSES,
0167: "horizontalVisibility", PROP_HIDDEN },
0168: { "javax.swing.JFormattedTextField", CLASS_EXACTLY,
0169: "formatterFactory", PROP_PREFERRED, "formatter",
0170: PROP_HIDDEN },
0171: { "javax.swing.JPasswordField", CLASS_EXACTLY, "password",
0172: PROP_HIDDEN },
0173: { "javax.swing.JTextArea", CLASS_AND_SUBCLASSES, "columns",
0174: PROP_PREFERRED, "rows", PROP_PREFERRED, "lineWrap",
0175: PROP_PREFERRED, "wrapStyleWord", PROP_PREFERRED },
0176: { "javax.swing.JEditorPane", CLASS_AND_SUBCLASSES,
0177: "border", PROP_PREFERRED, "font", PROP_PREFERRED,
0178: "contentType", PROP_PREFERRED, "editorKit",
0179: PROP_PREFERRED },
0180: { "javax.swing.JEditorPane", CLASS_AND_SWING_SUBCLASSES,
0181: "hyperlinkListeners", PROP_HIDDEN },
0182: { "javax.swing.JTextPane", CLASS_EXACTLY,
0183: "characterAttributes", PROP_HIDDEN,
0184: "paragraphAttributes", PROP_HIDDEN },
0185: { "javax.swing.JTree", CLASS_AND_SUBCLASSES, "border",
0186: PROP_PREFERRED },
0187: { "javax.swing.JTree", CLASS_EXACTLY, "editing",
0188: PROP_HIDDEN, "editingPath", PROP_HIDDEN,
0189: "selectionCount", PROP_HIDDEN, "selectionEmpty",
0190: PROP_HIDDEN, "lastSelectedPathComponent",
0191: PROP_HIDDEN, "leadSelectionRow", PROP_HIDDEN,
0192: "maxSelectionRow", PROP_HIDDEN, "minSelectionRow",
0193: PROP_HIDDEN, "treeExpansionListeners", PROP_HIDDEN,
0194: "treeSelectionListeners", PROP_HIDDEN,
0195: "treeWillExpandListeners", PROP_HIDDEN },
0196: { "javax.swing.AbstractButton", CLASS_AND_SUBCLASSES,
0197: "mnemonic", PROP_PREFERRED, "action",
0198: PROP_PREFERRED },
0199: { "javax.swing.AbstractButton", CLASS_AND_SWING_SUBCLASSES,
0200: "selectedObjects", PROP_HIDDEN },
0201: { "javax.swing.JToggleButton", CLASS_AND_SUBCLASSES,
0202: "icon", PROP_PREFERRED, "selected", PROP_PREFERRED,
0203: "buttonGroup", PROP_PREFERRED },
0204: { "javax.swing.JButton", CLASS_AND_SUBCLASSES, "icon",
0205: PROP_PREFERRED, "defaultButton", PROP_HIDDEN },
0206: { "javax.swing.JCheckBox", CLASS_EXACTLY, "icon",
0207: PROP_NORMAL, "model", PROP_PREFERRED },
0208: { "javax.swing.JRadioButton", CLASS_EXACTLY, "icon",
0209: PROP_NORMAL },
0210: { "javax.swing.JMenuItem", CLASS_AND_SUBCLASSES, "icon",
0211: PROP_PREFERRED },
0212: { "javax.swing.JMenuItem", CLASS_AND_SWING_SUBCLASSES,
0213: "menuDragMouseListeners", PROP_HIDDEN,
0214: "menuKeyListeners", PROP_HIDDEN },
0215: { "javax.swing.JCheckBoxMenuItem", CLASS_AND_SUBCLASSES,
0216: "selected", PROP_PREFERRED, "buttonGroup",
0217: PROP_PREFERRED, "icon", PROP_NORMAL },
0218: { "javax.swing.JRadioButtonMenuItem", CLASS_AND_SUBCLASSES,
0219: "selected", PROP_PREFERRED, "buttonGroup",
0220: PROP_PREFERRED, "icon", PROP_NORMAL },
0221: { "javax.swing.JTabbedPane", CLASS_EXACTLY,
0222: "selectedComponent", PROP_EXPERT },
0223: { "javax.swing.JSplitPane", CLASS_AND_SUBCLASSES,
0224: "dividerLocation", PROP_PREFERRED, "dividerSize",
0225: PROP_PREFERRED, "orientation", PROP_PREFERRED,
0226: "resizeWeight", PROP_PREFERRED },
0227: { "javax.swing.JSplitPane", CLASS_EXACTLY, "leftComponent",
0228: PROP_HIDDEN, "rightComponent", PROP_HIDDEN,
0229: "topComponent", PROP_HIDDEN, "bottomComponent",
0230: PROP_HIDDEN },
0231: { "javax.swing.JSlider", CLASS_AND_SUBCLASSES,
0232: "majorTickSpacing", PROP_PREFERRED,
0233: "minorTickSpacing", PROP_PREFERRED, "paintLabels",
0234: PROP_PREFERRED, "paintTicks", PROP_PREFERRED,
0235: "paintTrack", PROP_PREFERRED, "snapToTicks",
0236: PROP_PREFERRED },
0237: { "javax.swing.JLabel", CLASS_AND_SUBCLASSES,
0238: "horizontalAlignment", PROP_PREFERRED,
0239: "verticalAlignment", PROP_PREFERRED,
0240: "displayedMnemonic", PROP_PREFERRED, "labelFor",
0241: PROP_PREFERRED },
0242: { "javax.swing.JList", CLASS_AND_SUBCLASSES, "model",
0243: PROP_PREFERRED, "border", PROP_PREFERRED,
0244: "selectionMode", PROP_PREFERRED },
0245: { "javax.swing.JComboBox", CLASS_AND_SUBCLASSES, "model",
0246: PROP_PREFERRED },
0247: { "javax.swing.JComboBox", CLASS_EXACTLY, "popupVisible",
0248: PROP_HIDDEN, "popupMenuListeners", PROP_HIDDEN,
0249: "selectedObjects", PROP_HIDDEN },
0250: { "javax.swing.Scrollable", CLASS_AND_SWING_SUBCLASSES,
0251: "preferredScrollableViewportSize", PROP_HIDDEN,
0252: "scrollableTracksViewportWidth", PROP_HIDDEN,
0253: "scrollableTracksViewportHeight", PROP_HIDDEN },
0254: { "javax.swing.JScrollBar", CLASS_EXACTLY,
0255: "adjustmentListeners", PROP_HIDDEN },
0256: { "javax.swing.JTable", CLASS_AND_SUBCLASSES, "model",
0257: PROP_PREFERRED, "border", PROP_PREFERRED,
0258: "autoCreateColumnsFromModel", PROP_PREFERRED },
0259: { "javax.swing.JTable", CLASS_EXACTLY, "editing",
0260: PROP_HIDDEN, "editorComponent", PROP_HIDDEN,
0261: "selectedColumn", PROP_HIDDEN,
0262: "selectedColumnCount", PROP_HIDDEN,
0263: "selectedColumns", PROP_HIDDEN, "selectedRow",
0264: PROP_HIDDEN, "selectedRowCount", PROP_HIDDEN,
0265: "selectedRows", PROP_HIDDEN },
0266: { "javax.swing.JSeparator", CLASS_EXACTLY, "font",
0267: PROP_NORMAL },
0268: { "javax.swing.JInternalFrame", CLASS_AND_SUBCLASSES,
0269: "defaultCloseOperation", PROP_PREFERRED, "visible",
0270: PROP_NORMAL },
0271: { "javax.swing.JInternalFrame", CLASS_EXACTLY, "menuBar",
0272: PROP_HIDDEN, "JMenuBar", PROP_HIDDEN,
0273: "desktopPane", PROP_HIDDEN,
0274: "internalFrameListeners", PROP_HIDDEN,
0275: "mostRecentFocusOwner", PROP_HIDDEN,
0276: "warningString", PROP_HIDDEN, "closed", PROP_HIDDEN },
0277: { "javax.swing.JMenu", CLASS_EXACTLY, "accelerator",
0278: PROP_HIDDEN, "tearOff", PROP_HIDDEN,
0279: "menuComponents", PROP_HIDDEN, "menuListeners",
0280: PROP_HIDDEN, "popupMenu", PROP_HIDDEN,
0281: "topLevelMenu", PROP_HIDDEN },
0282: { "javax.swing.JPopupMenu", CLASS_AND_SWING_SUBCLASSES,
0283: "popupMenuListeners", PROP_HIDDEN },
0284: { "java.awt.Frame", CLASS_AND_SWING_SUBCLASSES,
0285: "cursorType", PROP_HIDDEN, "menuBar", PROP_HIDDEN },
0286: { "javax.swing.JFrame", CLASS_AND_SUBCLASSES, "title",
0287: PROP_PREFERRED },
0288: { "javax.swing.JFrame", CLASS_EXACTLY, "menuBar",
0289: PROP_HIDDEN, "layout", PROP_HIDDEN },
0290: { "javax.swing.JDialog", CLASS_AND_SUBCLASSES, "title",
0291: PROP_PREFERRED },
0292: { "javax.swing.JDialog", CLASS_EXACTLY, "layout",
0293: PROP_HIDDEN },
0294: { "javax.swing.MenuElement", CLASS_AND_SWING_SUBCLASSES,
0295: "component", PROP_HIDDEN, "subElements",
0296: PROP_HIDDEN },
0297: { "javax.swing.JMenuBar", CLASS_EXACTLY, "helpMenu",
0298: PROP_HIDDEN, "menuCount", PROP_HIDDEN, "selected",
0299: PROP_HIDDEN },
0300: { "javax.swing.JSpinner", CLASS_AND_SUBCLASSES, "model",
0301: PROP_PREFERRED },
0302: { "java.applet.Applet", CLASS_AND_SUBCLASSES,
0303: "appletContext", PROP_HIDDEN, "codeBase",
0304: PROP_HIDDEN, "documentBase", PROP_HIDDEN },
0305: { "javax.swing.JFileChooser", CLASS_EXACTLY,
0306: "acceptAllFileFilter", PROP_HIDDEN,
0307: "choosableFileFilters", PROP_HIDDEN } };
0308:
0309: /** Table with explicit changes to propeties accessibility. E.g. some
0310: * properties needs to be restricted to "detached write". */
0311: private static Object[][] propertiesAccess = { {
0312: "javax.swing.JFrame", CLASS_AND_SUBCLASSES,
0313: "defaultCloseOperation",
0314: new Integer(FormProperty.DETACHED_WRITE) } };
0315:
0316: /** Table of properties that need the component to be added in the parent,
0317: * or child components in the container before the property can be set.
0318: * [We use one table though these are two distinct categories - it's fine
0319: * until there is a property requiring both conditions.] */
0320: private static Object[][] propertyContainerDeps = {
0321: { "javax.swing.JTabbedPane", CLASS_AND_SUBCLASSES,
0322: "selectedIndex", PROP_REQUIRES_CHILDREN,
0323: "selectedComponent", PROP_REQUIRES_CHILDREN },
0324: { "javax.swing.JInternalFrame", CLASS_AND_SUBCLASSES,
0325: "maximum", PROP_REQUIRES_PARENT, "icon",
0326: PROP_REQUIRES_PARENT },
0327: // columnModel can be set by binding property
0328: { "javax.swing.JTable", CLASS_AND_SUBCLASSES,
0329: "columnModel", PROP_REQUIRES_PARENT } };
0330:
0331: /** Table defining order of dependent properties. */
0332: private static Object[][] propertyOrder = {
0333: { "javax.swing.text.JTextComponent", "document", "text" },
0334: { "javax.swing.JSpinner", "model", "editor" },
0335: { "javax.swing.AbstractButton", "action", "actionCommand",
0336: "action", "enabled", "action", "mnemonic",
0337: "action", "icon", "action", "text", "action",
0338: "toolTipText" },
0339: { "javax.swing.JMenuItem", "action", "accelerator" },
0340: { "javax.swing.JList", "model", "selectedIndex", "model",
0341: "selectedValues" },
0342: { "javax.swing.JComboBox", "model", "selectedIndex",
0343: "model", "selectedItem" },
0344: { "java.awt.TextComponent", "text", "selectionStart",
0345: "text", "selectionEnd" },
0346: { "javax.swing.JEditorPane", "contentType", "text",
0347: "editorKit", "text" },
0348: { "javax.swing.JTable", "autoCreateColumnsFromModel",
0349: "model" },
0350: { "javax.swing.JCheckBox", "model", "mnemonic", "model",
0351: "text" } };
0352:
0353: /** Table enumerating properties that can hold HTML text. */
0354: private static Object[][] swingTextProperties = { {
0355: "javax.swing.JComponent", FormUtils.CLASS_AND_SUBCLASSES,
0356: "text", Boolean.TRUE, "toolTipText", Boolean.TRUE } };
0357:
0358: /** List of components that should never be containers; some of them are
0359: * not specified in original Swing beaninfos. */
0360: private static String[] forbiddenContainers = {
0361: "javax.swing.JLabel", // NOI18N
0362: "javax.swing.JButton", // NOI18N
0363: "javax.swing.JToggleButton", // NOI18N
0364: "javax.swing.JCheckBox", // NOI18N
0365: "javax.swing.JRadioButton", // NOI18N
0366: "javax.swing.JComboBox", // NOI18N
0367: "javax.swing.JList", // NOI18N
0368: "javax.swing.JTextField", // NOI18N
0369: "javax.swing.JTextArea", // NOI18N
0370: "javax.swing.JScrollBar", // NOI18N
0371: "javax.swing.JSlider", // NOI18N
0372: "javax.swing.JProgressBar", // NOI18N
0373: "javax.swing.JFormattedTextField", // NOI18N
0374: "javax.swing.JPasswordField", // NOI18N
0375: "javax.swing.JSpinner", // NOI18N
0376: "javax.swing.JSeparator", // NOI18N
0377: "javax.swing.JTextPane", // NOI18N
0378: "javax.swing.JEditorPane", // NOI18N
0379: "javax.swing.JTree", // NOI18N
0380: "javax.swing.JTable", // NOI18N
0381: "javax.swing.JOptionPane", // NOI18N
0382: "javax.swing.JColorChooser", // NOI18N
0383: "javax.swing.JFileChooser", // NOI18N
0384: };
0385:
0386: private static Map<Class<?>, Map<String, DefaultValueDeviation>> defaultValueDeviations;
0387:
0388: // -----------------------------------------------------------------------------
0389: // Utility methods
0390:
0391: public static ResourceBundle getBundle() {
0392: return NbBundle.getBundle(FormUtils.class);
0393: }
0394:
0395: public static String getBundleString(String key) {
0396: return NbBundle.getBundle(FormUtils.class).getString(key);
0397: }
0398:
0399: public static String getFormattedBundleString(String key,
0400: Object[] arguments) {
0401: return NbBundle.getMessage(FormUtils.class, key, arguments);
0402: }
0403:
0404: /** Utility method that tries to clone an object. Objects of explicitly
0405: * specified types are constructed directly, other are serialized and
0406: * deserialized (if not serializable exception is thrown).
0407: *
0408: * @param o object to clone.
0409: * @param formModel form model.
0410: * @return cloned of the given object.
0411: * @throws java.lang.CloneNotSupportedException when cloning was unsuccessful.
0412: */
0413: public static Object cloneObject(Object o, FormModel formModel)
0414: throws CloneNotSupportedException {
0415: if (o == null)
0416: return null;
0417:
0418: if ((o instanceof Byte) || (o instanceof Short)
0419: || (o instanceof Integer) || (o instanceof Long)
0420: || (o instanceof Float) || (o instanceof Double)
0421: || (o instanceof Boolean) || (o instanceof Character)
0422: || (o instanceof String)) {
0423: return o; // no need to change reference
0424: }
0425:
0426: if (o.getClass() == Font.class) {
0427: return o;
0428: }
0429: // Issue 49973
0430: if ((o.getClass() == TitledBorder.class) && Utilities.isMac()) {
0431: TitledBorder border = (TitledBorder) o;
0432: return new TitledBorder(border.getBorder(), border
0433: .getTitle(), border.getTitleJustification(), border
0434: .getTitlePosition(), border.getTitleFont(), border
0435: .getTitleColor());
0436: }
0437: if (o.getClass() == Color.class)
0438: return new Color(((Color) o).getRGB());
0439: if (o instanceof Dimension)
0440: return new Dimension((Dimension) o);
0441: if (o instanceof Point)
0442: return new Point((Point) o);
0443: if (o instanceof Rectangle)
0444: return new Rectangle((Rectangle) o);
0445: if (o instanceof Insets)
0446: return ((Insets) o).clone();
0447: if (o instanceof GradientPaint) {
0448: GradientPaint gp = (GradientPaint) o;
0449: return new GradientPaint(gp.getPoint1(), gp.getColor1(), gp
0450: .getPoint2(), gp.getColor2(), gp.isCyclic());
0451: }
0452: if (o.getClass() == DefaultListModel.class) {
0453: // avoid potential problems with serialization of listeners (#72802)
0454: ListModel listModel = (ListModel) o;
0455: DefaultListModel newListModel = new DefaultListModel();
0456: for (int i = 0; i < listModel.getSize(); i++) {
0457: newListModel.addElement(cloneObject(listModel
0458: .getElementAt(i), formModel));
0459: }
0460: return newListModel;
0461: }
0462: if (o.getClass() == DefaultComboBoxModel.class) {
0463: // avoid potential problems with serialization of listeners (#72802)
0464: ListModel comboModel = (ListModel) o;
0465: DefaultComboBoxModel newComboModel = new DefaultComboBoxModel();
0466: for (int i = 0; i < comboModel.getSize(); i++) {
0467: newComboModel.addElement(cloneObject(comboModel
0468: .getElementAt(i), formModel));
0469: }
0470: return newComboModel;
0471: }
0472: // for TableModel we use TableModelEditor.NbTableModel which takes care of its serialization
0473:
0474: if (o instanceof Serializable) {
0475: return cloneBeanInstance(o, null, formModel);
0476: }
0477:
0478: throw new CloneNotSupportedException();
0479: }
0480:
0481: /** Utility method that tries to clone an object as a bean.
0482: * First - if it is serializable, then it is copied using serialization.
0483: * If not serializable, then all properties (taken from BeanInfo) are
0484: * copied (property values cloned recursively).
0485: *
0486: * @param bean bean to clone.
0487: * @param bInfo bean info.
0488: * @param formModel form model.
0489: * @return clone of the given bean.
0490: * @throws java.lang.CloneNotSupportedException when cloning was unsuccessful.
0491: */
0492: public static Object cloneBeanInstance(Object bean, BeanInfo bInfo,
0493: FormModel formModel) throws CloneNotSupportedException {
0494: if (bean == null)
0495: return null;
0496:
0497: if (bean instanceof Serializable) {
0498: OOS oos = null;
0499: try {
0500: ByteArrayOutputStream baos = new ByteArrayOutputStream();
0501: oos = new OOS(baos);
0502: oos.writeObject(bean);
0503: oos.close();
0504:
0505: ByteArrayInputStream bais = new ByteArrayInputStream(
0506: baos.toByteArray());
0507: return new OIS(bais, bean.getClass().getClassLoader(),
0508: formModel).readObject();
0509: } catch (Exception ex) {
0510: LOGGER.log(Level.INFO, "Cannot clone "
0511: + bean.getClass().getName(), ex); // NOI18N
0512: throw new CloneNotSupportedException();
0513: } finally {
0514: if (oos != null) {
0515: oos.checkJComponentSerialization();
0516: }
0517: }
0518: }
0519:
0520: // object is not Serializable
0521: Object clone;
0522: try {
0523: clone = CreationFactory.createDefaultInstance(bean
0524: .getClass());
0525: if (clone == null)
0526: throw new CloneNotSupportedException();
0527:
0528: if (bInfo == null)
0529: bInfo = Utilities.getBeanInfo(bean.getClass());
0530: } catch (Exception ex) {
0531: LOGGER.log(Level.INFO, "Cannot clone "
0532: + bean.getClass().getName(), ex); // NOI18N
0533: throw new CloneNotSupportedException();
0534: }
0535:
0536: // default instance successfully created, now copy properties
0537: PropertyDescriptor[] pds = bInfo.getPropertyDescriptors();
0538: for (int i = 0; i < pds.length; i++) {
0539: Method getter = pds[i].getReadMethod();
0540: Method setter = pds[i].getWriteMethod();
0541: if (getter != null && setter != null) {
0542: Object propertyValue;
0543: try {
0544: propertyValue = getter.invoke(bean, new Object[0]);
0545: } catch (Exception e1) { // ignore - do not copy this property
0546: continue;
0547: }
0548: try {
0549: propertyValue = cloneObject(propertyValue,
0550: formModel);
0551: } catch (Exception e2) { // ignore - do not clone property value
0552: }
0553: try {
0554: setter
0555: .invoke(clone,
0556: new Object[] { propertyValue });
0557: } catch (Exception e3) { // ignore - do not copy this property
0558: }
0559: }
0560: }
0561:
0562: return clone;
0563: }
0564:
0565: /**
0566: * Special ObjectOutputStream subclass that takes care of possible failure in
0567: * serialization of JComponent which may leave the component with uninstalled
0568: * ComponentUI. This may happen when serializing property values like
0569: * DefaultComboBoxModel which reference the component they are set to.
0570: * See issue 72802. [In future it would be nice to have a better way of
0571: * copying the property values, minimizing the use of serialization.]
0572: */
0573: private static class OOS extends ObjectOutputStream {
0574: private Set<SerializationMarker> placedMarkers = new HashSet<SerializationMarker>();
0575:
0576: private OOS(OutputStream os) throws IOException {
0577: super (os);
0578: enableReplaceObject(true);
0579: }
0580:
0581: /**
0582: * This method allows us to monitor objects going into the stream.
0583: * If the object is a JComponent, we add our special marker object to
0584: * its client properties. The marker keeps track of whether it was
0585: * serialized or not.
0586: */
0587: @Override
0588: protected Object replaceObject(Object obj) throws IOException {
0589: if (obj instanceof JComponent) {
0590: JComponent comp = (JComponent) obj;
0591: SerializationMarker sm = new SerializationMarker(comp);
0592: comp.putClientProperty(SerializationMarker.KEY, sm);
0593: placedMarkers.add(sm);
0594: }
0595: return obj;
0596: }
0597:
0598: /**
0599: * Go through all markers added to components during serialization.
0600: * If a marker was serialized, it means the component's client properties
0601: * serialization was at least started - which is done after installing
0602: * the ComponentUI back after serializing the component itself (see
0603: * JComponent.writeObject). If the marker was not serialized, it is
0604: * likely that the ComponentUI was left uninstalled (from
0605: * JComponent.compWriteObjectNotify).
0606: */
0607: private void checkJComponentSerialization() {
0608: for (SerializationMarker sm : placedMarkers) {
0609: JComponent comp = sm.component;
0610: if (!sm.serialized) {
0611: fixUnserializedJComponent(comp);
0612: }
0613: comp.putClientProperty(SerializationMarker.KEY, null);
0614: }
0615: }
0616:
0617: /**
0618: * Hack: Mimics the code of JComponent.writeObject() to install back
0619: * ComponentUI of the component if it was not done due to interrupted
0620: * serialization. Calling private methods and accessing private field
0621: * via reflection, yuck...
0622: */
0623: private static void fixUnserializedJComponent(JComponent comp) {
0624: try {
0625: Method getWriteObjCounter_Method = JComponent.class
0626: .getDeclaredMethod("getWriteObjCounter",
0627: JComponent.class); // NOI18N
0628: getWriteObjCounter_Method.setAccessible(true);
0629: Method setWriteObjCounter_Method = JComponent.class
0630: .getDeclaredMethod("setWriteObjCounter",
0631: JComponent.class, Byte.TYPE); // NOI18N
0632: setWriteObjCounter_Method.setAccessible(true);
0633: Field ui_Field = JComponent.class
0634: .getDeclaredField("ui"); // NOI18N
0635: ui_Field.setAccessible(true);
0636:
0637: byte count = ((Byte) getWriteObjCounter_Method.invoke(
0638: null, comp)).byteValue();
0639: if (count > 0) { // counter not 0, serialization has not finished
0640: count = 0;
0641: setWriteObjCounter_Method.invoke(null, comp, count);
0642: // reinstall ComponentUI
0643: LOGGER.log(Level.INFO,
0644: "Reinstalling ComponentUI after interrupted serialization of component: "
0645: + comp); // NOI18N
0646: ComponentUI ui = (ComponentUI) ui_Field.get(comp);
0647: ui.installUI(comp);
0648: }
0649: } catch (Exception ex) {
0650: LOGGER
0651: .log(
0652: Level.INFO,
0653: "Reinstalling ComponentUI after interrupted serialization of JComponent failed",
0654: ex); // NOI18N
0655: }
0656: }
0657: }
0658:
0659: /**
0660: * Special object added to JComponent's client properties to track whether
0661: * the client properties were sucessfully serialized (or at least started).
0662: */
0663: private static class SerializationMarker implements Serializable {
0664: private static final Object KEY = new Object();
0665:
0666: transient boolean serialized;
0667: transient JComponent component;
0668:
0669: private SerializationMarker(JComponent comp) {
0670: component = comp;
0671: }
0672:
0673: public Object writeReplace() {
0674: serialized = true;
0675: return new Object();
0676: }
0677: }
0678:
0679: /** This method provides copying of property values from one array of
0680: * properties to another. The arrays need not be equally sorted. It is
0681: * recommended to use arrays of FormProperty, for which the mode parameter
0682: * can be used to specify some options (using bit flags):
0683: * CHANGED_ONLY (to copy only values of changed properties),
0684: * DISABLE_CHANGE_FIRING (to disable firing of changes in target properties),
0685: * PASS_DESIGN_VALUES (to pass the same FormDesignValue instances if they
0686: * cannot or should not be copied),
0687: *
0688: * @param sourceProperties properties to copy values from.
0689: * @param targetProperties properties to copy values to.
0690: * @param mode see the description above.
0691: */
0692: public static void copyProperties(Node.Property[] sourceProperties,
0693: Node.Property[] targetProperties, int mode) {
0694: for (int i = 0; i < sourceProperties.length; i++) {
0695: Node.Property snProp = sourceProperties[i];
0696: FormProperty sfProp = snProp instanceof FormProperty ? (FormProperty) snProp
0697: : null;
0698:
0699: if (sfProp != null && (mode & CHANGED_ONLY) != 0
0700: && !sfProp.isChanged())
0701: continue; // copy only changed properties
0702:
0703: // find target property
0704: Node.Property tnProp = targetProperties[i];
0705: if (!tnProp.getName().equals(snProp.getName())) {
0706: int j;
0707: for (j = 0; j < targetProperties.length; j++) {
0708: tnProp = targetProperties[i];
0709: if (tnProp.getName().equals(snProp.getName()))
0710: break;
0711: }
0712: if (j == targetProperties.length)
0713: continue; // not found
0714: }
0715: FormProperty tfProp = tnProp instanceof FormProperty ? (FormProperty) tnProp
0716: : null;
0717:
0718: try {
0719: // get and clone property value
0720: Object propertyValue = snProp.getValue();
0721: Object copiedValue = propertyValue;
0722: if ((mode & DONT_CLONE_VALUES) == 0) {
0723: if (!(propertyValue instanceof FormDesignValue)) {
0724: try { // clone common property value
0725: FormModel formModel = (sfProp == null) ? null
0726: : sfProp.getPropertyContext()
0727: .getFormModel();
0728: copiedValue = FormUtils.cloneObject(
0729: propertyValue, formModel);
0730: } catch (CloneNotSupportedException ex) {
0731: } // ignore, don't report
0732: } else { // handle FormDesignValue
0733: Object val = ((FormDesignValue) propertyValue)
0734: .copy(tfProp);
0735: if (val != null)
0736: copiedValue = val;
0737: else if ((mode & PASS_DESIGN_VALUES) == 0)
0738: continue; // cannot just pass the same design value
0739: }
0740: }
0741:
0742: // set property value
0743: if (tfProp != null) {
0744: boolean firing = tfProp.isChangeFiring();
0745: tfProp
0746: .setChangeFiring((mode & DISABLE_CHANGE_FIRING) == 0);
0747: tfProp.setValue(copiedValue);
0748: tfProp.setChangeFiring(firing);
0749: } else
0750: tnProp.setValue(copiedValue);
0751:
0752: if (sfProp != null && tfProp != null) {
0753: // also clone current PropertyEditor
0754: PropertyEditor sPrEd = sfProp.getCurrentEditor();
0755: PropertyEditor tPrEd = tfProp.getCurrentEditor();
0756: if (sPrEd != null
0757: && (tPrEd == null || sPrEd.getClass() != tPrEd
0758: .getClass())
0759: && (propertyValue == copiedValue || (propertyValue != null
0760: && copiedValue != null && propertyValue
0761: .getClass() == copiedValue
0762: .getClass()))) {
0763: tPrEd = sPrEd instanceof RADConnectionPropertyEditor ? new RADConnectionPropertyEditor(
0764: tfProp.getValueType())
0765: : (PropertyEditor) CreationFactory
0766: .createDefaultInstance(sPrEd
0767: .getClass());
0768: tfProp.setCurrentEditor(tPrEd);
0769: }
0770: }
0771:
0772: // also copy the resource/i18n attributes set on the property
0773: copyPropertyAttrs(snProp, tnProp, ResourceSupport
0774: .getPropertyAttrNames());
0775: } catch (Exception ex) { // ignore
0776: ErrorManager.getDefault().notify(
0777: ErrorManager.INFORMATIONAL, ex);
0778: }
0779: }
0780: }
0781:
0782: private static void copyPropertyAttrs(Node.Property sourceProp,
0783: Node.Property targetProp, String[] attrs) {
0784: for (String attr : attrs) {
0785: Object value = sourceProp.getValue(attr);
0786: if (value != null) {
0787: targetProp.setValue(attr, value);
0788: }
0789: }
0790: }
0791:
0792: public static void copyPropertiesToBean(RADProperty[] props,
0793: Object targetBean,
0794: Collection<RADProperty> relativeProperties) {
0795: copyPropertiesToBean(Arrays.asList(props).iterator(),
0796: targetBean, relativeProperties);
0797: }
0798:
0799: public static void copyPropertiesToBean(
0800: Iterator<RADProperty> props, Object targetBean,
0801: Collection<RADProperty> relativeProperties) {
0802: while (props.hasNext()) {
0803: RADProperty prop = props.next();
0804: if (!prop.isChanged() || !prop.canWriteToTarget()) {
0805: continue;
0806: }
0807:
0808: try {
0809: if (relativeProperties != null) {
0810: Object value = prop.getValue();
0811: if (value instanceof RADComponent
0812: || value instanceof RADComponent.ComponentReference
0813: || isRelativeConnectionValue(value)) {
0814: relativeProperties.add(prop);
0815: continue;
0816: }
0817: }
0818:
0819: Method writeMethod = getPropertyWriteMethod(prop,
0820: targetBean.getClass()); //prop.getPropertyDescriptor().getWriteMethod();
0821: if (writeMethod == null) {
0822: continue;
0823: }
0824:
0825: Object value = prop.getValue();
0826: Object newValue = null;
0827: if (value instanceof FormDesignValue) {
0828: newValue = ((FormDesignValue) value)
0829: .getDesignValue(targetBean);
0830: }
0831: if (newValue == null) {
0832: Object realValue = prop.getRealValue();
0833: if (realValue == FormDesignValue.IGNORED_VALUE)
0834: continue; // ignore this value, as it is not a real value
0835:
0836: newValue = FormUtils.cloneObject(realValue, prop
0837: .getPropertyContext().getFormModel());
0838: }
0839: writeMethod.invoke(targetBean,
0840: new Object[] { newValue });
0841: } catch (CloneNotSupportedException ex) { // ignore, don't report
0842: } catch (Exception ex) {
0843: LOGGER.log(Level.INFO, null, ex); // NOI18N
0844: }
0845: }
0846: }
0847:
0848: static boolean isRelativeConnectionValue(Object value) {
0849: if (value instanceof RADConnectionPropertyEditor.RADConnectionDesignValue) {
0850: RADConnectionPropertyEditor.RADConnectionDesignValue conValue = (RADConnectionPropertyEditor.RADConnectionDesignValue) value;
0851: return conValue.type == RADConnectionPropertyEditor.RADConnectionDesignValue.TYPE_BEAN
0852: || conValue.type == RADConnectionPropertyEditor.RADConnectionDesignValue.TYPE_METHOD
0853: || conValue.type == RADConnectionPropertyEditor.RADConnectionDesignValue.TYPE_PROPERTY;
0854: }
0855: return false;
0856: }
0857:
0858: public static Method getPropertyWriteMethod(RADProperty property,
0859: Class targetClass) {
0860: Method method = property.getPropertyDescriptor()
0861: .getWriteMethod();
0862: if (method != null
0863: && targetClass != null
0864: && !method.getDeclaringClass().isAssignableFrom(
0865: targetClass)) {
0866: // try to use find the same method in the target class
0867: try {
0868: method = targetClass.getMethod(method.getName(), method
0869: .getParameterTypes());
0870: } catch (Exception ex) { // ignore
0871: method = null;
0872: }
0873: }
0874: return method;
0875: }
0876:
0877: public static void setupEditorPane(javax.swing.JEditorPane editor,
0878: FileObject srcFile, int ccPosition) {
0879: editor.setEditorKit(CloneableEditorSupport
0880: .getEditorKit("text/x-java")); // NOI18N
0881: DialogBinding.bindComponentToFile(srcFile, ccPosition, 0,
0882: editor);
0883:
0884: // do not highlight current row
0885: EditorUI eui = org.netbeans.editor.Utilities
0886: .getEditorUI(editor);
0887: eui.removeLayer(ExtCaret.HIGHLIGHT_ROW_LAYER_NAME);
0888:
0889: setupTextUndoRedo(editor);
0890: }
0891:
0892: public static void setupTextUndoRedo(
0893: javax.swing.text.JTextComponent editor) {
0894: // don't use global undo/redo actions, register basic ones
0895: KeyStroke[] undoKeys = new KeyStroke[] {
0896: KeyStroke.getKeyStroke(KeyEvent.VK_UNDO, 0),
0897: KeyStroke.getKeyStroke(KeyEvent.VK_Z, 130) };
0898: KeyStroke[] redoKeys = new KeyStroke[] {
0899: KeyStroke.getKeyStroke(KeyEvent.VK_AGAIN, 0),
0900: KeyStroke.getKeyStroke(KeyEvent.VK_Y, 130) };
0901: Keymap keymap = editor.getKeymap();
0902: Action undoAction = new ActionFactory.UndoAction();
0903: for (KeyStroke k : undoKeys) {
0904: keymap.removeKeyStrokeBinding(k);
0905: keymap.addActionForKeyStroke(k, undoAction);
0906: }
0907: Action redoAction = new ActionFactory.RedoAction();
0908: for (KeyStroke k : redoKeys) {
0909: keymap.removeKeyStrokeBinding(k);
0910: keymap.addActionForKeyStroke(k, redoAction);
0911: }
0912: Object currentUM = editor.getDocument().getProperty(
0913: BaseDocument.UNDO_MANAGER_PROP);
0914: if (currentUM instanceof UndoManager) {
0915: editor.getDocument().removeUndoableEditListener(
0916: (UndoManager) currentUM);
0917: }
0918: UndoManager um = new UndoManager();
0919: editor.getDocument().addUndoableEditListener(um);
0920: editor.getDocument().putProperty(
0921: BaseDocument.UNDO_MANAGER_PROP, um);
0922: }
0923:
0924: // ---------
0925:
0926: public static boolean isContainer(Class beanClass) {
0927: // Map containerBeans = formSettings.getContainerBeans();
0928: // Object registered = containerBeans != null ?
0929: // containerBeans.get(beanClass.getName()) : null;
0930: // if (registered instanceof Boolean)
0931: // return ((Boolean)registered).booleanValue();
0932:
0933: // not registered
0934: int containerStatus = canBeContainer(beanClass);
0935: if (containerStatus == -1) { // "isContainer" attribute not specified
0936: containerStatus = 1;
0937: Class cls = beanClass.getSuperclass();
0938: while (cls != null && !cls.equals(java.awt.Container.class)) {
0939: String beanClassName = cls.getName();
0940: int i;
0941: for (i = 0; i < forbiddenContainers.length; i++)
0942: if (beanClassName.equals(forbiddenContainers[i]))
0943: break; // superclass cannot be container
0944:
0945: if (i < forbiddenContainers.length) {
0946: containerStatus = 0;
0947: break;
0948: }
0949:
0950: cls = cls.getSuperclass();
0951: }
0952: }
0953:
0954: return containerStatus == 1;
0955: // boolean isContainer = containerStatus == 1;
0956: //
0957: // if (beanClass.getName().startsWith("javax.swing.")) // NOI18N
0958: // setIsContainer(beanClass, isContainer);
0959: //
0960: // return isContainer;
0961: }
0962:
0963: /**
0964: * Determines whether instances of the given class can serve as containers.
0965: *
0966: * @param beanClass class to check.
0967: * @return 1 if the class is explicitly specified as container in BeanInfo;
0968: * 0 if the class is explicitly enumerated in forbiddenContainers
0969: * or specified as non-container in its BeanInfo;
0970: * -1 if the class is not forbidden nor specified in BeanInfo at all
0971: */
0972: public static int canBeContainer(Class beanClass) {
0973: if (beanClass == null
0974: || !java.awt.Container.class
0975: .isAssignableFrom(beanClass))
0976: return 0;
0977:
0978: String beanClassName = beanClass.getName();
0979: if ("javax.swing.JPopupMenu".equals(beanClassName)) { // NOI18N
0980: return 1;
0981: }
0982: for (int i = 0; i < forbiddenContainers.length; i++)
0983: if (beanClassName.equals(forbiddenContainers[i]))
0984: return 0; // cannot be container
0985:
0986: Object isContainerValue = null;
0987: try {
0988: BeanDescriptor desc = Utilities.getBeanInfo(beanClass)
0989: .getBeanDescriptor();
0990: if (desc != null)
0991: isContainerValue = desc.getValue("isContainer"); // NOI18N
0992: } catch (Exception ex) { // ignore failure
0993: ErrorManager.getDefault().notify(
0994: ErrorManager.INFORMATIONAL, ex);
0995: } catch (Error ex) { // Issue 74002
0996: ErrorManager.getDefault().notify(
0997: ErrorManager.INFORMATIONAL, ex);
0998: }
0999:
1000: if (isContainerValue instanceof Boolean)
1001: return ((Boolean) isContainerValue).booleanValue() ? 1 : 0;
1002: return -1; // "isContainer" attribute not specified
1003: }
1004:
1005: // public static void setIsContainer(Class beanClass, boolean isContainer) {
1006: // if (beanClass == null)
1007: // return;
1008: //
1009: // Map containerBeans = formSettings.getContainerBeans();
1010: // if (containerBeans == null)
1011: // containerBeans = new HashMap();
1012: //
1013: // containerBeans.put(beanClass.getName(), isContainer ? Boolean.TRUE : Boolean.FALSE);
1014: // formSettings.setContainerBeans(containerBeans);
1015: // }
1016: //
1017: // public static void removeIsContainerRegistration(Class beanClass) {
1018: // Map containerBeans = formSettings.getContainerBeans();
1019: // if (containerBeans == null || beanClass == null)
1020: // return;
1021: //
1022: // containerBeans.remove(beanClass.getName());
1023: // formSettings.setContainerBeans(containerBeans);
1024: // }
1025:
1026: public static boolean isVisualizableClass(Class cls) {
1027: if (java.awt.Component.class.isAssignableFrom(cls)) {
1028: return true;
1029: }
1030: for (ViewConverter c : getViewConverters()) {
1031: if (c.canVisualize(cls)) {
1032: return true;
1033: }
1034: }
1035: return false;
1036: }
1037:
1038: static ViewConverter[] getViewConverters() {
1039: Lookup.Result<ViewConverter> result = Lookup.getDefault()
1040: .lookupResult(ViewConverter.class);
1041: Collection<? extends ViewConverter> all = result.allInstances();
1042: ViewConverter[] converters = new ViewConverter[all.size()];
1043: int i = all.size();
1044: for (ViewConverter c : all) {
1045: converters[--i] = c;
1046: }
1047: return converters;
1048: }
1049:
1050: static ComponentConverter[] getClassConverters() {
1051: Lookup.Result<ComponentConverter> result = Lookup.getDefault()
1052: .lookupResult(ComponentConverter.class);
1053: Collection<? extends ComponentConverter> all = result
1054: .allInstances();
1055: ComponentConverter[] converters = new ComponentConverter[all
1056: .size()];
1057: int i = all.size();
1058: for (ComponentConverter c : all) {
1059: converters[--i] = c;
1060: }
1061: return converters;
1062: }
1063:
1064: // ---------
1065:
1066: /** Returns explicit property category classification (defined in
1067: * propertyCategories table)for properties of given class.
1068: * The returned array can be used in getPropertyCategory method to get
1069: * category for individual property. Used for SWING components to
1070: * correct their default (insufficient) classification.
1071: */
1072: static Object[] getPropertiesCategoryClsf(Class beanClass,
1073: BeanDescriptor beanDescriptor) {
1074: List<Object> reClsf = null;
1075: // Class beanClass = beanInfo.getBeanDescriptor().getBeanClass();
1076:
1077: // some magic with JComponents first...
1078: if (javax.swing.JComponent.class.isAssignableFrom(beanClass)) {
1079: reClsf = new ArrayList<Object>(8);
1080: Object isContainerValue = beanDescriptor
1081: .getValue("isContainer"); // NOI18N
1082: if (isContainerValue == null
1083: || Boolean.TRUE.equals(isContainerValue)) {
1084: reClsf.add("font"); // NOI18N
1085: reClsf.add(PROP_NORMAL);
1086: } else {
1087: reClsf.add("border"); // NOI18N
1088: reClsf.add(PROP_NORMAL); // NOI18N
1089: }
1090: }
1091:
1092: return collectPropertiesClsf(beanClass, propertyCategories,
1093: reClsf);
1094: }
1095:
1096: /** Returns type of property (PROP_PREFERRED, PROP_NORMAL, PROP_EXPERT or
1097: * PROP_HIDDEN) based on PropertyDescriptor and definitions in
1098: * properties classification for given bean class (returned from
1099: * getPropertiesCategoryClsf method).
1100: */
1101: static Object getPropertyCategory(FeatureDescriptor pd,
1102: Object[] propsClsf) {
1103: Object cat = findPropertyClsf(pd.getName(), propsClsf);
1104: if (cat != null)
1105: return cat;
1106:
1107: if (pd.isHidden())
1108: return PROP_HIDDEN;
1109: if (pd.isExpert())
1110: return PROP_EXPERT;
1111: if (pd.isPreferred()
1112: || Boolean.TRUE.equals(pd.getValue("preferred"))) // NOI18N
1113: return PROP_PREFERRED;
1114: return PROP_NORMAL;
1115: }
1116:
1117: /** Returns explicit property access type classification for properties of
1118: * given class (defined in propertiesAccess table). The returned array can
1119: * be used in getPropertyAccess method to get the access type for
1120: * individual property.
1121: */
1122: static Object[] getPropertiesAccessClsf(Class beanClass) {
1123: return collectPropertiesClsf(beanClass, propertiesAccess, null);
1124: }
1125:
1126: /** Returns access type for given property (as FormProperty constant).
1127: * 0 if no restriction is explicitly defined.
1128: */
1129: static int getPropertyAccess(PropertyDescriptor pd,
1130: Object[] propsClsf) {
1131: Object access = findPropertyClsf(pd.getName(), propsClsf);
1132: return access == null ? 0 : ((Integer) access).intValue();
1133: }
1134:
1135: static Object[] getPropertiesParentChildDepsClsf(Class beanClass) {
1136: return collectPropertiesClsf(beanClass, propertyContainerDeps,
1137: null);
1138: }
1139:
1140: static String getPropertyParentChildDependency(
1141: PropertyDescriptor pd, Object[] propClsf) {
1142: return (String) findPropertyClsf(pd.getName(), propClsf);
1143: }
1144:
1145: /**
1146: * Finds out if given property can hold text with <html> prefix. Basically
1147: * it must be a text property of a Swing component. Used by String property
1148: * editor.
1149: *
1150: * @param property property to check.
1151: * @return true if the property can hold <html> text
1152: */
1153: public static boolean isHTMLTextProperty(Node.Property property) {
1154: if (property.getValueType() == String.class) {
1155: if (property instanceof RADProperty) {
1156: Class beanClass = ((RADProperty) property)
1157: .getRADComponent().getBeanClass();
1158: Object[] clsf = collectPropertiesClsf(beanClass,
1159: swingTextProperties, null);
1160: return findPropertyClsf(property.getName(), clsf) != null;
1161: } else if (property.getName().equals(
1162: "TabConstraints.tabTitle")) { // NOI18N
1163: return true;
1164: }
1165: }
1166: return false;
1167: }
1168:
1169: private static Object[] collectPropertiesClsf(Class beanClass,
1170: Object[][] table, java.util.List<Object> list) {
1171: // Set of names of super classes of the bean and interfaces implemented by the bean.
1172: Set<String> super Classes = super Classes(beanClass);
1173:
1174: for (int i = 0; i < table.length; i++) {
1175: Object[] clsf = table[i];
1176: String refClass = (String) clsf[0];
1177: Object subclasses = clsf[1];
1178:
1179: if (refClass.equals(beanClass.getName())
1180: || (subclasses == CLASS_AND_SUBCLASSES && super Classes
1181: .contains(refClass))
1182: || (subclasses == CLASS_AND_SWING_SUBCLASSES
1183: && super Classes.contains(refClass) && beanClass
1184: .getName().startsWith("javax.swing."))) { // NOI18N
1185: if (list == null)
1186: list = new ArrayList<Object>(8);
1187: for (int j = 2; j < clsf.length; j++)
1188: list.add(clsf[j]);
1189: }
1190: }
1191:
1192: if (list != null) {
1193: Object[] array = new Object[list.size()];
1194: list.toArray(array);
1195: return array;
1196: }
1197: return null;
1198: }
1199:
1200: private static Object findPropertyClsf(String name, Object[] clsf) {
1201: if (clsf != null) {
1202: int i = clsf.length;
1203: while (i > 0) {
1204: if (clsf[i - 2].equals(name))
1205: return clsf[i - 1];
1206: i -= 2;
1207: }
1208: }
1209: return null;
1210: }
1211:
1212: static boolean isMarkedParentDependentProperty(Node.Property prop) {
1213: return Boolean.TRUE.equals(prop.getValue(PROP_REQUIRES_PARENT));
1214: }
1215:
1216: static boolean isMarkedChildrenDependentProperty(Node.Property prop) {
1217: return Boolean.TRUE.equals(prop
1218: .getValue(PROP_REQUIRES_CHILDREN));
1219: }
1220:
1221: // -----
1222:
1223: private static abstract class DefaultValueDeviation {
1224: protected Object[] values;
1225:
1226: DefaultValueDeviation(Object[] values) {
1227: this .values = values;
1228: }
1229:
1230: abstract Object getValue(Object beanInstance);
1231: }
1232:
1233: private static Map<String, DefaultValueDeviation> getDefaultValueDeviations(
1234: Object bean) {
1235: if (defaultValueDeviations == null) {
1236: defaultValueDeviations = new HashMap<Class<?>, Map<String, DefaultValueDeviation>>();
1237: }
1238: Map<String, DefaultValueDeviation> deviationMap = defaultValueDeviations
1239: .get(bean.getClass());
1240: if (deviationMap == null) {
1241: if (bean instanceof javax.swing.JTextField) {
1242: // text field has different default background when not editable
1243: Object[] values = new Color[2];
1244: javax.swing.JTextField jtf = new javax.swing.JTextField();
1245: values[0] = jtf.getBackground();
1246: jtf.setEditable(false);
1247: values[1] = jtf.getBackground();
1248: deviationMap = new HashMap<String, DefaultValueDeviation>();
1249: deviationMap.put("background", // NOI18N
1250: new DefaultValueDeviation(values) {
1251: Object getValue(Object beanInstance) {
1252: return ((javax.swing.JTextField) beanInstance)
1253: .isEditable() ? this .values[0]
1254: : this .values[1];
1255: }
1256: });
1257: defaultValueDeviations.put(bean.getClass(),
1258: deviationMap);
1259: }
1260: }
1261: return deviationMap;
1262: }
1263:
1264: static Object getSpecialDefaultPropertyValue(Object bean,
1265: String propName) {
1266: Map<String, DefaultValueDeviation> deviationMap = getDefaultValueDeviations(bean);
1267: if (deviationMap != null) {
1268: DefaultValueDeviation deviation = deviationMap
1269: .get(propName);
1270: if (deviation != null) {
1271: return deviation.getValue(bean);
1272: }
1273: }
1274: return BeanSupport.NO_VALUE;
1275: }
1276:
1277: // -----
1278:
1279: /**
1280: * Utility method that returns name of the method.
1281: *
1282: * @param desc descriptor of the method.
1283: * @return a formatted name of specified method
1284: */
1285: public static String getMethodName(MethodDescriptor desc) {
1286: return getMethodName(desc.getName(), desc.getMethod()
1287: .getParameterTypes());
1288: }
1289:
1290: public static String getMethodName(String name, Class[] params) {
1291: StringBuffer sb = new StringBuffer(name);
1292: if ((params == null) || (params.length == 0)) {
1293: sb.append("()"); // NOI18N
1294: } else {
1295: for (int i = 0; i < params.length; i++) {
1296: if (i == 0)
1297: sb.append("("); // NOI18N
1298: else
1299: sb.append(", "); // NOI18N
1300: sb.append(Utilities.getShortClassName(params[i]));
1301: }
1302: sb.append(")"); // NOI18N
1303: }
1304:
1305: return sb.toString();
1306: }
1307:
1308: static void sortProperties(Node.Property[] properties) {
1309: Arrays.sort(properties, new Comparator<Node.Property>() {
1310: public int compare(Node.Property o1, Node.Property o2) {
1311: String n1 = o1.getDisplayName();
1312: String n2 = o2.getDisplayName();
1313: return n1.compareTo(n2);
1314: }
1315: });
1316: }
1317:
1318: static void reorderProperties(Class beanClass,
1319: RADProperty[] properties) {
1320: sortProperties(properties);
1321: Object[] order = collectPropertiesOrder(beanClass,
1322: propertyOrder);
1323: for (int i = 0; i < order.length / 2; i++) {
1324: updatePropertiesOrder(properties, (String) order[2 * i],
1325: (String) order[2 * i + 1]);
1326: }
1327: }
1328:
1329: private static void updatePropertiesOrder(RADProperty[] properties,
1330: String firstProp, String secondProp) {
1331: int firstIndex = findPropertyIndex(properties, firstProp);
1332: int secondIndex = findPropertyIndex(properties, secondProp);
1333: if ((firstIndex != -1) && (secondIndex != -1)
1334: && (firstIndex > secondIndex)) {
1335: // Move the first one before the second
1336: RADProperty first = properties[firstIndex];
1337: for (int i = firstIndex; i > secondIndex; i--) {
1338: properties[i] = properties[i - 1];
1339: }
1340: properties[secondIndex] = first;
1341: }
1342: }
1343:
1344: private static int findPropertyIndex(RADProperty[] properties,
1345: String property) {
1346: int index = -1;
1347: for (int i = 0; i < properties.length; i++) {
1348: if (property.equals(properties[i].getName())) {
1349: index = i;
1350: break;
1351: }
1352: }
1353: return index;
1354: }
1355:
1356: private static Object[] collectPropertiesOrder(Class beanClass,
1357: Object[][] table) {
1358: // Set of names of super classes of the bean and interfaces implemented by the bean.
1359: Set<String> super Classes = super Classes(beanClass);
1360:
1361: java.util.List<Object> list = new LinkedList<Object>();
1362: for (int i = 0; i < table.length; i++) {
1363: Object[] order = table[i];
1364: String refClass = (String) order[0];
1365:
1366: if (super Classes.contains(refClass)) {
1367: for (int j = 1; j < order.length; j++) {
1368: list.add(order[j]);
1369: }
1370: }
1371: }
1372: return list.toArray();
1373: }
1374:
1375: public static void checkVersionLevelForProperty(
1376: FormProperty property, Object value, PropertyEditor editor) {
1377: FormModel formModel = property.getPropertyContext()
1378: .getFormModel();
1379: if (formModel != null) {
1380: if (editor instanceof FormAwareEditor) {
1381: ((FormAwareEditor) editor).updateFormVersionLevel();
1382: } else if (value instanceof ResourceValue) {
1383: formModel.raiseVersionLevel(FormModel.FormVersion.NB60,
1384: FormModel.FormVersion.NB60);
1385: }
1386: }
1387: // this method is not called for binding properties - see BindingProperty.setValue
1388: }
1389:
1390: // ---------
1391:
1392: /** Loads a class of a component to be used (instantiated) in the form
1393: * editor. The class might be either a support class being part of the IDE,
1394: * or a user class defined externally (by a project classpath).
1395: * There are also separate loadSystemClass for loading a module class only.
1396: *
1397: * @param name String name of the class
1398: * @param formFile FileObject representing the form file as part of a project
1399: * @return loaded class.
1400: * @throws java.lang.ClassNotFoundException if there is a problem with class loading.
1401: */
1402: public static Class loadClass(String name, FileObject formFile)
1403: throws ClassNotFoundException {
1404: return ClassPathUtils.loadClass(name, formFile);
1405: }
1406:
1407: public static Class loadClass(String name, FormModel form)
1408: throws ClassNotFoundException {
1409: FormDataObject dobj = FormEditor.getFormDataObject(form);
1410: return dobj != null ? loadClass(name, dobj.getFormFile())
1411: : loadSystemClass(name); // layout test may have no data object
1412: }
1413:
1414: /** Loads a class using IDE system class loader. Usable for form module
1415: * support classes, property editors, etc.
1416: *
1417: * @param name name of the class to load.
1418: * @return loaded class.
1419: * @throws java.lang.ClassNotFoundException if there is a problem with class loading.
1420: */
1421: public static Class loadSystemClass(String name)
1422: throws ClassNotFoundException {
1423: ClassLoader loader = Lookup.getDefault().lookup(
1424: ClassLoader.class);
1425: if (loader == null)
1426: throw new ClassNotFoundException();
1427:
1428: return Class.forName(name, true, loader);
1429: }
1430:
1431: // ---------
1432:
1433: private static class OIS extends ObjectInputStream {
1434: private ClassLoader classLoader;
1435: private FormModel formModel;
1436:
1437: public OIS(InputStream is, ClassLoader loader,
1438: FormModel formModel) throws IOException {
1439: super (is);
1440: this .formModel = formModel;
1441: classLoader = loader;
1442: }
1443:
1444: @Override
1445: protected Class resolveClass(ObjectStreamClass streamCls)
1446: throws IOException, ClassNotFoundException {
1447: String name = streamCls.getName();
1448: return loadClass(name);
1449: }
1450:
1451: private Class loadClass(String name)
1452: throws ClassNotFoundException {
1453: if (classLoader != null) {
1454: try {
1455: return Class.forName(name, true, classLoader);
1456: } catch (ClassNotFoundException ex) {
1457: }
1458: }
1459: return FormUtils.loadClass(name, formModel);
1460: }
1461:
1462: }
1463:
1464: public static List<RADComponent> getSelectedLayoutComponents(
1465: Node[] nodes) {
1466: if ((nodes == null) || (nodes.length < 1))
1467: return null;
1468:
1469: List<RADComponent> components = new ArrayList<RADComponent>();
1470: for (int i = 0; i < nodes.length; i++) {
1471: RADComponentCookie radCookie = nodes[i]
1472: .getCookie(RADComponentCookie.class);
1473: if (radCookie != null) {
1474: RADComponent metacomp = radCookie.getRADComponent();
1475: if ((metacomp instanceof RADVisualComponent)) {
1476: RADVisualComponent visComp = (RADVisualComponent) metacomp;
1477: RADVisualContainer visCont = visComp
1478: .getParentContainer();
1479: if ((visCont != null)
1480: && javax.swing.JScrollPane.class
1481: .isAssignableFrom(visCont
1482: .getBeanInstance()
1483: .getClass())) {
1484: visComp = visCont;
1485: visCont = visCont.getParentContainer();
1486: }
1487:
1488: if (isVisualInDesigner(visComp)
1489: && (visCont != null)
1490: && (visCont.getLayoutSupport() == null)
1491: && !visComp.isMenuComponent()) {
1492: components.add(visComp);
1493: } else {
1494: return null;
1495: }
1496: } else {
1497: return null;
1498: }
1499: }
1500: }
1501: return components;
1502: }
1503:
1504: public static boolean isVisualInDesigner(RADComponent comp) {
1505: if (comp instanceof RADVisualComponent) {
1506: FormDesigner designer = FormEditor.getFormDesigner(comp
1507: .getFormModel());
1508: if (designer != null) {
1509: return designer.isInDesigner((RADVisualComponent) comp);
1510: }
1511: }
1512: return false;
1513: }
1514:
1515: private static Set<String> super Classes(Class beanClass) {
1516: Set<String> super Classes = new HashSet<String>();
1517: Class[] infaces = beanClass.getInterfaces();
1518: for (int i = 0; i < infaces.length; i++) {
1519: super Classes.add(infaces[i].getName());
1520: }
1521: Class super Class = beanClass;
1522: do {
1523: super Classes.add(super Class.getName());
1524: } while ((super Class = super Class.getSuperclass()) != null);
1525: return super Classes;
1526: }
1527:
1528: /**
1529: * "Un-generifies" the given type.
1530: *
1531: * @param type type to "un-generify".
1532: * @return "un-generified" type.
1533: */
1534: public static Class typeToClass(TypeHelper type) {
1535: Class clazz = Object.class;
1536: if (type == null)
1537: return clazz;
1538: Type t = type.getType();
1539: if (t instanceof Class) {
1540: clazz = (Class) t;
1541: } else if (t instanceof ParameterizedType) {
1542: ParameterizedType pt = (ParameterizedType) t;
1543: clazz = (Class) pt.getRawType();
1544: } else if (t instanceof WildcardType) {
1545: WildcardType wt = (WildcardType) t;
1546: for (Type bound : wt.getUpperBounds()) {
1547: clazz = typeToClass(new TypeHelper(bound, type
1548: .getActualTypeArgs()));
1549: if (!Object.class.equals(clazz) && !clazz.isInterface())
1550: break;
1551: }
1552: } else if (t instanceof TypeVariable) {
1553: TypeVariable tv = (TypeVariable) t;
1554: Map<String, TypeHelper> actualTypeArgs = type
1555: .getActualTypeArgs();
1556: if (actualTypeArgs != null) {
1557: TypeHelper tt = actualTypeArgs.get(tv.getName());
1558: if (tt != null) {
1559: Type typ = typeToClass(tt);
1560: clazz = typeToClass(new TypeHelper(typ,
1561: actualTypeArgs));
1562: }
1563: }
1564: }
1565: return clazz;
1566: }
1567:
1568: /**
1569: * Represents generified type with (possibly) some type parameters set.
1570: */
1571: public static class TypeHelper {
1572: /** The type. */
1573: private Type type;
1574: /** Fully qualified name of the type. */
1575: private String name;
1576: /** Type parameters that has been set. */
1577: private Map<String, TypeHelper> actualTypeArgs;
1578:
1579: /**
1580: * Creates <code>TypeHelper</code> that represents <code>Object</code>.
1581: */
1582: public TypeHelper() {
1583: this (Object.class, null);
1584: }
1585:
1586: public TypeHelper(String name) {
1587: this (name, null);
1588: }
1589:
1590: public TypeHelper(String name,
1591: Map<String, TypeHelper> actualTypeArgs) {
1592: this .name = name;
1593: this .actualTypeArgs = actualTypeArgs;
1594: }
1595:
1596: /**
1597: * Creates <code>TypeHelper</code> that represents given type with
1598: * no type arguments set.
1599: *
1600: * @param type type.
1601: */
1602: public TypeHelper(Type type) {
1603: this (type, null);
1604: }
1605:
1606: /**
1607: * Creates <code>TypeHelper</code> that represents given type with
1608: * some type arguments set.
1609: *
1610: * @param type type.
1611: * @param actualTypeArgs type parameters that has been set.
1612: */
1613: public TypeHelper(Type type,
1614: Map<String, TypeHelper> actualTypeArgs) {
1615: this .type = type;
1616: this .actualTypeArgs = actualTypeArgs;
1617: }
1618:
1619: /**
1620: * Returns generified type represented by this instance.
1621: *
1622: * @return generified type represented by this instance.
1623: */
1624: public Type getType() {
1625: return type;
1626: }
1627:
1628: public String getName() {
1629: return name;
1630: }
1631:
1632: /**
1633: * Returns map of type parameters that has been set.
1634: *
1635: * @return map or <code>null</code> if the type is not generified
1636: * or none of its type parameters has been set.
1637: */
1638: public Map<String, TypeHelper> getActualTypeArgs() {
1639: return actualTypeArgs;
1640: }
1641:
1642: /**
1643: * Returns (undefined ;-)) normalized form of this type.
1644: */
1645: TypeHelper normalize() {
1646: TypeHelper t = this ;
1647: if (type instanceof TypeVariable) {
1648: if (actualTypeArgs != null) {
1649: TypeVariable tv = (TypeVariable) type;
1650: t = actualTypeArgs.get(tv.getName());
1651: }
1652: } else if (type instanceof ParameterizedType) {
1653: ParameterizedType pt = (ParameterizedType) type;
1654: Class clazz = (Class) pt.getRawType();
1655: Map<String, TypeHelper> newMap = new HashMap<String, TypeHelper>();
1656: Type[] args = pt.getActualTypeArguments();
1657: TypeVariable[] tvar = clazz.getTypeParameters();
1658: for (int i = 0; i < tvar.length; i++) {
1659: Type arg = args[i];
1660: TypeHelper sub = new TypeHelper(arg, actualTypeArgs)
1661: .normalize();
1662: newMap.put(tvar[i].getName(), new TypeHelper(sub
1663: .getType()));
1664: }
1665: t = new TypeHelper(clazz, newMap);
1666: } else if (type instanceof WildcardType) {
1667: WildcardType wt = (WildcardType) type;
1668: // PENDING more upper bounds
1669: TypeHelper sub = new TypeHelper(wt.getUpperBounds()[0],
1670: actualTypeArgs).normalize();
1671: t = new TypeHelper(sub.getType());
1672: }
1673: return t;
1674: }
1675:
1676: @Override
1677: public boolean equals(Object o) {
1678: if (o instanceof TypeHelper) {
1679: TypeHelper t = (TypeHelper) o;
1680: return ((name == null) ? (t.name == null) : name
1681: .equals(t.name))
1682: && ((type == null) ? (t.type == null) : type
1683: .equals(t.type));
1684: } else {
1685: return false;
1686: }
1687: }
1688:
1689: @Override
1690: public int hashCode() {
1691: int hash = 3;
1692: hash = 67 * hash
1693: + (this .type != null ? this .type.hashCode() : 0);
1694: hash = 67 * hash
1695: + (this .name != null ? this .name.hashCode() : 0);
1696: return hash;
1697: }
1698: }
1699:
1700: public static String autobox(String className) {
1701: if (className.equals("byte")
1702: || className.equals("short")
1703: || className.equals("long") // NOI18N
1704: || className.equals("float")
1705: || className.equals("double")
1706: || className.equals("boolean")) { // NOI18N
1707: className = "java.lang."
1708: + Character.toUpperCase(className.charAt(0))
1709: + className.substring(1); // NOI18N
1710: } else if (className.equals("int")) { // NOI18N
1711: className = "java.lang.Integer"; // NOI18N
1712: } else if (className.equals("char")) { // NOI18N
1713: className = "java.lang.Character"; // NOI18N
1714: }
1715: return className;
1716: }
1717:
1718: public static String escapeCharactersInString(String str) {
1719: StringBuilder buf = new StringBuilder(str.length() * 6); // x -> \u1234
1720: char[] chars = str.toCharArray();
1721: for (int i = 0; i < chars.length; i++) {
1722: char c = chars[i];
1723: switch (c) {
1724: case '\b':
1725: buf.append("\\b");
1726: break; // NOI18N
1727: case '\t':
1728: buf.append("\\t");
1729: break; // NOI18N
1730: case '\n':
1731: buf.append("\\n");
1732: break; // NOI18N
1733: case '\f':
1734: buf.append("\\f");
1735: break; // NOI18N
1736: case '\r':
1737: buf.append("\\r");
1738: break; // NOI18N
1739: case '\"':
1740: buf.append("\\\"");
1741: break; // NOI18N
1742: case '\\':
1743: buf.append("\\\\");
1744: break; // NOI18N
1745: default:
1746: if (c >= 0x0020/* && c <= 0x007f*/)
1747: buf.append(c);
1748: else {
1749: buf.append("\\u"); // NOI18N
1750: String hex = Integer.toHexString(c);
1751: for (int j = 0; j < 4 - hex.length(); j++)
1752: buf.append('0');
1753: buf.append(hex);
1754: }
1755: }
1756: }
1757: return buf.toString();
1758: }
1759:
1760: /*
1761: * Calls Introspector.getBeanInfo() more safely to handle 3rd party BeanInfos
1762: * that may be broken or malformed. This is a replacement for Introspector.getBeanInfo().
1763: * @see java.beans.Introspector.getBeanInfo(Class)
1764: */
1765: public static BeanInfo getBeanInfo(Class clazz)
1766: throws IntrospectionException {
1767: try {
1768: return Utilities.getBeanInfo(clazz);//, java.beans.Introspector.USE_ALL_BEANINFO);
1769: } catch (Exception ex) {
1770: org.openide.ErrorManager.getDefault().notify(
1771: org.openide.ErrorManager.INFORMATIONAL, ex);
1772: return getBeanInfo(clazz,
1773: Introspector.IGNORE_IMMEDIATE_BEANINFO);
1774: } catch (Error err) {
1775: org.openide.ErrorManager.getDefault().notify(
1776: org.openide.ErrorManager.INFORMATIONAL, err);
1777: return getBeanInfo(clazz,
1778: Introspector.IGNORE_IMMEDIATE_BEANINFO);
1779: }
1780: }
1781:
1782: // helper method for getBeanInfo(Class)
1783: private static BeanInfo getBeanInfo(Class clazz, int mode)
1784: throws IntrospectionException {
1785: if (mode == Introspector.IGNORE_IMMEDIATE_BEANINFO) {
1786: try {
1787: return Introspector.getBeanInfo(clazz,
1788: Introspector.IGNORE_IMMEDIATE_BEANINFO);
1789: } catch (Exception ex) {
1790: org.openide.ErrorManager.getDefault().notify(
1791: org.openide.ErrorManager.INFORMATIONAL, ex);
1792: return getBeanInfo(clazz,
1793: Introspector.IGNORE_ALL_BEANINFO);
1794: } catch (Error err) {
1795: org.openide.ErrorManager.getDefault().notify(
1796: org.openide.ErrorManager.INFORMATIONAL, err);
1797: return getBeanInfo(clazz,
1798: Introspector.IGNORE_ALL_BEANINFO);
1799: }
1800: } else {
1801: assert mode == Introspector.IGNORE_ALL_BEANINFO;
1802: return Introspector.getBeanInfo(clazz,
1803: Introspector.IGNORE_ALL_BEANINFO);
1804: }
1805: }
1806: }
|