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.domains.Domain;
045: import com.sun.rave.propertyeditors.domains.EditableDomain;
046: import com.sun.rave.propertyeditors.domains.Element;
047: import java.awt.Component;
048:
049: /**
050: * A property editor for domains, that allows exactly one element from a domain to
051: * be selected as the property value. Element labels are treated as the "text"
052: * view of an element, and the currently selected element's value property is
053: * treated as the editor's current value. This editor typically manifests itself as
054: * an in-line drop-down selector of element labels. If a domain is large, a
055: * custom property editor will also be available, which facilitates searching
056: * through long lists (see {@link SelectOneDomainPanel}).
057: *
058: * @author gjmurphy
059: */
060: public class SelectOneDomainEditor extends DomainPropertyEditor {
061:
062: // Default maximum time in milliseconds that the most recently fetched list
063: // of elements will be used before being refreshed
064: static final long FETCH_TIME_LIMIT = 2500;
065:
066: // Non-editable domains that have more than this many elements will not be
067: // displayed for editing int the in-line drop-down widget. Instead, they
068: // will be displayed in a pop-up custom editor that supports searching by
069: // label prefix and uses a large, scrollable list.
070: static final int MAX_DOMAIN_SIZE = 8;
071:
072: // The domain element that represent's the property's current value. A
073: // SelectOne domain can have only one value selected at a time.
074: Element element;
075:
076: /**
077: * Creates a new instance of DomainPropertyEditor, that will pick up its
078: * domain later, from the property descriptor.
079: */
080: public SelectOneDomainEditor() {
081: super ();
082: }
083:
084: /**
085: * Creates a new instance of DomainPropertyEditor, with the domain
086: * specified.
087: */
088: public SelectOneDomainEditor(Domain domain) {
089: super (domain);
090: }
091:
092: public Object getValue() {
093: return this .element == null ? null : this .element.getValue();
094: }
095:
096: public void setValue(Object value) {
097: Domain domain = this .getDomain();
098: if (domain == null)
099: return;
100: Element[] elements = getElements();
101: Element e = null;
102: for (int i = 0; i < elements.length && e == null; i++) {
103: Object v = elements[i].getValue();
104: if ((value == v) || (v != null && v.equals(value))) {
105: e = elements[i];
106: }
107: }
108: if (e == null)
109: this .element = super .defaultElement;
110: else
111: this .element = e;
112: }
113:
114: public String getAsText() {
115: if (this .element == null)
116: this .element = super .defaultElement;
117: return this .element.getLabel();
118: }
119:
120: public void setAsText(String text) throws IllegalArgumentException {
121: Domain domain = this .getDomain();
122: if (domain == null)
123: return;
124: if (text == null || text.trim().length() == 0) {
125: this .element = super .defaultElement;
126: } else {
127: Element[] elements = getElements();
128: Element e = null;
129: for (int i = 0; i < elements.length && e == null; i++) {
130: if (elements[i].getLabel().equals(text)) {
131: e = elements[i];
132: }
133: }
134: if (e != null) {
135: this .element = e;
136: }
137: }
138: }
139:
140: public String[] getTags() {
141: Domain domain = this .getDomain();
142: if (domain == null)
143: return new String[0];
144: if (domain instanceof EditableDomain) {
145: // Reset this editors's domain's design property, just in case there
146: // have been changes to the domain since this editor was first attached
147: // to its design context.
148: ((EditableDomain) domain).setDesignProperty(this
149: .getDesignProperty());
150: }
151: // If domain is too large, shouldn't be displayed as in-line drop-down, so
152: // return null
153: if (domain.getSize() > MAX_DOMAIN_SIZE)
154: return null;
155: return getElementLabels();
156: }
157:
158: public boolean isPaintable() {
159: return false;
160: }
161:
162: public boolean supportsCustomEditor() {
163: return true;
164: }
165:
166: /**
167: * If domain is editable, returns an instance of SelectOneEditableDomainPanel;
168: * otherwise, if the property is bindable, or if it is too large for
169: * convenient display in an in-line drop down, returns an instance of
170: * SelectOneDomainPanel.
171: */
172: public Component getCustomEditor() {
173: Domain domain = this .getDomain();
174: if (domain instanceof EditableDomain) {
175: // Reset this editors's domain's design property, just in case there
176: // have been changes to the domain since this editor was first attached
177: // to its design context.
178: EditableDomain editableDomain = (EditableDomain) domain;
179: editableDomain.setDesignProperty(this .getDesignProperty());
180: }
181: SelectOneDomainPanel panel = new SelectOneDomainPanel(this );
182: return panel;
183: }
184:
185: /**
186: * Set the currently selected element. This is the element that supplies
187: * the values returned by <code>getValue()</code> and
188: * <code>getAsText()</code>.
189: */
190: public void setElement(Element element) {
191: this .element = element;
192: }
193:
194: /**
195: * Get the currently selected element.
196: */
197: public Element getElement() {
198: return this .element;
199: }
200:
201: public void setDesignProperty(DesignProperty designProperty) {
202: super .setDesignProperty(designProperty);
203: // If a domain was just picked up from the design property, and no value
204: // has been set yet, set it explicitly to null now so that the current
205: // element is correctly initialized (some domains have special elements
206: // for representing null values).
207: if (getDomain() != null && getValue() == null)
208: setValue(null);
209: }
210:
211: public String getJavaInitializationString() {
212: return this .element.getJavaInitializationString();
213: }
214:
215: private long elementsFetchTime;
216: private Element[] elements;
217: private String[] elementLabels;
218:
219: /**
220: * A wrapper method for fetching the backing domain's elements, that uses a simple
221: * time delay to avoid to many calls to Domain.getElements() in a short span of
222: * time. This is necessary because during paint operations, the NetBeans property
223: * sheet will make many successive calls to PropertyEditor.getTags().
224: */
225: private Element[] getElements() {
226: if (elements == null
227: || System.currentTimeMillis() - elementsFetchTime > FETCH_TIME_LIMIT) {
228: elements = this .domain.getElements();
229: elementsFetchTime = System.currentTimeMillis();
230: }
231: return elements;
232: }
233:
234: private String[] getElementLabels() {
235: if (elementLabels == null
236: || System.currentTimeMillis() - elementsFetchTime > FETCH_TIME_LIMIT) {
237: elements = this .getElements();
238: int i = 0;
239: int j = 0;
240: if (domain.isRequired()) {
241: elementLabels = new String[elements.length];
242: } else {
243: elementLabels = new String[elements.length + 1];
244: elementLabels[i++] = this.EMPTY_ELEMENT.getLabel();
245: }
246: while (j < elements.length) {
247: elementLabels[i++] = elements[j++].getLabel();
248: }
249: }
250: return elementLabels;
251: }
252:
253: }
|