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