source: josm/trunk/src/org/openstreetmap/josm/gui/GettingStarted.java@ 1450

Last change on this file since 1450 was 1450, checked in by stoecker, 15 years ago

fix #1848 - version in start screen. patch by xeen

  • Property svn:eol-style set to native
File size: 12.8 KB
RevLine 
[608]1// License: GPL. See LICENSE file for details.
2
3package org.openstreetmap.josm.gui;
4
[582]5import static org.openstreetmap.josm.tools.I18n.tr;
6
[623]7import java.io.IOException;
[1290]8import java.util.ArrayList;
[1350]9import java.util.concurrent.Executors;
10import java.util.concurrent.ExecutorService;
11import java.util.concurrent.Callable;
12import java.util.concurrent.Future;
[623]13import java.util.regex.Matcher;
14import java.util.regex.Pattern;
[582]15
[623]16import java.awt.BorderLayout;
[1350]17import java.awt.EventQueue;
[623]18
19import javax.swing.JScrollPane;
[582]20import javax.swing.JEditorPane;
21import javax.swing.JPanel;
22import javax.swing.event.HyperlinkEvent;
23import javax.swing.event.HyperlinkListener;
[623]24import javax.swing.border.EmptyBorder;
[582]25
26import org.openstreetmap.josm.Main;
[1450]27import org.openstreetmap.josm.io.CacheCustomContent;
[582]28import org.openstreetmap.josm.tools.OpenBrowser;
[623]29import org.openstreetmap.josm.tools.WikiReader;
30import org.openstreetmap.josm.actions.AboutAction;
[608]31
[623]32public class GettingStarted extends JPanel {
[1450]33 private String content = "";
[1356]34 static private String styles = "<style type=\"text/css\">\n"+
35 "body { font-family: sans-serif; font-weight: bold; }\n"+
36 "h1 {text-align: center;}\n"+
37 "</style>\n";
[608]38
[652]39 public class LinkGeneral extends JEditorPane implements HyperlinkListener {
40 public LinkGeneral(String text) {
41 setContentType("text/html");
42 setText(text);
43 setEditable(false);
44 setOpaque(false);
45 addHyperlinkListener(this);
[608]46 }
[652]47 public void hyperlinkUpdate(HyperlinkEvent e) {
48 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
49 OpenBrowser.displayUrl(e.getDescription());
50 }
[608]51 }
52 }
[1359]53
[1450]54 /**
55 * This class encapsulates the "reading URL" task and can be executed in background and in
56 * parallel. Since the MOTD is many separate pages this speeds things up quite a lot. If no
57 * localized version is available, it automatically falls back to the international one.
58 */
59 private class readMOTD implements Callable<String> {
[1350]60 private boolean isLocalized;
61 private boolean isHelp;
62 private String urlLoc;
63 private String urlIntl;
64 private String urlBase;
[1359]65
[1450]66 /**
67 * Read a MOTD page
68 * @param isLocalized If true, tries to get localized version as defined in urlLoc
69 * @param urlBase Base URL (i.e. http://www.openstreetmap.de/wiki/)
70 * @param urlLoc Part to append to base URL to receive localized version
71 * @param urlIntl Part to append to base URL to receive international version
72 * @param makeList If true, the URL's contents will be wrapped in a list (<ul><li>)
73 */
74 readMOTD(boolean isLocalized, String urlBase, String urlLoc, String urlIntl, boolean makeList) {
[1350]75 this.isLocalized = isLocalized;
76 this.urlBase = urlBase;
77 this.urlLoc = urlLoc;
78 this.urlIntl = urlIntl;
[1450]79 this.isHelp = makeList;
[1350]80 }
[608]81
[1450]82 /*
83 * Does the actual work
84 * @see java.util.concurrent.Callable#call()
85 */
[1350]86 public String call() {
87 WikiReader wr = new WikiReader(urlBase);
88 String content = "";
89 try {
[1450]90 // If we hit a non-localized link here, we already know there's no translated
91 // version available
[1350]92 String message = isLocalized ? wr.read(urlLoc) : "";
93 // Look for non-localized version
94 if (message.equals(""))
95 message = wr.read(urlIntl);
96
97 if (!message.equals(""))
98 if(isHelp)
99 content += message;
100 else
[1450]101 content += "<ul><li>"+ message.substring(8)
102 .replaceAll("\n *\\* +","</li><li>")+"</li></ul>";
[1350]103 } catch (IOException ioe) {
104 try {
105 if(isHelp)
106 content += wr.read(urlIntl);
107 else
[1450]108 content += "<ul><li>"+wr.read(urlIntl).substring(8)
109 .replaceAll("\n *\\* +","</li><li>")+"</li></ul>";
[1350]110 } catch (IOException ioe2) {
111 }
112 }
[1359]113
[1350]114 return content;
115 }
116 }
117
[1450]118 /**
119 * Grabs current MOTD from cache or webpage and parses it.
120 */
121 private class assignContent extends CacheCustomContent {
122 public assignContent() {
123 super("motd.html", CacheCustomContent.INTERVAL_DAILY);
[1290]124 }
[574]125
[1450]126 final private int myVersion = AboutAction.getVersionNumber();
[608]127
[1450]128 /**
129 * This function gets executed whenever the cached files need updating
130 * @see org.openstreetmap.josm.io.CacheCustomContent#updateData()
131 */
132 protected byte[] updateData() {
133 String motd = "";
134 String baseurl = Main.pref.get("help.baseurl", "http://josm.openstreetmap.de");
135 WikiReader wr = new WikiReader(baseurl);
136 String motdcontent = "";
137 try {
138 motdcontent = wr.read(baseurl + "/wiki/MessageOfTheDay?format=txt");
139 } catch (IOException ioe) {
140 motdcontent = "<html>" + styles + "<body><h1>" +
141 "JOSM - " + tr("Java OpenStreetMap Editor") +
142 "</h1>\n<h2 align=\"center\">(" +
143 tr ("Message of the day not available") +
144 ")</h2>";
145 }
[1290]146
[1450]147 String languageCode = Main.getLanguageCodeU();
[1290]148
[1450]149 // Finds wiki links like (underscores inserted for readability):
150 // [wiki:LANGCODE:messageoftheday_CONDITON_REVISION LANGCODE]
151 // Langcode usually consists of two letters describing the language and may be omitted
152 // Condition may be one of the following: > < <= =>
153 // Revision is the JOSM version
154 Pattern versionPattern = Pattern.compile(
155 "\\[wiki:(?:[A-Z]+:)?MessageOfTheDay(\\>\\=|\\<\\=|\\<|\\>)([0-9]+)\\s*([A-Z]*)\\]",
156 Pattern.CASE_INSENSITIVE);
157 // 1=condition, 2=targetVersion, 3=lang
158 Matcher matcher = versionPattern.matcher(motdcontent);
159 matcher.reset();
[1359]160
[1450]161 ArrayList<String[]> links = new ArrayList<String[]>();
162 String linksList="";
163 while (matcher.find()) {
164 // Discards all but the selected locale and non-localized links
165 if(!(matcher.group(3)+":").equals(languageCode) && !matcher.group(3).equals(""))
166 continue;
[1359]167
[1450]168 links.add(new String[] {matcher.group(1), matcher.group(2), matcher.group(3)});
169 linksList += matcher.group(1)+matcher.group(2)+matcher.group(3)+": ";
170 }
[1290]171
[1450]172 // We cannot use Main.worker here because it's single-threaded and
173 // setting it to multi-threading will cause problems elsewhere
174 ExecutorService slave = Executors.newCachedThreadPool();
[1290]175
[1450]176 ArrayList<Future<String>> linkContents = new ArrayList<Future<String>>();
177 for(int i=0; i < links.size(); i++) {
178 String[] obj = links.get(i);
179 int targetVersion = Integer.parseInt(obj[1]);
180 String condition = obj[0];
181 Boolean isLocalized = !obj[2].equals("");
[1290]182
[1450]183 // Prefer localized over non-localized links, if they're otherwise the same
184 if(!isLocalized && linksList.indexOf(condition + obj[1] + languageCode + " ") >= 0)
185 continue;
[1290]186
[1450]187 boolean included = false;
[1359]188
[1450]189 if(myVersion == 0)
190 included = true;
191 else if(condition.equals(">="))
192 included=myVersion >= targetVersion;
193 else if(condition.equals(">"))
194 included = myVersion > targetVersion;
195 else if(condition.equals("<"))
196 included=myVersion < targetVersion;
197 else
198 included = myVersion <= targetVersion;
[1359]199
[1450]200 if(!included) continue;
201
202 boolean isHelp = targetVersion == 1;
203 String urlStart = baseurl + "/wiki/";
204 String urlEnd = "MessageOfTheDay" + condition + targetVersion
205 + (isHelp ? "" : "?format=txt");
206 String urlLoc = urlStart + languageCode + urlEnd;
207 String urlIntl = urlStart + urlEnd;
208
209 // This adds all links to the worker which will download them concurrently
210 linkContents.add(slave.submit(new readMOTD(isLocalized, baseurl, urlLoc, urlIntl, isHelp)));
211 }
212 // Gets newest version numbers
213 linkContents.add(slave.submit(new readMOTD(false, baseurl, "",
214 baseurl + "/version?format=txt", true)));
215
216 for(int i=0; i < linkContents.size()-1; i++) {
217 try {
218 motd += linkContents.get(i).get();
219 } catch (Exception e) {}
220 }
221
222 motd = "<html>"
223 + styles
224 + "<h1>JOSM - "
225 + tr("Java OpenStreetMap Editor")
226 + "</h1>"
227 + motd.replace("</html>", "")
228 + getVersionNumber(linkContents.get(linkContents.size()-1))
229 + "</html>";
230
231 linkContents.clear();
232 try {
233 slave.shutdown();
234 } catch(SecurityException x) {}
235
236 // Save this to prefs in case JOSM is updated so MOTD can be refreshed
237 Main.pref.putInteger("cache.motd.html.version", myVersion);
238
239 return motd.getBytes();
[1350]240 }
[1359]241
[1450]242 /**
243 * Additionally check if JOSM has been updated and refresh MOTD
244 */
245 @Override
246 protected boolean isCacheValid() {
247 // We assume a default of myVersion because it only kicks in in two cases:
248 // 1. Not yet written - but so isn't the interval variable, so it gets updated anyway
249 // 2. Cannot be written (e.g. while developing). Obviously we don't want to update
250 // everytime because of something we can't read.
251 return Main.pref.getInteger("cache.motd.html.version", myVersion) == myVersion;
252 }
253
254 /**
255 * Tries to read the version number from a given Future<String>
256 * @param Future<String> that contains the version page
257 * @return String with HTML Code
258 */
259 private String getVersionNumber(Future<String> linkContent) {
[1290]260 try {
[1450]261 String str = linkContent.get();
262 Matcher m = Pattern.compile(".*josm-tested\\.jar: *(\\d+).*", Pattern.DOTALL).matcher(str);
263 m.matches();
264 int curVersion = Integer.parseInt(m.group(1));
265 m = Pattern.compile(".*josm-latest\\.jar: *(\\d+).*", Pattern.DOTALL).matcher(str);
266 m.matches();
267 int latest = Integer.parseInt(m.group(1));
268 return "<div style=\"text-align:right;font-size:small;font-weight:normal;\">"
269 + "<b>"
270 + (curVersion > myVersion ? tr("Update available") + " &#151; ": "")
271 + tr("Version Details:") + "</b> "
272 + tr("Yours: {2}; Current: {0}; <font style=\"font-size:x-small\">"
273 + "(latest untested: {1} &#150; not recommended)</font>",
274 curVersion, latest, myVersion)
275 + "</div>";
276 } catch(Exception e) {e.printStackTrace();}
277
278 return "";
[652]279 }
[608]280 }
[1169]281
[1450]282 /**
283 * Initializes getting the MOTD as well as enabling the FileDrop Listener.
284 * Displays a message while the MOTD is downloading.
285 */
[652]286 public GettingStarted() {
287 super(new BorderLayout());
[1356]288 final LinkGeneral lg = new LinkGeneral(
289 "<html>" +
290 styles +
291 "<h1>" +
292 "JOSM - " +
293 tr("Java OpenStreetMap Editor") +
294 "</h1><h2 align=\"center\">" +
295 tr("Downloading \"Message of the day\"") +
296 "</h2>");
[1350]297 JScrollPane scroller = new JScrollPane(lg);
[800]298 scroller.setViewportBorder(new EmptyBorder(10,100,10,100));
[652]299 add(scroller, BorderLayout.CENTER);
[1231]300
[1350]301 // Asynchronously get MOTD to speed-up JOSM startup
302 Thread t = new Thread(new Runnable() {
303 public void run() {
[1450]304 if (content.length() == 0 && Main.pref.getBoolean("help.displaymotd", true))
305 content = new assignContent().updateIfRequiredString();
306
[1350]307 EventQueue.invokeLater(new Runnable() {
308 public void run() {
309 lg.setText(content);
[1370]310 //lg.moveCaretPosition(0);
[1350]311 }
312 });
313 }
314 }, "MOTD-Loader");
315 t.setDaemon(true);
316 t.start();
317
[1370]318 new FileDrop(scroller);
[652]319 }
[608]320}
Note: See TracBrowser for help on using the repository browser.