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-2006 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:
042: package org.netbeans.beaninfo.editors;
043:
044: import java.beans.*;
045: import java.text.MessageFormat;
046: import org.netbeans.core.UIExceptions;
047:
048: import org.openide.loaders.DataObject;
049: import org.openide.nodes.Node;
050: import org.openide.nodes.NodeAcceptor;
051: import org.openide.loaders.DataFolder;
052: import org.openide.loaders.DataFilter;
053: import org.openide.explorer.propertysheet.*;
054: import org.openide.util.NbBundle;
055:
056: /**
057: * Property editor for [org.openide.loaders.DataObject].
058: * Uses class DataObjectPanel as custom property editor.
059: * @author David Strupl
060: */
061: public class DataObjectArrayEditor extends PropertyEditorSupport
062: implements ExPropertyEditor {
063:
064: /** Name of the custom property that can be passed in PropertyEnv. */
065: private static final String PROPERTY_CURRENT_FOLDER = "currentFolder"; // NOI18N
066: /** Name of the custom property that can be passed in PropertyEnv. */
067: private static final String PROPERTY_ROOT_FOLDER = "rootFolder"; // NOI18N
068: /** Name of the custom property that can be passed in PropertyEnv. */
069: private static final String PROPERTY_ROOT_NODE = "rootNode"; // NOI18N
070: /** Name of the custom property that can be passed in PropertyEnv. */
071: private static final String PROPERTY_COOKIES = "cookies"; // NOI18N
072: /** Name of the custom property that can be passed in PropertyEnv. */
073: private static final String PROPERTY_DATA_FILTER = "dataFilter"; // NOI18N
074: /** Name of the custom property that can be passed in PropertyEnv. */
075: private static final String PROPERTY_FOLDER_FILTER = "folderFilter"; // NOI18N
076: /** Name of the custom property that can be passed in PropertyEnv. */
077: private static final String PROPERTY_NODE_ACCEPTOR = "nodeAcceptor"; // NOI18N
078: /** Name of the custom property that can be passed in PropertyEnv. */
079: private static final String PROPERTY_LABEL = "label"; // NOI18N
080: /** Name of the custom property that can be passed in PropertyEnv. */
081: private static final String PROPERTY_TITLE = "title"; // NOI18N
082: /** Name of the custom property that can be passed in PropertyEnv. */
083: private static final String PROPERTY_INSET = "inset"; // NOI18N
084: /** Name of the custom property that can be passed in PropertyEnv. */
085: private static final String PROPERTY_DESCRIPTION = "description"; // NOI18N
086: /** Name of the custom property that can be passed in PropertyEnv. */
087: private static final String PROPERTY_GUI_TYPE = "guitype"; // NOI18N
088: /** Name of the custom property that can be passed in PropertyEnv. */
089: private static final String PROPERTY_SELECTION_MODE = "selectionMode"; // NOI18N
090:
091: /** This gets lazy initialized in getDataObjectPanel*/
092: private DataObjectPanel customEditor;
093:
094: /** A property stored between calls to atachEnv and getCustomEditor() */
095: private DataFolder rootFolder;
096: /** A property stored between calls to atachEnv and getCustomEditor() */
097: private Node rootNode;
098: /** A property stored between calls to atachEnv and getCustomEditor() */
099: private DataObject currentFolder;
100: /** A property stored between calls to atachEnv and getCustomEditor() */
101: private Class[] cookies;
102: /** A property stored between calls to atachEnv and getCustomEditor() */
103: private DataFilter dataFilter;
104: /** A property stored between calls to atachEnv and getCustomEditor() */
105: private DataFilter folderFilter;
106: /** A property stored between calls to atachEnv and getCustomEditor() */
107: private NodeAcceptor nodeAcceptor;
108: /** A property stored between calls to atachEnv and getCustomEditor() */
109: private String label;
110: /** A property stored between calls to atachEnv and getCustomEditor() */
111: private String title;
112: /** A property stored between calls to atachEnv and getCustomEditor() */
113: private Integer insets;
114: /** A property stored between calls to atachEnv and getCustomEditor() */
115: private String description;
116: /** A property stored between calls to atachEnv and getCustomEditor()
117: * It can be 'TreeView' or 'ListView'. Default is 'TreeView'.
118: */
119: private String guiType;
120: /** A property stored between calls to atachEnv and getCustomEditor()
121: * Valid only for 'ListView' GUI type. It controls selection mode of
122: * JFileChooser.
123: *
124: * Valid values are:
125: * JFileChooser.FILES_ONLY
126: * JFileChooser.DIRECTORIES_ONLY
127: * JFileChooser.FILES_AND_DIRECTORIES
128: */
129: private Integer selectionMode;
130:
131: private PropertyChangeSupport supp = new PropertyChangeSupport(this );
132:
133: private PropertyEnv env;
134:
135: /**
136: * This method is called by the IDE to pass
137: * the environment to the property editor.
138: */
139: public void attachEnv(PropertyEnv env) {
140: Object newObj = env.getFeatureDescriptor().getValue(
141: PROPERTY_CURRENT_FOLDER);
142: if (newObj instanceof DataObject) {
143: currentFolder = (DataObject) newObj;
144: }
145: newObj = env.getFeatureDescriptor().getValue(
146: PROPERTY_ROOT_FOLDER);
147: if (newObj instanceof DataFolder) {
148: rootFolder = (DataFolder) newObj;
149: }
150: newObj = env.getFeatureDescriptor()
151: .getValue(PROPERTY_ROOT_NODE);
152: if (newObj instanceof Node) {
153: rootNode = (Node) newObj;
154: }
155: newObj = env.getFeatureDescriptor().getValue(PROPERTY_COOKIES);
156: if (newObj instanceof Class[]) {
157: cookies = (Class[]) newObj;
158: }
159: newObj = env.getFeatureDescriptor().getValue(
160: PROPERTY_DATA_FILTER);
161: if (newObj instanceof DataFilter) {
162: dataFilter = (DataFilter) newObj;
163: }
164: newObj = env.getFeatureDescriptor().getValue(
165: PROPERTY_FOLDER_FILTER);
166: if (newObj instanceof DataFilter) {
167: folderFilter = (DataFilter) newObj;
168: }
169: newObj = env.getFeatureDescriptor().getValue(
170: PROPERTY_NODE_ACCEPTOR);
171: if (newObj instanceof NodeAcceptor) {
172: nodeAcceptor = (NodeAcceptor) newObj;
173: }
174: newObj = env.getFeatureDescriptor().getValue(PROPERTY_LABEL);
175: if (newObj instanceof String) {
176: label = (String) newObj;
177: }
178: newObj = env.getFeatureDescriptor().getValue(PROPERTY_TITLE);
179: if (newObj instanceof String) {
180: title = (String) newObj;
181: }
182: newObj = env.getFeatureDescriptor().getValue(PROPERTY_INSET);
183: if (newObj instanceof Integer) {
184: insets = (Integer) newObj;
185: }
186: newObj = env.getFeatureDescriptor().getValue(
187: PROPERTY_DESCRIPTION);
188: if (newObj instanceof String) {
189: description = (String) newObj;
190: }
191: newObj = env.getFeatureDescriptor().getValue(PROPERTY_GUI_TYPE);
192: if (newObj instanceof String) {
193: guiType = (String) newObj;
194: }
195: newObj = env.getFeatureDescriptor().getValue(
196: PROPERTY_SELECTION_MODE);
197: if (newObj instanceof Integer) {
198: selectionMode = (Integer) newObj;
199: }
200: // fix of 19318
201: env.getFeatureDescriptor().setValue("canEditAsText",
202: Boolean.FALSE);
203:
204: if (env.getClass().equals(PropertyEnv.class)) {
205: //allow reuse of the custom editor - it is probably being
206: //redisplayed, so we need to change the PropertyEnv that
207: //may be controlling the dialog.
208: if ((customEditor != null && customEditor.isVisible())
209: || customEditor == null) {
210: this .env = env;
211: }
212: }
213: }
214:
215: /**
216: * Calls lazy initialization in getDataObjectpanel().
217: * @return an instanceof DataObjectPanel
218: */
219: public java.awt.Component getCustomEditor() {
220: return getDataObjectPanel();
221: }
222:
223: void setOkButtonEnabled(boolean state) {
224: if (env != null) {
225: env.setState(state ? PropertyEnv.STATE_VALID
226: : PropertyEnv.STATE_INVALID);
227: }
228: }
229:
230: /**
231: * Lazy initializes customEditor (DataObjectPanel).
232: * Passes all parameters gathered in method attachEnv.
233: */
234: private DataObjectPanel getDataObjectPanel() {
235: //XXX we must cache the custom editor because the PropertyPanel usage
236: //will actually re-fetch it if something calls setState() on the env.
237: //The alternative is an endless loop during PropertyPanel initialization,
238: //as the initial OK button state is set, causing the PropertyPanel to
239: //rebuild itself, causing the OK button to be set again...
240: if (customEditor == null) {
241: if (guiType != null) {
242: if ("TreeView".equals(guiType)) {
243: customEditor = new DataObjectTreeView(this , env);
244: } else if ("ListView".equals(guiType)) {
245: customEditor = new DataObjectListView(this , env);
246: } else {
247: customEditor = new DataObjectListView(this , env);
248: }
249: } else {
250: customEditor = new DataObjectListView(this , env);
251: }
252: } else {
253: //Check explicitly for the env class - issue 36100
254: if (env.getClass().equals(PropertyEnv.class)) {
255: customEditor.setEnv(env);
256: }
257: }
258: if (cookies != null) {
259: customEditor.setDataFilter(new CookieFilter(cookies,
260: dataFilter));
261: } else {
262: customEditor.setDataFilter(dataFilter);
263: }
264: Object value = getValue();
265: if (value != null && value instanceof DataObject) {
266: customEditor.setDataObject((DataObject) value);
267: } else if (currentFolder != null) {
268: customEditor.setDataObject(currentFolder);
269: }
270: if (label != null) {
271: customEditor.setText(label);
272: }
273: if (title != null) {
274: customEditor.putClientProperty("title", title); // NOI18N
275: }
276: if (nodeAcceptor != null) {
277: customEditor.setNodeFilter(nodeAcceptor);
278: }
279: if (folderFilter != null) {
280: customEditor.setFolderFilter(folderFilter);
281: }
282: if (rootFolder != null) {
283: customEditor.setRootObject(rootFolder);
284: }
285: if (rootNode != null) {
286: customEditor.setRootNode(rootNode);
287: }
288: if (insets != null) {
289: customEditor.setInsetValue(insets.intValue());
290: }
291: if (description != null) {
292: customEditor.setDescription(description);
293: }
294: if (selectionMode != null) {
295: customEditor.setSelectionMode(selectionMode.intValue());
296: }
297: customEditor.setMultiSelection(true);
298: return customEditor;
299: }
300:
301: /**
302: * Determines whether the propertyEditor can provide a custom editor.
303: * @return true.
304: */
305: public boolean supportsCustomEditor() {
306: return true;
307: }
308:
309: /** Adds the listener also to private support supp.*/
310: public void addPropertyChangeListener(PropertyChangeListener l) {
311: super .addPropertyChangeListener(l);
312: supp.addPropertyChangeListener(l);
313: }
314:
315: /** Removes the listener also from private support supp.*/
316: public void removePropertyChangeListener(PropertyChangeListener l) {
317: super .removePropertyChangeListener(l);
318: supp.removePropertyChangeListener(l);
319: }
320:
321: public String getAsText() {
322: Object value = getValue();
323: if (value instanceof DataObject) {
324: return ((DataObject) value).getNodeDelegate()
325: .getDisplayName();
326: }
327: return "";
328: }
329:
330: public void setAsText(String text)
331: throws java.lang.IllegalArgumentException {
332: try {
333: if ((text == null) || ("".equals(text)))
334: setValue(null);
335: } catch (Exception e) {
336: IllegalArgumentException iae = new IllegalArgumentException(
337: e.getMessage());
338: String msg = e.getLocalizedMessage();
339: if (msg == null) {
340: msg = MessageFormat.format(NbBundle.getMessage(
341: DataObjectArrayEditor.class,
342: "FMT_EXC_GENERIC_BAD_VALUE"),
343: new Object[] { text }); //NOI18N
344: }
345: UIExceptions.annotateUser(iae, iae.getMessage(), msg, e,
346: new java.util.Date());
347: throw iae;
348: }
349: }
350:
351: /** CookieFilter allows you to filter DataObjects
352: * based on presence of specified cookies.
353: */
354: private static class CookieFilter implements DataFilter {
355: private Class[] cookieArray;
356: private DataFilter originalFilter;
357:
358: /** Just remember the cookie array and original filter.*/
359: public CookieFilter(Class[] cookieArray,
360: DataFilter originalFilter) {
361: this .cookieArray = cookieArray;
362: this .originalFilter = originalFilter;
363: }
364:
365: /** Should the data object be displayed or not? This implementation
366: * combines the originalFilter with set of cookies supplied
367: * in cookieArray.
368: * @param obj the data object
369: * @return <CODE>true</CODE> if the object should be displayed,
370: * <CODE>false</CODE> otherwise
371: */
372: public boolean acceptDataObject(DataObject obj) {
373: if (cookieArray == null) {
374: if (originalFilter != null) {
375: return originalFilter.acceptDataObject(obj);
376: } else {
377: return true;
378: }
379: }
380: for (int i = 0; i < cookieArray.length; i++) {
381: if (obj.getCookie(cookieArray[i]) == null) {
382: return false;
383: }
384: }
385: if (originalFilter != null) {
386: return originalFilter.acceptDataObject(obj);
387: } else {
388: return true;
389: }
390: }
391: }
392: }
|