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.ui;
030    
031    import java.util.List;
032    
033    import javax.swing.JComponent;
034    
035    import org.w3c.dom.Document;
036    import org.w3c.dom.Element;
037    
038    import ucar.unidata.idv.IntegratedDataViewer;
039    import ucar.unidata.idv.ui.IdvComponentHolder;
040    import ucar.unidata.idv.ui.IdvUIManager;
041    import ucar.unidata.idv.ui.IdvXmlUi;
042    import ucar.unidata.idv.ViewManager;
043    import ucar.unidata.util.WrapperException;
044    import ucar.unidata.xml.XmlUtil;
045    
046    /**
047     * <p>
048     * McIDAS-V needs its own ComponentHolder merely to associate ViewManagers with
049     * their parent ComponentHolders. This association is later used in
050     * McIDASVViewPanel to create a "hierarchical name" for each ViewManager.
051     * </p>
052     * 
053     * <p>
054     * Instead of having something like "Panel 1" appearing in the layer controls,
055     * we now have "ComponentHolder Name>Panel 1". Note: ComponentHolder names
056     * always double as tab names! McV also intercepts ComponentHolder renaming and
057     * updates the layer controls instantly.
058     * </p>
059     */
060    public class McvComponentHolder extends IdvComponentHolder {
061    
062        /** IDV friendly description of a dynamic XML skin. */
063        public static final String CATEGORY_DESCRIPTION = "UI Skin";
064    
065        /** Used to distinguish a dynamic skin from other things. */
066        public static final String TYPE_DYNAMIC_SKIN = "dynamicskin";
067    
068    //    private static Logger logger = LoggerFactory.getLogger(McvComponentHolder.class);
069    
070    //    private Map<String, ViewManager> dynamicViewManagers = new HashMap<String, ViewManager>();
071    
072        /** Kept around to avoid annoying casting. */
073        private UIManager uiManager;
074    
075        private JComponent cached = null;
076    
077        /**
078         * Default constructor for serialization.
079         */
080        public McvComponentHolder() {
081        }
082    
083        /**
084         * Fairly typical constructor.
085         * 
086         * @param idv Reference to the main IDV object.
087         * @param obj object being held in this component holder.
088         */
089        public McvComponentHolder(IntegratedDataViewer idv, Object obj) {
090            super(idv, obj);
091            uiManager = (UIManager)idv.getIdvUIManager();
092        }
093    
094        /**
095         * Overridden so that we can (one day) do the required extra work to write
096         * out the XML for this skin.
097         * 
098         * @param doc Parent document we'll use for XML generation.
099         * 
100         * @return XML representation of what is being held.
101         */
102        @Override public Element createXmlNode(Document doc) {
103            if (!getType().equals(TYPE_DYNAMIC_SKIN)) {
104                return super.createXmlNode(doc);
105            }
106    
107            // keep in mind that the IDV expects that we're holding a path
108            // to a skin... I don't think that this will work how you want it...
109            // TODO: investigate this!
110            Element node = doc.createElement(IdvUIManager.COMP_COMPONENT_SKIN);
111            node.setAttribute("url", getObject().toString());
112    
113            /*
114             * try { System.err.println(XmlUtil.toString((Element)getObject())); }
115             * catch (Exception e) { e.printStackTrace(); }
116             */
117    
118            return node;
119        }
120    
121        /**
122         * Overridden so that McV can do the required extra work if this holder is
123         * holding a dynamic XML skin.
124         * 
125         * @return Contents of this holder as a UI component.
126         */
127        @Override public JComponent doMakeContents() {
128            JComponent contents;
129            if (!getType().equals(TYPE_DYNAMIC_SKIN)) {
130                contents = super.doMakeContents();
131            } else {
132                contents = makeDynamicSkin();
133            }
134    //        contents.addComponentListener(new ComponentListener() {
135    //            @Override public void componentHidden(ComponentEvent e) {
136    //                logger.trace("component hidden");
137    //                GuiUtils.toggleHeavyWeightComponents(contents, false);
138    //            }
139    //            @Override public void componentShown(ComponentEvent e) {
140    //                logger.trace("component shown");
141    //                GuiUtils.toggleHeavyWeightComponents(contents, false);
142    //            }
143    //            @Override public void componentMoved(ComponentEvent e) {}
144    //            @Override public void componentResized(ComponentEvent e) {}
145    //        });
146            return contents;
147        }
148    
149        /**
150         * Lets the IDV take care of the details, but does null out the local
151         * reference to the UIManager.
152         */
153        @Override public void doRemove() {
154            super.doRemove();
155            uiManager = null;
156        }
157    
158        /**
159         * Overridden so that McV can return a more accurate category if this holder
160         * is holding a dynamic skin.
161         * 
162         * @return Category name for the type of thing we're holding.
163         */
164        @Override public String getCategory() {
165            if (!getType().equals(TYPE_DYNAMIC_SKIN)) {
166                return super.getCategory();
167            }
168            return CATEGORY_DESCRIPTION;
169        }
170    
171        /**
172         * Overridden so that McV can return a more accurate description if this
173         * holder is holding a dynamic skin.
174         * 
175         * @return The description of what is being held.
176         */
177        @Override public String getTypeName() {
178            if (!getType().equals(TYPE_DYNAMIC_SKIN)) {
179                return super.getTypeName();
180            }
181            return CATEGORY_DESCRIPTION;
182        }
183    
184        /**
185         * <p>
186         * If the object being held in this component holder is a skin, calling this
187         * method will create a component based upon the skin.
188         * </p>
189         * 
190         * <p>
191         * Overridden so that McV can tell the UIManager to associate the skin's
192         * ViewManagers with this component holder. That association is used to
193         * build the hierarchical names in the ViewPanel.
194         * </p>
195         * 
196         * @return The component represented by this holder's skin.
197         */
198        @Override protected JComponent makeSkin() {
199            JComponent comp = super.makeSkin();
200    
201            // let's hope that *getViewManagers* only gives us a list of 
202            // ViewManagers
203            @SuppressWarnings("unchecked")
204            List<ViewManager> vms = getViewManagers();
205            if (vms != null) {
206                for (int i = 0; i < vms.size(); i++) {
207                    uiManager.setViewManagerHolder(vms.get(i), this);
208                    uiManager.getViewPanel().viewManagerChanged(vms.get(i));
209                }
210            }
211            return comp;
212        }
213    
214        /**
215         * Mostly used to ensure that the local reference to the UI manager is valid
216         * when deserializing.
217         * 
218         * @param idv Main IDV reference!
219         */
220        @Override
221        public void setIdv(IntegratedDataViewer idv) {
222            super.setIdv(idv);
223            uiManager = (UIManager)idv.getIdvUIManager();
224        }
225    
226        /**
227         * <p>
228         * Merely sets the name of this component holder to the contents of
229         * <tt>value</tt>.
230         * </p>
231         * 
232         * <p>
233         * Overridden so that McV can tell the ViewPanel to update upon a name
234         * change.
235         * </p>
236         * 
237         * @param value New name of this component holder.
238         */
239        @Override public void setName(String value) {
240            super.setName(value);
241    
242            // let's hope that *getViewManagers* only gives us a list of 
243            // ViewManagers
244            @SuppressWarnings("unchecked")
245            List<ViewManager> vms = getViewManagers();
246            if (vms != null) {
247                for (int i = 0; i < vms.size(); i++) {
248                    uiManager.getViewPanel().viewManagerChanged(vms.get(i));
249                }
250            }
251        }
252    
253        /**
254         * Build the UI component using the XML skin contained by this holder.
255         * 
256         * @return UI Component specified by the skin contained in this holder.
257         */
258        public JComponent makeDynamicSkin() {
259            if (cached != null)
260                return cached;
261    
262            try {
263                Element root = XmlUtil.getRoot((String) getObject());
264    
265                IdvXmlUi ui = uiManager.doMakeIdvXmlUi(null, getViewManagers(),
266                        root);
267    
268                // look for any "embedded" ViewManagers.
269                Element startNode = XmlUtil.findElement(root, null, "embeddednode",
270                        "true");
271                if (startNode != null) {
272                    ui.setStartNode(startNode);
273                }
274    
275                JComponent contents = (JComponent)ui.getContents();
276                setViewManagers(ui.getViewManagers());
277    
278                cached = contents;
279                return contents;
280    
281            } catch (Exception e) {
282                throw new WrapperException(e);
283            }
284        }
285    
286        /**
287         * <p>
288         * Tell this component holder's component group that the tab corresponding
289         * to this holder should become the active tab.
290         * </p>
291         */
292        public void setAsActiveTab() {
293            McvComponentGroup parent = (McvComponentGroup)getParent();
294            if (parent != null) {
295                parent.setActiveComponentHolder(this);
296            }
297        }
298    }