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