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