View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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      //--- Constant(s) ---
57  
58      public static final String XNAP_MANUAL = "xnap-manual";
59  
60      //--- Data field(s) ---
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      //--- Constructor(s) ---
70  
71      private HelpManager()
72      {
73      }
74  
75      //--- Method(s) ---
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 }