001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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 https://www.gnu.org/licenses/. 027 */ 028 029package edu.wisc.ssec.mcidasv; 030 031 032import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.cast; 033 034import java.io.BufferedReader; 035import java.io.BufferedWriter; 036import java.io.File; 037import java.io.FileReader; 038import java.io.FileWriter; 039 040import java.util.ArrayList; 041import java.util.Hashtable; 042import java.util.List; 043import java.util.Map; 044import java.util.Objects; 045import java.util.Properties; 046 047import java.awt.event.ActionEvent; 048 049import javax.swing.JEditorPane; 050import javax.swing.JLabel; 051import javax.swing.JOptionPane; 052import javax.swing.JPanel; 053import javax.swing.event.HyperlinkEvent; 054import javax.swing.event.HyperlinkListener; 055 056import ucar.unidata.idv.ControlDescriptor; 057import ucar.unidata.idv.IdvObjectStore; 058import ucar.unidata.idv.IntegratedDataViewer; 059import ucar.unidata.util.FileManager; 060import ucar.unidata.util.IOUtil; 061import ucar.unidata.util.LogUtil; 062import ucar.unidata.util.Misc; 063import ucar.unidata.util.StringUtil; 064 065import org.slf4j.Logger; 066import org.slf4j.LoggerFactory; 067 068import edu.wisc.ssec.mcidasv.startupmanager.StartupManager; 069import edu.wisc.ssec.mcidasv.util.SystemState; 070 071/** 072 * This class is used to initialize McIDAS-V. 073 * 074 * <p>The initialization process includes creating an 075 * {@literal "object store"} (for preferences), user-modifiable settings, 076 * and so on.</p> 077 * 078 * <p>McIDAS-V uses this class to perform pretty much all version-check 079 * operations.</p> 080 */ 081public class StateManager extends ucar.unidata.idv.StateManager 082 implements Constants, HyperlinkListener 083{ 084 /** Logging object. */ 085 private static final Logger logger = 086 LoggerFactory.getLogger(StateManager.class); 087 088 /** Error message shown when given userpath cannot be used. */ 089 public static final String USERPATH_IS_BAD_MESSAGE = 090 "<html>McIDAS-V is unable to create or write to the local user's " + 091 "directory.<br>Please select a directory.</html>"; 092 093 /** Message shown when asking the user to select a userpath. */ 094 public static final String USERPATH_PICK = 095 "Please select a directory to use as the McIDAS-V user path."; 096 097 /** 098 * Lazily-loaded VisAD build date. Value may be {@code null}. 099 * 100 * @see #getVisadDate() 101 */ 102 private String visadDate; 103 104 /** 105 * Lazily-loaded VisAD revision number. Value may be {@code null}. 106 * 107 * @see #getVisadVersion() 108 */ 109 private String visadVersion; 110 111 /** 112 * Lazily-loaded {@code ncIdv.jar} build timestamp. Value may be 113 * {@code null}. 114 * 115 * @see #getNetcdfDate() 116 */ 117 private String netcdfDate; 118 119 /** 120 * Lazily-loaded {@code ncIdv.jar} version. Value may be {@code null}. 121 * 122 * @see #getNetcdfVersion() 123 */ 124 private String netcdfVersion; 125 126 /** 127 * Lazily-loaded {@code mcidasv.jar} version. Value may be {@code null}. 128 * 129 * @see #getMcIdasVersion() 130 */ 131 private String version; 132 133 public StateManager(IntegratedDataViewer idv) { 134 super(idv); 135 } 136 137 /** 138 * Override to set the right user directory. 139 * 140 * @return Newly created object store. 141 */ 142 @Override protected IdvObjectStore doMakeObjectStore() { 143 IdvObjectStore store = new IdvObjectStore(getIdv(), 144 getStoreSystemName(), getStoreName(), 145 getIdv().getEncoderForRead(), 146 StartupManager.getInstance().getPlatform().getUserDirectory()); 147 initObjectStore(store); 148 return store; 149 } 150 151 /** 152 * Initialize the given object store. This mostly initializes the user's 153 * {@literal "userpath"} directory when it is first created. 154 * 155 * @param store Object store to initialize. Cannot be {@code null}. 156 */ 157 @Override protected void initObjectStore(IdvObjectStore store) { 158 while (!store.userDirectoryOk()) { 159 LogUtil.userMessage(USERPATH_IS_BAD_MESSAGE); 160 File dir = FileManager.getDirectory(null, USERPATH_PICK); 161 if (dir != null) { 162 store.setOverrideDirectory(dir); 163 } else { 164 // TODO(jon): figure out why we aren't using regular exit stuff 165 System.exit(0); 166 } 167 } 168 169 if (store.getMadeUserDirectory()) { 170 initNewUserDirectory(store.getUserDirectory()); 171 } 172 initUserDirectory(store.getUserDirectory()); 173 } 174 175 /** 176 * Initialize the McIDAS-V user directory (if it is not already 177 * initalized). 178 * 179 * <p>Here, initialization means {@literal "the user directory exists, 180 * and contains a barebones version of mcidasv.rbi"}.</p> 181 * 182 * @param directory McIDAS-V user directory. Cannot be {@code null}. 183 */ 184 @Override protected void initUserDirectory(File directory) { 185 File idvRbi = new File(IOUtil.joinDir(directory, "idv.rbi")); 186 if (idvRbi.exists()) { 187 if (!idvRbi.delete()) { 188 logger.warn("Could not delete '"+idvRbi+'\''); 189 } 190 } 191 File rbiFile = new File(IOUtil.joinDir(directory, "mcidasv.rbi")); 192 if (!rbiFile.exists()) { 193 String defaultRbi = 194 IOUtil.readContents( 195 "/edu/wisc/ssec/mcidasv/resources/userrbi.rbi", 196 (String)null); 197 if (defaultRbi != null) { 198 try { 199 IOUtil.writeFile(rbiFile, defaultRbi); 200 } catch (Exception exc) { 201 logException("Writing default rbi", exc); 202 } 203 } 204 } 205 } 206 207 @Override protected void initState(boolean interactiveMode) { 208 super.initState(interactiveMode); 209 210 // At this point in the startup process, McV has read and initialized 211 // the resources specified in mcidasv.rbi. filtering out the disabled 212 // controls here allows us to do the work once and have it apply to 213 // the rest of the session. 214 removeDisabledControlDescriptors(); 215 } 216 217 /** 218 * Removes disabled {@link ControlDescriptor ControlDescriptors} from 219 * {@link IntegratedDataViewer IntegratedDataViewer's} 220 * {@code controlDescriptors} and {@code controlDescriptorMap} fields. 221 */ 222 private void removeDisabledControlDescriptors() { 223 McIDASV mcv = (McIDASV)getIdv(); 224 Map<String, ControlDescriptor> cdMap = mcv.getControlDescriptorMap(); 225 List<ControlDescriptor> cds = cast(mcv.getAllControlDescriptors()); 226 // copy is soley for iterating over (avoid concurrent modification probs) 227 List<ControlDescriptor> copy = new ArrayList<>(cds); 228 for (ControlDescriptor c : copy) { 229 Hashtable<String, String> props = cast(c.getProperties()); 230 String v = props.getOrDefault("disabled", "false"); 231 if (Objects.equals(v, "true")) { 232 cdMap.remove(c.getControlId()); 233 cds.remove(c); 234 } 235 } 236 } 237 238 /** 239 * Handle a change to a link. 240 * 241 * @param e Link event. Cannot be {@code null}. 242 */ 243 @Override public void hyperlinkUpdate(HyperlinkEvent e) { 244 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { 245 if (e.getURL() == null) { 246 click(e.getDescription()); 247 } else { 248 click(e.getURL().toString()); 249 } 250 } 251 } 252 253 /** 254 * Handle a click on a link. 255 * 256 * @param url Link to visit. 257 */ 258 public void click(String url) { 259 getIdv().actionPerformed(new ActionEvent(this, 0, url)); 260 } 261 262 /** 263 * Get the name of the current operating system (via 264 * {@literal "os.name"} system property). 265 * 266 * <p>Note: all space characters will be replaced with underscores.</p> 267 * 268 * @return Operating system name. 269 */ 270 public String getOSName() { 271 String os = System.getProperty("os.name"); 272 os = os.replaceAll(" ", "_"); 273 return os; 274 } 275 276 public String getMcIdasVersionAbout() { 277 if (version == null) { 278 getMcIdasVersion(); 279 } 280 281 String aboutText = (String)getProperty(Constants.PROP_ABOUTTEXT); 282 String versionAbout = IOUtil.readContents(aboutText, ""); 283 versionAbout = StringUtil.replace(versionAbout, MACRO_VERSION, version); 284 Properties props = Misc.readProperties( 285 (String) getProperty(Constants.PROP_VERSIONFILE), 286 null, 287 getClass() 288 ); 289 290 String value = getIdvVersion(); 291 versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_IDV_VERSION, value); 292 value = props.getProperty(PROP_COPYRIGHT_YEAR, ""); 293 versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_COPYRIGHT_YEAR, value); 294 value = props.getProperty(PROP_BUILD_DATE, "Unknown"); 295 versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_BUILDDATE, value); 296 versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_VISAD_VERSION, getVisadVersion()); 297 298 return versionAbout; 299 } 300 301 public String getMcIdasVersion() { 302 if (version != null) { 303 return version; 304 } 305 306 Properties props = new Properties(); 307 props = Misc.readProperties((String) getProperty(Constants.PROP_VERSIONFILE), null, getClass()); 308 String maj = props.getProperty(PROP_VERSION_MAJOR, "0"); 309 String min = props.getProperty(PROP_VERSION_MINOR, "0"); 310 String rel = props.getProperty(PROP_VERSION_RELEASE, ""); 311 312 version = maj.concat(".").concat(min).concat(rel); 313 314 return version; 315 } 316 317 /** 318 * Returns the current Jython version. 319 * 320 * @return Jython's version information. 321 */ 322 @Override public String getJythonVersion() { 323 return org.python.Version.PY_VERSION; 324 } 325 326 /** 327 * Get a property. 328 * 329 * @param name Name of the property. Cannot be {@code null}. 330 * 331 * @return Value associated with {@code name} or {@code null}. 332 */ 333 @Override public Object getProperty(final String name) { 334 Object value = null; 335 if (McIDASV.isMac()) { 336 value = getProperties().get("mac."+name); 337 } 338 if (value == null) { 339 value = getProperties().get(name); 340 } 341 if (value == null) { 342 String fixedName = StateManager.fixIds(name); 343 if (!name.equals(fixedName)) { 344 return getProperties().get(fixedName); 345 } 346 } 347 return value; 348 } 349 350 /** 351 * Find the value associated with the given ID by checking the 352 * {@literal "properties"}, and if nothing was found, check the preferences. 353 * 354 * @param name Property or preference ID. Cannot be {@code null}. 355 * 356 * @return Either the value associated with {@code name} or {@code null}. 357 */ 358 public Object getPropertyOrPreference(String name) { 359 Object o = getProperty(name); 360 if (o == null) { 361 o = getPreference(name); 362 } 363 return o; 364 } 365 366 /** 367 * Find the {@link String} value associated with the given ID by checking 368 * the {@literal "properties"}, and if nothing was found, check the 369 * preferences. 370 * 371 * @param name Property or preference ID. Cannot be {@code null}. 372 * @param dflt Value to return if there is no property or preference 373 * associated with {@code name} 374 * 375 * @return Either the value associated with {@code name} or {@code dflt}. 376 */ 377 public String getPropertyOrPreference(String name, String dflt) { 378 String value = dflt; 379 Object o = getPropertyOrPreference(name); 380 if (o != null) { 381 value = o.toString(); 382 } 383 return value; 384 } 385 386 /** 387 * Find the {@link Integer} value associated with the given ID by checking 388 * the {@literal "properties"}, and if nothing was found, check the 389 * preferences. 390 * 391 * @param name Property or preference ID. Cannot be {@code null}. 392 * @param dflt Value to return if there is no property or preference 393 * associated with {@code name} 394 * 395 * @return Either the value associated with {@code name} or {@code dflt}. 396 */ 397 public int getPropertyOrPreference(String name, int dflt) { 398 int value = dflt; 399 Object o = getPropertyOrPreference(name); 400 if (o != null) { 401 value = Integer.valueOf(o.toString()); 402 } 403 return value; 404 } 405 406 /** 407 * Find the {@link Double} value associated with the given ID by checking 408 * the {@literal "properties"}, and if nothing was found, check the 409 * preferences. 410 * 411 * @param name Property or preference ID. Cannot be {@code null}. 412 * @param dflt Value to return if there is no property or preference 413 * associated with {@code name} 414 * 415 * @return Either the value associated with {@code name} or {@code dflt}. 416 */ 417 public double getPropertyOrPreference(String name, double dflt) { 418 double value = dflt; 419 Object o = getPropertyOrPreference(name); 420 if (o != null) { 421 value = Double.valueOf(o.toString()); 422 } 423 return value; 424 } 425 426 /** 427 * Find the {@link Boolean} value associated with the given ID by checking 428 * the {@literal "properties"}, and if nothing was found, check the 429 * preferences. 430 * 431 * @param name Property or preference ID. Cannot be {@code null}. 432 * @param dflt Value to return if there is no property or preference 433 * associated with {@code name} 434 * 435 * @return Either the value associated with {@code name} or {@code dflt}. 436 */ 437 public boolean getPropertyOrPreference(String name, boolean dflt) { 438 boolean value = dflt; 439 Object o = getPropertyOrPreference(name); 440 if (o != null) { 441 value = Boolean.valueOf(o.toString()); 442 } 443 return value; 444 } 445 446 /** 447 * Returns information about the current version of McIDAS-V and the IDV, 448 * along with their respective build dates. 449 * 450 * @return {@code Hashtable} containing versioning information. 451 */ 452 public Hashtable<String, String> getVersionInfo() { 453 String versionFile = (String)getProperty(Constants.PROP_VERSIONFILE); 454 Properties props = 455 Misc.readProperties(versionFile, null, getClass()); 456 457 String mcvBuild = props.getProperty(PROP_BUILD_DATE, "Unknown"); 458 459 Hashtable<String, String> table = new Hashtable<>(); 460 table.put("mcv.version.general", getMcIdasVersion()); 461 table.put("mcv.version.build", mcvBuild); 462 table.put("idv.version.general", getVersion()); 463 table.put("idv.version.build", getBuildDate()); 464 table.put("visad.version.general", getVisadVersion()); 465 table.put("visad.version.build", getVisadDate()); 466 table.put("netcdf.version.general", getNetcdfVersion()); 467 table.put("netcdf.version.build", getNetcdfDate()); 468 return table; 469 } 470 471 /** 472 * Return the timestamp from when {@code ncIdv.jar} was created. 473 * 474 * @return {@code String} representation of the creation timestamp. 475 */ 476 public String getNetcdfDate() { 477 if (netcdfDate == null) { 478 Map<String, String> props = SystemState.queryNcidvBuildProperties(); 479 netcdfDate = props.get("buildDate"); 480 netcdfVersion = props.get("version"); 481 } 482 return netcdfDate; 483 } 484 485 /** 486 * Return the version information within {@code ncIdv.jar}. 487 * 488 * @return Version of {@code ncIdv.jar} shipped by McIDAS-V. 489 */ 490 public String getNetcdfVersion() { 491 if (netcdfVersion == null) { 492 Map<String, String> props = SystemState.queryNcidvBuildProperties(); 493 netcdfDate = props.get("buildDate"); 494 netcdfVersion = props.get("version"); 495 } 496 return netcdfVersion; 497 } 498 499 /** 500 * Return the timestamp from when visad.jar was created. 501 * 502 * @return {@code String} representation of the creation timestamp. 503 * Likely to change formatting over time. 504 */ 505 public String getVisadDate() { 506 if (visadDate == null) { 507 Map<String, String> props = SystemState.queryVisadBuildProperties(); 508 visadDate = props.get(Constants.PROP_VISAD_DATE); 509 visadVersion = props.get(Constants.PROP_VISAD_REVISION); 510 } 511 return visadDate; 512 } 513 514 /** 515 * Return the {@literal "version"} of VisAD. 516 * 517 * @return Currently returns whatever the SVN revision number was when 518 * visad.jar was built. 519 */ 520 public String getVisadVersion() { 521 if (visadVersion == null) { 522 Map<String, String> props = SystemState.queryVisadBuildProperties(); 523 visadDate = props.get(Constants.PROP_VISAD_DATE); 524 visadVersion = props.get(Constants.PROP_VISAD_REVISION); 525 } 526 return visadVersion; 527 } 528 529 public String getIdvVersion() { 530 return getVersion(); 531 } 532 533 /** 534 * Overridden to set default of McIDAS-V 535 */ 536 @Override public String getStoreSystemName() { 537 return StartupManager.getInstance().getPlatform().getUserDirectory(); 538 } 539 540 /** 541 * Overridden to get dir of the unnecessary second level directory. 542 */ 543 @Override public String getStoreName() { 544 return ""; 545 } 546 547 /** 548 * Connect to McIDAS-V website and look for latest stable version. 549 * 550 * @return Latest stable version. 551 */ 552 public String getMcIdasVersionStable() { 553 String offscreen = "0"; 554 if (getIdv().getArgsManager().getIsOffScreen()) { 555 offscreen = "1"; 556 } 557 558 String version = ""; 559 try { 560 version = IOUtil.readContents(Constants.HOMEPAGE_URL+"/"+Constants.VERSION_HANDLER_URL+"?v="+getMcIdasVersion()+"&os="+getOSName()+"&off="+offscreen, ""); 561 } catch (Exception e) { 562 logger.warn("Could not get latest McV stable version", e); 563 } 564 return version.trim(); 565 } 566 567 /** 568 * Connect to McIDAS-V website and look for latest pre-release version. 569 * 570 * @return Latest pre-release version. 571 */ 572 public String getMcIdasVersionPrerelease() { 573 String version = ""; 574 try { 575 String htmlList = IOUtil.readContents(Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL, ""); 576 String lines[] = htmlList.split("\n"); 577 for (int i=0; i<lines.length; i++) { 578 String line = lines[i].trim(); 579 if (line.matches(".*McIDAS-V_\\d+\\.\\d+.*")) { 580 line = line.substring(line.indexOf("McIDAS-V_")+9); 581 String aVersion = line.substring(0, line.indexOf("_")); 582 if (version.isEmpty()) { 583 version = aVersion; 584 } else { 585 int comp = compareVersions(version, aVersion); 586 if (comp > 0) { 587 version = aVersion; 588 } 589 } 590 } 591 } 592 } catch (Exception e) { 593 logger.warn("Could not get latest McV pre-release version", e); 594 } 595 return version.trim(); 596 } 597 598 /** 599 * Connect to McIDAS website and look for latest notice. 600 * 601 * @return Contents of notice. String may be empty. 602 */ 603 public String getNoticeLatest() { 604 String notice = ""; 605 try { 606 notice = IOUtil.readContents(Constants.HOMEPAGE_URL+"/"+Constants.NOTICE_URL+"?requesting="+getMcIdasVersion()+"&os="+getOSName(), ""); 607 } catch (Exception e) { 608 logger.warn("Could not get latest notice", e); 609 } 610 if (!notice.contains("<notice>")) { 611 notice = ""; 612 } 613 notice = notice.replaceAll("<[/?]notice>",""); 614 return notice.trim(); 615 } 616 617 /** 618 * Compare version strings. 619 * 620 * <p>The logic is as follows. 621 * <pre> 622 * 0: thisVersion and thatVersion are equal. 623 * <0: thisVersion is greater. 624 * >0: thatVersion is greater. 625 * </pre> 626 * 627 * @param thisVersion First version string to compare. 628 * @param thatVersion Second version string to compare. 629 * 630 * @return Value indicating which of {@code thisVersion} and 631 * {@code thatVersion} is {@literal "greater"}. 632 */ 633 public static int compareVersions(String thisVersion, String thatVersion) { 634 int thisInt = versionToInteger(thisVersion); 635 int thatInt = versionToInteger(thatVersion); 636 return thatInt - thisInt; 637 } 638 639 /** 640 * Turn version strings of the form {@code #.#(a#)}, where # is one or two 641 * digits, a is one of alpha or beta, and () is optional, into an integer 642 * value... (empty) > beta > alpha. 643 * 644 * @param version String representation of version number. 645 * 646 * @return Integer representation of {@code version}. 647 */ 648 public static int versionToInteger(String version) { 649 int value = 0; 650 int p; 651 String part; 652 Character one = null; 653 654 try { 655 // Major version 656 p = version.indexOf('.'); 657 if (p > 0) { 658 part = version.substring(0,p); 659 value += Integer.parseInt(part) * 1000000; 660 version = version.substring(p+1); 661 } 662 663 // Minor version 664 int minor = 0; 665 int i = 0; 666 for (i = 0; i < 2 && i < version.length(); i++) { 667 one = version.charAt(i); 668 if (Character.isDigit(one)) { 669 if (i > 0) { 670 minor *= 10; 671 } 672 minor += Character.digit(one, 10) * 10000; 673 } else { 674 break; 675 } 676 } 677 value += minor; 678 if (one != null) { 679 version = version.substring(i); 680 } 681 682 // Alpha/beta/update/release status 683 if (version.length() == 0) { 684 value += 300; 685 } else if (version.charAt(0) == 'b') { 686 value += 200; 687 } else if (version.charAt(0) == 'a') { 688 value += 100; 689 } else if (version.charAt(0) == 'u') { 690 value += 400; 691 } else if (version.charAt(0) == 'r') { 692 value += 400; 693 } 694 for (i = 0; i < version.length(); i++) { 695 one = version.charAt(i); 696 if (Character.isDigit(one)) { 697 break; 698 } 699 } 700 if (one != null) { 701 version = version.substring(i); 702 } 703 704 // Alpha/beta version 705 if (version.length() > 0) { 706 value += Integer.parseInt(version); 707 } 708 } catch (Exception e) { 709 710 } 711 return value; 712 } 713 714 public boolean getIsPrerelease() { 715 boolean isPrerelease = false; 716 String version = getMcIdasVersion(); 717 if (version.contains("a") || version.contains("b")) { 718 isPrerelease = true; 719 } 720 return isPrerelease; 721 } 722 723 public void checkForNewerVersion(boolean notifyDialog) { 724 checkForNewerVersionStable(notifyDialog); 725 if (getStore().get(Constants.PREF_PRERELEASE_CHECK, getIsPrerelease())) { 726 checkForNewerVersionPrerelease(notifyDialog); 727 } 728 } 729 730 public void checkForNewerVersionStable(boolean notifyDialog) { 731 732 // get the stable version from the website (for statistics recording) 733 String thatVersion = getMcIdasVersionStable(); 734 735 // shortcut the rest of the process if we are processing offscreen 736 if (getIdv().getArgsManager().getIsOffScreen()) { 737 return; 738 } 739 740 String thisVersion = getMcIdasVersion(); 741 String titleText = "Version Check"; 742 743 if (thisVersion.isEmpty() || thatVersion.isEmpty()) { 744 if (notifyDialog) { 745 JOptionPane.showMessageDialog(null, 746 "Version check failed", 747 titleText, 748 JOptionPane.WARNING_MESSAGE); 749 } 750 } else if (compareVersions(thisVersion, thatVersion) > 0) { 751 String labelText = "<html>Version <b>" + thatVersion + "</b> is available<br><br>"; 752 labelText += "Visit <a href=\"" + Constants.HOMEPAGE_URL + "\">"; 753 labelText += Constants.HOMEPAGE_URL + "</a> to download</html>"; 754 755 JPanel backgroundColorGetterPanel = new JPanel(); 756 JEditorPane messageText = new JEditorPane("text/html", labelText); 757 messageText.setBackground(backgroundColorGetterPanel.getBackground()); 758 messageText.setEditable(false); 759 messageText.addHyperlinkListener(this); 760 761 //JLabel message = new JLabel(labelText, JLabel.CENTER); 762 JOptionPane.showMessageDialog(null, 763 messageText, 764 titleText, 765 JOptionPane.INFORMATION_MESSAGE); 766 } else { 767 if (notifyDialog) { 768 String labelText = "<html>This version (<b>" + thisVersion + "</b>) is up to date</html>"; 769 JLabel message = new JLabel(labelText, JLabel.CENTER); 770 JOptionPane.showMessageDialog(null, 771 message, 772 titleText, 773 JOptionPane.INFORMATION_MESSAGE); 774 } 775 } 776 } 777 778 public void checkForNewerVersionPrerelease(boolean notifyDialog) { 779 780 // shortcut the rest of the process if we are processing offscreen 781 if (getIdv().getArgsManager().getIsOffScreen()) { 782 return; 783 } 784 785 String thisVersion = getMcIdasVersion(); 786 String thatVersion = getMcIdasVersionPrerelease(); 787 String titleText = "Prerelease Check"; 788 789 if (thisVersion.isEmpty() || thatVersion.isEmpty()) { 790 if (notifyDialog) { 791 JOptionPane.showMessageDialog( 792 null, "No prerelease version available", titleText, 793 JOptionPane.WARNING_MESSAGE); 794 } 795 } else if (compareVersions(thisVersion, thatVersion) > 0) { 796 String labelText = "<html>Prerelease <b>" + thatVersion + "</b> is available<br><br>"; 797 labelText += "Visit <a href=\"" + Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL + "\">"; 798 labelText += Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL + "</a> to download</html>"; 799 800 JPanel backgroundColorGetterPanel = new JPanel(); 801 JEditorPane messageText = new JEditorPane("text/html", labelText); 802 messageText.setBackground(backgroundColorGetterPanel.getBackground()); 803 messageText.setEditable(false); 804 messageText.addHyperlinkListener(this); 805 806 // JLabel message = new JLabel(labelText, JLabel.CENTER); 807 JOptionPane.showMessageDialog(null, 808 messageText, 809 titleText, 810 JOptionPane.INFORMATION_MESSAGE); 811 } else { 812 if (notifyDialog) { 813 String labelText = "<html>This version (<b>" + thisVersion + "</b>) is up to date</html>"; 814 JLabel message = new JLabel(labelText, JLabel.CENTER); 815 JOptionPane.showMessageDialog(null, 816 message, 817 titleText, 818 JOptionPane.INFORMATION_MESSAGE); 819 } 820 } 821 } 822 823 public void checkForNotice(boolean notifyDialog) { 824 825 // Shortcut this whole process if we are processing offscreen 826 if (getIdv().getArgsManager().getIsOffScreen()) { 827 return; 828 } 829 830 String thisNotice = getNoticeCached().trim(); 831 String thatNotice = getNoticeLatest().trim(); 832 String titleText = "New Notice"; 833 String labelText = thatNotice; 834 835 if (thatNotice.isEmpty()) { 836 setNoticeCached(thatNotice); 837 if (notifyDialog) { 838 titleText = "No Notice"; 839 JLabel message = new JLabel("There is no current notice", JLabel.CENTER); 840 JOptionPane.showMessageDialog(null, message, titleText, 841 JOptionPane.INFORMATION_MESSAGE); 842 } 843 } else if (!thisNotice.equals(thatNotice)) { 844 setNoticeCached(thatNotice); 845 846 JPanel backgroundColorGetterPanel = new JPanel(); 847 JEditorPane messageText = new JEditorPane("text/html", labelText); 848 messageText.setBackground(backgroundColorGetterPanel.getBackground()); 849 messageText.setEditable(false); 850 messageText.addHyperlinkListener(this); 851 JOptionPane.showMessageDialog(null, messageText, titleText, 852 JOptionPane.INFORMATION_MESSAGE); 853 } else { 854 if (notifyDialog) { 855 titleText = "Previous Notice"; 856 JPanel bgPanel = new JPanel(); 857 JEditorPane messageText = 858 new JEditorPane("text/html", labelText); 859 messageText.setBackground(bgPanel.getBackground()); 860 messageText.setEditable(false); 861 messageText.addHyperlinkListener(this); 862 JOptionPane.showMessageDialog(null, messageText, titleText, 863 JOptionPane.INFORMATION_MESSAGE); 864 } 865 } 866 } 867 868 /** 869 * Debug a McIDAS-V {@literal "system notice"} before sending it to all 870 * users! 871 * 872 * @param noticeContents Contents of the notice. 873 * @param notifyDialog if {@code true}, show notice even if already seen. 874 * @param disableCache Whether or not {@code noticeContents} will be cached. 875 */ 876 public void debugNotice(String noticeContents, boolean notifyDialog, 877 boolean disableCache) 878 { 879 // Shortcut this whole process if we are processing offscreen 880 if (getIdv().getArgsManager().getIsOffScreen()) { 881 return; 882 } 883 884 String thisNotice; 885 thisNotice = disableCache ? "" : getNoticeCached().trim(); 886 String thatNotice = noticeContents.trim(); 887 String labelText = thatNotice; 888 889 if (thatNotice.isEmpty()) { 890 if (!disableCache) { 891 setNoticeCached(thatNotice); 892 } 893 if (notifyDialog) { 894 String titleText = "No Notice"; 895 JLabel message = 896 new JLabel("There is no current notice", JLabel.CENTER); 897 JOptionPane.showMessageDialog(null, message, titleText, 898 JOptionPane.INFORMATION_MESSAGE); 899 } 900 } else if (!thisNotice.equals(thatNotice)) { 901 if (!disableCache) { 902 setNoticeCached(thatNotice); 903 } 904 String titleText = "New Notice"; 905 JPanel backgroundColorGetterPanel = new JPanel(); 906 JEditorPane messageText = new JEditorPane("text/html", labelText); 907 messageText.setBackground(backgroundColorGetterPanel.getBackground()); 908 messageText.setEditable(false); 909 messageText.addHyperlinkListener(this); 910 JOptionPane.showMessageDialog(null, messageText, titleText, 911 JOptionPane.INFORMATION_MESSAGE); 912 } else { 913 if (notifyDialog) { 914 String titleText = "Previous Notice"; 915 JPanel bgPanel = new JPanel(); 916 JEditorPane messageText = 917 new JEditorPane("text/html", labelText); 918 messageText.setBackground(bgPanel.getBackground()); 919 messageText.setEditable(false); 920 messageText.addHyperlinkListener(this); 921 JOptionPane.showMessageDialog(null, messageText, titleText, 922 JOptionPane.INFORMATION_MESSAGE); 923 } 924 } 925 } 926 927 private String getNoticePath() { 928 return StartupManager.getInstance().getPlatform().getUserFile("notice.txt"); 929 } 930 931 private String getNoticeCached() { 932 StringBuilder notice = new StringBuilder(1024); 933 try{ 934 FileReader fstream = new FileReader(getNoticePath()); 935 BufferedReader in = new BufferedReader(fstream); 936 String line; 937 while ((line = in.readLine()) != null) { 938 notice.append(line).append('\n'); 939 } 940 in.close(); 941 } catch (Exception e) { 942 logger.warn("Could not get cached notice", e); 943 } 944 return notice.toString(); 945 } 946 947 private void setNoticeCached(String notice) { 948 try { 949 FileWriter fstream = new FileWriter(getNoticePath()); 950 BufferedWriter out = new BufferedWriter(fstream); 951 out.write(notice); 952 out.close(); 953 } catch (Exception e) { 954 logger.warn("Could not cache downloaded notice", e); 955 } 956 } 957}