001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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.chooser; 030 031import static javax.swing.GroupLayout.DEFAULT_SIZE; 032import static javax.swing.GroupLayout.Alignment.BASELINE; 033import static javax.swing.GroupLayout.Alignment.LEADING; 034import static javax.swing.GroupLayout.Alignment.TRAILING; 035import static javax.swing.LayoutStyle.ComponentPlacement.RELATED; 036import static javax.swing.LayoutStyle.ComponentPlacement.UNRELATED; 037 038import java.awt.Component; 039import java.awt.event.ActionEvent; 040import java.io.IOException; 041import java.util.ArrayList; 042import java.util.List; 043import java.util.Set; 044 045import javax.swing.GroupLayout; 046import javax.swing.JButton; 047import javax.swing.JComboBox; 048import javax.swing.JComponent; 049import javax.swing.JLabel; 050import javax.swing.JPanel; 051 052import org.slf4j.Logger; 053import org.slf4j.LoggerFactory; 054import org.w3c.dom.Document; 055import org.w3c.dom.Element; 056 057import ucar.unidata.idv.chooser.IdvChooserManager; 058import ucar.unidata.idv.chooser.XmlHandler; 059import ucar.unidata.util.*; 060 061import edu.wisc.ssec.mcidasv.Constants; 062import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 063import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Position; 064import edu.wisc.ssec.mcidasv.util.McVGuiUtils.TextColor; 065import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width; 066 067/** 068 * This handles a variety of flavors of xml documents (e.g., thredds 069 * query capability, thredds catalogs, idv menus) to create data 070 * choosers from. It provides a combobox to enter urls to xml 071 * documents. It retrieves the xml and creates a {@link XmlHandler} 072 * based on the type of xml. Currently this class handles two 073 * types of xml: Thredds catalog and Web Map Server (WMS) 074 * capability documents. The XmlHandler does most of the work. 075 * <p> 076 * This class maintains the different xml docs the user has gone 077 * to coupled with the XmlHandler for each doc. It uses this list 078 * to support navigating back and forth through the history of 079 * documents. 080 * 081 * @author IDV development team 082 * @version $Revision$Date: 2011/03/24 16:06:31 $ 083 */ 084public class XmlChooser extends ucar.unidata.idv.chooser.XmlChooser implements Constants { 085 086 /** Catalog browser panel */ 087 JPanel catalogPanel; 088 089 /** Catalog browser panel label history */ 090 int labelHistoryIdx = -1; 091 List labelHistory = new ArrayList(); 092 private static final Logger logger = 093 LoggerFactory.getLogger(XmlChooser.class); 094 095 /** 096 * Create the {@code XmlChooser}. 097 * 098 * @param mgr {@code IdvChooserManager} 099 * @param root XML root that defines this chooser. 100 * 101 */ 102 public XmlChooser(IdvChooserManager mgr, Element root) { 103 super(mgr, root); 104 105 loadButton = McVGuiUtils.makeImageTextButton(ICON_ACCEPT_SMALL, getLoadCommandName()); 106 loadButton.setActionCommand(getLoadCommandName()); 107 loadButton.addActionListener(this); 108 109 cancelButton = McVGuiUtils.makeImageButton(ICON_CANCEL, "Cancel"); 110 cancelButton.setActionCommand(GuiUtils.CMD_CANCEL); 111 cancelButton.addActionListener(this); 112 cancelButton.setEnabled(false); 113 114 } 115 116 private void repaintCatalog() { 117 if (catalogPanel != null) { 118 catalogPanel.invalidate(); 119 catalogPanel.validate(); 120 catalogPanel.repaint(); 121 } 122 String labelName = (String)labelHistory.get(labelHistoryIdx); 123 catalogPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(labelName)); 124 } 125 126 /** 127 * Go back and display the previous document. 128 */ 129 public void goBack() { 130 super.goBack(); 131 labelHistoryIdx--; 132 repaintCatalog(); 133 } 134 135 /** 136 * Go forward and display the next document in the history list. 137 */ 138 public void goForward() { 139 super.goForward(); 140 labelHistoryIdx++; 141 repaintCatalog(); 142 } 143 144 /** 145 * Add a labeled border to the catalog browser indicating the data type 146 */ 147 protected void makeUi(Document doc, Element xmlRoot, String path) { 148 super.makeUi(doc, xmlRoot, path); 149 150 String tagName = xmlRoot.getTagName(); 151 String labelName = "Unknown Catalog Type"; 152 if (tagName.equals(WmsUtil.TAG_WMS1) || tagName.equals(WmsUtil.TAG_WMS2)) labelName = "Web Map Service"; 153 else if (tagName.equals(CatalogUtil.TAG_CATALOG)) labelName = "THREDDS"; 154 else if (tagName.equals("menus")) labelName = "Menu"; 155 156 labelHistoryIdx++; 157 labelHistory.add(labelHistoryIdx, labelName); 158 repaintCatalog(); 159 } 160 161 // McIDAS Inquiry #2842-3141 162 public void actionPerformed(ActionEvent ae) { 163 String cmd = ae.getActionCommand(); 164 if (cmd.equals(GuiUtils.CMD_CANCEL)) { 165 makeUiFromPath(urlBox.getSelectedItem().toString()); 166 this.getIdv().clearWaitCursor(); 167 if (this.cancelButton != null) { 168 this.cancelButton.setEnabled(false); 169 } 170 } else { 171 super.actionPerformed(ae); 172 } 173 } 174 175 private JLabel statusLabel = new JLabel("Status"); 176 177 @Override 178 public void setStatus(String statusString, String foo) { 179 if (statusString == null) 180 statusString = ""; 181 statusLabel.setText(statusString); 182 } 183 184 /** 185 * Create and return the Gui contents. 186 * 187 * @return The gui contents. 188 */ 189 protected JComponent doMakeContents() { 190 JComponent parentContents = super.doMakeContents(); 191 192 // Pull apart the panels 193 // Expected: 194 // Top: URL chooser 195 // Center: Catalog chooser 196 // Bottom: chooser buttons 197 // This takes a bit of digging--some of the components are really buried! 198 Component[] parentComps = parentContents.getComponents(); 199 if (parentComps.length != 3 || 200 !(parentComps[0] instanceof JPanel) || 201 !(parentComps[1] instanceof JPanel) || 202 !(parentComps[2] instanceof JPanel) 203 ) return parentContents; 204 205 // Assign file picker to fileComponent 206 JPanel topPanel = (JPanel)parentComps[0]; 207 Component[] panels = topPanel.getComponents(); 208 if (panels.length != 2 || 209 !(panels[0] instanceof JPanel) || 210 !(panels[1] instanceof JPanel) 211 ) return parentContents; 212 // Found the navigation panel 213 JPanel navigationPanel = (JPanel)panels[0]; 214 panels = ((JPanel)panels[1]).getComponents(); 215 if (panels.length != 3 || 216 !(panels[0] instanceof JLabel) || 217 !(panels[1] instanceof JPanel) || 218 !(panels[2] instanceof JButton) 219 ) return parentContents; 220 // Found the button 221 JButton fileButton = (JButton)panels[2]; 222 panels = ((JPanel)panels[1]).getComponents(); 223 if (panels.length != 1 || 224 !(panels[0] instanceof JComboBox) 225 ) return parentContents; 226 JComboBox fileComponent = (JComboBox)panels[0]; 227 McVGuiUtils.setButtonImage(fileButton, ICON_OPEN_SMALL); 228 McVGuiUtils.setComponentWidth(fileButton, Width.DOUBLE); 229 McVGuiUtils.setComponentWidth(fileComponent, Width.DOUBLEDOUBLE); 230 McVGuiUtils.setComponentHeight(fileComponent, fileButton); 231 232 // Deal with the navigation buttons 233 panels = navigationPanel.getComponents(); 234 if (panels.length != 2 || 235 !(panels[0] instanceof JButton) || 236 !(panels[1] instanceof JButton) 237 ) return parentContents; 238 McVGuiUtils.setButtonImage((JButton)panels[0], Constants.ICON_PREVIOUS_SMALL); 239 McVGuiUtils.setButtonImage((JButton)panels[1], Constants.ICON_NEXT_SMALL); 240 JLabel navigationLabel = McVGuiUtils.makeLabelRight("History:"); 241 navigationPanel = GuiUtils.hbox(panels[0], panels[1]); 242 243 // Rearrange the catalog browser and assign it to innerPanel 244 catalogPanel = (JPanel)parentComps[1]; 245 JPanel innerPanel = McVGuiUtils.makeLabeledComponent("Browse:", catalogPanel); 246 247 // Start building the whole thing here 248 JPanel outerPanel = new JPanel(); 249 250 JLabel fileLabel = McVGuiUtils.makeLabelRight("Catalog:"); 251 252 JLabel statusLabelLabel = McVGuiUtils.makeLabelRight(""); 253 254 McVGuiUtils.setLabelPosition(statusLabel, Position.RIGHT); 255 McVGuiUtils.setComponentColor(statusLabel, TextColor.STATUS); 256 257 JButton helpButton = McVGuiUtils.makeImageButton(ICON_HELP, "Show help"); 258 helpButton.setActionCommand(GuiUtils.CMD_HELP); 259 helpButton.addActionListener(this); 260 261 JButton refreshButton = McVGuiUtils.makeImageButton(ICON_REFRESH, "Refresh"); 262 refreshButton.setActionCommand(GuiUtils.CMD_UPDATE); 263 refreshButton.addActionListener(this); 264 265 McVGuiUtils.setButtonImage(loadButton, ICON_ACCEPT_SMALL); 266 McVGuiUtils.setComponentWidth(loadButton, Width.DOUBLE); 267 268 GroupLayout layout = new GroupLayout(outerPanel); 269 outerPanel.setLayout(layout); 270 layout.setHorizontalGroup( 271 layout.createParallelGroup(LEADING) 272 .addGroup(TRAILING, layout.createSequentialGroup() 273 .addGroup(layout.createParallelGroup(TRAILING) 274 .addGroup(layout.createSequentialGroup() 275 .addContainerGap() 276 .addComponent(helpButton) 277 .addGap(GAP_RELATED) 278 .addComponent(refreshButton) 279 .addGap(GAP_RELATED) 280 .addComponent(cancelButton) 281 .addPreferredGap(RELATED) 282 .addComponent(loadButton)) 283 .addGroup(LEADING, layout.createSequentialGroup() 284 .addContainerGap() 285 .addGroup(layout.createParallelGroup(LEADING) 286 .addGroup(layout.createSequentialGroup() 287 .addComponent(navigationLabel) 288 .addGap(GAP_RELATED) 289 .addComponent(navigationPanel)) 290 .addComponent(innerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE) 291 .addGroup(layout.createSequentialGroup() 292 .addComponent(fileLabel) 293 .addGap(GAP_RELATED) 294 .addComponent(fileComponent) 295 .addGap(GAP_UNRELATED) 296 .addComponent(fileButton)) 297 .addGroup(layout.createSequentialGroup() 298 .addComponent(statusLabelLabel) 299 .addGap(GAP_RELATED) 300 .addComponent(statusLabel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))))) 301 .addContainerGap()) 302 ); 303 layout.setVerticalGroup( 304 layout.createParallelGroup(LEADING) 305 .addGroup(layout.createSequentialGroup() 306 .addContainerGap() 307 .addGroup(layout.createParallelGroup(BASELINE) 308 .addComponent(fileLabel) 309 .addComponent(fileComponent) 310 .addComponent(fileButton)) 311 .addPreferredGap(UNRELATED) 312 .addGroup(layout.createParallelGroup(BASELINE) 313 .addComponent(navigationLabel) 314 .addComponent(navigationPanel)) 315 .addPreferredGap(RELATED) 316 317 .addComponent(innerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE) 318 .addPreferredGap(UNRELATED) 319 .addGroup(layout.createParallelGroup(BASELINE) 320 .addComponent(statusLabelLabel) 321 .addComponent(statusLabel)) 322 .addPreferredGap(UNRELATED) 323 .addGroup(layout.createParallelGroup(BASELINE) 324 .addComponent(loadButton) 325 .addComponent(cancelButton) 326 .addComponent(refreshButton) 327 .addComponent(helpButton)) 328 .addContainerGap()) 329 ); 330 331 return outerPanel; 332 333 } 334 335} 336