001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.propertyeditors;
042:
043: import com.sun.rave.designtime.DesignProperty;
044: import com.sun.rave.propertyeditors.resolver.PropertyEditorResolver;
045: import java.awt.Component;
046: import java.beans.PropertyChangeEvent;
047: import java.beans.PropertyDescriptor;
048: import java.beans.PropertyEditor;
049: import java.beans.PropertyVetoException;
050: import java.beans.VetoableChangeListener;
051: import java.util.Collection;
052: import javax.swing.JPanel;
053: import org.openide.explorer.propertysheet.PropertyEnv;
054: import org.openide.util.Lookup;
055:
056: /**
057: * A abstract base class for custom property editors. Editor panels that extend
058: * this class are intended for use either as custom editors returned by {@link
059: * java.beans.PropertyEditor#getCustomEditor()}, or as panels used within a
060: * design-time customizer. The initial state of the property and its context
061: * is made available to the editor in the design property passed to its
062: * constructor. When the user has clicked "ok" in the containing panel, the
063: * editor method <code>getPropertyValue()</code> is called and should return
064: * the current value.
065: *
066: * @author gjmurphy
067: */
068: public abstract class PropertyPanelBase extends JPanel {
069:
070: /**
071: * A utility factory method for creating a property panel, such as for use in a
072: * component customizer. If this method is unable to create a property panel
073: * for the given design property, it returns null. This may happen if the
074: * property is value bound, if the property does not specify a property editor
075: * class, or if the component returned by PropertyEditor.getCustomEditor() is
076: * not an instance of this base class.
077: */
078: public static PropertyPanelBase createPropertyPanel(
079: DesignProperty designProperty) {
080: PropertyDescriptor descriptor = designProperty
081: .getPropertyDescriptor();
082: Class editorClass = descriptor.getPropertyEditorClass();
083: if (editorClass == null)
084: return null;
085: try {
086: // Ask each property editor resolver service that was registered with the
087: // IDE for an editor appropriate for the property descriptor
088:
089: PropertyEditor editor = null;
090:
091: for (PropertyEditorResolver resolver : getPropertyEditorResolvers()) {
092: editor = resolver.getEditor(descriptor);
093: if (editor != null)
094: break;
095: }
096: if (editor == null) {
097: editor = (PropertyEditor) editorClass.newInstance();
098: }
099: if (PropertyEditorBase.class.isAssignableFrom(editor
100: .getClass()))
101: ((PropertyEditorBase) editor)
102: .setDesignProperty(designProperty);
103: editor.setValue(designProperty.getValue());
104: Component customEditor = editor.getCustomEditor();
105: if (PropertyPanelBase.class.isAssignableFrom(customEditor
106: .getClass()))
107: return (PropertyPanelBase) customEditor;
108: } catch (InstantiationException e) {
109: e.printStackTrace();
110: } catch (IllegalAccessException e) {
111: e.printStackTrace();
112: }
113: return null;
114: }
115:
116: private static Lookup.Result propertyEditorResolverLookupResult;
117:
118: /**
119: * Look up all property editor resolvers registered with the current IDE session.
120: */
121: private static PropertyEditorResolver[] getPropertyEditorResolvers() {
122: if (propertyEditorResolverLookupResult == null) {
123: Lookup.Template template = new Lookup.Template(
124: PropertyEditorResolver.class);
125: Lookup lookup = Lookup.getDefault();
126: propertyEditorResolverLookupResult = lookup
127: .lookup(template);
128: }
129: Collection instances = propertyEditorResolverLookupResult
130: .allInstances();
131: return (PropertyEditorResolver[]) instances
132: .toArray(new PropertyEditorResolver[instances.size()]);
133: }
134:
135: PropertyEditorBase propertyEditor;
136: PanelSubmissionListener panelSubmissionListener;
137:
138: /**
139: * Create a new instance of PropertyPanelBase, for the property editor specified.
140: * Property editors that extend {@link PropertyEditorBase} should pass themselves
141: * as an argument to the constructor of their property panel when the panel is
142: * created, in response to a call to {@link java.beans.PropertyEditor#getCustomEditor()}.
143: */
144: public PropertyPanelBase(PropertyEditorBase propertyEditor) {
145: PropertyEnv propertyEnv = propertyEditor.getEnv();
146: if (propertyEnv != null) {
147: propertyEnv.setState(PropertyEnv.STATE_NEEDS_VALIDATION);
148: panelSubmissionListener = new PanelSubmissionListener(
149: propertyEditor);
150: propertyEnv
151: .addVetoableChangeListener(panelSubmissionListener);
152: this .propertyEditor = propertyEditor;
153: }
154: }
155:
156: /**
157: * This method is called just after the user has clicked "ok". Sub-classes
158: * should use this method to calculate and return the property value.
159: */
160: public abstract Object getPropertyValue();
161:
162: protected void finalize() throws Throwable {
163: if (panelSubmissionListener != null)
164: this .propertyEditor.getEnv().removeVetoableChangeListener(
165: panelSubmissionListener);
166: super .finalize();
167: }
168:
169: class PanelSubmissionListener implements VetoableChangeListener {
170:
171: PropertyEditorBase propertyEditor;
172:
173: PanelSubmissionListener(PropertyEditorBase propertyEditor) {
174: this .propertyEditor = propertyEditor;
175: }
176:
177: public final void vetoableChange(PropertyChangeEvent event)
178: throws PropertyVetoException {
179: if (PropertyEnv.PROP_STATE.equals(event.getPropertyName())) {
180: propertyEditor.setValue(getPropertyValue());
181: // In theory, it should not be necessary to fire a property change event
182: // at this point, but NetBeans will not otherwise pick up the new value
183: propertyEditor.firePropertyChange();
184: propertyEditor.getEnv().setState(
185: PropertyEnv.STATE_VALID);
186: }
187: }
188: }
189:
190: }
|