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