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