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