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 }