001    /*
002     * $Id: FrameChooser.java,v 1.8 2012/02/19 17:35:36 davep Exp $
003     *
004     * This file is part of McIDAS-V
005     *
006     * Copyright 2007-2012
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    
031    package edu.wisc.ssec.mcidasv.chooser;
032    
033    
034    import ucar.unidata.idv.*;
035    
036    import ucar.unidata.ui.ChooserList;
037    import ucar.unidata.ui.ChooserPanel;
038    
039    import java.awt.*;
040    import java.awt.event.*;
041    
042    import java.util.Vector;
043    
044    import java.beans.*;
045    
046    import javax.swing.*;
047    import javax.swing.border.*;
048    import javax.swing.event.*;
049    
050    import ucar.unidata.util.GuiUtils;
051    import ucar.unidata.util.Misc;
052    import ucar.unidata.util.PreferenceList;
053    
054    /**
055     *
056     * @author Unidata IDV Development Team
057     * @version $Revision: 1.8 $
058     */
059    public 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    }