001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.view.TreeView; 016 017import java.io.BufferedInputStream; 018import java.io.BufferedOutputStream; 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.FileNotFoundException; 022import java.io.FileOutputStream; 023import java.io.Serializable; 024import java.lang.reflect.Method; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.BitSet; 028import java.util.Enumeration; 029import java.util.HashMap; 030import java.util.Iterator; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Queue; 034 035import org.eclipse.swt.SWT; 036import org.eclipse.swt.events.DisposeEvent; 037import org.eclipse.swt.events.DisposeListener; 038import org.eclipse.swt.events.KeyAdapter; 039import org.eclipse.swt.events.KeyEvent; 040import org.eclipse.swt.events.MenuAdapter; 041import org.eclipse.swt.events.MenuDetectEvent; 042import org.eclipse.swt.events.MenuDetectListener; 043import org.eclipse.swt.events.MenuEvent; 044import org.eclipse.swt.events.MouseAdapter; 045import org.eclipse.swt.events.MouseEvent; 046import org.eclipse.swt.events.SelectionAdapter; 047import org.eclipse.swt.events.SelectionEvent; 048import org.eclipse.swt.graphics.Font; 049import org.eclipse.swt.graphics.Image; 050import org.eclipse.swt.graphics.Point; 051import org.eclipse.swt.graphics.Rectangle; 052import org.eclipse.swt.layout.GridData; 053import org.eclipse.swt.layout.GridLayout; 054import org.eclipse.swt.widgets.Button; 055import org.eclipse.swt.widgets.Combo; 056import org.eclipse.swt.widgets.Composite; 057import org.eclipse.swt.widgets.Dialog; 058import org.eclipse.swt.widgets.Display; 059import org.eclipse.swt.widgets.Event; 060import org.eclipse.swt.widgets.FileDialog; 061import org.eclipse.swt.widgets.Label; 062import org.eclipse.swt.widgets.Listener; 063import org.eclipse.swt.widgets.Menu; 064import org.eclipse.swt.widgets.MenuItem; 065import org.eclipse.swt.widgets.Shell; 066import org.eclipse.swt.widgets.Tree; 067import org.eclipse.swt.widgets.TreeItem; 068 069import hdf.hdf5lib.HDF5Constants; 070 071import hdf.object.CompoundDS; 072import hdf.object.DataFormat; 073import hdf.object.Dataset; 074import hdf.object.Datatype; 075import hdf.object.FileFormat; 076import hdf.object.Group; 077import hdf.object.HObject; 078import hdf.object.MetaDataContainer; 079import hdf.object.ScalarDS; 080 081import hdf.view.DefaultFileFilter; 082import hdf.view.HDFView; 083import hdf.view.Tools; 084import hdf.view.ViewProperties; 085import hdf.view.ViewProperties.DATA_VIEW_KEY; 086import hdf.view.ViewProperties.DataViewType; 087import hdf.view.DataView.DataView; 088import hdf.view.DataView.DataViewFactory; 089import hdf.view.DataView.DataViewFactoryProducer; 090import hdf.view.DataView.DataViewManager; 091import hdf.view.MetaDataView.MetaDataView; 092import hdf.view.dialog.DataOptionDialog; 093import hdf.view.dialog.InputDialog; 094import hdf.view.dialog.NewCompoundDatasetDialog; 095import hdf.view.dialog.NewDatasetDialog; 096import hdf.view.dialog.NewDatatypeDialog; 097import hdf.view.dialog.NewGroupDialog; 098import hdf.view.dialog.NewImageDialog; 099import hdf.view.dialog.NewLinkDialog; 100 101/** 102 * TreeView defines APIs for opening files and displaying the file structure in 103 * a tree structure. 104 * 105 * TreeView uses folders and leaf items to represent groups and data objects in 106 * the file. You can expand or collapse folders to navigate data objects in the 107 * file. 108 * 109 * From the TreeView, you can open data content or metadata of the selected object. 110 * You can select object(s) to delete or add new objects to the file. 111 * 112 * @author Jordan T. Henderson 113 * @version 2.4 12//2015 114 */ 115public class DefaultTreeView implements TreeView { 116 117 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultTreeView.class); 118 119 private Shell shell; 120 121 private Font curFont; 122 123 /** The owner of this TreeView */ 124 private DataViewManager viewer; 125 126 /** Thread to load TableView Data in the background */ 127 private LoadDataThread loadDataThread; 128 129 /** 130 * The tree which holds file structures. 131 */ 132 private final Tree tree; 133 134 /** The currently selected tree item */ 135 private TreeItem selectedItem = null; 136 137 /** The list of current selected objects for copying */ 138 private TreeItem[] objectsToCopy = null; 139 140 private TreeItem[] currentSelectionsForMove = null; 141 142 /** The currently selected object */ 143 private HObject selectedObject; 144 145 /** The currently selected file */ 146 private FileFormat selectedFile; 147 148 /** Maintains a list of TreeItems in the tree in breadth-first order 149 * to prevent many calls of getAllItemsBreadthFirst. 150 */ 151 //private ArrayList<TreeItem> breadthFirstItems = null; 152 153 /** A list of currently open files */ 154 private final List<FileFormat> fileList = new ArrayList<>(); 155 156 /** A list of editing GUI components */ 157 private List<MenuItem> editGUIs = new ArrayList<>(); 158 159 /** 160 * The popup menu used to display user choice of actions on data object. 161 */ 162 private final Menu popupMenu; 163 164 private Menu newObjectMenu; 165 private Menu exportDatasetMenu; 166 167 private MenuItem openVirtualFilesMenuItem; 168 private MenuItem addDatasetMenuItem; 169 private MenuItem exportDatasetMenuItem; 170 private MenuItem addTableMenuItem; 171 private MenuItem addDatatypeMenuItem; 172 private MenuItem addLinkMenuItem; 173 private MenuItem setLibVerBoundsItem; 174 private MenuItem changeIndexItem; 175 176 /** Keep Image instances to prevent many calls to ViewProperties.getTypeIcon() */ 177 private Image h4Icon = ViewProperties.getH4Icon(); 178 private Image h4IconR = ViewProperties.getH4IconR(); 179 private Image h5Icon = ViewProperties.getH5Icon(); 180 private Image h5IconR = ViewProperties.getH5IconR(); 181 private Image nc3Icon = ViewProperties.getNC3Icon(); 182 private Image nc3IconR = ViewProperties.getNC3IconR(); 183 private Image imageIcon = ViewProperties.getImageIcon(); 184 private Image imageIconA = ViewProperties.getImageIconA(); 185 private Image textIcon = ViewProperties.getTextIcon(); 186 private Image textIconA = ViewProperties.getTextIconA(); 187 private Image datasetIcon = ViewProperties.getDatasetIcon(); 188 private Image datasetIconA = ViewProperties.getDatasetIconA(); 189 private Image tableIcon = ViewProperties.getTableIcon(); 190 private Image tableIconA = ViewProperties.getTableIconA(); 191 private Image datatypeIcon = ViewProperties.getDatatypeIcon(); 192 private Image datatypeIconA = ViewProperties.getDatatypeIconA(); 193 private Image folderCloseIcon = ViewProperties.getFoldercloseIcon(); 194 private Image folderCloseIconA = ViewProperties.getFoldercloseIconA(); 195 private Image folderOpenIcon = ViewProperties.getFolderopenIcon(); 196 private Image folderOpenIconA = ViewProperties.getFolderopenIconA(); 197 private Image questionIcon = ViewProperties.getQuestionIcon(); 198 199 /** Flag to indicate if the dataset is displayed as default */ 200 private boolean isDefaultDisplay = true; 201 202 /** Flag to indicate if TreeItems are being moved */ 203 private boolean moveFlag = false; 204 205 private boolean isApplyBitmaskOnly = false; 206 207 private int binaryOrder; 208 209 private String currentSearchPhrase = null; 210 211 /** Used to open a File using a temporary indexing type and order */ 212 private int tempIdxType = -1; 213 private int tempIdxOrder = -1; 214 215 private enum OBJECT_TYPE {GROUP, DATASET, IMAGE, TABLE, DATATYPE, LINK}; 216 217 /** 218 * Create a visual component for opening files and displaying the file 219 * structure in a tree structure. 220 * 221 * @param parent 222 * the parent component 223 * @param theView 224 * the associated data view manager 225 */ 226 public DefaultTreeView(Composite parent, DataViewManager theView) { 227 viewer = theView; 228 shell = parent.getShell(); 229 230 try { 231 curFont = new Font( 232 Display.getCurrent(), 233 ViewProperties.getFontType(), 234 ViewProperties.getFontSize(), 235 SWT.NORMAL); 236 } 237 catch (Exception ex) { 238 curFont = null; 239 } 240 241 // Initialize the Tree 242 tree = new Tree(parent, SWT.MULTI | SWT.VIRTUAL); 243 tree.setSize(tree.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 244 tree.setFont(curFont); 245 246 // Create the context menu for the Tree 247 popupMenu = createPopupMenu(); 248 tree.setMenu(popupMenu); 249 250 // Handle tree key events 251 tree.addKeyListener(new KeyAdapter() { 252 @Override 253 public void keyReleased(KeyEvent e) { 254 int key = e.keyCode; 255 256 if (key == SWT.ARROW_DOWN || key == SWT.ARROW_UP || key == SWT.KEYPAD_2 || key == SWT.KEYPAD_8) { 257 TreeItem[] selectedItems = tree.getSelection(); 258 TreeItem theItem = selectedItems[0]; 259 260 if(theItem.equals(selectedItem)) return; 261 262 selectedItem = theItem; 263 selectedObject = ((HObject) (selectedItem.getData())); 264 FileFormat theFile = selectedObject.getFileFormat(); 265 if ((theFile != null) && !theFile.equals(selectedFile)) { 266 // A different file is selected, handle only one file at a time 267 selectedFile = theFile; 268 tree.deselectAll(); 269 } 270 271 ((HDFView) viewer).showMetaData(selectedObject); 272 } 273 else if (key == SWT.ARROW_LEFT || key == SWT.KEYPAD_4) { 274 if(selectedObject instanceof Group) { 275 selectedItem.setExpanded(false); 276 277 Event collapse = new Event(); 278 collapse.item = selectedItem; 279 280 tree.notifyListeners(SWT.Collapse, collapse); 281 } 282 } 283 else if (key == SWT.ARROW_RIGHT || key == SWT.KEYPAD_6) { 284 if(selectedObject instanceof Group) { 285 selectedItem.setExpanded(true); 286 287 Event expand = new Event(); 288 expand.item = selectedItem; 289 290 tree.notifyListeners(SWT.Expand, expand); 291 } 292 } 293 } 294 }); 295 296 /** 297 * If user presses Enter on a TreeItem, expand/collapse the item if it 298 * is a group, or try to show the data content if it is a data object. 299 */ 300 tree.addListener(SWT.Traverse, new Listener() { 301 @Override 302 public void handleEvent(Event event) { 303 if (event.detail != SWT.TRAVERSE_RETURN) 304 return; 305 306 TreeItem item = selectedItem; 307 if(item == null) 308 return; 309 310 final HObject obj = (HObject) item.getData(); 311 if(obj == null) 312 return; 313 314 if(obj instanceof Group) { 315 boolean isExpanded = item.getExpanded(); 316 317 item.setExpanded(!isExpanded); 318 319 Event expand = new Event(); 320 expand.item = item; 321 322 if(isExpanded) 323 tree.notifyListeners(SWT.Collapse, expand); 324 else 325 tree.notifyListeners(SWT.Expand, expand); 326 } 327 else { 328 try { 329 loadDataThread = new LoadDataThread(); 330 loadDataThread.start(); 331 } 332 catch (Exception err) { 333 shell.getDisplay().beep(); 334 Tools.showError(shell, "Select", err.getMessage()); 335 } 336 } 337 } 338 }); 339 340 /** 341 * Handle mouse clicks on data objects in the tree view. A right mouse-click 342 * to show the popup menu for user choice. A double left-mouse-click to 343 * display the data content. A single left-mouse-click to select the current 344 * data object. 345 */ 346 tree.addMouseListener(new MouseAdapter() { 347 // Double click opens data content of selected data object 348 @Override 349 public void mouseDoubleClick(MouseEvent e) { 350 isDefaultDisplay = true; 351 352 try { 353 if(!(selectedObject instanceof Group)) { 354 loadDataThread = new LoadDataThread(); 355 loadDataThread.start(); 356 } 357 else { 358 boolean isExpanded = selectedItem.getExpanded(); 359 360 selectedItem.setExpanded(!isExpanded); 361 362 Event expand = new Event(); 363 expand.item = selectedItem; 364 365 if(isExpanded) 366 tree.notifyListeners(SWT.Collapse, expand); 367 else 368 tree.notifyListeners(SWT.Expand, expand); 369 } 370 } 371 catch (Exception ex) { 372 log.trace("defaultDisplay showDataContent failed: {}", ex.getMessage()); 373 ex.printStackTrace(); 374 } 375 } 376 377 // When a mouse release is detected, attempt to set the selected item 378 // and object to the TreeItem under the pointer 379 @Override 380 public void mouseUp(MouseEvent e) { 381 // Make sure user clicked on a TreeItem 382 TreeItem theItem = tree.getItem(new Point(e.x, e.y)); 383 384 if (theItem == null) { 385 tree.deselectAll(); 386 selectedItem = null; 387 selectedObject = null; 388 selectedFile = null; 389 390 // Clear any information shown in the object info panel 391 ((HDFView) viewer).showMetaData(null); 392 393 return; 394 } 395 396 if (theItem.equals(selectedItem)) 397 return; 398 399 FileFormat theFile = null; 400 401 selectedItem = theItem; 402 403 try { 404 selectedObject = (HObject) selectedItem.getData(); 405 } 406 catch(NullPointerException ex) { 407 viewer.showError("Object " + selectedItem.getText() + " had no associated data."); 408 return; 409 } 410 411 try { 412 theFile = selectedObject.getFileFormat(); 413 } 414 catch(NullPointerException ex) { 415 viewer.showError("Error retrieving FileFormat of HObject " + selectedObject.getName() + "."); 416 return; 417 } 418 419 if ((theFile != null) && !theFile.equals(selectedFile)) { 420 // A different file is selected, handle only one file at a time 421 selectedFile = theFile; 422 } 423 424 // Set this file to the most recently selected file in the recent files bar 425 Combo recentFilesCombo = ((HDFView) viewer).getUrlBar(); 426 String filename = selectedFile.getAbsolutePath(); 427 428 try { 429 recentFilesCombo.remove(filename); 430 } 431 catch (Exception ex) {} 432 433 // first entry is always the workdir 434 recentFilesCombo.add(filename, 1); 435 recentFilesCombo.select(1); 436 437 ((HDFView) viewer).showMetaData(selectedObject); 438 } 439 }); 440 441 // Show context menu only if user has selected a data object 442 tree.addMenuDetectListener(new MenuDetectListener() { 443 @Override 444 public void menuDetected(MenuDetectEvent e) { 445 Display display = Display.getDefault(); 446 447 Point pt = display.map(null, tree, new Point(e.x, e.y)); 448 TreeItem item = tree.getItem(pt); 449 if(item == null) { e.doit = false; return; } 450 451 FileFormat theFile = null; 452 453 selectedItem = item; 454 455 log.trace("tree.addMenuDetectListener(): selectedItem={}", selectedItem.getText()); 456 try { 457 selectedObject = (HObject) selectedItem.getData(); 458 } 459 catch(NullPointerException ex) { 460 viewer.showError("Object " + selectedItem.getText() + " had no associated data."); 461 return; 462 } 463 464 try { 465 theFile = selectedObject.getFileFormat(); 466 } 467 catch(NullPointerException ex) { 468 viewer.showError("Error retrieving FileFormat of HObject " + selectedObject.getName() + "."); 469 return; 470 } 471 472 if ((theFile != null) && !theFile.equals(selectedFile)) { 473 // A different file is selected, handle only one file at a time 474 selectedFile = theFile; 475 //tree.deselectAll(); 476 //tree.setSelection(selPath); 477 log.trace("tree.addMenuDetectListener(): selectedFile={}", selectedFile.getAbsolutePath()); 478 } 479 480 ((HDFView) viewer).showMetaData(selectedObject); 481 482 popupMenu.setLocation(display.map(tree, null, pt)); 483 popupMenu.setVisible(true); 484 } 485 }); 486 487 tree.addListener(SWT.Expand, new Listener() { 488 @Override 489 public void handleEvent(Event event) { 490 TreeItem item = (TreeItem) event.item; 491 Object obj = item.getData(); 492 493 if (!(obj instanceof Group)) 494 return; 495 496 Group theGroup = (Group) item.getData(); 497 498 if(theGroup.isRoot()) 499 return; 500 501 // Prevent graphical issues from happening by stopping 502 // tree from redrawing until all the items are created 503 tree.setRedraw(false); 504 505 if(item.getItemCount() > 0) 506 item.setImage(theGroup.hasAttribute() ? folderOpenIconA : folderOpenIcon); 507 508 // Process any remaining SetData events and then allow 509 // the tree to redraw once all are finished 510 // while(tree.getDisplay().readAndDispatch()); 511 512 tree.setRedraw(true); 513 } 514 }); 515 516 tree.addListener(SWT.Collapse, new Listener() { 517 @Override 518 public void handleEvent(Event event) { 519 TreeItem item = (TreeItem) event.item; 520 Object obj = item.getData(); 521 522 if (!(obj instanceof Group)) 523 return; 524 525 Group theGroup = (Group) item.getData(); 526 527 if(theGroup.isRoot()) 528 return; 529 530 item.setImage(theGroup.hasAttribute() ? folderCloseIconA : folderCloseIcon); 531 } 532 }); 533 534 // When groups are expanded, populate TreeItems corresponding to file objects 535 // on demand. 536 tree.addListener(SWT.SetData, new Listener() { 537 @Override 538 public void handleEvent(Event event) { 539 TreeItem item = (TreeItem) event.item; 540 TreeItem parentItem = item.getParentItem(); 541 542 int position = parentItem.indexOf(item); 543 HObject obj = ((Group) parentItem.getData()).getMember(position); 544 545 item.setData(obj); 546 item.setFont(curFont); 547 item.setText(obj.getName()); 548 item.setImage(getObjectTypeImage(obj)); 549 550 if(obj instanceof Group) 551 item.setItemCount(((Group) obj).getMemberList().size()); 552 } 553 }); 554 555 tree.addDisposeListener(new DisposeListener() { 556 @Override 557 public void widgetDisposed(DisposeEvent e) { 558 if (curFont != null) 559 curFont.dispose(); 560 } 561 }); 562 } 563 564 /** Creates a popup menu for a right mouse click on a data object */ 565 private Menu createPopupMenu() { 566 Menu menu = new Menu(tree); 567 MenuItem item; 568 569 item = new MenuItem(menu, SWT.PUSH); 570 item.setText("&Open"); 571 item.addSelectionListener(new SelectionAdapter() { 572 @Override 573 public void widgetSelected(SelectionEvent e) { 574 isDefaultDisplay = true; 575 576 try { 577 loadDataThread = new LoadDataThread(); 578 loadDataThread.start(); 579 } 580 catch (Exception err) { 581 shell.getDisplay().beep(); 582 Tools.showError(shell, "Open", err.getMessage()); 583 } 584 } 585 }); 586 587 item = new MenuItem(menu, SWT.PUSH); 588 item.setText("Open &As"); 589 item.addSelectionListener(new SelectionAdapter() { 590 @Override 591 public void widgetSelected(SelectionEvent e) { 592 isDefaultDisplay = false; 593 594 try { 595 loadDataThread = new LoadDataThread(); 596 loadDataThread.start(); 597 } 598 catch (Exception err) { 599 shell.getDisplay().beep(); 600 err.printStackTrace(); 601 Tools.showError(shell, "Open", err.getMessage()); 602 } 603 } 604 }); 605 606 openVirtualFilesMenuItem = new MenuItem(menu, SWT.PUSH); 607 openVirtualFilesMenuItem.setText("Open Source Fi&les"); 608 openVirtualFilesMenuItem.addSelectionListener(new SelectionAdapter() { 609 @Override 610 public void widgetSelected(SelectionEvent e) { 611 isDefaultDisplay = false; 612 613 log.trace("createPopupMenu(): selectedObject={}", selectedObject); 614 // If dataset is virtual - open source files. Only for HDF5 615 if (selectedObject != null) { 616 log.trace("createPopupMenu(): selectedObject={} is dataset instance-{} of type H5 {}", selectedObject, selectedObject instanceof Dataset, selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))); 617 if (selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)) && 618 (selectedObject instanceof Dataset)) { 619 Dataset dataset = (Dataset) selectedObject; 620 boolean isVirtual = dataset.isVirtual(); 621 log.trace("createPopupMenu(): isVirtual={}", isVirtual); 622 if(isVirtual) { 623 for(int ndx=0; ndx<dataset.getVirtualMaps(); ndx++) { 624 try { 625 String theFile = selectedFile.getParentFile().getAbsolutePath() + File.separator + dataset.getVirtualFilename(ndx); 626 openFile(theFile, FileFormat.WRITE); 627 } 628 catch (Exception ex) { 629 shell.getDisplay().beep(); 630 ex.printStackTrace(); 631 Tools.showError(shell, "Open", ex.getMessage() + "\n" + dataset.getVirtualFilename(ndx)); 632 } 633 log.trace("createPopupMenu(): virtualNameList[{}]={}", ndx, dataset.getVirtualFilename(ndx)); 634 } 635 } 636 } 637 } 638 } 639 }); 640 641 new MenuItem(menu, SWT.SEPARATOR); 642 643 MenuItem newObjectMenuItem = new MenuItem(menu, SWT.CASCADE); 644 newObjectMenuItem.setText("New"); 645 editGUIs.add(newObjectMenuItem); 646 647 new MenuItem(menu, SWT.SEPARATOR); 648 649 item = new MenuItem(menu, SWT.PUSH); 650 item.setText("Cu&t"); 651 item.addSelectionListener(new SelectionAdapter() { 652 @Override 653 public void widgetSelected(SelectionEvent e) { 654 moveObject(); 655 } 656 }); 657 editGUIs.add(item); 658 659 item = new MenuItem(menu, SWT.PUSH); 660 item.setText("&Copy"); 661 item.addSelectionListener(new SelectionAdapter() { 662 @Override 663 public void widgetSelected(SelectionEvent e) { 664 copyObject(); 665 } 666 }); 667 668 item = new MenuItem(menu, SWT.PUSH); 669 item.setText("&Paste"); 670 item.addSelectionListener(new SelectionAdapter() { 671 @Override 672 public void widgetSelected(SelectionEvent e) { 673 pasteObject(); 674 } 675 }); 676 editGUIs.add(item); 677 678 item = new MenuItem(menu, SWT.PUSH); 679 item.setText("&Delete"); 680 item.addSelectionListener(new SelectionAdapter() { 681 @Override 682 public void widgetSelected(SelectionEvent e) { 683 cutObject(); 684 } 685 }); 686 editGUIs.add(item); 687 688 exportDatasetMenuItem = new MenuItem(menu, SWT.CASCADE); 689 exportDatasetMenuItem.setText("Export Dataset"); 690 691 new MenuItem(menu, SWT.SEPARATOR); 692 693 item = new MenuItem(menu, SWT.PUSH); 694 item.setText("&Save to"); 695 item.addSelectionListener(new SelectionAdapter() { 696 @Override 697 public void widgetSelected(SelectionEvent e) { 698 TreeItem[] selectedItems = tree.getSelection(); 699 700 if (selectedItems.length <= 0) return; 701 702 for (int i = 0; i < selectedItems.length; i++) { 703 if (((HObject) selectedItems[i].getData() instanceof Group) 704 && ((Group) selectedItems[i].getData()).isRoot()) { 705 shell.getDisplay().beep(); 706 Tools.showError(shell, "Save", "Cannot save the root group.\nUse \"Save As\" from file menu to save the whole file"); 707 return; 708 } 709 } 710 711 String filetype = FileFormat.FILE_TYPE_HDF4; 712 if (selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) 713 filetype = FileFormat.FILE_TYPE_HDF5; 714 else if (selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3))) 715 filetype = FileFormat.FILE_TYPE_NC3; 716 717 String currentDir = selectedObject.getFileFormat().getParent(); 718 719 if (currentDir != null) 720 currentDir += File.separator; 721 else 722 currentDir = ""; 723 724 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 725 726 DefaultFileFilter filter = null; 727 728 if (filetype.equals(FileFormat.FILE_TYPE_HDF4)) { 729 fChooser.setFileName(Tools.checkNewFile(currentDir, ".hdf").getName()); 730 filter = DefaultFileFilter.getFileFilterHDF4(); 731 } 732 else if (filetype.equals(FileFormat.FILE_TYPE_NC3)) { 733 fChooser.setFileName(Tools.checkNewFile(currentDir, ".nc").getName()); 734 filter = DefaultFileFilter.getFileFilterNetCDF3(); 735 } 736 else { 737 fChooser.setFileName(Tools.checkNewFile(currentDir, ".h5").getName()); 738 filter = DefaultFileFilter.getFileFilterHDF5(); 739 } 740 741 fChooser.setFilterExtensions(new String[] {filter.getExtensions()}); 742 fChooser.setFilterNames(new String[] {filter.getDescription()}); 743 fChooser.setFilterIndex(0); 744 745 String filename = fChooser.open(); 746 747 if(filename == null) 748 return; 749 750 try { 751 Tools.createNewFile(filename, currentDir, filetype, fileList); 752 } 753 catch (Exception ex) { 754 Tools.showError(shell, "Save", ex.getMessage()); 755 } 756 757 FileFormat dstFile = null; 758 759 try { 760 dstFile = openFile(filename, FileFormat.WRITE); 761 } 762 catch (Exception ex) { 763 shell.getDisplay().beep(); 764 Tools.showError(shell, "Save", ex.getMessage() + "\n" + filename); 765 } 766 if (dstFile != null) 767 pasteObject(selectedItems, findTreeItem(dstFile.getRootObject()), dstFile); 768 } 769 }); 770 771 item = new MenuItem(menu, SWT.PUSH); 772 item.setText("&Rename"); 773 item.addSelectionListener(new SelectionAdapter() { 774 @Override 775 public void widgetSelected(SelectionEvent e) { 776 renameObject(); 777 } 778 }); 779 editGUIs.add(item); 780 781 new MenuItem(menu, SWT.SEPARATOR); 782 783 changeIndexItem = new MenuItem(menu, SWT.PUSH); 784 changeIndexItem.setText("Change file indexing"); 785 changeIndexItem.addSelectionListener(new SelectionAdapter() { 786 @Override 787 public void widgetSelected(SelectionEvent e) { 788 ChangeIndexingDialog dialog = new ChangeIndexingDialog(shell, SWT.NONE, selectedFile); 789 dialog.open(); 790 if (dialog.isReloadFile()) { 791 try { 792 selectedFile.setIndexType(dialog.getIndexType()); 793 } 794 catch (Exception ex) { 795 log.debug("ChangeIndexingDialog(): setIndexType failed: ", ex); 796 } 797 try { 798 selectedFile.setIndexOrder(dialog.getIndexOrder()); 799 } 800 catch (Exception ex) { 801 log.debug("ChangeIndexingDialog(): setIndexOrder failed: ", ex); 802 } 803 804 try { 805 reopenFile(selectedFile, -1); 806 } 807 catch (Exception ex) { 808 log.debug("reload file {} failure after indexing change: ", selectedFile.getAbsolutePath(), ex); 809 Tools.showError(shell, "File reload error", "Error reloading file " + selectedFile.getAbsolutePath() + " after changing indexing: " + ex.getMessage()); 810 } 811 } 812 } 813 }); 814 815 new MenuItem(menu, SWT.SEPARATOR); 816 817 item = new MenuItem(menu, SWT.PUSH); 818 item.setText("&Find"); 819 item.addSelectionListener(new SelectionAdapter() { 820 @Override 821 public void widgetSelected(SelectionEvent e) { 822 String findStr = currentSearchPhrase; 823 if (findStr == null) 824 findStr = ""; 825 826 findStr = (new InputDialog(shell, "Find Object by Name", 827 "Find (e.g. O3Quality, O3*, or *Quality):", findStr)).open(); 828 829 if (findStr != null && findStr.length() > 0) 830 currentSearchPhrase = findStr; 831 832 find(currentSearchPhrase, selectedItem); 833 } 834 }); 835 836 new MenuItem(menu, SWT.SEPARATOR); 837 838 item = new MenuItem(menu, SWT.PUSH); 839 item.setText("Expand All"); 840 item.addSelectionListener(new SelectionAdapter() { 841 @Override 842 public void widgetSelected(SelectionEvent e) { 843 if(selectedItem != null) 844 recursiveExpand(selectedItem, true); 845 } 846 }); 847 848 item = new MenuItem(menu, SWT.PUSH); 849 item.setText("Collapse All"); 850 item.addSelectionListener(new SelectionAdapter() { 851 @Override 852 public void widgetSelected(SelectionEvent e) { 853 if(selectedItem != null) 854 recursiveExpand(selectedItem, false); 855 } 856 }); 857 858 new MenuItem(menu, SWT.SEPARATOR); 859 860 item = new MenuItem(menu, SWT.PUSH); 861 item.setText("Close Fil&e"); 862 item.addSelectionListener(new SelectionAdapter() { 863 @Override 864 public void widgetSelected(SelectionEvent e) { 865 try { 866 ((HDFView) viewer).closeFile(selectedFile); 867 } 868 catch (Exception ex) { 869 Tools.showError(shell, "Close", ex.getMessage()); 870 } 871 } 872 }); 873 874 item = new MenuItem(menu, SWT.PUSH); 875 item.setText("&Reload File"); 876 item.addSelectionListener(new SelectionAdapter() { 877 @Override 878 public void widgetSelected(SelectionEvent e) { 879 try { 880 reopenFile(selectedFile, -1); 881 } 882 catch (Exception ex) { 883 log.debug("reload file {} failure: ", selectedFile.getAbsolutePath(), ex); 884 Tools.showError(shell, "File reload error", "Error reloading file " + selectedFile.getAbsolutePath() + ": " + ex.getMessage()); 885 } 886 } 887 }); 888 889 item = new MenuItem(menu, SWT.CASCADE); 890 item.setText("Reload File As"); 891 892 Menu reloadFileMenu = new Menu(item); 893 item.setMenu(reloadFileMenu); 894 895 item = new MenuItem(reloadFileMenu, SWT.PUSH); 896 item.setText("Read-Only"); 897 item.addSelectionListener(new SelectionAdapter() { 898 @Override 899 public void widgetSelected(SelectionEvent e) { 900 try { 901 reopenFile(selectedFile, FileFormat.READ); 902 } 903 catch (Exception ex) { 904 log.debug("reload file {} as read-only failure: ", selectedFile.getAbsolutePath(), ex); 905 Tools.showError(shell, "File reload error", "Error reloading file " + selectedFile.getAbsolutePath() + " read-only: " + ex.getMessage()); 906 } 907 } 908 }); 909 910 item = new MenuItem(reloadFileMenu, SWT.PUSH); 911 item.setText("Read/Write"); 912 item.addSelectionListener(new SelectionAdapter() { 913 @Override 914 public void widgetSelected(SelectionEvent e) { 915 try { 916 reopenFile(selectedFile, FileFormat.WRITE); 917 } 918 catch (Exception ex) { 919 log.debug("reload file {} as read/write failure: ", selectedFile.getAbsolutePath(), ex); 920 Tools.showError(shell, "File reload error", "Error reloading file " + selectedFile.getAbsolutePath() + " read/write: " + ex.getMessage()); 921 } 922 } 923 }); 924 925 new MenuItem(menu, SWT.SEPARATOR); 926 927 setLibVerBoundsItem = new MenuItem(menu, SWT.NONE); 928 setLibVerBoundsItem.setText("Set Lib version bounds"); 929 setLibVerBoundsItem.addSelectionListener(new SelectionAdapter() { 930 @Override 931 public void widgetSelected(SelectionEvent e) { 932 new ChangeLibVersionDialog(shell, SWT.NONE).open(); 933 } 934 }); 935 936 937 // Add new object menu 938 newObjectMenu = new Menu(menu); 939 newObjectMenuItem.setMenu(newObjectMenu); 940 941 item = new MenuItem(newObjectMenu, SWT.PUSH); 942 item.setText("Group"); 943 item.setImage(ViewProperties.getFoldercloseIcon()); 944 item.addSelectionListener(new SelectionAdapter() { 945 @Override 946 public void widgetSelected(SelectionEvent e) { 947 addNewObject(OBJECT_TYPE.GROUP); 948 } 949 }); 950 editGUIs.add(item); 951 952 addDatasetMenuItem = new MenuItem(newObjectMenu, SWT.PUSH); 953 addDatasetMenuItem.setText("Dataset"); 954 addDatasetMenuItem.setImage(ViewProperties.getDatasetIcon()); 955 addDatasetMenuItem.addSelectionListener(new SelectionAdapter() { 956 @Override 957 public void widgetSelected(SelectionEvent e) { 958 addNewObject(OBJECT_TYPE.DATASET); 959 } 960 }); 961 editGUIs.add(addDatasetMenuItem); 962 963 item = new MenuItem(newObjectMenu, SWT.PUSH); 964 item.setText("Image"); 965 item.setImage(ViewProperties.getImageIcon()); 966 item.addSelectionListener(new SelectionAdapter() { 967 @Override 968 public void widgetSelected(SelectionEvent e) { 969 addNewObject(OBJECT_TYPE.IMAGE); 970 } 971 }); 972 editGUIs.add(item); 973 974 addTableMenuItem = new MenuItem(newObjectMenu, SWT.PUSH); 975 addTableMenuItem.setText("Compound DS"); 976 addTableMenuItem.setImage(ViewProperties.getTableIcon()); 977 addTableMenuItem.addSelectionListener(new SelectionAdapter() { 978 @Override 979 public void widgetSelected(SelectionEvent e) { 980 addNewObject(OBJECT_TYPE.TABLE); 981 } 982 }); 983 editGUIs.add(addTableMenuItem); 984 985 addDatatypeMenuItem = new MenuItem(newObjectMenu, SWT.PUSH); 986 addDatatypeMenuItem.setText("Datatype"); 987 addDatatypeMenuItem.setImage(ViewProperties.getDatatypeIcon()); 988 addDatatypeMenuItem.addSelectionListener(new SelectionAdapter() { 989 @Override 990 public void widgetSelected(SelectionEvent e) { 991 addNewObject(OBJECT_TYPE.DATATYPE); 992 } 993 }); 994 editGUIs.add(addDatatypeMenuItem); 995 996 addLinkMenuItem = new MenuItem(newObjectMenu, SWT.PUSH); 997 addLinkMenuItem.setText("Link"); 998 addLinkMenuItem.setImage(ViewProperties.getLinkIcon()); 999 addLinkMenuItem.addSelectionListener(new SelectionAdapter() { 1000 @Override 1001 public void widgetSelected(SelectionEvent e) { 1002 addNewObject(OBJECT_TYPE.LINK); 1003 } 1004 }); 1005 editGUIs.add(addLinkMenuItem); 1006 1007 1008 // Add export dataset menu 1009 exportDatasetMenu = new Menu(menu); 1010 exportDatasetMenuItem.setMenu(exportDatasetMenu); 1011 1012 item = new MenuItem(exportDatasetMenu, SWT.PUSH); 1013 item.setText("Export Data to Text File"); 1014 item.addSelectionListener(new SelectionAdapter() { 1015 @Override 1016 public void widgetSelected(SelectionEvent e) { 1017 binaryOrder = 99; 1018 1019 try { 1020 saveDataAsFile(); 1021 } 1022 catch (Exception ex) { 1023 shell.getDisplay().beep(); 1024 Tools.showError(shell, "Export Dataset", ex.getMessage()); 1025 } 1026 } 1027 }); 1028 1029 item = new MenuItem(exportDatasetMenu, SWT.PUSH); 1030 item.setText("Export Data as Native Order"); 1031 item.addSelectionListener(new SelectionAdapter() { 1032 @Override 1033 public void widgetSelected(SelectionEvent e) { 1034 binaryOrder = 1; 1035 1036 try { 1037 saveDataAsFile(); 1038 } 1039 catch (Exception ex) { 1040 shell.getDisplay().beep(); 1041 Tools.showError(shell, "Export Dataset", ex.getMessage()); 1042 } 1043 } 1044 }); 1045 1046 item = new MenuItem(exportDatasetMenu, SWT.PUSH); 1047 item.setText("Export Data as Little Endian"); 1048 item.addSelectionListener(new SelectionAdapter() { 1049 @Override 1050 public void widgetSelected(SelectionEvent e) { 1051 binaryOrder = 2; 1052 1053 try { 1054 saveDataAsFile(); 1055 } 1056 catch (Exception ex) { 1057 shell.getDisplay().beep(); 1058 Tools.showError(shell, "Export Dataset", ex.getMessage()); 1059 } 1060 } 1061 }); 1062 1063 item = new MenuItem(exportDatasetMenu, SWT.PUSH); 1064 item.setText("Export Data as Big Endian"); 1065 item.addSelectionListener(new SelectionAdapter() { 1066 @Override 1067 public void widgetSelected(SelectionEvent e) { 1068 binaryOrder = 3; 1069 1070 try { 1071 saveDataAsFile(); 1072 } 1073 catch (Exception ex) { 1074 shell.getDisplay().beep(); 1075 Tools.showError(shell, "Export Dataset", ex.getMessage()); 1076 } 1077 } 1078 }); 1079 1080 // Add listener to dynamically enable/disable menu items based 1081 // on selection in tree 1082 menu.addMenuListener(new MenuAdapter() { 1083 @Override 1084 public void menuShown(MenuEvent e) { 1085 if (selectedItem == null || selectedObject == null || selectedFile == null) return; 1086 1087 boolean isReadOnly = selectedObject.getFileFormat().isReadOnly(); 1088 boolean isWritable = !isReadOnly; 1089 1090 setEnabled(editGUIs, isWritable); 1091 1092 if (selectedObject instanceof Group) { 1093 boolean state = !(((Group) selectedObject).isRoot()); 1094 1095 popupMenu.getItem(0).setEnabled(false); // "Open" menuitem 1096 popupMenu.getItem(1).setEnabled(false); // "Open as" menuitem 1097 popupMenu.getItem(2).setEnabled(false); // "Open Source Files" menuitem 1098 popupMenu.getItem(6).setEnabled( 1099 (selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) 1100 && state && isWritable); // "Cut" menuitem 1101 popupMenu.getItem(7).setEnabled(state); // "Copy" menuitem 1102 popupMenu.getItem(9).setEnabled(state && isWritable); // "Delete" menuitem 1103 popupMenu.getItem(10).setEnabled(false); // "Export Dataset" menuitem 1104 popupMenu.getItem(12).setEnabled(state && isWritable); // "Save to" menuitem 1105 popupMenu.getItem(13).setEnabled(state && isWritable); // "Rename" menuitem 1106 } 1107 else { 1108 popupMenu.getItem(0).setEnabled(true); // "Open" menuitem 1109 popupMenu.getItem(1).setEnabled(true); // "Open as" menuitem 1110 popupMenu.getItem(2).setEnabled( 1111 (selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)))); // "Open Source Files" menuitem 1112 popupMenu.getItem(6).setEnabled( 1113 (selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) 1114 && isWritable); // "Cut" menuitem 1115 popupMenu.getItem(7).setEnabled(true); // "Copy" menuitem 1116 popupMenu.getItem(9).setEnabled(isWritable); // "Delete" menuitem 1117 popupMenu.getItem(10).setEnabled(true); // "Export Dataset" menuitem 1118 popupMenu.getItem(12).setEnabled(true); // "Save to" menuitem 1119 popupMenu.getItem(13).setEnabled(isWritable); // "Rename" menuitem 1120 } 1121 1122 // Adding table is only supported by HDF5 1123 if ((selectedFile != null) && selectedFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) { 1124 //openVirtualFilesMenuItem.setEnabled(true); // Should be moved to createPopupMenu() since swt doesn't support MenuItem.setVisible 1125 1126 boolean state = false; 1127 if ((selectedObject instanceof Group)) { 1128 state = (((Group) selectedObject).isRoot()); 1129 setLibVerBoundsItem.setEnabled(isWritable && state); 1130 } 1131 else { 1132 setLibVerBoundsItem.setEnabled(false); 1133 } 1134 1135 changeIndexItem.setEnabled(state); 1136 } 1137 else { 1138 addTableMenuItem.setEnabled(false); 1139 addDatatypeMenuItem.setEnabled(false); 1140 addLinkMenuItem.setEnabled(false); 1141 //openVirtualFilesMenuItem.setEnabled(false); 1142 setLibVerBoundsItem.setEnabled(false); 1143 changeIndexItem.setEnabled(false); 1144 } 1145 1146 // Export table is only supported by HDF5 1147 if ((selectedObject != null) && selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) { 1148 if ((selectedObject instanceof Dataset)) { 1149 Dataset dataset = (Dataset) selectedObject; 1150 if ((dataset instanceof ScalarDS)) 1151 exportDatasetMenuItem.setEnabled(true); 1152 openVirtualFilesMenuItem.setEnabled(true); 1153 } 1154 else { 1155 exportDatasetMenuItem.setEnabled(false); 1156 openVirtualFilesMenuItem.setEnabled(false); 1157 } 1158 } 1159 else { 1160 exportDatasetMenuItem.setEnabled(false); 1161 openVirtualFilesMenuItem.setEnabled(false); 1162 } 1163 } 1164 }); 1165 1166 return menu; 1167 } 1168 1169 /** 1170 * Creates a dialog for the user to select a type of new 1171 * object to be added to the TreeView, then passes the 1172 * result of the dialog on to addObject(HObject newObject, Group parentGroup) 1173 * 1174 * @param type 1175 * The type (GROUP, DATASET, IMAGE, TABLE, DATATYPE, LINK) of object to add. 1176 */ 1177 private void addNewObject(OBJECT_TYPE type) { 1178 if ((selectedObject == null) || (selectedItem == null)) return; 1179 1180 TreeItem parentItem = null; 1181 if(selectedObject instanceof Group) 1182 parentItem = selectedItem; 1183 else 1184 parentItem = selectedItem.getParentItem(); 1185 1186 // Find the root item of the selected file 1187 TreeItem rootItem = selectedItem; 1188 while(rootItem.getParentItem() != null) 1189 rootItem = rootItem.getParentItem(); 1190 1191 HObject obj = null; 1192 1193 switch(type) { 1194 case GROUP: 1195 NewGroupDialog groupDialog = new NewGroupDialog(shell, (Group) parentItem.getData(), 1196 breadthFirstUserObjects(rootItem)); 1197 groupDialog.open(); 1198 obj = groupDialog.getObject(); 1199 parentItem = findTreeItem(groupDialog.getParentGroup()); 1200 break; 1201 case DATASET: 1202 NewDatasetDialog datasetDialog = new NewDatasetDialog(shell, (Group) parentItem.getData(), breadthFirstUserObjects(rootItem)); 1203 datasetDialog.open(); 1204 obj = datasetDialog.getObject(); 1205 parentItem = findTreeItem(datasetDialog.getParentGroup()); 1206 break; 1207 case IMAGE: 1208 NewImageDialog imageDialog = new NewImageDialog(shell, (Group) parentItem.getData(), breadthFirstUserObjects(rootItem)); 1209 imageDialog.open(); 1210 obj = imageDialog.getObject(); 1211 parentItem = findTreeItem(imageDialog.getParentGroup()); 1212 break; 1213 case TABLE: 1214 NewCompoundDatasetDialog tableDialog = new NewCompoundDatasetDialog(shell, (Group) parentItem.getData(), breadthFirstUserObjects(rootItem)); 1215 tableDialog.open(); 1216 obj = tableDialog.getObject(); 1217 parentItem = findTreeItem(tableDialog.getParentGroup()); 1218 break; 1219 case DATATYPE: 1220 NewDatatypeDialog datatypeDialog = new NewDatatypeDialog(shell, (Group) parentItem.getData(), breadthFirstUserObjects(rootItem)); 1221 datatypeDialog.open(); 1222 obj = datatypeDialog.getObject(); 1223 parentItem = findTreeItem(datatypeDialog.getParentGroup()); 1224 break; 1225 case LINK: 1226 NewLinkDialog linkDialog = new NewLinkDialog(shell, (Group) parentItem.getData(), breadthFirstUserObjects(rootItem), getCurrentFiles()); 1227 linkDialog.open(); 1228 obj = linkDialog.getObject(); 1229 parentItem = findTreeItem(linkDialog.getParentGroup()); 1230 break; 1231 } 1232 1233 if (obj == null) 1234 return; 1235 1236 try { 1237 this.insertObject(obj, parentItem); 1238 } 1239 catch (Exception ex) { 1240 shell.getDisplay().beep(); 1241 Tools.showError(shell, "Create", ex.getMessage()); 1242 } 1243 } 1244 1245 /** 1246 * Adds an already created HObject to the tree under the 1247 * TreeItem containing the specified parent group. 1248 * 1249 * @param obj 1250 * the object to add. 1251 * @param parentGroup 1252 * the parent group to add the object to. 1253 */ 1254 @Override 1255 public TreeItem addObject(HObject obj, Group parentGroup) { 1256 if ((obj == null) || (parentGroup == null)) 1257 return null; 1258 1259 return insertObject(obj, findTreeItem(parentGroup)); 1260 } 1261 1262 /** 1263 * Insert an object into the tree as the last object 1264 * under parent item pobj. 1265 * 1266 * @param obj 1267 * the object to insert. 1268 * @param pobj 1269 * the parent TreeItem to insert the new object under. 1270 * If null, inserts the object at the end of the Tree. 1271 * 1272 * @return the newly created TreeItem 1273 */ 1274 private TreeItem insertObject(HObject obj, TreeItem pobj) { 1275 if ((obj == null)) 1276 return null; 1277 1278 TreeItem item; 1279 1280 if(pobj != null) { 1281 item = new TreeItem(pobj, SWT.NONE, pobj.getItemCount()); 1282 item.setFont(curFont); 1283 item.setText(obj.getName()); 1284 } 1285 else { 1286 // Parent object was null, insert at end of tree as root object 1287 item = new TreeItem(tree, SWT.NONE, tree.getItemCount()); 1288 item.setFont(curFont); 1289 item.setText(obj.getFileFormat().getName()); 1290 } 1291 1292 item.setData(obj); 1293 item.setImage(getObjectTypeImage(obj)); 1294 1295 return item; 1296 } 1297 1298 /** Move selected objects */ 1299 private void moveObject() { 1300 objectsToCopy = tree.getSelection(); 1301 moveFlag = true; 1302 currentSelectionsForMove = tree.getSelection(); 1303 } 1304 1305 /** Copy selected objects */ 1306 private void copyObject() { 1307 if (moveFlag) 1308 if(!Tools.showConfirm(shell, "Copy object", "Do you want to copy all the selected object(s) instead of move?")) 1309 return; 1310 moveFlag = false; 1311 currentSelectionsForMove = null; 1312 objectsToCopy = tree.getSelection(); 1313 } 1314 1315 /** Delete selected objects */ 1316 private void cutObject() { 1317 if (moveFlag) 1318 if(!Tools.showConfirm(shell, "Delete object", "Do you want to delete all the selected object(s) instead of move?")) 1319 return; 1320 moveFlag = false; 1321 currentSelectionsForMove = null; 1322 objectsToCopy = tree.getSelection(); 1323 removeSelectedObjects(); 1324 } 1325 1326 /** Paste selected objects */ 1327 private void pasteObject() { 1328 if (moveFlag) { 1329 HObject theObj = null; 1330 for (int i = 0; i < currentSelectionsForMove.length; i++) { 1331 TreeItem currentItem = currentSelectionsForMove[i]; 1332 theObj = (HObject) currentItem.getData(); 1333 1334 if (isObjectOpen(theObj)) { 1335 shell.getDisplay().beep(); 1336 Tools.showError(shell, "Move Objects", "Cannot move the selected object: " + theObj 1337 + "\nThe dataset or dataset in the group is in use." 1338 + "\n\nPlease close the dataset(s) and try again.\n"); 1339 1340 moveFlag = false; 1341 currentSelectionsForMove = null; 1342 objectsToCopy = null; 1343 return; 1344 } 1345 } 1346 } 1347 1348 TreeItem pitem = selectedItem; 1349 1350 if ((objectsToCopy == null) || (objectsToCopy.length <= 0) || (pitem == null)) 1351 return; 1352 1353 FileFormat srcFile = ((HObject) objectsToCopy[0].getData()).getFileFormat(); 1354 FileFormat dstFile = getSelectedFile(); 1355 FileFormat h5file = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5); 1356 FileFormat h4file = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4); 1357 FileFormat ncfile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3); 1358 1359 if (srcFile == null) { 1360 shell.getDisplay().beep(); 1361 Tools.showError(shell, "Copy", "Source file is null."); 1362 return; 1363 } 1364 else if (dstFile == null) { 1365 shell.getDisplay().beep(); 1366 Tools.showError(shell, "Copy", "Destination file is null."); 1367 return; 1368 } 1369 else if (srcFile.isThisType(h4file) && dstFile.isThisType(h5file)) { 1370 shell.getDisplay().beep(); 1371 Tools.showError(shell, "Copy", "Unsupported operation: cannot copy HDF4 object to HDF5 file"); 1372 return; 1373 } 1374 else if (srcFile.isThisType(h5file) && dstFile.isThisType(h4file)) { 1375 shell.getDisplay().beep(); 1376 Tools.showError(shell, "Copy", "Unsupported operation: cannot copy HDF5 object to HDF4 file"); 1377 return; 1378 } 1379 else if (srcFile.isThisType(ncfile) && dstFile.isThisType(ncfile)) { 1380 shell.getDisplay().beep(); 1381 Tools.showError(shell, "Copy", "Unsupported operation: cannot copy NetCDF3 objects"); 1382 return; 1383 } 1384 1385 if (moveFlag) { 1386 if (srcFile != dstFile) { 1387 shell.getDisplay().beep(); 1388 Tools.showError(shell, "Move", "Cannot move the selected object to different file"); 1389 moveFlag = false; 1390 currentSelectionsForMove = null; 1391 objectsToCopy = null; 1392 return; 1393 } 1394 } 1395 1396 /* 1397 if (pitem.getParentItem() != null) { 1398 pitem = pitem.getParentItem(); 1399 }*/ 1400 1401 Group pgroup = (Group) pitem.getData(); 1402 String fullPath = pgroup.getPath() + pgroup.getName(); 1403 if (pgroup.isRoot()) { 1404 fullPath = HObject.SEPARATOR; 1405 } 1406 1407 String msg = ""; 1408 if (srcFile.isThisType(h4file)) 1409 msg = "WARNING: object can not be deleted after it is copied.\n\n"; 1410 1411 msg += "Do you want to copy the selected object(s) to \nGroup: " + fullPath + "\nFile: " 1412 + dstFile.getFilePath(); 1413 1414 if (moveFlag) { 1415 String moveMsg = "Do you want to move the selected object(s) to \nGroup: " + fullPath + "\nFile: " 1416 + dstFile.getFilePath(); 1417 if(!Tools.showConfirm(shell, "Move Object", moveMsg)) 1418 return; 1419 } 1420 else { 1421 if(!Tools.showConfirm(shell, "Copy object", msg)) 1422 return; 1423 } 1424 1425 pasteObject(objectsToCopy, pitem, dstFile); 1426 1427 if (moveFlag) { 1428 removeSelectedObjects(); 1429 moveFlag = false; 1430 currentSelectionsForMove = null; 1431 objectsToCopy = null; 1432 } 1433 } 1434 1435 /** Paste selected objects */ 1436 private void pasteObject(TreeItem[] objList, TreeItem pobj, FileFormat dstFile) { 1437 if ((objList == null) || (objList.length <= 0) || (pobj == null)) return; 1438 1439 FileFormat srcFile = ((HObject) objList[0].getData()).getFileFormat(); 1440 Group pgroup = (Group) pobj.getData(); 1441 1442 HObject theObj = null; 1443 for (int i = 0; i < objList.length; i++) { 1444 theObj = (HObject) objList[i].getData(); 1445 1446 if ((theObj instanceof Group) && ((Group) theObj).isRoot()) { 1447 shell.getDisplay().beep(); 1448 Tools.showError(shell, "Paste", "Unsupported operation: cannot copy the root group"); 1449 return; 1450 } 1451 1452 // Check if it creates infinite loop 1453 Group pg = pgroup; 1454 while (!pg.isRoot()) { 1455 if (theObj.equals(pg)) { 1456 shell.getDisplay().beep(); 1457 Tools.showError(shell, "Paste", "Unsupported operation: cannot copy a group to itself."); 1458 return; 1459 } 1460 pg = pg.getParent(); 1461 } 1462 1463 try { 1464 log.trace("pasteObject(...): dstFile.copy({}, {}, null)", theObj, pgroup); 1465 1466 HObject newObj = null; 1467 if((newObj = srcFile.copy(theObj, pgroup, null)) != null) { 1468 // Add the node to the tree 1469 TreeItem newItem = insertObject(newObj, pobj); 1470 1471 // If this is a group, add its first level child items 1472 if(newObj instanceof Group) { 1473 Iterator<HObject> children = ((Group) newObj).getMemberList().iterator(); 1474 while(children.hasNext()) 1475 insertObject(children.next(), newItem); 1476 } 1477 } 1478 } 1479 catch (Exception ex) { 1480 shell.getDisplay().beep(); 1481 Tools.showError(shell, "Paste", ex.getMessage()); 1482 } 1483 } // (int i = 0; i < objList.length; i++) 1484 } 1485 1486 /** 1487 * Rename the currently selected object. 1488 */ 1489 private void renameObject() { 1490 if (moveFlag) { 1491 if(!Tools.showConfirm(shell, "Rename object", "Do you want to rename all the selected object(s) instead of move?")) 1492 return; 1493 } 1494 moveFlag = false; 1495 currentSelectionsForMove = null; 1496 1497 if (selectedObject == null) 1498 return; 1499 1500 if ((selectedObject instanceof Group) && ((Group) selectedObject).isRoot()) { 1501 shell.getDisplay().beep(); 1502 Tools.showError(shell, "Rename", "Cannot rename the root."); 1503 return; 1504 } 1505 1506 boolean isH4 = selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4)); 1507 if (isH4) { 1508 shell.getDisplay().beep(); 1509 Tools.showError(shell, "Rename", "Cannot rename HDF4 object."); 1510 return; 1511 } 1512 1513 boolean isN3 = selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3)); 1514 if (isN3) { 1515 shell.getDisplay().beep(); 1516 Tools.showError(shell, "Rename", "Cannot rename NetCDF3 object."); 1517 return; 1518 } 1519 1520 String oldName = selectedObject.getName(); 1521 String newName = (new InputDialog(shell, "Rename Object", 1522 "Rename \"" + oldName + "\" to:", oldName)).open(); 1523 1524 if (newName == null) 1525 return; 1526 1527 newName = newName.trim(); 1528 if ((newName == null) || (newName.length() == 0) || newName.equals(oldName)) 1529 return; 1530 1531 try { 1532 selectedObject.setName(newName); 1533 } 1534 catch (Exception ex) { 1535 shell.getDisplay().beep(); 1536 Tools.showError(shell, "Rename Object", ex.getMessage()); 1537 } 1538 1539 selectedItem.setText(newName); 1540 } 1541 1542 private void removeSelectedObjects() { 1543 FileFormat theFile = getSelectedFile(); 1544 if (theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4))) { 1545 shell.getDisplay().beep(); 1546 Tools.showError(shell, "Remove object", "Unsupported operation: cannot delete HDF4 object."); 1547 return; 1548 } 1549 if (theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3))) { 1550 shell.getDisplay().beep(); 1551 Tools.showError(shell, "Remove object", "Unsupported operation: cannot delete NetCDF3 object."); 1552 return; 1553 } 1554 1555 TreeItem[] currentSelections = tree.getSelection(); 1556 1557 if (moveFlag) 1558 currentSelections = currentSelectionsForMove; 1559 if ((currentSelections == null) || (currentSelections.length <= 0)) 1560 return; 1561 1562 if (!moveFlag) { 1563 if(!Tools.showConfirm(shell, "Remove object", "Do you want to remove all the selected object(s) ?")) 1564 return; 1565 } 1566 1567 HObject theObj = null; 1568 for (int i = 0; i < currentSelections.length; i++) { 1569 TreeItem currentItem = currentSelections[i]; 1570 theObj = (HObject) currentItem.getData(); 1571 1572 // Cannot delete a root object 1573 if (theObj instanceof Group && ((Group) theObj).isRoot()) { 1574 shell.getDisplay().beep(); 1575 Tools.showError(shell, "Delete Objects", "Unsupported operation: cannot delete the file root."); 1576 return; 1577 } 1578 1579 if (!moveFlag) { 1580 if (isObjectOpen(theObj)) { 1581 shell.getDisplay().beep(); 1582 Tools.showError(shell, "Delete Objects", "Cannot delete the selected object: " + theObj 1583 + "\nThe dataset or dataset in the group is in use." 1584 + "\n\nPlease close the dataset(s) and try again.\n"); 1585 continue; 1586 } 1587 } 1588 1589 try { 1590 theFile.delete(theObj); 1591 } 1592 catch (Exception ex) { 1593 shell.getDisplay().beep(); 1594 Tools.showError(shell, "Delete Objects", ex.getMessage()); 1595 continue; 1596 } 1597 1598 // When a TreeItem is disposed, it should be removed from its parent 1599 // items member list to prevent a bug when copying and deleting 1600 // groups/datasets 1601 ((Group) currentItem.getParentItem().getData()).removeFromMemberList(theObj); 1602 1603 if (currentItem.equals(selectedItem)) { 1604 selectedItem = null; 1605 selectedObject = null; 1606 selectedFile = null; 1607 } 1608 1609 currentItem.dispose(); 1610 } // (int i=0; i < currentSelections.length; i++) 1611 } 1612 1613 /** 1614 * Populates the TreeView with TreeItems corresponding to 1615 * the top-level user objects in the specified file. The rest 1616 * of the user objects in the file are populated as TreeItems 1617 * on demand when the user expands groups. 1618 * 1619 * @return the root TreeItem created in the Tree corresponding 1620 * to the file object. 1621 */ 1622 private TreeItem populateTree(FileFormat theFile) { 1623 if (theFile == null) { 1624 shell.getDisplay().beep(); 1625 Tools.showError(shell, "Open File", "Error opening file"); 1626 log.debug("Error populating tree, File object was null."); 1627 return null; 1628 } 1629 else if ((theFile.getFID() < 0) || (theFile.getRootObject() == null)) { 1630 if (theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3))) { 1631 log.trace("populateTree(): FileID={} Null Root={}", theFile.getFID(), (theFile.getRootObject() == null)); 1632 } 1633 //TODO: Update FitsFile and NC2File to have a fid other than -1 1634 // so this check isn't needed 1635 if (theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4)) || 1636 //theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3)) || 1637 theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) { 1638 shell.getDisplay().beep(); 1639 Tools.showError(shell, "Open File", "Error opening file " + theFile.getName()); 1640 log.debug("Error populating tree for {}, File ID was wrong or File root object was null.", theFile.getFilePath()); 1641 return null; 1642 } 1643 } 1644 1645 TreeItem rootItem = null; 1646 1647 try { 1648 rootItem = insertObject(theFile.getRootObject(), null); 1649 if (rootItem != null) { 1650 Iterator<HObject> it = ((Group) rootItem.getData()).getMemberList().iterator(); 1651 while (it.hasNext()) { 1652 TreeItem newItem = null; 1653 HObject obj = it.next(); 1654 1655 newItem = insertObject(obj, rootItem); 1656 1657 // Tell SWT how many members this group has so they can 1658 // be populated when the group is expanded 1659 if (obj instanceof Group) { 1660 newItem.setItemCount(((Group) obj).getMemberList().size()); 1661 log.debug("populateTree(): group members size {}:", ((Group) obj).getMemberList().size()); 1662 } 1663 } 1664 } 1665 } 1666 catch (Exception ex) { 1667 log.debug("populateTree(): Error populating Tree with members of file {}:", theFile.getFilePath(), ex); 1668 if (rootItem != null) 1669 rootItem.dispose(); 1670 shell.getDisplay().beep(); 1671 Tools.showError(shell, "Open File", "Error opening file " + theFile.getName() + "\n\n" + ex.getMessage()); 1672 return null; 1673 } 1674 1675 return rootItem; 1676 } 1677 1678 /** 1679 * Recursively expand/collapse a given selected TreeItem. 1680 * 1681 * @param item the selected tree item 1682 * @param expand 1683 * Expands the TreeItem and its children if true. 1684 * Collapse the TreeItem and its children if false. 1685 */ 1686 //TODO: some groups dont get expanded right, likely due to SetData not being 1687 // able to catch up with a large number of expanding 1688 private void recursiveExpand(TreeItem item, boolean expand) { 1689 if(item == null || !(item.getData() instanceof Group)) 1690 return; 1691 1692 TreeItem[] toExpand = item.getItems(); 1693 1694 item.setExpanded(expand); 1695 1696 // Make sure the TreeItem's icon gets set appropriately by 1697 // notifying its Expand or Collapse listener 1698 Event event = new Event(); 1699 event.item = item; 1700 tree.notifyListeners(expand ? SWT.Expand : SWT.Collapse, event); 1701 1702 // All SetData events for this group must be processed before any 1703 // child groups can be expanded, otherwise their data will be 1704 // null 1705 while(tree.getDisplay().readAndDispatch()); 1706 1707 for(int i = 0; i < toExpand.length; i++) 1708 recursiveExpand(toExpand[i], expand); 1709 } 1710 1711 /** 1712 * Gets the Image to set on the TreeItem for the specified HObject, 1713 * based on the type of HObject it is. 1714 * 1715 * @param obj 1716 * 1717 * @return the image for the specified HObject 1718 */ 1719 private Image getObjectTypeImage(HObject obj) { 1720 if (obj == null) 1721 return null; 1722 1723 // Should be safe to cast to a MetaDataContainer here because the 1724 // TreeView should never be able to select an object that does 1725 // not implement the MetaDataContainer interface 1726 boolean hasAttribute = ((MetaDataContainer) obj).hasAttribute(); 1727 1728 if(obj instanceof Dataset) { 1729 if (obj instanceof ScalarDS) { 1730 ScalarDS sd = (ScalarDS) obj; 1731 Datatype dt = sd.getDatatype(); 1732 1733 if (sd.isImage()) { 1734 if (hasAttribute) 1735 return imageIconA; 1736 else 1737 return imageIcon; 1738 } 1739 else if ((dt != null) && dt.isText()) { 1740 if (hasAttribute) 1741 return textIconA; 1742 else 1743 return textIcon; 1744 } 1745 else { 1746 if (hasAttribute) 1747 return datasetIconA; 1748 else 1749 return datasetIcon; 1750 } 1751 } 1752 else if (obj instanceof CompoundDS) { 1753 if (hasAttribute) 1754 return tableIconA; 1755 else 1756 return tableIcon; 1757 } 1758 } 1759 else if(obj instanceof Group) { 1760 if(((Group) obj).isRoot()) { 1761 FileFormat theFile = obj.getFileFormat(); 1762 1763 if(theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3))) { 1764 if(theFile.isReadOnly()) 1765 return nc3IconR; 1766 else 1767 return nc3Icon; 1768 } 1769 else if(theFile.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4))) { 1770 if(theFile.isReadOnly()) 1771 return h4IconR; 1772 else 1773 return h4Icon; 1774 } 1775 else { 1776 if(theFile.isReadOnly()) 1777 return h5IconR; 1778 else 1779 return h5Icon; 1780 } 1781 } 1782 else { 1783 if(hasAttribute) 1784 return folderCloseIconA; 1785 else 1786 return folderCloseIcon; 1787 } 1788 } 1789 else if(obj instanceof Datatype) { 1790 if(hasAttribute) 1791 return datatypeIconA; 1792 else 1793 return datatypeIcon; 1794 } 1795 1796 return questionIcon; 1797 } 1798 1799 /** 1800 * Checks if a file is already open. 1801 * 1802 * @param filename the file to query 1803 * 1804 * @return true if the file is open 1805 */ 1806 private boolean isFileOpen(String filename) { 1807 boolean isOpen = false; 1808 1809 // Find the file by matching its file name from the list of open files 1810 FileFormat theFile = null; 1811 Iterator<FileFormat> iterator = fileList.iterator(); 1812 while (iterator.hasNext()) { 1813 theFile = iterator.next(); 1814 if (theFile.getFilePath().equals(filename)) { 1815 isOpen = true; 1816 break; 1817 } 1818 } 1819 1820 return isOpen; 1821 } 1822 1823 /** 1824 * Checks if an object is already open. 1825 */ 1826 private boolean isObjectOpen(HObject obj) { 1827 boolean isOpen = false; 1828 1829 if (obj instanceof Group) { 1830 Group g = (Group) obj; 1831 List<?> members = g.getMemberList(); 1832 if ((members == null) || members.isEmpty()) { 1833 return false; 1834 } 1835 else { 1836 int n = members.size(); 1837 for (int i = 0; i < n; i++) { 1838 HObject theObj = (HObject) members.get(i); 1839 isOpen = (viewer.getDataView(theObj) != null); 1840 if (isOpen) 1841 break; 1842 } 1843 } 1844 } 1845 else { 1846 return (viewer.getDataView(obj) != null); 1847 } 1848 1849 return isOpen; 1850 } 1851 1852 /** 1853 * Returns a list that lists all TreeItems in the 1854 * current Tree that are children of the specified 1855 * TreeItem in a breadth-first manner. 1856 * 1857 * @param the current Tree item 1858 * 1859 * @return list of TreeItems 1860 */ 1861 private ArrayList<TreeItem> getItemsBreadthFirst(TreeItem item) { 1862 if (item == null) 1863 return null; 1864 1865 ArrayList<TreeItem> allItems = new ArrayList<>(); 1866 Queue<TreeItem> currentChildren = new LinkedList<>(); 1867 TreeItem currentItem = item; 1868 1869 // Add all root items in the Tree to a Queue 1870 currentChildren.addAll(Arrays.asList(currentItem.getItems())); 1871 1872 // For every item in the queue, remove it from the head of the queue, 1873 // add it to the list of all items, then add all of its possible children 1874 // TreeItems to the end of the queue. This produces a breadth-first 1875 // ordering of the Tree's TreeItems. 1876 while(!currentChildren.isEmpty()) { 1877 currentItem = currentChildren.remove(); 1878 allItems.add(currentItem); 1879 1880 if(currentItem.getItemCount() <= 0) 1881 continue; 1882 1883 currentChildren.addAll(Arrays.asList(currentItem.getItems())); 1884 } 1885 1886 return allItems; 1887 } 1888 1889 /** 1890 * Returns a list of all user objects that traverses the subtree rooted at 1891 * this item in breadth-first order.. 1892 * 1893 * @param item 1894 * the item to start with. 1895 */ 1896 private final List<Object> breadthFirstUserObjects(TreeItem item) { 1897 if (item == null) return null; 1898 1899 ArrayList<Object> list = new ArrayList<>(); 1900 list.add(item.getData()); // Add this item to the list first 1901 1902 Iterator<TreeItem> it = getItemsBreadthFirst(item).iterator(); 1903 TreeItem theItem = null; 1904 1905 while (it.hasNext()) { 1906 theItem = it.next(); 1907 list.add(theItem.getData()); 1908 } 1909 1910 return list; 1911 } 1912 1913 /** 1914 * Find first object that is matched by name under the specified 1915 * TreeItem. 1916 * 1917 * @param objName 1918 * -- the object name. 1919 * @return the object if found, otherwise, returns null. 1920 */ 1921 private final HObject find(String objName, TreeItem parentItem) { 1922 if (objName == null || objName.length() <= 0 || parentItem == null) return null; 1923 1924 HObject retObj = null; 1925 boolean isFound = false; 1926 boolean isPrefix = false; 1927 boolean isSuffix = false; 1928 boolean isContain = false; 1929 1930 if (objName.equals("*")) 1931 return null; 1932 1933 if (objName.startsWith("*")) { 1934 isSuffix = true; 1935 objName = objName.substring(1, objName.length()); 1936 } 1937 1938 if (objName.endsWith("*")) { 1939 isPrefix = true; 1940 objName = objName.substring(0, objName.length() - 1); 1941 } 1942 1943 if (isPrefix && isSuffix) { 1944 isContain = true; 1945 isPrefix = isSuffix = false; 1946 } 1947 1948 if (objName == null || objName.length() <= 0) 1949 return null; 1950 1951 HObject obj = null; 1952 String theName = null; 1953 TreeItem theItem = null; 1954 Iterator<TreeItem> it = getItemsBreadthFirst(parentItem).iterator(); 1955 while (it.hasNext()) { 1956 theItem = it.next(); 1957 obj = (HObject) theItem.getData(); 1958 if (obj != null && (theName = obj.getName()) != null) { 1959 if (isPrefix) 1960 isFound = theName.startsWith(objName); 1961 else if (isSuffix) 1962 isFound = theName.endsWith(objName); 1963 else if (isContain) 1964 isFound = theName.contains(objName); 1965 else 1966 isFound = theName.equals(objName); 1967 1968 if (isFound) { 1969 retObj = obj; 1970 break; 1971 } 1972 } 1973 } 1974 1975 if (retObj != null) { 1976 tree.deselectAll(); 1977 tree.setSelection(theItem); 1978 tree.showItem(theItem); 1979 } 1980 1981 return retObj; 1982 } 1983 1984 /** 1985 * Save the current file into a new HDF4 file. Since HDF4 does not 1986 * support packing, the source file is copied into the new file with 1987 * the exact same content. 1988 */ 1989 private final void saveAsHDF4(FileFormat srcFile) { 1990 if (srcFile == null) { 1991 shell.getDisplay().beep(); 1992 Tools.showError(shell, "Save", "Select a file to save."); 1993 return; 1994 } 1995 1996 HObject root = srcFile.getRootObject(); 1997 if (root == null) { 1998 shell.getDisplay().beep(); 1999 Tools.showError(shell, "Save", "The file is empty."); 2000 return; 2001 } 2002 2003 String currentDir = srcFile.getParent(); 2004 2005 if (currentDir != null) 2006 currentDir += File.separator; 2007 else 2008 currentDir = ""; 2009 2010 String filename = null; 2011 if (((HDFView) viewer).getTestState()) { 2012 filename = currentDir + File.separator + new InputDialog(shell, "Enter a file name", "").open(); 2013 } 2014 else { 2015 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 2016 fChooser.setFileName(Tools.checkNewFile(currentDir, ".hdf").getName()); 2017 2018 DefaultFileFilter filter = DefaultFileFilter.getFileFilterHDF4(); 2019 fChooser.setFilterExtensions(new String[] {filter.getExtensions()}); 2020 fChooser.setFilterNames(new String[] {filter.getDescription()}); 2021 fChooser.setFilterIndex(0); 2022 2023 filename = fChooser.open(); 2024 } 2025 if(filename == null) 2026 return; 2027 2028 try { 2029 Tools.createNewFile(filename, currentDir, FileFormat.FILE_TYPE_HDF4, fileList); 2030 } 2031 catch (Exception ex) { 2032 Tools.showError(shell, "Save", ex.getMessage()); 2033 } 2034 2035 // Since cannot pack hdf4, simply copy the whole physical file 2036 int length = 0; 2037 int bsize = 512; 2038 byte[] buffer; 2039 2040 try (BufferedInputStream bi = new BufferedInputStream(new FileInputStream(srcFile.getFilePath()))) { 2041 try (BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(filename))) { 2042 buffer = new byte[bsize]; 2043 try { 2044 length = bi.read(buffer, 0, bsize); 2045 } 2046 catch (Exception ex) { 2047 length = 0; 2048 } 2049 while (length > 0) { 2050 try { 2051 bo.write(buffer, 0, length); 2052 length = bi.read(buffer, 0, bsize); 2053 } 2054 catch (Exception ex) { 2055 length = 0; 2056 } 2057 } 2058 2059 try { 2060 bo.flush(); 2061 } 2062 catch (Exception ex) { 2063 log.debug("Output file:", ex); 2064 } 2065 } 2066 catch (Exception ex) { 2067 shell.getDisplay().beep(); 2068 Tools.showError(shell, "Save", ex.getMessage()); 2069 return; 2070 } 2071 } 2072 catch (Exception ex) { 2073 shell.getDisplay().beep(); 2074 Tools.showError(shell, "Save", ex.getMessage() + "\n" + filename); 2075 return; 2076 } 2077 2078 try { 2079 openFile(filename, FileFormat.WRITE); 2080 } 2081 catch (Exception ex) { 2082 shell.getDisplay().beep(); 2083 Tools.showError(shell, "Save", ex.getMessage() + "\n" + filename); 2084 } 2085 } 2086 2087 /** 2088 * Copy the current file into a new HDF5 file. The new file does not include the 2089 * inaccessible objects. Values of reference dataset are not updated in the 2090 * new file. 2091 */ 2092 private void saveAsHDF5(FileFormat srcFile) { 2093 if (srcFile == null) { 2094 shell.getDisplay().beep(); 2095 Tools.showError(shell, "Save", "Select a file to save."); 2096 return; 2097 } 2098 2099 HObject root = srcFile.getRootObject(); 2100 if (root == null) { 2101 shell.getDisplay().beep(); 2102 Tools.showError(shell, "Save", "The file is empty."); 2103 return; 2104 } 2105 2106 String currentDir = srcFile.getParent(); 2107 2108 if (currentDir != null) 2109 currentDir += File.separator; 2110 else 2111 currentDir = ""; 2112 2113 String filename = null; 2114 if (((HDFView) viewer).getTestState()) { 2115 filename = currentDir + File.separator + new InputDialog(shell, "Enter a file name", "").open(); 2116 } 2117 else { 2118 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 2119 fChooser.setFileName(Tools.checkNewFile(currentDir, ".h5").getName()); 2120 2121 DefaultFileFilter filter = DefaultFileFilter.getFileFilterHDF5(); 2122 fChooser.setFilterExtensions(new String[] {filter.getExtensions()}); 2123 fChooser.setFilterNames(new String[] {filter.getDescription()}); 2124 fChooser.setFilterIndex(0); 2125 2126 filename = fChooser.open(); 2127 } 2128 if(filename == null) 2129 return; 2130 2131 try { 2132 Tools.createNewFile(filename, currentDir, FileFormat.FILE_TYPE_HDF5, fileList); 2133 } 2134 catch (Exception ex) { 2135 Tools.showError(shell, "Save", ex.getMessage()); 2136 } 2137 2138 TreeItem rootItem = findTreeItem(root); 2139 int n = rootItem.getItemCount(); 2140 ArrayList<TreeItem> objList = new ArrayList<>(n); 2141 2142 try { 2143 for (int i = 0; i < n; i++) objList.add(rootItem.getItem(i)); 2144 } 2145 catch (Exception ex) { 2146 log.debug("saveAsHDF5() objList add failure: ", ex); 2147 } 2148 2149 FileFormat newFile = null; 2150 try { 2151 newFile = openFile(filename, FileFormat.WRITE); 2152 } 2153 catch (Exception ex) { 2154 shell.getDisplay().beep(); 2155 Tools.showError(shell, "Save", ex.getMessage() + "\n" + filename); 2156 return; 2157 } 2158 2159 if (newFile == null) 2160 return; 2161 2162 HObject pitem = newFile.getRootObject(); 2163 2164 pasteObject(objList.toArray(new TreeItem[0]), findTreeItem(pitem), newFile); 2165 objList.clear(); 2166 2167 Group srcGroup = (Group) root; 2168 Group dstGroup = (Group) newFile.getRootObject(); 2169 Object[] parameter = new Object[2]; 2170 Class<?> classHOjbect = null; 2171 Class<?>[] parameterClass = new Class[2]; 2172 Method method = null; 2173 2174 // Copy attributes of the root group 2175 try { 2176 parameter[0] = srcGroup; 2177 parameter[1] = dstGroup; 2178 classHOjbect = Class.forName("hdf.object.HObject"); 2179 parameterClass[0] = parameterClass[1] = classHOjbect; 2180 method = newFile.getClass().getMethod("copyAttributes", parameterClass); 2181 method.invoke(newFile, parameter); 2182 } 2183 catch (Exception ex) { 2184 shell.getDisplay().beep(); 2185 Tools.showError(shell, "Save", ex.getMessage()); 2186 } 2187 2188 // Update reference datasets 2189 parameter[0] = srcGroup.getFileFormat(); 2190 parameter[1] = newFile; 2191 parameterClass[0] = parameterClass[1] = parameter[0].getClass(); 2192 try { 2193 method = newFile.getClass().getMethod("updateReferenceDataset", parameterClass); 2194 method.invoke(newFile, parameter); 2195 } 2196 catch (Exception ex) { 2197 shell.getDisplay().beep(); 2198 Tools.showError(shell, "Save", ex.getMessage()); 2199 } 2200 } 2201 2202 /** Save data as file. 2203 * 2204 * @throws Exception if a failure occurred 2205 */ 2206 private void saveDataAsFile() throws Exception { 2207 if (!(selectedObject instanceof Dataset) || (selectedObject == null) || (selectedItem == null)) 2208 return; 2209 2210 File chosenFile = null; 2211 String filename = null; 2212 Dataset dataset = (Dataset) selectedObject; 2213 String currentDir = dataset.getFile().substring(0, dataset.getFile().lastIndexOf(File.separator)); 2214 String msgtext = null; 2215 if(binaryOrder == 99) 2216 msgtext = "Save Dataset Data To Text File --- " + dataset.getName(); 2217 else 2218 msgtext = "Save Current Data To Binary File --- " + dataset.getName(); 2219 if (((HDFView) viewer).getTestState()) { 2220 filename = currentDir + File.separator + new InputDialog(shell, msgtext, "").open(); 2221 } 2222 else { 2223 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 2224 fChooser.setFilterPath(currentDir); 2225 2226 DefaultFileFilter filter = null; 2227 2228 if (binaryOrder == 99) { 2229 fChooser.setText(msgtext); 2230 fChooser.setFileName(dataset.getName() + ".txt"); 2231 filter = DefaultFileFilter.getFileFilterText(); 2232 } 2233 else { 2234 fChooser.setText(msgtext); 2235 fChooser.setFileName(dataset.getName() + ".bin"); 2236 filter = DefaultFileFilter.getFileFilterBinary(); 2237 } 2238 2239 fChooser.setFilterExtensions(new String[] {"*", filter.getExtensions()}); 2240 fChooser.setFilterNames(new String[] {"All Files", filter.getDescription()}); 2241 fChooser.setFilterIndex(1); 2242 2243 filename = fChooser.open(); 2244 } 2245 if(filename == null) 2246 return; 2247 2248 // Check if the file is in use 2249 List<?> saveFileList = viewer.getTreeView().getCurrentFiles(); 2250 if (saveFileList != null) { 2251 FileFormat theFile = null; 2252 Iterator<?> iterator = saveFileList.iterator(); 2253 while (iterator.hasNext()) { 2254 theFile = (FileFormat) iterator.next(); 2255 if (theFile.getFilePath().equals(filename)) { 2256 shell.getDisplay().beep(); 2257 Tools.showError(shell, "Export Dataset", "Unable to save data to file \"" + filename + "\". \nThe file is being used."); 2258 return; 2259 } 2260 } 2261 } 2262 2263 chosenFile = new File(filename); 2264 2265 if (chosenFile.exists()) { 2266 if(!Tools.showConfirm(shell, "Export Dataset", "File exists. Do you want to replace it?")) 2267 return; 2268 } 2269 2270 boolean isH4 = selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4)); 2271 if (isH4) { 2272 shell.getDisplay().beep(); 2273 Tools.showError(shell, "Save", "Cannot export HDF4 object."); 2274 return; 2275 } 2276 2277 boolean isN3 = selectedObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3)); 2278 if (isN3) { 2279 shell.getDisplay().beep(); 2280 Tools.showError(shell, "Save", "Cannot export netCDF3 object."); 2281 return; 2282 } 2283 2284 try { 2285 selectedObject.getFileFormat().exportDataset(filename, dataset, binaryOrder); 2286 viewer.showStatus("Data saved to: " + filename); 2287 } 2288 catch (Exception ex) { 2289 shell.getDisplay().beep(); 2290 Tools.showError(shell, "Save", "Unable to export dataset: " + ex.getMessage()); 2291 } 2292 } 2293 2294 /** enable/disable GUI components */ 2295 private static void setEnabled(List<MenuItem> list, boolean b) { 2296 if (list == null) 2297 return; 2298 2299 Iterator<MenuItem> it = list.iterator(); 2300 while (it.hasNext()) 2301 it.next().setEnabled(b); 2302 } 2303 2304 /** 2305 * Opens a file and retrieves the file structure of the file. It also can be 2306 * used to create a new file by setting the accessID to FileFormat.CREATE. 2307 * 2308 * Subclasses must implement this function to take appropriate steps to open 2309 * a file. 2310 * 2311 * @param filename 2312 * the name of the file to open. 2313 * @param accessID 2314 * identifier for the file access. Valid value of accessID is: 2315 * <ul> 2316 * <li>FileFormat.READ --- allow read-only access to file.</li> 2317 * <li>FileFormat.WRITE --- allow read and write access to file.</li> 2318 * <li>FileFormat.CREATE --- create a new file.</li> 2319 * </ul> 2320 * 2321 * @return the FileFormat of this file if successful; otherwise returns null. 2322 * 2323 * @throws Exception if a failure occurred 2324 */ 2325 @Override 2326 public FileFormat openFile(String filename, int accessID) throws Exception { 2327 log.trace("openFile: {},{}", filename, accessID); 2328 FileFormat fileFormat = null; 2329 boolean isNewFile = (FileFormat.OPEN_NEW == (accessID & FileFormat.OPEN_NEW)); 2330 if (isNewFile) 2331 accessID = accessID - FileFormat.OPEN_NEW; 2332 2333 if (isFileOpen(filename)) { 2334 viewer.showStatus("File is in use."); 2335 return null; 2336 } 2337 2338 File tmpFile = new File(filename); 2339 if (!tmpFile.exists()) 2340 throw new FileNotFoundException("File does not exist."); 2341 2342 if (!tmpFile.canWrite()) 2343 accessID = FileFormat.READ; 2344 2345 Enumeration<?> keys = FileFormat.getFileFormatKeys(); 2346 2347 String theKey = null; 2348 while (keys.hasMoreElements()) { 2349 theKey = (String) keys.nextElement(); 2350 if (theKey.equals(FileFormat.FILE_TYPE_HDF4)) { 2351 log.trace("openFile: {} FILE_TYPE_HDF4", filename); 2352 try { 2353 FileFormat h4format = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4); 2354 if ((h4format != null) && h4format.isThisType(filename)) { 2355 fileFormat = h4format.createInstance(filename, accessID); 2356 break; 2357 } 2358 } 2359 catch (UnsatisfiedLinkError e) { 2360 log.debug("openFile({}): HDF4 library link error:", filename, e); 2361 viewer.showError("Unable to open file '" + filename + "': HDF4 library linking error"); 2362 } 2363 catch (Exception err) { 2364 log.debug("openFile: Error retrieving the file structure of {}:", filename, err); 2365 } 2366 continue; 2367 } 2368 else if (theKey.equals(FileFormat.FILE_TYPE_HDF5)) { 2369 log.trace("openFile: {} FILE_TYPE_HDF5", filename); 2370 try { 2371 FileFormat h5format = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5); 2372 if ((h5format != null) && h5format.isThisType(filename)) { 2373 fileFormat = h5format.createInstance(filename, accessID); 2374 break; 2375 } 2376 } 2377 catch (UnsatisfiedLinkError e) { 2378 log.debug("openFile({}): HDF5 library link error:", filename, e); 2379 viewer.showError("Unable to open file '" + filename + "': HDF5 library linking error"); 2380 } 2381 catch (Exception err) { 2382 log.debug("openFile: Error retrieving the file structure of {}:", filename, err); 2383 } 2384 continue; 2385 } 2386 else if (theKey.equals(FileFormat.FILE_TYPE_NC3)) { 2387 log.trace("openFile: {} FILE_TYPE_NC3", filename); 2388 try { 2389 FileFormat nc3format = FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3); 2390 if ((nc3format != null) && nc3format.isThisType(filename)) { 2391 fileFormat = nc3format.createInstance(filename, accessID); 2392 break; 2393 } 2394 } 2395 catch (UnsatisfiedLinkError e) { 2396 log.debug("openFile({}): NetCDF3 library link error:", filename, e); 2397 viewer.showError("Unable to open file '" + filename + "': NetCDF3 library linking error"); 2398 } 2399 catch (Exception err) { 2400 log.debug("openFile: Error retrieving the file structure of {}:", filename, err); 2401 } 2402 continue; 2403 } 2404 else { 2405 log.trace("openFile: {} Other", filename); 2406 try { 2407 FileFormat theformat = FileFormat.getFileFormat(theKey); 2408 if (theformat.isThisType(filename)) { 2409 fileFormat = theformat.createInstance(filename, accessID); 2410 break; 2411 } 2412 } 2413 catch (Exception err) { 2414 log.debug("openFile: Error retrieving the file structure of {}:", filename, err); 2415 } 2416 } 2417 } 2418 2419 if (fileFormat == null) 2420 throw new java.io.IOException("Unsupported fileformat - " + filename); 2421 2422 if (fileFormat.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) { 2423 if (tempIdxType >= 0) { 2424 fileFormat.setIndexType(tempIdxType); 2425 2426 // Reset the temporary index type 2427 tempIdxType = -1; 2428 } 2429 else 2430 fileFormat.setIndexType(fileFormat.getIndexType(ViewProperties.getIndexType())); 2431 2432 if (tempIdxOrder >= 0) { 2433 fileFormat.setIndexOrder(tempIdxOrder); 2434 2435 // Reset the temporary index order 2436 tempIdxOrder = -1; 2437 } 2438 else 2439 fileFormat.setIndexOrder(fileFormat.getIndexOrder(ViewProperties.getIndexOrder())); 2440 } 2441 2442 return initFile(fileFormat); 2443 } 2444 2445 /** 2446 * Initializes a FileFormat object by opening it and populating the file tree structure. 2447 * 2448 * @param fileFormat 2449 * the file to open with an existing FileFormat instance. 2450 * 2451 * @return the initialized FileFormat of this file if successful; otherwise returns null. 2452 * 2453 * @throws Exception 2454 * if a failure occurred 2455 */ 2456 private FileFormat initFile(FileFormat fileFormat) throws Exception { 2457 log.trace("initFile[{}] - start", fileFormat.getAbsolutePath()); 2458 2459 TreeItem fileRoot = null; 2460 2461 shell.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_WAIT)); 2462 2463 try { 2464 fileFormat.setMaxMembers(ViewProperties.getMaxMembers()); 2465 fileFormat.setStartMembers(ViewProperties.getStartMembers()); 2466 2467 fileFormat.open(); 2468 2469 fileRoot = populateTree(fileFormat); 2470 2471 if (fileRoot != null) { 2472 /* Expand top level items of root object */ 2473 int currentRowCount = tree.getItemCount(); 2474 if (currentRowCount > 0) 2475 tree.getItem(currentRowCount - 1).setExpanded(true); 2476 2477 fileList.add(fileFormat); 2478 } 2479 2480 tree.setItemCount(fileList.size()); 2481 2482 log.trace("initFile[{}] - fileList items={}", fileFormat.getAbsolutePath(), fileList.size()); 2483 } 2484 catch (Exception ex) { 2485 log.debug("initFile: FileFormat init error:", ex); 2486 fileFormat = null; 2487 } 2488 finally { 2489 shell.setCursor(null); 2490 } 2491 2492 return fileFormat; 2493 } 2494 2495 @Override 2496 public FileFormat reopenFile(FileFormat fileFormat, int newFileAccessMode) throws Exception { 2497 String fileFormatName = fileFormat.getAbsolutePath(); 2498 2499 // Make sure to reload the file using the file's current indexing options 2500 tempIdxType = fileFormat.getIndexType(null); 2501 tempIdxOrder = fileFormat.getIndexOrder(null); 2502 2503 closeFile(fileFormat); 2504 ((HDFView) viewer).showMetaData(null); 2505 2506 if (newFileAccessMode < 0) { 2507 if (ViewProperties.isReadOnly()) 2508 return openFile(fileFormatName, FileFormat.READ); 2509 else 2510 return openFile(fileFormatName, FileFormat.WRITE); 2511 } 2512 else 2513 return openFile(fileFormatName, newFileAccessMode); 2514 } 2515 2516 /** 2517 * Close a file 2518 * 2519 * @param file 2520 * the file to close 2521 * 2522 * @throws Exception if a failure occurred 2523 */ 2524 @Override 2525 public void closeFile(FileFormat file) throws Exception { 2526 if (file == null) return; 2527 2528 // Find the file item in the tree and remove it 2529 FileFormat theFile = null; 2530 TreeItem[] openFiles = tree.getItems(); // Returns the top-level items of the tree 2531 2532 for (int i = 0; i < openFiles.length; i++) { 2533 theFile = ((Group) openFiles[i].getData()).getFileFormat(); 2534 2535 if (theFile.equals(file)) { 2536 // Remove TreeItem from the view 2537 openFiles[i].dispose(); 2538 log.trace("dispose({}):", theFile.getFilePath()); 2539 2540 try { 2541 theFile.close(); 2542 } 2543 catch (Exception ex) { 2544 log.debug("closeFile({}):", theFile.getFilePath(), ex); 2545 } 2546 2547 fileList.remove(theFile); 2548 if (theFile.equals(selectedFile)) { 2549 selectedFile = null; 2550 selectedObject = null; 2551 selectedItem = null; 2552 } 2553 2554 break; 2555 } 2556 } 2557 } 2558 2559 /** 2560 * Save a file 2561 * 2562 * @param file 2563 * the file to save 2564 * 2565 * @throws Exception if a failure occurred 2566 */ 2567 @Override 2568 public void saveFile(FileFormat file) throws Exception { 2569 if (file == null) { 2570 shell.getDisplay().beep(); 2571 Tools.showError(shell, "Save", "Select a file to save."); 2572 return; 2573 } 2574 2575 boolean isH4 = file.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4)); 2576 boolean isH5 = file.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)); 2577 2578 if (!(isH4 || isH5)) { 2579 shell.getDisplay().beep(); 2580 Tools.showError(shell, "Save", "Saving file is not supported for this file type"); 2581 return; 2582 } 2583 2584 // Write the change of the data into the file before saving the file 2585 ((HDFView) viewer).writeDataToFile(file); 2586 2587 if (isH5) 2588 saveAsHDF5(file); 2589 else if (isH4) 2590 saveAsHDF4(file); 2591 } 2592 2593 /** 2594 * Returns the tree item that contains the given data object. 2595 */ 2596 @Override 2597 public TreeItem findTreeItem(HObject obj) { 2598 if (obj == null) 2599 return null; 2600 2601 if (obj.getFileFormat().getRootObject() == null) 2602 return null; 2603 2604 // Locate the item's file root to save on search time in large files 2605 TreeItem[] fileRoots = tree.getItems(); 2606 TreeItem rootItem = null; 2607 HObject rootObject = null; 2608 for (int i = 0; i < fileRoots.length; i++) { 2609 rootItem = fileRoots[i]; 2610 rootObject = (HObject) rootItem.getData(); 2611 2612 if (rootObject == null) 2613 continue; 2614 2615 if (rootObject.getFileFormat().equals(obj.getFileFormat())) { 2616 // If the object being looked for is a file root, return 2617 // this found TreeItem 2618 if (obj instanceof Group && ((Group) obj).isRoot()) 2619 return rootItem; 2620 2621 // Else the file root for the object being looked for has 2622 // been found, continue the search through only this TreeItem's 2623 // members 2624 break; 2625 } 2626 } 2627 2628 TreeItem theItem = null; 2629 HObject theObj = null; 2630 List<TreeItem> breadthFirstItems = getItemsBreadthFirst(rootItem); 2631 2632 if (breadthFirstItems != null) { 2633 Iterator<TreeItem> it = getItemsBreadthFirst(rootItem).iterator(); 2634 2635 while (it.hasNext()) { 2636 theItem = it.next(); 2637 theObj = (HObject) theItem.getData(); 2638 2639 if (theObj == null) 2640 continue; 2641 2642 if (theObj.equals(obj)) 2643 return theItem; 2644 } 2645 } 2646 2647 return null; 2648 } 2649 2650 /** 2651 * change the display option. 2652 */ 2653 @Override 2654 public void setDefaultDisplayMode(boolean displaymode) { 2655 isDefaultDisplay = displaymode; 2656 } 2657 2658 /** 2659 * Gets the selected file. When multiple files are open, we need to know 2660 * which file is currently selected. 2661 * 2662 * @return the FileFormat of the currently selected file. 2663 */ 2664 @Override 2665 public FileFormat getSelectedFile() { 2666 return selectedFile; 2667 } 2668 2669 /** 2670 * @return the currently selected object in the tree. 2671 */ 2672 @Override 2673 public HObject getCurrentObject() { 2674 return selectedObject; 2675 } 2676 2677 /** 2678 * @return the Tree which holds the file structure. 2679 */ 2680 @Override 2681 public Tree getTree() { 2682 return tree; 2683 } 2684 2685 /** 2686 * @return the list of currently open files. 2687 */ 2688 @Override 2689 public List<FileFormat> getCurrentFiles() { 2690 return fileList; 2691 } 2692 2693 /** 2694 * Display the content of a data object. 2695 * 2696 * @param dataObject 2697 * the data object 2698 * 2699 * @return the DataView that displays the data content 2700 * 2701 * @throws Exception if a failure occurred 2702 */ 2703 @Override 2704 public DataView showDataContent(HObject dataObject) throws Exception { 2705 /* Can only display objects with data */ 2706 if ((dataObject == null) || !(dataObject instanceof DataFormat)) 2707 return null; 2708 2709 log.trace("showDataContent({}): start", dataObject.getName()); 2710 2711 /* Set up the default display properties passed to the DataView instance */ 2712 DataView theView = null; 2713 DataFormat d = (DataFormat) dataObject; 2714 HashMap<DATA_VIEW_KEY, Serializable> map = new HashMap<>(8); 2715 2716 if (!d.isInited()) 2717 d.init(); 2718 2719 boolean isImage = ((d instanceof ScalarDS) && ((ScalarDS) d).isImage()); 2720 boolean isDisplayTypeChar = false; 2721 boolean isTransposed = false; 2722 boolean isIndexBase1 = ViewProperties.isIndexBase1(); 2723 BitSet bitmask = null; 2724 String dataViewName = null; 2725 2726 if (isDefaultDisplay) { /* Displaying a data object using the default display options */ 2727 DataView existingView = viewer.getDataView((HObject) d); 2728 2729 /* 2730 * Check to make sure this data object isn't already opened in an existing 2731 * DataView. If it is, just bring that DataView to focus. 2732 */ 2733 if (existingView != null) { 2734 Shell[] shells = Display.getDefault().getShells(); 2735 2736 if (shells.length >= 1) { 2737 for (int i = 0; i < shells.length; i++) { 2738 DataView view = (DataView) shells[i].getData(); 2739 2740 if (view != null) { 2741 if (view.equals(existingView)) { 2742 shells[i].forceActive(); 2743 2744 log.trace("showDataContent(): found existing DataView for data object {}", dataObject.getName()); 2745 2746 return view; 2747 } 2748 } 2749 } 2750 } 2751 } 2752 } 2753 else { /* Open Dialog to allow user to choose different data display options */ 2754 DataOptionDialog dialog = new DataOptionDialog(shell, d); 2755 dialog.open(); 2756 2757 if (dialog.isCancelled()) 2758 return null; 2759 2760 isImage = dialog.isImageDisplay(); 2761 isDisplayTypeChar = dialog.isDisplayTypeChar(); 2762 dataViewName = dialog.getDataViewName(); 2763 isTransposed = dialog.isTransposed(); 2764 bitmask = dialog.getBitmask(); 2765 isIndexBase1 = dialog.isIndexBase1(); 2766 isApplyBitmaskOnly = dialog.isApplyBitmaskOnly(); 2767 } 2768 2769 map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dataObject); 2770 map.put(ViewProperties.DATA_VIEW_KEY.VIEW_NAME, dataViewName); 2771 map.put(ViewProperties.DATA_VIEW_KEY.CHAR, isDisplayTypeChar); 2772 map.put(ViewProperties.DATA_VIEW_KEY.TRANSPOSED, isTransposed); 2773 map.put(ViewProperties.DATA_VIEW_KEY.INDEXBASE1, isIndexBase1); 2774 map.put(ViewProperties.DATA_VIEW_KEY.BITMASK, bitmask); 2775 if (isApplyBitmaskOnly) 2776 map.put(ViewProperties.DATA_VIEW_KEY.BITMASKOP, ViewProperties.BITMASK_OP.AND); 2777 2778 log.trace( 2779 "showDataContent(): object={} dataViewName={} isDisplayTypeChar={} isTransposed={} isIndexBase1={} bitmask={}", 2780 dataObject, dataViewName, isDisplayTypeChar, isTransposed, isIndexBase1, bitmask); 2781 2782 shell.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_WAIT)); 2783 2784 if (isImage) { 2785 DataViewFactory imageViewFactory = null; 2786 try { 2787 imageViewFactory = DataViewFactoryProducer.getFactory(DataViewType.IMAGE); 2788 } 2789 catch (Exception ex) { 2790 log.debug("showDataContent(): error occurred while instantiating ImageView factory class", ex); 2791 viewer.showError("Error occurred while instantiating ImageView factory class"); 2792 return null; 2793 } 2794 2795 if (imageViewFactory == null) { 2796 log.debug("showDataContent(): ImageView factory is null"); 2797 return null; 2798 } 2799 2800 try { 2801 theView = imageViewFactory.getImageView(viewer, map); 2802 2803 if (theView == null) { 2804 log.debug("showDataContent(): error occurred while instantiating ImageView class"); 2805 viewer.showError("Error occurred while instantiating ImageView class"); 2806 Tools.showError(shell, "Show Data", "Error occurred while instantiating ImageView class"); 2807 } 2808 } 2809 catch (ClassNotFoundException ex) { 2810 log.debug("showDataContent(): no suitable ImageView class found"); 2811 viewer.showError("Unable to find suitable ImageView class for object '" + dataObject.getName() + "'"); 2812 Tools.showError(shell, "Show Data", "Unable to find suitable ImageView class for object '" + dataObject.getName() + "'"); 2813 theView = null; 2814 } 2815 } 2816 else { 2817 DataViewFactory tableViewFactory = null; 2818 try { 2819 tableViewFactory = DataViewFactoryProducer.getFactory(DataViewType.TABLE); 2820 } 2821 catch (Exception ex) { 2822 log.debug("showDataContent(): error occurred while instantiating TableView factory class", ex); 2823 viewer.showError("Error occurred while instantiating TableView factory class"); 2824 return null; 2825 } 2826 2827 if (tableViewFactory == null) { 2828 log.debug("showDataContent(): TableView factory is null"); 2829 return null; 2830 } 2831 2832 try { 2833 theView = tableViewFactory.getTableView(viewer, map); 2834 2835 if (theView == null) { 2836 log.debug("showDataContent(): error occurred while instantiating TableView class"); 2837 viewer.showError("Error occurred while instantiating TableView class"); 2838 Tools.showError(shell, "Show Data", "Error occurred while instantiating TableView class"); 2839 } 2840 } 2841 catch (ClassNotFoundException ex) { 2842 log.debug("showDataContent(): no suitable TableView class found"); 2843 viewer.showError("Unable to find suitable TableView class for object '" + dataObject.getName() + "'"); 2844 Tools.showError(shell, "Show Data", "Unable to find suitable TableView class for object '" + dataObject.getName() + "'"); 2845 theView = null; 2846 } 2847 } 2848 2849 if (!shell.isDisposed()) 2850 shell.setCursor(null); 2851 2852 return theView; 2853 } 2854 2855 /** 2856 * Displays the meta data of a data object. 2857 * 2858 * @param dataObject 2859 * the data object 2860 * 2861 * @return the MetaDataView that displays the MetaData of the data object 2862 * 2863 * @throws Exception if a failure occurred 2864 */ 2865 @Override 2866 public MetaDataView showMetaData(HObject dataObject) throws Exception { 2867 if (dataObject == null) 2868 return null; 2869 2870 log.trace("showMetaData({}): start", dataObject.getName()); 2871 2872 DataViewFactory metaDataViewFactory = null; 2873 try { 2874 metaDataViewFactory = DataViewFactoryProducer.getFactory(DataViewType.METADATA); 2875 } 2876 catch (Exception ex) { 2877 log.debug("showMetaData(): error occurred while instantiating MetaDataView factory class", ex); 2878 viewer.showError("Error occurred while instantiating MetaDataView factory class"); 2879 return null; 2880 } 2881 2882 if (metaDataViewFactory == null) { 2883 log.debug("showMetaData(): MetaDataView factory is null"); 2884 return null; 2885 } 2886 2887 /* TODO: initargs needs access to MetaDataView parent composite */ 2888 MetaDataView theView; 2889 try { 2890 theView = metaDataViewFactory.getMetaDataView(null, viewer, dataObject); 2891 2892 if (theView == null) { 2893 log.debug("showMetaData(): error occurred while instantiating MetaDataView class"); 2894 viewer.showError("Error occurred while instantiating MetaDataView class"); 2895 return null; 2896 } 2897 } 2898 catch (ClassNotFoundException ex) { 2899 log.debug("showMetaData(): no suitable MetaDataView class found"); 2900 viewer.showError("Unable to find suitable MetaDataView class for object '" + dataObject.getName() + "'"); 2901 return null; 2902 } 2903 2904 return theView; 2905 } 2906 2907 /** 2908 * Updates the current font. 2909 * 2910 * @param font 2911 * the new font 2912 */ 2913 public void updateFont(Font font) { 2914 if (curFont != null) 2915 curFont.dispose(); 2916 2917 curFont = font; 2918 2919 tree.setFont(font); 2920 } 2921 2922 /** 2923 * Updates the icon for the TreeItem representing the given HObject. Used 2924 * to change the icon after a status update, such as adding an attribute to 2925 * an object. 2926 * 2927 * @param obj 2928 * the object to update the icon for 2929 */ 2930 public void updateItemIcon(HObject obj) { 2931 if (obj == null) { 2932 log.debug("updateItemIcon(): object is null"); 2933 return; 2934 } 2935 2936 TreeItem theItem = findTreeItem(obj); 2937 2938 if (theItem == null) { 2939 log.debug("updateItemIcon(): could not find TreeItem for HObject"); 2940 } 2941 else { 2942 if (obj instanceof Group && !(((Group) obj).isRoot())) { 2943 if (theItem.getExpanded()) { 2944 if (((MetaDataContainer) obj).hasAttribute()) 2945 theItem.setImage(folderOpenIconA); 2946 else 2947 theItem.setImage(folderOpenIcon); 2948 } 2949 else { 2950 if (((MetaDataContainer) obj).hasAttribute()) 2951 theItem.setImage(folderCloseIconA); 2952 else 2953 theItem.setImage(folderCloseIcon); 2954 } 2955 } 2956 else { 2957 theItem.setImage(getObjectTypeImage(obj)); 2958 } 2959 } 2960 } 2961 2962 /** 2963 * ChangeIndexingDialog displays file index options. 2964 */ 2965 private class ChangeIndexingDialog extends Dialog 2966 { 2967 private Button checkIndexByName; 2968 private Button checkIndexIncrements; 2969 private Button checkIndexNative; 2970 2971 private boolean reloadFile; 2972 2973 private FileFormat selectedFile; 2974 private int indexType; 2975 private int indexOrder; 2976 2977 private ChangeIndexingDialog(Shell parent, int style, FileFormat viewSelectedFile) { 2978 super(parent, style); 2979 2980 selectedFile = viewSelectedFile; 2981 try { 2982 indexType = selectedFile.getIndexType(null); 2983 } 2984 catch (Exception ex) { 2985 log.debug("ChangeIndexingDialog(): getIndexType failed: ", ex); 2986 } 2987 try { 2988 indexOrder = selectedFile.getIndexOrder(null); 2989 } 2990 catch (Exception ex) { 2991 log.debug("ChangeIndexingDialog(): getIndexOrder failed: ", ex); 2992 } 2993 reloadFile = false; 2994 } 2995 2996 private void setIndexOptions() { 2997 try { 2998 if (checkIndexByName.getSelection()) 2999 indexType = selectedFile.getIndexType("H5_INDEX_NAME"); 3000 else 3001 indexType = selectedFile.getIndexType("H5_INDEX_CRT_ORDER"); 3002 } 3003 catch (Exception ex) { 3004 log.debug("setIndexOptions(): getIndexType failed: ", ex); 3005 } 3006 3007 try { 3008 if (checkIndexIncrements.getSelection()) 3009 indexOrder = selectedFile.getIndexOrder("H5_ITER_INC"); 3010 else if (checkIndexNative.getSelection()) 3011 indexOrder = selectedFile.getIndexOrder("H5_ITER_NATIVE"); 3012 else 3013 indexOrder = selectedFile.getIndexOrder("H5_ITER_DEC"); 3014 } 3015 catch (Exception ex) { 3016 log.debug("setIndexOptions(): getIndexOrder failed: ", ex); 3017 } 3018 3019 reloadFile = true; 3020 } 3021 3022 /** @return the current value of the index type. */ 3023 public int getIndexType() { 3024 return indexType; 3025 } 3026 3027 /** @return the current value of the index order. */ 3028 public int getIndexOrder() { 3029 return indexOrder; 3030 } 3031 3032 /** @return the current value of the reloadFile. */ 3033 public boolean isReloadFile() { 3034 return reloadFile; 3035 } 3036 3037 /** open the ChangeIndexingDialog for setting the indexing values. */ 3038 public void open() { 3039 Shell parent = getParent(); 3040 final Shell openShell = new Shell(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); 3041 openShell.setFont(curFont); 3042 openShell.setText("Indexing options"); 3043 openShell.setImage(ViewProperties.getHdfIcon()); 3044 openShell.setLayout(new GridLayout(1, true)); 3045 3046 // Create main content region 3047 Composite content = new Composite(openShell, SWT.NONE); 3048 content.setLayout(new GridLayout(1, true)); 3049 content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 3050 3051 org.eclipse.swt.widgets.Group indexingTypeGroup = new org.eclipse.swt.widgets.Group(content, SWT.NONE); 3052 indexingTypeGroup.setFont(curFont); 3053 indexingTypeGroup.setText("Indexing Type"); 3054 indexingTypeGroup.setLayout(new GridLayout(2, true)); 3055 indexingTypeGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 3056 3057 int initIndexType = 0; 3058 try { 3059 initIndexType = selectedFile.getIndexType("H5_INDEX_NAME"); 3060 } 3061 catch (Exception ex) { 3062 log.debug("open(): getIndexType failed: ", ex); 3063 } 3064 checkIndexByName = new Button(indexingTypeGroup, SWT.RADIO); 3065 checkIndexByName.setFont(curFont); 3066 checkIndexByName.setText("By Name"); 3067 checkIndexByName.setSelection((indexType) == initIndexType); 3068 checkIndexByName.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 3069 3070 try { 3071 initIndexType = selectedFile.getIndexType("H5_INDEX_CRT_ORDER"); 3072 } 3073 catch (Exception ex) { 3074 log.debug("open(): getIndexType failed: ", ex); 3075 } 3076 Button byOrder = new Button(indexingTypeGroup, SWT.RADIO); 3077 byOrder.setFont(curFont); 3078 byOrder.setText("By Creation Order"); 3079 byOrder.setSelection((indexType) == initIndexType); 3080 byOrder.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 3081 3082 org.eclipse.swt.widgets.Group indexingOrderGroup = new org.eclipse.swt.widgets.Group(content, SWT.NONE); 3083 indexingOrderGroup.setFont(curFont); 3084 indexingOrderGroup.setText("Indexing Order"); 3085 indexingOrderGroup.setLayout(new GridLayout(3, true)); 3086 indexingOrderGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 3087 3088 int initIndexOrder = 0; 3089 try { 3090 initIndexOrder = selectedFile.getIndexOrder("H5_ITER_INC"); 3091 } 3092 catch (Exception ex) { 3093 log.debug("open(): getIndexOrder failed: ", ex); 3094 } 3095 checkIndexIncrements = new Button(indexingOrderGroup, SWT.RADIO); 3096 checkIndexIncrements.setFont(curFont); 3097 checkIndexIncrements.setText("Increments"); 3098 checkIndexIncrements.setSelection((indexOrder) == initIndexOrder); 3099 checkIndexIncrements.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 3100 3101 try { 3102 initIndexOrder = selectedFile.getIndexOrder("H5_ITER_DEC"); 3103 } 3104 catch (Exception ex) { 3105 log.debug("open(): getIndexOrder failed: ", ex); 3106 } 3107 Button decrements = new Button(indexingOrderGroup, SWT.RADIO); 3108 decrements.setFont(curFont); 3109 decrements.setText("Decrements"); 3110 decrements.setSelection((indexOrder) == initIndexOrder); 3111 decrements.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 3112 3113 try { 3114 initIndexOrder = selectedFile.getIndexOrder("H5_ITER_NATIVE"); 3115 } 3116 catch (Exception ex) { 3117 log.debug("open(): getIndexOrder failed: ", ex); 3118 } 3119 checkIndexNative = new Button(indexingOrderGroup, SWT.RADIO); 3120 checkIndexNative.setFont(curFont); 3121 checkIndexNative.setText("Native"); 3122 checkIndexNative.setSelection((indexOrder) == initIndexOrder); 3123 checkIndexNative.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 3124 3125 3126 // Create Ok/Cancel button region 3127 Composite buttonComposite = new Composite(openShell, SWT.NONE); 3128 buttonComposite.setLayout(new GridLayout(2, true)); 3129 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3130 3131 Button okButton = new Button(buttonComposite, SWT.PUSH); 3132 okButton.setFont(curFont); 3133 okButton.setText(" &Reload File "); 3134 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 3135 okButton.addSelectionListener(new SelectionAdapter() { 3136 @Override 3137 public void widgetSelected(SelectionEvent e) { 3138 setIndexOptions(); 3139 openShell.dispose(); 3140 } 3141 }); 3142 3143 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 3144 cancelButton.setFont(curFont); 3145 cancelButton.setText(" &Cancel "); 3146 cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 3147 cancelButton.addSelectionListener(new SelectionAdapter() { 3148 @Override 3149 public void widgetSelected(SelectionEvent e) { 3150 reloadFile = false; 3151 openShell.dispose(); 3152 } 3153 }); 3154 3155 openShell.pack(); 3156 3157 Point minimumSize = openShell.computeSize(SWT.DEFAULT, SWT.DEFAULT); 3158 3159 openShell.setMinimumSize(minimumSize); 3160 3161 Rectangle parentBounds = parent.getBounds(); 3162 Point shellSize = openShell.getSize(); 3163 openShell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 3164 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 3165 3166 openShell.open(); 3167 3168 Display display = parent.getDisplay(); 3169 while (!openShell.isDisposed()) 3170 if (!display.readAndDispatch()) 3171 display.sleep(); 3172 } 3173 } 3174 3175 private class ChangeLibVersionDialog extends Dialog 3176 { 3177 public ChangeLibVersionDialog(Shell parent, int style) { 3178 super(parent, style); 3179 } 3180 3181 public void open() { 3182 Shell parent = getParent(); 3183 final Shell openShell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 3184 openShell.setFont(curFont); 3185 openShell.setText("Set the library version bounds: "); 3186 openShell.setImage(ViewProperties.getHdfIcon()); 3187 openShell.setLayout(new GridLayout(1, true)); 3188 3189 String[] lowValues = { "Earliest", "V18", "V110", "Latest" }; 3190 int[] lowConstants = { HDF5Constants.H5F_LIBVER_EARLIEST, HDF5Constants.H5F_LIBVER_V18, HDF5Constants.H5F_LIBVER_V110, HDF5Constants.H5F_LIBVER_LATEST }; 3191 String[] highValues = { "V18", "V110", "Latest" }; 3192 int[] highConstants = { HDF5Constants.H5F_LIBVER_V18, HDF5Constants.H5F_LIBVER_V110, HDF5Constants.H5F_LIBVER_LATEST }; 3193 3194 // Try to retrieve the existing version bounds 3195 int[] current = null; 3196 try { 3197 current = selectedObject.getFileFormat().getLibBounds(); 3198 } 3199 catch (Exception err) { 3200 openShell.getDisplay().beep(); 3201 Tools.showError(openShell, "Version bounds", "Error when getting lib version bounds, using default"); 3202 current = new int[]{HDF5Constants.H5F_LIBVER_EARLIEST, HDF5Constants.H5F_LIBVER_LATEST}; 3203 } 3204 int lowidx = 0; 3205 for(int i = 0; i < lowConstants.length; i++) { 3206 if(lowConstants[i] == current[0]){ 3207 lowidx = i; 3208 break; 3209 } 3210 } 3211 int highidx = 0; 3212 for(int i = 0; i < highConstants.length; i++) { 3213 if(highConstants[i] == current[1]){ 3214 highidx = i; 3215 break; 3216 } 3217 } 3218 3219 // Dummy label 3220 new Label(openShell, SWT.LEFT); 3221 3222 Label label = new Label(openShell, SWT.LEFT); 3223 label.setFont(curFont); 3224 label.setText("Earliest Version: "); 3225 3226 final Combo earliestCombo = new Combo(openShell, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); 3227 earliestCombo.setFont(curFont); 3228 earliestCombo.setItems(lowValues); 3229 earliestCombo.select(lowidx); 3230 earliestCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3231 3232 label = new Label(openShell, SWT.LEFT); 3233 label.setFont(curFont); 3234 label.setText("Latest Version: "); 3235 3236 final Combo latestCombo = new Combo(openShell, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); 3237 latestCombo.setFont(curFont); 3238 latestCombo.setItems(highValues); 3239 latestCombo.select(highidx); 3240 latestCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3241 3242 // Dummy label to consume remain space after resizing 3243 new Label(openShell, SWT.LEFT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 3244 3245 // Create Ok/Cancel button region 3246 Composite buttonComposite = new Composite(openShell, SWT.NONE); 3247 buttonComposite.setLayout(new GridLayout(2, true)); 3248 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3249 3250 Button okButton = new Button(buttonComposite, SWT.PUSH); 3251 okButton.setFont(curFont); 3252 okButton.setText(" &OK "); 3253 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 3254 okButton.addSelectionListener(new SelectionAdapter() { 3255 @Override 3256 public void widgetSelected(SelectionEvent e) { 3257 try { 3258 selectedObject.getFileFormat().setLibBounds(earliestCombo.getItem(earliestCombo.getSelectionIndex()), latestCombo.getItem(latestCombo.getSelectionIndex())); 3259 } 3260 catch (Exception err) { 3261 openShell.getDisplay().beep(); 3262 Tools.showError(openShell, "Version bounds", "Error when setting lib version bounds"); 3263 return; 3264 } 3265 3266 openShell.dispose(); 3267 3268 ((HDFView) viewer).showMetaData(selectedObject); 3269 } 3270 }); 3271 3272 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 3273 cancelButton.setFont(curFont); 3274 cancelButton.setText(" &Cancel "); 3275 cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 3276 cancelButton.addSelectionListener(new SelectionAdapter() { 3277 @Override 3278 public void widgetSelected(SelectionEvent e) { 3279 openShell.dispose(); 3280 } 3281 }); 3282 3283 openShell.pack(); 3284 3285 Point minimumSize = openShell.computeSize(SWT.DEFAULT, SWT.DEFAULT); 3286 3287 openShell.setMinimumSize(minimumSize); 3288 openShell.setSize(minimumSize.x + 50, minimumSize.y); 3289 3290 Rectangle parentBounds = parent.getBounds(); 3291 Point shellSize = openShell.getSize(); 3292 openShell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 3293 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 3294 3295 openShell.open(); 3296 3297 Display display = parent.getDisplay(); 3298 while (!openShell.isDisposed()) 3299 if (!display.readAndDispatch()) 3300 display.sleep(); 3301 } 3302 } 3303 3304 private class LoadDataThread extends Thread 3305 { 3306 LoadDataThread() { 3307 super(); 3308 setDaemon(true); 3309 } 3310 3311 @Override 3312 public void run() { 3313 try { 3314 Display.getDefault().syncExec(new Runnable() { 3315 @Override 3316 public void run() { 3317 try { 3318 showDataContent(selectedObject); 3319 } 3320 catch (Exception ex) { 3321 log.debug("showDataContent failure: ", ex); 3322 } 3323 } 3324 }); 3325 } 3326 catch (Exception e) { 3327 log.debug("showDataContent loading manually interrupted"); 3328 } 3329 } 3330 } 3331}