001/*
002 * $Id: ImagePlanViewControl.java,v 1.22 2011/03/24 16:06:32 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.control;
032
033import java.awt.BorderLayout;
034import java.awt.Color;
035import java.awt.Component;
036import java.awt.Container;
037import java.awt.Dimension;
038import java.awt.event.ActionEvent;
039import java.awt.event.ActionListener;
040import java.awt.event.MouseEvent;
041import java.rmi.RemoteException;
042import java.util.ArrayList;
043import java.util.Hashtable;
044import java.util.List;
045
046import javax.swing.JButton;
047import javax.swing.JComponent;
048import javax.swing.JFrame;
049import javax.swing.JLabel;
050import javax.swing.JMenu;
051import javax.swing.JMenuItem;
052import javax.swing.JPanel;
053import javax.swing.JPopupMenu;
054import javax.swing.JTabbedPane;
055import javax.swing.JTextField;
056import javax.swing.event.ChangeEvent;
057import javax.swing.event.ChangeListener;
058
059import org.slf4j.Logger;
060import org.slf4j.LoggerFactory;
061import org.w3c.dom.Document;
062import org.w3c.dom.Element;
063import org.w3c.dom.Node;
064
065import visad.Data;
066import visad.DateTime;
067import visad.FieldImpl;
068import visad.FlatField;
069import visad.VisADException;
070import visad.meteorology.ImageSequenceImpl;
071
072import ucar.unidata.data.DataChoice;
073import ucar.unidata.data.DataSelection;
074import ucar.unidata.data.DataSourceImpl;
075import ucar.unidata.data.imagery.AddeImageDescriptor;
076import ucar.unidata.data.imagery.BandInfo;
077import ucar.unidata.idv.ControlContext;
078import ucar.unidata.idv.IdvResourceManager;
079import ucar.unidata.idv.control.ColorTableWidget;
080import ucar.unidata.idv.control.DisplayControlImpl;
081import ucar.unidata.ui.XmlTree;
082import ucar.unidata.util.ColorTable;
083import ucar.unidata.util.GuiUtils;
084import ucar.unidata.util.Range;
085import ucar.unidata.xml.XmlResourceCollection;
086import ucar.unidata.xml.XmlUtil;
087
088import edu.wisc.ssec.mcidasv.PersistenceManager;
089import edu.wisc.ssec.mcidasv.chooser.ImageParameters;
090import edu.wisc.ssec.mcidasv.data.ComboDataChoice;
091import edu.wisc.ssec.mcidasv.data.adde.AddeImageParameterDataSource;
092
093/**
094 * {@link ucar.unidata.idv.control.ImagePlanViewControl} with some McIDAS-V
095 * specific extensions. Namely parameter sets and support for inverted 
096 * parameter defaults.
097 */
098public class ImagePlanViewControl extends ucar.unidata.idv.control.ImagePlanViewControl {
099
100    private static final Logger logger = LoggerFactory.getLogger(ImagePlanViewControl.class);
101
102    private static final String TAG_FOLDER = "folder";
103    private static final String TAG_DEFAULT = "default";
104    private static final String ATTR_NAME = "name";
105    private static final String ATTR_SERVER = "server";
106    private static final String ATTR_POS = "POS";
107    private static final String ATTR_DAY = "DAY";
108    private static final String ATTR_TIME = "TIME";
109    private static final String ATTR_UNIT = "UNIT";
110
111    /** Command for connecting */
112    protected static final String CMD_NEWFOLDER = "cmd.newfolder";
113    protected static final String CMD_NEWPARASET = "cmd.newparaset";
114
115    /** save parameter set */
116    private JFrame saveWindow;
117
118    private static String newFolder;
119
120    private XmlTree xmlTree;
121
122    /** Install new folder fld */
123    private JTextField folderFld;
124
125    /** Holds the current save set tree */
126    private JPanel treePanel;
127
128    /** The user imagedefaults xml root */
129    private static Element imageDefaultsRoot;
130
131    /** The user imagedefaults xml document */
132    private static Document imageDefaultsDocument;
133
134    /** Holds the ADDE servers and groups*/
135    private static XmlResourceCollection imageDefaults;
136
137    private Node lastCat;
138
139    private static Element lastClicked;
140
141    private JButton newFolderBtn;
142
143    private JButton newSetBtn;
144
145    private String newCompName = "";
146
147    /** Shows the status */
148    private JLabel statusLabel;
149
150    /** Status bar component */
151    private JComponent statusComp;
152
153    private JPanel contents;
154
155    private DataSourceImpl dataSource;
156
157    private FlatField image;
158
159    private McIDASVHistogramWrapper histoWrapper;
160
161    public ImagePlanViewControl() {
162        super();
163        logger.trace("created new imageplanviewcontrol={}", Integer.toHexString(hashCode()));
164        this.imageDefaults = getImageDefaults();
165    }
166
167    @Override public boolean init(DataChoice dataChoice) 
168        throws VisADException, RemoteException 
169    {
170//        this.dataChoice = (DataChoice)this.getDataChoices().get(0);
171        boolean result = super.init((DataChoice)this.getDataChoices().get(0));
172        return result;
173    }
174
175    /**
176     * Get the xml resource collection that defines the image default xml
177     *
178     * @return Image defaults resources
179     */
180    protected XmlResourceCollection getImageDefaults() {
181        XmlResourceCollection ret = null;
182        try {
183            ControlContext controlContext = getControlContext();
184            if (controlContext != null) {
185                IdvResourceManager irm = controlContext.getResourceManager();
186                ret=irm.getXmlResources( IdvResourceManager.RSC_IMAGEDEFAULTS);
187                if (ret.hasWritableResource()) {
188                    imageDefaultsDocument =
189                        ret.getWritableDocument("<imagedefaults></imagedefaults>");
190                    imageDefaultsRoot =
191                        ret.getWritableRoot("<imagedefaults></imagedefaults>");
192                }
193            }
194        } catch (Exception e) {
195            System.out.println("e=" + e);
196        }
197        return ret;
198    }
199
200
201    /**
202     * Called by doMakeWindow in DisplayControlImpl, which then calls its
203     * doMakeMainButtonPanel(), which makes more buttons.
204     *
205     * @return container of contents
206     */
207    public Container doMakeContents() {
208        try {
209            JTabbedPane tab = new MyTabbedPane();
210            tab.add("Settings",
211                GuiUtils.inset(GuiUtils.top(doMakeWidgetComponent()), 5));
212            tab.add("Histogram", GuiUtils.inset(getHistogramTabComponent(),5));
213            //Set this here so we don't get odd crud on the screen
214            //When the MyTabbedPane goes to paint itself the first time it
215            //will set the tab back to 0
216            tab.setSelectedIndex(1);
217            GuiUtils.handleHeavyWeightComponentsInTabs(tab);
218//            ColorTableWidget ctw = getColorTableWidget(getRange());
219            Range range = getRange();
220//            int lo = (int)range.getMin();
221//            int hi = (int)range.getMax();
222            double lo = range.getMin();
223            double hi = range.getMax();
224            boolean flag = histoWrapper.modifyRange(lo, hi);
225            ((MyTabbedPane)tab).setPopupFlag(!flag);
226            histoWrapper.setHigh(hi);
227            histoWrapper.setLow(lo);
228            return tab;
229        } catch (Exception exc) {
230            logException("doMakeContents", exc);
231        }
232        return null;
233    }
234
235    protected JComponent getHistogramTabComponent() {
236        List choices = new ArrayList();
237        if (datachoice == null) {
238            datachoice = getDataChoice();
239        }
240        choices.add(datachoice);
241        histoWrapper = new McIDASVHistogramWrapper("histo", choices, (DisplayControlImpl)this);
242        dataSource = getDataSource();
243
244        if (dataSource == null) {
245            try {
246                image = (FlatField)((ComboDataChoice)datachoice).getData();
247                histoWrapper.loadData(image);
248            } catch (Exception e) {
249                
250            }
251        } else {
252            Hashtable props = dataSource.getProperties();
253            try {
254//                this.dataSelection = dataChoice.getDataSelection();
255                DataSelection testSelection = datachoice.getDataSelection();
256                DataSelection realSelection = getDataSelection();
257                if (testSelection == null) {
258                    datachoice.setDataSelection(realSelection);
259                }
260                ImageSequenceImpl seq = null;
261                if (dataSelection == null)
262                    dataSelection = dataSource.getDataSelection();
263                if (dataSelection == null) {
264                    image = (FlatField)dataSource.getData(datachoice, null, props);
265                    if (image == null) {
266                        image = (FlatField)datachoice.getData(null);
267                    }
268                } else {
269//                    if (dataChoice.getDataSelection() == null) {
270//                        dataChoice.setDataSelection(dataSelection)
271//                    }
272                    Data data = dataSource.getData(datachoice, null, dataSelection, props);
273                    if (data instanceof ImageSequenceImpl) {
274                        seq = (ImageSequenceImpl) data;
275                    } else if (data instanceof FlatField) {
276                        image = (FlatField) data;
277                    } else if (data instanceof FieldImpl) {
278                        image = (FlatField) ((FieldImpl)data).getSample(0, false);
279                    }
280                    else {
281                        throw new Exception("Histogram must be made from a FlatField");
282                    }
283                }
284                if (seq != null) {
285                    if (seq.getImageCount() > 0) 
286                        image = (FlatField)seq.getImage(0);
287                }
288                histoWrapper.loadData(image);
289                /*
290            double lo = histoWrapper.getLow();
291            double hi = histoWrapper.getHigh();
292            contrastStretch(lo, hi);
293                 */
294            } catch (Exception e) {
295                //System.out.println("Histo e=" + e);
296            }
297        }
298
299        JComponent histoComp = histoWrapper.doMakeContents();
300        JButton resetButton = new JButton("Reset");
301        resetButton.addActionListener(new ActionListener() {
302            public void actionPerformed(ActionEvent ae) {
303                resetColorTable();
304            }
305        });
306        JPanel resetPanel =
307            GuiUtils.center(GuiUtils.inset(GuiUtils.wrap(resetButton), 4));
308        return GuiUtils.centerBottom(histoComp, resetPanel);
309    }
310
311    protected void contrastStretch(double low, double high) {
312        ColorTable ct = getColorTable();
313        if (ct != null) {
314            Range range = new Range(low, high);
315            try {
316                setRange(ct.getName(), range);
317            } catch (Exception e) {
318                System.out.println("contrast stretch e=" + e);
319            }
320        }
321    }
322
323    @Override public boolean setData(DataChoice dataChoice) throws VisADException, RemoteException {
324        boolean result = super.setData(dataChoice);
325        logger.trace("result: {}, dataChoice: {}", result, dataChoice);
326        return result;
327    }
328
329    @Override public void setRange(final Range newRange) throws RemoteException, VisADException {
330        logger.trace("newRange: {} [avoiding NPE!]", newRange);
331        super.setRange(newRange);
332    }
333        
334    public void resetColorTable() {
335        try {
336            revertToDefaultColorTable();
337            revertToDefaultRange();
338            histoWrapper.resetPlot();
339        } catch (Exception e) {
340            System.out.println("resetColorTable e=" + e);
341        }
342    }
343
344    protected void getSaveMenuItems(List items, boolean forMenuBar) {
345        super.getSaveMenuItems(items, forMenuBar);
346
347        // DAVEP: Remove the parameter set save options for now...
348//        items.add(GuiUtils.makeMenuItem("Save Image Parameter Set (TEST)", this,
349//        "popupPersistImageParameters"));
350//
351//        items.add(GuiUtils.makeMenuItem("Save Image Parameter Set", this,
352//        "popupSaveImageParameters"));
353        
354        items.add(GuiUtils.makeMenuItem("Save As Local Data Source", this,
355        "saveDataToLocalDisk"));
356    }
357
358    public void popupPersistImageParameters() {
359        PersistenceManager pm = (PersistenceManager)getIdv().getPersistenceManager();
360        pm.saveParameterSet("addeimagery", makeParameterValues());
361    }
362
363    private Hashtable makeParameterValues() {
364        Hashtable parameterValues = new Hashtable();
365        //      Document doc = XmlUtil.makeDocument();
366        //      Element newChild = doc.createElement(TAG_DEFAULT);
367
368        if (datachoice == null) {
369            datachoice = getDataChoice();
370        }
371        dataSource = getDataSource();
372        if (!(dataSource.getClass().isInstance(new AddeImageParameterDataSource()))) {
373            System.err.println("dataSource not a AddeImageParameterDataSource");
374            return parameterValues;
375        }
376        AddeImageParameterDataSource testDataSource = (AddeImageParameterDataSource)dataSource;
377        List imageList = testDataSource.getDescriptors(datachoice, this.dataSelection);
378        int numImages = imageList.size();
379        List dateTimes = new ArrayList();
380        DateTime thisDT = null;
381        if (!(imageList == null)) {
382            AddeImageDescriptor aid = null;
383            for (int imageNo=0; imageNo<numImages; imageNo++) {
384                aid = (AddeImageDescriptor)(imageList.get(imageNo));
385                thisDT = aid.getImageTime();
386                if (!(dateTimes.contains(thisDT))) {
387                    if (thisDT != null) {
388                        dateTimes.add(thisDT);
389                    }
390                }
391            }
392
393            // Set the date and time for later reference
394            String dateS = "";
395            String timeS = "";
396            if (!(dateTimes.isEmpty())) {
397                thisDT = (DateTime)dateTimes.get(0);
398                dateS = thisDT.dateString();
399                timeS = thisDT.timeString();
400                if (dateTimes.size() > 1) {
401                    for (int img=1; img<dateTimes.size(); img++) {
402                        thisDT = (DateTime)dateTimes.get(img);
403                        String str = "," + thisDT.dateString();
404                        String newString = new String(dateS + str);
405                        dateS = newString;
406                        str = "," + thisDT.timeString();
407                        newString = new String(timeS + str);
408                        timeS = newString;
409                    }
410                }
411            }
412
413            // Set the unit for later reference
414            String unitS = "";
415            if (!(datachoice.getId() instanceof BandInfo)) {
416                System.err.println("dataChoice ID not a BandInfo");
417                return parameterValues;
418            }
419            BandInfo bi = (BandInfo)datachoice.getId();
420            unitS = bi.getPreferredUnit();
421
422            if (aid != null) {
423                String displayUrl = testDataSource.getDisplaySource();
424                ImageParameters ip = new ImageParameters(displayUrl);                           
425                List props = ip.getProperties();
426                List vals = ip.getValues();
427                String server = ip.getServer();
428                parameterValues.put(ATTR_SERVER, server);
429                //                      newChild.setAttribute(ATTR_SERVER, server);
430                int num = props.size();
431                if (num > 0) {
432                    String attr = "";
433                    String val = "";
434                    for (int i=0; i<num; i++) {
435                        attr = (String)(props.get(i));
436                        if (attr.equals(ATTR_POS)) {
437                            val = new Integer(numImages - 1).toString();
438                        } else if (attr.equals(ATTR_DAY)) {
439                            val = dateS;
440                        } else if (attr.equals(ATTR_TIME)) {
441                            val = timeS;
442                        } else if (attr.equals(ATTR_UNIT)) {
443                            val = unitS;
444                        } else {
445                            val = (String)(vals.get(i));
446                        }
447                        parameterValues.put(attr, val);
448                    }
449                }
450            }
451        }
452        return parameterValues;
453    }
454
455    public void saveDataToLocalDisk() {
456        getDataSource().saveDataToLocalDisk();
457    }
458
459    public void popupSaveImageParameters() {
460        if (saveWindow == null) {
461            showSaveDialog();
462            return;
463        }
464        saveWindow.setVisible(true);
465        GuiUtils.toFront(saveWindow);
466    }
467
468    private void showSaveDialog() {
469        if (saveWindow == null) {
470            saveWindow = GuiUtils.createFrame("Save Image Parameter Set");
471        }
472        if (statusComp == null) {
473            statusLabel = new JLabel();
474            statusComp = GuiUtils.inset(statusLabel, 2);
475            statusComp.setBackground(new Color(255, 255, 204));
476            statusLabel.setOpaque(true); 
477            statusLabel.setBackground(new Color(255, 255, 204));
478        }
479        JPanel statusPanel = GuiUtils.inset(GuiUtils.top( GuiUtils.vbox(new JLabel(" "),
480            GuiUtils.hbox(GuiUtils.rLabel("Status: "), statusComp),
481            new JLabel(" "))), 6);
482        JPanel sPanel = GuiUtils.topCenter(statusPanel, GuiUtils.filler());
483
484        List newComps = new ArrayList();
485        final JTextField newName = new JTextField(20);
486        newName.addActionListener(new ActionListener() {
487            public void actionPerformed(ActionEvent ae) {
488                setStatus("Click New Folder or New ParameterSet button");
489                newCompName = newName.getText().trim();
490            }
491        });
492        newComps.add(newName);
493        newComps.add(GuiUtils.filler());
494        newFolderBtn = new JButton("New Folder");
495        newFolderBtn.addActionListener(new ActionListener() {
496            public void actionPerformed(ActionEvent ae) {
497                newFolder = newName.getText().trim();
498                if (newFolder.length() == 0) {
499                    newComponentError("folder");
500                    return;
501                }
502                Element exists = XmlUtil.findElement(imageDefaultsRoot, "folder", ATTR_NAME, newFolder);
503                if (!(exists == null)) {
504                    if (!GuiUtils.askYesNo("Verify Replace Folder",
505                        "Do you want to replace the folder " +
506                        "\"" + newFolder + "\"?" +
507                    "\nNOTE: All parameter sets it contains will be deleted.")) return;
508                    imageDefaultsRoot.removeChild(exists);
509                }
510                newName.setText("");
511                Node newEle = makeNewFolder();
512                makeXmlTree();
513                xmlTree.selectElement((Element)newEle);
514                lastCat = newEle;
515                lastClicked = null;
516                newSetBtn.setEnabled(true);
517                setStatus("Please enter a name for the new parameter set");
518            }
519        });
520        newComps.add(newFolderBtn);
521        newComps.add(GuiUtils.filler());
522        newName.setEnabled(true);
523        newFolderBtn.setEnabled(true);
524        newSetBtn = new JButton("New Parameter Set");
525        newSetBtn.setActionCommand(CMD_NEWPARASET);
526        newSetBtn.addActionListener(new ActionListener() {
527            public void actionPerformed(ActionEvent ae) {
528                newCompName = newName.getText().trim();
529                if (newCompName.length() == 0) {
530                    newComponentError("parameter set");
531                    return;
532                }
533                newName.setText("");
534                Element newEle = saveParameterSet();
535                if (newEle == null) return;
536                xmlTree.selectElement(newEle);
537                lastClicked = newEle;
538            }
539        });
540        newComps.add(newSetBtn);
541        newSetBtn.setEnabled(false);
542
543        JPanel newPanel = GuiUtils.top(GuiUtils.left(GuiUtils.hbox(newComps)));
544        JPanel topPanel = GuiUtils.topCenter(sPanel, newPanel);
545
546        treePanel = new JPanel();
547        treePanel.setLayout(new BorderLayout());
548        makeXmlTree();
549        ActionListener listener = new ActionListener() {
550            public void actionPerformed(ActionEvent event) {
551                String cmd = event.getActionCommand();
552                if (cmd.equals(GuiUtils.CMD_CANCEL)) {
553                    if (lastClicked != null) {
554                        removeNode(lastClicked);
555                        lastClicked = null;
556                    }
557                    saveWindow.setVisible(false);
558                    saveWindow = null;
559                } else {
560                    saveWindow.setVisible(false);
561                    saveWindow = null;
562                }
563            }
564        };
565        JPanel bottom =
566            GuiUtils.inset(GuiUtils.makeApplyCancelButtons(listener), 5);
567        contents = 
568            GuiUtils.topCenterBottom(topPanel, treePanel, bottom);
569
570        saveWindow.getContentPane().add(contents);
571        saveWindow.pack();
572        saveWindow.setLocation(200, 200);
573
574        saveWindow.setVisible(true);
575        GuiUtils.toFront(saveWindow);
576        setStatus("Please select a folder from tree, or create a new folder");
577    }
578
579    private void newComponentError(String comp) {
580        JLabel label = new JLabel("Please enter " + comp +" name");
581        JPanel contents = GuiUtils.top(GuiUtils.inset(label, 24));
582        GuiUtils.showOkCancelDialog(null, "Make Component Error", contents, null);
583    }
584
585    private void setStatus(String msg) {
586        statusLabel.setText(msg);
587        contents.paintImmediately(0,0,contents.getWidth(),
588            contents.getHeight());
589    }
590
591    private void removeNode(Element node) {
592        if (imageDefaults == null) {
593            imageDefaults = getImageDefaults();
594        }
595        Node parent = node.getParentNode();
596        parent.removeChild(node);
597        makeXmlTree();
598        try {
599            imageDefaults.writeWritable();
600        } catch (Exception e) {
601            System.out.println("write error e=" + e);
602        }
603        imageDefaults.setWritableDocument(imageDefaultsDocument,
604            imageDefaultsRoot);
605    }
606
607    private Node makeNewFolder() {
608        if (imageDefaults == null) {
609            imageDefaults = getImageDefaults();
610        }
611        if (newFolder.length() == 0) {
612            return null;
613        }
614        List newChild = new ArrayList();
615        Node newEle = imageDefaultsDocument.createElement(TAG_FOLDER);
616        lastCat = newEle;
617        String[] newAttrs = { ATTR_NAME, newFolder };
618        XmlUtil.setAttributes((Element)newEle, newAttrs);
619        newChild.add(newEle);
620        XmlUtil.addChildren(imageDefaultsRoot, newChild);
621        try {
622            imageDefaults.writeWritable();
623        } catch (Exception e) {
624            System.out.println("write error e=" + e);
625        }
626        imageDefaults.setWritableDocument(imageDefaultsDocument,
627            imageDefaultsRoot);
628        return newEle;
629    }
630
631    /**
632     * Just creates an empty XmlTree
633     */
634    private void makeXmlTree() {
635        if (imageDefaults == null) {
636            imageDefaults = getImageDefaults();
637        }
638        xmlTree = new XmlTree(imageDefaultsRoot, true, "") {
639            public void doClick(XmlTree theTree, XmlTree.XmlTreeNode node,
640                Element element) {
641                Element clicked = xmlTree.getSelectedElement();
642                String lastTag = clicked.getTagName();
643                if ("folder".equals(lastTag)) {
644                    lastCat = clicked;
645                    lastClicked = null;
646                    setStatus("Please enter a name for the new parameter set");
647                    newSetBtn.setEnabled(true);
648                } else {
649                    lastCat = clicked.getParentNode();
650                    lastClicked = clicked;
651                }
652            }
653
654            public void doRightClick(XmlTree theTree,
655                XmlTree.XmlTreeNode node,
656                Element element, MouseEvent event) {
657                JPopupMenu popup = new JPopupMenu();
658                if (makePopupMenu(theTree, element, popup)) {
659                    popup.show((Component) event.getSource(), event.getX(),
660                        event.getY());
661                }
662            }
663        };
664        List tagList = new ArrayList();
665        tagList.add(TAG_FOLDER);
666        tagList.add(TAG_DEFAULT);
667        xmlTree.addTagsToProcess(tagList);
668        xmlTree.defineLabelAttr(TAG_FOLDER, ATTR_NAME);
669        addToContents(GuiUtils.inset(GuiUtils.topCenter(new JPanel(),
670            xmlTree.getScroller()), 5));
671        return;
672    }
673
674    private List getFolders() {
675        return XmlUtil.findChildren(imageDefaultsRoot, TAG_FOLDER);
676    }
677
678
679    private void doDeleteRequest(Node node) {
680        if (node == null) {
681            return;
682        }
683        Element ele = (Element)node;
684        String tagName = ele.getTagName();
685        if (tagName.equals("folder")) {
686            if (!GuiUtils.askYesNo("Verify Delete Folder",
687                "Do you want to delete the folder " +
688                "\"" + ele.getAttribute("name") + "\"?" +
689            "\nNOTE: All parameter sets it contains will be deleted.")) return;
690            XmlUtil.removeChildren(ele);
691        } else if (tagName.equals("default")) {
692            if (!GuiUtils.askYesNo("Verify Delete", "Do you want to delete " +
693                "\"" + ele.getAttribute(ATTR_NAME) + "\"?")) return;
694        } else { return; }
695        removeNode(ele);
696    }
697    /**
698     *  Create and popup a command menu for when the user has clicked on the given xml node.
699     *
700     *  @param theTree The XmlTree object displaying the current xml document.
701     *  @param node The xml node the user clicked on.
702     *  @param popup The popup menu to put the menu items in.
703     * @return Did we add any items into the menu
704     */
705    private boolean makePopupMenu(final XmlTree theTree, final Element node,
706        JPopupMenu popup) 
707    {
708        theTree.selectElement(node);
709        String tagName = node.getTagName();
710        final Element parent = (Element)node.getParentNode();
711        boolean didone  = false;
712        JMenuItem mi;
713
714        if (tagName.equals("default")) {
715            lastClicked = node;
716            JMenu moveMenu = new JMenu("Move to");
717            List folders = getFolders();
718            for (int i = 0; i < folders.size(); i++) {
719                final Element newFolder = (Element)folders.get(i);
720                if (!newFolder.isSameNode(parent)) {
721                    String name = newFolder.getAttribute(ATTR_NAME);
722                    mi = new JMenuItem(name);
723                    mi.addActionListener(new ActionListener() {
724                        public void actionPerformed(ActionEvent ae) {
725                            moveParameterSet(parent, newFolder);
726                        }
727                    });
728                    moveMenu.add(mi);
729                }
730            }
731            popup.add(moveMenu);
732            popup.addSeparator();
733            didone = true;
734        }
735
736        mi = new JMenuItem("Rename...");
737        mi.addActionListener(new ActionListener() {
738            public void actionPerformed(ActionEvent ae) {
739                doRename(node);
740            }
741        });
742        popup.add(mi);
743        didone = true;
744
745        mi = new JMenuItem("Delete");
746        mi.addActionListener(new ActionListener() {
747            public void actionPerformed(ActionEvent ae) {
748                doDeleteRequest(node);
749            }
750        });
751        popup.add(mi);
752        didone = true;
753
754        return didone;
755    }
756
757    public void moveParameterSet(Element parent, Element newFolder) {
758        if (imageDefaults == null) {
759            imageDefaults = getImageDefaults();
760        }
761        if (lastClicked == null) {
762            return;
763        }
764        Node copyNode = lastClicked.cloneNode(true);
765        newFolder.appendChild(copyNode);
766        parent.removeChild(lastClicked);
767        lastCat = newFolder;
768        makeXmlTree();
769        try {
770            imageDefaults.writeWritable();
771        } catch (Exception e) {
772            System.out.println("write error e=" + e);
773        }
774        imageDefaults.setWritableDocument(imageDefaultsDocument, imageDefaultsRoot);
775    }
776
777    private void doRename(Element node) {
778        if (imageDefaults == null) {
779            imageDefaults = getImageDefaults();
780        }
781        if (!node.hasAttribute(ATTR_NAME)) return;
782        JLabel label = new JLabel("New name: ");
783        JTextField nameFld = new JTextField("", 20);
784        JComponent contents = GuiUtils.doLayout(new Component[] {
785            GuiUtils.rLabel("New name: "), nameFld, }, 2,
786            GuiUtils.WT_N, GuiUtils.WT_N);
787        contents = GuiUtils.center(contents);
788        contents = GuiUtils.inset(contents, 10);
789        if (!GuiUtils.showOkCancelDialog(null, "Rename \"" +
790            node.getAttribute("name") + "\"", contents, null)) return;
791        String newName = nameFld.getText().trim();
792        String tagName = node.getTagName();
793        Element root = imageDefaultsRoot;
794        if (tagName.equals("default")) {
795            root = (Element)node.getParentNode();
796        }
797        Element exists = XmlUtil.findElement(root, tagName, ATTR_NAME, newName);
798        if (!(exists == null)) {
799            if (!GuiUtils.askYesNo("Name Already Exists",
800                "Do you want to replace " + node.getAttribute("name") + " with" +
801                "\"" + newName + "\"?")) return;
802        }
803        node.removeAttribute(ATTR_NAME);
804        node.setAttribute(ATTR_NAME, newName);
805        makeXmlTree();
806        try {
807            imageDefaults.writeWritable();
808        } catch (Exception e) {
809            System.out.println("write error e=" + e);
810        }
811        imageDefaults.setWritableDocument(imageDefaultsDocument,
812            imageDefaultsRoot);
813    }
814
815    /**
816     *  Remove the currently display gui and insert the given one.
817     *
818     *  @param comp The new gui.
819     */
820    private void addToContents(JComponent comp) {
821        treePanel.removeAll();
822        comp.setPreferredSize(new Dimension(200, 300));
823        treePanel.add(comp, BorderLayout.CENTER);
824        if (contents != null) {
825            contents.invalidate();
826            contents.validate();
827            contents.repaint();
828        }
829    }
830
831    public DataSourceImpl getDataSource() {
832        DataSourceImpl ds = null;
833        List dataSources = getDataSources();
834        if (!dataSources.isEmpty()) {
835            ds = (DataSourceImpl)dataSources.get(0);
836        }
837        return ds;
838    }
839
840    public Element saveParameterSet() {
841        if (imageDefaults == null) {
842            imageDefaults = getImageDefaults();
843        }
844        if (newCompName.length() == 0) {
845            newComponentError("parameter set");
846            return null;
847        }
848        Element newChild = imageDefaultsDocument.createElement(TAG_DEFAULT);
849        newChild.setAttribute(ATTR_NAME, newCompName);
850
851        if (datachoice == null) {
852            datachoice = getDataChoice();
853        }
854        dataSource = getDataSource();
855        if (!(dataSource.getClass().isInstance(new AddeImageParameterDataSource()))) {
856            return newChild;
857        }
858        AddeImageParameterDataSource testDataSource = (AddeImageParameterDataSource)dataSource;
859        List imageList = testDataSource.getDescriptors(datachoice, this.dataSelection);
860        int numImages = imageList.size();
861        List dateTimes = new ArrayList();
862        DateTime thisDT = null;
863        if (!(imageList == null)) {
864            AddeImageDescriptor aid = null;
865            for (int imageNo = 0; imageNo < numImages; imageNo++) {
866                aid = (AddeImageDescriptor)(imageList.get(imageNo));
867                thisDT = aid.getImageTime();
868                if (!(dateTimes.contains(thisDT))) {
869                    if (thisDT != null) {
870                        dateTimes.add(thisDT);
871                    }
872                }
873            }
874            String dateS = "";
875            String timeS = "";
876            if (!(dateTimes.isEmpty())) {
877                thisDT = (DateTime)dateTimes.get(0);
878                dateS = thisDT.dateString();
879                timeS = thisDT.timeString();
880                if (dateTimes.size() > 1) {
881                    for (int img = 1; img < dateTimes.size(); img++) {
882                        thisDT = (DateTime)dateTimes.get(img);
883                        String str = ',' + thisDT.dateString();
884                        String newString = new String(dateS + str);
885                        dateS = newString;
886                        str = ',' + thisDT.timeString();
887                        newString = new String(timeS + str);
888                        timeS = newString;
889                    }
890                }
891            }
892            if (aid != null) {
893                String displayUrl = testDataSource.getDisplaySource();
894                ImageParameters ip = new ImageParameters(displayUrl);
895                List props = ip.getProperties();
896                List vals = ip.getValues();
897                String server = ip.getServer();
898                newChild.setAttribute(ATTR_SERVER, server);
899                int num = props.size();
900                if (num > 0) {
901                    String attr = "";
902                    String val = "";
903                    for (int i = 0; i < num; i++) {
904                        attr = (String)(props.get(i));
905                        if (attr.equals(ATTR_POS)) {
906                            val = new Integer(numImages - 1).toString();
907                        } else if (attr.equals(ATTR_DAY)) {
908                            val = dateS;
909                        } else if (attr.equals(ATTR_TIME)) {
910                            val = timeS;
911                        } else {
912                            val = (String)(vals.get(i));
913                        }
914                        newChild.setAttribute(attr, val);
915                    }
916                }
917            }
918        }
919        Element parent = xmlTree.getSelectedElement();
920        if (parent == null) {
921            parent = (Element)lastCat;
922        }
923        if (parent != null) {
924            Element exists = XmlUtil.findElement(parent, "default", ATTR_NAME, newCompName);
925            if (!(exists == null)) {
926                JLabel label = new JLabel("Replace \"" + newCompName + "\"?");
927                JPanel contents = GuiUtils.top(GuiUtils.inset(label, newCompName.length()+12));
928                if (!GuiUtils.showOkCancelDialog(null, "Parameter Set Exists", contents, null)) {
929                    return newChild;
930                }
931                parent.removeChild(exists);
932            }
933            parent.appendChild(newChild);
934            makeXmlTree();
935        }
936        try {
937            imageDefaults.writeWritable();
938        } catch (Exception e) {
939            System.out.println("write error e=" + e);
940        }
941        imageDefaults.setWritableDocument(imageDefaultsDocument, imageDefaultsRoot);
942        return newChild;
943    }
944
945    /**
946     * Holds a JFreeChart histogram of image values.
947     */
948    private class MyTabbedPane extends JTabbedPane implements ChangeListener {
949        /** Have we been painted */
950        boolean painted = false;
951
952        boolean popupFlag = false;
953
954        /**
955         * Creates a new {@code MyTabbedPane} that gets immediately registered
956         * as a {@link javax.swing.event.ChangeListener} for its own events.
957         */
958        public MyTabbedPane() {
959            addChangeListener(this);
960        }
961        /**
962         *
963         * Handle when the tab has changed. When we move to tab 1 then hide the heavy
964         * component. Show it on change to tab 0.
965         *
966         * @param e The event
967         */
968        public void stateChanged(ChangeEvent e) {
969            if (!getActive() || !getHaveInitialized()) {
970                return;
971            }
972            if ((getSelectedIndex() == 1) && popupFlag) {
973                JLabel label = new JLabel("Can't make a histogram");
974                JPanel contents = GuiUtils.top(GuiUtils.inset(label, label.getText().length() + 12));
975                GuiUtils.showOkDialog(null, "Data Unavailable", contents, null);
976                setPopupFlag(false);
977            }
978        }
979
980        private void setPopupFlag(boolean flag) {
981            this.popupFlag = flag;
982        }
983
984        /**
985         * The first time we paint toggle the selected index. This seems to get rid of
986         * screen crud
987         *
988         * @param g graphics
989         */
990        public void paint(java.awt.Graphics g) {
991            if (!painted) {
992                painted = true;
993                setSelectedIndex(1);
994                setSelectedIndex(0);
995                repaint();
996            }
997            super.paint(g);
998        }
999    }
1000}