2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.beaninfo.editors;
44
import java.awt.Component;
46
import java.awt.GridBagConstraints;
47
import java.awt.GridBagLayout;
48
import java.awt.Insets;
49
import java.awt.event.ActionEvent;
50
import java.awt.event.ActionListener;
51
import java.beans.IntrospectionException;
52
import java.beans.Introspector;
53
import java.beans.PropertyEditorSupport;
54
import java.text.MessageFormat;
55
import java.util.ArrayList;
56
import java.util.Collection;
57
import java.util.Date;
58
import java.util.Iterator;
59
import javax.swing.ButtonGroup;
60
import javax.swing.JLabel;
61
import javax.swing.JPanel;
62
import javax.swing.JRadioButton;
63
import org.netbeans.core.UIExceptions;
64
import org.openide.explorer.propertysheet.ExPropertyEditor;
65
import org.openide.explorer.propertysheet.PropertyEnv;
66
import org.openide.util.NbBundle;
67
import org.openide.util.Lookup;
68
import org.openide.util.Utilities;
71
* Defines editor for choosing of any object using lookup.
73
* @author Jaroslav Tulach
75
public final class ObjectEditor extends PropertyEditorSupport
76
implements ExPropertyEditor {
77
/** Name of the custom property that can be passed in PropertyEnv.
78
* Should contain superclass that is allowed to be
80
private static final String PROP_SUPERCLASS = "superClass"; // NOI18N
81
/** Name of the custom property that can be passed in PropertyEnv.
82
* Either Boolean.TRUE or a String, in such case the string represents
83
* human readable name of the value.
85
private static final String PROP_NULL = "nullValue"; // NOI18N
86
/** Name of the custom property that can be passed in PropertyEnv.
87
* A lookup to use to query for results.
89
private static final String PROP_LOOKUP = "lookup"; // NOI18N
92
private ObjectPanel customEditor;
94
/** super class to search for */
95
private Lookup.Template<Object> template;
97
/** null or name to use for null value */
98
private String nullValue;
100
/** a special lookup to use or null */
101
private Lookup lookup;
103
/** Creates new ObjectEditor */
104
public ObjectEditor() {
108
* This method is called by the IDE to pass
109
* the environment to the property editor.
111
public synchronized void attachEnv(PropertyEnv env) {
112
Object obj = env.getFeatureDescriptor ().getValue (PROP_SUPERCLASS);
113
if (obj instanceof Class) {
114
@SuppressWarnings("unchecked") Class<Object> clz = (Class<Object>)obj;
115
template = new Lookup.Template<Object> (clz);
120
obj = env.getFeatureDescriptor ().getValue (PROP_NULL);
121
if (Boolean.TRUE.equals (obj)) {
122
nullValue = NbBundle.getMessage (ObjectEditor.class, "CTL_NullValue");
124
if (obj instanceof String) {
125
nullValue = (String)obj;
131
obj = env.getFeatureDescriptor ().getValue (PROP_LOOKUP);
132
lookup = obj instanceof Lookup ? (Lookup)obj : null;
133
//Don't allow editing in the case only one item and tags are null
134
if (getTags()==null || getTags().length <= 1) {
135
env.getFeatureDescriptor().setValue("canEditAsText",Boolean.FALSE); //NOI18N
139
/** A lookup to work on.
142
protected Lookup lookup () {
144
return l == null ? Lookup.getDefault () : l;
147
/** A template to use.
149
protected Lookup.Template<Object> template () {
150
if (template == null) {
151
template = new Lookup.Template<Object> (Object.class);
158
public String getAsText() {
159
Object value = getValue ();
161
return nullValue == null ?
162
NbBundle.getMessage (ObjectEditor.class, "CTL_NullValue")
167
Lookup.Template<Object> t = new Lookup.Template<Object> (
168
template ().getType (),
169
template ().getId (),
170
value // instance to search for
172
Lookup.Item item = lookup ().lookupItem (t);
175
return NbBundle.getMessage (ObjectEditor.class, "CTL_NullItem");
178
return item.getDisplayName();
181
/** Searches between items whether there is one with the same display name.
182
* @param str item name
185
public void setAsText(java.lang.String str) throws java.lang.IllegalArgumentException {
186
if (nullValue != null && nullValue.equals (str)) {
192
Collection allItems = lookup ().lookup (template ()).allItems ();
194
Iterator it = allItems.iterator ();
195
while (it.hasNext ()) {
196
Lookup.Item item = (Lookup.Item)it.next ();
198
if (item.getDisplayName().equals (str)) {
199
setValue (item.getInstance ());
200
firePropertyChange();
204
IllegalArgumentException iae = new IllegalArgumentException (str);
205
String msg = MessageFormat.format(
207
ObjectEditor.class, "FMT_EXC_GENERIC_BAD_VALUE"), //NOI18N
209
UIExceptions.annotateUser(iae, str, msg, null, new Date());
213
/** List of all display names for items.
214
* @return array of strings
217
public java.lang.String[] getTags() {
218
Collection<? extends Lookup.Item<Object>> allItems = lookup ().lookup (template ()).allItems ();
219
if (allItems.size() <= 1) {
223
ArrayList<String> list = new ArrayList<String> (allItems.size () + 1);
224
if (nullValue != null) {
225
list.add (nullValue);
228
for (Lookup.Item<Object> item: allItems) {
229
list.add (item.getDisplayName());
232
String[] retValue = new String[list.size()];
233
list.toArray(retValue);
237
/** Yes we have custom editor.
240
public boolean supportsCustomEditor() {
241
//Don't allow custom editor if there will be nothing to show
242
return getTags()!= null && getTags().length > 1;
246
public synchronized Component getCustomEditor () {
247
if (!supportsCustomEditor()) {
250
if (customEditor != null) {
253
Lookup.Result<Object> contents = lookup().lookup(template());
254
ObjectPanel panel = new ObjectPanel(contents);
255
return customEditor = panel;
258
private class ObjectPanel extends JPanel implements ActionListener {
259
static final long serialVersionUID = 1L;
261
public ObjectPanel(Lookup.Result<Object> res) {
262
getAccessibleContext().setAccessibleName(
263
NbBundle.getMessage(ObjectEditor.class,
264
"ACSN_ObjectTree")); //NOI18N
265
getAccessibleContext().setAccessibleDescription(
266
NbBundle.getMessage(ObjectEditor.class, "ACSD_ObjectTree")); //NOI18N
268
setLayout (new GridBagLayout());
269
GridBagConstraints gbc = new GridBagConstraints();
271
ButtonGroup bg = new ButtonGroup();
274
if (Utilities.isMac()) {
275
// don't use deriveFont() - see #49973 for details
276
bold = new Font(getFont().getName(), Font.BOLD, getFont().getSize());
277
//For default metal L&F where labels are by default bold
278
// don't use deriveFont() - see #49973 for details
279
plain = new Font(getFont().getName(), Font.PLAIN, getFont().getSize());
281
bold = getFont().deriveFont(Font.BOLD);
282
plain = getFont().deriveFont(Font.PLAIN);
285
Collection<? extends Lookup.Item<Object>> c = res.allItems();
286
Lookup.Item[] items = new Lookup.Item[c.size()];
287
items = c.toArray(items);
289
int BASE_LEFT_INSET=7;
290
for (int i=0; i < items.length; i++) {
291
JRadioButton rb = new ItemRadioButton(items[i], bold);
292
Object inst = items[i].getInstance();
293
if (inst != null && inst.equals(getValue())) {
294
rb.setSelected(true);
296
rb.addActionListener(this);
298
String description = getDescription(items[i]);
302
gbc.insets = new Insets(i==0 ? 7 : 0, BASE_LEFT_INSET,
303
description != null ? 1 : i==items.length-1 ? 7: 4, BASE_LEFT_INSET);
304
gbc.fill=GridBagConstraints.HORIZONTAL;
307
if (description != null) {
308
JLabel lbl = new JLabel(description);
311
int left = rb.getIcon() != null ? rb.getIcon().getIconWidth() : 20;
312
gbc.insets = new Insets(0, BASE_LEFT_INSET +
313
left, 4, BASE_LEFT_INSET + left);
322
private String getDescription (Lookup.Item item) {
323
String id = item.getId ();
324
String result = null;
326
result = Introspector.getBeanInfo(item.getInstance().getClass()).getBeanDescriptor().getShortDescription();
327
} catch (IntrospectionException ie) {
330
String toCheck = item.getInstance().getClass().getName();
331
toCheck = toCheck.lastIndexOf('.')!=-1 ?
332
toCheck.substring(toCheck.lastIndexOf('.')+1) : toCheck; //NOI18N
333
if (toCheck.equals(result)) {
339
public void actionPerformed(ActionEvent ae) {
340
Lookup.Item item = ((ItemRadioButton) ae.getSource()).item;
341
Object o = item.getInstance();
342
setValue (item.getInstance());
343
ObjectEditor.this.firePropertyChange();
347
private static class ItemRadioButton extends JRadioButton {
348
static final long serialVersionUID = 3L;
351
public ItemRadioButton(Lookup.Item item, Font font) {
353
setName(item.getId());
354
setText(item.getDisplayName());
356
getAccessibleContext().setAccessibleName(getName());
357
getAccessibleContext().setAccessibleDescription(