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