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