001    /*
002     * $Id: McvDataManager.java,v 1.12 2012/02/19 17:35:45 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.data;
032    
033    import java.util.ArrayList;
034    import java.util.Collections;
035    import java.util.Comparator;
036    import java.util.HashMap;
037    import java.util.Map;
038    
039    import ucar.unidata.data.DataChoice;
040    import ucar.unidata.data.DataContext;
041    import ucar.unidata.data.DataManager;
042    import ucar.unidata.data.DataSource;
043    
044    import ucar.unidata.util.TwoFacedObject;
045    
046    import ucar.unidata.xml.XmlResourceCollection;
047    
048    import edu.wisc.ssec.mcidasv.control.HydraControl;
049    import edu.wisc.ssec.mcidasv.control.MultiSpectralControl;
050    
051    import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay;
052    
053    /**
054     * <p>
055     * The McvDataManager exists purely as a UI nicety. In the IDV, the list of
056     * {@link DataSource}s are presented in the same ordering found in
057     * {@code datasources.xml}.
058     * </p>
059     * 
060     * <p>
061     * While ordering the contents of {@code datasources.xml} certainly would have
062     * been easier, the approach taken here is a bit more future-proof. McV simply
063     * sorts the data sources known to the IDV.
064     * </p>
065     */
066    public class McvDataManager extends DataManager {
067    
068        /**
069         * ID of the "I'm Still Feeling Lucky" data source. The IDV lowercases it
070         * automatically.
071         */
072        private static final String STILL_LUCKY_ID = "file.any";
073    
074        private final Map<DataChoice, HydraControl> hydraDataToControl = new HashMap<DataChoice, HydraControl>();
075        private final Map<DataChoice, MultiSpectralDisplay> hydraDataToDisplay = new HashMap<DataChoice, MultiSpectralDisplay>();
076    
077        /**
078         * Default constructor.
079         */
080        public McvDataManager() {
081            super(null);
082        }
083    
084        /**
085         * Creates a new DataManager with the given {@link DataContext}.
086         * 
087         * @param dataContext The {@code DataContext} that this DataManager exists
088         *        within (this is usually an instance of
089         *        {@link ucar.unidata.idv.IntegratedDataViewer}).
090         */
091        public McvDataManager(final DataContext dataContext) {
092            super(dataContext);
093        }
094    
095        public boolean containsHydraControl(final DataChoice choice) {
096            return hydraDataToControl.containsKey(choice);
097        }
098    
099        public boolean containsHydraDisplay(final DataChoice choice) {
100            return hydraDataToDisplay.containsKey(choice);
101        }
102    
103        public void setHydraControl(final DataChoice choice, final HydraControl control) {
104            hydraDataToControl.put(choice, control);
105        }
106    
107        public void setHydraDisplay(final DataChoice choice, final MultiSpectralDisplay display) {
108            hydraDataToDisplay.put(choice, display);
109        }
110    
111        public HydraControl getHydraControl(final DataChoice choice) {
112            return hydraDataToControl.get(choice);
113        }
114    
115        public MultiSpectralDisplay getHydraDisplay(final DataChoice choice) {
116            return hydraDataToDisplay.get(choice);
117        }
118    
119        /**
120         * Process the list of xml documents that define the different
121         * {@link DataSource}s used within the idv. Overridden so that McIDAS-V
122         * can alphabetize the lists of {@link DataSource}s presented in the UI.
123         * 
124         * @param resources The {@link XmlResourceCollection} that holds the set of
125         *        datasource xml documents. This may be null.
126         */
127        @Override public void loadDataSourceXml(
128            final XmlResourceCollection resources) {
129            super.loadDataSourceXml(resources);
130            allDataSourceIds = sortTwoFacedObjects(allDataSourceIds);
131            fileDataSourceIds = sortTwoFacedObjects(fileDataSourceIds);
132        }
133    
134        /**
135         * <p>
136         * Sorts an {@link ArrayList} of {@link TwoFacedObject}s by label. Case is
137         * ignored.
138         * </p>
139         * 
140         * <p>
141         * <b>NOTE:</b> If the ID of one of the objects represents the "I'm Still
142         * Feeling Lucky" data source, it'll always wind up at the end of the list.
143         * </p>
144         * 
145         * @param objs The list that needs some sortin' out.
146         * 
147         * @return The sorted contents of {@code objs}.
148         */
149        private ArrayList<TwoFacedObject> sortTwoFacedObjects(final ArrayList<TwoFacedObject> objs) {
150            Comparator<TwoFacedObject> comp = new Comparator<TwoFacedObject>() {
151    
152                public int compare(final TwoFacedObject a, final TwoFacedObject b) {
153    
154                    // make sure "I'm still feeling lucky" is always last.
155                    if (a.getId().equals(STILL_LUCKY_ID))
156                        return 1;
157    
158                    // same as above!
159                    if (b.getId().equals(STILL_LUCKY_ID))
160                        return -1;
161    
162                    // otherwise sorting by label is just fine.
163                    return ((String)a.getLabel()).compareToIgnoreCase((String)b.getLabel());
164                }
165    
166                @Override public boolean equals(Object o) {
167                    return (o == this);
168                }
169            };
170    
171            ArrayList<TwoFacedObject> reordered = new ArrayList<TwoFacedObject>(objs);
172            Collections.sort(reordered, comp);
173            return reordered;
174        }
175    }