001/*
002 * $Id: McvComponentHolder.java,v 1.10 2011/03/24 16:06:34 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
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
031package edu.wisc.ssec.mcidasv.ui;
032
033import java.util.List;
034
035import javax.swing.JComponent;
036
037import org.w3c.dom.Document;
038import org.w3c.dom.Element;
039
040import ucar.unidata.idv.IntegratedDataViewer;
041import ucar.unidata.idv.ui.IdvComponentHolder;
042import ucar.unidata.idv.ui.IdvUIManager;
043import ucar.unidata.idv.ui.IdvXmlUi;
044import ucar.unidata.idv.ViewManager;
045import ucar.unidata.util.WrapperException;
046import 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 */
062public 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}