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 }