001 /*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2013
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 *
010 * All Rights Reserved
011 *
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.
014 *
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 *
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023 * GNU Lesser Public License for more details.
024 *
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program. If not, see http://www.gnu.org/licenses.
027 */
028
029 package edu.wisc.ssec.mcidasv;
030
031 import java.awt.event.ActionEvent;
032 import java.io.BufferedReader;
033 import java.io.BufferedWriter;
034 import java.io.FileReader;
035 import java.io.FileWriter;
036 import java.util.Hashtable;
037 import java.util.Map;
038 import java.util.Properties;
039
040 import javax.swing.JEditorPane;
041 import javax.swing.JLabel;
042 import javax.swing.JOptionPane;
043 import javax.swing.JPanel;
044 import javax.swing.event.HyperlinkEvent;
045 import javax.swing.event.HyperlinkListener;
046
047 import ucar.unidata.idv.IdvObjectStore;
048 import ucar.unidata.idv.IntegratedDataViewer;
049 import ucar.unidata.util.IOUtil;
050 import ucar.unidata.util.Misc;
051 import ucar.unidata.util.StringUtil;
052 import edu.wisc.ssec.mcidasv.startupmanager.StartupManager;
053 import edu.wisc.ssec.mcidasv.util.SystemState;
054
055 public class StateManager extends ucar.unidata.idv.StateManager implements Constants, HyperlinkListener {
056
057 /** Lazily-loaded VisAD build date. */
058 private String visadDate;
059
060 /** Lazily-loaded VisAD SVN revision number. */
061 private String visadVersion;
062
063 private String version;
064 private String versionAbout;
065
066 public StateManager(IntegratedDataViewer idv) {
067 super(idv);
068 }
069
070 /**
071 * Override to set the right user directory
072 */
073 protected IdvObjectStore doMakeObjectStore() {
074 IdvObjectStore store = new IdvObjectStore(getIdv(),
075 getStoreSystemName(), getStoreName(),
076 getIdv().getEncoderForRead(),
077 StartupManager.getInstance().getPlatform().getUserDirectory());
078 initObjectStore(store);
079 return store;
080 }
081
082 /**
083 * Handle a change to a link
084 *
085 * @param e the link's event
086 */
087 public void hyperlinkUpdate(HyperlinkEvent e) {
088 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
089 if (e.getURL() == null) {
090 click(e.getDescription());
091 } else {
092 click(e.getURL().toString());
093 }
094 }
095 }
096
097 /**
098 * Handle a click on a link
099 *
100 * @param url the link definition
101 */
102 public void click(String url) {
103 getIdv().actionPerformed(new ActionEvent(this, 0, url));
104 }
105
106 public String getOSName() {
107 String os = System.getProperty("os.name");
108 os = os.replaceAll(" ", "_");
109 return os;
110 }
111
112 public String getMcIdasVersionAbout() {
113 getMcIdasVersion();
114
115 versionAbout = IOUtil.readContents((String) getProperty(Constants.PROP_ABOUTTEXT), "");
116 versionAbout = StringUtil.replace(versionAbout, MACRO_VERSION, version);
117 Properties props = Misc.readProperties(
118 (String) getProperty(Constants.PROP_VERSIONFILE),
119 null,
120 getClass()
121 );
122
123 String value = getIdvVersion();
124 versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_IDV_VERSION, value);
125 value = props.getProperty(PROP_COPYRIGHT_YEAR, "");
126 versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_COPYRIGHT_YEAR, value);
127 value = props.getProperty(PROP_BUILD_DATE, "Unknown");
128 versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_BUILDDATE, value);
129 versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_VISAD_VERSION, getVisadVersion());
130
131 return versionAbout;
132 }
133
134 public String getMcIdasVersion() {
135 if (version != null) {
136 return version;
137 }
138
139 Properties props = new Properties();
140 props = Misc.readProperties((String) getProperty(Constants.PROP_VERSIONFILE), null, getClass());
141 String maj = props.getProperty(PROP_VERSION_MAJOR, "0");
142 String min = props.getProperty(PROP_VERSION_MINOR, "0");
143 String rel = props.getProperty(PROP_VERSION_RELEASE, "");
144
145 version = maj.concat(".").concat(min).concat(rel);
146
147 return version;
148 }
149
150 /**
151 * Returns the current Jython version.
152 *
153 * @return Jython's version information.
154 */
155 @Override public String getJythonVersion() {
156 return org.python.Version.PY_VERSION;
157 }
158
159 /**
160 * Get a property
161 *
162 * @param name name of the property
163 *
164 * @return the property or null
165 */
166 @Override public Object getProperty(final String name) {
167 Object value = null;
168 if (McIDASV.isMac()) {
169 value = getProperties().get("mac."+name);
170 }
171 if (value == null) {
172 value = getProperties().get(name);
173 }
174 if (value == null) {
175 String fixedName = StateManager.fixIds(name);
176 if (!name.equals(fixedName)) {
177 return getProperties().get(fixedName);
178 }
179 }
180 return value;
181 }
182
183 /**
184 * Returns information about the current version of McIDAS-V and the IDV,
185 * along with their respective build dates.
186 *
187 * @return Hashtable containing versioning information.
188 */
189 public Hashtable<String, String> getVersionInfo() {
190 Properties props = new Properties();
191 props = Misc.readProperties((String) getProperty(Constants.PROP_VERSIONFILE), null, getClass());
192
193 String mcvBuild = props.getProperty(PROP_BUILD_DATE, "Unknown");
194
195 Hashtable<String, String> table = new Hashtable<String, String>();
196 table.put("mcv.version.general", getMcIdasVersion());
197 table.put("mcv.version.build", mcvBuild);
198 table.put("idv.version.general", getVersion());
199 table.put("idv.version.build", getBuildDate());
200 table.put("visad.version.general", getVisadVersion());
201 table.put("visad.version.build", getVisadDate());
202 return table;
203 }
204
205 /**
206 * Return the timestamp from visad.jar was created.
207 *
208 * @return {@code String} representation of the creation timestamp. Likely to change formatting over time.
209 */
210 public String getVisadDate() {
211 if (visadDate == null) {
212 Map<String, String> props = SystemState.queryVisadBuildProperties();
213 visadDate = props.get(Constants.PROP_VISAD_DATE);
214 visadVersion = props.get(Constants.PROP_VISAD_REVISION);
215 }
216 return visadDate;
217 }
218
219 /**
220 * Return the {@literal "version"} of VisAD.
221 *
222 * @return Currently returns whatever the SVN revision number was when
223 * visad.jar was built.
224 */
225 public String getVisadVersion() {
226 if (visadVersion== null) {
227 Map<String, String> props = SystemState.queryVisadBuildProperties();
228 visadDate = props.get(Constants.PROP_VISAD_DATE);
229 visadVersion = props.get(Constants.PROP_VISAD_REVISION);
230 }
231 return visadVersion;
232 }
233
234 public String getIdvVersion() {
235 return getVersion();
236 }
237
238 /**
239 * Overridden to set default of McIDAS-V
240 */
241 public String getStoreSystemName() {
242 return StartupManager.getInstance().getPlatform().getUserDirectory();
243 }
244
245 /**
246 * Overridden to get dir of the unnecessary second level directory.
247 *
248 * @see ucar.unidata.idv.StateManager#getStoreName()
249 */
250 public String getStoreName() {
251 return "";
252 }
253
254 /**
255 * Connect to McIDAS website and look for latest stable version
256 */
257 public String getMcIdasVersionStable() {
258 String offscreen = "0";
259 if (super.getIdv().getArgsManager().getIsOffScreen()) {
260 offscreen = "1";
261 }
262
263 String version = "";
264 try {
265 version = IOUtil.readContents(Constants.HOMEPAGE_URL+"/"+Constants.VERSION_HANDLER_URL+"?v="+getMcIdasVersion()+"&os="+getOSName()+"&off="+offscreen, "");
266 } catch (Exception e) {}
267 return version.trim();
268 }
269
270 /**
271 * Connect to McIDAS website and look for latest prerelease version
272 */
273 public String getMcIdasVersionPrerelease() {
274 String version = "";
275 try {
276 String htmlList = IOUtil.readContents(Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL, "");
277 String lines[] = htmlList.split("\n");
278 for (int i=0; i<lines.length; i++) {
279 String line = lines[i].trim();
280 if (line.matches(".*McIDAS-V_\\d+\\.\\d+.*")) {
281 line = line.substring(line.indexOf("McIDAS-V_")+9);
282 String aVersion = line.substring(0, line.indexOf("_"));
283 if (version == "") {
284 version = aVersion;
285 }
286 else {
287 int comp = compareVersions(version, aVersion);
288 if (comp > 0) {
289 version = aVersion;
290 }
291 }
292 }
293 }
294 } catch (Exception e) {}
295 return version.trim();
296 }
297
298 /**
299 * Connect to McIDAS website and look for latest notice
300 */
301 public String getNoticeLatest() {
302 String notice = "";
303 try {
304 notice = IOUtil.readContents(Constants.HOMEPAGE_URL+"/"+Constants.NOTICE_URL+"?requesting="+getMcIdasVersion()+"&os="+getOSName(), "");
305 } catch (Exception e) {}
306 if (notice.indexOf("<notice>")<0) notice="";
307 notice = notice.replaceAll("<[/?]notice>","");
308 return notice.trim();
309 }
310
311 /**
312 * Compare version strings
313 * 0: equal
314 * <0: this version is greater
315 * >0: that version is greater
316 */
317 private int compareVersions(String thisVersion, String thatVersion) {
318 int thisInt = versionToInteger(thisVersion);
319 int thatInt = versionToInteger(thatVersion);
320 return (thatInt - thisInt);
321 }
322
323 /**
324 * Turn version strings of the form #.#(a#)
325 * where # is one or two digits, a is one of alpha or beta, and () is optional
326 * Into an integer... (empty) > beta > alpha
327 */
328 private int versionToInteger(String version) {
329 int value = 0;
330 int p;
331 String part;
332 Character one = null;
333
334 try {
335
336 // Major version
337 p = version.indexOf('.');
338 if (p > 0) {
339 part = version.substring(0,p);
340 value += Integer.parseInt(part) * 1000000;
341 version = version.substring(p+1);
342 }
343
344 // Minor version
345 int minor = 0;
346 int i=0;
347 for (i=0; i<2 && i<version.length(); i++) {
348 one = version.charAt(i);
349 if (Character.isDigit(one)) {
350 if (i>0) minor *= 10;
351 minor += Character.digit(one, 10) * 10000;
352 }
353 else {
354 break;
355 }
356 }
357 value += minor;
358 if (one!=null) version = version.substring(i);
359
360 // Alpha/beta/update/release status
361 if (version.length() == 0) value += 300;
362 else if (version.charAt(0) == 'b') value += 200;
363 else if (version.charAt(0) == 'a') value += 100;
364 else if (version.charAt(0) == 'u') value += 400;
365 else if (version.charAt(0) == 'r') value += 400;
366 for (i=0; i<version.length(); i++) {
367 one = version.charAt(i);
368 if (Character.isDigit(one)) break;
369 }
370 if (one!=null) version = version.substring(i);
371
372 // Alpha/beta version
373 if (version.length() > 0)
374 value += Integer.parseInt(version);
375
376 } catch (Exception e) {}
377
378 return value;
379 }
380
381 public boolean getIsPrerelease() {
382 boolean isPrerelease = false;
383 String version = getMcIdasVersion();
384 if (version.indexOf("a") >= 0 || version.indexOf("b") >= 0) {
385 isPrerelease = true;
386 }
387 return isPrerelease;
388 }
389
390 public void checkForNewerVersion(boolean notifyDialog) {
391 checkForNewerVersionStable(notifyDialog);
392 if (getStore().get(Constants.PREF_PRERELEASE_CHECK, getIsPrerelease())) {
393 checkForNewerVersionPrerelease(notifyDialog);
394 }
395 }
396
397 public void checkForNewerVersionStable(boolean notifyDialog) {
398
399 /** Get the stable version from the website (for statistics recording) */
400 String thatVersion = getMcIdasVersionStable();
401
402 /** Shortcut the rest of the process if we are processing offscreen */
403 if (super.getIdv().getArgsManager().getIsOffScreen()) {
404 return;
405 }
406
407 String thisVersion = getMcIdasVersion();
408 String titleText = "Version Check";
409
410 if (thisVersion.equals("") || thatVersion.equals("")) {
411 if (notifyDialog) {
412 JOptionPane.showMessageDialog(null, "Version check failed", titleText,
413 JOptionPane.WARNING_MESSAGE);
414 }
415 }
416 else if (compareVersions(thisVersion, thatVersion) > 0) {
417 String labelText = "<html>Version <b>" + thatVersion + "</b> is available<br><br>";
418 labelText += "Visit <a href=\"" + Constants.HOMEPAGE_URL + "\">";
419 labelText += Constants.HOMEPAGE_URL + "</a> to download</html>";
420
421 JPanel backgroundColorGetterPanel = new JPanel();
422 JEditorPane messageText = new JEditorPane("text/html", labelText);
423 messageText.setBackground(backgroundColorGetterPanel.getBackground());
424 messageText.setEditable(false);
425 messageText.addHyperlinkListener(this);
426
427 // JLabel message = new JLabel(labelText, JLabel.CENTER);
428 JOptionPane.showMessageDialog(null, messageText, titleText,
429 JOptionPane.INFORMATION_MESSAGE);
430 }
431 else {
432 if (notifyDialog) {
433 String labelText = "<html>This version (<b>" + thisVersion + "</b>) is up to date</html>";
434 JLabel message = new JLabel(labelText, JLabel.CENTER);
435 JOptionPane.showMessageDialog(null, message, titleText,
436 JOptionPane.INFORMATION_MESSAGE);
437 }
438 }
439
440 }
441
442 public void checkForNewerVersionPrerelease(boolean notifyDialog) {
443
444 /** Shortcut the rest of the process if we are processing offscreen */
445 if (super.getIdv().getArgsManager().getIsOffScreen()) {
446 return;
447 }
448
449 String thisVersion = getMcIdasVersion();
450 String thatVersion = getMcIdasVersionPrerelease();
451 String titleText = "Prerelease Check";
452
453 if (thisVersion.equals("") || thatVersion.equals("")) {
454 if (notifyDialog) {
455 JOptionPane.showMessageDialog(null, "No prerelease version available", titleText,
456 JOptionPane.WARNING_MESSAGE);
457 }
458 }
459 else if (compareVersions(thisVersion, thatVersion) > 0) {
460 String labelText = "<html>Prerelease <b>" + thatVersion + "</b> is available<br><br>";
461 labelText += "Visit <a href=\"" + Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL + "\">";
462 labelText += Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL + "</a> to download</html>";
463
464 JPanel backgroundColorGetterPanel = new JPanel();
465 JEditorPane messageText = new JEditorPane("text/html", labelText);
466 messageText.setBackground(backgroundColorGetterPanel.getBackground());
467 messageText.setEditable(false);
468 messageText.addHyperlinkListener(this);
469
470 // JLabel message = new JLabel(labelText, JLabel.CENTER);
471 JOptionPane.showMessageDialog(null, messageText, titleText,
472 JOptionPane.INFORMATION_MESSAGE);
473 }
474 else {
475 if (notifyDialog) {
476 String labelText = "<html>This version (<b>" + thisVersion + "</b>) is up to date</html>";
477 JLabel message = new JLabel(labelText, JLabel.CENTER);
478 JOptionPane.showMessageDialog(null, message, titleText,
479 JOptionPane.INFORMATION_MESSAGE);
480 }
481 }
482
483 }
484
485 public void checkForNotice(boolean notifyDialog) {
486
487 /** Shortcut this whole process if we are processing offscreen */
488 if (super.getIdv().getArgsManager().getIsOffScreen())
489 return;
490
491 String thisNotice = getNoticeCached().trim();
492 String thatNotice = getNoticeLatest().trim();
493 String titleText = "New Notice";
494 String labelText = thatNotice;
495
496 if (thatNotice.equals("")) {
497 setNoticeCached(thatNotice);
498 if (notifyDialog) {
499 titleText = "No Notice";
500 JLabel message = new JLabel("There is no current notice", JLabel.CENTER);
501 JOptionPane.showMessageDialog(null, message, titleText,
502 JOptionPane.INFORMATION_MESSAGE);
503 }
504 return;
505 }
506 else if (!thisNotice.equals(thatNotice)) {
507 setNoticeCached(thatNotice);
508
509 JPanel backgroundColorGetterPanel = new JPanel();
510 JEditorPane messageText = new JEditorPane("text/html", labelText);
511 messageText.setBackground(backgroundColorGetterPanel.getBackground());
512 messageText.setEditable(false);
513 messageText.addHyperlinkListener(this);
514
515 // JLabel message = new JLabel(labelText, JLabel.CENTER);
516 JOptionPane.showMessageDialog(null, messageText, titleText,
517 JOptionPane.INFORMATION_MESSAGE);
518 }
519 else {
520 if (notifyDialog) {
521 titleText = "Previous Notice";
522 JLabel message = new JLabel(labelText, JLabel.CENTER);
523 JOptionPane.showMessageDialog(null, message, titleText,
524 JOptionPane.INFORMATION_MESSAGE);
525 }
526 }
527
528 }
529
530 private String getNoticePath() {
531 return StartupManager.getInstance().getPlatform().getUserFile("notice.txt");
532 }
533
534 private String getNoticeCached() {
535 String notice = "";
536 try{
537 FileReader fstream = new FileReader(getNoticePath());
538 BufferedReader in = new BufferedReader(fstream);
539 String line;
540 while ((line = in.readLine()) != null) {
541 notice += line + '\n';
542 }
543 in.close();
544 } catch (Exception e){
545 System.err.println("Error: " + e.getMessage());
546 }
547 return notice;
548 }
549
550 private void setNoticeCached(String notice) {
551 try{
552 FileWriter fstream = new FileWriter(getNoticePath());
553 BufferedWriter out = new BufferedWriter(fstream);
554 out.write(notice);
555 out.close();
556 } catch (Exception e){
557 System.err.println("Error: " + e.getMessage());
558 }
559 }
560
561 }