001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2016 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 @Override public void doRemove() throws RemoteException, VisADException { 239 super.doRemove(); 240 } 241 242 /** 243 * Take out the histogram-related stuff that was in doMakeContents and put it 244 * in a standalone method, so we can wait and call it only after the 245 * histogram is actually initialized. 246 */ 247 private void setInitialHistogramRange() { 248 try { 249 Range range = getRange(); 250 double lo = range.getMin(); 251 double hi = range.getMax(); 252 histoWrapper.setHigh(hi); 253 histoWrapper.setLow(lo); 254 } catch (Exception exc) { 255 logException("setInitialHistogramRange", exc); 256 } 257 } 258 259 protected JComponent getHistogramTabComponent() { 260 List choices = new ArrayList(); 261 if (datachoice == null) { 262 datachoice = getDataChoice(); 263 } 264 choices.add(datachoice); 265 histoWrapper = new McIDASVHistogramWrapper("histo", choices, (DisplayControlImpl)this); 266 dataSource = getDataSource(); 267 268 if (dataSource == null) { 269 try { 270 image = (FlatField) ((ComboDataChoice) datachoice).getData(); 271 histoWrapper.loadData(image); 272 } catch (IllegalArgumentException e) { 273 logger.trace("Could not create histogram: nothing to show!", e); 274 } catch (RemoteException | VisADException e) { 275 logger.error("Could not create histogram!", e); 276 } 277 } else { 278 Hashtable props = dataSource.getProperties(); 279 try { 280 DataSelection testSelection = datachoice.getDataSelection(); 281 DataSelection realSelection = getDataSelection(); 282 if (testSelection == null) { 283 datachoice.setDataSelection(realSelection); 284 } 285 ImageSequenceImpl seq = null; 286 if (dataSelection == null) 287 dataSelection = dataSource.getDataSelection(); 288 if (dataSelection == null) { 289 image = (FlatField)dataSource.getData(datachoice, null, props); 290 if (image == null) { 291 image = (FlatField)datachoice.getData(null); 292 } 293 } else { 294 Data data = dataSource.getData(datachoice, null, dataSelection, props); 295 if (data instanceof ImageSequenceImpl) { 296 seq = (ImageSequenceImpl) data; 297 } else if (data instanceof FlatField) { 298 image = (FlatField) data; 299 } else if (data instanceof FieldImpl) { 300 image = (FlatField) ((FieldImpl)data).getSample(0, false); 301 } else { 302 throw new Exception("Histogram must be made from a FlatField"); 303 } 304 } 305 if ((seq != null) && (seq.getImageCount() > 0)) { 306 image = (FlatField)seq.getImage(0); 307 } 308 try { 309 histoWrapper.loadData(image); 310 } catch (IllegalArgumentException e) { 311 logger.trace("Could not create histogram: nothing to show!", e); 312 } 313 } catch (Exception e) { 314 logger.error("attempting to set up histogram", e); 315 } 316 } 317 318 JComponent histoComp = histoWrapper.doMakeContents(); 319 JButton resetButton = new JButton("Reset"); 320 resetButton.addActionListener(new ActionListener() { 321 public void actionPerformed(ActionEvent ae) { 322 resetColorTable(); 323 } 324 }); 325 JPanel resetPanel = 326 GuiUtils.center(GuiUtils.inset(GuiUtils.wrap(resetButton), 4)); 327 return GuiUtils.centerBottom(histoComp, resetPanel); 328 } 329 330 protected void contrastStretch(double low, double high) { 331 ColorTable ct = getColorTable(); 332 if (ct != null) { 333 Range range = new Range(low, high); 334 try { 335 setRange(ct.getName(), range); 336 } catch (Exception e) { 337 logger.error("problem stretching contrast", e); 338 } 339 } 340 } 341 342 @Override public boolean setData(DataChoice dataChoice) throws VisADException, RemoteException { 343 boolean result = super.setData(dataChoice); 344// logger.trace("result: {}, dataChoice: {}", result, dataChoice); 345 return result; 346 } 347 348 @Override public void setRange(final Range newRange) throws RemoteException, VisADException { 349// logger.trace("newRange: {} [avoiding NPE!]", newRange); 350 super.setRange(newRange); 351 if (histoWrapper != null) { 352 histoWrapper.modifyRange(newRange.getMin(), newRange.getMax(), false); 353 } 354 } 355 356 public void resetColorTable() { 357 try { 358 revertToDefaultColorTable(); 359 revertToDefaultRange(); 360 histoWrapper.resetPlot(); 361 } catch (Exception e) { 362 logger.error("problem resetting color table", e); 363 } 364 } 365 366 protected void getSaveMenuItems(List items, boolean forMenuBar) { 367 super.getSaveMenuItems(items, forMenuBar); 368 369 // DAVEP: Remove the parameter set save options for now... 370// items.add(GuiUtils.makeMenuItem("Save Image Parameter Set (TEST)", this, 371// "popupPersistImageParameters")); 372// 373// items.add(GuiUtils.makeMenuItem("Save Image Parameter Set", this, 374// "popupSaveImageParameters")); 375 376 items.add(GuiUtils.makeMenuItem("Save As Local Data Source", this, 377 "saveDataToLocalDisk")); 378 } 379 380 public void popupPersistImageParameters() { 381 PersistenceManager pm = (PersistenceManager)getIdv().getPersistenceManager(); 382 pm.saveParameterSet("addeimagery", makeParameterValues()); 383 } 384 385 private Hashtable makeParameterValues() { 386 Hashtable parameterValues = new Hashtable(); 387// Document doc = XmlUtil.makeDocument(); 388// Element newChild = doc.createElement(TAG_DEFAULT); 389 390 if (datachoice == null) { 391 datachoice = getDataChoice(); 392 } 393 dataSource = getDataSource(); 394 if (!(dataSource.getClass().isInstance(new AddeImageParameterDataSource()))) { 395 logger.trace("dataSource not a AddeImageParameterDataSource; it is: {}", dataSource.getClass().toString()); 396 return parameterValues; 397 } 398 AddeImageParameterDataSource testDataSource = (AddeImageParameterDataSource)dataSource; 399 List imageList = testDataSource.getDescriptors(datachoice, this.dataSelection); 400 int numImages = imageList.size(); 401 List dateTimes = new ArrayList(); 402 DateTime thisDT = null; 403 if (!(imageList == null)) { 404 AddeImageDescriptor aid = null; 405 for (int imageNo=0; imageNo<numImages; imageNo++) { 406 aid = (AddeImageDescriptor) imageList.get(imageNo); 407 thisDT = aid.getImageTime(); 408 if (!dateTimes.contains(thisDT)) { 409 if (thisDT != null) { 410 dateTimes.add(thisDT); 411 } 412 } 413 } 414 415 // Set the date and time for later reference 416 String dateS = ""; 417 String timeS = ""; 418 if (!dateTimes.isEmpty()) { 419 thisDT = (DateTime)dateTimes.get(0); 420 dateS = thisDT.dateString(); 421 timeS = thisDT.timeString(); 422 if (dateTimes.size() > 1) { 423 for (int img=1; img<dateTimes.size(); img++) { 424 thisDT = (DateTime)dateTimes.get(img); 425 String str = "," + thisDT.dateString(); 426 String newString = dateS + str; 427 dateS = newString; 428 str = "," + thisDT.timeString(); 429 newString = timeS + str; 430 timeS = newString; 431 } 432 } 433 } 434 435 // Set the unit for later reference 436 String unitS = ""; 437 if (!(datachoice.getId() instanceof BandInfo)) { 438 logger.trace("dataChoice ID not a BandInfo; it is: {}", datachoice.getId().getClass().toString()); 439 return parameterValues; 440 } 441 BandInfo bi = (BandInfo)datachoice.getId(); 442 unitS = bi.getPreferredUnit(); 443 444 if (aid != null) { 445 String displayUrl = testDataSource.getDisplaySource(); 446 ImageParameters ip = new ImageParameters(displayUrl); 447 List props = ip.getProperties(); 448 List vals = ip.getValues(); 449 String server = ip.getServer(); 450 parameterValues.put(ATTR_SERVER, server); 451// newChild.setAttribute(ATTR_SERVER, server); 452 int num = props.size(); 453 if (num > 0) { 454 String attr = ""; 455 String val = ""; 456 for (int i=0; i<num; i++) { 457 attr = (String)(props.get(i)); 458 if (attr.equals(ATTR_POS)) { 459 val = new Integer(numImages - 1).toString(); 460 } else if (attr.equals(ATTR_DAY)) { 461 val = dateS; 462 } else if (attr.equals(ATTR_TIME)) { 463 val = timeS; 464 } else if (attr.equals(ATTR_UNIT)) { 465 val = unitS; 466 } else { 467 val = (String)(vals.get(i)); 468 } 469 parameterValues.put(attr, val); 470 } 471 } 472 } 473 } 474 return parameterValues; 475 } 476 477 public void saveDataToLocalDisk() { 478 getDataSource().saveDataToLocalDisk(); 479 } 480 481 public void popupSaveImageParameters() { 482 if (saveWindow == null) { 483 showSaveDialog(); 484 return; 485 } 486 saveWindow.setVisible(true); 487 GuiUtils.toFront(saveWindow); 488 } 489 490 private void showSaveDialog() { 491 if (saveWindow == null) { 492 saveWindow = GuiUtils.createFrame("Save Image Parameter Set"); 493 } 494 if (statusComp == null) { 495 statusLabel = new JLabel(); 496 statusComp = GuiUtils.inset(statusLabel, 2); 497 statusComp.setBackground(new Color(255, 255, 204)); 498 statusLabel.setOpaque(true); 499 statusLabel.setBackground(new Color(255, 255, 204)); 500 } 501 JPanel statusPanel = GuiUtils.inset(GuiUtils.top( GuiUtils.vbox(new JLabel(" "), 502 GuiUtils.hbox(GuiUtils.rLabel("Status: "), statusComp), 503 new JLabel(" "))), 6); 504 JPanel sPanel = GuiUtils.topCenter(statusPanel, GuiUtils.filler()); 505 506 List newComps = new ArrayList(); 507 final JTextField newName = new JTextField(20); 508 newName.addActionListener(new ActionListener() { 509 public void actionPerformed(ActionEvent ae) { 510 setStatus("Click New Folder or New ParameterSet button"); 511 newCompName = newName.getText().trim(); 512 } 513 }); 514 newComps.add(newName); 515 newComps.add(GuiUtils.filler()); 516 newFolderBtn = new JButton("New Folder"); 517 newFolderBtn.addActionListener(new ActionListener() { 518 public void actionPerformed(ActionEvent ae) { 519 newFolder = newName.getText().trim(); 520 if (newFolder.length() == 0) { 521 newComponentError("folder"); 522 return; 523 } 524 Element exists = XmlUtil.findElement(imageDefaultsRoot, "folder", ATTR_NAME, newFolder); 525 if (!(exists == null)) { 526 if (!GuiUtils.askYesNo("Verify Replace Folder", 527 "Do you want to replace the folder " + 528 "\"" + newFolder + "\"?" + 529 "\nNOTE: All parameter sets it contains will be deleted.")) return; 530 imageDefaultsRoot.removeChild(exists); 531 } 532 newName.setText(""); 533 Node newEle = makeNewFolder(); 534 makeXmlTree(); 535 xmlTree.selectElement((Element)newEle); 536 lastCat = newEle; 537 lastClicked = null; 538 newSetBtn.setEnabled(true); 539 setStatus("Please enter a name for the new parameter set"); 540 } 541 }); 542 newComps.add(newFolderBtn); 543 newComps.add(GuiUtils.filler()); 544 newName.setEnabled(true); 545 newFolderBtn.setEnabled(true); 546 newSetBtn = new JButton("New Parameter Set"); 547 newSetBtn.setActionCommand(CMD_NEWPARASET); 548 newSetBtn.addActionListener(new ActionListener() { 549 public void actionPerformed(ActionEvent ae) { 550 newCompName = newName.getText().trim(); 551 if (newCompName.length() == 0) { 552 newComponentError("parameter set"); 553 return; 554 } 555 newName.setText(""); 556 Element newEle = saveParameterSet(); 557 if (newEle == null) return; 558 xmlTree.selectElement(newEle); 559 lastClicked = newEle; 560 } 561 }); 562 newComps.add(newSetBtn); 563 newSetBtn.setEnabled(false); 564 565 JPanel newPanel = GuiUtils.top(GuiUtils.left(GuiUtils.hbox(newComps))); 566 JPanel topPanel = GuiUtils.topCenter(sPanel, newPanel); 567 568 treePanel = new JPanel(); 569 treePanel.setLayout(new BorderLayout()); 570 makeXmlTree(); 571 ActionListener listener = new ActionListener() { 572 public void actionPerformed(ActionEvent event) { 573 String cmd = event.getActionCommand(); 574 if (cmd.equals(GuiUtils.CMD_CANCEL)) { 575 if (lastClicked != null) { 576 removeNode(lastClicked); 577 lastClicked = null; 578 } 579 saveWindow.setVisible(false); 580 saveWindow = null; 581 } else { 582 saveWindow.setVisible(false); 583 saveWindow = null; 584 } 585 } 586 }; 587 JPanel bottom = 588 GuiUtils.inset(GuiUtils.makeApplyCancelButtons(listener), 5); 589 contents = 590 GuiUtils.topCenterBottom(topPanel, treePanel, bottom); 591 592 saveWindow.getContentPane().add(contents); 593 saveWindow.pack(); 594 saveWindow.setLocation(200, 200); 595 596 saveWindow.setVisible(true); 597 GuiUtils.toFront(saveWindow); 598 setStatus("Please select a folder from tree, or create a new folder"); 599 } 600 601 private void newComponentError(String comp) { 602 JLabel label = new JLabel("Please enter " + comp +" name"); 603 JPanel contents = GuiUtils.top(GuiUtils.inset(label, 24)); 604 GuiUtils.showOkCancelDialog(null, "Make Component Error", contents, null); 605 } 606 607 private void setStatus(String msg) { 608 statusLabel.setText(msg); 609 contents.paintImmediately(0,0,contents.getWidth(), 610 contents.getHeight()); 611 } 612 613 private void removeNode(Element node) { 614 if (imageDefaults == null) { 615 imageDefaults = getImageDefaults(); 616 } 617 Node parent = node.getParentNode(); 618 parent.removeChild(node); 619 makeXmlTree(); 620 try { 621 imageDefaults.writeWritable(); 622 } catch (Exception e) { 623 logger.error("write error!", e); 624 } 625 imageDefaults.setWritableDocument(imageDefaultsDocument, 626 imageDefaultsRoot); 627 } 628 629 private Node makeNewFolder() { 630 if (imageDefaults == null) { 631 imageDefaults = getImageDefaults(); 632 } 633 if (newFolder.length() == 0) { 634 return null; 635 } 636 List newChild = new ArrayList(); 637 Node newEle = imageDefaultsDocument.createElement(TAG_FOLDER); 638 lastCat = newEle; 639 String[] newAttrs = { ATTR_NAME, newFolder }; 640 XmlUtil.setAttributes((Element)newEle, newAttrs); 641 newChild.add(newEle); 642 XmlUtil.addChildren(imageDefaultsRoot, newChild); 643 try { 644 imageDefaults.writeWritable(); 645 } catch (Exception e) { 646 logger.error("write error!", e); 647 } 648 imageDefaults.setWritableDocument(imageDefaultsDocument, 649 imageDefaultsRoot); 650 return newEle; 651 } 652 653 /** 654 * Just creates an empty XmlTree 655 */ 656 private void makeXmlTree() { 657 if (imageDefaults == null) { 658 imageDefaults = getImageDefaults(); 659 } 660 xmlTree = new XmlTree(imageDefaultsRoot, true, "") { 661 public void doClick(XmlTree theTree, XmlTree.XmlTreeNode node, 662 Element element) { 663 Element clicked = xmlTree.getSelectedElement(); 664 String lastTag = clicked.getTagName(); 665 if ("folder".equals(lastTag)) { 666 lastCat = clicked; 667 lastClicked = null; 668 setStatus("Please enter a name for the new parameter set"); 669 newSetBtn.setEnabled(true); 670 } else { 671 lastCat = clicked.getParentNode(); 672 lastClicked = clicked; 673 } 674 } 675 676 public void doRightClick(XmlTree theTree, 677 XmlTree.XmlTreeNode node, 678 Element element, MouseEvent event) { 679 JPopupMenu popup = new JPopupMenu(); 680 if (makePopupMenu(theTree, element, popup)) { 681 popup.show((Component) event.getSource(), event.getX(), 682 event.getY()); 683 } 684 } 685 }; 686 List tagList = new ArrayList(); 687 tagList.add(TAG_FOLDER); 688 tagList.add(TAG_DEFAULT); 689 xmlTree.addTagsToProcess(tagList); 690 xmlTree.defineLabelAttr(TAG_FOLDER, ATTR_NAME); 691 addToContents(GuiUtils.inset(GuiUtils.topCenter(new JPanel(), 692 xmlTree.getScroller()), 5)); 693 return; 694 } 695 696 private List getFolders() { 697 return XmlUtil.findChildren(imageDefaultsRoot, TAG_FOLDER); 698 } 699 700 701 private void doDeleteRequest(Node node) { 702 if (node == null) { 703 return; 704 } 705 Element ele = (Element)node; 706 String tagName = ele.getTagName(); 707 if (tagName.equals("folder")) { 708 if (!GuiUtils.askYesNo("Verify Delete Folder", 709 "Do you want to delete the folder " + 710 "\"" + ele.getAttribute("name") + "\"?" + 711 "\nNOTE: All parameter sets it contains will be deleted.")) return; 712 XmlUtil.removeChildren(ele); 713 } else if (tagName.equals("default")) { 714 if (!GuiUtils.askYesNo("Verify Delete", "Do you want to delete " + 715 "\"" + ele.getAttribute(ATTR_NAME) + "\"?")) return; 716 } else { return; } 717 removeNode(ele); 718 } 719 /** 720 * Create and popup a command menu for when the user has clicked on the given xml node. 721 * 722 * @param theTree The XmlTree object displaying the current xml document. 723 * @param node The xml node the user clicked on. 724 * @param popup The popup menu to put the menu items in. 725 * @return Did we add any items into the menu 726 */ 727 private boolean makePopupMenu(final XmlTree theTree, final Element node, 728 JPopupMenu popup) 729 { 730 theTree.selectElement(node); 731 String tagName = node.getTagName(); 732 final Element parent = (Element)node.getParentNode(); 733 boolean didone = false; 734 JMenuItem mi; 735 736 if (tagName.equals("default")) { 737 lastClicked = node; 738 JMenu moveMenu = new JMenu("Move to"); 739 List folders = getFolders(); 740 for (int i = 0; i < folders.size(); i++) { 741 final Element newFolder = (Element)folders.get(i); 742 if (!newFolder.isSameNode(parent)) { 743 String name = newFolder.getAttribute(ATTR_NAME); 744 mi = new JMenuItem(name); 745 mi.addActionListener(new ActionListener() { 746 public void actionPerformed(ActionEvent ae) { 747 moveParameterSet(parent, newFolder); 748 } 749 }); 750 moveMenu.add(mi); 751 } 752 } 753 popup.add(moveMenu); 754 popup.addSeparator(); 755 didone = true; 756 } 757 758 mi = new JMenuItem("Rename..."); 759 mi.addActionListener(new ActionListener() { 760 public void actionPerformed(ActionEvent ae) { 761 doRename(node); 762 } 763 }); 764 popup.add(mi); 765 didone = true; 766 767 mi = new JMenuItem("Delete"); 768 mi.addActionListener(new ActionListener() { 769 public void actionPerformed(ActionEvent ae) { 770 doDeleteRequest(node); 771 } 772 }); 773 popup.add(mi); 774 didone = true; 775 776 return didone; 777 } 778 779 public void moveParameterSet(Element parent, Element newFolder) { 780 if (imageDefaults == null) { 781 imageDefaults = getImageDefaults(); 782 } 783 if (lastClicked == null) { 784 return; 785 } 786 Node copyNode = lastClicked.cloneNode(true); 787 newFolder.appendChild(copyNode); 788 parent.removeChild(lastClicked); 789 lastCat = newFolder; 790 makeXmlTree(); 791 try { 792 imageDefaults.writeWritable(); 793 } catch (Exception e) { 794 logger.error("write error!", e); 795 } 796 imageDefaults.setWritableDocument(imageDefaultsDocument, imageDefaultsRoot); 797 } 798 799 private void doRename(Element node) { 800 if (imageDefaults == null) { 801 imageDefaults = getImageDefaults(); 802 } 803 if (!node.hasAttribute(ATTR_NAME)) return; 804 JLabel label = new JLabel("New name: "); 805 JTextField nameFld = new JTextField("", 20); 806 JComponent contents = GuiUtils.doLayout(new Component[] { 807 GuiUtils.rLabel("New name: "), nameFld, }, 2, 808 GuiUtils.WT_N, GuiUtils.WT_N); 809 contents = GuiUtils.center(contents); 810 contents = GuiUtils.inset(contents, 10); 811 if (!GuiUtils.showOkCancelDialog(null, "Rename \"" + 812 node.getAttribute("name") + "\"", contents, null)) return; 813 String newName = nameFld.getText().trim(); 814 String tagName = node.getTagName(); 815 Element root = imageDefaultsRoot; 816 if (tagName.equals("default")) { 817 root = (Element)node.getParentNode(); 818 } 819 Element exists = XmlUtil.findElement(root, tagName, ATTR_NAME, newName); 820 if (!(exists == null)) { 821 if (!GuiUtils.askYesNo("Name Already Exists", 822 "Do you want to replace " + node.getAttribute("name") + " with" + 823 "\"" + newName + "\"?")) return; 824 } 825 node.removeAttribute(ATTR_NAME); 826 node.setAttribute(ATTR_NAME, newName); 827 makeXmlTree(); 828 try { 829 imageDefaults.writeWritable(); 830 } catch (Exception e) { 831 logger.error("write error!", e); 832 } 833 imageDefaults.setWritableDocument(imageDefaultsDocument, 834 imageDefaultsRoot); 835 } 836 837 /** 838 * Remove the currently display gui and insert the given one. 839 * 840 * @param comp The new gui. 841 */ 842 private void addToContents(JComponent comp) { 843 treePanel.removeAll(); 844 comp.setPreferredSize(new Dimension(200, 300)); 845 treePanel.add(comp, BorderLayout.CENTER); 846 if (contents != null) { 847 contents.invalidate(); 848 contents.validate(); 849 contents.repaint(); 850 } 851 } 852 853 public DataSourceImpl getDataSource() { 854 DataSourceImpl ds = null; 855 List dataSources = getDataSources(); 856 if (!dataSources.isEmpty()) { 857 ds = (DataSourceImpl)dataSources.get(0); 858 } 859 return ds; 860 } 861 862 public Element saveParameterSet() { 863 if (imageDefaults == null) { 864 imageDefaults = getImageDefaults(); 865 } 866 if (newCompName.length() == 0) { 867 newComponentError("parameter set"); 868 return null; 869 } 870 Element newChild = imageDefaultsDocument.createElement(TAG_DEFAULT); 871 newChild.setAttribute(ATTR_NAME, newCompName); 872 873 if (datachoice == null) { 874 datachoice = getDataChoice(); 875 } 876 dataSource = getDataSource(); 877 if (!(dataSource.getClass().isInstance(new AddeImageParameterDataSource()))) { 878 return newChild; 879 } 880 AddeImageParameterDataSource testDataSource = (AddeImageParameterDataSource)dataSource; 881 List imageList = testDataSource.getDescriptors(datachoice, this.dataSelection); 882 int numImages = imageList.size(); 883 List dateTimes = new ArrayList(); 884 DateTime thisDT = null; 885 if (!(imageList == null)) { 886 AddeImageDescriptor aid = null; 887 for (int imageNo = 0; imageNo < numImages; imageNo++) { 888 aid = (AddeImageDescriptor)(imageList.get(imageNo)); 889 thisDT = aid.getImageTime(); 890 if (!(dateTimes.contains(thisDT))) { 891 if (thisDT != null) { 892 dateTimes.add(thisDT); 893 } 894 } 895 } 896 String dateS = ""; 897 String timeS = ""; 898 if (!(dateTimes.isEmpty())) { 899 thisDT = (DateTime)dateTimes.get(0); 900 dateS = thisDT.dateString(); 901 timeS = thisDT.timeString(); 902 if (dateTimes.size() > 1) { 903 for (int img = 1; img < dateTimes.size(); img++) { 904 thisDT = (DateTime)dateTimes.get(img); 905 String str = ',' + thisDT.dateString(); 906 String newString = new String(dateS + str); 907 dateS = newString; 908 str = ',' + thisDT.timeString(); 909 newString = new String(timeS + str); 910 timeS = newString; 911 } 912 } 913 } 914 if (aid != null) { 915 String displayUrl = testDataSource.getDisplaySource(); 916 ImageParameters ip = new ImageParameters(displayUrl); 917 List props = ip.getProperties(); 918 List vals = ip.getValues(); 919 String server = ip.getServer(); 920 newChild.setAttribute(ATTR_SERVER, server); 921 int num = props.size(); 922 if (num > 0) { 923 String attr = ""; 924 String val = ""; 925 for (int i = 0; i < num; i++) { 926 attr = (String)(props.get(i)); 927 if (attr.equals(ATTR_POS)) { 928 val = new Integer(numImages - 1).toString(); 929 } else if (attr.equals(ATTR_DAY)) { 930 val = dateS; 931 } else if (attr.equals(ATTR_TIME)) { 932 val = timeS; 933 } else { 934 val = (String)(vals.get(i)); 935 } 936 newChild.setAttribute(attr, val); 937 } 938 } 939 } 940 } 941 Element parent = xmlTree.getSelectedElement(); 942 if (parent == null) { 943 parent = (Element)lastCat; 944 } 945 if (parent != null) { 946 Element exists = XmlUtil.findElement(parent, "default", ATTR_NAME, newCompName); 947 if (!(exists == null)) { 948 JLabel label = new JLabel("Replace \"" + newCompName + "\"?"); 949 JPanel contents = GuiUtils.top(GuiUtils.inset(label, newCompName.length()+12)); 950 if (!GuiUtils.showOkCancelDialog(null, "Parameter Set Exists", contents, null)) { 951 return newChild; 952 } 953 parent.removeChild(exists); 954 } 955 parent.appendChild(newChild); 956 makeXmlTree(); 957 } 958 try { 959 imageDefaults.writeWritable(); 960 } catch (Exception e) { 961 logger.error("write error!", e); 962 } 963 imageDefaults.setWritableDocument(imageDefaultsDocument, imageDefaultsRoot); 964 return newChild; 965 } 966 967 /** 968 * Holds a JFreeChart histogram of image values. 969 */ 970 private class MyTabbedPane extends JTabbedPane implements ChangeListener { 971 /** Have we been painted */ 972 boolean painted = false; 973 974 boolean popupFlag = false; 975 976 boolean haveDoneHistogramInit = false; 977 978 /** 979 * Creates a new {@code MyTabbedPane} that gets immediately registered 980 * as a {@link javax.swing.event.ChangeListener} for its own events. 981 */ 982 public MyTabbedPane() { 983 addChangeListener(this); 984 } 985 /** 986 * The histogram isn't created unless the user selects the histogram 987 * tab (this is done in an effort to avoid a spike in memory usage). 988 * 989 * @param e The event. Ignored for now. 990 */ 991 public void stateChanged(ChangeEvent e) { 992 // MH: don't make the histogram until user clicks the tab. 993 int index = getSelectedIndex(); 994 if (index >= 0 && getTitleAt(index).equals("Histogram") && !haveDoneHistogramInit) { 995 getIdv().showWaitCursor(); 996 this.setComponentAt(index, 997 GuiUtils.inset(getHistogramTabComponent(),5)); 998 setInitialHistogramRange(); 999 getIdv().clearWaitCursor(); 1000// haveDoneHistogramInit = true; 1001 } 1002 } 1003 1004 /** 1005 * MH: Not really doing anything useful...but will leave it here for now... 1006 */ 1007 private void setPopupFlag(boolean flag) { 1008 this.popupFlag = flag; 1009 } 1010 1011 /** 1012 * MH: Not really doing anything useful...but will leave it here for now... 1013 * 1014 * @param g graphics 1015 */ 1016 public void paint(java.awt.Graphics g) { 1017 if (!painted) { 1018 painted = true; 1019 } 1020 super.paint(g); 1021 } 1022 } 1023}