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