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