001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.view; 016 017import java.io.BufferedInputStream; 018import java.io.BufferedOutputStream; 019import java.io.File; 020import java.io.FileOutputStream; 021import java.net.URL; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Enumeration; 025import java.util.Iterator; 026import java.util.List; 027 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031import org.eclipse.jface.preference.PreferenceManager; 032import org.eclipse.swt.SWT; 033import org.eclipse.swt.custom.SashForm; 034import org.eclipse.swt.custom.ScrolledComposite; 035import org.eclipse.swt.dnd.DND; 036import org.eclipse.swt.dnd.DropTarget; 037import org.eclipse.swt.dnd.DropTargetEvent; 038import org.eclipse.swt.dnd.DropTargetListener; 039import org.eclipse.swt.dnd.FileTransfer; 040import org.eclipse.swt.dnd.Transfer; 041import org.eclipse.swt.events.DisposeEvent; 042import org.eclipse.swt.events.DisposeListener; 043import org.eclipse.swt.events.KeyAdapter; 044import org.eclipse.swt.events.KeyEvent; 045import org.eclipse.swt.events.SelectionAdapter; 046import org.eclipse.swt.events.SelectionEvent; 047import org.eclipse.swt.graphics.Font; 048import org.eclipse.swt.graphics.Image; 049import org.eclipse.swt.graphics.Point; 050import org.eclipse.swt.graphics.Rectangle; 051import org.eclipse.swt.layout.FillLayout; 052import org.eclipse.swt.layout.GridData; 053import org.eclipse.swt.layout.GridLayout; 054import org.eclipse.swt.layout.RowLayout; 055import org.eclipse.swt.widgets.Button; 056import org.eclipse.swt.widgets.Combo; 057import org.eclipse.swt.widgets.Composite; 058import org.eclipse.swt.widgets.Control; 059import org.eclipse.swt.widgets.Dialog; 060import org.eclipse.swt.widgets.Display; 061import org.eclipse.swt.widgets.Event; 062import org.eclipse.swt.widgets.FileDialog; 063import org.eclipse.swt.widgets.Label; 064import org.eclipse.swt.widgets.Listener; 065import org.eclipse.swt.widgets.Menu; 066import org.eclipse.swt.widgets.MenuItem; 067import org.eclipse.swt.widgets.Monitor; 068import org.eclipse.swt.widgets.Shell; 069import org.eclipse.swt.widgets.Text; 070import org.eclipse.swt.widgets.ToolBar; 071import org.eclipse.swt.widgets.ToolItem; 072 073import hdf.HDFVersions; 074import hdf.object.DataFormat; 075import hdf.object.FileFormat; 076import hdf.object.HObject; 077import hdf.view.ViewProperties.DataViewType; 078import hdf.view.DataView.DataView; 079import hdf.view.DataView.DataViewFactory; 080import hdf.view.DataView.DataViewFactoryProducer; 081import hdf.view.DataView.DataViewManager; 082import hdf.view.HelpView.HelpView; 083import hdf.view.MetaDataView.MetaDataView; 084import hdf.view.TableView.TableView; 085import hdf.view.TreeView.DefaultTreeView; 086import hdf.view.TreeView.TreeView; 087import hdf.view.dialog.ImageConversionDialog; 088import hdf.view.dialog.InputDialog; 089import hdf.view.dialog.UserOptionsDialog; 090import hdf.view.dialog.UserOptionsGeneralPage; 091import hdf.view.dialog.UserOptionsHDFPage; 092import hdf.view.dialog.UserOptionsNode; 093import hdf.view.dialog.UserOptionsViewModulesPage; 094 095 096/** 097 * HDFView is the main class of this HDF visual tool. It is used to layout the 098 * graphical components of the hdfview. The major GUI components of the HDFView 099 * include Menubar, Toolbar, TreeView, ContentView, and MessageArea. 100 * 101 * The HDFView is designed in such a way that it does not have direct access to 102 * the HDF library. All the HDF library access is done through HDF objects. 103 * Therefore, the HDFView package depends on the object package but not the 104 * library package. The source code of the view package (hdf.view) should 105 * be compiled with the library package (hdf.hdflib and hdf.hdf5lib). 106 * 107 * @author Jordan T. Henderson 108 * @version 2.4 //2015 109 */ 110public class HDFView implements DataViewManager 111{ 112 private static final Logger log = LoggerFactory.getLogger(HDFView.class); 113 114 private static Display display; 115 private static Shell mainWindow; 116 117 /* Determines whether HDFView is being executed for GUI testing */ 118 private boolean isTesting = false; 119 120 /* The directory where HDFView is installed */ 121 private String rootDir; 122 123 /* The initial directory where HDFView looks for files */ 124 private String startDir; 125 126 /* The current working directory */ 127 private String currentDir; 128 129 /* The current working file */ 130 private String currentFile = null; 131 132 /* The view properties */ 133 private ViewProperties props; 134 135 /* A list of tree view implementations. */ 136 private static List<String> treeViews; 137 138 /* A list of image view implementations. */ 139 private static List<String> imageViews; 140 141 /* A list of tree table implementations. */ 142 private static List<?> tableViews; 143 144 /* A list of metadata view implementations. */ 145 private static List<?> metaDataViews; 146 147 /* A list of palette view implementations. */ 148 private static List<?> paletteViews; 149 150 /* A list of help view implementations. */ 151 private static List<?> helpViews; 152 153 /* The list of GUI components related to NetCDF3 */ 154 private final List<MenuItem> n3GUIs = new ArrayList<>(); 155 156 /* The list of GUI components related to HDF4 */ 157 private final List<MenuItem> h4GUIs = new ArrayList<>(); 158 159 /* The list of GUI components related to HDF5 */ 160 private final List<MenuItem> h5GUIs = new ArrayList<>(); 161 162 /* The list of GUI components related to editing */ 163 //private final List<?> editGUIs; 164 165 /* GUI component: the TreeView */ 166 private TreeView treeView = null; 167 168 private static final String JAVA_VERSION = HDFVersions.getPropertyVersionJava(); 169 private static final String HDF4_VERSION = HDFVersions.getPropertyVersionHDF4(); 170 private static final String HDF5_VERSION = HDFVersions.getPropertyVersionHDF5(); 171 private static final String HDFVIEW_VERSION = HDFVersions.getPropertyVersionView(); 172 private static final String HDFVIEW_USERSGUIDE_URL = "https://portal.hdfgroup.org/display/HDFVIEW/HDFView+3.x+User%27s+Guide"; 173 private static final String JAVA_COMPILER = "jdk " + JAVA_VERSION; 174 private static final String JAVA_VER_INFO = "Compiled at " + JAVA_COMPILER + "\nRunning at " + System.getProperty("java.version"); 175 176 private static final String ABOUT_HDFVIEW = "HDF Viewer, " + "Version " + ViewProperties.VERSION + "\n" 177 + "For " + System.getProperty("os.name") + "\n\n" 178 + "Copyright " + '\u00a9' + " 2006 The HDF Group.\n" 179 + "All rights reserved."; 180 181 /* GUI component: The toolbar for open, close, help and hdf4 and hdf5 library information */ 182 private ToolBar toolBar; 183 184 /* GUI component: The text area for showing status messages */ 185 private Text status; 186 187 /* GUI component: The area for object view */ 188 private ScrolledComposite treeArea; 189 190 /* GUI component: The area for quick general view */ 191 private ScrolledComposite generalArea; 192 193 /* GUI component: To add and display URLs */ 194 private Combo urlBar; 195 196 private Button recentFilesButton; 197 private Button clearTextButton; 198 199 /* GUI component: A list of current data windows */ 200 private Menu windowMenu; 201 202 /* GUI component: File menu on the menubar */ 203 //private final Menu fileMenu; 204 205 /* The font to be used for display text on all Controls */ 206 private Font currentFont; 207 208 private UserOptionsDialog userOptionDialog; 209 210 /** State of refresh. */ 211 public boolean viewerState = false; 212 213 /** Timer for refresh functions. */ 214 private final Runnable timer = new Runnable() { 215 public void run() { 216 // refresh each table displaying data 217 Shell[] shellList = display.getShells(); 218 if (shellList != null) { 219 for (int i = 0; i < shellList.length; i++) { 220 if (shellList[i].equals(mainWindow)) 221 showMetaData(treeView.getCurrentObject()); 222 else { 223 DataView view = (DataView) shellList[i].getData(); 224 if ((view != null) && (view instanceof TableView)) { 225 HObject obj = view.getDataObject(); 226 if (obj == null || obj.getFileFormat() == null || !(obj instanceof DataFormat)) 227 continue; 228 229 FileFormat file = obj.getFileFormat(); 230 if (file.isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) 231 ((TableView)view).refreshDataTable(); 232 } 233 } 234 } 235 } 236 log.trace("viewerState = {}", viewerState); 237 if (viewerState) 238 display.timerExec(ViewProperties.getTimerRefresh(), timer); 239 else 240 display.timerExec(-1, timer); 241 } 242 }; 243 244 /** 245 * Constructs HDFView with a given root directory, where the HDFView is 246 * installed, and opens the given files in the viewer. 247 * 248 * @param root 249 * the directory where the HDFView is installed. 250 * @param start_dir 251 * the starting directory for file searches 252 */ 253 public HDFView(String root, String start_dir) { 254 log.debug("Root is {}", root); 255 256 if (display == null || display.isDisposed()) 257 display = new Display(); 258 259 rootDir = root; 260 startDir = start_dir; 261 262 //editGUIs = new Vector<Object>(); 263 264 props = new ViewProperties(rootDir, startDir); 265 try { 266 props.load(); 267 } 268 catch (Exception ex) { 269 log.debug("Failed to load View Properties from {}", rootDir); 270 } 271 272 ViewProperties.loadIcons(); 273 274 String workDir = System.getProperty("hdfview.workdir"); 275 if (workDir != null) 276 currentDir = workDir; 277 else 278 currentDir = ViewProperties.getWorkDir(); 279 280 if (currentDir == null) 281 currentDir = System.getProperty("user.dir"); 282 283 log.info("Current directory is {}", currentDir); 284 285 try { 286 currentFont = new Font( 287 display, 288 ViewProperties.getFontType(), 289 ViewProperties.getFontSize(), 290 SWT.NORMAL); 291 } 292 catch (Exception ex) { 293 currentFont = null; 294 } 295 296 treeViews = ViewProperties.getTreeViewList(); 297 metaDataViews = ViewProperties.getMetaDataViewList(); 298 tableViews = ViewProperties.getTableViewList(); 299 imageViews = ViewProperties.getImageViewList(); 300 paletteViews = ViewProperties.getPaletteViewList(); 301 helpViews = ViewProperties.getHelpViewList(); 302 303 log.debug("Constructor exit"); 304 } 305 306 307 /** 308 * Creates HDFView with a given size, and opens the given files in the viewer. 309 * 310 * @param flist 311 * a list of files to open. 312 * @param width 313 * the width of the app in pixels 314 * @param height 315 * the height of the app in pixels 316 * @param x 317 * the coord x of the app in pixels 318 * @param y 319 * the coord y of the app in pixels 320 * 321 * @return 322 * the newly-created HDFView Shell 323 */ 324 public Shell openMainWindow(List<File> flist, int width, int height, int x, int y) { 325 log.debug("openMainWindow enter current directory is {}", currentDir); 326 327 // Initialize all GUI components 328 mainWindow = createMainWindow(); 329 330 try { 331 Font font = null; 332 String fType = ViewProperties.getFontType(); 333 int fSize = ViewProperties.getFontSize(); 334 335 try { 336 font = new Font(display, fType, fSize, SWT.NORMAL); 337 } 338 catch (Exception ex) { 339 log.debug("Failed to load font"); 340 font = null; 341 } 342 343 if (font != null) 344 updateFont(font); 345 } 346 catch (Exception ex) { 347 log.debug("Failed to load Font properties"); 348 } 349 350 // Make sure all GUI components are in place before 351 // opening any files 352 mainWindow.pack(); 353 354 int nfiles = flist.size(); 355 File theFile = null; 356 for (int i = 0; i < nfiles; i++) { 357 theFile = flist.get(i); 358 359 if (theFile.isFile()) { 360 currentDir = theFile.getParentFile().getAbsolutePath(); 361 currentFile = theFile.getAbsolutePath(); 362 363 try { 364 int access_mode = FileFormat.WRITE; 365 if (ViewProperties.isReadOnly()) 366 access_mode = FileFormat.READ; 367 else if (ViewProperties.isReadSWMR()) 368 access_mode = FileFormat.READ | FileFormat.MULTIREAD; 369 treeView.openFile(currentFile, access_mode); 370 371 try { 372 urlBar.remove(currentFile); 373 } 374 catch (Exception ex) {} 375 376 // first entry is always the workdir 377 urlBar.add(currentFile, 1); 378 urlBar.select(1); 379 } 380 catch (Exception ex) { 381 showError(ex.toString()); 382 } 383 } 384 else { 385 currentDir = theFile.getAbsolutePath(); 386 } 387 388 log.info("CurrentDir is {}", currentDir); 389 } 390 391 if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3) == null) 392 setEnabled(n3GUIs, false); 393 394 if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4) == null) 395 setEnabled(h4GUIs, false); 396 397 if (FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5) == null) 398 setEnabled(h5GUIs, false); 399 400 // Set size of main window 401 // float inset = 0.17f; // for UG only. 402 float inset = 0.04f; 403 Point winDim = new Point(width, height); 404 405 // If given height and width are too small, adjust accordingly 406 if (height <= 300) 407 winDim.y = (int) ((1 - 2 * inset) * mainWindow.getSize().y); 408 409 if (width <= 300) 410 winDim.x = (int) (0.9 * mainWindow.getSize().y); 411 412 mainWindow.setLocation(x, y); 413 mainWindow.setSize(winDim.x + 200, winDim.y); 414 415 // Display the window 416 mainWindow.open(); 417 log.debug("openMainWindow exit"); 418 return mainWindow; 419 } 420 421 /** switch processing to the main application window */ 422 public void runMainWindow() { 423 log.debug("runMainWindow enter"); 424 425 while(!mainWindow.isDisposed()) { 426 // =================================================== 427 // Wrap each event dispatch in an exception handler 428 // so that if any event causes an exception it does 429 // not break the main UI loop 430 // =================================================== 431 try { 432 if (!display.readAndDispatch()) 433 display.sleep(); 434 } 435 catch (Exception e) { 436 e.printStackTrace(); 437 } 438 } 439 440 if (!isTesting) 441 display.dispose(); 442 log.debug("runMainWindow exit"); 443 } 444 445 /** 446 * Creates and lays out GUI components. 447 * 448 * <pre> 449 * ||=========||=============================|| 450 * || || || 451 * || || || 452 * || TreeView|| ContentPane || 453 * || || || 454 * ||=========||=============================|| 455 * || Message Area || 456 * ||========================================|| 457 * </pre> 458 */ 459 private Shell createMainWindow() { 460 Image hdfImage = ViewProperties.getLargeHdfIcon(); 461 // Create a new display window 462 final Shell shell = new Shell(display); 463 shell.setImage(hdfImage); 464 shell.setImages(ViewProperties.getHdfIcons()); 465 shell.setFont(currentFont); 466 shell.setText("HDFView " + HDFVIEW_VERSION); 467 shell.setLayout(new GridLayout(3, false)); 468 shell.addDisposeListener(new DisposeListener() { 469 @Override 470 public void widgetDisposed(DisposeEvent e) { 471 ViewProperties.setRecentFiles(new ArrayList<>(Arrays.asList(urlBar.getItems()))); 472 473 try { 474 props.save(); 475 } 476 catch (Exception ex) {} 477 478 closeAllWindows(); 479 480 // Close all open files 481 try { 482 List<FileFormat> filelist = treeView.getCurrentFiles(); 483 484 if ((filelist != null) && !filelist.isEmpty()) { 485 Object[] files = filelist.toArray(); 486 487 for (int i = 0; i < files.length; i++) { 488 try { 489 treeView.closeFile((FileFormat) files[i]); 490 } 491 catch (Exception ex) { 492 continue; 493 } 494 } 495 } 496 } 497 catch (Exception ex) {} 498 499 if (currentFont != null) 500 currentFont.dispose(); 501 } 502 }); 503 504 createMenuBar(shell); 505 createToolbar(shell); 506 createUrlToolbar(shell); 507 createContentArea(shell); 508 509 log.info("Main Window created"); 510 511 return shell; 512 } 513 514 private void createMenuBar(final Shell shell) { 515 Menu menu = new Menu(shell, SWT.BAR); 516 shell.setMenuBar(menu); 517 518 MenuItem menuItem = new MenuItem(menu, SWT.CASCADE); 519 menuItem.setText("&File"); 520 521 Menu fileMenu = new Menu(menuItem); 522 menuItem.setMenu(fileMenu); 523 524 MenuItem item = new MenuItem(fileMenu, SWT.PUSH); 525 item.setText("&Open\tCtrl-O"); 526 item.setAccelerator(SWT.MOD1 + 'O'); 527 item.addSelectionListener(new SelectionAdapter() { 528 @Override 529 public void widgetSelected(SelectionEvent e) { 530 openLocalFile(null, -1); 531 } 532 }); 533 534 item = new MenuItem(fileMenu, SWT.CASCADE); 535 item.setText("Open As"); 536 537 Menu openAsMenu = new Menu(item); 538 item.setMenu(openAsMenu); 539 540 item = new MenuItem(openAsMenu, SWT.PUSH); 541 item.setText("Read-Only"); 542 item.addSelectionListener(new SelectionAdapter() { 543 @Override 544 public void widgetSelected(SelectionEvent e) { 545 openLocalFile(null, FileFormat.READ); 546 } 547 }); 548 549 item = new MenuItem(openAsMenu, SWT.PUSH); 550 item.setText("SWMR Read-Only"); 551 item.addSelectionListener(new SelectionAdapter() { 552 @Override 553 public void widgetSelected(SelectionEvent e) { 554 openLocalFile(null, FileFormat.READ | FileFormat.MULTIREAD); 555 } 556 }); 557 558 item = new MenuItem(openAsMenu, SWT.PUSH); 559 item.setText("Read/Write"); 560 item.addSelectionListener(new SelectionAdapter() { 561 @Override 562 public void widgetSelected(SelectionEvent e) { 563 openLocalFile(null, FileFormat.WRITE); 564 } 565 }); 566 567 new MenuItem(fileMenu, SWT.SEPARATOR); 568 569 MenuItem fileNewMenu = new MenuItem(fileMenu, SWT.CASCADE); 570 fileNewMenu.setText("New"); 571 572 Menu newMenu = new Menu(fileNewMenu); 573 fileNewMenu.setMenu(newMenu); 574 575 item = new MenuItem(newMenu, SWT.PUSH); 576 item.setText("HDF&4"); 577 h4GUIs.add(item); 578 item.addSelectionListener(new SelectionAdapter() { 579 @Override 580 public void widgetSelected(SelectionEvent e) { 581 if (currentDir != null) 582 currentDir += File.separator; 583 else 584 currentDir = ""; 585 586 String filename = null; 587 588 if (!isTesting) { 589 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 590 fChooser.setFileName(Tools.checkNewFile(currentDir, ".hdf").getName()); 591 592 DefaultFileFilter filter = DefaultFileFilter.getFileFilterHDF4(); 593 fChooser.setFilterExtensions(new String[] {filter.getExtensions()}); 594 fChooser.setFilterNames(new String[] {filter.getDescription()}); 595 fChooser.setFilterIndex(0); 596 597 filename = fChooser.open(); 598 } 599 else { 600 // Prepend test file directory to filename 601 filename = currentDir.concat(new InputDialog(mainWindow, "Enter a file name", "").open()); 602 } 603 604 if(filename == null) 605 return; 606 607 try { 608 log.trace("HDFView create hdf4 file"); 609 FileFormat theFile = Tools.createNewFile(filename, currentDir, 610 FileFormat.FILE_TYPE_HDF4, getTreeView().getCurrentFiles()); 611 612 if (theFile == null) 613 return; 614 615 currentDir = theFile.getParent(); 616 } 617 catch (Exception ex) { 618 Tools.showError(mainWindow, "New", ex.getMessage()); 619 return; 620 } 621 622 try { 623 treeView.openFile(filename, FileFormat.WRITE); 624 currentFile = filename; 625 626 try { 627 urlBar.remove(filename); 628 } 629 catch (Exception ex) { 630 log.debug("unable to remove {} from urlBar", filename); 631 } 632 633 // first entry is always the workdir 634 urlBar.add(filename, 1); 635 urlBar.select(1); 636 } 637 catch (Exception ex) { 638 display.beep(); 639 Tools.showError(mainWindow, "New", ex.getMessage() + "\n" + filename); 640 } 641 } 642 }); 643 644 item = new MenuItem(newMenu, SWT.PUSH); 645 item.setText("HDF&5"); 646 h5GUIs.add(item); 647 item.addSelectionListener(new SelectionAdapter() { 648 @Override 649 public void widgetSelected(SelectionEvent e) { 650 if (currentDir != null) 651 currentDir += File.separator; 652 else 653 currentDir = ""; 654 655 String filename = null; 656 657 if (!isTesting) { 658 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 659 fChooser.setFileName(Tools.checkNewFile(currentDir, ".h5").getName()); 660 661 DefaultFileFilter filter = DefaultFileFilter.getFileFilterHDF5(); 662 fChooser.setFilterExtensions(new String[] {filter.getExtensions()}); 663 fChooser.setFilterNames(new String[] {filter.getDescription()}); 664 fChooser.setFilterIndex(0); 665 666 filename = fChooser.open(); 667 } 668 else { 669 // Prepend test file directory to filename 670 filename = currentDir.concat(new InputDialog(mainWindow, "Enter a file name", "").open()); 671 } 672 673 if(filename == null) 674 return; 675 676 try { 677 log.trace("HDFView create hdf5 file"); 678 FileFormat theFile = Tools.createNewFile(filename, currentDir, 679 FileFormat.FILE_TYPE_HDF5, getTreeView().getCurrentFiles()); 680 681 if (theFile == null) 682 return; 683 684 currentDir = theFile.getParent(); 685 } 686 catch (Exception ex) { 687 Tools.showError(mainWindow, "New", ex.getMessage()); 688 return; 689 } 690 691 try { 692 treeView.openFile(filename, FileFormat.WRITE); 693 currentFile = filename; 694 695 try { 696 urlBar.remove(filename); 697 } 698 catch (Exception ex) { 699 log.debug("unable to remove {} from urlBar", filename); 700 } 701 702 // first entry is always the workdir 703 urlBar.add(filename, 1); 704 urlBar.select(1); 705 } 706 catch (Exception ex) { 707 display.beep(); 708 Tools.showError(mainWindow, "New", ex.getMessage() + "\n" + filename); 709 } 710 } 711 }); 712 713 new MenuItem(fileMenu, SWT.SEPARATOR); 714 715 item = new MenuItem(fileMenu, SWT.PUSH); 716 item.setText("&Close"); 717 item.addSelectionListener(new SelectionAdapter() { 718 @Override 719 public void widgetSelected(SelectionEvent e) { 720 closeFile(treeView.getSelectedFile()); 721 } 722 }); 723 724 item = new MenuItem(fileMenu, SWT.PUSH); 725 item.setText("Close &All"); 726 item.addSelectionListener(new SelectionAdapter() { 727 @Override 728 public void widgetSelected(SelectionEvent e) { 729 closeAllWindows(); 730 731 List<FileFormat> files = treeView.getCurrentFiles(); 732 while (!files.isEmpty()) { 733 try { 734 treeView.closeFile(files.get(0)); 735 } 736 catch (Exception ex) { 737 log.trace("unable to close {} in treeView", files.get(0)); 738 } 739 } 740 741 currentFile = null; 742 743 for (Control control : generalArea.getChildren()) 744 control.dispose(); 745 generalArea.setContent(null); 746 747 urlBar.setText(""); 748 } 749 }); 750 751 new MenuItem(fileMenu, SWT.SEPARATOR); 752 753 item = new MenuItem(fileMenu, SWT.PUSH); 754 item.setText("&Save"); 755 item.addSelectionListener(new SelectionAdapter() { 756 @Override 757 public void widgetSelected(SelectionEvent e) { 758 if (treeView.getCurrentFiles().isEmpty()) { 759 Tools.showError(mainWindow, "Save", "No files currently open."); 760 return; 761 } 762 763 if (treeView.getSelectedFile() == null) { 764 Tools.showError(mainWindow, "Save", "No files currently selected."); 765 return; 766 } 767 768 // Save what has been changed in memory into file 769 writeDataToFile(treeView.getSelectedFile()); 770 } 771 }); 772 773 item = new MenuItem(fileMenu, SWT.PUSH); 774 item.setText("S&ave As"); 775 item.addSelectionListener(new SelectionAdapter() { 776 @Override 777 public void widgetSelected(SelectionEvent e) { 778 if (treeView.getCurrentFiles().isEmpty()) { 779 Tools.showError(mainWindow, "Save", "No files currently open."); 780 return; 781 } 782 783 if (treeView.getSelectedFile() == null) { 784 Tools.showError(mainWindow, "Save", "No files currently selected."); 785 return; 786 } 787 788 try { 789 treeView.saveFile(treeView.getSelectedFile()); 790 } 791 catch (Exception ex) { 792 display.beep(); 793 Tools.showError(mainWindow, "Save", ex.getMessage()); 794 } 795 } 796 }); 797 798 new MenuItem(fileMenu, SWT.SEPARATOR); 799 800 item = new MenuItem(fileMenu, SWT.PUSH); 801 item.setText("E&xit\tCtrl-Q"); 802 item.setAccelerator(SWT.MOD1 + 'Q'); 803 item.addSelectionListener(new SelectionAdapter() { 804 @Override 805 public void widgetSelected(SelectionEvent e) { 806 mainWindow.dispose(); 807 } 808 }); 809 810 menuItem = new MenuItem(menu, SWT.CASCADE); 811 menuItem.setText("&Window"); 812 813 windowMenu = new Menu(menuItem); 814 menuItem.setMenu(windowMenu); 815 816 item = new MenuItem(windowMenu, SWT.PUSH); 817 item.setText("&Cascade"); 818 item.addSelectionListener(new SelectionAdapter() { 819 @Override 820 public void widgetSelected(SelectionEvent e) { 821 cascadeWindows(); 822 } 823 }); 824 825 item = new MenuItem(windowMenu, SWT.PUSH); 826 item.setText("&Tile"); 827 item.addSelectionListener(new SelectionAdapter() { 828 @Override 829 public void widgetSelected(SelectionEvent e) { 830 tileWindows(); 831 } 832 }); 833 834 new MenuItem(windowMenu, SWT.SEPARATOR); 835 836 item = new MenuItem(windowMenu, SWT.PUSH); 837 item.setText("Close &All"); 838 item.addSelectionListener(new SelectionAdapter() { 839 @Override 840 public void widgetSelected(SelectionEvent e) { 841 closeAllWindows(); 842 } 843 }); 844 845 new MenuItem(windowMenu, SWT.SEPARATOR); 846 847 menuItem = new MenuItem(menu, SWT.CASCADE); 848 menuItem.setText("&Tools"); 849 850 Menu toolsMenu = new Menu(menuItem); 851 menuItem.setMenu(toolsMenu); 852 853 MenuItem convertMenuItem = new MenuItem(toolsMenu, SWT.CASCADE); 854 convertMenuItem.setText("Convert Image To"); 855 856 Menu convertMenu = new Menu(convertMenuItem); 857 convertMenuItem.setMenu(convertMenu); 858 859 item = new MenuItem(convertMenu, SWT.PUSH); 860 item.setText("HDF4"); 861 item.addSelectionListener(new SelectionAdapter() { 862 @Override 863 public void widgetSelected(SelectionEvent e) { 864 convertFile(Tools.FILE_TYPE_IMAGE, FileFormat.FILE_TYPE_HDF4); 865 } 866 }); 867 h4GUIs.add(item); 868 869 item = new MenuItem(convertMenu, SWT.PUSH); 870 item.setText("HDF5"); 871 item.addSelectionListener(new SelectionAdapter() { 872 @Override 873 public void widgetSelected(SelectionEvent e) { 874 convertFile(Tools.FILE_TYPE_IMAGE, FileFormat.FILE_TYPE_HDF5); 875 } 876 }); 877 h5GUIs.add(item); 878 879 new MenuItem(toolsMenu, SWT.SEPARATOR); 880 881 item = new MenuItem(toolsMenu, SWT.PUSH); 882 item.setText("User &Options"); 883 item.addSelectionListener(new SelectionAdapter() { 884 @Override 885 public void widgetSelected(SelectionEvent e) { 886 // Create the preference manager 887 PreferenceManager mgr = new PreferenceManager(); 888 889 // Create the nodes 890 UserOptionsNode one = new UserOptionsNode("general", new UserOptionsGeneralPage()); 891 UserOptionsNode two = new UserOptionsNode("hdf", new UserOptionsHDFPage()); 892 UserOptionsNode three = new UserOptionsNode("modules", new UserOptionsViewModulesPage()); 893 894 // Add the nodes 895 mgr.addToRoot(one); 896 mgr.addToRoot(two); 897 mgr.addToRoot(three); 898 899 // Create the preferences dialog 900 userOptionDialog = new UserOptionsDialog(shell, mgr, rootDir); 901 902 // Set the preference store 903 userOptionDialog.setPreferenceStore(props); 904 userOptionDialog.create(); 905 906 // Open the dialog 907 userOptionDialog.open(); 908 909 // TODO: this functionality is currently broken because isWorkDirChanged() is not exposed correctly. 910 // if (userOptionDialog.isWorkDirChanged()) 911 // this will always overwrite the currentDir until isWorkDirChanged() is fixed 912 currentDir = ViewProperties.getWorkDir(); 913 914 //if (userOptionDialog.isFontChanged()) { 915 Font font = null; 916 917 try { 918 font = new Font(display, ViewProperties.getFontType(), ViewProperties.getFontSize(), SWT.NORMAL); 919 } 920 catch (Exception ex) { 921 font = null; 922 } 923 924 log.trace("update fonts"); 925 updateFont(font); 926 } 927 }); 928 929 new MenuItem(toolsMenu, SWT.SEPARATOR); 930 931 item = new MenuItem(toolsMenu, SWT.PUSH); 932 item.setText("&Register File Format"); 933 item.addSelectionListener(new SelectionAdapter() { 934 @Override 935 public void widgetSelected(SelectionEvent e) { 936 registerFileFormat(); 937 } 938 }); 939 940 item = new MenuItem(toolsMenu, SWT.PUSH); 941 item.setText("&Unregister File Format"); 942 item.addSelectionListener(new SelectionAdapter() { 943 @Override 944 public void widgetSelected(SelectionEvent e) { 945 unregisterFileFormat(); 946 } 947 }); 948 949 menuItem = new MenuItem(menu, SWT.CASCADE); 950 menuItem.setText("&Help"); 951 952 Menu helpMenu = new Menu(menuItem); 953 menuItem.setMenu(helpMenu); 954 955 item = new MenuItem(helpMenu, SWT.PUSH); 956 item.setText("&User's Guide"); 957 item.addSelectionListener(new SelectionAdapter() { 958 @Override 959 public void widgetSelected(SelectionEvent e) { 960 org.eclipse.swt.program.Program.launch(HDFVIEW_USERSGUIDE_URL); 961 } 962 }); 963 964 if ((helpViews != null) && !helpViews.isEmpty()) { 965 int n = helpViews.size(); 966 for (int i = 0; i < n; i++) { 967 HelpView theView = (HelpView) helpViews.get(i); 968 item = new MenuItem(helpMenu, SWT.PUSH); 969 item.setText(theView.getLabel()); 970 //item.setActionCommand(theView.getActionCommand()); 971 } 972 } 973 974 new MenuItem(helpMenu, SWT.SEPARATOR); 975 976 item = new MenuItem(helpMenu, SWT.PUSH); 977 item.setText("HDF&4 Library Version"); 978 h4GUIs.add(item); 979 item.addSelectionListener(new SelectionAdapter() { 980 @Override 981 public void widgetSelected(SelectionEvent e) { 982 new LibraryVersionDialog(shell, FileFormat.FILE_TYPE_HDF4).open(); 983 } 984 }); 985 986 item = new MenuItem(helpMenu, SWT.PUSH); 987 item.setText("HDF&5 Library Version"); 988 h5GUIs.add(item); 989 item.addSelectionListener(new SelectionAdapter() { 990 @Override 991 public void widgetSelected(SelectionEvent e) { 992 new LibraryVersionDialog(shell, FileFormat.FILE_TYPE_HDF5).open(); 993 } 994 }); 995 996 item = new MenuItem(helpMenu, SWT.PUSH); 997 item.setText("&Java Version"); 998 item.addSelectionListener(new SelectionAdapter() { 999 @Override 1000 public void widgetSelected(SelectionEvent e) { 1001 new JavaVersionDialog(mainWindow).open(); 1002 } 1003 }); 1004 1005 new MenuItem(helpMenu, SWT.SEPARATOR); 1006 1007 item = new MenuItem(helpMenu, SWT.PUSH); 1008 item.setText("Supported Fi&le Formats"); 1009 item.addSelectionListener(new SelectionAdapter() { 1010 @Override 1011 public void widgetSelected(SelectionEvent e) { 1012 new SupportedFileFormatsDialog(mainWindow).open(); 1013 } 1014 }); 1015 1016 new MenuItem(helpMenu, SWT.SEPARATOR); 1017 1018 item = new MenuItem(helpMenu, SWT.PUSH); 1019 item.setText("&About..."); 1020 item.addSelectionListener(new SelectionAdapter() { 1021 @Override 1022 public void widgetSelected(SelectionEvent e) { 1023 new AboutDialog(mainWindow).open(); 1024 } 1025 }); 1026 1027 setEnabled(Arrays.asList(windowMenu.getItems()), false); 1028 1029 log.info("Menubar created"); 1030 } 1031 1032 private void createToolbar(final Shell shell) { 1033 toolBar = new ToolBar(shell, SWT.HORIZONTAL | SWT.RIGHT); 1034 toolBar.setFont(Display.getCurrent().getSystemFont()); 1035 toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1)); 1036 1037 ToolItem openItem = new ToolItem(toolBar, SWT.PUSH); 1038 openItem.setToolTipText("Open"); 1039 openItem.setImage(ViewProperties.getFileopenIcon()); 1040 openItem.addSelectionListener(new SelectionAdapter() { 1041 @Override 1042 public void widgetSelected(SelectionEvent e) { 1043 openLocalFile(null, -1); 1044 } 1045 }); 1046 1047 new ToolItem(toolBar, SWT.SEPARATOR).setWidth(4); 1048 1049 ToolItem closeItem = new ToolItem(toolBar, SWT.PUSH); 1050 closeItem.setImage(ViewProperties.getFilecloseIcon()); 1051 closeItem.setToolTipText("Close"); 1052 closeItem.addSelectionListener(new SelectionAdapter() { 1053 @Override 1054 public void widgetSelected(SelectionEvent e) { 1055 closeFile(treeView.getSelectedFile()); 1056 } 1057 }); 1058 1059 new ToolItem(toolBar, SWT.SEPARATOR).setWidth(20); 1060 1061 ToolItem helpItem = new ToolItem(toolBar, SWT.PUSH); 1062 helpItem.setImage(ViewProperties.getHelpIcon()); 1063 helpItem.setToolTipText("Help"); 1064 helpItem.addSelectionListener(new SelectionAdapter() { 1065 @Override 1066 public void widgetSelected(SelectionEvent e) { 1067 String ugPath = ViewProperties.getUsersGuide(); 1068 1069 if(ugPath == null || !ugPath.startsWith("http://")) { 1070 String sep = File.separator; 1071 File tmpFile = new File(ugPath); 1072 1073 if(!(tmpFile.exists())) { 1074 ugPath = rootDir + sep + "UsersGuide" + sep + "index.html"; 1075 tmpFile = new File(ugPath); 1076 1077 if(!(tmpFile.exists())) 1078 ugPath = HDFVIEW_USERSGUIDE_URL; 1079 1080 ViewProperties.setUsersGuide(ugPath); 1081 } 1082 } 1083 1084 try { 1085 org.eclipse.swt.program.Program.launch(ugPath); 1086 } 1087 catch (Exception ex) { 1088 Tools.showError(shell, "Help", ex.getMessage()); 1089 } 1090 } 1091 }); 1092 1093 new ToolItem(toolBar, SWT.SEPARATOR).setWidth(4); 1094 1095 ToolItem hdf4Item = new ToolItem(toolBar, SWT.PUSH); 1096 hdf4Item.setImage(ViewProperties.getH4Icon()); 1097 hdf4Item.setToolTipText("HDF4 Library Version"); 1098 hdf4Item.addSelectionListener(new SelectionAdapter() { 1099 @Override 1100 public void widgetSelected(SelectionEvent e) { 1101 new LibraryVersionDialog(shell, FileFormat.FILE_TYPE_HDF4).open(); 1102 } 1103 }); 1104 1105 if(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4) == null) 1106 hdf4Item.setEnabled(false); 1107 1108 new ToolItem(toolBar, SWT.SEPARATOR).setWidth(4); 1109 1110 ToolItem hdf5Item = new ToolItem(toolBar, SWT.PUSH); 1111 hdf5Item.setImage(ViewProperties.getH5Icon()); 1112 hdf5Item.setToolTipText("HDF5 Library Version"); 1113 hdf5Item.addSelectionListener(new SelectionAdapter() { 1114 @Override 1115 public void widgetSelected(SelectionEvent e) { 1116 new LibraryVersionDialog(shell, FileFormat.FILE_TYPE_HDF5).open(); 1117 } 1118 }); 1119 1120 if(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5) == null) 1121 hdf5Item.setEnabled(false); 1122 1123 // Make the toolbar as wide as the window and as 1124 // tall as the buttons 1125 toolBar.setSize(shell.getClientArea().width, openItem.getBounds().height); 1126 toolBar.setLocation(0, 0); 1127 1128 log.info("Toolbar created"); 1129 } 1130 1131 private void createUrlToolbar(final Shell shell) { 1132 // Recent Files button 1133 recentFilesButton = new Button(shell, SWT.PUSH); 1134 recentFilesButton.setFont(currentFont); 1135 recentFilesButton.setText("Recent Files"); 1136 recentFilesButton.setToolTipText("List of recent files"); 1137 recentFilesButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 1138 recentFilesButton.addSelectionListener(new SelectionAdapter() { 1139 @Override 1140 public void widgetSelected(SelectionEvent e) { 1141 urlBar.setListVisible(true); 1142 } 1143 }); 1144 1145 // Recent files combo box 1146 urlBar = new Combo(shell, SWT.BORDER | SWT.SINGLE); 1147 urlBar.setFont(currentFont); 1148 urlBar.setItems(ViewProperties.getMRF().toArray(new String[0])); 1149 urlBar.setVisibleItemCount(ViewProperties.MAX_RECENT_FILES); 1150 urlBar.deselectAll(); 1151 urlBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 1152 urlBar.addKeyListener(new KeyAdapter() { 1153 @Override 1154 public void keyPressed(KeyEvent e) { 1155 if(e.keyCode == SWT.CR) { 1156 String filename = urlBar.getText(); 1157 if (filename == null || filename.length() < 1 || filename.equals(currentFile)) 1158 return; 1159 1160 if (!(filename.startsWith("http://") || filename.startsWith("https://") || filename.startsWith("ftp://"))) { 1161 openLocalFile(filename, -1); 1162 } 1163 else { 1164 String remoteFile = openRemoteFile(filename); 1165 1166 if (remoteFile != null) 1167 openLocalFile(remoteFile, -1); 1168 } 1169 } 1170 } 1171 }); 1172 urlBar.addSelectionListener(new SelectionAdapter() { 1173 @Override 1174 public void widgetSelected(SelectionEvent e) { 1175 String filename = urlBar.getText(); 1176 if (filename == null || filename.length() < 1 || filename.equals(currentFile)) { 1177 return; 1178 } 1179 1180 if (!(filename.startsWith("http://") || filename.startsWith("https://") || filename.startsWith("ftp://"))) { 1181 openLocalFile(filename, -1); 1182 } 1183 else { 1184 String remoteFile = openRemoteFile(filename); 1185 1186 if (remoteFile != null) 1187 openLocalFile(remoteFile, -1); 1188 } 1189 } 1190 }); 1191 1192 clearTextButton = new Button(shell, SWT.PUSH); 1193 clearTextButton.setToolTipText("Clear current selection"); 1194 clearTextButton.setFont(currentFont); 1195 clearTextButton.setText("Clear Text"); 1196 clearTextButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 1197 clearTextButton.addSelectionListener(new SelectionAdapter() { 1198 @Override 1199 public void widgetSelected(SelectionEvent e) { 1200 urlBar.setText(""); 1201 urlBar.deselectAll(); 1202 } 1203 }); 1204 1205 log.info("URL Toolbar created"); 1206 } 1207 1208 private void createContentArea(final Shell shell) { 1209 SashForm content = new SashForm(shell, SWT.VERTICAL); 1210 content.setSashWidth(10); 1211 content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); 1212 1213 // Add Data content area and Status Area to main window 1214 Composite container = new Composite(content, SWT.NONE); 1215 container.setLayout(new FillLayout()); 1216 1217 Composite statusArea = new Composite(content, SWT.NONE); 1218 statusArea.setLayout(new FillLayout(SWT.HORIZONTAL)); 1219 1220 final SashForm contentArea = new SashForm(container, SWT.HORIZONTAL); 1221 contentArea.setSashWidth(10); 1222 1223 // Add TreeView and DataView to content area pane 1224 treeArea = new ScrolledComposite(contentArea, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); 1225 treeArea.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); 1226 treeArea.setExpandHorizontal(true); 1227 treeArea.setExpandVertical(true); 1228 1229 generalArea = new ScrolledComposite(contentArea, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); 1230 generalArea.setExpandHorizontal(true); 1231 generalArea.setExpandVertical(true); 1232 generalArea.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW)); 1233 generalArea.setMinHeight(contentArea.getSize().y - 2); 1234 1235 // Create status area for displaying messages and metadata 1236 status = new Text(statusArea, SWT.V_SCROLL | SWT.MULTI | SWT.BORDER); 1237 status.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW)); 1238 status.setEditable(false); 1239 status.setFont(currentFont); 1240 1241 contentArea.addListener(SWT.Resize, new Listener() { 1242 @Override 1243 public void handleEvent(Event arg0) { 1244 generalArea.setMinHeight(contentArea.getSize().y - 2); 1245 } 1246 }); 1247 1248 // Add drag and drop support for opening files 1249 DropTarget target = new DropTarget(treeArea, DND.DROP_COPY); 1250 final FileTransfer fileTransfer = FileTransfer.getInstance(); 1251 target.setTransfer(new Transfer[] { fileTransfer }); 1252 target.addDropListener(new DropTargetListener() { 1253 @Override 1254 public void dragEnter(DropTargetEvent e) { 1255 e.detail = DND.DROP_COPY; 1256 } 1257 @Override 1258 public void dragOver(DropTargetEvent e) { 1259 // Intentional 1260 } 1261 @Override 1262 public void dragOperationChanged(DropTargetEvent e) { 1263 // Intentional 1264 } 1265 @Override 1266 public void dragLeave(DropTargetEvent e) { 1267 // Intentional 1268 } 1269 @Override 1270 public void dropAccept(DropTargetEvent e) { 1271 // Intentional 1272 } 1273 @Override 1274 public void drop(DropTargetEvent e) { 1275 if (fileTransfer.isSupportedType(e.currentDataType)) { 1276 String[] files = (String[]) e.data; 1277 for (int i = 0; i < files.length; i++) 1278 openLocalFile(files[i], -1); 1279 } 1280 } 1281 }); 1282 1283 showStatus("HDFView root - " + rootDir); 1284 showStatus("User property file - " + ViewProperties.getPropertyFile()); 1285 1286 content.setWeights(new int[] { 9, 1 }); 1287 contentArea.setWeights(new int[] { 1, 3 }); 1288 1289 DataViewFactory treeViewFactory = null; 1290 try { 1291 treeViewFactory = DataViewFactoryProducer.getFactory(DataViewType.TREEVIEW); 1292 } 1293 catch (Exception ex) { 1294 log.debug("createContentArea(): error occurred while instantiating TreeView factory class", ex); 1295 this.showError("Error occurred while instantiating TreeView factory class"); 1296 return; 1297 } 1298 1299 if (treeViewFactory == null) { 1300 log.debug("createContentArea(): TreeView factory is null"); 1301 return; 1302 } 1303 1304 try { 1305 treeView = treeViewFactory.getTreeView(treeArea, this); 1306 1307 if (treeView == null) { 1308 log.debug("createContentArea(): error occurred while instantiating TreeView class"); 1309 this.showError("Error occurred while instantiating TreeView class"); 1310 return; 1311 } 1312 } 1313 catch (ClassNotFoundException ex) { 1314 log.debug("createContentArea(): no suitable TreeView class found"); 1315 this.showError("Unable to find suitable TreeView class"); 1316 return; 1317 } 1318 1319 treeArea.setContent(treeView.getTree()); 1320 1321 log.info("Content Area created"); 1322 } 1323 1324 /** 1325 * @return a list of treeview implementations. 1326 */ 1327 public static final List<String> getListOfTreeViews() { 1328 return treeViews; 1329 } 1330 1331 /** 1332 * @return a list of imageview implementations. 1333 */ 1334 public static final List<String> getListOfImageViews() { 1335 return imageViews; 1336 } 1337 1338 /** 1339 * @return a list of tableview implementations. 1340 */ 1341 public static final List<?> getListOfTableViews() { 1342 return tableViews; 1343 } 1344 1345 /** 1346 * @return a list of metaDataview implementations. 1347 */ 1348 public static final List<?> getListOfMetaDataViews() { 1349 return metaDataViews; 1350 } 1351 1352 /** 1353 * @return a list of paletteview implementations. 1354 */ 1355 public static final List<?> getListOfPaletteViews() { 1356 return paletteViews; 1357 } 1358 1359 @Override 1360 public TreeView getTreeView() { 1361 return treeView; 1362 } 1363 1364 /** 1365 * @return the combobox associated with a URL entry. 1366 */ 1367 public Combo getUrlBar() { 1368 return urlBar; 1369 } 1370 1371 /** 1372 * Start stop a timer. 1373 * 1374 * @param toggleTimer 1375 * -- true: start timer, false stop timer. 1376 */ 1377 @Override 1378 public final void executeTimer(boolean toggleTimer) { 1379 showStatus("toggleTimer: " + toggleTimer); 1380 viewerState = toggleTimer; 1381 if (viewerState) 1382 display.timerExec(ViewProperties.getTimerRefresh(), timer); 1383 else 1384 display.timerExec(-1, timer); 1385 } 1386 1387 /** 1388 * Display feedback message. 1389 * 1390 * @param msg 1391 * the message to display. 1392 */ 1393 @Override 1394 public void showStatus(String msg) { 1395 if (status == null) { 1396 log.debug("showStatus(): status area is null"); 1397 return; 1398 } 1399 1400 status.append(msg); 1401 status.append("\n"); 1402 } 1403 1404 /** 1405 * Display error message 1406 * 1407 * @param errMsg 1408 * the error message to display 1409 */ 1410 @Override 1411 public void showError(String errMsg) { 1412 if (status == null) { 1413 log.debug("showError(): status area is null"); 1414 return; 1415 } 1416 1417 status.append(" *** "); 1418 status.append(errMsg); 1419 if (log.isDebugEnabled()) 1420 status.append(" - see log for more info"); 1421 status.append(" *** "); 1422 status.append("\n"); 1423 } 1424 1425 /** 1426 * Display the metadata view for an object 1427 * 1428 * @param obj 1429 * the object containing the metadata to show 1430 */ 1431 public void showMetaData(final HObject obj) { 1432 for (Control control : generalArea.getChildren()) 1433 control.dispose(); 1434 generalArea.setContent(null); 1435 1436 if (obj == null) 1437 return; 1438 1439 DataViewFactory metaDataViewFactory = null; 1440 try { 1441 metaDataViewFactory = DataViewFactoryProducer.getFactory(DataViewType.METADATA); 1442 } 1443 catch (Exception ex) { 1444 log.debug("showMetaData(): error occurred while instantiating MetaDataView factory class", ex); 1445 this.showError("Error occurred while instantiating MetaDataView factory class"); 1446 return; 1447 } 1448 1449 if (metaDataViewFactory == null) { 1450 log.debug("showMetaData(): MetaDataView factory is null"); 1451 return; 1452 } 1453 1454 MetaDataView theView; 1455 try { 1456 theView = metaDataViewFactory.getMetaDataView(generalArea, this, obj); 1457 1458 if (theView == null) { 1459 log.debug("showMetaData(): error occurred while instantiating MetaDataView class"); 1460 this.showError("Error occurred while instantiating MetaDataView class"); 1461 return; 1462 } 1463 } 1464 catch (ClassNotFoundException ex) { 1465 log.debug("showMetaData(): no suitable MetaDataView class found"); 1466 this.showError("Unable to find suitable MetaDataView class"); 1467 return; 1468 } 1469 } 1470 1471 /** 1472 * close the file currently selected in the application 1473 * 1474 * @param theFile 1475 * the file selected or specified 1476 */ 1477 public void closeFile(FileFormat theFile) { 1478 if (theFile == null) { 1479 display.beep(); 1480 Tools.showError(mainWindow, "Close", "Select a file to close"); 1481 return; 1482 } 1483 1484 // Close all the data windows of this file 1485 Shell[] views = display.getShells(); 1486 if (views != null) { 1487 for (int i = 0; i < views.length; i++) { 1488 Object shellData = views[i].getData(); 1489 1490 if (!(shellData instanceof DataView)) 1491 continue; 1492 1493 if ((DataView) shellData != null) { 1494 HObject obj = ((DataView) shellData).getDataObject(); 1495 1496 if (obj == null || obj.getFileFormat() == null) 1497 continue; 1498 1499 if (obj.getFileFormat().equals(theFile)) { 1500 views[i].dispose(); 1501 views[i] = null; 1502 } 1503 } 1504 } 1505 } 1506 1507 int index = urlBar.getSelectionIndex(); 1508 if (index >= 0) { 1509 String fName = urlBar.getItem(urlBar.getSelectionIndex()); 1510 if (theFile.getFilePath().equals(fName)) { 1511 currentFile = null; 1512 urlBar.setText(""); 1513 } 1514 } 1515 1516 try { 1517 treeView.closeFile(theFile); 1518 } 1519 catch (Exception ex) { 1520 // Intentional 1521 } 1522 1523 for (Control control : generalArea.getChildren()) 1524 control.dispose(); 1525 generalArea.setContent(null); 1526 1527 System.gc(); 1528 } 1529 1530 /** 1531 * Write the change of data to the given file. 1532 * 1533 * @param theFile 1534 * The file to be updated. 1535 */ 1536 public void writeDataToFile(FileFormat theFile) { 1537 try { 1538 Shell[] openShells = display.getShells(); 1539 1540 if (openShells != null) { 1541 for (int i = 0; i < openShells.length; i++) { 1542 DataView theView = (DataView) openShells[i].getData(); 1543 1544 if (theView instanceof TableView) { 1545 TableView tableView = (TableView) theView; 1546 FileFormat file = tableView.getDataObject().getFileFormat(); 1547 if (file.equals(theFile)) 1548 tableView.updateValueInFile(); 1549 } 1550 } 1551 } 1552 } 1553 catch (Exception ex) { 1554 display.beep(); 1555 Tools.showError(mainWindow, "Save", ex.getMessage()); 1556 } 1557 } 1558 1559 @Override 1560 public void addDataView(DataView dataView) { 1561 if (dataView == null || dataView instanceof MetaDataView) 1562 return; 1563 1564 // Check if the data content is already displayed 1565 Shell[] shellList = display.getShells(); 1566 if (shellList != null) { 1567 for (int i = 0; i < shellList.length; i++) { 1568 if (dataView.equals(shellList[i].getData()) && shellList[i].isVisible()) { 1569 showWindow(shellList[i]); 1570 return; 1571 } 1572 } 1573 } 1574 1575 // First window being added 1576 if (shellList != null && shellList.length == 2) 1577 setEnabled(Arrays.asList(windowMenu.getItems()), true); 1578 1579 HObject obj = dataView.getDataObject(); 1580 String fullPath = ((obj.getPath() == null) ? "" : obj.getPath()) + ((obj.getName() == null) ? "" : obj.getName()); 1581 1582 MenuItem item = new MenuItem(windowMenu, SWT.PUSH); 1583 item.setText(fullPath); 1584 item.addSelectionListener(new SelectionAdapter() { 1585 @Override 1586 public void widgetSelected(SelectionEvent e) { 1587 Shell[] sList = display.getShells(); 1588 1589 for (int i = 0; i < sList.length; i++) { 1590 DataView view = (DataView) sList[i].getData(); 1591 1592 if (view != null) { 1593 HObject obj = view.getDataObject(); 1594 1595 if (obj.getFullName().equals(((MenuItem) e.widget).getText())) 1596 showWindow(sList[i]); 1597 } 1598 } 1599 } 1600 }); 1601 1602 mainWindow.setCursor(null); 1603 } 1604 1605 @Override 1606 public void removeDataView(DataView dataView) { 1607 if (mainWindow.isDisposed()) 1608 return; 1609 1610 HObject obj = dataView.getDataObject(); 1611 if (obj == null) 1612 return; 1613 1614 MenuItem[] items = windowMenu.getItems(); 1615 for (int i = 0; i < items.length; i++) { 1616 if(items[i].getText().equals(obj.getFullName())) 1617 items[i].dispose(); 1618 } 1619 1620 // Last window being closed 1621 if (display.getShells().length == 2) 1622 for (MenuItem item : windowMenu.getItems()) item.setEnabled(false); 1623 } 1624 1625 @Override 1626 public DataView getDataView(HObject dataObject) { 1627 Shell[] openShells = display.getShells(); 1628 DataView view = null; 1629 HObject currentObj = null; 1630 FileFormat currentDataViewFile = null; 1631 1632 for (int i = 0; i < openShells.length; i++) { 1633 view = (DataView) openShells[i].getData(); 1634 1635 if (view != null) { 1636 currentObj = view.getDataObject(); 1637 if (currentObj == null) 1638 continue; 1639 1640 currentDataViewFile = currentObj.getFileFormat(); 1641 1642 if (currentObj.equals(dataObject) && currentDataViewFile.equals(dataObject.getFileFormat())) 1643 return view; 1644 } 1645 } 1646 1647 return null; 1648 } 1649 1650 /** 1651 * Set the testing state that determines if HDFView 1652 * is being executed for GUI testing. 1653 * 1654 * @param testing 1655 * Provides SWTBot native dialog compatibility 1656 * workarounds if set to true. 1657 */ 1658 public void setTestState(boolean testing) { 1659 isTesting = testing; 1660 } 1661 1662 /** 1663 * Get the testing state that determines if HDFView 1664 * is being executed for GUI testing. 1665 * 1666 * @return true if HDFView is being executed for GUI testing. 1667 */ 1668 public boolean getTestState() { 1669 return isTesting; 1670 } 1671 1672 /** 1673 * Set default UI fonts. 1674 */ 1675 private void updateFont(Font font) { 1676 if (currentFont != null) 1677 currentFont.dispose(); 1678 1679 log.trace("updateFont():"); 1680 currentFont = font; 1681 1682 mainWindow.setFont(font); 1683 recentFilesButton.setFont(font); 1684 recentFilesButton.requestLayout(); 1685 urlBar.setFont(font); 1686 urlBar.requestLayout(); 1687 clearTextButton.setFont(font); 1688 clearTextButton.requestLayout(); 1689 status.setFont(font); 1690 1691 // On certain platforms the url_bar items don't update their size after 1692 // a font change. Removing and replacing them fixes this. 1693 for (String item : urlBar.getItems()) { 1694 urlBar.remove(item); 1695 urlBar.add(item); 1696 } 1697 1698 treeArea.setFont(font); 1699 treeArea.requestLayout(); 1700 for (Control control : treeArea.getChildren()) { 1701 control.setFont(font); 1702 control.requestLayout(); 1703 } 1704 1705 generalArea.setFont(font); 1706 generalArea.requestLayout(); 1707 for (Control control : generalArea.getChildren()) { 1708 control.setFont(font); 1709 control.requestLayout(); 1710 } 1711 1712 if (treeView.getSelectedFile() != null) 1713 urlBar.select(0); 1714 1715 if (treeView instanceof DefaultTreeView) 1716 ((DefaultTreeView) treeView).updateFont(font); 1717 1718 Shell[] shellList = display.getShells(); 1719 if (shellList != null) { 1720 for (int i = 0; i < shellList.length; i++) { 1721 shellList[i].setFont(font); 1722 shellList[i].requestLayout(); 1723 } 1724 } 1725 1726 mainWindow.requestLayout(); 1727 } 1728 1729 /** 1730 * Bring window to the front. 1731 * 1732 * @param name 1733 * the name of the window to show. 1734 */ 1735 private void showWindow(final Shell shell) { 1736 shell.getDisplay().asyncExec(new Runnable() { 1737 @Override 1738 public void run() { 1739 shell.forceActive(); 1740 } 1741 }); 1742 } 1743 1744 /** 1745 * Cascade all windows. 1746 */ 1747 private void cascadeWindows() { 1748 Shell[] sList = display.getShells(); 1749 1750 // Return if main window (shell) is the only open shell 1751 if (sList.length <= 1) 1752 return; 1753 1754 Shell shell = null; 1755 1756 Rectangle bounds = Display.getCurrent().getPrimaryMonitor().getClientArea(); 1757 int w = Math.max(50, bounds.width - 100); 1758 int h = Math.max(50, bounds.height - 100); 1759 1760 int x = bounds.x; 1761 int y = bounds.y; 1762 1763 for (int i = 0; i < sList.length; i++) { 1764 shell = sList[i]; 1765 shell.setBounds(x, y, w, h); 1766 shell.setActive(); 1767 x += 20; 1768 y += 20; 1769 } 1770 } 1771 1772 /** 1773 * Tile all windows. 1774 */ 1775 private void tileWindows() { 1776 Shell[] sList = display.getShells(); 1777 1778 // Return if main window (shell) is the only open shell 1779 if (sList.length <= 1) 1780 return; 1781 1782 int x = 0; 1783 int y = 0; 1784 int idx = 0; 1785 Shell shell = null; 1786 1787 int n = sList.length; 1788 int cols = (int) Math.sqrt(n); 1789 int rows = (int) Math.ceil((double) n / (double) cols); 1790 1791 Rectangle bounds = Display.getCurrent().getPrimaryMonitor().getClientArea(); 1792 int w = bounds.width / cols; 1793 int h = bounds.height / rows; 1794 1795 y = bounds.y; 1796 for (int i = 0; i < rows; i++) { 1797 x = bounds.x; 1798 1799 for (int j = 0; j < cols; j++) { 1800 idx = i * cols + j; 1801 if (idx >= n) 1802 return; 1803 1804 shell = sList[idx]; 1805 shell.setBounds(x, y, w, h); 1806 shell.setActive(); 1807 x += w; 1808 } 1809 1810 y += h; 1811 } 1812 } 1813 1814 /** 1815 * Closes all windows. 1816 */ 1817 private void closeAllWindows() { 1818 Shell[] sList = display.getShells(); 1819 1820 for (int i = 0; i < sList.length; i++) { 1821 if (sList[i].equals(mainWindow)) continue; 1822 sList[i].dispose(); 1823 } 1824 } 1825 1826 /* Enable and disable GUI components */ 1827 private static void setEnabled(List<MenuItem> list, boolean b) { 1828 Iterator<MenuItem> it = list.iterator(); 1829 1830 while (it.hasNext()) 1831 it.next().setEnabled(b); 1832 } 1833 1834 /** Open local file */ 1835 private void openLocalFile(String filename, int fileAccessID) { 1836 log.trace("openLocalFile {},{}",filename, fileAccessID); 1837 1838 /* 1839 * If given a specific access mode, use it without changing it. If not given a 1840 * specific access mode, check the current status of the "is read only" property 1841 * to determine how to open the file. This is to allow one time overrides of the 1842 * default file access mode when opening a file. 1843 */ 1844 int accessMode = fileAccessID; 1845 if (accessMode < 0) { 1846 if (ViewProperties.isReadOnly()) 1847 accessMode = FileFormat.READ; 1848 else if (ViewProperties.isReadSWMR()) 1849 accessMode = FileFormat.READ | FileFormat.MULTIREAD; 1850 else 1851 accessMode = FileFormat.WRITE; 1852 } 1853 1854 String[] selectedFilenames = null; 1855 File[] chosenFiles = null; 1856 1857 if (filename != null) { 1858 File file = new File(filename); 1859 if(!file.exists()) { 1860 Tools.showError(mainWindow, "Open", "File " + filename + " does not exist."); 1861 return; 1862 } 1863 1864 if(file.isDirectory()) { 1865 currentDir = filename; 1866 openLocalFile(null, -1); 1867 } 1868 else { 1869 currentFile = filename; 1870 1871 try { 1872 treeView.openFile(filename, accessMode); 1873 } 1874 catch (Exception ex) { 1875 try { 1876 treeView.openFile(filename, FileFormat.READ); 1877 } 1878 catch (Exception ex2) { 1879 display.beep(); 1880 urlBar.deselectAll(); 1881 Tools.showError(mainWindow, "Open", "Failed to open file " + filename + "\n" + ex2); 1882 currentFile = null; 1883 } 1884 } 1885 } 1886 1887 try { 1888 urlBar.remove(filename); 1889 } 1890 catch (Exception ex) { 1891 log.trace("unable to remove {} from urlBar", filename); 1892 } 1893 1894 // first entry is always the workdir 1895 urlBar.add(filename, 1); 1896 urlBar.select(1); 1897 } 1898 else { 1899 if (!isTesting) { 1900 log.trace("openLocalFile filename is null"); 1901 FileDialog fChooser = new FileDialog(mainWindow, SWT.OPEN | SWT.MULTI); 1902 String modeStr = "Read/Write"; 1903 boolean isSWMRFile = (FileFormat.MULTIREAD == (accessMode & FileFormat.MULTIREAD)); 1904 if (isSWMRFile) 1905 modeStr = "SWMR Read-only"; 1906 else if (accessMode == FileFormat.READ) 1907 modeStr = "Read-only"; 1908 fChooser.setText(mainWindow.getText() + " - Open File " + modeStr); 1909 fChooser.setFilterPath(currentDir); 1910 1911 DefaultFileFilter filter = DefaultFileFilter.getFileFilter(); 1912 fChooser.setFilterExtensions(new String[] {"*", filter.getExtensions()}); 1913 fChooser.setFilterNames(new String[] {"All Files", filter.getDescription()}); 1914 fChooser.setFilterIndex(1); 1915 1916 fChooser.open(); 1917 1918 selectedFilenames = fChooser.getFileNames(); 1919 if(selectedFilenames.length <= 0) 1920 return; 1921 1922 chosenFiles = new File[selectedFilenames.length]; 1923 for(int i = 0; i < chosenFiles.length; i++) { 1924 log.trace("openLocalFile selectedFilenames[{}]: {}",i,selectedFilenames[i]); 1925 chosenFiles[i] = new File(fChooser.getFilterPath() + File.separator + selectedFilenames[i]); 1926 1927 if(!chosenFiles[i].exists()) { 1928 Tools.showError(mainWindow, "Open", "File " + chosenFiles[i].getName() + " does not exist."); 1929 continue; 1930 } 1931 1932 if (chosenFiles[i].isDirectory()) 1933 currentDir = chosenFiles[i].getPath(); 1934 else 1935 currentDir = chosenFiles[i].getParent(); 1936 1937 try { 1938 urlBar.remove(chosenFiles[i].getAbsolutePath()); 1939 } 1940 catch (Exception ex) { 1941 log.trace("unable to remove {} from urlBar", chosenFiles[i].getAbsolutePath()); 1942 } 1943 1944 // first entry is always the workdir 1945 urlBar.add(chosenFiles[i].getAbsolutePath(), 1); 1946 urlBar.select(1); 1947 1948 log.trace("openLocalFile treeView.openFile(accessMode={} chosenFiles[{}]: {}",accessMode,i,chosenFiles[i].getAbsolutePath()); 1949 try { 1950 treeView.openFile(chosenFiles[i].getAbsolutePath(), accessMode + FileFormat.OPEN_NEW); 1951 } 1952 catch (Exception ex) { 1953 try { 1954 treeView.openFile(chosenFiles[i].getAbsolutePath(), FileFormat.READ); 1955 } 1956 catch (Exception ex2) { 1957 display.beep(); 1958 urlBar.deselectAll(); 1959 Tools.showError(mainWindow, "Open", "Failed to open file " + selectedFilenames[i] + "\n" + ex2); 1960 currentFile = null; 1961 } 1962 } 1963 } 1964 1965 currentFile = chosenFiles[0].getAbsolutePath(); 1966 } 1967 else { 1968 // Prepend test file directory to filename 1969 String fName = currentDir + File.separator + new InputDialog(mainWindow, "Enter a file name", "").open(); 1970 1971 File chosenFile = new File(fName); 1972 1973 if(!chosenFile.exists()) { 1974 Tools.showError(mainWindow, "Open", "File " + chosenFile.getName() + " does not exist."); 1975 return; 1976 } 1977 1978 if (chosenFile.isDirectory()) 1979 currentDir = chosenFile.getPath(); 1980 else 1981 currentDir = chosenFile.getParent(); 1982 1983 try { 1984 urlBar.remove(chosenFile.getAbsolutePath()); 1985 } 1986 catch (Exception ex) { 1987 log.trace("unable to remove {} from urlBar", chosenFile.getAbsolutePath()); 1988 } 1989 1990 // first entry is always the workdir 1991 urlBar.add(chosenFile.getAbsolutePath(), 1); 1992 urlBar.select(1); 1993 1994 log.trace("openLocalFile treeView.openFile(chosenFile[{}]: {}", chosenFile.getAbsolutePath(), accessMode + FileFormat.OPEN_NEW); 1995 try { 1996 treeView.openFile(chosenFile.getAbsolutePath(), accessMode + FileFormat.OPEN_NEW); 1997 } 1998 catch (Exception ex) { 1999 try { 2000 treeView.openFile(chosenFile.getAbsolutePath(), FileFormat.READ); 2001 } 2002 catch (Exception ex2) { 2003 display.beep(); 2004 urlBar.deselectAll(); 2005 Tools.showError(mainWindow, "Open", "Failed to open file " + chosenFile + "\n" + ex2); 2006 currentFile = null; 2007 } 2008 } 2009 2010 currentFile = chosenFile.getAbsolutePath(); 2011 } 2012 } 2013 } 2014 2015 /** Load remote file and save it to local temporary directory */ 2016 private String openRemoteFile(String urlStr) { 2017 if (urlStr == null) 2018 return null; 2019 2020 String localFile = null; 2021 2022 if(urlStr.startsWith("http://")) 2023 localFile = urlStr.substring(7); 2024 else if (urlStr.startsWith("https://")) 2025 localFile = urlStr.substring(8); 2026 else if (urlStr.startsWith("ftp://")) 2027 localFile = urlStr.substring(6); 2028 else 2029 return null; 2030 2031 localFile = localFile.replace('/', '@'); 2032 localFile = localFile.replace('\\', '@'); 2033 2034 // Search the local file cache 2035 String tmpDir = System.getProperty("java.io.tmpdir"); 2036 2037 File tmpFile = new File(tmpDir); 2038 if (!tmpFile.canWrite()) 2039 tmpDir = System.getProperty("user.home"); 2040 2041 localFile = tmpDir + File.separator + localFile; 2042 2043 tmpFile = new File(localFile); 2044 if (tmpFile.exists()) 2045 return localFile; 2046 2047 URL url = null; 2048 2049 try { 2050 url = new URL(urlStr); 2051 } 2052 catch (Exception ex) { 2053 url = null; 2054 display.beep(); 2055 Tools.showError(mainWindow, "Open", ex.getMessage()); 2056 return null; 2057 } 2058 2059 try (BufferedInputStream in = new BufferedInputStream(url.openStream())) { 2060 try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(tmpFile))) { 2061 mainWindow.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 2062 byte[] buff = new byte[512]; // set default buffer size to 512 2063 int n = 0; 2064 while ((n = in.read(buff)) > 0) 2065 out.write(buff, 0, n); 2066 } 2067 catch (Exception ex) { 2068 log.debug("Remote file: ", ex); 2069 throw ex; 2070 } 2071 } 2072 catch (Exception ex) { 2073 display.beep(); 2074 Tools.showError(mainWindow, "Open", ex.getMessage()); 2075 // Want to call setCursor always 2076 localFile = null; 2077 } 2078 2079 mainWindow.setCursor(null); 2080 2081 return localFile; 2082 } 2083 2084 private void convertFile(String typeFrom, String typeTo) { 2085 ImageConversionDialog dialog = new ImageConversionDialog(mainWindow, typeFrom, typeTo, 2086 currentDir, treeView.getCurrentFiles()); 2087 dialog.open(); 2088 2089 if (dialog.isFileConverted()) { 2090 String filename = dialog.getConvertedFile(); 2091 File theFile = new File(filename); 2092 2093 if (!theFile.exists()) 2094 return; 2095 2096 currentDir = theFile.getParentFile().getAbsolutePath(); 2097 currentFile = theFile.getAbsolutePath(); 2098 2099 try { 2100 treeView.openFile(filename, FileFormat.WRITE); 2101 2102 try { 2103 urlBar.remove(filename); 2104 } 2105 catch (Exception ex) { 2106 log.trace("unable to remove {} from urlBar", filename); 2107 } 2108 2109 // first entry is always the workdir 2110 urlBar.add(filename, 1); 2111 urlBar.select(1); 2112 } 2113 catch (Exception ex) { 2114 showError(ex.toString()); 2115 } 2116 } 2117 } 2118 2119 private void registerFileFormat() { 2120 String msg = "Register a new file format by \nKEY:FILE_FORMAT:FILE_EXTENSION\n" 2121 + "where, KEY: the unique identifier for the file format" 2122 + "\n FILE_FORMAT: the full class name of the file format" 2123 + "\n FILE_EXTENSION: the file extension for the file format" + "\n\nFor example, " 2124 + "\n\t to add NetCDF, \"NetCDF:hdf.object.nc2.NC2File:nc\"" 2125 + "\n\t to add FITS, \"FITS:hdf.object.fits.FitsFile:fits\"\n\n"; 2126 2127 // TODO:Add custom HDFLarge icon to dialog 2128 InputDialog dialog = new InputDialog(mainWindow, "Register a file format", msg, SWT.ICON_INFORMATION); 2129 2130 String str = dialog.open(); 2131 2132 if ((str == null) || (str.length() < 1)) 2133 return; 2134 2135 int idx1 = str.indexOf(':'); 2136 int idx2 = str.lastIndexOf(':'); 2137 2138 if ((idx1 < 0) || (idx2 <= idx1)) { 2139 Tools.showError(mainWindow, "Register File Format", "Failed to register " + str 2140 + "\n\nMust in the form of KEY:FILE_FORMAT:FILE_EXTENSION"); 2141 return; 2142 } 2143 2144 String key = str.substring(0, idx1); 2145 String className = str.substring(idx1 + 1, idx2); 2146 String extension = str.substring(idx2 + 1); 2147 2148 // Check if the file format has been registered or the key is taken. 2149 String theKey = null; 2150 String theClassName = null; 2151 Enumeration<?> localEnum = FileFormat.getFileFormatKeys(); 2152 while (localEnum.hasMoreElements()) { 2153 theKey = (String) localEnum.nextElement(); 2154 if (theKey.endsWith(key)) { 2155 Tools.showError(mainWindow, "Register File Format", "Invalid key: " + key + " is taken."); 2156 return; 2157 } 2158 2159 theClassName = FileFormat.getFileFormat(theKey).getClass().getName(); 2160 if (theClassName.endsWith(className)) { 2161 Tools.showError(mainWindow, "Register File Format", "The file format has already been registered: " + className); 2162 return; 2163 } 2164 } 2165 2166 // Enables use of JHDF5 in JNLP (Web Start) applications, the system 2167 // class loader with reflection first. 2168 Class<?> theClass = null; 2169 try { 2170 theClass = Class.forName(className); 2171 } 2172 catch (Exception ex) { 2173 try { 2174 theClass = ViewProperties.loadExtClass().loadClass(className); 2175 } 2176 catch (Exception ex2) { 2177 theClass = null; 2178 } 2179 } 2180 2181 if (theClass == null) 2182 return; 2183 2184 try { 2185 Object theObject = theClass.newInstance(); 2186 if (theObject instanceof FileFormat) 2187 FileFormat.addFileFormat(key, (FileFormat) theObject); 2188 } 2189 catch (Exception ex) { 2190 Tools.showError(mainWindow, "Register File Format", "Failed to register " + str + "\n\n" + ex); 2191 return; 2192 } 2193 2194 if ((extension != null) && (extension.length() > 0)) { 2195 extension = extension.trim(); 2196 String ext = ViewProperties.getFileExtension(); 2197 ext += ", " + extension; 2198 ViewProperties.setFileExtension(ext); 2199 } 2200 } 2201 2202 private void unregisterFileFormat() { 2203 Enumeration<?> keys = FileFormat.getFileFormatKeys(); 2204 ArrayList<Object> keyList = new ArrayList<>(); 2205 2206 while (keys.hasMoreElements()) 2207 keyList.add(keys.nextElement()); 2208 2209 String theKey = new UnregisterFileFormatDialog(mainWindow, SWT.NONE, keyList).open(); 2210 2211 if (theKey == null) 2212 return; 2213 2214 FileFormat.removeFileFormat(theKey); 2215 } 2216 2217 private class LibraryVersionDialog extends Dialog 2218 { 2219 private String message; 2220 2221 public LibraryVersionDialog(Shell parent, String libType) { 2222 super(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); 2223 2224 if (libType.equals(FileFormat.FILE_TYPE_HDF4)) 2225 setMessage("HDF " + HDF4_VERSION); 2226 else if (libType.equals(FileFormat.FILE_TYPE_HDF5)) 2227 setMessage("HDF5 " + HDF5_VERSION); 2228 } 2229 2230 public void setMessage(String message) { 2231 this.message = message; 2232 } 2233 2234 public void open() { 2235 Shell dialog = new Shell(getParent(), getStyle()); 2236 dialog.setFont(currentFont); 2237 dialog.setText("HDF Library Version"); 2238 2239 createContents(dialog); 2240 2241 dialog.pack(); 2242 2243 Point computedSize = dialog.computeSize(SWT.DEFAULT, SWT.DEFAULT); 2244 dialog.setSize(computedSize.x + 50, computedSize.y + 50); 2245 2246 // Center the window relative to the main HDFView window 2247 Point winCenter = new Point( 2248 mainWindow.getBounds().x + (mainWindow.getBounds().width / 2), 2249 mainWindow.getBounds().y + (mainWindow.getBounds().height / 2)); 2250 2251 dialog.setLocation(winCenter.x - (dialog.getSize().x / 2), winCenter.y - (dialog.getSize().y / 2)); 2252 2253 dialog.open(); 2254 2255 Display display = getParent().getDisplay(); 2256 while (!dialog.isDisposed()) { 2257 if (!display.readAndDispatch()) 2258 display.sleep(); 2259 } 2260 } 2261 2262 private void createContents(final Shell shell) { 2263 shell.setLayout(new GridLayout(2, false)); 2264 2265 Image hdfImage = ViewProperties.getLargeHdfIcon(); 2266 2267 Label imageLabel = new Label(shell, SWT.CENTER); 2268 imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 2269 imageLabel.setImage(hdfImage); 2270 2271 Label versionLabel = new Label(shell, SWT.CENTER); 2272 versionLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false)); 2273 versionLabel.setFont(currentFont); 2274 versionLabel.setText(message); 2275 2276 // Draw HDF Icon and Version string 2277 Composite buttonComposite = new Composite(shell, SWT.NONE); 2278 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 2279 RowLayout buttonLayout = new RowLayout(); 2280 buttonLayout.center = true; 2281 buttonLayout.justify = true; 2282 buttonLayout.type = SWT.HORIZONTAL; 2283 buttonComposite.setLayout(buttonLayout); 2284 2285 Button okButton = new Button(buttonComposite, SWT.PUSH); 2286 okButton.setFont(currentFont); 2287 okButton.setText(" &OK "); 2288 shell.setDefaultButton(okButton); 2289 okButton.addSelectionListener(new SelectionAdapter() { 2290 @Override 2291 public void widgetSelected(SelectionEvent e) { 2292 shell.dispose(); 2293 } 2294 }); 2295 } 2296 } 2297 2298 private class JavaVersionDialog extends Dialog 2299 { 2300 public JavaVersionDialog(Shell parent) { 2301 super(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); 2302 } 2303 2304 public void open() { 2305 final Shell dialog = new Shell(getParent(), getStyle()); 2306 dialog.setFont(currentFont); 2307 dialog.setText("HDFView Java Version"); 2308 dialog.setLayout(new GridLayout(2, false)); 2309 2310 Image hdfImage = ViewProperties.getLargeHdfIcon(); 2311 2312 Label imageLabel = new Label(dialog, SWT.CENTER); 2313 imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 2314 imageLabel.setImage(hdfImage); 2315 2316 Label versionLabel = new Label(dialog, SWT.CENTER); 2317 versionLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false)); 2318 versionLabel.setFont(currentFont); 2319 versionLabel.setText(JAVA_VER_INFO); 2320 2321 Composite buttonComposite = new Composite(dialog, SWT.NONE); 2322 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 2323 RowLayout buttonLayout = new RowLayout(); 2324 buttonLayout.center = true; 2325 buttonLayout.justify = true; 2326 buttonLayout.type = SWT.HORIZONTAL; 2327 buttonComposite.setLayout(buttonLayout); 2328 2329 Button okButton = new Button(buttonComposite, SWT.PUSH); 2330 okButton.setFont(currentFont); 2331 okButton.setText(" &OK "); 2332 dialog.setDefaultButton(okButton); 2333 okButton.addSelectionListener(new SelectionAdapter() { 2334 @Override 2335 public void widgetSelected(SelectionEvent e) { 2336 dialog.dispose(); 2337 } 2338 }); 2339 2340 dialog.pack(); 2341 2342 Point computedSize = dialog.computeSize(SWT.DEFAULT, SWT.DEFAULT); 2343 dialog.setSize(computedSize.x + 50, computedSize.y + 50); 2344 2345 // Center the window relative to the main HDFView window 2346 Point winCenter = new Point( 2347 mainWindow.getBounds().x + (mainWindow.getBounds().width / 2), 2348 mainWindow.getBounds().y + (mainWindow.getBounds().height / 2)); 2349 2350 dialog.setLocation(winCenter.x - (dialog.getSize().x / 2), winCenter.y - (dialog.getSize().y / 2)); 2351 2352 dialog.open(); 2353 2354 Display openDisplay = getParent().getDisplay(); 2355 while (!dialog.isDisposed()) { 2356 if (!openDisplay.readAndDispatch()) 2357 openDisplay.sleep(); 2358 } 2359 } 2360 } 2361 2362 private class SupportedFileFormatsDialog extends Dialog 2363 { 2364 public SupportedFileFormatsDialog(Shell parent) { 2365 super(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); 2366 } 2367 2368 public void open() { 2369 final Shell dialog = new Shell(getParent(), getStyle()); 2370 dialog.setFont(currentFont); 2371 dialog.setText("Supported File Formats"); 2372 dialog.setLayout(new GridLayout(2, false)); 2373 2374 Image hdfImage = ViewProperties.getLargeHdfIcon(); 2375 2376 Label imageLabel = new Label(dialog, SWT.CENTER); 2377 imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 2378 imageLabel.setImage(hdfImage); 2379 2380 Enumeration<?> formatKeys = FileFormat.getFileFormatKeys(); 2381 2382 StringBuilder formats = new StringBuilder("\nSupported File Formats: \n"); 2383 while (formatKeys.hasMoreElements()) 2384 formats.append(" ").append(formatKeys.nextElement()).append("\n"); 2385 formats.append("\n"); 2386 2387 Label formatsLabel = new Label(dialog, SWT.LEFT); 2388 formatsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false)); 2389 formatsLabel.setFont(currentFont); 2390 formatsLabel.setText(formats.toString()); 2391 2392 Composite buttonComposite = new Composite(dialog, SWT.NONE); 2393 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 2394 RowLayout buttonLayout = new RowLayout(); 2395 buttonLayout.center = true; 2396 buttonLayout.justify = true; 2397 buttonLayout.type = SWT.HORIZONTAL; 2398 buttonComposite.setLayout(buttonLayout); 2399 2400 Button okButton = new Button(buttonComposite, SWT.PUSH); 2401 okButton.setFont(currentFont); 2402 okButton.setText(" &OK "); 2403 dialog.setDefaultButton(okButton); 2404 okButton.addSelectionListener(new SelectionAdapter() { 2405 @Override 2406 public void widgetSelected(SelectionEvent e) { 2407 dialog.dispose(); 2408 } 2409 }); 2410 2411 dialog.pack(); 2412 2413 Point computedSize = dialog.computeSize(SWT.DEFAULT, SWT.DEFAULT); 2414 dialog.setSize(computedSize.x + 50, computedSize.y + 50); 2415 2416 // Center the window relative to the main HDFView window 2417 Point winCenter = new Point( 2418 mainWindow.getBounds().x + (mainWindow.getBounds().width / 2), 2419 mainWindow.getBounds().y + (mainWindow.getBounds().height / 2)); 2420 2421 dialog.setLocation(winCenter.x - (dialog.getSize().x / 2), winCenter.y - (dialog.getSize().y / 2)); 2422 2423 dialog.open(); 2424 2425 Display openDisplay = getParent().getDisplay(); 2426 while (!dialog.isDisposed()) { 2427 if (!openDisplay.readAndDispatch()) 2428 openDisplay.sleep(); 2429 } 2430 } 2431 } 2432 2433 private class AboutDialog extends Dialog 2434 { 2435 public AboutDialog(Shell parent) { 2436 super(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); 2437 } 2438 2439 public void open() { 2440 final Shell dialog = new Shell(getParent(), getStyle()); 2441 dialog.setFont(currentFont); 2442 dialog.setText("About HDFView"); 2443 dialog.setLayout(new GridLayout(2, false)); 2444 2445 Image hdfImage = ViewProperties.getLargeHdfIcon(); 2446 2447 Label imageLabel = new Label(dialog, SWT.CENTER); 2448 imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 2449 imageLabel.setImage(hdfImage); 2450 2451 Label aboutLabel = new Label(dialog, SWT.LEFT); 2452 aboutLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false)); 2453 aboutLabel.setFont(currentFont); 2454 aboutLabel.setText(ABOUT_HDFVIEW); 2455 2456 Composite buttonComposite = new Composite(dialog, SWT.NONE); 2457 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 2458 RowLayout buttonLayout = new RowLayout(); 2459 buttonLayout.center = true; 2460 buttonLayout.justify = true; 2461 buttonLayout.type = SWT.HORIZONTAL; 2462 buttonComposite.setLayout(buttonLayout); 2463 2464 Button okButton = new Button(buttonComposite, SWT.PUSH); 2465 okButton.setFont(currentFont); 2466 okButton.setText(" &OK "); 2467 dialog.setDefaultButton(okButton); 2468 okButton.addSelectionListener(new SelectionAdapter() { 2469 @Override 2470 public void widgetSelected(SelectionEvent e) { 2471 dialog.dispose(); 2472 } 2473 }); 2474 2475 dialog.pack(); 2476 2477 Point computedSize = dialog.computeSize(SWT.DEFAULT, SWT.DEFAULT); 2478 dialog.setSize(computedSize.x + 50, computedSize.y + 50); 2479 2480 // Center the window relative to the main HDFView window 2481 Point winCenter = new Point( 2482 mainWindow.getBounds().x + (mainWindow.getBounds().width / 2), 2483 mainWindow.getBounds().y + (mainWindow.getBounds().height / 2)); 2484 2485 dialog.setLocation(winCenter.x - (dialog.getSize().x / 2), winCenter.y - (dialog.getSize().y / 2)); 2486 2487 dialog.open(); 2488 2489 Display openDisplay = getParent().getDisplay(); 2490 while (!dialog.isDisposed()) { 2491 if (!openDisplay.readAndDispatch()) 2492 openDisplay.sleep(); 2493 } 2494 } 2495 } 2496 2497 private class UnregisterFileFormatDialog extends Dialog 2498 { 2499 private List<Object> keyList; 2500 private String formatChoice = null; 2501 2502 public UnregisterFileFormatDialog(Shell parent, int style, List<Object> keyList) { 2503 super(parent, style); 2504 2505 this.keyList = keyList; 2506 } 2507 2508 public String open() { 2509 Shell parent = getParent(); 2510 final Shell shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM); 2511 shell.setFont(currentFont); 2512 shell.setText("Unregister a file format"); 2513 shell.setLayout(new GridLayout(2, false)); 2514 2515 Image hdfImage = ViewProperties.getLargeHdfIcon(); 2516 2517 Label imageLabel = new Label(shell, SWT.CENTER); 2518 imageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 2519 imageLabel.setImage(hdfImage); 2520 2521 2522 final Combo formatChoiceCombo = new Combo(shell, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY); 2523 formatChoiceCombo.setFont(currentFont); 2524 formatChoiceCombo.setItems(keyList.toArray(new String[0])); 2525 formatChoiceCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); 2526 formatChoiceCombo.select(0); 2527 formatChoiceCombo.addSelectionListener(new SelectionAdapter() { 2528 @Override 2529 public void widgetSelected(SelectionEvent e) { 2530 formatChoice = formatChoiceCombo.getItem(formatChoiceCombo.getSelectionIndex()); 2531 } 2532 }); 2533 2534 Composite buttonComposite = new Composite(shell, SWT.NONE); 2535 buttonComposite.setLayout(new GridLayout(2, true)); 2536 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 2537 2538 Button okButton = new Button(buttonComposite, SWT.PUSH); 2539 okButton.setFont(currentFont); 2540 okButton.setText(" &OK "); 2541 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 2542 okButton.addSelectionListener(new SelectionAdapter() { 2543 @Override 2544 public void widgetSelected(SelectionEvent e) { 2545 shell.dispose(); 2546 } 2547 }); 2548 2549 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 2550 cancelButton.setFont(currentFont); 2551 cancelButton.setText(" &Cancel "); 2552 cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 2553 cancelButton.addSelectionListener(new SelectionAdapter() { 2554 @Override 2555 public void widgetSelected(SelectionEvent e) { 2556 shell.dispose(); 2557 } 2558 }); 2559 2560 shell.pack(); 2561 2562 Point computedSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT); 2563 shell.setSize(computedSize.x + 50, computedSize.y + 50); 2564 2565 Rectangle parentBounds = parent.getBounds(); 2566 Point shellSize = shell.getSize(); 2567 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 2568 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 2569 2570 shell.open(); 2571 2572 Display openDisplay = parent.getDisplay(); 2573 while(!shell.isDisposed()) { 2574 if (!openDisplay.readAndDispatch()) 2575 openDisplay.sleep(); 2576 } 2577 2578 return formatChoice; 2579 } 2580 } 2581 2582 /** 2583 * The starting point of this application. 2584 * 2585 * <pre> 2586 * Usage: java(w) 2587 * -Dhdf.hdf5lib.H5.hdf5lib="your HDF5 library path" 2588 * -Dhdf.hdflib.HDFLibrary.hdflib="your HDF4 library path" 2589 * -root "the directory where the HDFView is installed" 2590 * -start "the directory HDFView searches for files" 2591 * -geometry or -g "the preferred window size as WIDTHxHEIGHT+XOFF+YOFF" 2592 * -java.version "show the version of jave used to build the HDFView and exit" 2593 * [filename] "the file to open" 2594 * </pre> 2595 * 2596 * @param args the command line arguments 2597 */ 2598 public static void main(String[] args) { 2599 if (display == null || display.isDisposed()) 2600 display = new Display(); 2601 2602 String rootDir = System.getProperty("hdfview.root"); 2603 if (rootDir == null) 2604 rootDir = System.getProperty("user.dir"); 2605 String startDir = System.getProperty("user.dir"); 2606 log.trace("main: rootDir = {} startDir = {}", rootDir, startDir); 2607 2608 File tmpFile = null; 2609 Monitor primaryMonitor = display.getPrimaryMonitor(); 2610 Point margin = new Point(primaryMonitor.getBounds().width, primaryMonitor.getBounds().height); 2611 2612 int j = args.length; 2613 int W = margin.x / 2; 2614 int H = margin.y; 2615 int X = 0; 2616 int Y = 0; 2617 2618 for(int i = 0; i < args.length; i++) { 2619 if ("-root".equalsIgnoreCase(args[i])) { 2620 j--; 2621 try { 2622 j--; 2623 tmpFile = new File(args[++i]); 2624 2625 if(tmpFile.isDirectory()) 2626 rootDir = tmpFile.getPath(); 2627 else if(tmpFile.isFile()) 2628 rootDir = tmpFile.getParent(); 2629 } 2630 catch (Exception ex) {} 2631 } 2632 else if ("-start".equalsIgnoreCase(args[i])) { 2633 j--; 2634 try { 2635 j--; 2636 tmpFile = new File(args[++i]); 2637 2638 if(tmpFile.isDirectory()) 2639 startDir = tmpFile.getPath(); 2640 else if(tmpFile.isFile()) 2641 startDir = tmpFile.getParent(); 2642 } 2643 catch (Exception ex) {} 2644 } 2645 else if("-g".equalsIgnoreCase(args[i]) || "-geometry".equalsIgnoreCase(args[i])) { 2646 j--; 2647 // -geometry WIDTHxHEIGHT+XOFF+YOFF 2648 try { 2649 String geom = args[++i]; 2650 j--; 2651 2652 int idx = 0; 2653 int idx2 = geom.lastIndexOf('-'); 2654 int idx3 = geom.lastIndexOf('+'); 2655 2656 idx = Math.max(idx2, idx3); 2657 if(idx > 0) { 2658 Y = Integer.parseInt(geom.substring(idx + 1)); 2659 2660 if(idx == idx2) 2661 Y = -Y; 2662 2663 geom = geom.substring(0, idx); 2664 idx2 = geom.lastIndexOf('-'); 2665 idx3 = geom.lastIndexOf('+'); 2666 idx = Math.max(idx2, idx3); 2667 2668 if(idx > 0) { 2669 X = Integer.parseInt(geom.substring(idx + 1)); 2670 2671 if(idx == idx2) 2672 X = -X; 2673 2674 geom = geom.substring(0, idx); 2675 } 2676 } 2677 2678 idx = geom.indexOf('x'); 2679 2680 if(idx > 0) { 2681 W = Integer.parseInt(geom.substring(0, idx)); 2682 H = Integer.parseInt(geom.substring(idx + 1)); 2683 } 2684 2685 } 2686 catch (Exception ex) { 2687 ex.printStackTrace(); 2688 } 2689 } 2690 else if("-java.version".equalsIgnoreCase(args[i])) { 2691 /* Set icon to ViewProperties.getLargeHdfIcon() */ 2692 Tools.showInformation(mainWindow, "Java Version", JAVA_VER_INFO); 2693 System.exit(0); 2694 } 2695 } 2696 2697 ArrayList<File> fList = new ArrayList<>(); 2698 2699 if(j >= 0) { 2700 for(int i = args.length - j; i < args.length; i++) { 2701 tmpFile = new File(args[i]); 2702 if(!tmpFile.isAbsolute()) 2703 tmpFile = new File(rootDir, args[i]); 2704 log.trace("main: filelist - file = {} ", tmpFile.getAbsolutePath()); 2705 log.trace("main: filelist - add file = {} exists={} isFile={} isDir={}", tmpFile, tmpFile.exists(), tmpFile.isFile(), tmpFile.isDirectory()); 2706 if(tmpFile.exists() && (tmpFile.isFile() || tmpFile.isDirectory())) { 2707 log.trace("main: flist - add file = {}", tmpFile.getAbsolutePath()); 2708 fList.add(new File(tmpFile.getAbsolutePath())); 2709 } 2710 } 2711 } 2712 2713 final ArrayList<File> theFileList = fList; 2714 final String the_rootDir = rootDir; 2715 final String the_startDir = startDir; 2716 final int the_X = X, the_Y = Y, the_W = W, the_H = H; 2717 2718 display.syncExec(new Runnable() { 2719 @Override 2720 public void run() { 2721 HDFView app = new HDFView(the_rootDir, the_startDir); 2722 2723 // TODO: Look for a better solution to native dialog problem 2724 app.setTestState(false); 2725 2726 app.openMainWindow(theFileList, the_W, the_H, the_X, the_Y); 2727 app.runMainWindow(); 2728 } 2729 }); 2730 } 2731}