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 */
028
029package edu.wisc.ssec.mcidasv.chooser;
030
031
032import ucar.unidata.idv.*;
033
034import ucar.unidata.ui.ChooserList;
035import ucar.unidata.ui.ChooserPanel;
036
037import java.awt.*;
038import java.awt.event.*;
039
040import java.util.Vector;
041
042import java.beans.*;
043
044import javax.swing.*;
045import javax.swing.border.*;
046import javax.swing.event.*;
047
048import ucar.unidata.util.GuiUtils;
049import ucar.unidata.util.Misc;
050import ucar.unidata.util.PreferenceList;
051
052/**
053 *
054 * @author Unidata IDV Development Team
055 * @version $Revision$
056 */
057public abstract class FrameChooser extends ChooserPanel {
058
059    /** Property for new data selection */
060    public static String NEW_SELECTION = "FrameChooser.NEW_SELECTION";
061
062    /** Have connected */
063    protected static final int STATE_CONNECTED = 2;
064
065    /** flag for ignoring combobox changes */
066    protected boolean ignoreStateChangedEvents = false;
067
068    /**
069     * Public keys for frame numbers, request, and data name.
070     */
071    public final static String FRAME_NUMBERS_KEY = "frame numbers";
072    public final static String DATA_NAME_KEY = "data name";
073    public final static String REQUEST_HOST = "host";
074    public final static String REQUEST_PORT = "port";
075    public final static String REQUEST_KEY = "key";
076
077    /** Used to synchronize access to widgets (eg: disabling, setting state, etc). */
078    protected Object WIDGET_MUTEX = new Object();
079
080    /** frames list */
081    private ChooserList framesList;
082
083    /** Keep track of when are are doing a frame loop */
084    private boolean doLoop = false;
085
086    /** Frame loop radio button */
087    private JRadioButton loopRB;
088
089    /** Refresh current frame radio button */
090    private JRadioButton curRB;
091
092    /**
093     * Create me.
094     */
095    public FrameChooser() {}
096
097    /**
098     * Handle when the user presses the update button
099     *
100     * @throws Exception _more_
101     */
102    public void handleUpdate() throws Exception {}
103
104    /**
105     * Handle when the user presses the update button
106     */
107    public void handleUpdateFromThread() {
108        showWaitCursor();
109        try {
110            handleUpdate();
111        } catch (Exception exc) {
112        }
113        showNormalCursor();
114    }
115
116    /**
117     * Update the selector. Call handleUpdate in a thread
118     */
119    public final void doUpdate() {
120        Misc.run(this, "handleUpdateFromThread");
121    }
122
123    /**
124     * Handle the event
125     *
126     * @param ae The event
127     */
128    public void actionPerformed(ActionEvent ae) {
129        String cmd = ae.getActionCommand();
130        super.actionPerformed(ae);
131    }
132
133    /**
134     * Disable/enable any components that depend on the server.
135     * Try to update the status labelwith what we know here.
136     */
137    protected void updateStatus() {
138       setHaveData(getGoodToGo());
139    }
140
141    /**
142     * Are there any times in the times list.
143     *
144     * @return Do we have any times at all.
145     */
146    protected boolean haveAnyTimes() {
147        return framesList.getModel().getSize() > 0;
148    }
149
150    /**
151     * Are there more than one times in the times list.
152     *
153     * @return Do we have a series.
154     */
155    protected boolean haveASeries() {
156        return !getTimesList().getSelectedValuesList().isEmpty();
157    }
158
159    /**
160     * Create (if needed) and return the list that shows frames.
161     *
162     * @return The frames list.
163     */
164    public ChooserList getTimesList() {
165        if (framesList == null) {
166            framesList = new ChooserList();
167            framesList.setVisibleRowCount(getTimesListSize());
168            framesList.addListSelectionListener(new ListSelectionListener() {
169                public void valueChanged(ListSelectionEvent e) {
170                    updateStatus();
171                }
172            });
173        }
174        return framesList;
175    }
176
177    /**
178     * Get the size of the times list
179     *
180     * @return the times list size
181     */
182    protected int getTimesListSize() {
183        return 6;
184    }
185
186    /**
187     * Clear all times in the times list.
188     */
189    protected void clearFramesList() {
190        getTimesList().setListData(new Vector());
191    }
192
193    /**
194     *  Do what needs to be done to read in the times.  Subclasses
195     *  need to implement this.
196     */
197    protected abstract void readFrames();
198
199    /**
200     * Are we all set to load data.
201     *
202     * @return All set to load.
203     */
204    protected boolean getGoodToGo() {
205        if ( !haveFrameSelected()) {
206            return false;
207        }
208        return true;
209    }
210
211    /**
212     * Create the current frame / frame loop selector
213     *
214     * @return  the image list panel
215     */
216    protected JPanel makeFramesPanel() {
217
218        getTimesList().addListSelectionListener(new ListSelectionListener() {
219            public void valueChanged(ListSelectionEvent e) {
220                if ( !getDoFrameLoop()) {
221                    return;
222                }
223            }
224        });
225
226        ChangeListener listener = new ChangeListener() {
227            public void stateChanged(ChangeEvent ae) {
228                if (loopRB.isSelected() == getDoFrameLoop()) {
229                    return;
230                }
231                doLoop = loopRB.isSelected();
232                if (doLoop && !haveAnyTimes()) {
233                    readFrames();
234                } else {
235                    updateStatus();
236                }
237                enableWidgets();
238            }
239        };
240
241        loopRB = new JRadioButton("Select frames", getDoFrameLoop());
242        loopRB.addChangeListener(listener);
243        curRB = new JRadioButton("Refresh current frame", !getDoFrameLoop());
244        curRB.addChangeListener(listener);
245        GuiUtils.buttonGroup(loopRB, curRB);
246        JPanel panel = GuiUtils.doLayout(new Component[] {
247            curRB, loopRB, 
248            new JLabel(" "),getTimesList().getScroller() 
249        }, 2, GuiUtils.WT_N, GuiUtils.WT_NY);
250        return GuiUtils.wrap(panel);
251    }
252
253    /**
254     * Are there any frames selected.
255     *
256     * @return Any frames selected.
257     */
258    protected boolean haveFrameSelected() {
259        return !getDoFrameLoop() || getTimesList().haveDataSelected();
260    }
261
262    /**
263     * Do we do a frame loop or refresh current frame
264     *
265     * @return Do we do frame loop
266     */
267    protected boolean getDoFrameLoop() {
268        return doLoop;
269    }
270
271    /**
272     * Set whether we do a frame loop or refresh current frame
273     *
274     * @param yesorno true to do frame loop
275     */
276    protected void setDoFrameLoop(boolean yesorno) {
277        doLoop = yesorno;
278        // Should this be in 
279        if (curRB != null) {
280            curRB.setSelected(yesorno);
281        }
282    }
283
284    /**
285     * Did the user select current frame?
286     *
287     * @return Should we load current frame
288     */
289    protected boolean getDoCurrentFrame() {
290        return !getDoFrameLoop();
291    }
292
293    /**
294     * Enable or disable the GUI widgets based on what has been
295     * selected.
296     */
297    protected void enableWidgets() {
298        getTimesList().setEnabled(getDoFrameLoop());
299    }
300}