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