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