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 */ 028package edu.wisc.ssec.mcidasv.util; 029 030import static edu.wisc.ssec.mcidasv.util.McVGuiUtils.setButtonImage; 031 032import java.awt.Dimension; 033import java.awt.EventQueue; 034import java.awt.GridBagConstraints; 035import java.awt.GridBagLayout; 036import java.awt.event.ActionEvent; 037import java.awt.event.WindowAdapter; 038import java.awt.event.WindowEvent; 039 040import java.io.IOException; 041 042import javax.swing.GroupLayout; 043import javax.swing.ImageIcon; 044import javax.swing.JButton; 045import javax.swing.JDialog; 046import javax.swing.JFrame; 047import javax.swing.JLabel; 048import javax.swing.JPanel; 049import javax.swing.JScrollPane; 050import javax.swing.JTextPane; 051import javax.swing.LayoutStyle; 052import javax.swing.WindowConstants; 053import javax.swing.event.HyperlinkEvent; 054 055import org.slf4j.Logger; 056import org.slf4j.LoggerFactory; 057 058/** 059 * {@code WelcomeWindow} is really just intended to <i>try</i> to detect known 060 * hardware problems and inform the user about any problems. 061 * 062 * <p>The current implementation does not perform <i>any</i> detection, but 063 * expect this to change. 064 */ 065// NOTE TO MCV CODERS: 066// **DOCUMENT WHAT CHECKS AND/OR DETECTION ARE BEING PERFORMED** 067//public class WelcomeWindow extends JFrame { 068public class WelcomeWindow extends JDialog { 069 070 private static final Logger logger = 071 LoggerFactory.getLogger(WelcomeWindow.class); 072 073 /** Path to {@literal "header"} image. */ 074 private static final String LOGO_PATH = 075 "/edu/wisc/ssec/mcidasv/images/mcidasv_logo.gif"; 076 077 /** Path to the HTML to display within {@link #textPane}. */ 078 private static final String WELCOME_HTML = 079 "/edu/wisc/ssec/mcidasv/resources/welcome.html"; 080 081 /** 082 * Message to display if there was a problem loading 083 * {@link #WELCOME_HTML}. 084 */ 085 private static final String ERROR_MESSAGE = 086 "McIDAS-V had a problem displaying its welcome message. Please" 087 + " contact the McIDAS Help Desk for assistance."; 088 089 /** Dimensions of the welcome window frame. */ 090 private static final Dimension WINDOW_SIZE = new Dimension(495, 431); 091 092 /** Default auto-quit delay (in milliseconds). */ 093 public static final long DEFAULT_QUIT_DELAY = 2500; 094 095 /** Java-friendly location of the path to the welcome message. */ 096 private final java.net.URL contents; 097 098 /** Whether or not the window should automatically close. */ 099 private final boolean autoQuit; 100 101 /** Delay in milliseconds for auto-quitting. */ 102 private final long autoQuitDelay; 103 104 /** 105 * Creates new form WelcomeWindow. 106 */ 107 public WelcomeWindow() { 108 this(false, Long.MAX_VALUE); 109 } 110 111 public WelcomeWindow(boolean autoQuit, long delay) { 112 this.autoQuit = autoQuit; 113 this.autoQuitDelay = delay; 114 this.contents = WelcomeWindow.class.getResource(WELCOME_HTML); 115 initComponents(); 116 } 117 118 /** 119 * This method is called from within the constructor to 120 * initialize the form. 121 * WARNING: Do NOT modify this code. The content of this method is 122 * always regenerated by the Form Editor. 123 */ 124 // <editor-fold defaultstate="collapsed" desc="Generated Code"> 125 private void initComponents() { 126 127 setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 128 setTitle("Welcome to McIDAS-V"); 129 setLocationByPlatform(true); 130 addWindowListener(new WindowAdapter() { 131 @Override public void windowClosing(WindowEvent evt) { 132 formWindowClosing(evt); 133 } 134 }); 135 136 logoPanel.setLayout(new GridBagLayout()); 137 138 logoLabel.setIcon(new ImageIcon(getClass().getResource(LOGO_PATH))); // NOI18N 139 logoPanel.add(logoLabel, new GridBagConstraints()); 140 141 textPane.setEditable(false); 142 try { 143 textPane.setPage(contents); 144 } catch (IOException e) { 145 textPane.setText(ERROR_MESSAGE); 146 logger.error("Could not change contents of textPane", e); 147 } 148 textPane.addHyperlinkListener(this::textPaneHyperlinkUpdate); 149 scrollPane.setViewportView(textPane); 150 151 GroupLayout mainPanelLayout = new GroupLayout(mainPanel); 152 mainPanel.setLayout(mainPanelLayout); 153 mainPanelLayout.setHorizontalGroup( 154 mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 155 .addComponent(scrollPane, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 360, Short.MAX_VALUE) 156 ); 157 mainPanelLayout.setVerticalGroup( 158 mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 159 .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 273, Short.MAX_VALUE) 160 ); 161 162 setButtonImage(startButton, McVGuiUtils.ICON_APPLY_SMALL); 163 startButton.addActionListener(this::startButtonActionPerformed); 164 165 setButtonImage(quitButton, McVGuiUtils.ICON_CANCEL_SMALL); 166 quitButton.addActionListener(this::quitButtonActionPerformed); 167 168 GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel); 169 buttonPanel.setLayout(buttonPanelLayout); 170 buttonPanelLayout.setHorizontalGroup( 171 buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 172 .addGroup(GroupLayout.Alignment.TRAILING, buttonPanelLayout.createSequentialGroup() 173 .addContainerGap(144, Short.MAX_VALUE) 174 .addComponent(quitButton) 175 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 176 .addComponent(startButton)) 177 ); 178 buttonPanelLayout.setVerticalGroup( 179 buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 180 .addGroup(buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) 181 .addComponent(startButton) 182 .addComponent(quitButton)) 183 ); 184 185 GroupLayout layout = new GroupLayout(getContentPane()); 186 getContentPane().setLayout(layout); 187 layout.setHorizontalGroup( 188 layout.createParallelGroup(GroupLayout.Alignment.LEADING) 189 .addGroup(layout.createSequentialGroup() 190 .addContainerGap() 191 .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) 192 .addComponent(mainPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 193 .addComponent(buttonPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 194 .addComponent(logoPanel, GroupLayout.DEFAULT_SIZE, 360, Short.MAX_VALUE)) 195 .addContainerGap()) 196 ); 197 layout.setVerticalGroup( 198 layout.createParallelGroup(GroupLayout.Alignment.LEADING) 199 .addGroup(layout.createSequentialGroup() 200 .addContainerGap() 201 .addComponent(logoPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 202 .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 203 .addComponent(mainPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 204 .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 205 .addComponent(buttonPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 206 .addContainerGap()) 207 ); 208 209 pack(); 210 setLocationRelativeTo(null); 211 setSize(WINDOW_SIZE); 212 setModal(true); 213 }// </editor-fold> 214 215 /** 216 * Show or close the Welcome Window. 217 * 218 * <p>Overridden in McV to handle auto-quitting. If we're supposed to 219 * auto-quit, a thread will be started that calls {@link JButton#doClick()}. 220 * </p> 221 * 222 * @param visible Whether or not the dialog should be opened or closed. 223 */ 224 @Override public void setVisible(boolean visible) { 225 if (autoQuit) { 226 new Thread() { 227 public void run() { 228 try { 229 sleep(autoQuitDelay); 230 } catch (InterruptedException ex) { 231 // not much else to be done... 232 logger.error("Problem changing visibility", ex); 233 } finally { 234 EventQueue.invokeLater(startButton::doClick); 235 } 236 } 237 }.start(); 238 } 239 super.setVisible(visible); 240 } 241 242 /** 243 * Handles the user clicking on {@link #startButton}. 244 * 245 * @param evt Event to handle. Currently ignored. 246 */ 247 private void startButtonActionPerformed(ActionEvent evt) { 248 this.setVisible(false); 249 } 250 251 /** 252 * Handles the user clicking on {@link #quitButton}. Doesn't do anything 253 * aside from handing off things to 254 * {@link #formWindowClosing(WindowEvent)} 255 * 256 * @param evt Event to handle. Currently ignored. 257 * 258 * @see #formWindowClosing(WindowEvent) 259 */ 260 private void quitButtonActionPerformed(ActionEvent evt) { 261 formWindowClosing(null); 262 } 263 264 /** 265 * Handles the user opting to close the welcome window 266 * {@link JFrame}. Executes {@code System.exit(1)} in an 267 * effort to signal to the startup scripts that window terminated 268 * {@literal "abnormally"}. 269 * 270 * <p>An abnormal termination will result in the startup script 271 * terminating the launch of McIDAS-V. 272 * 273 * @param evt Event to handle. Currently ignored. 274 */ 275 private void formWindowClosing(WindowEvent evt) { 276 System.exit(1); 277 } 278 279 /** 280 * Listens to {@link #textPane} in order to handle the user clicking on 281 * HTML links. 282 * 283 * @param evt Event to handle. Anything other than 284 * an {@literal "ACTIVATED"} 285 * {@link javax.swing.event.HyperlinkEvent.EventType HyperlinkEvent.EventType} 286 * is ignored. 287 * 288 * @see WebBrowser#browse(String) 289 */ 290 private void textPaneHyperlinkUpdate(HyperlinkEvent evt) { 291 if (evt.getEventType() != HyperlinkEvent.EventType.ACTIVATED) { 292 return; 293 } 294 295 String url = null; 296 if (evt.getURL() == null) { 297 url = evt.getDescription(); 298 } else { 299 url = evt.getURL().toString(); 300 } 301 302 WebBrowser.browse(url); 303 } 304 305 /** 306 * Kick the tires. 307 * 308 * @param args Command line arguments 309 */ 310 public static void main(String[] args) { 311 EventQueue.invokeLater(() -> { 312 WelcomeWindow ww; 313 if (args.length == 2) { 314 boolean autoQuit = "-autoquit".equals(args[0]); 315 long delay = Long.parseLong(args[1]); 316 ww = new WelcomeWindow(autoQuit, delay); 317 } else if (args.length == 1) { 318 boolean autoQuit = "-autoquit".equals(args[0]); 319 ww = new WelcomeWindow(autoQuit, DEFAULT_QUIT_DELAY); 320 } 321 else { 322 ww = new WelcomeWindow(); 323 } 324 ww.setVisible(true); 325 }); 326 } 327 328 // boring gui components 329 private final JPanel buttonPanel = new JPanel(); 330 private final JLabel logoLabel = new JLabel(); 331 private final JPanel logoPanel = new JPanel(); 332 private final JPanel mainPanel = new JPanel(); 333 private final JButton quitButton = new JButton("Quit"); 334 private final JScrollPane scrollPane = new JScrollPane(); 335 private final JButton startButton = new JButton("Start McIDAS-V"); 336 private final JTextPane textPane = new JTextPane(); 337}