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 }