~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to core/src/org/netbeans/beaninfo/editors/ObjectEditor.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
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]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
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.
 
29
 *
 
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.
 
40
 */
 
41
 
 
42
package org.netbeans.beaninfo.editors;
 
43
 
 
44
import java.awt.Component;
 
45
import java.awt.Font;
 
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;
 
69
 
 
70
/**
 
71
 * Defines editor for choosing of any object using lookup.
 
72
 *
 
73
 * @author Jaroslav Tulach
 
74
 */
 
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 
 
79
     */
 
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.
 
84
     */
 
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.
 
88
     */
 
89
    private static final String PROP_LOOKUP = "lookup"; // NOI18N
 
90
    
 
91
    /** custom editor */
 
92
    private ObjectPanel customEditor;
 
93
    
 
94
    /** super class to search for */
 
95
    private Lookup.Template<Object> template;
 
96
    
 
97
    /** null or name to use for null value */
 
98
    private String nullValue;
 
99
    
 
100
    /** a special lookup to use or null */
 
101
    private Lookup lookup;
 
102
    
 
103
    /** Creates new ObjectEditor  */
 
104
    public ObjectEditor() {
 
105
    }
 
106
 
 
107
    /**
 
108
     * This method is called by the IDE to pass
 
109
     * the environment to the property editor.
 
110
     */
 
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);
 
116
        } else {
 
117
            template = null;
 
118
        }
 
119
        
 
120
        obj = env.getFeatureDescriptor ().getValue (PROP_NULL);
 
121
        if (Boolean.TRUE.equals (obj)) {
 
122
            nullValue = NbBundle.getMessage (ObjectEditor.class, "CTL_NullValue");
 
123
        } else {
 
124
            if (obj instanceof String) {
 
125
                nullValue = (String)obj;
 
126
            } else {
 
127
                nullValue = null;
 
128
            }
 
129
        }
 
130
        
 
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
 
136
        }
 
137
    }
 
138
    
 
139
    /** A lookup to work on.
 
140
     * @return a lookup.
 
141
     */
 
142
    protected Lookup lookup () {
 
143
        Lookup l = lookup;
 
144
        return l == null ? Lookup.getDefault () : l;
 
145
    }
 
146
    
 
147
    /** A template to use.
 
148
     */
 
149
    protected Lookup.Template<Object> template () {
 
150
        if (template == null) {
 
151
            template = new Lookup.Template<Object> (Object.class);
 
152
        }
 
153
         
 
154
        return template;
 
155
    }
 
156
    
 
157
    @Override
 
158
    public String getAsText() {
 
159
        Object value = getValue ();
 
160
        if (value == null) {
 
161
            return nullValue == null ? 
 
162
                NbBundle.getMessage (ObjectEditor.class, "CTL_NullValue")
 
163
            :
 
164
                nullValue;
 
165
        }
 
166
        
 
167
        Lookup.Template<Object> t = new Lookup.Template<Object> (
 
168
            template ().getType (),
 
169
            template ().getId (),
 
170
            value // instance to search for
 
171
        );
 
172
        Lookup.Item item = lookup ().lookupItem (t);
 
173
        
 
174
        if (item == null) {
 
175
            return NbBundle.getMessage (ObjectEditor.class, "CTL_NullItem");
 
176
        }
 
177
        
 
178
        return item.getDisplayName();
 
179
    }
 
180
    
 
181
    /** Searches between items whether there is one with the same display name.
 
182
     * @param str item name
 
183
     */
 
184
    @Override
 
185
    public void setAsText(java.lang.String str) throws java.lang.IllegalArgumentException {
 
186
        if (nullValue != null && nullValue.equals (str)) {
 
187
            setValue (null);
 
188
            return;
 
189
        }
 
190
        
 
191
        
 
192
        Collection allItems = lookup ().lookup (template ()).allItems ();
 
193
        
 
194
        Iterator it = allItems.iterator ();
 
195
        while (it.hasNext ()) {
 
196
            Lookup.Item item = (Lookup.Item)it.next ();
 
197
            
 
198
            if (item.getDisplayName().equals (str)) {
 
199
                setValue (item.getInstance ());
 
200
                firePropertyChange();
 
201
                return;
 
202
            }
 
203
        }
 
204
        IllegalArgumentException iae = new IllegalArgumentException (str);
 
205
        String msg = MessageFormat.format(
 
206
            NbBundle.getMessage(
 
207
                ObjectEditor.class, "FMT_EXC_GENERIC_BAD_VALUE"),  //NOI18N
 
208
                new Object[] {str});
 
209
        UIExceptions.annotateUser(iae, str, msg, null, new Date());
 
210
        throw iae;        
 
211
    }
 
