001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.gui.help;
003
004 import java.io.BufferedReader;
005 import java.io.IOException;
006 import java.io.InputStreamReader;
007 import java.net.HttpURLConnection;
008 import java.net.MalformedURLException;
009 import java.net.URL;
010
011 import org.openstreetmap.josm.tools.WikiReader;
012
013 /**
014 * Reads help content from the JOSM Wiki and prepares it for rendering in the internal
015 * help browser.
016 *
017 * The help content has to be <strong>filtered</strong> because only the main content <tt><div></tt>
018 * of a Wiki help page is displayed in the internal help browser.
019 *
020 * It also has to be <strong>transformed</strong> because the internal help browser required slightly
021 * different HTML than what is provided by the Wiki.
022 *
023 * @see WikiReader
024 */
025 public class HelpContentReader {
026
027 /** the base url */
028 private String baseUrl;
029
030 /**
031 * constructor
032 *
033 * @param baseUrl the base url of the JOSM help wiki, i.e. http://josm.openstreetmap.org
034 */
035 public HelpContentReader(String baseUrl) {
036 this.baseUrl = baseUrl;
037 }
038
039 /**
040 * Fetches the content of a help topic from the JOSM wiki.
041 *
042 * @param helpTopicUrl the absolute help topic URL
043 * @return the content, filtered and transformed for being displayed in the internal help browser
044 * @throws HelpContentReaderException thrown if problem occurs
045 * @throws MissingHelpContentException thrown if this helpTopicUrl doesn't point to an existing Wiki help page
046 */
047 public String fetchHelpTopicContent(String helpTopicUrl, boolean dotest) throws HelpContentReaderException {
048 URL url = null;
049 HttpURLConnection con = null;
050 BufferedReader in = null;
051 try {
052 url = new URL(helpTopicUrl);
053 con = (HttpURLConnection)url.openConnection();
054 con.connect();
055 in = new BufferedReader(new InputStreamReader(con.getInputStream(),"utf-8"));
056 return prepareHelpContent(in, dotest);
057 } catch(MalformedURLException e) {
058 throw new HelpContentReaderException(e);
059 } catch(IOException e) {
060 HelpContentReaderException ex = new HelpContentReaderException(e);
061 if (con != null) {
062 try {
063 ex.setResponseCode(con.getResponseCode());
064 } catch(IOException e1) {
065 // ignore
066 }
067 }
068 throw ex;
069 } finally {
070 if (in != null) {
071 try {
072 in.close();
073 } catch(IOException e) {
074 // ignore
075 }
076 }
077 }
078 }
079
080 /**
081 * Reads help content from the input stream and prepares it to be rendered later
082 * in the internal help browser.
083 *
084 * Throws a {@link MissingHelpContentException} if the content read from the stream
085 * most likely represents a stub help page.
086 *
087 * @param in the input stream
088 * @return the content
089 * @throws HelpContentReaderException thrown if an exception occurs
090 * @throws MissingHelpContentException thrown, if the content read isn't a help page
091 */
092 protected String prepareHelpContent(BufferedReader in, boolean dotest) throws HelpContentReaderException {
093 boolean isInContent = false;
094 boolean isInTranslationsSideBar = false;
095 boolean isExistingHelpPage = false;
096 StringBuffer sball = new StringBuffer();
097 StringBuffer sb = new StringBuffer();
098 try {
099 for (String line = in.readLine(); line != null; line = in.readLine()) {
100 sball.append(line);
101 sball.append("\n");
102 if (line.contains("<div id=\"searchable\">")) {
103 isInContent = true;
104 } else if (line.contains("<div class=\"wiki-toc trac-nav\"")) {
105 isInTranslationsSideBar = true;
106 } else if (line.contains("<div class=\"wikipage searchable\">")) {
107 isInContent = true;
108 } else if (line.contains("<div class=\"buttons\">")) {
109 isInContent = false;
110 } else if (line.contains("<h3>Attachments</h3>")) {
111 isInContent = false;
112 } else if (line.contains("<div id=\"attachments\">")) {
113 isInContent = false;
114 } else if (line.contains("<div class=\"trac-modifiedby\">")) {
115 continue;
116 } else if (line.contains("<input type=\"submit\" name=\"attachfilebutton\"")) {
117 // heuristic: if we find a button for uploading images we are in an
118 // existing pages. Otherwise this is probably the stub page for a not yet
119 // existing help page
120 isExistingHelpPage = true;
121 }
122 if (isInContent && !isInTranslationsSideBar) {
123 // add a border="0" attribute to images, otherwise the internal help browser
124 // will render a thick border around images inside an <a> element
125 //
126 // Also make sure image URLs are absolute
127 //
128 line = line.replaceAll("<img ([^>]*)src=\"/", "<img border=\"0\" \\1src=\"" + baseUrl + "/").replaceAll("href=\"/",
129 "href=\"" + baseUrl + "/").replaceAll(" />", ">");
130 sb.append(line);
131 sb.append("\n");
132 } else if (isInTranslationsSideBar && line.contains("</div>")) {
133 isInTranslationsSideBar = false;
134 }
135 }
136 } catch(IOException e) {
137 throw new HelpContentReaderException(e);
138 }
139 if(!dotest && sb.length() == 0)
140 sb = sball;
141 else if (dotest && !isExistingHelpPage)
142 throw new MissingHelpContentException();
143 sb.insert(0, "<html>");
144 sb.append("<html>");
145 return sb.toString();
146 }
147 }