001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2018 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 029package edu.wisc.ssec.mcidasv.startupmanager; 030 031import static edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.EMPTY_STRING; 032import static edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster.SET_PREFIX; 033 034import java.awt.BorderLayout; 035import java.awt.Color; 036import java.awt.Component; 037import java.awt.Container; 038import java.awt.Dimension; 039import java.awt.FlowLayout; 040import java.awt.Graphics; 041import java.awt.Graphics2D; 042import java.awt.RenderingHints; 043import java.awt.event.ActionEvent; 044import java.awt.event.ActionListener; 045import java.io.BufferedReader; 046import java.io.File; 047import java.io.FileInputStream; 048import java.io.FileOutputStream; 049import java.io.FileReader; 050import java.io.IOException; 051import java.io.InputStream; 052import java.io.OutputStream; 053import java.util.HashMap; 054import java.util.List; 055import java.util.Map; 056import java.util.Objects; 057import java.util.Properties; 058 059import javax.swing.BorderFactory; 060import javax.swing.DefaultListCellRenderer; 061import javax.swing.DefaultListModel; 062import javax.swing.GroupLayout; 063import javax.swing.ImageIcon; 064import javax.swing.JButton; 065import javax.swing.JCheckBox; 066import javax.swing.JComboBox; 067import javax.swing.JComponent; 068import javax.swing.JFrame; 069import javax.swing.JLabel; 070import javax.swing.JList; 071import javax.swing.JPanel; 072import javax.swing.JScrollPane; 073import javax.swing.JSplitPane; 074import javax.swing.JTextField; 075import javax.swing.JTree; 076import javax.swing.LayoutStyle; 077import javax.swing.ListModel; 078import javax.swing.ListSelectionModel; 079import javax.swing.SwingConstants; 080import javax.swing.WindowConstants; 081import javax.swing.border.EmptyBorder; 082import javax.swing.tree.DefaultMutableTreeNode; 083import javax.swing.tree.DefaultTreeCellRenderer; 084 085import edu.wisc.ssec.mcidasv.startupmanager.options.FileOption; 086import edu.wisc.ssec.mcidasv.util.GetMem; 087import ucar.unidata.ui.Help; 088import ucar.unidata.util.GuiUtils; 089import ucar.unidata.util.LogUtil; 090import ucar.unidata.util.StringUtil; 091import edu.wisc.ssec.mcidasv.ArgumentManager; 092import edu.wisc.ssec.mcidasv.Constants; 093import edu.wisc.ssec.mcidasv.startupmanager.options.BooleanOption; 094import edu.wisc.ssec.mcidasv.startupmanager.options.LoggerLevelOption; 095import edu.wisc.ssec.mcidasv.startupmanager.options.MemoryOption; 096import edu.wisc.ssec.mcidasv.startupmanager.options.OptionMaster; 097import edu.wisc.ssec.mcidasv.startupmanager.options.TextOption; 098import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 099 100/** 101 * Manages the McIDAS-V startup options in a context that is completely free 102 * from the traditional IDV/McIDAS-V overhead. 103 */ 104public class StartupManager implements edu.wisc.ssec.mcidasv.Constants { 105 106 // TODO(jon): replace 107 public static final String[][] PREF_PANELS = { 108 { Constants.PREF_LIST_GENERAL, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/mcidasv-round32.png" }, 109 { Constants.PREF_LIST_VIEW, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/tab-new32.png" }, 110 { Constants.PREF_LIST_TOOLBAR, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/application-x-executable32.png" }, 111 { Constants.PREF_LIST_DATA_CHOOSERS, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/preferences-desktop-remote-desktop32.png" }, 112 { Constants.PREF_LIST_ADDE_SERVERS, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/applications-internet32.png" }, 113 { Constants.PREF_LIST_AVAILABLE_DISPLAYS, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/video-display32.png" }, 114 { Constants.PREF_LIST_NAV_CONTROLS, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/input-mouse32.png" }, 115 { Constants.PREF_LIST_FORMATS_DATA,"/edu/wisc/ssec/mcidasv/resources/icons/prefs/preferences-desktop-theme32.png" }, 116 { Constants.PREF_LIST_ADVANCED, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/applications-internet32.png" }, 117 }; 118 119 // TODO(jon): replace 120 public static final Object[][] RENDER_HINTS = { 121 { RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON }, 122 { RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY }, 123 { RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON }, 124 }; 125 126 /** usage message */ 127 public static final String USAGE_MESSAGE = 128 "Usage: runMcV-Prefs <args>"; 129 130 /** Path to the McIDAS-V help set within {@literal mcv_userguide.jar}. */ 131 private static final String HELP_PATH = "/docs/userguide"; 132 133 /** ID of the startup prefs help page. */ 134 private static final String HELP_TARGET = "idv.tools.preferences.advancedpreferences"; 135 136 /** The type of platform as reported by {@link #determinePlatform()}. */ 137 private final Platform platform = determinePlatform(); 138 139 /** Cached copy of the application rendering hints. */ 140 public static final RenderingHints HINTS = getRenderingHints(); 141 142 /** Contains the list of the different preference panels. */ 143 private final JList panelList = new JList(new DefaultListModel()); 144 145 /** Panel containing the startup options. */ 146 private JPanel ADVANCED_PANEL; 147 148 /** 149 * Panel to use for all other preference panels while running startup 150 * manager. 151 */ 152 private JPanel BAD_CHOICE_PANEL; 153 154 /** Contains the various buttons (Apply, Ok, Help, Cancel). */ 155 private JPanel COMMAND_ROW_PANEL; 156 157 private static StartupManager instance; 158 159 private StartupManager() { 160 161 } 162 163 public static StartupManager getInstance() { 164 if (instance == null) { 165 instance = new StartupManager(); 166 } 167 return instance; 168 } 169 170 /** 171 * Creates and returns the rendering hints for the GUI. 172 * Built from {@link #RENDER_HINTS} 173 * 174 * @return Hints to use when displaying the GUI. 175 */ 176 public static RenderingHints getRenderingHints() { 177 RenderingHints hints = new RenderingHints(null); 178 for (int i = 0; i < RENDER_HINTS.length; i++) 179 hints.put(RENDER_HINTS[i][0], RENDER_HINTS[i][1]); 180 return hints; 181 } 182 183 /** 184 * Figures out the type of platform. Queries the {@literal "os.name"} 185 * system property to determine the platform type. 186 * 187 * @return {@link Platform#UNIXLIKE} or {@link Platform#WINDOWS}. 188 */ 189 private Platform determinePlatform() { 190 String os = System.getProperty("os.name"); 191 if (os == null) { 192 throw new RuntimeException(); 193 } 194 return os.startsWith("Windows") ? Platform.WINDOWS : Platform.UNIXLIKE; 195 } 196 197 /** 198 * Returns either {@link Platform#UNIXLIKE} or 199 * {@link Platform#WINDOWS}. 200 * 201 * @return The platform as determined by {@link #determinePlatform()}. 202 */ 203 public Platform getPlatform() { 204 return platform; 205 } 206 207 /** 208 * Saves the changes to the preferences and quits. Unlike the other button 209 * handling methods, this one is public. This was done so that the advanced 210 * preferences (within McIDAS-V) can force an update to the startup prefs. 211 */ 212 public void handleApply() { 213 OptionMaster.getInstance().writeStartup(); 214 } 215 216 /** 217 * Saves the preference changes. 218 */ 219 protected void handleOk() { 220 OptionMaster.getInstance().writeStartup(); 221 System.exit(0); 222 } 223 224 /** 225 * Shows the startup preferences help page. 226 */ 227 protected void handleHelp() { 228 Help.setTopDir(HELP_PATH); 229 Help.getDefaultHelp().gotoTarget(HELP_TARGET); 230 } 231 232 /** 233 * Simply quits the program. 234 */ 235 protected void handleCancel() { 236 System.exit(0); 237 } 238 239 /** 240 * Returns the preferences panel that corresponds with the user's 241 * {@code JList} selection. 242 * 243 * <p>In the context of the startup manager, this means that any 244 * {@code JList} selection <i>other than</i> {@literal "Advanced"} will 245 * return the results of {@link #getUnavailablePanel()}. Otherwise the 246 * results of {@link #getAdvancedPanel(boolean)} will be returned. 247 * 248 * @return Either the advanced preferences panel or an 249 * {@literal "unavailable"}, depending upon the user's selection. 250 */ 251 private Container getSelectedPanel() { 252 ListModel listModel = panelList.getModel(); 253 int index = panelList.getSelectedIndex(); 254 if (index == -1) { 255 return getAdvancedPanel(true); 256 } 257 String key = ((JLabel)listModel.getElementAt(index)).getText(); 258 if (!Constants.PREF_LIST_ADVANCED.equals(key)) { 259 return getUnavailablePanel(); 260 } 261 return getAdvancedPanel(true); 262 } 263 264 /** 265 * Creates and returns a dummy panel. 266 * 267 * @return Panel containing only a note about 268 * "options unavailable." 269 */ 270 private JPanel buildUnavailablePanel() { 271 JPanel panel = new JPanel(); 272 panel.add(new JLabel("These options are unavailable in this context")); 273 return panel; 274 } 275 276 /** 277 * Creates and returns the advanced preferences panel. 278 * 279 * @return Panel with all of the various startup options. 280 */ 281 private JPanel buildAdvancedPanel() { 282 OptionMaster optMaster = OptionMaster.getInstance(); 283 MemoryOption heapSize = optMaster.getMemoryOption("HEAP_SIZE"); 284 BooleanOption jogl = optMaster.getBooleanOption("JOGL_TOGL"); 285 BooleanOption use3d = optMaster.getBooleanOption("USE_3DSTUFF"); 286 BooleanOption defaultBundle = optMaster.getBooleanOption("DEFAULT_LAYOUT"); 287 BooleanOption useCmsCollector = optMaster.getBooleanOption("USE_CMSGC"); 288 BooleanOption useNpot = optMaster.getBooleanOption("USE_NPOT"); 289 BooleanOption useGeometryByRef = optMaster.getBooleanOption("USE_GEOBYREF"); 290 BooleanOption useImageByRef = optMaster.getBooleanOption("USE_IMAGEBYREF"); 291 FileOption startupBundle = optMaster.getFileOption("STARTUP_BUNDLE"); 292 TextOption jvmArgs = optMaster.getTextOption("JVM_OPTIONS"); 293 LoggerLevelOption logLevel = optMaster.getLoggerLevelOption("LOG_LEVEL"); 294 TextOption textureWidth = optMaster.getTextOption("TEXTURE_WIDTH"); 295 296 JPanel startupPanel = new JPanel(); 297 startupPanel.setBorder(BorderFactory.createTitledBorder("Startup Options")); 298 299 // Build the memory panel 300 JPanel heapPanel = McVGuiUtils.makeLabeledComponent(heapSize.getLabel()+':', heapSize.getComponent()); 301 302 // Build the 3D panel 303 JCheckBox use3dCheckBox = use3d.getComponent(); 304 use3dCheckBox.setText(use3d.getLabel()); 305 final JCheckBox joglCheckBox = jogl.getComponent(); 306 joglCheckBox.setText(jogl.getLabel()); 307 JPanel texturePanel = McVGuiUtils.makeLabeledComponent(textureWidth.getLabel()+':', textureWidth.getComponent()); 308// JTextField textureField = textureWidth.getComponent(); 309 310 JPanel internalPanel = McVGuiUtils.topBottom(use3dCheckBox, joglCheckBox, McVGuiUtils.Prefer.TOP); 311 JPanel j3dPanel = McVGuiUtils.makeLabeledComponent("3D:", internalPanel); 312 313 // Build the bundle panel 314 JComponent startupBundlePanel = startupBundle.getComponent(); 315 JCheckBox defaultBundleCheckBox = defaultBundle.getComponent(); 316 defaultBundleCheckBox.setText(defaultBundle.getLabel()); 317 JPanel bundlePanel = McVGuiUtils.makeLabeledComponent(startupBundle.getLabel()+ ':', 318 McVGuiUtils.topBottom(startupBundlePanel, defaultBundleCheckBox, McVGuiUtils.Prefer.TOP)); 319 320 JCheckBox useCmsCollectorCheckBox = useCmsCollector.getComponent(); 321 useCmsCollectorCheckBox.setText(useCmsCollector.getLabel()); 322 323 JCheckBox useGeometryByRefCheckBox = useGeometryByRef.getComponent(); 324 useGeometryByRefCheckBox.setText(useGeometryByRef.getLabel()); 325 326 JCheckBox useImageByRefCheckBox = useImageByRef.getComponent(); 327 useImageByRefCheckBox.setText(useImageByRef.getLabel()); 328 329 JCheckBox useNpotCheckBox = useNpot.getComponent(); 330 useNpotCheckBox.setText(useNpot.getLabel()); 331 332 // this is a JComboBox<String>; kinda struggling to represent this 333 // in java's type system. 334 JComboBox logLevelComboBox = logLevel.getComponent(); 335 336 JPanel logLevelPanel = McVGuiUtils.makeLabeledComponent(logLevel.getLabel()+':', logLevelComboBox); 337 338 JPanel miscPanel = McVGuiUtils.makeLabeledComponent("Misc:", useCmsCollectorCheckBox); 339 340 JTextField jvmArgsField = jvmArgs.getComponent(); 341 JPanel jvmPanel = McVGuiUtils.makeLabeledComponent("Java Flags:", jvmArgsField); 342 343 // TJJ Nov 2018 344 // Add note at top of Startup Options alerting user a restart may be needed 345 JLabel restartLabel = new JLabel("Note: Most startup options require a McIDAS-V restart to take effect"); 346 restartLabel.setForeground(Color.red); 347 restartLabel.setBorder(new EmptyBorder(6, 6, 6, 6)); 348 349 Component[] visadComponents = { 350 useGeometryByRefCheckBox, 351 useImageByRefCheckBox, 352 useNpotCheckBox, 353 texturePanel, 354 }; 355 356 JPanel visadPanel = McVGuiUtils.makeLabeledComponent("VisAD:", McVGuiUtils.vertical(visadComponents)); 357 358 GroupLayout panelLayout = new GroupLayout(startupPanel); 359 startupPanel.setLayout(panelLayout); 360 panelLayout.setHorizontalGroup( 361 panelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 362 .addComponent(restartLabel) 363 .addComponent(heapPanel) 364 .addComponent(j3dPanel) 365 .addComponent(bundlePanel) 366 .addComponent(visadPanel) 367 .addComponent(logLevelPanel) 368 .addComponent(miscPanel) 369 .addComponent(jvmPanel) 370 ); 371 panelLayout.setVerticalGroup( 372 panelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 373 .addGroup(panelLayout.createSequentialGroup() 374 .addComponent(restartLabel) 375 .addComponent(heapPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 376 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 377 .addComponent(bundlePanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 378 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 379 .addComponent(j3dPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 380 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 381 .addComponent(visadPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 382 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 383 .addComponent(logLevelPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 384 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 385 .addComponent(miscPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 386 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 387 .addComponent(jvmPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 388 ) 389 ); 390 return startupPanel; 391 } 392 393 /** 394 * Builds and returns a {@link JPanel} containing the various buttons that 395 * control the startup manager. These buttons offer identical 396 * functionality to those built by the IDV's preference manager code. 397 * 398 * @return A {@code JPanel} containing the following types of buttons: 399 * {@link ApplyButton}, {@link OkButton}, {@link HelpButton}, 400 * and {@link CancelButton}. 401 * 402 * @see GuiUtils#makeApplyOkHelpCancelButtons(ActionListener) 403 */ 404 private JPanel buildCommandRow() { 405 JPanel panel = new JPanel(new FlowLayout()); 406 // Apply doesn't really mean anything in standalone mode... 407// panel.add(new ApplyButton()); 408 panel.add(new OkButton()); 409 panel.add(new HelpButton()); 410 panel.add(new CancelButton()); 411 panel = McVGuiUtils.makePrettyButtons(panel); 412 return panel; 413 } 414 415 /** 416 * Returns the advanced preferences panel. Differs from the 417 * {@link #buildAdvancedPanel()} in that a panel isn't created, unless 418 * {@code forceBuild} is {@code true}. 419 * 420 * @param forceBuild Always rebuilds the advanced panel if {@code true}. 421 * 422 * @return Panel containing the startup options. 423 */ 424 public JPanel getAdvancedPanel(final boolean forceBuild) { 425 if (forceBuild || (ADVANCED_PANEL == null)) { 426 OptionMaster.getInstance().readStartup(); 427 ADVANCED_PANEL = buildAdvancedPanel(); 428 } 429 return ADVANCED_PANEL; 430 } 431 432 public JPanel getUnavailablePanel() { 433 if (BAD_CHOICE_PANEL == null) { 434 BAD_CHOICE_PANEL = buildUnavailablePanel(); 435 } 436 return BAD_CHOICE_PANEL; 437 } 438 439 /** 440 * Returns a panel containing the Apply/Ok/Help/Cancel buttons. 441 * 442 * @return Panel containing the the command row. 443 */ 444 public JPanel getCommandRow() { 445 if (COMMAND_ROW_PANEL == null) { 446 COMMAND_ROW_PANEL = buildCommandRow(); 447 } 448 return COMMAND_ROW_PANEL; 449 } 450 451 /** 452 * Build and display the startup manager window. 453 */ 454 protected void createDisplay() { 455 DefaultListModel listModel = (DefaultListModel)panelList.getModel(); 456 457 for (String[] PREF_PANEL : PREF_PANELS) { 458 ImageIcon icon = new ImageIcon(getClass().getResource(PREF_PANEL[1])); 459 JLabel label = new JLabel(PREF_PANEL[0], icon, SwingConstants.LEADING); 460 listModel.addElement(label); 461 } 462 463 JScrollPane scroller = new JScrollPane(panelList); 464 final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 465 splitPane.setResizeWeight(0.0); 466 splitPane.setLeftComponent(scroller); 467 scroller.setMinimumSize(new Dimension(166, 319)); 468 469 panelList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 470 panelList.setSelectedIndex(PREF_PANELS.length - 1); 471 panelList.setVisibleRowCount(PREF_PANELS.length); 472 panelList.setCellRenderer(new IconCellRenderer()); 473 474 panelList.addListSelectionListener(e -> { 475 if (!e.getValueIsAdjusting()) { 476 splitPane.setRightComponent(getSelectedPanel()); 477 } 478 }); 479 480 splitPane.setRightComponent(getSelectedPanel()); 481 482 JFrame frame = new JFrame("User Preferences"); 483 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 484 frame.getContentPane().add(splitPane); 485 frame.getContentPane().add(getCommandRow(), BorderLayout.PAGE_END); 486 487 frame.pack(); 488 frame.setVisible(true); 489 } 490 491 /** 492 * Copies a file. 493 * 494 * @param src The file to copy. 495 * @param dst The path to the copy of {@code src}. 496 * 497 * @throws IOException If there was a problem while attempting to copy. 498 */ 499 public void copy(final File src, final File dst) throws IOException { 500 InputStream in = new FileInputStream(src); 501 OutputStream out = new FileOutputStream(dst); 502 503 byte[] buf = new byte[1024]; 504 int length; 505 506 while ((length = in.read(buf)) > 0) { 507 out.write(buf, 0, length); 508 } 509 in.close(); 510 out.close(); 511 } 512 513 public static class TreeCellRenderer extends DefaultTreeCellRenderer { 514 @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { 515 super.getTreeCellRendererComponent(tree, value, sel, expanded, 516 leaf, row, hasFocus); 517 518 DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; 519 520 File f = (File)node.getUserObject(); 521 String path = f.getPath(); 522 523 if (f.isDirectory()) { 524 setToolTipText("Bundle Directory: " + path); 525 } else if (ArgumentManager.isZippedBundle(path)) { 526 setToolTipText("Zipped Bundle: " + path); 527 } else if (ArgumentManager.isXmlBundle(path)) { 528 setToolTipText("XML Bundle: " + path); 529 } else { 530 setToolTipText("Unknown file type: " + path); 531 } 532 setText(f.getName().replace(f.getParent(), "")); 533 return this; 534 } 535 } 536 537 public static class IconCellRenderer extends DefaultListCellRenderer { 538 @Override public Component getListCellRendererComponent(JList list, 539 Object value, int index, boolean isSelected, boolean cellHasFocus) 540 { 541 super.getListCellRendererComponent(list, value, index, isSelected, 542 cellHasFocus); 543 544 if (value instanceof JLabel) { 545 setText(((JLabel)value).getText()); 546 setIcon(((JLabel)value).getIcon()); 547 } 548 549 return this; 550 } 551 552 @Override protected void paintComponent(Graphics g) { 553 Graphics2D g2d = (Graphics2D)g; 554 g2d.setRenderingHints(StartupManager.HINTS); 555 super.paintComponent(g2d); 556 } 557 } 558 559 private static abstract class CommandButton extends JButton 560 implements ActionListener 561 { 562 public CommandButton(final String label) { 563 super(label); 564 McVGuiUtils.setComponentWidth(this); 565 addActionListener(this); 566 } 567 568 @Override public void paintComponent(Graphics g) { 569 Graphics2D g2d = (Graphics2D)g; 570 g2d.setRenderingHints(StartupManager.HINTS); 571 super.paintComponent(g2d); 572 } 573 574 abstract public void actionPerformed(final ActionEvent e); 575 } 576 577 private static class ApplyButton extends CommandButton { 578 public ApplyButton() { 579 super("Apply"); 580 } 581 public void actionPerformed(final ActionEvent e) { 582 StartupManager.getInstance().handleApply(); 583 } 584 } 585 586 private static class OkButton extends CommandButton { 587 public OkButton() { 588 super("OK"); 589 } 590 public void actionPerformed(final ActionEvent e) { 591 StartupManager.getInstance().handleOk(); 592 } 593 } 594 595 private static class HelpButton extends CommandButton { 596 public HelpButton() { 597 super("Help"); 598 } 599 public void actionPerformed(final ActionEvent e) { 600 StartupManager.getInstance().handleHelp(); 601 } 602 } 603 604 private static class CancelButton extends CommandButton { 605 public CancelButton() { 606 super("Cancel"); 607 } 608 public void actionPerformed(final ActionEvent e) { 609 StartupManager.getInstance().handleCancel(); 610 } 611 } 612 613 public static Properties getDefaultProperties() { 614 Properties props = new Properties(); 615 String osName = System.getProperty("os.name"); 616 if (osName.startsWith("Mac OS X")) { 617 props.setProperty("userpath", String.format("%s%s%s%s%s", System.getProperty("user.home"), File.separator, "Documents", File.separator, Constants.USER_DIRECTORY_NAME)); 618 } else { 619 props.setProperty("userpath", String.format("%s%s%s", System.getProperty("user.home"), File.separator, Constants.USER_DIRECTORY_NAME)); 620 } 621 props.setProperty(Constants.PROP_SYSMEM, "0"); 622 return props; 623 } 624 625 /** 626 * Extract any command-line properties and their corresponding values. 627 * 628 * <p>May print out usage information if a badly formatted 629 * {@literal "property=value"} pair is encountered, or when an unknown 630 * argument is found (depending on value of the {@code ignoreUnknown} 631 * parameter). 632 * 633 * <p><b>NOTE:</b> {@code null} is not a permitted value for any parameter. 634 * 635 * @param ignoreUnknown Whether or not to handle unknown arguments. 636 * @param fromStartupManager Whether or not this call originated from 637 * {@code startupmanager.jar}. 638 * @param args Array containing command-line arguments. 639 * @param defaults Default parameter values. 640 * 641 * @return Command-line arguments as a collection of property identifiers 642 * and values. 643 */ 644 public static Properties getArgs(final boolean ignoreUnknown, 645 final boolean fromStartupManager, final String[] args, 646 final Properties defaults) 647 { 648 Properties props = new Properties(defaults); 649 for (int i = 0; i < args.length; i++) { 650 651 // handle property definitions 652 if (args[i].startsWith("-D")) { 653 List<String> l = StringUtil.split(args[i].substring(2), "="); 654 if (l.size() == 2) { 655 props.setProperty(l.get(0), l.get(1)); 656 } else { 657 usage("Invalid property:" + args[i]); 658 } 659 } 660 661 // handle userpath changes 662 else if (ARG_USERPATH.equals(args[i]) && ((i + 1) < args.length)) { 663 props.setProperty("userpath", args[++i]); 664 } 665 666 // handle help requests 667 else if (ARG_HELP.equals(args[i]) && (fromStartupManager)) { 668 System.err.println(USAGE_MESSAGE); 669 System.err.println(getUsageMessage()); 670 System.exit(1); 671 } 672 673 // bail out for unknown args, unless we don't care! 674 else if (!ignoreUnknown){ 675 usage("Unknown argument: " + args[i]); 676 } 677 } 678 return props; 679 } 680 681 public static int getMaximumHeapSize() { 682 int sysmem = 683 StartupManager.getInstance().getPlatform().getAvailableMemory(); 684 if ((sysmem > Constants.MAX_MEMORY_32BIT) && 685 (!System.getProperty("os.arch").contains("64"))) 686 { 687 return Constants.MAX_MEMORY_32BIT; 688 } 689 return sysmem; 690 } 691 692 /** 693 * Print out the command line usage message and exit. Taken entirely from 694 * {@link ucar.unidata.idv.ArgsManager}. 695 * 696 * @param err The usage message 697 */ 698 private static void usage(final String err) { 699 String msg = USAGE_MESSAGE; 700 msg = msg + '\n' + getUsageMessage(); 701 LogUtil.userErrorMessage(err + '\n' + msg); 702 System.exit(1); 703 } 704 705 /** 706 * Return the command line usage message. 707 * 708 * @return The usage message 709 */ 710 protected static String getUsageMessage() { 711 return '\t'+ARG_HELP+" (this message)\n"+ 712 '\t'+ARG_USERPATH+" <user directory to use>\n"+ 713 "\t-Dpropertyname=value (Define the property value)\n"; 714 } 715 716 /** 717 * Applies the command line arguments to the startup preferences. 718 * 719 * This method is mostly useful because it allows us to supply an 720 * arbitrary {@code args} array, link in 721 * {@link edu.wisc.ssec.mcidasv.McIDASV#main(String[])}. 722 * 723 * @param ignoreUnknown If {@code true} ignore any parameters that do not 724 * apply to the startup manager. If {@code false}, 725 * the non-applicable parameters should signify an 726 * error. 727 * @param fromStartupManager Whether or not this call originated from the 728 * startup manager (rather than preferences). 729 * @param args Incoming command line arguments. Cannot be {@code null}. 730 * 731 * @throws NullPointerException if {@code args} is null. 732 * 733 * @see #getArgs(boolean, boolean, String[], Properties) 734 */ 735 public static void applyArgs(final boolean ignoreUnknown, 736 final boolean fromStartupManager, 737 final String[] args) 738 throws IllegalArgumentException 739 { 740 Objects.requireNonNull(args, "Argument list cannot be null"); 741 742 StartupManager sm = StartupManager.getInstance(); 743 Platform platform = sm.getPlatform(); 744 745 Properties props = getArgs(ignoreUnknown, 746 fromStartupManager, 747 args, 748 getDefaultProperties()); 749 platform.setUserDirectory(props.getProperty("userpath")); 750 platform.setAvailableMemory(GetMem.getMemory()); 751 } 752 753 /** 754 * Extracts all startup preferences and returns them in a convenient 755 * {@code Map}. 756 * 757 * @return Either a {@link HashMap} mapping {@literal "preference ID"} to 758 * its corresponding value, or an empty map. 759 */ 760 public static Map<String, String> getStartupPrefs() { 761 StartupManager sm = StartupManager.getInstance(); 762 int size = OptionMaster.getInstance().blahblah.length; 763 File script = new File(sm.getPlatform().getUserPrefs()); 764 Map<String, String> startupPrefs = new HashMap<>(size); 765 try (BufferedReader br = new BufferedReader(new FileReader(script))) { 766 String line; 767 while ((line = br.readLine()) != null) { 768 if (line.startsWith("#")) { 769 continue; 770 } 771 if (line.startsWith(SET_PREFIX)) { 772 line = line.replace(SET_PREFIX, EMPTY_STRING); 773 } 774 int splitAt = line.indexOf('='); 775 if (splitAt >= 0) { 776 String k = line.substring(0, splitAt); 777 String v = line.substring(splitAt + 1); 778 startupPrefs.put(k, v); 779 } 780 } 781 } catch (IOException e) { 782 System.err.println("Problem reading from '"+script.getPath()+"': "+e.getMessage()); 783 } 784 return startupPrefs; 785 } 786 787 public static void main(String[] args) { 788 applyArgs(false, true, args); 789 StartupManager.getInstance().createDisplay(); 790 } 791}