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.openide.util;
043:
044: import java.beans.BeanDescriptor;
045: import java.beans.IntrospectionException;
046: import java.beans.Introspector;
047: import java.net.URL;
048: import java.util.logging.Level;
049: import java.util.logging.Logger;
050: import javax.swing.JComponent;
051:
052: /** Provides help for any window or other feature in the system.
053: * It is designed to be JavaHelp-compatible and to use the same tactics when
054: * assigning help to {@link JComponent} instances.
055: * @see <a href="@org-netbeans-modules-javahelp@/">JavaHelp Integration API</a>
056: * @author Petr Hamernik, Jaroslav Tulach, Jesse Glick
057: */
058: public final class HelpCtx extends Object {
059: private static final Logger err = Logger
060: .getLogger("org.openide.util.HelpCtx"); // NOI18N
061:
062: /** Default help page.
063: * This (hopefully) points to a note explaining to the user that no help is available.
064: * Precisely, the Help ID is set to <code>org.openide.util.HelpCtx.DEFAULT_HELP</code>.
065: */
066: public final static HelpCtx DEFAULT_HELP = new HelpCtx(
067: HelpCtx.class.getName() + ".DEFAULT_HELP"); // NOI18N
068:
069: /** URL of the help page */
070: private final URL helpCtx;
071:
072: /** JavaHelp ID for the help */
073: private final String helpID;
074:
075: /** Create a help context by URL.
076: * @deprecated Does not work nicely with JavaHelp.
077: * @param helpCtx URL to point help to
078: */
079: @Deprecated
080: public HelpCtx(URL helpCtx) {
081: this .helpCtx = helpCtx;
082: this .helpID = null;
083: }
084:
085: /** Create a help context by tag.
086: * You must provide an ID of the
087: * desired help for the item. The ID should refer to an
088: * already installed help; this can be easily installed by specifying
089: * a JavaHelp help set for the module (see the Modules API for details).
090: *
091: * @param helpID the JavaHelp ID of the help
092: */
093: public HelpCtx(String helpID) {
094: this .helpID = helpID;
095: this .helpCtx = null;
096: }
097:
098: /** Create a help context by class.
099: * Assigns the name of a class as
100: * the ID.
101: *
102: * @param clazz the class to take the name from
103: */
104: public HelpCtx(Class clazz) {
105: this (clazz.getName());
106: }
107:
108: /** Get a URL to the help page, if applicable.
109: * @return a URL to the page, or <code>null</code> if the target was specified by ID
110: */
111: public URL getHelp() {
112: return helpCtx;
113: }
114:
115: /** Get the ID of the help page, if applicable.
116: * @return the JavaHelp ID string, or <code>null</code> if specified by URL
117: */
118: public String getHelpID() {
119: return helpID;
120: }
121:
122: // object identity
123: public int hashCode() {
124: int base = HelpCtx.class.hashCode();
125:
126: if (helpCtx != null) {
127: base ^= helpCtx.hashCode();
128: }
129:
130: if (helpID != null) {
131: base ^= helpID.hashCode();
132: }
133:
134: return base;
135: }
136:
137: public boolean equals(Object o) {
138: if ((o == null) || !(o instanceof HelpCtx)) {
139: return false;
140: }
141:
142: HelpCtx oo = (HelpCtx) o;
143:
144: return ((helpCtx == oo.helpCtx) || ((helpCtx != null) && helpCtx
145: .equals(oo.helpCtx)))
146: && ((helpID == oo.helpID) || ((helpID != null) && helpID
147: .equals(oo.helpID)));
148: }
149:
150: public String toString() {
151: if (helpID != null) {
152: return "HelpCtx[" + helpID + "]"; // NOI18N
153: } else {
154: return "HelpCtx[" + helpCtx + "]"; // NOI18N
155: }
156: }
157:
158: /** Set the help ID for a component.
159: * @param comp the visual component to associate help to
160: * @param helpID help ID, or <code>null</code> if the help ID should be removed
161: */
162: public static void setHelpIDString(JComponent comp, String helpID) {
163: err.fine("setHelpIDString: " + helpID + " on " + comp);
164:
165: comp.putClientProperty("HelpID", helpID); // NOI18N
166: }
167:
168: /** Find the help ID for a component.
169: * If the component implements {@link org.openide.util.HelpCtx.Provider},
170: * its method {@link org.openide.util.HelpCtx.Provider#getHelpCtx} is called.
171: * If the component has help attached by {@link #setHelpIDString}, it returns that.
172: * Otherwise it checks the parent component recursively.
173: *
174: * @param comp the component to find help for
175: * @return the help for that component (never <code>null</code>)
176: */
177: public static HelpCtx findHelp(java.awt.Component comp) {
178: if (err.isLoggable(Level.FINEST)) {
179: err.log(Level.FINEST, "findHelp on " + comp,
180: new Exception());
181: } else {
182: err.fine("findHelp on " + comp);
183: }
184:
185: while (comp != null) {
186: if (comp instanceof HelpCtx.Provider) {
187: HelpCtx h = ((HelpCtx.Provider) comp).getHelpCtx();
188:
189: err.fine("found help " + h
190: + " through HelpCtx.Provider interface");
191:
192: return h;
193: }
194:
195: if (comp instanceof JComponent) {
196: JComponent jc = (JComponent) comp;
197: String hid = (String) jc.getClientProperty("HelpID"); // NOI18N
198:
199: if (hid != null) {
200: err.fine("found help " + hid
201: + " by client property");
202:
203: return new HelpCtx(hid);
204: }
205: }
206:
207: comp = comp.getParent();
208:
209: err.fine("no luck, trying parent " + comp);
210: }
211:
212: err.fine("nothing found");
213:
214: return DEFAULT_HELP;
215: }
216:
217: /** Finds help context for a generic object. Right now checks
218: * for HelpCtx.Provider and handles java.awt.Component in a
219: * special way compatible with JavaHelp.
220: * Also {@link BeanDescriptor}'s are checked for a string-valued attribute
221: * <code>helpID</code>, as per the JavaHelp specification (but no help sets
222: * will be loaded).
223: *
224: * @param instance to search help for
225: * @return the help for the object or <code>HelpCtx.DEFAULT_HELP</code> if HelpCtx cannot be found
226: *
227: * @since 4.3
228: */
229: public static HelpCtx findHelp(Object instance) {
230: if (instance instanceof java.awt.Component) {
231: return findHelp((java.awt.Component) instance);
232: }
233:
234: if (instance instanceof HelpCtx.Provider) {
235: return ((HelpCtx.Provider) instance).getHelpCtx();
236: }
237:
238: try {
239: BeanDescriptor d = Introspector.getBeanInfo(
240: instance.getClass()).getBeanDescriptor();
241: String v = (String) d.getValue("helpID"); // NOI18N
242:
243: if (v != null) {
244: return new HelpCtx(v);
245: }
246: } catch (IntrospectionException e) {
247: err.fine("findHelp on " + instance + ": " + e);
248: }
249:
250: return HelpCtx.DEFAULT_HELP;
251: }
252:
253: /**
254: * An object implementing this interface is willing to answer
255: * the HelpCtx.findHelp() query itself.
256: *
257: * @since 3.20
258: */
259: public static interface Provider {
260: /**
261: * Get the {@link HelpCtx} associated with implementing object.
262: * @return assigned <code>HelpCtx</code> or
263: * {@link #DEFAULT_HELP}, never <code>null</code>.
264: */
265: public HelpCtx getHelpCtx();
266: }
267: }
|