001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
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    
029    package edu.wisc.ssec.mcidasv.chooser;
030    
031    
032    import ucar.unidata.idv.*;
033    
034    import ucar.unidata.ui.ChooserList;
035    import ucar.unidata.ui.ChooserPanel;
036    
037    import java.awt.*;
038    import java.awt.event.*;
039    
040    import java.util.Vector;
041    
042    import java.beans.*;
043    
044    import javax.swing.*;
045    import javax.swing.border.*;
046    import javax.swing.event.*;
047    
048    import ucar.unidata.util.GuiUtils;
049    import ucar.unidata.util.Misc;
050    import ucar.unidata.util.PreferenceList;
051    
052    /**
053     *
054     * @author Unidata IDV Development Team
055     * @version $Revision$
056     */
057    public 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            Object[] selectedTimes = getTimesList().getSelectedValues();
157            return selectedTimes.length > 1;
158        }
159    
160        /**
161         * Create (if needed) and return the list that shows frames.
162         *
163         * @return The frames list.
164         */
165        public ChooserList getTimesList() {
166            if (framesList == null) {
167                framesList = new ChooserList();
168                framesList.setVisibleRowCount(getTimesListSize());
169                framesList.addListSelectionListener(new ListSelectionListener() {
170                    public void valueChanged(ListSelectionEvent e) {
171                        updateStatus();
172                    }
173                });
174            }
175            return framesList;
176        }
177    
178        /**
179         * Get the size of the times list
180         *
181         * @return the times list size
182         */
183        protected int getTimesListSize() {
184            return 6;
185        }
186    
187        /**
188         * Clear all times in the times list.
189         */
190        protected void clearFramesList() {
191            getTimesList().setListData(new Vector());
192        }
193    
194        /**
195         *  Do what needs to be done to read in the times.  Subclasses
196         *  need to implement this.
197         */
198        protected abstract void readFrames();
199    
200        /**
201         * Are we all set to load data.
202         *
203         * @return All set to load.
204         */
205        protected boolean getGoodToGo() {
206            if ( !haveFrameSelected()) {
207                return false;
208            }
209            return true;
210        }
211    
212        /**
213         * Create the current frame / frame loop selector
214         *
215         * @return  the image list panel
216         */
217        protected JPanel makeFramesPanel() {
218    
219            getTimesList().addListSelectionListener(new ListSelectionListener() {
220                public void valueChanged(ListSelectionEvent e) {
221                    if ( !getDoFrameLoop()) {
222                        return;
223                    }
224                }
225            });
226    
227            ChangeListener listener = new ChangeListener() {
228                public void stateChanged(ChangeEvent ae) {
229                    if (loopRB.isSelected() == getDoFrameLoop()) {
230                        return;
231                    }
232                    doLoop = loopRB.isSelected();
233                    if (doLoop && !haveAnyTimes()) {
234                        readFrames();
235                    } else {
236                        updateStatus();
237                    }
238                    enableWidgets();
239                }
240            };
241    
242            loopRB = new JRadioButton("Select frames", getDoFrameLoop());
243            loopRB.addChangeListener(listener);
244            curRB = new JRadioButton("Refresh current frame", !getDoFrameLoop());
245            curRB.addChangeListener(listener);
246            GuiUtils.buttonGroup(loopRB, curRB);
247            JPanel panel = GuiUtils.doLayout(new Component[] {
248                curRB, loopRB, 
249                new JLabel(" "),getTimesList().getScroller() 
250            }, 2, GuiUtils.WT_N, GuiUtils.WT_NY);
251            return GuiUtils.wrap(panel);
252        }
253    
254        /**
255         * Are there any frames selected.
256         *
257         * @return Any frames selected.
258         */
259        protected boolean haveFrameSelected() {
260            return !getDoFrameLoop() || getTimesList().haveDataSelected();
261        }
262    
263        /**
264         * Do we do a frame loop or refresh current frame
265         *
266         * @return Do we do frame loop
267         */
268        protected boolean getDoFrameLoop() {
269            return doLoop;
270        }
271    
272        /**
273         * Set whether we do a frame loop or refresh current frame
274         *
275         * @param yesorno true to do frame loop
276         */
277        protected void setDoFrameLoop(boolean yesorno) {
278            doLoop = yesorno;
279            // Should this be in 
280            if (curRB != null) {
281                curRB.setSelected(yesorno);
282            }
283        }
284    
285        /**
286         * Did the user select current frame?
287         *
288         * @return Should we load current frame
289         */
290        protected boolean getDoCurrentFrame() {
291            return !getDoFrameLoop();
292        }
293    
294        /**
295         * Enable or disable the GUI widgets based on what has been
296         * selected.
297         */
298        protected void enableWidgets() {
299            getTimesList().setEnabled(getDoFrameLoop());
300        }
301    }