001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2017
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.adde;
030
031import static javax.swing.GroupLayout.DEFAULT_SIZE;
032import static javax.swing.GroupLayout.PREFERRED_SIZE;
033import static javax.swing.GroupLayout.Alignment.BASELINE;
034import static javax.swing.GroupLayout.Alignment.LEADING;
035import static javax.swing.KeyStroke.getKeyStroke;
036import static javax.swing.LayoutStyle.ComponentPlacement.RELATED;
037
038import java.awt.BorderLayout;
039import java.awt.Color;
040import java.awt.Component;
041import java.awt.IllegalComponentStateException;
042import java.awt.Insets;
043import java.awt.Point;
044import java.awt.event.ActionEvent;
045import java.awt.event.ActionListener;
046import java.awt.event.KeyEvent;
047import java.awt.event.KeyListener;
048import java.text.SimpleDateFormat;
049import java.util.ArrayList;
050import java.util.Arrays;
051import java.util.Collections;
052import java.util.Date;
053import java.util.Hashtable;
054import java.util.Iterator;
055import java.util.List;
056import java.util.StringTokenizer;
057import java.util.Vector;
058import java.util.regex.Matcher;
059import java.util.regex.Pattern;
060
061import javax.swing.GroupLayout;
062import javax.swing.JButton;
063import javax.swing.JCheckBox;
064import javax.swing.JComboBox;
065import javax.swing.JComponent;
066import javax.swing.JDialog;
067import javax.swing.JLabel;
068import javax.swing.JOptionPane;
069import javax.swing.JPanel;
070import javax.swing.JSlider;
071import javax.swing.JTextField;
072import javax.swing.JToggleButton;
073import javax.swing.KeyStroke;
074import javax.swing.event.ChangeEvent;
075import javax.swing.event.ChangeListener;
076
077import org.slf4j.Logger;
078import org.slf4j.LoggerFactory;
079import org.w3c.dom.Element;
080
081import ucar.unidata.data.DataSelection;
082import ucar.unidata.data.imagery.AddeImageDescriptor;
083import ucar.unidata.data.imagery.AddeImageInfo;
084import ucar.unidata.data.imagery.BandInfo;
085import ucar.unidata.data.imagery.ImageDataSource;
086import ucar.unidata.data.imagery.ImageDataset;
087import ucar.unidata.idv.IdvResourceManager;
088import ucar.unidata.idv.chooser.IdvChooserManager;
089import ucar.unidata.idv.chooser.adde.AddeServer;
090import ucar.unidata.ui.LatLonWidget;
091import ucar.unidata.util.Format;
092import ucar.unidata.util.GuiUtils;
093import ucar.unidata.util.LogUtil;
094import ucar.unidata.util.Misc;
095import ucar.unidata.util.StringUtil;
096import ucar.unidata.util.TwoFacedObject;
097import ucar.unidata.xml.XmlNodeList;
098import ucar.unidata.xml.XmlResourceCollection;
099import ucar.unidata.xml.XmlUtil;
100import ucar.visad.UtcDate;
101
102import visad.DateTime;
103import visad.Gridded1DSet;
104import visad.VisADException;
105
106import edu.wisc.ssec.mcidas.AreaDirectory;
107import edu.wisc.ssec.mcidas.AreaDirectoryList;
108import edu.wisc.ssec.mcidas.McIDASException;
109import edu.wisc.ssec.mcidas.adde.AddeSatBands;
110import edu.wisc.ssec.mcidas.adde.AddeURL;
111import edu.wisc.ssec.mcidas.adde.AddeURLException;
112import edu.wisc.ssec.mcidasv.servermanager.EntryStore;
113import edu.wisc.ssec.mcidasv.ui.JCalendarDateEditor;
114import edu.wisc.ssec.mcidasv.ui.JCalendarPicker;
115import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
116
117/**
118 * Widget to select images from a remote ADDE server Displays a list of the
119 * descriptors (names) of the image datasets available for a particular ADDE
120 * group on the remote server.
121 * 
122 * @author Don Murray
123 */
124
125public class AddeImageChooser extends AddeChooser implements
126        ucar.unidata.ui.imagery.ImageSelector {
127
128    private static final Logger logger = LoggerFactory.getLogger(AddeImageChooser.class);
129
130    // TODO: get rid of this button right?
131    public static JToggleButton mineBtn = GuiUtils
132            .getToggleImageButton(
133                    "/edu/wisc/ssec/mcidasv/resources/icons/toolbar/internet-web-browser16.png",
134                    "/edu/wisc/ssec/mcidasv/resources/icons/toolbar/system-software-update16.png",
135                    0, 0, true);
136
137    /** _more_ */
138    public static final int SIZE_THRESHOLD = 50;
139
140    /** default magnification */
141    private static final int DEFAULT_MAG = 0;
142
143    /** flag for center */
144    private static final String PLACE_CENTER = "CENTER";
145
146    /** flag for upper left */
147    private static final String PLACE_ULEFT = "ULEFT";
148
149    /** flag for lower left */
150    private static final String PLACE_LLEFT = "LLEFT";
151
152    /** flag for upper right */
153    private static final String PLACE_URIGHT = "URIGHT";
154
155    /** flag for lower right */
156    private static final String PLACE_LRIGHT = "LRIGHT";
157
158    /** Property for the satband file */
159    protected static final String FILE_SATBAND = "SATBAND";
160
161    /** Property for image default value band */
162    protected static final String PROP_BAND = "BAND";
163
164    /** Property for image default value id */
165    protected static final String PROP_ID = "ID";
166
167    /** Property for image default value key */
168    protected static final String PROP_KEY = "key";
169
170    /** Property for image default value lat/lon */
171    protected static final String PROP_LATLON = "LATLON";
172
173    /** Property for image default value line/ele */
174    protected static final String PROP_LINELE = "LINELE";
175
176    /** Property for image default value loc */
177    protected static final String PROP_LOC = "LOC";
178
179    /** Property for image default value mag */
180    protected static final String PROP_MAG = "MAG";
181
182    /** Property for num */
183    protected static final String PROP_NUM = "NUM";
184
185    /** Property for image default value place */
186    protected static final String PROP_PLACE = "PLACE";
187
188    /** Property for image default value size */
189    protected static final String PROP_SIZE = "SIZE";
190
191    /** Property for image default value spac */
192    protected static final String PROP_SPAC = "SPAC";
193
194    /** Property for image default value unit */
195    protected static final String PROP_UNIT = "UNIT";
196
197    /** Property for image default value unit */
198    protected static final String PROP_NAV = "NAV";
199
200    /** This is the list of properties that are used in the advanced gui */
201    private static final String[] ADVANCED_PROPS = { PROP_UNIT, PROP_BAND,
202            PROP_PLACE, PROP_LOC, PROP_SIZE, PROP_MAG, PROP_NAV };
203
204    /** This is the list of labels used for the advanced gui */
205    private static final String[] ADVANCED_LABELS = { "Data Type:", "Channel:",
206            "Placement:", "Location:", "Image Size:", "Magnification:",
207            "Navigation Type:" };
208
209    /** Xml tag name for the defaults */
210    protected static final String TAG_DEFAULT = "default";
211
212    /** identifiere for the default value */
213    protected static final String VALUE_DEFAULT = "default";
214
215    /** Xml attr name for the defaults */
216    protected static final String ATTR_NAME = "name";
217
218    /** Xml attr name for the defaults */
219    protected static final String ATTR_PATTERN = "pattern";
220
221    /** flag for setting properties */
222    private boolean amSettingProperties = false;
223
224    /** Are we currently reading times */
225    private Object readTimesTask;
226
227    /** archive date */
228    protected String archiveDay = null;
229    
230    /** number of image times to list */
231    protected String numTimes = "all";
232
233    /** Holds the properties */
234    private JPanel propPanel;
235
236    /** Archive day selector button. */
237    protected JButton archiveDayBtn;
238
239    protected JButton numImagesButton;
240    
241    protected JTextField imageCountTextField;
242
243    /** Maps the PROP_ property name to the gui component */
244    private Hashtable propToComps = new Hashtable();
245
246    /**
247     * This is a list of hashtables, one per imagedefaults resource. The
248     * Hashtables map the pattern to the xml node
249     */
250    private List resourceMaps;
251
252    /** Holds the subsetting defaults */
253    private XmlResourceCollection addeDefaults;
254
255    /** archive date formatter */
256    private SimpleDateFormat archiveDayFormatter;
257
258    /** Input for lat/lon center point */
259    protected LatLonWidget latLonWidget;
260
261    /** Widget for the line magnfication in the advanced section */
262    protected JSlider lineMagSlider;
263
264    /** Label for the line mag. in the advanced section */
265    protected JLabel lineMagLbl;
266
267    /** Widget for the element magnfication in the advanced section */
268    protected JSlider elementMagSlider;
269
270    /** Label for the element mag. in the advanced section */
271    protected JLabel elementMagLbl;
272
273    /** base number of lines */
274    private double baseNumLines = 0.0;
275
276    /** size label */
277    JLabel sizeLbl;
278
279    /** base number of lines */
280    private double baseNumElements = 0.0;
281
282    /** Widget to hold the number of elements in the advanced */
283    JTextField numElementsFld;
284
285    /** Widget to hold the number of lines in the advanced */
286    JTextField numLinesFld;
287
288    /** Widget for the line center point in the advanced section */
289    protected JTextField centerLineFld;
290
291    /** Widget for the element center point in the advanced section */
292    protected JTextField centerElementFld;
293
294    /** _more_ */
295    private JToggleButton lockBtn;
296
297    /** full resolution button */
298    private JButton fullResBtn;
299
300    /** Identifier for the maximum number of bands */
301    int MAX_BANDS = 100;
302
303    /** The last AreaDirectory we have seen. */
304    private AreaDirectory lastAD;
305
306    /** The current AreaDirectory used for properties */
307    private AreaDirectory propertiesAD;
308
309    /** The previous AreaDirectory used for properties */
310    private AreaDirectory prevPropertiesAD;
311
312    /** Mapping of area directory to list of BandInfos */
313    protected Hashtable bandTable;
314
315    /** Mapping of band index to {@link edu.wisc.ssec.mcidas.AreaDirectory}. */
316    protected Hashtable bandDirs;
317
318    /**
319     * The list of currently loaded AddeImageDescriptor-s
320     */
321    protected Vector imageDescriptors;
322
323    /** maximum size for the widget */
324    private static final int MAX_SIZE = 700;
325
326    /** Widget for selecting image units */
327    protected JComboBox unitComboBox;
328
329    /** place label */
330    private JLabel placeLbl;
331
332    /** the place string */
333    private String place;
334
335    /** location panel */
336    private GuiUtils.CardLayoutPanel locationPanel;
337
338    /** Widget for selecting image nav type */
339    protected JComboBox navComboBox;
340
341    /**
342     * Mapping of sensor id (String) to hashtable that maps Integer band number
343     * to name
344     */
345    private Hashtable sensorToBandToName;
346
347    /** A flag so we can debug the new way of processing sat band file */
348    private boolean useSatBandInfo = true;
349
350    /** Used to parse the sat band file */
351    private AddeSatBands satBandInfo;
352
353    /** Widget for selecting the band */
354    protected JComboBox bandComboBox;
355
356    /** string for ALL */
357    protected static final String ALL = "ALL";
358
359    /** object for selecting all bands */
360    protected static final TwoFacedObject ALLBANDS = new TwoFacedObject(
361            "All Bands", ALL);
362
363    /** object for selecting all calibrations */
364    protected static final TwoFacedObject ALLUNITS = new TwoFacedObject(
365            "All Types", ALL);
366
367    /**
368     * Keep track of the lines to element ratio
369     */
370    private double linesToElements = 1.0;
371
372    /**
373     * limit of slider
374     */
375    private static final int SLIDER_MAX = 29;
376
377    private static final String DEFAULT_ARCHIVE_IMAGE_COUNT = "100";
378
379    /**
380     * the list of band infos
381     */
382    private List<BandInfo> bandInfos;
383
384    /**
385     * Construct an Adde image selection widget
386     * 
387     * 
388     * @param mgr
389     *            The chooser manager
390     * @param root
391     *            The chooser.xml node
392     */
393    public AddeImageChooser(IdvChooserManager mgr, Element root) {
394        super(mgr, root);
395//        AnnotationProcessor.process(this);
396        addDescComp(loadButton);
397
398        archiveDayBtn = new JButton("Select Day");
399        archiveDayBtn.addActionListener(e -> getArchiveDay());
400        archiveDayBtn.setToolTipText("Select a day for archive datasets");
401
402        numImagesButton = new JButton("List Images");
403        numImagesButton.addActionListener(e -> readTimes(false));
404        numImagesButton.setToolTipText("<html>By default, up to the 100 most " +
405            "recent times are listed.<br/><br/>For a different image count, " +
406            "provide a positive integer in<br/>the adjacent text box,  " +                
407            "or \"ALL\" for ALL relevant times.<br/><br/>Choosing ALL may be slow for" +
408            " datasets with many times.</html>");
409        
410        // Initialize the image count to default
411        imageCountTextField = new JTextField(AddeImageChooser.DEFAULT_ARCHIVE_IMAGE_COUNT, 4);
412        imageCountTextField.setToolTipText("<html>By default, up to the 100 most " +
413            "recent times are listed.<br/><br/>You may set this field to any positive " +
414            "integer, or the value ALL.<br/>Using ALL may take awhile for" +
415            " datasets with many times.</html>");
416
417        this.addeDefaults = getImageDefaults();
418    }
419
420    /**
421     * Number of absolute times to list in the chooser. 
422     * Must be a positive integer, or the word "ALL".
423     * Will throw up a dialog for invalid entries.
424     * 
425     * @return 0 for valid entries, -1 for invalid
426     */
427    
428    private int parseImageCount() {
429        String countStr = imageCountTextField.getText();
430        try {
431            int newCount = Integer.parseInt(countStr);
432            // Make sure it's reasonable 
433            if (newCount > 0) {
434                int addeParam = 0 - newCount + 1;
435                numTimes = "" + addeParam;
436            } else {
437                throw new NumberFormatException();
438            }
439        } catch (NumberFormatException nfe) {
440            // Still ok if they entered "ALL"
441            if (imageCountTextField.getText().isEmpty()) {
442                JOptionPane.showMessageDialog(this, 
443                        "Empty field, please enter a valid positive integer");
444                return -1;
445            }
446            if (! imageCountTextField.getText().equalsIgnoreCase("all")) {
447                JOptionPane.showMessageDialog(this, 
448                        "Invalid entry: " + imageCountTextField.getText());
449                return -1;
450            }
451            numTimes = imageCountTextField.getText();
452        }
453        return 0;
454    }
455
456    /**
457     * Get the xml resource collection that defines the image default xml
458     * 
459     * @return Image defaults resources
460     */
461    protected XmlResourceCollection getImageDefaults() {
462        return getIdv().getResourceManager().getXmlResources(
463                IdvResourceManager.RSC_IMAGEDEFAULTS);
464    }
465
466    /**
467     * Update labels, enable widgets, etc.
468     */
469    @Override protected void updateStatus() {
470        super.updateStatus();
471        if (getDoAbsoluteTimes()) {
472            setPropertiesState(getASelectedTime());
473        } else {
474            setPropertiesState(lastAD);
475        }
476
477        if (readTimesTask != null) {
478            if (taskOk(readTimesTask)) {
479                setStatus("Reading available times from server");
480            }
481        } else if ((getState() == STATE_CONNECTED) && getDoAbsoluteTimes() && !haveTimeSelected() && haveDescriptorSelected()) {
482            setStatus(MSG_TIMES);
483        }
484        enableWidgets();
485    }
486
487    /**
488     * Do we have times selected. Either we are doing absolute times and there
489     * are some selected in the list. Or we are doing relative times and we have
490     * done a connect to the server
491     * 
492     * @return Do we have times
493     */
494    public boolean timesOk() {
495        if (getDoAbsoluteTimes() && !haveTimeSelected()) {
496            return false;
497        }
498        return (lastAD != null);
499    }
500
501    /**
502     * Get the list of advanced property names
503     * 
504     * @return array of advanced property names
505     */
506    protected String[] getAdvancedProps() {
507        return ADVANCED_PROPS;
508    }
509
510    /**
511     * Get the list of advanced property labels
512     * 
513     * @return list of advanced property labels
514     */
515    protected String[] getAdvancedLabels() {
516        return ADVANCED_LABELS;
517    }
518
519    /**
520     * Convenience method for lazy people who don't want to call
521     * {@link ucar.unidata.util.LogUtil#logException(String, Throwable)}.
522     * 
523     * @param msg
524     *            log message
525     * @param exc
526     *            Exception to log
527     */
528    @Override public void logException(String msg, Exception exc) {
529        LogUtil.logException(msg, exc);
530    }
531
532    /**
533     * This allows derived classes to provide their own name for labeling, etc.
534     * 
535     * @return the dataset name
536     */
537    @Override public String getDataName() {
538        return "Image Data";
539    }
540
541    /**
542     * Get the descriptor widget label
543     * 
544     * @return label for the descriptor widget
545     */
546    @Override public String getDescriptorLabel() {
547        return "Image Type";
548    }
549        
550    /**
551     * Respond to a change in the descriptor list.
552     */
553    protected void checkSetNav() {
554        String descriptor = getDescriptor();
555        if (descriptor!=null) {
556            String[] suffixes = { "AMSU", "HIRS", "HRPT", "GAC", "LAC" };
557            for (int i=0; i<suffixes.length; i++) {
558                Pattern p = Pattern.compile("N\\d\\d" + suffixes[i]);
559                Matcher m = p.matcher(descriptor);
560                if (m.find()) {
561                    navComboBox.setSelectedIndex(1);
562                    break;
563                }
564            }
565        }
566    }
567
568    /**
569     * Get the name of the dataset.
570     * 
571     * @return descriptive name of the dataset.
572     */
573    public String getDatasetName() {
574        StringBuffer buf = new StringBuffer();
575        buf.append(getSelectedDescriptor());
576        if (bandComboBox != null && bandComboBox.getItemCount() > 1) {
577            buf.append(" (");
578            buf.append(bandComboBox.getSelectedItem());
579            buf.append(")");
580        }
581        return buf.toString();
582    }
583    
584    /**
585     * Check if we are ready to read times
586     * 
587     * @return true if times can be read
588     */
589    protected boolean canReadTimes() {
590        return haveDescriptorSelected();
591    }
592
593    /**
594     * Handle when the user presses the update button
595     * 
596     * @throws Exception
597     *             On badness
598     */
599    @Override public void handleUpdate() throws Exception {
600        if (getState() != STATE_CONNECTED) {
601            // If not connected then update the server list
602            updateServerList();
603        } else {
604            // If we are already connected then update the rest of the chooser
605            descriptorChanged();
606        }
607        updateStatus();
608    }
609
610    /**
611     * Do server connection stuff... override this with type-specific methods
612     */
613    @Override protected void readFromServer() {
614        archiveDay = null;
615        if (archiveDayBtn != null) {
616            archiveDayBtn.setText("Select Day");
617        }
618        readSatBands();
619        super.readFromServer();
620    }
621
622    /**
623     * Overwrite base class method to clear out the lastAD member here.
624     */
625    @Override protected void clearTimesList() {
626        lastAD = null;
627        super.clearTimesList();
628    }
629
630    /**
631     * Show the archive dialog. This method is not meant to be called but is
632     * public by reason of implementation (or insanity).
633     */
634    public void getArchiveDay() {
635        final JDialog dialog = GuiUtils.createDialog("Set Archive Day", true);
636        final JCalendarPicker picker = new JCalendarPicker(false);
637        if (archiveDay != null) {
638            if (archiveDayFormatter == null) {
639                archiveDayFormatter = new SimpleDateFormat(UtcDate.YMD_FORMAT);
640            }
641            Date d = null;
642            try {
643                d = archiveDayFormatter.parse(archiveDay);
644                picker.setDate(d);
645            } catch (Exception e) {
646                logException("parsing archive day " + archiveDay, e);
647            }
648        }
649
650        ActionListener listener = new ActionListener() {
651            public void actionPerformed(ActionEvent ae) {
652                String cmd = ae.getActionCommand();
653                if (cmd.equals(GuiUtils.CMD_REMOVE)) {
654                    archiveDay = null;
655                    archiveDayBtn.setText("Select Day");
656                    setDoAbsoluteTimes(true);
657                    descriptorChanged();
658                } else if (cmd.equals(GuiUtils.CMD_OK)) {
659                    try {
660                        archiveDay = picker.getUserSelectedDay();
661                        archiveDayBtn.setText(archiveDay);
662                    } catch (Exception e) {
663                    }
664                    // System.out.println("archiveDay = " + archiveDay);
665                    setDoAbsoluteTimes(true);
666                    descriptorChanged();
667                }
668                dialog.dispose();
669            }
670        };
671
672        final JCalendarDateEditor dateEditor =
673            (JCalendarDateEditor)picker.getDateChooser().getDateEditor();
674        dateEditor.getUiComponent().addKeyListener(new KeyListener() {
675            @Override public void keyTyped(KeyEvent e) { }
676
677            @Override public void keyPressed(KeyEvent e) { }
678
679            @Override public void keyReleased(KeyEvent e) {
680                if (!Color.RED.equals(dateEditor.getForeground())) {
681                    KeyStroke stroke =
682                        getKeyStroke(e.getKeyCode(), e.getModifiers());
683                    if (stroke.getKeyCode() == KeyEvent.VK_ENTER) {
684                        try {
685                            archiveDay = picker.getUserSelectedDay();
686                            archiveDayBtn.setText(archiveDay);
687                        } catch (Exception ex) {
688                            // nothing to do
689                        }
690                        setDoAbsoluteTimes(true);
691                        descriptorChanged();
692                        dialog.dispose();
693                    }
694                }
695            }
696        });
697
698        JPanel buttons = GuiUtils.makeButtons(listener, new String[] {
699                GuiUtils.CMD_OK, GuiUtils.CMD_REMOVE, GuiUtils.CMD_CANCEL });
700
701        JComponent contents = GuiUtils.topCenterBottom(GuiUtils.inset(GuiUtils
702                .lLabel("Please select a day for this dataset:"), 10), GuiUtils
703                .inset(picker, 10), buttons);
704        Point p = new Point(200, 200);
705        if (archiveDayBtn != null) {
706            try {
707                p = archiveDayBtn.getLocationOnScreen();
708            } catch (IllegalComponentStateException ice) {
709            }
710        }
711        dialog.setLocation(p);
712        dialog.getContentPane().add(contents);
713        dialog.pack();
714        dialog.setVisible(true);
715    }
716
717    /**
718     * Add the bottom advanced gui panel to the list
719     * 
720     * @param bottomComps
721     *            the bottom components
722     */
723    protected void getBottomComponents(List bottomComps) {
724
725        String[] propArray = getAdvancedProps();
726        String[] labelArray = getAdvancedLabels();
727        // List bottomComps = new ArrayList();
728        Insets dfltGridSpacing = new Insets(4, 0, 4, 0);
729        String dfltLblSpacing = " ";
730
731        boolean haveBand = Misc.toList(propArray).contains(PROP_BAND);
732        boolean haveNav = Misc.toList(propArray).contains(PROP_NAV);
733        for (int propIdx = 0; propIdx < propArray.length; propIdx++) {
734            JComponent propComp = null;
735            String prop = propArray[propIdx];
736            if (prop.equals(PROP_UNIT)) {
737                unitComboBox = new JComboBox();
738                addPropComp(PROP_UNIT, propComp = unitComboBox);
739                GuiUtils.setPreferredWidth(unitComboBox, 100);
740                if (haveBand) {
741                    bandComboBox = new JComboBox();
742                    bandComboBox.addActionListener(new ActionListener() {
743                        public void actionPerformed(ActionEvent e) {
744                            setAvailableUnits(propertiesAD, getSelectedBand());
745                        }
746                    });
747                    addPropComp(PROP_BAND, bandComboBox);
748
749                    propComp = GuiUtils.hbox(propComp, GuiUtils.inset(
750                            new JLabel("Channel:"), new Insets(0, 10, 0, 5)),
751                            bandComboBox, 5);
752                }
753            } else if (prop.equals(PROP_BAND)) {
754                // Moved to PROP_UNIT
755            } else if (prop.equals(PROP_PLACE)) {
756                // Moved to PROP_LOC
757            } else if (prop.equals(PROP_LOC)) {
758                placeLbl = GuiUtils.getFixedWidthLabel("");
759                changePlace(PLACE_CENTER);
760                addPropComp(PROP_PLACE, placeLbl);
761
762                latLonWidget = new LatLonWidget();
763                centerLineFld = new JTextField("", 3);
764                centerElementFld = new JTextField("", 3);
765
766                fullResBtn = GuiUtils.makeImageButton(
767                        "/auxdata/ui/icons/arrow_out.png", this,
768                        "setToFullResolution");
769                fullResBtn.setContentAreaFilled(false);
770                fullResBtn.setToolTipText("Set to full resolution");
771
772                // lockBtn =
773                // GuiUtils.getToggleImageButton(IdvUIManager.ICON_UNLOCK,
774                // IdvUIManager.ICON_LOCK, 0, 0, true);
775                // lockBtn.setContentAreaFilled(false);
776                // lockBtn.setSelected(true);
777                // lockBtn.setToolTipText(
778                // "Unlock to automatically change size when changing magnification");
779
780                final JButton centerPopupBtn = GuiUtils.getImageButton(
781                        "/auxdata/ui/icons/MapIcon16.png", getClass());
782                centerPopupBtn.setToolTipText("Center on current displays");
783                centerPopupBtn.addActionListener(new ActionListener() {
784                    public void actionPerformed(ActionEvent ae) {
785                        getIdv().getIdvUIManager().popupCenterMenu(
786                                centerPopupBtn, latLonWidget);
787                    }
788                });
789                JComponent centerPopup = GuiUtils.inset(centerPopupBtn,
790                        new Insets(0, 0, 0, 4));
791
792                GuiUtils.tmpInsets = dfltGridSpacing;
793                final JPanel latLonPanel = GuiUtils.hbox(new Component[] {
794                        GuiUtils.rLabel(" Lat:" + dfltLblSpacing),
795                        latLonWidget.getLatField(),
796                        GuiUtils.rLabel(" Lon:" + dfltLblSpacing),
797                        latLonWidget.getLonField(), new JLabel(" "),
798                        centerPopup });
799
800                final JPanel lineElementPanel = GuiUtils.hbox(new Component[] {
801                        GuiUtils.rLabel(" Line:" + dfltLblSpacing),
802                        centerLineFld,
803                        GuiUtils.rLabel(" Element:" + dfltLblSpacing),
804                        centerElementFld });
805
806                locationPanel = new GuiUtils.CardLayoutPanel();
807                locationPanel.addCard(latLonPanel);
808                locationPanel.addCard(lineElementPanel);
809
810                JButton locPosButton = GuiUtils.makeImageButton(
811                        "/auxdata/ui/icons/Refresh16.gif", this, "cyclePlace",
812                        null, true);
813
814                locPosButton.setToolTipText("Change place type");
815
816                JButton locTypeButton = GuiUtils.makeImageButton(
817                        "/auxdata/ui/icons/Refresh16.gif", locationPanel,
818                        "flip", null, true);
819                locTypeButton
820                        .setToolTipText("Toggle between Latitude/Longitude and Line/Element");
821
822                propComp = GuiUtils.hbox(new Component[] { locPosButton,
823                        placeLbl, locTypeButton, locationPanel }, 5);
824                addPropComp(PROP_LOC, propComp);
825            } else if (prop.equals(PROP_MAG)) {
826                boolean oldAmSettingProperties = amSettingProperties;
827                amSettingProperties = true;
828                ChangeListener lineListener = new javax.swing.event.ChangeListener() {
829                    public void stateChanged(ChangeEvent evt) {
830                        if (amSettingProperties) {
831                            return;
832                        }
833                        lineMagSliderChanged(!getLockButton().isSelected());
834                    }
835                };
836                ChangeListener elementListener = new ChangeListener() {
837                    public void stateChanged(javax.swing.event.ChangeEvent evt) {
838                        if (amSettingProperties) {
839                            return;
840                        }
841                        elementMagSliderChanged(true);
842                    }
843                };
844                JComponent[] lineMagComps = GuiUtils.makeSliderPopup(
845                        -SLIDER_MAX, SLIDER_MAX, 0, lineListener);
846                lineMagSlider = (JSlider) lineMagComps[1];
847                lineMagSlider.setMajorTickSpacing(1);
848                lineMagSlider.setSnapToTicks(true);
849                lineMagSlider.setExtent(1);
850                lineMagComps[0].setToolTipText("Change the line magnification");
851                JComponent[] elementMagComps = GuiUtils.makeSliderPopup(
852                        -SLIDER_MAX, SLIDER_MAX, 0, elementListener);
853                elementMagSlider = (JSlider) elementMagComps[1];
854                elementMagSlider.setExtent(1);
855                elementMagSlider.setMajorTickSpacing(1);
856                elementMagSlider.setSnapToTicks(true);
857                elementMagComps[0]
858                        .setToolTipText("Change the element magnification");
859                lineMagSlider
860                        .setToolTipText("Slide to set line magnification factor");
861                lineMagLbl = GuiUtils.getFixedWidthLabel(StringUtil.padLeft(
862                        "1", 4));
863                elementMagSlider
864                        .setToolTipText("Slide to set element magnification factor");
865                elementMagLbl = GuiUtils.getFixedWidthLabel(StringUtil.padLeft(
866                        "1", 4));
867                amSettingProperties = oldAmSettingProperties;
868
869                GuiUtils.tmpInsets = dfltGridSpacing;
870                /*
871                 * JPanel magPanel = GuiUtils.doLayout(new Component[] {
872                 * GuiUtils.rLabel("Line:" + dfltLblSpacing), lineMagLbl,
873                 * GuiUtils.inset(lineMagComps[0], new Insets(0, 4, 0, 0)),
874                 * GuiUtils.rLabel("   Element:" + dfltLblSpacing),
875                 * elementMagLbl, GuiUtils.inset(elementMagComps[0], new
876                 * Insets(0, 4, 0, 0)), }, 6, GuiUtils.WT_N, GuiUtils.WT_N);
877                 */
878                /*
879                 * JPanel magPanel = GuiUtils.doLayout(new Component[] {
880                 * lineMagLbl, GuiUtils.inset(lineMagComps[0], new Insets(0, 4,
881                 * 0, 0)), new JLabel("    X "), elementMagLbl,
882                 * GuiUtils.inset(elementMagComps[0], new Insets(0, 4, 0, 0)),
883                 * }, 6, GuiUtils.WT_N, GuiUtils.WT_N);
884                 */
885
886                JPanel magPanel = GuiUtils.doLayout(
887                        new Component[] {
888                                lineMagLbl,
889                                GuiUtils.inset(lineMagComps[0], new Insets(0,
890                                        4, 0, 0)),
891                                new JLabel("    X"),
892                                elementMagLbl,
893                                GuiUtils.inset(elementMagComps[0], new Insets(
894                                        0, 4, 0, 0)),
895                                GuiUtils.inset(getLockButton(), new Insets(0,
896                                        10, 0, 0)) }, 7, GuiUtils.WT_N,
897                        GuiUtils.WT_N);
898
899                addPropComp(PROP_MAG, propComp = magPanel);
900                if (haveNav) {
901                    navComboBox = new JComboBox();
902                    GuiUtils.setListData(navComboBox, Misc.newList(
903                            new TwoFacedObject("Default", "X"),
904                            new TwoFacedObject("Lat/Lon", "LALO")));
905                    addPropComp(PROP_NAV, navComboBox);
906                    boolean showNav = false;
907                    showNav = getProperty("includeNavComp", false);
908                    if (showNav) {
909                        propComp = GuiUtils.hbox(propComp, GuiUtils.inset(
910                                new JLabel("Navigation Type:"), new Insets(0,
911                                        10, 0, 5)), navComboBox, 5);
912                    }
913                }
914            } else if (prop.equals(PROP_SIZE)) {
915                numLinesFld = new JTextField("", 4);
916                numElementsFld = new JTextField("", 4);
917                numLinesFld.setToolTipText("Number of lines");
918                numElementsFld.setToolTipText("Number of elements");
919                GuiUtils.tmpInsets = dfltGridSpacing;
920                sizeLbl = GuiUtils.lLabel("");
921
922                /*
923                 * JPanel sizePanel = GuiUtils.left(GuiUtils.doLayout(new
924                 * Component[] { GuiUtils.rLabel("Lines:" + dfltLblSpacing),
925                 * numLinesFld, GuiUtils.rLabel(" Elements:" + dfltLblSpacing),
926                 * numElementsFld, new JLabel(" "), sizeLbl }, 6, GuiUtils.WT_N,
927                 * GuiUtils.WT_N));
928                 */
929
930                JPanel sizePanel = GuiUtils.left(GuiUtils.doLayout(
931                        new Component[] { numLinesFld, new JLabel(" X "),
932                                numElementsFld, fullResBtn, /* new JLabel(" "), */
933                                sizeLbl }, 5, GuiUtils.WT_N, GuiUtils.WT_N));
934                addPropComp(PROP_SIZE, propComp = sizePanel);
935            }
936
937            if (propComp != null) {
938                bottomComps.add(GuiUtils.rLabel(labelArray[propIdx]));
939                bottomComps.add(GuiUtils.left(propComp));
940            }
941
942        }
943
944        GuiUtils.tmpInsets = new Insets(3, 4, 0, 4);
945        propPanel = GuiUtils.doLayout(bottomComps, 2, GuiUtils.WT_N,
946                GuiUtils.WT_N);
947        enableWidgets();
948    }
949
950    /**
951     * Get the "lock" button
952     * 
953     * @return the lock button
954     */
955    private JToggleButton getLockButton() {
956        if (lockBtn == null) {
957            lockBtn = GuiUtils.getToggleImageButton(
958                    "/auxdata/ui/icons/Linked.gif",
959                    "/auxdata/ui/icons/Unlinked.gif", 0, 0, true);
960            lockBtn.setContentAreaFilled(false);
961            lockBtn.setSelected(true);
962            lockBtn
963                    .setToolTipText("Unlock to automatically change size when changing magnification");
964        }
965        return lockBtn;
966
967    }
968
969    /**
970     * Set to full resolution
971     */
972    public void setToFullResolution() {
973
974        if (propertiesAD == null) {
975            return;
976        }
977        amSettingProperties = true;
978        numLinesFld.setText("" + propertiesAD.getLines());
979        numElementsFld.setText("" + propertiesAD.getElements());
980        changePlace(PLACE_CENTER);
981        if (useLatLon()) {
982            locationPanel.flip();
983        }
984        centerLineFld.setText("" + (propertiesAD.getLines() / 2));
985        centerElementFld.setText("" + (propertiesAD.getElements() / 2));
986
987        setMagSliders(1, 1);
988        amSettingProperties = false;
989
990    }
991
992    /**
993     * Cycle the place
994     */
995    public void cyclePlace() {
996        if (place.equals(PLACE_CENTER)) {
997            changePlace(PLACE_ULEFT);
998        } else {
999            changePlace(PLACE_CENTER);
1000        }
1001    }
1002
1003    /**
1004     * Change the place
1005     * 
1006     * @param newPlace
1007     *            new place
1008     */
1009    public void changePlace(String newPlace) {
1010        this.place = newPlace;
1011        String s = translatePlace(place) + "=";
1012        placeLbl.setText(StringUtil.padRight(s, 12));
1013    }
1014
1015    /**
1016     * _more_
1017     * 
1018     * @param recomputeLineEleRatio
1019     *            _more_
1020     */
1021    protected void elementMagSliderChanged(boolean recomputeLineEleRatio) {
1022        int value = getElementMagValue();
1023        if ((Math.abs(value) < SLIDER_MAX)) {
1024            int lineMag = getLineMagValue();
1025            if (lineMag > value) {
1026                linesToElements = Math.abs(lineMag / (double) value);
1027            } else {
1028                linesToElements = Math.abs((double) value / lineMag);
1029            }
1030        }
1031        // System.out.println(" changelistener: linesToElements = " +
1032        // linesToElements);
1033        elementMagLbl.setText(StringUtil.padLeft("" + value, 4));
1034        if (!getLockButton().isSelected()) {
1035            if (value > 0) {
1036                numElementsFld.setText("" + (int) (baseNumElements * value));
1037            } else {
1038                numElementsFld.setText(""
1039                        + (int) (baseNumElements / (double) -value));
1040            }
1041        }
1042    }
1043
1044    /**
1045     * Handle the line mag slider changed event
1046     * 
1047     * 
1048     * @param autoSetSize
1049     *            _more_
1050     */
1051    protected void lineMagSliderChanged(boolean autoSetSize) {
1052        try {
1053            int value = getLineMagValue();
1054            lineMagLbl.setText(StringUtil.padLeft("" + value, 4));
1055            if (autoSetSize) {
1056                if (value > 0) {
1057                    numLinesFld.setText("" + (int) (baseNumLines * value));
1058                } else {
1059                    numLinesFld.setText(""
1060                            + (int) (baseNumLines / (double) -value));
1061                }
1062            }
1063
1064            if (value == 1) { // special case
1065                if (linesToElements < 1.0) {
1066                    value = (int) (-value / linesToElements);
1067                } else {
1068                    value = (int) (value * linesToElements);
1069                }
1070
1071            } else if (value > 1) {
1072                value = (int) (value * linesToElements);
1073
1074            } else {
1075                value = (int) (value / linesToElements);
1076            }
1077
1078            value = (value > 0) ? value - 1 : value + 1; // since slider is one
1079                                                            // off
1080            amSettingProperties = true;
1081            elementMagSlider.setValue(value);
1082            amSettingProperties = false;
1083            elementMagSliderChanged(false);
1084        } catch (Exception exc) {
1085            logException("Setting line magnification", exc);
1086        }
1087        // amSettingProperties = false;
1088    }
1089
1090    /**
1091     * Get the value of the line magnification slider.
1092     * 
1093     * @return The magnification value for the line
1094     */
1095    protected int getLineMagValue() {
1096        return getMagValue(lineMagSlider);
1097    }
1098
1099    /**
1100     * Get the value of the element magnification slider.
1101     * 
1102     * @return The magnification value for the element
1103     */
1104    protected int getElementMagValue() {
1105        return getMagValue(elementMagSlider);
1106    }
1107
1108    /**
1109     * Handle the absolute time selection changing
1110     */
1111    @Override protected void absoluteTimesSelectionChanged() {
1112        if (!getDoAbsoluteTimes()) {
1113            return;
1114        }
1115        if (getIdv().getProperty("idv.chooser.addeimage.updateontimechange",
1116                true)) {
1117            setPropertiesState(getASelectedTime(), false);
1118        }
1119    }
1120
1121    /**
1122     * Set the relative and absolute extra components.
1123     */
1124    @Override protected JPanel makeTimesPanel() {
1125        JPanel panel =
1126            super.makeTimesPanel(false, true, getIdv().getUseTimeDriver());
1127        underTimelistPanel.add(BorderLayout.WEST, numImagesButton);
1128        underTimelistPanel.add(BorderLayout.CENTER, imageCountTextField);
1129        underTimelistPanel.add(BorderLayout.EAST, archiveDayBtn);
1130        return panel;
1131    }
1132
1133    /**
1134     * Associates the given JComponent with the PROP_ property identified by the
1135     * given propId
1136     * 
1137     * @param propId
1138     *            The property
1139     * @param comp
1140     *            The gui component that allows the user to set the property
1141     * 
1142     * @return Just returns the given comp
1143     */
1144    protected JComponent addPropComp(String propId, JComponent comp) {
1145        Object oldComp = propToComps.get(propId);
1146        if (oldComp != null) {
1147            throw new IllegalStateException("Already have a component defined:"
1148                    + propId);
1149        }
1150        propToComps.put(propId, comp);
1151        return comp;
1152    }
1153
1154    /**
1155     * Should we use the user supplied property
1156     * 
1157     * @param propId
1158     *            The property
1159     * 
1160     * @return Should use the value from the advanced widget
1161     */
1162    protected boolean usePropFromUser(String propId) {
1163        if (propToComps.get(propId) == null) {
1164            return false;
1165        }
1166        return true;
1167    }
1168
1169    /**
1170     * Get one of the selected times.
1171     * 
1172     * @return One of the selected times.
1173     */
1174    protected AreaDirectory getASelectedTime() {
1175        if (haveTimeSelected()) {
1176            List selected = getSelectedAbsoluteTimes();
1177            if (selected.size() > 0) {
1178                AddeImageDescriptor aid = (AddeImageDescriptor) selected.get(0);
1179                if (aid != null) {
1180                    return aid.getDirectory();
1181                }
1182            }
1183        }
1184        return null;
1185    }
1186
1187    /**
1188     * Enable or disable the GUI widgets based on what has been selected.
1189     */
1190    @Override protected void enableWidgets() {
1191        boolean descriptorState = ((getState() == STATE_CONNECTED) && canReadTimes());
1192
1193        for (int i = 0; i < compsThatNeedDescriptor.size(); i++) {
1194            JComponent comp = (JComponent) compsThatNeedDescriptor.get(i);
1195            GuiUtils.enableTree(comp, descriptorState);
1196        }
1197
1198        boolean timesOk = timesOk();
1199        if (propPanel != null) {
1200            GuiUtils.enableTree(propPanel, timesOk);
1201        }
1202
1203        // Require times to be selected
1204        GuiUtils.enableTree(loadButton, descriptorState && timesOk);
1205
1206        if (timesOk) {
1207            checkCenterEnabled();
1208        }
1209        checkTimesLists();
1210
1211        // TODO: This is temporary... absolute times on Windows makes the local
1212        // servers choke
1213        // Update: this works now, but leave it here as a reminder
1214        // boolean localWindowsServer = isLocalServer() &&
1215        // System.getProperty("os.name").startsWith("Windows");
1216        // setDoAbsoluteTimes(getDoAbsoluteTimes() && !localWindowsServer);
1217
1218        enableAbsoluteTimesList(getDoAbsoluteTimes() && descriptorState);
1219
1220        getRelativeTimesChooser().setEnabled(
1221                !getDoAbsoluteTimes() && descriptorState);
1222
1223        if (drivercbx != null) {
1224//            logger.trace("set drivercbx={}", anyTimeDrivers() && descriptorState);
1225            drivercbx.setEnabled(anyTimeDrivers() && descriptorState);
1226        }
1227        revalidate();
1228    }
1229
1230    /**
1231     * Check if we are using the lat/lon widget
1232     * 
1233     * @return true if we are using the lat/lon widget
1234     */
1235    protected boolean useLatLon() {
1236        return locationPanel.getVisibleIndex() == 0;
1237    }
1238
1239    /**
1240     * Enable or disable the center lat/lon and line/element widgets
1241     */
1242    protected void checkCenterEnabled() {
1243        // NOT NOW
1244        if (true) {
1245            return;
1246        }
1247
1248        boolean usingLatLon = useLatLon();
1249
1250        latLonWidget.getLatField().setEnabled(usingLatLon);
1251        latLonWidget.getLonField().setEnabled(usingLatLon);
1252        // centerLatLbl.setEnabled(usingLatLon);
1253        // centerLonLbl.setEnabled(usingLatLon);
1254
1255        centerLineFld.setEnabled(!usingLatLon);
1256        centerElementFld.setEnabled(!usingLatLon);
1257        // centerLineLbl.setEnabled( !usingLatLon);
1258        // centerElementLbl.setEnabled( !usingLatLon);
1259
1260    }
1261
1262    /**
1263     * Get the selected calibration unit.
1264     * 
1265     * @return the selected calibration unit
1266     */
1267    protected String getSelectedUnit() {
1268        if (unitComboBox==null || unitComboBox.getSelectedItem()==null) return "";
1269        String selection = (String) ((TwoFacedObject) unitComboBox.getSelectedItem()).getId();
1270        return selection;
1271    }
1272
1273    /**
1274     * Get the data type for this chooser
1275     * 
1276     * @return the data type
1277     */
1278    @Override public String getDataType() {
1279        return "IMAGE";
1280    }
1281
1282    /**
1283     * Get a description of the currently selected dataset
1284     * 
1285     * @return a description of the currently selected dataset
1286     * @deprecated use #getDatasetName()
1287     */
1288    @Deprecated public String getDatasetDescription() {
1289        return getDatasetName();
1290    }
1291
1292    /**
1293     * Read the set of image times available for the current server/group/type
1294     * This method is a wrapper, setting the wait cursor and wrapping the call
1295     * to {@link #readTimesInner(boolean)}; in a try/catch block
1296     */
1297    @Override public void readTimes() {
1298        readTimes(false);
1299    }
1300
1301    public void readTimes(boolean forceAll) {
1302        
1303        // Make sure there is a valid entry in the image count text field
1304        if (parseImageCount() < 0) return;
1305        
1306        clearTimesList();
1307        if (!canReadTimes()) {
1308            return;
1309        }
1310        Misc.run(new Runnable() {
1311            public void run() {
1312                updateStatus();
1313                showWaitCursor();
1314                try {
1315                    readTimesInner(forceAll);
1316                    checkSetNav();
1317                } catch (Exception e) {
1318                    handleConnectionError(e);
1319                }
1320                showNormalCursor();
1321                updateStatus();
1322            }
1323        });
1324    }
1325
1326    /**
1327     * _more_
1328     */
1329    @Override public void doCancel() {
1330        readTimesTask = null;
1331        setState(STATE_UNCONNECTED);
1332        super.doCancel();
1333    }
1334
1335    /** locking mutex */
1336    private Object MUTEX = new Object();
1337
1338    /**
1339     * Set the list of dates/times based on the image selection
1340     * 
1341     */
1342    protected void readTimesInner(boolean forceAll) {
1343        String descriptor = getDescriptor();
1344        // String archivePosition = forceAll ? "all" : numTimes;
1345        String archivePosition = numTimes;
1346        String pos = (getDoAbsoluteTimes() || (archiveDay != null))
1347                      ? archivePosition
1348                      : "0";
1349
1350        StringBuffer addeCmdBuff = getGroupUrl(REQ_IMAGEDIR, getGroup());
1351        String id = getSelectedStation();
1352        if (id != null) {
1353            appendKeyValue(addeCmdBuff, PROP_ID, id);
1354        }
1355        appendKeyValue(addeCmdBuff, PROP_DESCR, descriptor);
1356        appendKeyValue(addeCmdBuff, PROP_POS, "" + pos);
1357        if (archiveDay != null) {
1358            appendKeyValue(addeCmdBuff, PROP_DAY, archiveDay);
1359        }
1360        String url = addeCmdBuff.toString();
1361        readTimesTask = startTask();
1362        updateStatus();
1363        Object task = readTimesTask;
1364        try {
1365            AreaDirectoryList adir = new AreaDirectoryList(url);
1366            // Make sure no other loads are occurred
1367            boolean ok = stopTaskAndIsOk(task);
1368            if (!Misc.equals(readTimesTask, task) || !ok) {
1369                return;
1370            }
1371            readTimesTask = null;
1372
1373            synchronized (MUTEX) {
1374                // Array of AreaDirectory-s sorted by time
1375                AreaDirectory[][] dirs = adir.getSortedDirs();
1376                int numImages = dirs.length;
1377                imageDescriptors = new Vector();
1378                // TODO: Add a setBands method to AreaDirectory to replace bandtable
1379                bandTable = new Hashtable(numImages);
1380                int len = dirs[0].length;
1381                bandDirs = new Hashtable(len);
1382                for (int i = 0; i < len; i++) {
1383                    AreaDirectory dir = dirs[0][i];
1384                    int ilen = dirs[0][i].getBands().length;
1385                    for(int j = 0; j < ilen; j++){
1386                        int bindex = dirs[0][i].getBands()[j];
1387                        bandDirs.put(bindex, dir);
1388                    }
1389                }
1390                lastAD = null;
1391                for (int i = 0; i < numImages; i++) {
1392                    int bandIndex = 0;
1393                    lastAD = (AreaDirectory) dirs[i][0];
1394                    int[] allBands = new int[MAX_BANDS];
1395                    Vector[] allCals = new Vector[MAX_BANDS];
1396                    for (int j = 0; j < dirs[i].length; j++) {
1397                        int nbands = dirs[i][j].getNumberOfBands();
1398                        int[] abands = dirs[i][j].getBands();
1399                        Vector[] vb = dirs[i][j].getCalInfo();
1400                        for (int k = 0; k < nbands; k++) {
1401                            allBands[bandIndex] = abands[k];
1402                            allCals[bandIndex++] = vb[k];
1403                        }
1404                    }
1405                    int[] bands = new int[bandIndex];
1406                    System.arraycopy(allBands, 0, bands, 0, bandIndex);
1407                    Vector[] cals = new Vector[bandIndex];
1408                    System.arraycopy(allCals, 0, cals, 0, bandIndex);
1409                    lastAD.setCalInfo(cals);
1410                    bandTable.put(lastAD, bands);
1411                    AddeImageDescriptor aid = new AddeImageDescriptor(lastAD, null);
1412                    imageDescriptors.add(aid);
1413                }
1414
1415                Collections.sort(imageDescriptors);
1416                if (getDoAbsoluteTimes()) {
1417                    setAbsoluteTimes(imageDescriptors);
1418                }
1419                // revalidate();
1420            }
1421            setState(STATE_CONNECTED);
1422        } catch (McIDASException e) {
1423            logger.warn("Exception while reading times from server", e);
1424            stopTask(task);
1425            readTimesTask = null;
1426            handleConnectionError("\nError reading times", e);
1427            // you want this step because readTimes() will call updateStatus(),
1428            // and since we already have a server and dataset, all the user needs
1429            // to do is select an image type (descriptor).
1430            setState(STATE_CONNECTED);
1431        }
1432    }
1433
1434    /**
1435     * Set the selected times in the times list based on the input times
1436     * 
1437     * @param times Input times.
1438     */
1439    @Override protected void setSelectedTimes(DateTime[] times) {
1440        if ((times == null) || (times.length == 0)) {
1441            return;
1442        }
1443        DateTime[] imageTimes = new DateTime[times.length];
1444
1445        if (imageDescriptors != null) {
1446            imageTimes = new DateTime[imageDescriptors.size()];
1447            for (int idIdx = 0; idIdx < imageDescriptors.size(); idIdx++) {
1448                AddeImageDescriptor aid = (AddeImageDescriptor) imageDescriptors.get(idIdx);
1449                imageTimes[idIdx] = aid.getImageTime();
1450            }
1451        } else {
1452            imageTimes = times;
1453        }
1454        if (imageTimes.length > 0) {
1455            try {
1456                Gridded1DSet imageSet    = DateTime.makeTimeSet(imageTimes);
1457                int          numTimes    = times.length;
1458                double[][]   timesValues = new double[1][numTimes];
1459                for (int i = 0; i < times.length; i++) {
1460                    timesValues[0][i] = times[i].getValue(imageSet.getSetUnits()[0]);
1461                }
1462                setSelectedAbsoluteTimes(imageSet.doubleToIndex(timesValues));
1463                absoluteTimesSelectionChanged();
1464            } catch (VisADException ve) {
1465                logException("Unable to set times from display", ve);
1466            }
1467        }
1468    }
1469
1470    /**
1471     * Set the center location portion of the request. If the input from the
1472     * widget is null, use the centerpoint from the image descriptor.
1473     * 
1474     * @param aid Image descriptor for the image.
1475     */
1476    protected void setCenterLocation(AddeImageDescriptor aid) {
1477        String latPoint = "";
1478        String lonPoint = "";
1479        if (aid != null) {
1480            AreaDirectory ad = aid.getDirectory();
1481            latPoint = "" + ad.getCenterLatitude();
1482            lonPoint = "" + ad.getCenterLongitude();
1483        }
1484        if (!latPoint.trim().equals("")) {
1485            latLonWidget.setLat(latPoint);
1486        }
1487        if (!lonPoint.trim().equals("")) {
1488            latLonWidget.setLon(lonPoint);
1489        }
1490    }
1491
1492    /**
1493     * get the adde server grup type to use
1494     * 
1495     * @return group type
1496     */
1497    @Override protected String getGroupType() {
1498        return AddeServer.TYPE_IMAGE;
1499    }
1500
1501    /**
1502     * Does this selector have all of its state set to load in data
1503     * 
1504     * @return Has the user chosen everything they need to choose to load data
1505     */
1506    @Override protected boolean getGoodToGo() {
1507        // if(!super.getGoodToGo()) return false;
1508        if (getDoAbsoluteTimes()) {
1509            return getHaveAbsoluteTimesSelected();
1510        } else {
1511            return canReadTimes() && (lastAD != null);
1512        }
1513    }
1514
1515    /**
1516     * Returns a list of the images to load or null if none have been selected.
1517     * 
1518     * @return list get the list of image descriptors
1519     */
1520    @Override public List getImageList() {
1521        if (!timesOk()) {
1522            return null;
1523        }
1524        List images = new ArrayList();
1525        String defaultBand = getDefault(PROP_BAND, ALL);
1526        try {
1527            if (getDoRelativeTimes()) {
1528                AddeImageDescriptor firstDescriptor = (AddeImageDescriptor) imageDescriptors.get(0);
1529                AreaDirectory ad = firstDescriptor.getDirectory();
1530                int[] bands    = (int[]) bandTable.get(ad);
1531                bandInfos = makeBandInfos(ad, bands);
1532                int[] relativeTimesIndices = getRelativeTimeIndices();
1533                for (int i = 0; i < relativeTimesIndices.length; i++) {
1534                    AddeImageDescriptor aid = new AddeImageDescriptor(relativeTimesIndices[i], firstDescriptor);
1535                    AddeImageInfo aii = makeImageInfo(aid.getDirectory(), true, relativeTimesIndices[i]);
1536                    aii.setDebug(EntryStore.isAddeDebugEnabled(false));
1537                    if (aii.getBand() == null) aii.setBand(defaultBand);
1538                    aid.setImageInfo(aii);
1539                    aid.setSource(aii.getURLString());
1540                    images.add(aid);
1541                }
1542            } else {
1543                List selectedTimes = getSelectedAbsoluteTimes();
1544                for (int i = 0; i < selectedTimes.size(); i++) {
1545                    AddeImageDescriptor aid = new AddeImageDescriptor((AddeImageDescriptor) selectedTimes.get(i));
1546                    AddeImageInfo aii = makeImageInfo(aid.getDirectory(), false, i);
1547                    aii.setDebug(EntryStore.isAddeDebugEnabled(false));
1548                    if (aii.getBand() == null) aii.setBand(defaultBand);
1549                    aid.setImageInfo(aii);
1550                    aid.setSource(aii.getURLString());
1551                    images.add(aid);
1552                }
1553            }
1554        } catch (Exception exc) {
1555            logException("Error occured", exc);
1556            return null;
1557        }
1558        return images;
1559    }
1560
1561    /**
1562     * Process the image defaults resources
1563     */
1564    protected void initializeAddeDefaults() {
1565        resourceMaps = new ArrayList();
1566        if (addeDefaults == null) {
1567            return;
1568        }
1569        for (int resourceIdx = 0; resourceIdx < addeDefaults.size(); resourceIdx++) {
1570            Element root = addeDefaults.getRoot(resourceIdx);
1571            if (root == null) {
1572                continue;
1573            }
1574            Hashtable resourceMap = new Hashtable();
1575            resourceMaps.add(resourceMap);
1576
1577            XmlNodeList defaultNodes = XmlUtil.getElements(root, TAG_DEFAULT);
1578            for (int nodeIdx = 0; nodeIdx < defaultNodes.size(); nodeIdx++) {
1579                Element dfltNode = (Element) defaultNodes.item(nodeIdx);
1580                String pattern = XmlUtil.getAttribute(dfltNode, ATTR_PATTERN,
1581                        (String) null);
1582                if (pattern == null) {
1583                    pattern = XmlUtil.getAttribute(dfltNode, ATTR_NAME);
1584                }
1585                if (pattern != null) {
1586                    pattern = pattern.toLowerCase();
1587                }
1588                resourceMap.put(pattern, dfltNode);
1589            }
1590        }
1591    }
1592
1593    /**
1594     * Get the default value for a key
1595     * 
1596     * @param property
1597     *            property (key type)
1598     * @param dflt
1599     *            default value
1600     * @return value for key or dflt if not found
1601     */
1602    protected String getDefault(String property, String dflt) {
1603        if (resourceMaps == null) {
1604            initializeAddeDefaults();
1605        }
1606        property = property.toLowerCase();
1607
1608        String userDefault = null;
1609        String server = getServer();
1610        String group = getGroup();
1611        String descriptor = getDescriptor();
1612        String[] keys = { userDefault, server + ":" + group + "/" + descriptor,
1613                group + "/" + descriptor, server + ":" + group + "/*",
1614                group + "/*", server + ":*/" + descriptor, "*/" + descriptor,
1615                descriptor, server + ":*/*", server, "*" };
1616
1617        if (server != null) {
1618            if (PROP_USER.equals(property))
1619                return getLastAddedUser();
1620            if (PROP_PROJ.equals(property))
1621                return getLastAddedProj();
1622        }
1623
1624        for (int resourceIdx = 0; resourceIdx < resourceMaps.size(); resourceIdx++) {
1625            Hashtable resourceMap = (Hashtable) resourceMaps.get(resourceIdx);
1626            for (int keyIdx = 0; keyIdx < keys.length; keyIdx++) {
1627                String key = keys[keyIdx];
1628                if (key == null) {
1629                    continue;
1630                }
1631                key = key.toLowerCase();
1632                Element defaultNode = (Element)resourceMap.get(key);
1633                if (defaultNode == null) {
1634                    continue;
1635                }
1636                String value = XmlUtil.getAttribute(defaultNode, property, (String)null);
1637                if (value == null) {
1638                    continue;
1639                }
1640                if (value.equals(VALUE_DEFAULT)) {
1641                    return dflt;
1642                } else {
1643                    return value;
1644                }
1645            }
1646        }
1647        return dflt;
1648    }
1649
1650    /**
1651     * Get the image size string from the directory and defaults
1652     * 
1653     * @param ad
1654     *            image directory
1655     * @return request size
1656     */
1657    protected String getSizeString(AreaDirectory ad) {
1658        String retString = MAX_SIZE + " " + MAX_SIZE;
1659        if (ad != null) {
1660            int x = ad.getElements();
1661            int y = ad.getLines();
1662            if ((x < MAX_SIZE) && (y < MAX_SIZE)) {
1663                retString = x + " " + y;
1664            } else if ((x >= MAX_SIZE) && (y >= MAX_SIZE)) {
1665                retString = MAX_SIZE + " " + MAX_SIZE;
1666            } else if ((x >= MAX_SIZE) && (y < MAX_SIZE)) {
1667                retString = MAX_SIZE + " " + y;
1668            } else if ((x < MAX_SIZE) && (y >= MAX_SIZE)) {
1669                retString = x + " " + MAX_SIZE;
1670            }
1671        }
1672        return retString;
1673    }
1674
1675    /**
1676     * Check for valid lat/lon values
1677     * 
1678     * @return true if values are valid
1679     */
1680    protected boolean checkForValidValues() {
1681        if (usePropFromUser(PROP_LOC)) {
1682            if (useLatLon()) {
1683                String msg = latLonWidget.isValidValues();
1684                if ((msg != null) && (msg.length() > 0)) {
1685                    LogUtil.userMessage(msg);
1686                    return false;
1687                }
1688            }
1689        }
1690        return true;
1691    }
1692
1693    /**
1694     * Get the list of properties for the base URL
1695     * 
1696     * @return list of properties
1697     */
1698    protected String[] getBaseUrlProps() {
1699        return new String[] { PROP_DESCR, PROP_UNIT, PROP_SPAC, PROP_BAND,
1700                PROP_NAV, PROP_USER, PROP_PROJ, };
1701    }
1702
1703    /**
1704     * A utility that creates the url argument line for the given set of
1705     * properties.
1706     * 
1707     * @param props
1708     *            The PROP_ properties to make the request string for
1709     * @param ad
1710     *            The area directory.
1711     * 
1712     * @return The adde request string
1713     */
1714    protected String makeProps(String[] props, AreaDirectory ad) {
1715        StringBuffer buf = new StringBuffer();
1716        for (int propIdx = 0; propIdx < props.length; propIdx++) {
1717            appendKeyValue(buf, props[propIdx],
1718                    getPropValue(props[propIdx], ad));
1719        }
1720        return buf.toString();
1721    }
1722
1723    /**
1724     * Get the value for the given property. This can either be the value
1725     * supplied by the end user through the advanced GUI or is the default
1726     * 
1727     * @param prop
1728     *            The property
1729     * @param ad
1730     *            The AreaDirectory
1731     * 
1732     * @return The value of the property to use in the request string
1733     */
1734    protected String getPropValue(String prop, AreaDirectory ad) {
1735        if (usePropFromUser(prop)) {
1736            return getUserPropValue(prop, ad);
1737        }
1738
1739        // Handle size specially because we really want to get the minimum of
1740        // the default and the ad size
1741        if (PROP_SIZE.equals(prop)) {
1742            int[] size = getSize(ad);
1743            return size[0] + " " + size[1];
1744        }
1745
1746        return getDefault(prop, getDefaultPropValue(prop, ad, false));
1747    }
1748
1749    /**
1750     * Get the user supplied property value for the adde request string
1751     * 
1752     * @param prop
1753     *            The property
1754     * @param ad
1755     *            The AreaDirectory
1756     * 
1757     * @return The value, supplied by the user, of the property to use in the
1758     *         request string
1759     */
1760    protected String getUserPropValue(String prop, AreaDirectory ad) {
1761        if (PROP_LATLON.equals(prop) && (latLonWidget != null)) {
1762            // apparently the ADDE server can't handle long numbers
1763            return Format.dfrac(latLonWidget.getLat(), 5) + " "
1764                    + Format.dfrac(latLonWidget.getLon(), 5);
1765        }
1766        if (PROP_PLACE.equals(prop) && (placeLbl != null)) {
1767            return place;
1768        }
1769
1770        if (PROP_LINELE.equals(prop) && (centerLineFld != null)) {
1771            return centerLineFld.getText().trim() + " "
1772                    + centerElementFld.getText().trim();
1773        }
1774
1775        if (PROP_SIZE.equals(prop) && (numLinesFld != null)) {
1776            return numLinesFld.getText().trim() + " "
1777                    + numElementsFld.getText().trim();
1778        }
1779        if (PROP_MAG.equals(prop) && (lineMagSlider != null)) {
1780            return getLineMagValue() + " " + getElementMagValue();
1781        }
1782        if (PROP_BAND.equals(prop) && (bandComboBox != null)) {
1783
1784            Object selected = bandComboBox.getSelectedItem();
1785            if (selected != null) {
1786                if (selected.equals(ALLBANDS)) {
1787                    return ALLBANDS.toString();
1788                } else {
1789                    return "" + ((BandInfo) selected).getBandNumber();
1790                }
1791            }
1792        }
1793        if (PROP_UNIT.equals(prop)) {
1794            return getSelectedUnit();
1795        }
1796        if (PROP_NAV.equals(prop)) {
1797            return TwoFacedObject.getIdString(navComboBox.getSelectedItem());
1798        }
1799
1800        if (PROP_USER.equals(prop))
1801            return getLastAddedUser();
1802        if (PROP_PROJ.equals(prop))
1803            return getLastAddedProj();
1804
1805        return null;
1806    }
1807
1808    /**
1809     * Get the default property value for the adde request string
1810     * 
1811     * @param prop
1812     *            The property
1813     * @param ad
1814     *            The AreaDirectory
1815     * @param forDisplay
1816     *            Is this to display to the user in the gui
1817     * 
1818     * @return The default of the property to use in the request string
1819     */
1820    protected String getDefaultPropValue(String prop, AreaDirectory ad,
1821            boolean forDisplay) {
1822        if (PROP_USER.equals(prop)) {
1823            return DEFAULT_USER;
1824        }
1825        if (PROP_USER.equals(prop)) {
1826            return PLACE_CENTER;
1827        }
1828        if (PROP_PROJ.equals(prop)) {
1829            return DEFAULT_PROJ;
1830        }
1831        if (PROP_DESCR.equals(prop)) {
1832            return getDescriptor();
1833        }
1834        if (PROP_VERSION.equals(prop)) {
1835            return DEFAULT_VERSION;
1836        }
1837        if (PROP_COMPRESS.equals(prop)) {
1838            return "gzip";
1839        }
1840        if (PROP_PORT.equals(prop)) {
1841            return DEFAULT_PORT;
1842        }
1843        if (PROP_DEBUG.equals(prop)) {
1844//          return DEFAULT_DEBUG;
1845            Boolean.toString(EntryStore.isAddeDebugEnabled(false));
1846        }
1847        if (PROP_SIZE.equals(prop)) {
1848            if (ad != null) {
1849                return ad.getLines() + " " + ad.getElements();
1850            }
1851            return MAX_SIZE + " " + MAX_SIZE;
1852        }
1853        if (PROP_MAG.equals(prop)) {
1854            return "1 1";
1855        }
1856        // if (prop.equals(PROP_LOC) || prop.equals(PROP_LINELE)) {
1857        if (PROP_MAG.equals(prop)) {
1858            if (ad == null) {
1859                return "0 0";
1860            }
1861            return ad.getLines() / 2 + " " + ad.getElements() / 2;
1862        }
1863        // if (prop.equals(PROP_LATLON)) {
1864        if (PROP_LOC.equals(prop) || PROP_LATLON.equals(prop)) {
1865            if (ad == null) {
1866                return "0 0";
1867            }
1868            return ad.getCenterLatitude() + " " + ad.getCenterLongitude();
1869        }
1870        if (PROP_BAND.equals(prop)) {
1871            if (bandTable==null) return "";
1872            if (forDisplay) {
1873                return getBandName(ad, ((int[]) bandTable.get(ad))[0]);
1874            }
1875            return "" + ((int[]) bandTable.get(ad))[0];
1876        }
1877        if (PROP_SPAC.equals(prop)) {
1878            return getSelectedUnit().equalsIgnoreCase("BRIT") ? "1" : "4";
1879        }
1880        if (PROP_UNIT.equals(prop)) {
1881            return "X";
1882        }
1883        if (PROP_NAV.equals(prop)) {
1884            return "X";
1885        }
1886        return "";
1887    }
1888
1889    /**
1890     * Set the properties on the AddeImageInfo from the list of properties
1891     * 
1892     * @param aii
1893     *            The AddeImageInfo
1894     * @param props
1895     *            list of props to set
1896     * @param ad
1897     *            The AreaDirectory
1898     */
1899    protected void setImageInfoProps(AddeImageInfo aii, String[] props, AreaDirectory ad) {
1900        for (int i = 0; i < props.length; i++) {
1901            String prop = props[i];
1902            String value = getPropValue(prop, ad);
1903            if (prop.equals(PROP_USER)) {
1904                aii.setUser(value);
1905            } else if (prop.equals(PROP_PROJ)) {
1906                aii.setProject(Integer.parseInt(value));
1907            } else if (prop.equals(PROP_DESCR)) {
1908                aii.setDescriptor(value);
1909            } else if (prop.equals(PROP_VERSION)) {
1910                aii.setVersion(value);
1911            } else if (prop.equals(PROP_COMPRESS)) {
1912                int compVal = AddeURL.GZIP;
1913                if (value.equals("none") || value.equals("1")) {
1914                    compVal = AddeURL.NO_COMPRESS;
1915                } else if (value.equals("compress") || value.equals("2") || value.equals("true")) {
1916                    compVal = AddeURL.COMPRESS;
1917                }
1918                aii.setCompression(compVal);
1919            } else if (prop.equals(PROP_PORT)) {
1920                aii.setPort(Integer.parseInt(value));
1921            } else if (prop.equals(PROP_DEBUG)) {
1922//              aii.setDebug(Boolean.getBoolean(value));
1923                aii.setDebug(EntryStore.isAddeDebugEnabled(false));
1924            } else if (prop.equals(PROP_SPAC)) {
1925                aii.setSpacing(Integer.parseInt(value));
1926            } else if (prop.equals(PROP_UNIT)) {
1927                if (value.equals(ALLUNITS.getId())) {
1928                    value = getDefault(prop, getDefaultPropValue(prop, ad, false));
1929                }
1930                aii.setUnit(value);
1931            } else if (prop.equals(PROP_BAND)) {
1932                if (value.equals(ALLBANDS.toString())) {
1933                    value = getDefault(prop, getDefaultPropValue(prop, ad, false));
1934                }
1935                aii.setBand(value);
1936            } else if (prop.equals(PROP_NAV)) {
1937                aii.setNavType(value);
1938            } else if (prop.equals(PROP_ID)) {
1939                aii.setId(value);
1940            }
1941        }
1942    }
1943
1944    /**
1945     * Get the name of the selected band
1946     * 
1947     * @return the name of the band
1948     */
1949    public String getSelectedBandName() {
1950        return getBandName(propertiesAD, getSelectedBand());
1951    }
1952
1953    /**
1954     * Clear the properties widgets
1955     */
1956    protected void clearPropertiesWidgets() {
1957        if (latLonWidget != null) {
1958            latLonWidget.getLatField().setText("");
1959            latLonWidget.getLonField().setText("");
1960        }
1961        if (centerLineFld != null) {
1962            centerLineFld.setText("");
1963            centerElementFld.setText("");
1964        }
1965        if (numLinesFld != null) {
1966            if (sizeLbl != null) {
1967                sizeLbl.setText("");
1968            }
1969            numLinesFld.setText("");
1970            numElementsFld.setText("");
1971        }
1972        if (unitComboBox != null) {
1973            GuiUtils.setListData(unitComboBox, new Vector());
1974        }
1975        if (bandComboBox != null) {
1976            GuiUtils.setListData(bandComboBox, new Vector());
1977        }
1978
1979        setMagSliders(DEFAULT_MAG, DEFAULT_MAG);
1980
1981        if (placeLbl != null) {
1982            changePlace(PLACE_CENTER);
1983        }
1984
1985        if (navComboBox != null) {
1986            checkSetNav();
1987//          navComboBox.setSelectedIndex(0);
1988        }
1989        baseNumLines = 0.0;
1990        baseNumElements = 0.0;
1991    }
1992
1993    /**
1994     * Set the widgets with the state from the given AreaDirectory
1995     * 
1996     * @param ad
1997     *            AreaDirectory for the image
1998     */
1999    protected void setPropertiesState(AreaDirectory ad) {
2000        setPropertiesState(ad, false);
2001    }
2002
2003    /**
2004     * _more_
2005     * 
2006     * @param ad
2007     *            _more_
2008     * 
2009     * @return _more_
2010     */
2011    protected int[] getSize(AreaDirectory ad) {
2012        baseNumLines = ad.getLines();
2013        baseNumElements = ad.getElements();
2014
2015        String sizeDefault = getDefault(PROP_SIZE, (String) null);
2016        List toks = ((sizeDefault != null) ? StringUtil.split(sizeDefault, " ",
2017                true, true) : null);
2018        if ((toks == null) || (toks.size() == 0)) {
2019            return new int[] { (int) baseNumLines, (int) baseNumElements };
2020        } else {
2021            String lines = "" + toks.get(0);
2022            if (lines.equalsIgnoreCase(ALL)) {
2023                lines = "" + (int) baseNumLines;
2024            }
2025            int numLines = new Integer(lines.trim()).intValue();
2026
2027            String elems = (toks.size() > 1) ? "" + toks.get(1) : ""
2028                    + (int) baseNumElements;
2029            if (elems.equalsIgnoreCase(ALL)) {
2030                elems = "" + baseNumElements;
2031            }
2032            int numElements = new Integer(elems.trim()).intValue();
2033            return new int[] { (int) Math.min(numLines, baseNumLines),
2034                    (int) Math.min(numElements, baseNumElements) };
2035        }
2036
2037    }
2038
2039    /**
2040     * Set the widgets with the state from the given AreaDirectory
2041     * 
2042     * @param ad
2043     *            AreaDirectory for the image
2044     * @param force
2045     *            force an update regardless of the previous invocation
2046     */
2047    protected void setPropertiesState(AreaDirectory ad, boolean force) {
2048        if (amSettingProperties)
2049            return;
2050
2051        prevPropertiesAD = propertiesAD;
2052        propertiesAD = ad;
2053        if (!force && checkPropertiesEqual(prevPropertiesAD, propertiesAD))
2054            return;
2055
2056        amSettingProperties = true;
2057
2058        if (ad == null) {
2059            clearPropertiesWidgets();
2060            amSettingProperties = false;
2061            return;
2062        }
2063
2064        String[] propArray = getAdvancedProps();
2065
2066        if (numLinesFld != null) {
2067            int[] size = getSize(ad);
2068            numLinesFld.setText("" + size[0]);
2069            numElementsFld.setText("" + size[1]);
2070            if (sizeLbl != null) {
2071                String label = "  Raw size: " + ad.getLines() + " X "
2072                        + ad.getElements();
2073                sizeLbl.setText(label);
2074            }
2075        }
2076        if (latLonWidget != null) {
2077            latLonWidget.getLatField().setText("" + ad.getCenterLatitude());
2078            latLonWidget.getLonField().setText("" + ad.getCenterLongitude());
2079        }
2080        if (centerLineFld != null) {
2081            centerLineFld.setText("" + ad.getLines() / 2);
2082            centerElementFld.setText("" + ad.getElements() / 2);
2083        }
2084
2085        List<BandInfo> bandList = null;
2086        int[] bands = (int[]) bandTable.get(ad);
2087        if (bands != null)
2088            bandList = makeBandInfos(ad, bands);
2089        bandInfos = bandList;
2090
2091        if (bandComboBox != null) {
2092            List comboList = bandList;
2093            if (bandList.size() > 1) {
2094                comboList = new ArrayList();
2095                comboList.addAll(bandList);
2096                comboList.add(ALLBANDS);
2097            }
2098            GuiUtils.setListData(bandComboBox, comboList);
2099        }
2100
2101        setAvailableUnits(ad, getSelectedBand());
2102
2103        for (int propIdx = 0; propIdx < propArray.length; propIdx++) {
2104            String prop = propArray[propIdx];
2105            String value = getDefault(prop, getDefaultPropValue(prop, ad, false));
2106            if (value == null)
2107                value = "";
2108
2109            value = value.trim();
2110            if (prop.equals(PROP_LOC)) {
2111                String key = getDefault(PROP_KEY, PROP_LATLON);
2112
2113                boolean usingLineElement = key.equals(PROP_LINELE);
2114                if (usingLineElement) {
2115                    locationPanel.show(1);
2116                } else {
2117                    locationPanel.show(0);
2118                }
2119                if (usingLineElement) {
2120                    value = getDefault(PROP_LOC, getDefaultPropValue(
2121                            PROP_LINELE, ad, false));
2122                } else {
2123                    value = getDefault(PROP_LOC, getDefaultPropValue(
2124                            PROP_LATLON, ad, false));
2125                }
2126                String[] pair = getPair(value);
2127                if (pair != null) {
2128                    if (usingLineElement) {
2129                        centerLineFld.setText(pair[0]);
2130                        centerElementFld.setText(pair[1]);
2131                    } else {
2132                        latLonWidget.setLat(pair[0]);
2133                        latLonWidget.setLon(pair[1]);
2134                    }
2135                }
2136            } else if (prop.equals(PROP_BAND)) {
2137                if (value.equalsIgnoreCase((String) ALLBANDS.getId())) {
2138                    bandComboBox.setSelectedItem(ALLBANDS);
2139                } else {
2140                    int bandNum = 0;
2141                    try {
2142                        bandNum = Integer.parseInt(value);
2143                    } catch (NumberFormatException nfe) {
2144                    }
2145                    int index = BandInfo.findIndexByNumber(bandNum, bandList);
2146                    if (index != -1) {
2147                        bandComboBox.setSelectedIndex(index);
2148                    }
2149                }
2150            } else if (prop.equals(PROP_PLACE)) {
2151                changePlace(value);
2152            } else if (prop.equals(PROP_MAG)) {
2153                String[] pair = getPair(value);
2154                if (pair != null) {
2155                    setMagSliders(new Integer(pair[0]).intValue(), new Integer(
2156                            pair[1]).intValue());
2157                } else {
2158                    setMagSliders(DEFAULT_MAG, DEFAULT_MAG);
2159                }
2160            } else if (prop.equals(PROP_NAV)) {
2161                if (navComboBox != null) {
2162                    navComboBox.setSelectedIndex((value
2163                            .equalsIgnoreCase("LALO") ? 1 : 0));
2164                }
2165                checkSetNav();
2166            }
2167        }
2168        amSettingProperties = false;
2169
2170    }
2171
2172    /**
2173     * Set the mag slider values
2174     * 
2175     * @param lineValue
2176     *            the line value
2177     * @param elementValue
2178     *            the element value
2179     */
2180    protected void setMagSliders(int lineValue, int elementValue) {
2181        if (lineMagSlider != null) {
2182            if (lineValue > 0) {
2183                lineValue--;
2184            } else if (lineValue < 0) {
2185                lineValue++;
2186            }
2187            if (elementValue > 0) {
2188                elementValue--;
2189            } else if (elementValue < 0) {
2190                elementValue++;
2191            }
2192
2193            lineMagSlider.setValue(lineValue);
2194            elementMagSlider.setValue(elementValue);
2195            lineMagLbl.setText(StringUtil.padLeft("" + getLineMagValue(), 4));
2196            elementMagLbl.setText(StringUtil.padLeft("" + getElementMagValue(),
2197                    4));
2198            linesToElements = Math.abs(lineValue / (double) elementValue);
2199            if (Double.isNaN(linesToElements)) {
2200                linesToElements = 1.0;
2201            }
2202        }
2203    }
2204
2205    /**
2206     * Get the value of the given magnification slider.
2207     * 
2208     * @param slider
2209     *            The slider to get the value from
2210     * @return The magnification value
2211     */
2212    protected int getMagValue(JSlider slider) {
2213        // Value is [-SLIDER_MAX,SLIDER_MAX]. We change 0 and -1 to 1
2214        int value = slider.getValue();
2215        if (value >= 0) {
2216            return value + 1;
2217        }
2218        return value - 1;
2219    }
2220
2221    /**
2222     * Get a pair of properties
2223     * 
2224     * @param v
2225     *            a space separated string
2226     * 
2227     * @return an array of the two strings
2228     */
2229    protected String[] getPair(String v) {
2230        if (v == null) {
2231            return null;
2232        }
2233        v = v.trim();
2234        List toks = StringUtil.split(v, " ", true, true);
2235        if ((toks == null) || (toks.size() == 0)) {
2236            return null;
2237        }
2238        String tok1 = toks.get(0).toString();
2239        return new String[] { tok1,
2240                ((toks.size() > 1) ? toks.get(1).toString() : tok1) };
2241
2242    }
2243
2244    /**
2245     * Get the selected band from the advanced chooser
2246     * 
2247     * @return selected band number
2248     */
2249    protected int getSelectedBand() {
2250
2251        Object bi = (bandComboBox == null) ? null : bandComboBox
2252                .getSelectedItem();
2253        if ((bi == null) || bi.equals(ALLBANDS)) {
2254            return 0;
2255        }
2256        return ((BandInfo) bi).getBandNumber();
2257    }
2258
2259    /**
2260     * Translate a place name into a human readable form
2261     * 
2262     * @param place
2263     *            raw name
2264     * 
2265     * @return human readable name
2266     */
2267    protected String translatePlace(String place) {
2268        place = place.toUpperCase();
2269        if (place.equals(PLACE_ULEFT)) {
2270            return "Upper left";
2271        }
2272        if (place.equals(PLACE_LLEFT)) {
2273            return "Lower left";
2274        }
2275        if (place.equals(PLACE_URIGHT)) {
2276            return "Upper right";
2277        }
2278        if (place.equals(PLACE_LRIGHT)) {
2279            return "Lower right";
2280        }
2281        if (place.equals(PLACE_CENTER)) {
2282            return "Center";
2283        }
2284        return place;
2285    }
2286
2287    /**
2288     * Get the band name for a particular area
2289     * 
2290     * @param ad
2291     *            AreaDirectory
2292     * @param band
2293     *            band number
2294     * 
2295     * @return name of the band
2296     */
2297    protected String getBandName(AreaDirectory ad, int band) {
2298        // if (band== 0) return ALLBANDS.toString();
2299
2300        if (useSatBandInfo) {
2301            if (satBandInfo == null) {
2302                return "Band: " + band;
2303            }
2304            String[] descrs = satBandInfo.getBandDescr(ad.getSensorID(), ad
2305                    .getSourceType());
2306            if (descrs != null) {
2307                if ((band >= 0) && (band < descrs.length)) {
2308                    return descrs[band];
2309                }
2310            }
2311            return "Band: " + band;
2312        }
2313
2314        if (sensorToBandToName == null) {
2315            return "Band: " + band;
2316        }
2317        Hashtable bandToName = (Hashtable) sensorToBandToName.get(new Integer(
2318                ad.getSensorID()));
2319        String name = null;
2320        Integer bandInteger = new Integer(band);
2321
2322        if (bandToName != null) {
2323            name = (String) bandToName.get(bandInteger);
2324        }
2325        if (name == null) {
2326            name = "Band: " + band;
2327        }
2328        /*
2329         * else { name = band + " - " + name.trim(); }
2330         */
2331        return name;
2332    }
2333
2334    /**
2335     * Set the available units in the unit selector
2336     * 
2337     * @param ad
2338     *            AreaDirectory for the image
2339     * @param band
2340     *            band to use for units
2341     */
2342    protected void setAvailableUnits(AreaDirectory ad, int band) {
2343        List l = getAvailableUnits(ad, band);
2344        l.add(ALLUNITS);
2345        GuiUtils.setListData(unitComboBox, l);
2346        TwoFacedObject tfo = null;
2347        if ((bandComboBox != null) && (getSelectedBand() == 0)) {
2348            tfo = ALLUNITS;
2349        } else {
2350            String preferredUnit = getDefault(PROP_UNIT, "BRIT");
2351            tfo = TwoFacedObject.findId(preferredUnit, l);
2352        }
2353        if (tfo != null) {
2354            unitComboBox.setSelectedItem(tfo);
2355        }
2356    }
2357
2358    /**
2359     * Set the available units in the unit selector
2360     * 
2361     * @param ad
2362     *            AreaDirectory for the image
2363     * @param band
2364     *            band to use for units
2365     * 
2366     * @return List of available units
2367     */
2368    protected List<TwoFacedObject> getAvailableUnits(AreaDirectory ad, int band) {
2369        // get Vector array of Calibration types. Layout is
2370        // v[i] = band[i] and for each band, it is a vector of
2371        // strings of calibration names and descriptions
2372        // n = name, n+1 = desc.
2373        // for radar, we only have one band
2374        if (ad == null) {
2375            return new ArrayList<>();
2376        }
2377        int[] bands = (int[]) bandTable.get(ad);
2378        int index = (bands == null) ? 0 : Arrays.binarySearch(bands, band);
2379        if (index < 0) index = 0;
2380        Vector<TwoFacedObject> l = new Vector<>();
2381        Vector v = ad.getCalInfo()[index];
2382        TwoFacedObject tfo = null;
2383        int preferredUnitIndex = 0;
2384        String preferredUnit = getDefault(PROP_UNIT, "BRIT");
2385        if ((v != null) && (v.size() / 2 > 0)) {
2386            for (int i = 0; i < v.size() / 2; i++) {
2387                String name = (String) v.get(2 * i);
2388                String desc = (String) v.get(2 * i + 1);
2389                desc = StringUtil.camelCase(desc);
2390                tfo = new TwoFacedObject(desc, name);
2391                l.add(tfo);
2392                if (name.equalsIgnoreCase(preferredUnit)) {
2393                    preferredUnitIndex = i;
2394                }
2395            }
2396        } else {
2397            l.add(new TwoFacedObject("Raw Value", "RAW"));
2398        }
2399        return l;
2400    }
2401
2402    /**
2403     * Get the band name information from the server
2404     */
2405    protected void readSatBands() {
2406        satBandInfo = null;
2407        sensorToBandToName = null;
2408        List lines = null;
2409        try {
2410            StringBuffer buff = getUrl(REQ_TEXT);
2411            appendKeyValue(buff, PROP_FILE, FILE_SATBAND);
2412            lines = readTextLines(buff.toString());
2413            if (lines == null) {
2414                return;
2415            }
2416            if (useSatBandInfo) {
2417                satBandInfo = new AddeSatBands(StringUtil.listToStringArray(lines));
2418                return;
2419            }
2420        } catch (Exception e) {
2421            return;
2422        }
2423
2424        if (lines == null) {
2425            return;
2426        }
2427
2428        sensorToBandToName = new Hashtable();
2429
2430        for (int i = 0; i < lines.size(); i++) {
2431            if (!lines.get(i).toString().startsWith("Sat")) {
2432                continue;
2433            }
2434            List satIds = StringUtil.split(lines.get(i).toString(), " ", true,
2435                    true);
2436            satIds.remove(0);
2437            Hashtable bandToName = new Hashtable();
2438            for (int j = i + 1; j < lines.size(); j++, i++) {
2439                String line = lines.get(i).toString();
2440                line = line.trim();
2441                if (line.startsWith("EndSat")) {
2442                    break;
2443                }
2444
2445                int idx = line.indexOf(" ");
2446                if (idx < 0) {
2447                    continue;
2448                }
2449                String bandTok = line.substring(0, idx);
2450                try {
2451                    bandToName.put(Integer.decode(bandTok.trim()), line
2452                            .substring(idx).trim());
2453                } catch (NumberFormatException nfe) {
2454                }
2455            }
2456            for (int j = 0; j < satIds.size(); j++) {
2457                Integer sensorId = new Integer(satIds.get(j).toString());
2458                sensorToBandToName.put(sensorId, bandToName);
2459            }
2460        }
2461    }
2462
2463    /**
2464     * Make an AddeImageInfo from a URL and an AreaDirectory
2465     * 
2466     * @param dir
2467     *            AreaDirectory
2468     * @param isRelative
2469     *            true if is relative
2470     * @param num
2471     *            number (for relative images)
2472     * 
2473     * @return corresponding AddeImageInfo
2474     */
2475    protected AddeImageInfo makeImageInfo(AreaDirectory dir,
2476            boolean isRelative, int num) {
2477        AddeImageInfo info = new AddeImageInfo(getAddeServer().getName(),
2478                AddeImageInfo.REQ_IMAGEDATA, getGroup(), getDescriptor());
2479        if (isRelative) {
2480            info.setDatasetPosition((num == 0) ? 0 : -num);
2481        } else {
2482            info.setStartDate(dir.getNominalTime());
2483        }
2484        setImageInfoProps(info, getMiscKeyProps(), dir);
2485        setImageInfoProps(info, getBaseUrlProps(), dir);
2486
2487        String locKey = getDefault(PROP_KEY, PROP_LINELE);
2488        String locValue = null;
2489        if (usePropFromUser(PROP_LOC)) {
2490            if (useLatLon()) {
2491                locKey = PROP_LATLON;
2492                locValue = getUserPropValue(PROP_LATLON, dir);
2493            } else {
2494                locKey = PROP_LINELE;
2495                locValue = getUserPropValue(PROP_LINELE, dir);
2496            }
2497        } else {
2498            locValue = getPropValue(PROP_LOC, dir);
2499        }
2500        info.setLocateKey(locKey);
2501        info.setLocateValue(locValue);
2502
2503        String placeKey = getPropValue(PROP_PLACE, dir);
2504        info.setPlaceValue(placeKey);
2505
2506        String magKey = getPropValue(PROP_MAG, dir);
2507        int lmag = 1;
2508        int emag = 1;
2509        StringTokenizer tok = new StringTokenizer(magKey);
2510        lmag = (int) Misc.parseNumber((String) tok.nextElement());
2511        if (tok.hasMoreTokens()) {
2512            emag = (int) Misc.parseNumber((String) tok.nextElement());
2513        } else {
2514            emag = lmag;
2515        }
2516        info.setLineMag(lmag);
2517        info.setElementMag(emag);
2518
2519        int lines = dir.getLines();
2520        int elems = dir.getElements();
2521        String sizeKey = getPropValue(PROP_SIZE, dir);
2522        tok = new StringTokenizer(sizeKey);
2523        String size = (String) tok.nextElement();
2524        if (!size.equalsIgnoreCase("all")) {
2525            lines = (int) Misc.parseNumber(size);
2526            if (tok.hasMoreTokens()) {
2527                elems = (int) Misc.parseNumber((String) tok.nextElement());
2528            } else {
2529                elems = lines;
2530            }
2531        }
2532        info.setLines(lines);
2533        info.setElements(elems);
2534        /*
2535         * System.out.println("url = " + info.getURLString().toLowerCase() +
2536         * "\n");
2537         */
2538        return info;
2539    }
2540
2541    /**
2542     * Check to see if the two Area directories are equal
2543     * 
2544     * @param ad1
2545     *            first AD (may be null)
2546     * @param ad2
2547     *            second AD (may be null)
2548     * 
2549     * @return true if they are equal
2550     */
2551    protected boolean checkPropertiesEqual(AreaDirectory ad1, AreaDirectory ad2) {
2552        if (ad1 == null) {
2553            return false;
2554        }
2555        if (ad2 == null) {
2556            return false;
2557        }
2558        return Misc.equals(ad1, ad2)
2559                || ((ad1.getLines() == ad2.getLines())
2560                        && (ad1.getElements() == ad2.getElements()) && Arrays
2561                        .equals(ad1.getBands(), ad2.getBands()));
2562    }
2563
2564    /**
2565     * Get a description of the properties
2566     * 
2567     * @return a description
2568     */
2569    protected String getPropertiesDescription() {
2570        StringBuffer buf = new StringBuffer();
2571        String[] propArray = getAdvancedProps();
2572        List list = Misc.toList(propArray);
2573        if (list.contains(PROP_BAND)) {
2574            buf.append(getSelectedBandName());
2575            buf.append(", ");
2576        }
2577        if (list.contains(PROP_SIZE)) {
2578            buf.append("Size: ");
2579            String sizeKey = getUserPropValue(PROP_SIZE, propertiesAD);
2580            StringTokenizer tok = new StringTokenizer(sizeKey);
2581            if (tok.hasMoreTokens()) {
2582                String size = ((String) tok.nextElement()).trim();
2583                buf.append(size);
2584                buf.append("x");
2585                if (!size.equalsIgnoreCase("all")) {
2586                    if (tok.hasMoreTokens()) {
2587                        buf.append(((String) tok.nextElement()).trim());
2588                    } else {
2589                        buf.append(size);
2590                    }
2591                }
2592            }
2593        }
2594        return buf.toString();
2595    }
2596
2597    /**
2598     * Show the given error to the user. If it was an ADDE exception that was
2599     * a bad server error then print out a nice message.
2600     *
2601     * <p>Overridden in McIDAS-V to work with ADDE {@literal "archive"}
2602     * servers (servers that require a {@literal "DAY="} parameter).</p>
2603     *
2604     * @param e Exception to be handled. Cannot be {@code null}.
2605     */
2606    @Override protected void handleConnectionError(Exception e) {
2607        handleConnectionError("", e);
2608    }
2609
2610    /**
2611     * Show the given error to the user. If it was an ADDE exception that was
2612     * a bad server error then print out a nice message.
2613     *
2614     * <p>Overridden in McIDAS-V to work with ADDE {@literal "archive"}
2615     * servers (servers that require a {@literal "DAY="} parameter).</p>
2616     * 
2617     * @param details Details about the context of {@code e}. {@code null}
2618     * will be treated as an empty {@code String}.
2619     * @param e Exception to be handled. Cannot be {@code null}.
2620     */
2621    @Override protected void handleConnectionError(String details, Exception e) {
2622        if ((e != null) && (e.getMessage() != null)) {
2623            Throwable cause = e.getCause();
2624            if (cause.getMessage() != null) {
2625                String msg = cause.getMessage().toLowerCase();
2626                if ((cause instanceof AddeURLException) && msg.contains("must be used with archived datasets")) {
2627                    getArchiveDay();
2628                    return;
2629                }
2630            }
2631        }
2632        super.handleConnectionError(details, e);
2633    }
2634
2635    /**
2636     * Get the list of bands for the images
2637     * 
2638     * @param ad
2639     *            AreaDirectory
2640     * @param bands
2641     *            list of bands
2642     * @return list of BandInfos for the selected images
2643     */
2644    protected List<BandInfo> makeBandInfos(AreaDirectory ad, int[] bands) {
2645        // readSatBands();
2646        List<BandInfo> l = new ArrayList<>();
2647        if (ad != null) {
2648            if (bands != null) {
2649                for (int i = 0; i < bands.length; i++) {
2650                    int band = bands[i];
2651                    if (band > 0) {
2652                        BandInfo bi = new BandInfo(ad.getSensorID(), band);
2653                        bi.setBandDescription(getBandName(ad, band));
2654                        bi.setCalibrationUnits(getAvailableUnits(ad, band));
2655                        bi.setPreferredUnit(getDefault(PROP_UNIT, "BRIT"));
2656                        l.add(bi);
2657                    }
2658                }
2659            }
2660        }
2661        return l;
2662    }
2663    
2664    /**
2665     * Get the pregenerated bandInfos
2666     */
2667    protected List<BandInfo> getBandInfos() {
2668        return bandInfos;
2669    }
2670    
2671    /**
2672     * Get the list of BandInfos for the current selected images
2673     * 
2674     * @return list of BandInfos
2675     */
2676    public List<BandInfo> getSelectedBandInfos() {
2677        // update the BandInfo list based on what has been chosen
2678        List selectedBandInfos = new ArrayList<>();
2679        List selectedUnits = null;
2680        if (unitComboBox != null) {
2681            TwoFacedObject tfo = (TwoFacedObject) unitComboBox.getSelectedItem();
2682            if (!(tfo.equals(ALLUNITS))) { // specific unit requested
2683                selectedUnits = new ArrayList<>();
2684                selectedUnits.add(tfo);
2685            }
2686        }
2687        if (getSelectedBand() == 0) { // All bands selected
2688            if (selectedUnits != null) {
2689                for (Iterator iter = bandInfos.iterator(); iter.hasNext();) {
2690                    BandInfo newBI = new BandInfo((BandInfo) iter.next());
2691                    newBI.setCalibrationUnits(selectedUnits);
2692                    newBI.setPreferredUnit((String) ((TwoFacedObject) selectedUnits.get(0)).getId());
2693                    selectedBandInfos.add(newBI);
2694                }
2695            } else { // else All Bands, AllUnits
2696                selectedBandInfos = bandInfos;
2697            }
2698        } else { // not All selected;
2699            int index = BandInfo.findIndexByNumber(getSelectedBand(), bandInfos);
2700            BandInfo selectedBandInfo = null;
2701            if (index != -1) {
2702                selectedBandInfo = bandInfos.get(index);
2703            }
2704            if (selectedBandInfo != null) {
2705                if (selectedUnits != null) {
2706                    BandInfo newBI = new BandInfo(selectedBandInfo);
2707                    newBI.setCalibrationUnits(selectedUnits);
2708                    newBI.setPreferredUnit((String) ((TwoFacedObject) selectedUnits.get(0)).getId());
2709                    selectedBandInfos.add(newBI);
2710                } else {
2711                    selectedBandInfos.add(selectedBandInfo);
2712                }
2713            }
2714        }
2715        return selectedBandInfos;
2716    }
2717
2718    /**
2719     * Get the id for the default display type
2720     * 
2721     * @return the display id
2722     */
2723    @Override protected String getDefaultDisplayType() {
2724        return "imagedisplay";
2725    }
2726
2727    /**
2728     * User said go, we go. Simply get the list of images from the imageChooser
2729     * and create the ADDE.IMAGE DataSource
2730     * 
2731     */
2732    @Override public void doLoadInThread() {
2733        if (!checkForValidValues()) {
2734            return;
2735        }
2736        if (!getGoodToGo()) {
2737            updateStatus();
2738            return;
2739        }
2740
2741        List imageList = getImageList();
2742        if ((imageList == null) || (imageList.isEmpty())) {
2743            return;
2744        }
2745
2746        // Check for size threshold
2747        final int[] dim = { 0, 0 };
2748        AddeImageDescriptor aid = (AddeImageDescriptor) imageList.get(0);
2749        dim[0] = aid.getImageInfo().getElements();
2750        dim[1] = aid.getImageInfo().getLines();
2751        // System.err.println("dim:" + dim[0] + " x " + dim[1] + " # images:"
2752        // + imageList.size());
2753        int numPixels = dim[0] * dim[1] * imageList.size();
2754        double megs = (4 * numPixels) / (double) 1000000;
2755        
2756        //DAVEP: take this out--it should be warning in the data source, not the chooser
2757        boolean doSizeCheck = false;
2758        if (megs > SIZE_THRESHOLD && doSizeCheck) {
2759            final JCheckBox maintainSize = new JCheckBox(
2760                    "Maintain spatial extent", false);
2761            final JLabel sizeLbl = new JLabel(StringUtil.padRight("  "
2762                    + ((double) ((int) megs * 100)) / 100.0 + " MB", 14));
2763            GuiUtils.setFixedWidthFont(sizeLbl);
2764            final List[] listHolder = { imageList };
2765            final JSlider slider = new JSlider(2, (int) megs, (int) megs);
2766            slider.setMajorTickSpacing((int) (megs - 2) / 10);
2767            slider.setMinorTickSpacing((int) (megs - 2) / 10);
2768            // slider.setPaintTicks(true);
2769            slider.setSnapToTicks(true);
2770            final long timeNow = System.currentTimeMillis();
2771            ChangeListener sizeListener = new javax.swing.event.ChangeListener() {
2772                public void stateChanged(ChangeEvent evt) {
2773                    // A hack so we don't respond to the first event that we get
2774                    // from the slider when
2775                    // the dialog is first shown
2776                    if (System.currentTimeMillis() - timeNow < 500)
2777                        return;
2778                    JSlider slider = (JSlider) evt.getSource();
2779                    int pixelsPerImage = 1000000 * slider.getValue()
2780                            / listHolder[0].size() / 4;
2781                    double aspect = dim[1] / (double) dim[0];
2782                    int nx = (int) Math.sqrt(pixelsPerImage / aspect);
2783                    int ny = (int) (aspect * nx);
2784                    if (maintainSize.isSelected()) {
2785                        // doesn't work
2786                        lineMagSlider.setValue(getLineMagValue() - 1);
2787                        lineMagSliderChanged(true);
2788                    } else {
2789                        numElementsFld.setText("" + nx);
2790                        numLinesFld.setText("" + ny);
2791                    }
2792                    listHolder[0] = getImageList();
2793                    AddeImageDescriptor aid = (AddeImageDescriptor) listHolder[0]
2794                            .get(0);
2795                    dim[0] = aid.getImageInfo().getElements();
2796                    dim[1] = aid.getImageInfo().getLines();
2797                    int numPixels = dim[0] * dim[1] * listHolder[0].size();
2798                    double nmegs = (4 * numPixels) / (double) 1000000;
2799                    sizeLbl.setText(StringUtil.padRight("  "
2800                            + ((double) ((int) nmegs * 100)) / 100.0 + " MB",
2801                            14));
2802                }
2803            };
2804            slider.addChangeListener(sizeListener);
2805
2806            JComponent msgContents = GuiUtils
2807                    .vbox(
2808                            new JLabel(
2809                                    "<html>You are about to load "
2810                                            + megs
2811                                            + " MB of imagery.<br>Are you sure you want to do this?<p><hr><p></html>"),
2812                            GuiUtils.inset(GuiUtils.leftCenterRight(new JLabel(
2813                                    "Change Size: "),
2814                                    GuiUtils.inset(slider, 5), sizeLbl), 5));
2815
2816            if (!GuiUtils.askOkCancel("Image Size", msgContents)) {
2817                return;
2818            }
2819            imageList = listHolder[0];
2820        }
2821
2822        ImageDataset ids = new ImageDataset(getDatasetName(), imageList);
2823        // make properties Hashtable to hand the station name
2824        // to the AddeImageDataSource
2825        Hashtable ht = new Hashtable();
2826        ht.put(DataSelection.PROP_CHOOSERTIMEMATCHING, getDoTimeDrivers());
2827        getDataSourceProperties(ht);
2828        Object bandName = getSelectedBandName();
2829        if (bandName != null && !(bandName.equals(ALLBANDS.toString()))) {
2830            ht.put(DATA_NAME_KEY, bandName);
2831        }
2832        ht.put("allBands", bandDirs);
2833        makeDataSource(ids, getDataSourceId(), ht);
2834        saveServerState();
2835        // uncheck the check box every time click the add source button
2836        drivercbx.setSelected(false);
2837        enableTimeWidgets();
2838        setDoTimeDrivers(false);
2839    }
2840    
2841    /**
2842     * Return the data source ID.  Used by extending classes.
2843     */
2844    @Override protected String getDataSourceId() {
2845        return "ADDE.IMAGE";
2846    }
2847
2848    /**
2849     * Get the DataSource properties
2850     * 
2851     * @param ht
2852     *            Hashtable of properties
2853     */
2854    @Override protected void getDataSourceProperties(Hashtable ht) {
2855        super.getDataSourceProperties(ht);
2856        ht.put(DATASET_NAME_KEY, getDatasetName());
2857        ht.put(ImageDataSource.PROP_BANDINFO, getSelectedBandInfos());
2858    }
2859
2860    /**
2861     * _more_
2862     * 
2863     * @return _more_
2864     */
2865    protected List processPropertyComponents() {
2866        List bottomComps = new ArrayList();
2867        getBottomComponents(bottomComps);
2868        for (int i = 0; i < bottomComps.size(); i++) {
2869            addDescComp((JComponent) bottomComps.get(i));
2870        }
2871        return bottomComps;
2872    }
2873
2874    /**
2875     * Make the UI for this selector.
2876     * 
2877     * @return The gui
2878     */
2879    @Override public JComponent doMakeContents() {
2880        JPanel myPanel = new JPanel();
2881
2882        JLabel timesLabel = McVGuiUtils.makeLabelRight("Times:");
2883        addDescComp(timesLabel);
2884
2885        JPanel timesPanel = makeTimesPanel();
2886        timesPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
2887        addDescComp(timesPanel);
2888
2889        JLabel imageLabel = McVGuiUtils.makeLabelRight("Other:");
2890        addDescComp(imageLabel);
2891
2892        List comps = new ArrayList();
2893        comps.addAll(processPropertyComponents());
2894        GuiUtils.tmpInsets = GRID_INSETS;
2895        JPanel imagePanel = GuiUtils.doLayout(comps, 2, GuiUtils.WT_NY, GuiUtils.WT_N);
2896        imagePanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
2897
2898        GroupLayout layout = new GroupLayout(myPanel);
2899        myPanel.setLayout(layout);
2900        layout.setHorizontalGroup(layout.createParallelGroup(LEADING)
2901            .addGroup(layout.createSequentialGroup()
2902                .addGroup(layout.createParallelGroup(LEADING)
2903                .addGroup(layout.createSequentialGroup()
2904                    .addComponent(descriptorLabel)
2905                    .addGap(GAP_RELATED)
2906                    .addComponent(descriptorComboBox))
2907                .addGroup(layout.createSequentialGroup()
2908                    .addComponent(timesLabel)
2909                    .addGap(GAP_RELATED)
2910                    .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
2911                .addGroup(layout.createSequentialGroup()
2912                    .addComponent(imageLabel)
2913                    .addGap(GAP_RELATED)
2914                    .addComponent(imagePanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)))));
2915
2916        layout.setVerticalGroup(layout.createParallelGroup(LEADING)
2917            .addGroup(layout.createSequentialGroup()
2918            .addGroup(layout.createParallelGroup(BASELINE)
2919                .addComponent(descriptorLabel)
2920                .addComponent(descriptorComboBox))
2921            .addPreferredGap(RELATED)
2922            .addGroup(layout.createParallelGroup(LEADING)
2923                .addComponent(timesLabel)
2924                .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
2925                .addPreferredGap(RELATED)
2926                .addGroup(layout.createParallelGroup(LEADING)
2927                    .addComponent(imageLabel)
2928                    .addComponent(imagePanel))));
2929
2930        setInnerPanel(myPanel);
2931        return super.doMakeContents();
2932    }
2933
2934    public JComponent doMakeContents(boolean doesOverride) {
2935        return doesOverride ? super.doMakeContents() : doMakeContents();
2936    }
2937
2938}