001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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 https://www.gnu.org/licenses/. 027 */ 028 029package edu.wisc.ssec.mcidasv.ui; 030 031 032import java.awt.Component; 033import java.awt.Dimension; 034import java.awt.event.KeyAdapter; 035import java.awt.event.KeyEvent; 036import java.awt.event.MouseAdapter; 037import java.awt.event.MouseEvent; 038import java.util.ArrayList; 039import java.util.Enumeration; 040import java.util.Hashtable; 041import java.util.List; 042 043import javax.swing.ImageIcon; 044import javax.swing.JComponent; 045import javax.swing.JFrame; 046import javax.swing.JMenu; 047import javax.swing.JMenuBar; 048import javax.swing.JPanel; 049import javax.swing.JPopupMenu; 050import javax.swing.JScrollPane; 051import javax.swing.JTree; 052import javax.swing.SwingUtilities; 053import javax.swing.tree.DefaultMutableTreeNode; 054import javax.swing.tree.DefaultTreeCellRenderer; 055import javax.swing.tree.DefaultTreeModel; 056import javax.swing.tree.TreePath; 057import javax.swing.tree.TreeSelectionModel; 058 059import ucar.unidata.idv.IdvPersistenceManager; 060import ucar.unidata.ui.DndTree; 061import ucar.unidata.util.GuiUtils; 062import ucar.unidata.util.LogUtil; 063import edu.wisc.ssec.mcidasv.ParameterSet; 064import edu.wisc.ssec.mcidasv.PersistenceManager; 065 066 067/** 068 * Class ParameterTree Gives a tree gui for editing parameter sets 069 * 070 * 071 * @author IDV Development Team 072 * @version $Revision$ 073 */ 074public class ParameterTree extends DndTree { 075 076 /** The window */ 077 private JFrame frame; 078 079 /** What is the type of the parameter set we are showing */ 080 private String parameterType; 081 082 /** The root of the tree */ 083 private DefaultMutableTreeNode treeRoot; 084 085 /** The tree model */ 086 private DefaultTreeModel treeModel; 087 088 /** A mapping from tree node to, either, category or ParameterSet */ 089 private Hashtable nodeToData; 090 091 /** The ui manager */ 092 private UIManager uiManager; 093 094 /** The persistence manager */ 095 private PersistenceManager persistenceManager; 096 097 /** Icon to use for categories */ 098 private ImageIcon categoryIcon; 099 100 /** Icon to use for parameters */ 101 private ImageIcon parameterIcon; 102 103 104 105 106 /** 107 * Create the tree with the given parameter set type 108 * 109 * 110 * @param uiManager The UI manager 111 * @param parameterType The type of the parameter set we are showing 112 */ 113 public ParameterTree(UIManager uiManager, String parameterType) { 114 115 categoryIcon = GuiUtils.getImageIcon("/auxdata/ui/icons/folder.png", 116 getClass()); 117 parameterIcon = GuiUtils.getImageIcon("/auxdata/ui/icons/page.png", 118 getClass()); 119 120 this.uiManager = uiManager; 121 this.persistenceManager = (PersistenceManager)(uiManager.getPersistenceManager()); 122 123 setToolTipText( 124 "<html>Right click to show popup menu.<br>Drag to move parameter sets or categories</html>"); 125 126 this.parameterType = parameterType; 127 treeRoot = new DefaultMutableTreeNode("Parameter Sets"); 128 129 // setRootVisible(false); 130 setShowsRootHandles(true); 131 treeModel = new DefaultTreeModel(treeRoot); 132 setModel(treeModel); 133 DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer() { 134 public Component getTreeCellRendererComponent(JTree theTree, 135 Object value, boolean sel, boolean expanded, 136 boolean leaf, int row, boolean hasFocus) { 137 138 super.getTreeCellRendererComponent(theTree, value, sel, 139 expanded, leaf, row, hasFocus); 140 if ((nodeToData == null) || (value == null)) { 141 return this; 142 } 143 Object data = nodeToData.get(value); 144 if (data == null) { 145 setIcon(categoryIcon); 146 return this; 147 } 148 if (data instanceof ParameterSet) { 149 setToolTipText( 150 "<html>Right click to show parameter set menu.<br>Drag to move parameter set</html>"); 151 setIcon(parameterIcon); 152 } else { 153 setToolTipText( 154 "<html>Right click to show category menu.<br>Drag to move parameter sets or categories</html><"); 155 setIcon(categoryIcon); 156 } 157 return this; 158 } 159 }; 160 setCellRenderer(renderer); 161 162 163 164 165 addKeyListener(new KeyAdapter() { 166 public void keyPressed(KeyEvent e) { 167 if (e.getKeyCode() == e.VK_DELETE) { 168 deleteSelected(); 169 } 170 } 171 }); 172 173 getSelectionModel().setSelectionMode( 174 TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); 175 // TreeSelectionModel.SINGLE_TREE_SELECTION); 176 177 178 addMouseListener(new MouseAdapter() { 179 public void mouseClicked(MouseEvent event) { 180 TreePath path = getPathForLocation(event.getX(), 181 event.getY()); 182 Object data = findDataAtPath(path); 183 if ( !SwingUtilities.isRightMouseButton(event)) { 184// if (event.getClickCount() > 1) { 185// if ((data != null) && (data instanceof SavedBundle)) { 186// doOpen((SavedBundle) data); 187// } 188// } 189 return; 190 } 191 clearSelection(); 192 addSelectionPath(path); 193 final DefaultMutableTreeNode parentNode = 194 (DefaultMutableTreeNode) path.getLastPathComponent(); 195 196 JPopupMenu popup = new JPopupMenu(); 197 if (data == null) { 198 popup.add(GuiUtils.makeMenuItem("Add Subcategory", 199 ParameterTree.this, "addCategory", parentNode)); 200 } else { 201 if (data instanceof ParameterSet) { 202 ParameterSet set = (ParameterSet) data; 203 popup.add(GuiUtils.makeMenuItem("Rename", 204 ParameterTree.this, "doRename", set)); 205 popup.add(GuiUtils.makeMenuItem("Delete", 206 ParameterTree.this, "deleteParameterSet", set)); 207 } else { 208 popup.add(GuiUtils.makeMenuItem("Delete Category", 209 ParameterTree.this, "deleteCategory", 210 data.toString())); 211 popup.add(GuiUtils.makeMenuItem("Add Subcategory", 212 ParameterTree.this, "addCategory", parentNode)); 213 } 214 } 215 popup.show((Component) event.getSource(), event.getX(), 216 event.getY()); 217 } 218 }); 219 loadParameterSets(); 220 221 String title = "Parameter Set Manager"; 222 223 Dimension defaultDimension = new Dimension(300, 400); 224 JScrollPane sp = GuiUtils.makeScrollPane(this, 225 (int) defaultDimension.getWidth(), 226 (int) defaultDimension.getHeight()); 227 sp.setPreferredSize(defaultDimension); 228 229 230 JMenuBar menuBar = new JMenuBar(); 231 JMenu fileMenu = new JMenu("File"); 232 JMenu helpMenu = new JMenu("Help"); 233 menuBar.add(fileMenu); 234 // menuBar.add(helpMenu); 235// fileMenu.add(GuiUtils.makeMenuItem("Export to File", this, 236// "doExport")); 237// fileMenu.add(GuiUtils.makeMenuItem("Export to Plugin", this, 238// "doExportToPlugin")); 239// fileMenu.addSeparator(); 240 fileMenu.add(GuiUtils.makeMenuItem("Close", this, "doClose")); 241 242 243 244 245 JComponent bottom = GuiUtils.wrap(GuiUtils.makeButton("Close", this, 246 "doClose")); 247 248 JPanel contents = GuiUtils.topCenterBottom(menuBar, sp, bottom); 249 frame = GuiUtils.createFrame(title); 250 frame.getContentPane().add(contents); 251 frame.pack(); 252 frame.setLocation(100, 100); 253 } 254 255 /** 256 * close 257 */ 258 public void doClose() { 259 frame.dispose(); 260 } 261 262 263 /** 264 * Get the list of selected parameter sets 265 * 266 * @return The selected parameter sets 267 */ 268 private List getSelectedParameterSets() { 269 TreePath[] paths = getSelectionModel().getSelectionPaths(); 270 if ((paths == null) || (paths.length == 0)) { 271 return new ArrayList(); 272 } 273 List sets = new ArrayList(); 274 for (int i = 0; i < paths.length; i++) { 275 Object data = findDataAtPath(paths[i]); 276 if (data == null) { 277 continue; 278 } 279 if ( !(data instanceof ParameterSet)) { 280 continue; 281 } 282 sets.add(data); 283 } 284 return sets; 285 } 286 287 /** 288 * Show the window 289 */ 290 public void setVisible(boolean visibility) { 291 frame.setVisible(visibility); 292 } 293 294 295 /** 296 * Ok to drag the node 297 * 298 * @param sourceNode The node to drag 299 * 300 * @return Ok to drag 301 */ 302 protected boolean okToDrag(DefaultMutableTreeNode sourceNode) { 303 return sourceNode.getParent() != null; 304 } 305 306 307 /** 308 * Ok to drop the node 309 * 310 * 311 * @param sourceNode The dragged node 312 * @param destNode Where to drop 313 * 314 * @return Ok to drop 315 */ 316 protected boolean okToDrop(DefaultMutableTreeNode sourceNode, 317 DefaultMutableTreeNode destNode) { 318 319 320 //Don't drop a parameter set onto the root. It must be in a category 321 if (sourceNode.getUserObject() instanceof ParameterSet) { 322 if (destNode.getParent() == null) { 323 return false; 324 } 325 } 326 327 if (destNode.getUserObject() instanceof ParameterSet) { 328 return false; 329 } 330 if (destNode == sourceNode.getParent()) { 331 return false; 332 } 333 while (destNode != null) { 334 if (destNode == sourceNode) { 335 return false; 336 } 337 destNode = (DefaultMutableTreeNode) destNode.getParent(); 338 } 339 return true; 340 } 341 342 343 344 /** 345 * Handle the DND drop 346 * 347 * 348 * @param sourceNode The dragged node 349 * @param destNode Where to drop 350 */ 351 protected void doDrop(DefaultMutableTreeNode sourceNode, 352 DefaultMutableTreeNode destNode) { 353 if (sourceNode.getUserObject() instanceof ParameterSet) { 354 persistenceManager.moveParameterSet( 355 parameterType, 356 (ParameterSet) sourceNode.getUserObject(), 357 getCategoryList(destNode)); 358 } else { 359 persistenceManager.moveParameterSetCategory( 360 parameterType, 361 getCategoryList(sourceNode), 362 getCategoryList(destNode)); 363 } 364 365 loadParameterSets(); 366 } 367 368 369 370 371 /** 372 * Create the list of categories 373 * 374 * @param destNode From where 375 * 376 * @return List of String categories 377 */ 378 private List getCategoryList(DefaultMutableTreeNode destNode) { 379 List categories = new ArrayList(); 380 while (destNode.getParent() != null) { 381 categories.add(0, destNode.getUserObject().toString()); 382 destNode = (DefaultMutableTreeNode) destNode.getParent(); 383 } 384 return categories; 385 } 386 387 /** 388 * Load the parameter sets into the tree 389 */ 390 protected void loadParameterSets() { 391 392 Enumeration paths = 393 getExpandedDescendants(new TreePath(treeRoot.getPath())); 394 Hashtable expandedState = 395 GuiUtils.initializeExpandedPathsBeforeChange(this, treeRoot); 396 397 List allCategories = persistenceManager.getAllParameterSetCategories(parameterType); 398 nodeToData = new Hashtable(); 399 treeRoot.removeAllChildren(); 400 Hashtable catNodes = new Hashtable(); 401 Hashtable fakeSets = new Hashtable(); 402 List sets = new ArrayList(); 403 404 //We use a set of fake parameter sets to we include all categories into the tree 405 for (int i = 0; i < allCategories.size(); i++) { 406 List categories = persistenceManager.stringToCategories((String) allCategories.get(i)); 407 ParameterSet fakeSet = new ParameterSet("", categories, parameterType); 408 fakeSets.put(fakeSet, fakeSet); 409 sets.add(fakeSet); 410 } 411 sets.addAll(persistenceManager.getAllParameterSets(parameterType)); 412 for (int i = 0; i < sets.size(); i++) { 413 ParameterSet set = (ParameterSet) sets.get(i); 414 List categories = set.getCategories(); 415 DefaultMutableTreeNode catNode = treeRoot; 416 String fullCat = ""; 417 for (int catIdx = 0; catIdx < categories.size(); catIdx++) { 418 String cat = (String) categories.get(catIdx); 419 if (fullCat.length() > 0) { 420 fullCat = fullCat + IdvPersistenceManager.CATEGORY_SEPARATOR; 421 } 422 fullCat = fullCat + cat; 423 DefaultMutableTreeNode tmpNode = (DefaultMutableTreeNode) catNodes.get(fullCat); 424 if (tmpNode == null) { 425 tmpNode = new DefaultMutableTreeNode(cat); 426 nodeToData.put(tmpNode, fullCat); 427 catNode.add(tmpNode); 428 catNodes.put(fullCat, tmpNode); 429 } 430 catNode = tmpNode; 431 } 432 //Skip over the fake ones 433 if (fakeSets.get(set) == null) { 434 DefaultMutableTreeNode setNode = new DefaultMutableTreeNode(set); 435 nodeToData.put(setNode, set); 436 catNode.add(setNode); 437 } 438 } 439 treeModel.nodeStructureChanged(treeRoot); 440 GuiUtils.expandPathsAfterChange(this, expandedState, treeRoot); 441 } 442 443 444 /** 445 * Find the data (either a ParameterSet or a category) 446 * associated with the given tree path 447 * 448 * @param path The path 449 * 450 * @return The data 451 */ 452 453 private Object findDataAtPath(TreePath path) { 454 if ((path == null) || (nodeToData == null)) { 455 return null; 456 } 457 DefaultMutableTreeNode last = 458 (DefaultMutableTreeNode) path.getLastPathComponent(); 459 if (last == null) { 460 return null; 461 } 462 return nodeToData.get(last); 463 } 464 465 /** 466 * Delete the selected item in the tree 467 */ 468 public void deleteSelected() { 469 System.out.println("deleteSelected"); 470 TreePath[] paths = getSelectionModel().getSelectionPaths(); 471 if ((paths == null) || (paths.length == 0)) { 472 return; 473 } 474 Object data = findDataAtPath(paths[0]); 475 if (data == null) { 476 return; 477 } 478 if (data instanceof ParameterSet) { 479 deleteParameterSet((ParameterSet) data); 480 } else { 481 deleteCategory(data.toString()); 482 } 483 } 484 485 486 /** 487 * Delete the given parameter set 488 * 489 * @param parameterSet The parameter set to delete 490 */ 491 public void deleteParameterSet(ParameterSet parameterSet) { 492 if ( !GuiUtils.askYesNo( 493 "Parameter set delete confirmation", 494 "Are you sure you want to delete the parameter set \"" + parameterSet 495 + "\" ?")) { 496 return; 497 } 498 System.out.println("deleteParameterSet"); 499 persistenceManager.deleteParameterSet(parameterType, parameterSet); 500 loadParameterSets(); 501 } 502 503 504 /** 505 * Delete the given parameter set category 506 * 507 * @param category The category to delete 508 */ 509 public void deleteCategory(String category) { 510 if ( !GuiUtils.askYesNo( 511 "Parameter Set Category Delete Confirmation", 512 "<html>Are you sure you want to delete the category:<p> <center>\"" 513 + category 514 + "\"</center> <br> and all parameter sets and categories under it?</html>")) { 515 return; 516 } 517 System.out.println("deleteCategory"); 518 persistenceManager.deleteParameterSetCategory(parameterType, category); 519 loadParameterSets(); 520 } 521 522 /** 523 * Create a new category under the given node 524 * 525 * @param parentNode The parent tree node 526 */ 527 public void addCategory(DefaultMutableTreeNode parentNode) { 528 String cat = 529 GuiUtils.getInput("Please enter the new category name", 530 "Name: ", ""); 531 if (cat == null) { 532 return; 533 } 534 String parentCat = (String) nodeToData.get(parentNode); 535 String fullCat = ((parentCat == null) 536 ? cat 537 : (parentCat 538 + IdvPersistenceManager.CATEGORY_SEPARATOR 539 + cat)); 540 System.out.println("addCategory"); 541 if ( !persistenceManager.addParameterSetCategory(parameterType, fullCat)) { 542 LogUtil.userMessage( 543 "A category with the given name already exists"); 544 return; 545 } 546 DefaultMutableTreeNode newCatNode = new DefaultMutableTreeNode(cat); 547 nodeToData.put(newCatNode, fullCat); 548 parentNode.add(newCatNode); 549 550 551 Hashtable expandedState = 552 GuiUtils.initializeExpandedPathsBeforeChange(this, treeRoot); 553 treeModel.nodeStructureChanged(treeRoot); 554 GuiUtils.expandPathsAfterChange(this, expandedState, treeRoot); 555 } 556 557 558 /** 559 * Rename the parameter set 560 * @param parameterSet the parameter set 561 */ 562 public void doRename(ParameterSet parameterSet) { 563 System.out.println("doRename"); 564 persistenceManager.renameParameterSet(parameterType, parameterSet); 565 } 566 567} 568