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