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.DesignBean;
044: import com.sun.rave.designtime.DesignProperty;
045: import com.sun.rave.designtime.PropertyEditor2;
046: import com.sun.rave.designtime.faces.FacesBindingPropertyEditor;
047: import com.sun.rave.designtime.faces.FacesDesignContext;
048: import com.sun.rave.designtime.faces.FacesDesignProject;
049: import java.beans.PropertyEditorSupport;
050: import java.text.MessageFormat;
051: import java.util.Comparator;
052: import java.util.HashMap;
053: import java.util.Iterator;
054: import java.util.ResourceBundle;
055: import java.util.TreeSet;
056: import javax.faces.application.Application;
057: import javax.faces.context.FacesContext;
058: import javax.faces.convert.*;
059: import javax.faces.el.ValueBinding;
060:
061: /**
062: * A property editor for converter properties.
063: *
064: * @author gjmurphy
065: */
066: public class ConverterPropertyEditor extends PropertyEditorBase
067: implements FacesBindingPropertyEditor,
068: com.sun.rave.propertyeditors.ConverterPropertyEditor {
069:
070: private static final ResourceBundle bundle = ResourceBundle
071: .getBundle("org.netbeans.modules.visualweb.propertyeditors.Bundle"); //NOI18N
072:
073: // Some default JSF converters, used in the event that the project context cannot be scanned
074: // for converters
075: private static final Class[] defaultFacesConverterClasses = new Class[] {
076: BooleanConverter.class, ByteConverter.class,
077: CharacterConverter.class, DateTimeConverter.class,
078: DoubleConverter.class, FloatConverter.class,
079: IntegerConverter.class, LongConverter.class,
080: NumberConverter.class, ShortConverter.class };
081:
082: public String[] getTags() {
083: DesignBean[] converterBeans = getConverterBeans();
084: String[] converterLabels = getConverterLabels();
085: String[] tags = new String[converterBeans.length
086: + converterLabels.length + 1];
087: int index = 0;
088: tags[index++] = "";
089: for (int i = 0; i < converterBeans.length; i++) {
090: tags[index++] = converterBeans[i].getInstanceName();
091: }
092: for (int i = 0; i < converterLabels.length; i++) {
093: tags[index++] = converterLabels[i];
094: }
095: return tags;
096: }
097:
098: public void setAsText(String text) throws IllegalArgumentException {
099: if (text == null || text.trim().length() == 0) {
100: this .setValue(null);
101: return;
102: }
103: DesignBean[] converterBeans = getConverterBeans();
104: Converter converter = null;
105: // Determine if user selected a converter that is already created
106: for (int i = 0; i < converterBeans.length && converter == null; i++) {
107: if (converterBeans[i].getInstanceName().equals(text)) {
108: converter = (Converter) converterBeans[i].getInstance();
109: }
110: }
111: if (converter == null) {
112: String[] converterLabels = getConverterLabels();
113: // Created a new converter of the type the user selected
114: Class[] converterClasses = getConverterClasses();
115: for (int i = 0; i < converterLabels.length
116: && converter == null; i++) {
117: if (converterLabels[i].equals(text)) {
118: DesignProperty designProperty = this
119: .getDesignProperty();
120: DesignBean createResult = designProperty
121: .getDesignBean().getDesignContext()
122: .createBean(converterClasses[i].getName(),
123: null, null);
124: if (createResult != null) {
125: converter = (Converter) createResult
126: .getInstance();
127: }
128: }
129: }
130: }
131: this .setValue(converter);
132: }
133:
134: public String getAsText() {
135: Object value = getValue();
136: if (value instanceof ValueBinding) {
137: return ((ValueBinding) value).getExpressionString();
138: }
139: if (value instanceof String) {
140: return (String) value;
141: }
142: DesignBean designBean = getDesignBean();
143: if (designBean != null) {
144: if (designBean.getInstance() instanceof NumberConverter) {
145: // Here are the defautls the NumberConverter has:
146: // - min integer digits to 1
147: // - max integer digits to 40
148: // - min fractional digites to 0
149: // - max fractional digits to 3
150: designBean.getProperty("minIntegerDigits").setValue(
151: new Integer(1));
152: designBean.getProperty("maxIntegerDigits").setValue(
153: new Integer(40));
154: designBean.getProperty("minFractionDigits").setValue(
155: new Integer(0));
156: designBean.getProperty("maxFractionDigits").setValue(
157: new Integer(3));
158: }
159: }
160: return (designBean == null) ? "" : designBean.getInstanceName(); //NOI18N
161: }
162:
163: public boolean supportsCustomEditor() {
164: return false;
165: }
166:
167: private static Comparator converterComparator = new Comparator() {
168: public int compare(Object obj1, Object obj2) {
169: String name1 = ((Class) obj1).getName();
170: String name2 = ((Class) obj2).getName();
171: return name1
172: .substring(name1.lastIndexOf('.') + 1)
173: .compareTo(
174: name2.substring(name2.lastIndexOf('.') + 1));
175: }
176: };
177:
178: // A global map of classes to converters for those classes, used to avoid expensive
179: // repetitive recalculation of converter classes. If a new component library is
180: // imported into the IDE, any converters will be discovered and added to the map.
181: private static HashMap converterClassMap = new HashMap();
182:
183: private Class[] converterClasses;
184:
185: /**
186: * Generates an array of classes for all converter components registered with the
187: * design-time JSF application.
188: */
189: protected Class[] getConverterClasses() {
190: if (converterClasses != null)
191: return converterClasses;
192: DesignProperty designProperty = this .getDesignProperty();
193: if (designProperty == null)
194: return defaultFacesConverterClasses;
195: FacesContext facesContext = ((FacesDesignContext) designProperty
196: .getDesignBean().getDesignContext()).getFacesContext();
197: Application application = facesContext.getApplication();
198:
199: TreeSet set = new TreeSet(converterComparator);
200:
201: Iterator iter;
202:
203: FacesDesignProject facesDesignProject = (FacesDesignProject) designProperty
204: .getDesignBean().getDesignContext().getProject();
205: ClassLoader oldContextClassLoader = Thread.currentThread()
206: .getContextClassLoader();
207: try {
208: Thread.currentThread().setContextClassLoader(
209: facesDesignProject.getContextClassLoader());
210: // Add the conveters registered by types
211: iter = application.getConverterTypes();
212: while (iter.hasNext()) {
213: Class propertyClass = (Class) iter.next();
214: if (!converterClassMap.containsKey(propertyClass)) {
215: Converter converter = application
216: .createConverter(propertyClass);
217: converterClassMap.put(propertyClass, converter
218: .getClass());
219: }
220: set.add(converterClassMap.get(propertyClass));
221: }
222:
223: // Add the converters registered by Ids
224: Iterator idConverterIter = application.getConverterIds();
225: while (idConverterIter.hasNext()) {
226: Converter converter = application
227: .createConverter((String) idConverterIter
228: .next());
229: set.add(converter.getClass());
230: }
231: } finally {
232: Thread.currentThread().setContextClassLoader(
233: oldContextClassLoader);
234: }
235:
236: converterClasses = new Class[set.size()];
237: iter = set.iterator();
238: for (int i = 0; i < converterClasses.length; i++)
239: converterClasses[i] = (Class) iter.next();
240:
241: return converterClasses;
242: }
243:
244: private String[] converterLabels;
245:
246: /**
247: * Generates an array of display labels for all converter classes.
248: */
249: protected String[] getConverterLabels() {
250: if (converterLabels != null)
251: return converterLabels;
252: Class[] converterClasses = getConverterClasses();
253: converterLabels = new String[converterClasses.length];
254: MessageFormat labelFormat = new MessageFormat(bundle
255: .getString("ConverterPropertyEditor.newConverterLabel")); //NOI18N
256: Object[] args = new Object[1];
257: for (int i = 0; i < converterClasses.length; i++) {
258: String name = converterClasses[i].getName();
259: args[0] = name.substring(name.lastIndexOf('.') + 1);
260: converterLabels[i] = labelFormat.format(args);
261: }
262: return converterLabels;
263: }
264:
265: private DesignBean getDesignBean() {
266: Object value = getValue();
267: DesignBean[] lbeans = getConverterBeans();
268: for (int i = 0; i < lbeans.length; i++) {
269: if (lbeans[i].getInstance() == value) {
270: return lbeans[i];
271: }
272: }
273: return null;
274: }
275:
276: private DesignBean[] getConverterBeans() {
277: DesignProperty designProperty = this .getDesignProperty();
278: if (designProperty == null)
279: return new DesignBean[0];
280: return designProperty.getDesignBean().getDesignContext()
281: .getBeansOfType(Converter.class);
282: }
283:
284: }
|