001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
005     * Space Science and Engineering Center (SSEC)
006     * University of Wisconsin - Madison
007     * 1225 W. Dayton Street, Madison, WI 53706, USA
008     * https://www.ssec.wisc.edu/mcidas
009     * 
010     * All Rights Reserved
011     * 
012     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013     * some McIDAS-V source code is based on IDV and VisAD source code.  
014     * 
015     * McIDAS-V is free software; you can redistribute it and/or modify
016     * it under the terms of the GNU Lesser Public License as published by
017     * the Free Software Foundation; either version 3 of the License, or
018     * (at your option) any later version.
019     * 
020     * McIDAS-V is distributed in the hope that it will be useful,
021     * but WITHOUT ANY WARRANTY; without even the implied warranty of
022     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023     * GNU Lesser Public License for more details.
024     * 
025     * You should have received a copy of the GNU Lesser Public License
026     * along with this program.  If not, see http://www.gnu.org/licenses.
027     */
028    
029    package edu.wisc.ssec.mcidasv.data;
030    
031    import java.util.ArrayList;
032    import java.util.Collections;
033    import java.util.Comparator;
034    import java.util.HashMap;
035    import java.util.Map;
036    
037    import ucar.unidata.data.DataChoice;
038    import ucar.unidata.data.DataContext;
039    import ucar.unidata.data.DataManager;
040    import ucar.unidata.data.DataSource;
041    
042    import ucar.unidata.util.TwoFacedObject;
043    
044    import ucar.unidata.xml.XmlResourceCollection;
045    
046    import edu.wisc.ssec.mcidasv.control.HydraControl;
047    import edu.wisc.ssec.mcidasv.control.MultiSpectralControl;
048    
049    import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay;
050    
051    /**
052     * <p>
053     * The McvDataManager exists purely as a UI nicety. In the IDV, the list of
054     * {@link DataSource}s are presented in the same ordering found in
055     * {@code datasources.xml}.
056     * </p>
057     * 
058     * <p>
059     * While ordering the contents of {@code datasources.xml} certainly would have
060     * been easier, the approach taken here is a bit more future-proof. McV simply
061     * sorts the data sources known to the IDV.
062     * </p>
063     */
064    public class McvDataManager extends DataManager {
065    
066        /**
067         * ID of the "I'm Still Feeling Lucky" data source. The IDV lowercases it
068         * automatically.
069         */
070        private static final String STILL_LUCKY_ID = "file.any";
071    
072        private final Map<DataChoice, HydraControl> hydraDataToControl = new HashMap<DataChoice, HydraControl>();
073        private final Map<DataChoice, MultiSpectralDisplay> hydraDataToDisplay = new HashMap<DataChoice, MultiSpectralDisplay>();
074    
075        /**
076         * Default constructor.
077         */
078        public McvDataManager() {
079            super(null);
080        }
081    
082        /**
083         * Creates a new DataManager with the given {@link DataContext}.
084         * 
085         * @param dataContext The {@code DataContext} that this DataManager exists
086         *        within (this is usually an instance of
087         *        {@link ucar.unidata.idv.IntegratedDataViewer}).
088         */
089        public McvDataManager(final DataContext dataContext) {
090            super(dataContext);
091        }
092    
093        public boolean containsHydraControl(final DataChoice choice) {
094            return hydraDataToControl.containsKey(choice);
095        }
096    
097        public boolean containsHydraDisplay(final DataChoice choice) {
098            return hydraDataToDisplay.containsKey(choice);
099        }
100    
101        public void setHydraControl(final DataChoice choice, final HydraControl control) {
102            hydraDataToControl.put(choice, control);
103        }
104    
105        public void setHydraDisplay(final DataChoice choice, final MultiSpectralDisplay display) {
106            hydraDataToDisplay.put(choice, display);
107        }
108    
109        public HydraControl getHydraControl(final DataChoice choice) {
110            return hydraDataToControl.get(choice);
111        }
112    
113        public MultiSpectralDisplay getHydraDisplay(final DataChoice choice) {
114            return hydraDataToDisplay.get(choice);
115        }
116    
117        /**
118         * Process the list of xml documents that define the different
119         * {@link DataSource}s used within the idv. Overridden so that McIDAS-V
120         * can alphabetize the lists of {@link DataSource}s presented in the UI.
121         * 
122         * @param resources The {@link XmlResourceCollection} that holds the set of
123         *        datasource xml documents. This may be null.
124         */
125        @Override public void loadDataSourceXml(
126            final XmlResourceCollection resources) {
127            super.loadDataSourceXml(resources);
128            allDataSourceIds = sortTwoFacedObjects(allDataSourceIds);
129            fileDataSourceIds = sortTwoFacedObjects(fileDataSourceIds);
130        }
131    
132        /**
133         * <p>
134         * Sorts an {@link ArrayList} of {@link TwoFacedObject}s by label. Case is
135         * ignored.
136         * </p>
137         * 
138         * <p>
139         * <b>NOTE:</b> If the ID of one of the objects represents the "I'm Still
140         * Feeling Lucky" data source, it'll always wind up at the end of the list.
141         * </p>
142         * 
143         * @param objs The list that needs some sortin' out.
144         * 
145         * @return The sorted contents of {@code objs}.
146         */
147        private ArrayList<TwoFacedObject> sortTwoFacedObjects(final ArrayList<TwoFacedObject> objs) {
148            Comparator<TwoFacedObject> comp = new Comparator<TwoFacedObject>() {
149    
150                public int compare(final TwoFacedObject a, final TwoFacedObject b) {
151    
152                    // make sure "I'm still feeling lucky" is always last.
153                    if (a.getId().equals(STILL_LUCKY_ID))
154                        return 1;
155    
156                    // same as above!
157                    if (b.getId().equals(STILL_LUCKY_ID))
158                        return -1;
159    
160                    // otherwise sorting by label is just fine.
161                    return ((String)a.getLabel()).compareToIgnoreCase((String)b.getLabel());
162                }
163    
164                @Override public boolean equals(Object o) {
165                    return (o == this);
166                }
167            };
168    
169            ArrayList<TwoFacedObject> reordered = new ArrayList<TwoFacedObject>(objs);
170            Collections.sort(reordered, comp);
171            return reordered;
172        }
173    }