001/*
002 * $Id: FrameChooser.java,v 1.7 2011/03/24 16:06:31 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 * 
012 * All Rights Reserved
013 * 
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.  
016 * 
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 * 
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025 * GNU Lesser Public License for more details.
026 * 
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program.  If not, see http://www.gnu.org/licenses.
029 */
030
031package edu.wisc.ssec.mcidasv.chooser;
032
033
034import ucar.unidata.idv.*;
035
036import ucar.unidata.ui.ChooserList;
037import ucar.unidata.ui.ChooserPanel;
038
039import java.awt.*;
040import java.awt.event.*;
041
042import java.util.Vector;
043
044import java.beans.*;
045
046import javax.swing.*;
047import javax.swing.border.*;
048import javax.swing.event.*;
049
050import ucar.unidata.util.GuiUtils;
051import ucar.unidata.util.Misc;
052import ucar.unidata.util.PreferenceList;
053
054/**
055 *
056 * @author Unidata IDV Development Team
057 * @version $Revision: 1.7 $
058 */
059public abstract class FrameChooser extends ChooserPanel {
060
061    /** Property for new data selection */
062    public static String NEW_SELECTION = "FrameChooser.NEW_SELECTION";
063
064    /** Have connected */
065    protected static final int STATE_CONNECTED = 2;
066
067    /** flag for ignoring combobox changes */
068    protected boolean ignoreStateChangedEvents = false;
069
070    /**
071     * Public keys for frame numbers, request, and data name.
072     */
073    public final static String FRAME_NUMBERS_KEY = "frame numbers";
074    public final static String DATA_NAME_KEY = "data name";
075    public final static String REQUEST_HOST = "host";
076    public final static String REQUEST_PORT = "port";
077    public final static String REQUEST_KEY = "key";
078
079    /** Used to synchronize access to widgets (eg: disabling, setting state, etc). */
080    protected Object WIDGET_MUTEX = new Object();
081
082    /** frames list */
083    private ChooserList framesList;
084
085    /** Keep track of when are are doing a frame loop */
086    private boolean doLoop = false;
087
088    /** Frame loop radio button */
089    private JRadioButton loopRB;
090
091    /** Refresh current frame radio button */
092    private JRadioButton curRB;
093
094    /**
095     * Create me.
096     */
097    public FrameChooser() {}
098
099    /**
100     * Handle when the user presses the update button
101     *
102     * @throws Exception _more_
103     */
104    public void handleUpdate() throws Exception {}
105
106    /**
107     * Handle when the user presses the update button
108     */
109    public void handleUpdateFromThread() {
110        showWaitCursor();
111        try {
112            handleUpdate();
113        } catch (Exception exc) {
114        }
115        showNormalCursor();
116    }
117
118    /**
119     * Update the selector. Call handleUpdate in a thread
120     */
121    public final void doUpdate() {
122        Misc.run(this, "handleUpdateFromThread");
123    }
124
125    /**
126     * Handle the event
127     *
128     * @param ae The event
129     */
130    public void actionPerformed(ActionEvent ae) {
131        String cmd = ae.getActionCommand();
132        super.actionPerformed(ae);
133    }
134
135    /**
136     * Disable/enable any components that depend on the server.
137     * Try to update the status labelwith what we know here.
138     */
139    protected void updateStatus() {
140       setHaveData(getGoodToGo());
141    }
142
143    /**
144     * Are there any times in the times list.
145     *
146     * @return Do we have any times at all.
147     */
148    protected boolean haveAnyTimes() {
149        return framesList.getModel().getSize() > 0;
150    }
151
152    /**
153     * Are there more than one times in the times list.
154     *
155     * @return Do we have a series.
156     */
157    protected boolean haveASeries() {
158        Object[] selectedTimes = getTimesList().getSelectedValues();
159        return selectedTimes.length > 1;
160    }
161
162    /**
163     * Create (if needed) and return the list that shows frames.
164     *
165     * @return The frames list.
166     */
167    public ChooserList getTimesList() {
168        if (framesList == null) {
169            framesList = new ChooserList();
170            framesList.setVisibleRowCount(getTimesListSize());
171            framesList.addListSelectionListener(new ListSelectionListener() {
172                public void valueChanged(ListSelectionEvent e) {
173                    updateStatus();
174                }
175            });
176        }
177        return framesList;
178    }
179
180    /**
181     * Get the size of the times list
182     *
183     * @return the times list size
184     */
185    protected int getTimesListSize() {
186        return 6;
187    }
188
189    /**
190     * Clear all times in the times list.
191     */
192    protected void clearFramesList() {
193        getTimesList().setListData(new Vector());
194    }
195
196    /**
197     *  Do what needs to be done to read in the times.  Subclasses
198     *  need to implement this.
199     */
200    protected abstract void readFrames();
201
202    /**
203     * Are we all set to load data.
204     *
205     * @return All set to load.
206     */
207    protected boolean getGoodToGo() {
208        if ( !haveFrameSelected()) {
209            return false;
210        }
211        return true;
212    }
213
214    /**
215     * Create the current frame / frame loop selector
216     *
217     * @return  the image list panel
218     */
219    protected JPanel makeFramesPanel() {
220
221        getTimesList().addListSelectionListener(new ListSelectionListener() {
222            public void valueChanged(ListSelectionEvent e) {
223                if ( !getDoFrameLoop()) {
224                    return;
225                }
226            }
227        });
228
229        ChangeListener listener = new ChangeListener() {
230            public void stateChanged(ChangeEvent ae) {
231                if (loopRB.isSelected() == getDoFrameLoop()) {
232                    return;
233                }
234                doLoop = loopRB.isSelected();
235                if (doLoop && !haveAnyTimes()) {
236                    readFrames();
237                } else {
238                    updateStatus();
239                }
240                enableWidgets();
241            }
242        };
243
244        loopRB = new JRadioButton("Select frames", getDoFrameLoop());
245        loopRB.addChangeListener(listener);
246        curRB = new JRadioButton("Refresh current frame", !getDoFrameLoop());
247        curRB.addChangeListener(listener);
248        GuiUtils.buttonGroup(loopRB, curRB);
249        JPanel panel = GuiUtils.doLayout(new Component[] {
250            curRB, loopRB, 
251            new JLabel(" "),getTimesList().getScroller() 
252        }, 2, GuiUtils.WT_N, GuiUtils.WT_NY);
253        return GuiUtils.wrap(panel);
254    }
255
256    /**
257     * Are there any frames selected.
258     *
259     * @return Any frames selected.
260     */
261    protected boolean haveFrameSelected() {
262        return !getDoFrameLoop() || getTimesList().haveDataSelected();
263    }
264
265    /**
266     * Do we do a frame loop or refresh current frame
267     *
268     * @return Do we do frame loop
269     */
270    protected boolean getDoFrameLoop() {
271        return doLoop;
272    }
273
274    /**
275     * Set whether we do a frame loop or refresh current frame
276     *
277     * @param yesorno true to do frame loop
278     */
279    protected void setDoFrameLoop(boolean yesorno) {
280        doLoop = yesorno;
281        // Should this be in 
282        if (curRB != null) {
283            curRB.setSelected(yesorno);
284        }
285    }
286
287    /**
288     * Did the user select current frame?
289     *
290     * @return Should we load current frame
291     */
292    protected boolean getDoCurrentFrame() {
293        return !getDoFrameLoop();
294    }
295
296    /**
297     * Enable or disable the GUI widgets based on what has been
298     * selected.
299     */
300    protected void enableWidgets() {
301        getTimesList().setEnabled(getDoFrameLoop());
302    }
303}