1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.gui.util;
21
22 import java.awt.Color;
23 import java.awt.Component;
24 import java.awt.Container;
25 import java.awt.Window;
26 import java.awt.event.ActionEvent;
27 import java.awt.event.ActionListener;
28 import java.awt.event.KeyEvent;
29 import java.net.URL;
30 import java.util.Iterator;
31 import java.util.LinkedList;
32 import java.util.List;
33 import javax.help.CSH;
34 import javax.help.HelpBroker;
35 import javax.help.HelpSet;
36 import javax.swing.AbstractButton;
37 import javax.swing.JComponent;
38 import javax.swing.JMenu;
39 import javax.swing.JPopupMenu;
40 import javax.swing.KeyStroke;
41 import javax.swing.MenuElement;
42 import javax.swing.border.Border;
43 import javax.swing.border.LineBorder;
44 import javax.swing.plaf.BorderUIResource;
45 import javax.swing.plaf.basic.BasicBorders;
46 import org.apache.log4j.Logger;
47 import org.xnap.loader.XNapClassLoader;
48
49 /***
50 * A helper class providing the main helpset and helpbroker and some
51 * convenience functions for registering help keys in components.
52 */
53 public class HelpManager
54 {
55
56
57
58 public static final String XNAP_MANUAL = "xnap-manual";
59
60
61
62 private static HelpSet mainHelpSet = null;
63 private static XNapHelpBroker mainHelpBroker = null;
64
65 private static ActionListener tracker = null;
66
67 private static Logger logger = Logger.getLogger(HelpManager.class);
68
69
70
71 private HelpManager()
72 {
73 }
74
75
76
77 /***
78 * Returns the main helpset.
79 *
80 * If helpset isn't loaded yet, it will be loaded on demand.
81 *
82 * @return returns null if helpset couldn't be loaded.
83 */
84 public static HelpSet getMainHelpSet()
85 {
86 if (mainHelpSet == null) {
87 mainHelpSet = loadHelpSet(XNAP_MANUAL);
88 }
89 return mainHelpSet;
90 }
91
92 /***
93 * Returns the main helpbroker.
94 */
95 public static XNapHelpBroker getMainHelpBroker()
96 {
97 if (mainHelpBroker == null) {
98 if (getMainHelpSet() != null) {
99 mainHelpBroker = new XNapHelpBroker(getMainHelpSet());
100 }
101 }
102 return mainHelpBroker;
103 }
104
105 /***
106 * Adds helpset to the main helpset hierarchy.
107 */
108 public static void add(HelpSet hs)
109 {
110 getMainHelpSet().add(hs);
111 }
112
113 /***
114 * Removes helpset from the main helpset hierarchy.
115 */
116 public static void remove(HelpSet hs)
117 {
118 getMainHelpSet().remove(hs);
119 }
120
121 /***
122 * Helper method to load helpsets.
123 *
124 * @param helpset name of the helpset file without the ending, e.g.
125 * "xnap-manual" from "xnap-manual.hs".
126 */
127 public static HelpSet loadHelpSet(String helpset)
128 {
129 URL url = HelpSet.findHelpSet(XNapClassLoader.getInstance(), helpset);
130 if (url != null) {
131 try {
132 return new HelpSet(XNapClassLoader.getInstance(), url);
133 }
134 catch (Exception e) {
135 logger.debug("Could not load helpset" + helpset, e);
136 }
137 }
138 else {
139 logger.debug("Could not find helpset");
140 }
141 return null;
142 }
143
144 /***
145 * Convenience method enabling the help keys and the context help key for
146 * a JComponent.
147 */
148 public static void enableHelpKeys(JComponent comp, String id, HelpSet hs)
149 {
150 HelpBroker hb = getMainHelpBroker();
151 if (hb != null) {
152 hb.enableHelpKey(comp, id, hs);
153 enableContextHelpKey(comp);
154 }
155 }
156
157 /***
158 * Enables the context help key for a JComponent.
159 */
160 public static void enableContextHelpKey(JComponent jc)
161 {
162 if (getMainHelpBroker() != null) {
163 jc.registerKeyboardAction
164 (getTracker(), KeyStroke.getKeyStroke(KeyEvent.VK_F1,
165 KeyEvent.SHIFT_MASK),
166 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
167 }
168 }
169
170 public static ActionListener getTracker()
171 {
172 if (tracker == null) {
173 tracker = new Tracker();
174 }
175 return tracker;
176 }
177
178 private static class Tracker implements ActionListener
179 {
180 private ActionListener tracker =
181 new CSH.DisplayHelpAfterTracking(getMainHelpBroker());
182
183 private class CBPair
184 {
185 public JComponent c;
186 public Border b;
187 public boolean p;
188
189 public CBPair(JComponent c, Border b, boolean p)
190 {
191 this.c = c;
192 this.b = b;
193 this.p = p;
194 }
195
196 public CBPair(JComponent c, Border b)
197 {
198 this(c, b, false);
199 }
200 }
201
202 public void actionPerformed(ActionEvent event)
203 {
204 List borders = new LinkedList();
205 if (event.getSource() instanceof Component) {
206 Component c = (Component)event.getSource();
207 c = getTopComponent(c);
208 setBorders(c, borders);
209 }
210 tracker.actionPerformed(event);
211 resetBorders(borders);
212 }
213
214 private Component getTopComponent(Component c)
215 {
216 for (Component parent = c; parent != null;) {
217 c = parent;
218 if (parent instanceof Window) {
219 break;
220 }
221 if (parent instanceof MenuElement) {
222 if (parent instanceof JPopupMenu) {
223 parent = ((JPopupMenu)parent).getInvoker();
224 }
225 else {
226 parent = ((MenuElement)parent).getComponent();
227 }
228 }
229 parent = parent.getParent();
230 }
231 return c;
232 }
233
234 private void setBorders(Component c, List borders)
235 {
236 if (c instanceof JComponent) {
237 JComponent jc = (JComponent)c;
238 String helpID = (String)jc.getClientProperty("HelpID");
239 if (helpID != null) {
240 try {
241 BorderUIResource.CompoundBorderUIResource b =
242 new BorderUIResource.CompoundBorderUIResource
243 (new LineBorder(Color.RED),
244 jc.getBorder());
245 if (jc instanceof AbstractButton) {
246 AbstractButton ab = (AbstractButton)jc;
247 borders.add(new CBPair(jc, jc.getBorder(),
248 ab.isBorderPainted()));
249 ab.setBorderPainted(true);
250 ab.setBorder(b);
251 }
252 else {
253 borders.add(new CBPair(jc, jc.getBorder()));
254 jc.setBorder(b);
255 }
256 }
257 catch (IllegalArgumentException iae) {
258 }
259 }
260 }
261 if (c instanceof Container) {
262 Container cont = (Container)c;
263 for (int i = 0; i < cont.getComponentCount(); i++) {
264 setBorders(cont.getComponent(i), borders);
265 }
266 }
267 else if (c instanceof JMenu) {
268 setBorders(((JMenu)c).getPopupMenu(), borders);
269 }
270 }
271
272 private void resetBorders(List borders)
273 {
274 for (Iterator it = borders.iterator(); it.hasNext();) {
275 CBPair pair = (CBPair)it.next();
276 if (pair.c instanceof AbstractButton) {
277 ((AbstractButton)pair.c).setBorderPainted(pair.p);
278 }
279 pair.c.setBorder(pair.b);
280 }
281 }
282 }
283 }