001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.gui.help;
003
004 import java.awt.Component;
005 import java.util.Locale;
006
007 import javax.swing.AbstractButton;
008 import javax.swing.Action;
009 import javax.swing.JComponent;
010 import javax.swing.JMenu;
011 import javax.swing.KeyStroke;
012
013 import org.openstreetmap.josm.Main;
014 import org.openstreetmap.josm.actions.HelpAction;
015 import org.openstreetmap.josm.tools.LanguageInfo;
016
017 public class HelpUtil {
018
019 /**
020 * Replies the base wiki URL.
021 *
022 * @return the base wiki URL
023 */
024 static public String getWikiBaseUrl() {
025 return Main.pref.get("help.baseurl", "http://josm.openstreetmap.de");
026 }
027
028 /**
029 * Replies the base wiki URL for help pages
030 *
031 * @return the base wiki URL for help pages
032 */
033 static public String getWikiBaseHelpUrl() {
034 return getWikiBaseUrl() + "/wiki";
035 }
036
037 /**
038 * Replies the URL on the wiki for an absolute help topic. The URL is encoded in UTF-8.
039 *
040 * @param absoluteHelpTopic the absolute help topic
041 * @return the url
042 * @see #buildAbsoluteHelpTopic(String)
043 * @see #buildAbsoluteHelpTopic(String, Locale)
044 */
045 static public String getHelpTopicUrl(String absoluteHelpTopic) {
046 String ret = getWikiBaseHelpUrl();
047 ret = ret.replaceAll("\\/+$", "");
048 absoluteHelpTopic =absoluteHelpTopic.replace(" ", "%20");
049 absoluteHelpTopic = absoluteHelpTopic.replaceAll("^\\/+", "/");
050 return ret + absoluteHelpTopic;
051 }
052
053 /**
054 * Replies the URL to the edit page for the absolute help topic.
055 *
056 * @param absoluteHelpTopic the absolute help topic
057 * @return the URL to the edit page
058 */
059 static public String getHelpTopicEditUrl(String absoluteHelpTopic) {
060 String topicUrl = getHelpTopicUrl(absoluteHelpTopic);
061 topicUrl = topicUrl.replaceAll("#[^#]*$", ""); // remove optional fragment
062 return topicUrl + "?action=edit";
063 }
064
065 /**
066 * Extracts the relative help topic from an URL. Replies null, if
067 * no relative help topic is found.
068 *
069 * @param url the url
070 * @return the relative help topic in the URL, i.e. "/Action/New"
071 */
072 static public String extractRelativeHelpTopic(String url) {
073 String topic = extractAbsoluteHelpTopic(url);
074 if (topic == null) return null;
075 String pattern = "/[A-Z][a-z]:" + getHelpTopicPrefix(Locale.ENGLISH).replaceAll("^\\/+", "");
076 if (url.matches(pattern))
077 return topic.substring(pattern.length());
078 return null;
079 }
080
081 /**
082 * Extracts the absolute help topic from an URL. Replies null, if
083 * no absolute help topic is found.
084 *
085 * @param url the url
086 * @return the absolute help topic in the URL, i.e. "/De:Help/Action/New"
087 */
088 static public String extractAbsoluteHelpTopic(String url) {
089 if (!url.startsWith(getWikiBaseHelpUrl())) return null;
090 url = url.substring(getWikiBaseHelpUrl().length());
091 String prefix = getHelpTopicPrefix(Locale.ENGLISH);
092 if (url.startsWith(prefix))
093 return url;
094
095 String pattern = "/[A-Z][a-z]:" + prefix.replaceAll("^\\/+", "");
096 if (url.matches(pattern))
097 return url;
098
099 return null;
100 }
101
102 /**
103 * Replies the help topic prefix for the current locale. Examples:
104 * <ul>
105 * <li>/Help if the current locale is a locale with language "en"</li>
106 * <li>/De:Help if the current locale is a locale with language "de"</li>
107 * </ul>
108 *
109 * @return the help topic prefix
110 * @see #getHelpTopicPrefix(Locale)
111 */
112 static public String getHelpTopicPrefix() {
113 return getHelpTopicPrefix(Locale.getDefault());
114 }
115
116 /**
117 * Replies the help topic prefix for the given locale. Examples:
118 * <ul>
119 * <li>/Help if the locale is a locale with language "en"</li>
120 * <li>/De:Help if the locale is a locale with language "de"</li>
121 * </ul>
122 *
123 * @param locale the locale. {@link Locale#ENGLISH} assumed, if null.
124 * @return the help topic prefix
125 * @see #getHelpTopicPrefix(Locale)
126 */
127 static public String getHelpTopicPrefix(Locale locale) {
128 if (locale == null) {
129 locale = Locale.ENGLISH;
130 }
131 String ret = Main.pref.get("help.pathhelp", "/Help");
132 ret = ret.replaceAll("^\\/+", ""); // remove leading /
133 ret = "/" + LanguageInfo.getWikiLanguagePrefix(locale) + ret;
134 return ret;
135 }
136
137 /**
138 * Replies the absolute, localized help topic for the given topic.
139 *
140 * Example: for a topic "/Dialog/RelationEditor" and the locale "de", this method
141 * replies "/De:Help/Dialog/RelationEditor"
142 *
143 * @param topic the relative help topic. Home help topic assumed, if null.
144 * @param locale the locale. {@link Locale#ENGLISH} assumed, if null.
145 * @return the absolute, localized help topic
146 */
147 static public String buildAbsoluteHelpTopic(String topic, Locale locale) {
148 if (locale == null) {
149 locale = Locale.ENGLISH;
150 }
151 if (topic == null || topic.trim().length() == 0 || topic.trim().equals("/"))
152 return getHelpTopicPrefix(locale);
153 String ret = getHelpTopicPrefix(locale);
154 if (topic.startsWith("/")) {
155 ret += topic;
156 } else {
157 ret += "/" + topic;
158 }
159 ret = ret.replaceAll("\\/+", "\\/"); // just in case, collapse sequences of //
160 return ret;
161 }
162
163 /**
164 * Replies the absolute, localized help topic for the given topic and the
165 * current locale.
166 *
167 * @param topic the relative help topic. Home help topic assumed, if null.
168 * @return the absolute, localized help topic
169 * @see Locale#getDefault()
170 * @see #buildAbsoluteHelpTopic(String, Locale)
171 */
172 static public String buildAbsoluteHelpTopic(String topic) {
173 return buildAbsoluteHelpTopic(topic, Locale.getDefault());
174 }
175
176 /**
177 * Replies the context specific help topic configured for <code>context</code>.
178 *
179 * @return the help topic. null, if no context specific help topic is found
180 */
181 static public String getContextSpecificHelpTopic(Object context) {
182 if (context == null)
183 return null;
184 if (context instanceof Helpful)
185 return ((Helpful)context).helpTopic();
186 if (context instanceof JMenu) {
187 JMenu b = (JMenu)context;
188 if (b.getClientProperty("help") != null)
189 return (String)b.getClientProperty("help");
190 return null;
191 }
192 if (context instanceof AbstractButton) {
193 AbstractButton b = (AbstractButton)context;
194 if (b.getClientProperty("help") != null)
195 return (String)b.getClientProperty("help");
196 return getContextSpecificHelpTopic(b.getAction());
197 }
198 if (context instanceof Action)
199 return (String)((Action)context).getValue("help");
200 if (context instanceof JComponent && ((JComponent)context).getClientProperty("help") != null)
201 return (String)((JComponent)context).getClientProperty("help");
202 if (context instanceof Component)
203 return getContextSpecificHelpTopic(((Component)context).getParent());
204 return null;
205 }
206
207 /**
208 * Replies the global help action, if available. Otherwise, creates an instance
209 * of {@link HelpAction}.
210 *
211 * @return
212 */
213 static private Action getHelpAction() {
214 try {
215 return Main.main.menu.help;
216 } catch(NullPointerException e) {
217 return new HelpAction();
218 }
219 }
220
221 /**
222 * Makes a component aware of context sensitive help.
223 *
224 * A relative help topic doesn't start with /Help and doesn't include a locale
225 * code. Example: /Dialog/RelationEditor is a relative help topic, /De:Help/Dialog/RelationEditor
226 * is not.
227 *
228 * @param component the component the component
229 * @param topic the help topic. Set to the default help topic if null.
230 */
231 static public void setHelpContext(JComponent component, String relativeHelpTopic) {
232 if (relativeHelpTopic == null) {
233 relativeHelpTopic = "/";
234 }
235 component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F1"), "help");
236 component.getActionMap().put("help", getHelpAction());
237 component.putClientProperty("help", relativeHelpTopic);
238 }
239
240 /**
241 * This is a simple marker method for help topic literals. If you declare a help
242 * topic literal in the source you should enclose it in ht(...).
243 *
244 * <strong>Example</strong>
245 * <pre>
246 * String helpTopic = ht("/Dialog/RelationEditor");
247 * or
248 * putValue("help", ht("/Dialog/RelationEditor"));
249 * </pre>
250 *
251 *
252 * @param helpTopic
253 */
254 static public String ht(String helpTopic) {
255 // this is just a marker method
256 return helpTopic;
257 }
258 }