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