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.core.ui;
043:
044: import javax.swing.Action;
045: import org.openide.actions.FileSystemAction;
046: import org.openide.actions.MoveDownAction;
047: import org.openide.actions.MoveUpAction;
048: import org.openide.actions.NewTemplateAction;
049: import org.openide.actions.PasteAction;
050: import org.openide.actions.PropertiesAction;
051: import org.openide.actions.ReorderAction;
052: import org.openide.actions.ToolsAction;
053: import org.openide.filesystems.FileObject;
054: import org.openide.filesystems.FileSystem;
055: import org.openide.filesystems.FileUtil;
056: import org.openide.filesystems.Repository;
057: import org.openide.loaders.DataFolder;
058: import org.openide.loaders.DataObject;
059: import org.openide.loaders.DataShadow;
060: import org.openide.loaders.TemplateWizard;
061: import org.openide.loaders.XMLDataObject;
062: import org.openide.nodes.FilterNode;
063: import org.openide.nodes.Node;
064: import org.openide.nodes.Sheet;
065: import org.openide.util.HelpCtx;
066: import org.openide.util.actions.SystemAction;
067:
068: /** Node that displays the content of Services directory and let's user
069: * customize it.
070: *
071: * @author Jaroslav Tulach
072: */
073: public class LookupNode extends DataFolder.FolderNode implements
074: NewTemplateAction.Cookie {
075: /** extended attribute that signals that this object should not be visible to the user */
076: private static final String EA_HIDDEN = "hidden"; // NOI18N
077: private static final String EA_HELPCTX = "helpID"; // NOI18N
078: /** This is quite unsafe, but it's the only way how to test that we got uncustomized
079: * InstanceDataNode's help (which is really of no use to the user).
080: */
081: private static final HelpCtx INSTANCE_DEFAULT_HELP = new HelpCtx(
082: "org.openide.loaders.InstanceDataObject"); // NOI18N
083: /** This is quite unsafe, but it's the only way how to test that we got uncustomized
084: * DataFolder's help (which is really of no use to the user).
085: */
086: private static final HelpCtx FOLDER_DEFAULT_HELP = new HelpCtx(
087: "org.openide.loaders.DataFolder"); // NOI18N
088: private static final String PREFIX_SETTING_CATEGORIES = "UI"; // NOI18N
089:
090: /** Constructs this node with given node to filter.
091: */
092: public LookupNode(DataFolder folder) {
093: folder.super (new Ch(folder));
094: // setShortDescription(bundle.getString("CTL_Lookup_hint"));
095: // super.setIconBase ("/org/netbeans/modules/url/Lookup"); // NOI18N
096: getCookieSet().add(this );
097: }
098:
099: /** is this node representing a setting ui category? */
100: private boolean isUISettingCategoryNode() {
101: DataFolder df = (DataFolder) super .getCookie(DataFolder.class);
102: if (df != null) {
103: String name = df.getPrimaryFile().getPath();
104: return name.startsWith(PREFIX_SETTING_CATEGORIES);
105: } else
106: return false;
107: }
108:
109: public HelpCtx getHelpCtx() {
110: Object o = getDataObject().getPrimaryFile().getAttribute(
111: EA_HELPCTX);
112: if (o != null) {
113: return new HelpCtx(o.toString());
114: }
115: // now try the original DataObject (assume it is a folder-thing)
116: HelpCtx ctx = getDataObject().getHelpCtx();
117: if (ctx != null && ctx != HelpCtx.DEFAULT_HELP
118: && !FOLDER_DEFAULT_HELP.equals(ctx)) {
119: return ctx;
120: }
121: // try the parent node:
122: Node n = getParentNode();
123: if (n != null)
124: ctx = n.getHelpCtx();
125: return ctx;
126: }
127:
128: public final Action[] getActions(boolean context) {
129: if (isUISettingCategoryNode()) {
130: return new Action[0];
131: } else {
132: return new Action[] {
133: SystemAction.get(FileSystemAction.class), null,
134: SystemAction.get(PasteAction.class), null,
135: SystemAction.get(MoveUpAction.class),
136: SystemAction.get(MoveDownAction.class),
137: SystemAction.get(ReorderAction.class), null,
138: SystemAction.get(NewTemplateAction.class), null,
139: SystemAction.get(ToolsAction.class),
140: SystemAction.get(PropertiesAction.class), };
141: }
142: }
143:
144: /** @return empty property sets. *
145: public PropertySet[] getPropertySets () {
146: return NO_PROPERTIES;
147: }
148: */
149:
150: public final Node.Cookie getCookie(Class type) {
151: if (isUISettingCategoryNode())
152: return null;
153: return super .getCookie(type);
154: }
155:
156: /** NewTemplateAction.Cookie method implementation to create the desired
157: * template wizard for this node.
158: */
159: public final TemplateWizard getTemplateWizard() {
160: TemplateWizard templateWizard = createWizard();
161:
162: templateWizard.setTemplatesFolder(findFolder(root(),
163: findName(), true));
164: templateWizard.setTargetFolder(findFolder(root(), findName(),
165: false));
166: return templateWizard;
167: }
168:
169: /** Allows subclasses to create special wizard.
170: */
171: protected TemplateWizard createWizard() {
172: return new TemplateWizard();
173: }
174:
175: /** A method to allow subclasses to create different child for folder.
176: * @param folder the folder to create child for
177: */
178: protected LookupNode createChild(DataFolder folder) {
179: return new LookupNode(folder);
180: }
181:
182: /** A method to allow subclasses to create different child for any other node then folder.
183: * @param node to create child for
184: */
185: protected Node createChild(Node node) {
186: return node.cloneNode();
187: }
188:
189: /** Gets the root from children on system filesystem and in
190: * templates folder.
191: */
192: protected String root() {
193: return "Services"; // NOI18N
194: }
195:
196: /** Finds a prefix for templates.
197: * @return prefix
198: */
199: private static String prefTemplates(String root) {
200: return "Templates/" + root; // NOI18N
201: }
202:
203: /** Finds a prefix for objects.
204: */
205: private static String prefObjects(String root) {
206: return root;
207: }
208:
209: /** Finds name of the node by extracting the begin of nodes.
210: * @return the string name
211: */
212: private String findName() {
213: DataFolder df = (DataFolder) getCookie(DataFolder.class);
214: if (df == null) {
215: return "";
216: }
217: String name = df.getPrimaryFile().getPath();
218: if (name.startsWith(prefObjects(root()))) {
219: name = name.substring(prefObjects(root()).length());
220: }
221: return name;
222: }
223:
224: /** Locates the right folder for given service name.
225: * @param name of the resource
226: * @param template folder for templates or for instances?
227: * @return the folder
228: */
229: static DataFolder findFolder(String root, String name,
230: boolean template) {
231: try {
232: FileSystem fs = Repository.getDefault()
233: .getDefaultFileSystem();
234: if (template) {
235: name = '/' + prefTemplates(root) + name;
236: } else {
237: name = '/' + prefObjects(root) + name;
238: }
239: FileObject fo = fs.findResource(name);
240:
241: if (fo == null && template) {
242: // we do not create template directories, if it is missing
243: // we use the root services template directory
244: name = prefTemplates(root);
245: }
246:
247: if (fo == null) {
248: // if the directory is missing, create new one
249: fo = FileUtil.createFolder(fs.getRoot(), name);
250: }
251:
252: return DataFolder.findFolder(fo);
253: } catch (java.io.IOException ex) {
254: throw (IllegalStateException) new IllegalStateException(ex
255: .toString()).initCause(ex);
256: }
257: }
258:
259: /** Refreshes the node for given key.
260: * @param node the original node
261: */
262: public final void refreshKey(Node node) {
263: ((Ch) getChildren()).refreshKey0(node);
264: }
265:
266: public boolean canDestroy() {
267: return false;
268: }
269:
270: public boolean canCut() {
271: return false;
272: }
273:
274: public boolean canCopy() {
275: return false;
276: }
277:
278: protected Sheet createSheet() {
279: return new Sheet();
280: }
281:
282: public boolean canRename() {
283: return false;
284: }
285:
286: public Node cloneNode() {
287: return new LookupNode((DataFolder) super
288: .getCookie(DataFolder.class));
289: }
290:
291: /** Misleading name: need not be a leaf at all. */
292: private static final class Leaf extends FilterNode {
293: DataObject data;
294: Node parent;
295:
296: Leaf(Node node, DataObject data, Node parent) {
297: super (node, ((data instanceof XMLDataObject) || node
298: .isLeaf()) ? Children.LEAF
299: : new FilterNode.Children(node));
300: this .data = data;
301: this .parent = parent;
302: }
303:
304: // #17920: Index cookie works only when equality works
305: public boolean equals(Object o) {
306: return this == o || getOriginal().equals(o)
307: || (o != null && o.equals(getOriginal()));
308: }
309:
310: public int hashCode() {
311: return getOriginal().hashCode();
312: }
313:
314: public HelpCtx getHelpCtx() {
315: Object o = data.getPrimaryFile().getAttribute(EA_HELPCTX);
316: if (o != null) {
317: return new HelpCtx(o.toString());
318: }
319: // now try the original DataObject (assume it is a folder-thing)
320: HelpCtx ctx = getOriginal().getHelpCtx();
321: if (ctx != null && ctx != HelpCtx.DEFAULT_HELP
322: && !INSTANCE_DEFAULT_HELP.equals(ctx)) {
323: return ctx;
324: }
325: // try the parent node:
326: Node n = getParentNode();
327: if (n == null)
328: n = parent;
329: if (n != null)
330: ctx = n.getHelpCtx();
331: return ctx;
332: }
333:
334: public Action getPreferredAction() {
335: return null;
336: }
337:
338: }
339:
340: /** Children for the LookupNode. Creates LookupNodes or
341: * LookupItemNodes as filter subnodes...
342: */
343: private static final class Ch extends FilterNode.Children {
344: /** @param or original node to take children from */
345: public Ch(DataFolder folder) {
346: super (folder.getNodeDelegate());
347: }
348:
349: /** Overridden to provide package-private access. */
350: void refreshKey0(Node node) {
351: refreshKey(node);
352: }
353:
354: /** Overridden, returns LookupNode filters of original nodes.
355: *
356: * @param node node to create copy of
357: * @return LookupNode filter of the original node
358: */
359: @Override
360: protected Node[] createNodes(Node node) {
361: DataObject obj = (DataObject) node
362: .getCookie(DataObject.class);
363: //System.err.println("obj="+obj+" node="+node+" hidden="+(obj==null?null:obj.getPrimaryFile ().getAttribute (EA_HIDDEN)));
364:
365: if (obj != null
366: && Boolean.TRUE.equals(obj.getPrimaryFile()
367: .getAttribute(EA_HIDDEN))) {
368: return new Node[0];
369: }
370:
371: LookupNode parent = (LookupNode) getNode();
372:
373: if (obj != null) {
374: if (obj instanceof DataFolder
375: && node.equals(obj.getNodeDelegate())) {
376: node = parent.createChild((DataFolder) obj);
377: return new Node[] { node };
378: } else if (obj instanceof DataShadow) {
379: DataObject orig = ((DataShadow) obj).getOriginal();
380: FileObject fo = orig.getPrimaryFile();
381:
382: // if folder referenced by shadow is empty do not show it
383: if (fo.isFolder()
384: && !fo.getChildren(false).hasMoreElements())
385: return null;
386:
387: if (orig instanceof DataFolder) {
388: return new Node[] { parent
389: .createChild((DataFolder) orig) };
390: } else {
391: obj = orig;
392: node = orig.getNodeDelegate();
393: }
394: }
395: node = new Leaf(node, obj, parent);
396: }
397:
398: node = parent.createChild(node);
399:
400: return new Node[] { node };
401: }
402:
403: }
404:
405: }
|