212
    
 
213
    /** List of all display names for items.
 
214
     * @return array of strings
 
215
     */
 
216
    @Override
 
217
    public java.lang.String[] getTags() {
 
218
        Collection<? extends Lookup.Item<Object>> allItems = lookup ().lookup (template ()).allItems ();
 
219
        if (allItems.size() <= 1) {
 
220
            return null;
 
221
        }
 
222
   
 
223
        ArrayList<String> list = new ArrayList<String> (allItems.size () + 1);
 
224
        if (nullValue != null) {
 
225
            list.add (nullValue);
 
226
        }
 
227
        
 
228
        for (Lookup.Item<Object> item: allItems) {
 
229
            list.add (item.getDisplayName());
 
230
        }
 
231
        
 
232
        String[] retValue = new String[list.size()];
 
233
        list.toArray(retValue);
 
234
        return retValue;
 
235
    }
 
236
 
 
237
    /** Yes we have custom editor.
 
238
     */
 
239
    @Override
 
240
    public boolean supportsCustomEditor() {
 
241
        //Don't allow custom editor if there will be nothing to show
 
242
        return getTags()!= null && getTags().length > 1;
 
243
    }
 
244
    
 
245
    @Override
 
246
    public synchronized Component getCustomEditor () {
 
247
        if (!supportsCustomEditor()) {
 
248
            return null;
 
249
        }
 
250
        if (customEditor != null) {
 
251
            return customEditor;
 
252
        }
 
253
        Lookup.Result<Object> contents = lookup().lookup(template());
 
254
        ObjectPanel panel = new ObjectPanel(contents);
 
255
        return customEditor = panel;
 
256
    }
 
257
 
 
258
    private class ObjectPanel extends JPanel implements ActionListener {
 
259
        static final long serialVersionUID = 1L;
 
260
        
 
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
 
267
            
 
268
            setLayout (new GridBagLayout());
 
269
            GridBagConstraints gbc = new GridBagConstraints();
 
270
            int row = 0;
 
271
            ButtonGroup bg = new ButtonGroup();
 
272
            Font bold;
 
273
            Font plain;
 
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());
 
280
            } else {
 
281
                bold = getFont().deriveFont(Font.BOLD);
 
282
                plain = getFont().deriveFont(Font.PLAIN);
 
283
            }
 
284
            
 
285
            Collection<? extends Lookup.Item<Object>> c = res.allItems();
 
286
            Lookup.Item[] items = new Lookup.Item[c.size()];
 
287
            items = c.toArray(items);
 
288
 
 
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);
 
295
                }
 
296
                rb.addActionListener(this);
 
297
                bg.add(rb);
 
298
                String description = getDescription(items[i]);
 
299
                
 
300
                gbc.gridx=0;
 
301
                gbc.gridy=row;
 
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;
 
305
                add(rb, gbc);
 
306
                row++;
 
307
                if (description != null) {
 
308
                    JLabel lbl = new JLabel(description);
 
309
                    lbl.setLabelFor(rb);
 
310
                    lbl.setFont(plain);
 
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);
 
314
                    gbc.gridx=0;
 
315
                    gbc.gridy=row;
 
316
                    add(lbl, gbc);
 
317
                    row++;
 
318
               }
 
319
            }
 
320
        }
 
321
        
 
322
        private String getDescription (Lookup.Item item) {
 
323
            String id = item.getId ();
 
324
            String result = null;
 
325
            try {
 
326
                result = Introspector.getBeanInfo(item.getInstance().getClass()).getBeanDescriptor().getShortDescription();
 
327
            } catch (IntrospectionException ie) {
 
328
                //do nothing
 
329
            }
 
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)) {
 
334
                result = null;
 
335
            } 
 
336
            return result;
 
337
        }
 
338
        
 
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();
 
344
        }
 
345
    }
 
346
    
 
347
    private static class ItemRadioButton extends JRadioButton {
 
348
        static final long serialVersionUID = 3L;
 
349
        
 
350
        Lookup.Item item;
 
351
        public ItemRadioButton(Lookup.Item item, Font font) {
 
352
            this.item = item;
 
353
            setName(item.getId());
 
354
            setText(item.getDisplayName());
 
355
            setFont(font);
 
356
            getAccessibleContext().setAccessibleName(getName());
 
357
            getAccessibleContext().setAccessibleDescription(
 
358
            getText());
 
359
        }
 
360
    }
 
361
}
 
362