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.TableView; 016 017import java.lang.reflect.Array; 018import java.lang.reflect.Constructor; 019import java.math.BigInteger; 020import java.util.ArrayList; 021import java.util.HashMap; 022import java.util.Iterator; 023import java.util.LinkedHashSet; 024import java.util.List; 025import java.util.Set; 026import java.util.StringTokenizer; 027 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031import org.eclipse.nebula.widgets.nattable.NatTable; 032import org.eclipse.nebula.widgets.nattable.command.VisualRefreshCommand; 033import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration; 034import org.eclipse.nebula.widgets.nattable.config.EditableRule; 035import org.eclipse.nebula.widgets.nattable.config.IEditableRule; 036import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate; 037import org.eclipse.nebula.widgets.nattable.coordinate.Range; 038import org.eclipse.nebula.widgets.nattable.data.IDataProvider; 039import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider; 040import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer; 041import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer; 042import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer; 043import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer; 044import org.eclipse.nebula.widgets.nattable.layer.DataLayer; 045import org.eclipse.nebula.widgets.nattable.layer.ILayer; 046import org.eclipse.nebula.widgets.nattable.layer.ILayerListener; 047import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent; 048import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; 049import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand; 050import org.eclipse.nebula.widgets.nattable.selection.event.CellSelectionEvent; 051import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer; 052import org.eclipse.swt.SWT; 053import org.eclipse.swt.custom.ScrolledComposite; 054import org.eclipse.swt.events.DisposeEvent; 055import org.eclipse.swt.events.DisposeListener; 056import org.eclipse.swt.events.SelectionAdapter; 057import org.eclipse.swt.events.SelectionEvent; 058import org.eclipse.swt.widgets.Composite; 059import org.eclipse.swt.widgets.Menu; 060import org.eclipse.swt.widgets.MenuItem; 061import org.eclipse.swt.widgets.Shell; 062 063import hdf.object.Attribute; 064import hdf.object.DataFormat; 065import hdf.object.Dataset; 066import hdf.object.Datatype; 067import hdf.object.FileFormat; 068import hdf.object.HObject; 069import hdf.object.ScalarDS; 070import hdf.object.Utils; 071 072import hdf.hdf5lib.HDF5Constants; 073 074import hdf.object.h5.H5Datatype; 075import hdf.object.h5.H5File; 076import hdf.object.h5.H5ScalarAttr; 077import hdf.object.h5.H5ReferenceType.H5ReferenceData; 078import hdf.object.h5.H5ReferenceType; 079 080import hdf.view.HDFView; 081import hdf.view.Tools; 082import hdf.view.ViewProperties; 083import hdf.view.DataView.DataViewManager; 084import hdf.view.dialog.InputDialog; 085 086/** 087 * A class to construct a ScalarDS TableView. 088 */ 089public class DefaultScalarDSTableView extends DefaultBaseTableView implements TableView 090{ 091 private static final Logger log = LoggerFactory.getLogger(DefaultScalarDSTableView.class); 092 093 /** 094 * Constructs a ScalarDS TableView with no additional data properties. 095 * 096 * @param theView 097 * the main HDFView. 098 */ 099 public DefaultScalarDSTableView(DataViewManager theView) { 100 this(theView, null); 101 } 102 103 /** 104 * Constructs a ScalarDS TableView with the specified data properties. 105 * 106 * @param theView 107 * the main HDFView. 108 * 109 * @param dataPropertiesMap 110 * the properties on how to show the data. The map is used to allow 111 * applications to pass properties on how to display the data, such 112 * as: transposing data, showing data as characters, applying a 113 * bitmask, and etc. Predefined keys are listed at 114 * ViewProperties.DATA_VIEW_KEY. 115 */ 116 @SuppressWarnings("rawtypes") 117 public DefaultScalarDSTableView(DataViewManager theView, HashMap dataPropertiesMap) { 118 super(theView, dataPropertiesMap); 119 120 if (!shell.isDisposed()) { 121 if (System.getProperty("os.name").toLowerCase().contains("mac")) { 122 shell.setImages(ViewProperties.getHdfIcons()); 123 } 124 else { 125 shell.setImage(dataObject.getDatatype().isText() ? ViewProperties.getTextIcon() : ViewProperties.getDatasetIcon()); 126 } 127 128 shell.addDisposeListener(new DisposeListener() { 129 @Override 130 public void widgetDisposed(DisposeEvent e) { 131 if (dataObject instanceof ScalarDS) { 132 ScalarDS ds = (ScalarDS) dataObject; 133 134 /* 135 * Reload the data when it is displayed next time because the display type 136 * (table or image) may be different. 137 */ 138 if (ds.isImage()) ds.clearData(); 139 } 140 } 141 }); 142 143 viewer.addDataView(this); 144 145 shell.open(); 146 } 147 } 148 149 @Override 150 protected void loadData(DataFormat dataObject) throws Exception { 151 super.loadData(dataObject); 152 153 try { 154 if (Tools.applyBitmask(dataValue, bitmask, bitmaskOP)) { 155 isReadOnly = true; 156 String opName = "Bits "; 157 158 if (bitmaskOP == ViewProperties.BITMASK_OP.AND) 159 opName = "Bitwise AND "; 160 161 String title = indexBaseGroup.getText(); 162 title += ", " + opName + bitmask; 163 indexBaseGroup.setText(title); 164 } 165 166 dataObject.convertFromUnsignedC(); 167 168 dataValue = dataObject.getData(); 169 } 170 catch (Exception ex) { 171 log.debug("loadData(): ", ex); 172 dataValue = null; 173 throw ex; 174 } 175 176 if (dataValue == null) { 177 log.debug("loadData(): data value is null"); 178 throw new RuntimeException("data value is null"); 179 } 180 181 fillValue = dataObject.getFillValue(); 182 log.trace("loadData(): fillValue={}", fillValue); 183 184 char runtimeTypeClass = Utils.getJavaObjectRuntimeClass(dataValue); 185 log.trace("loadData(): cName={} runtimeTypeClass={}", dataValue.getClass().getName(), runtimeTypeClass); 186 187 /* 188 * Convert numerical data into character data; only possible cases are byte[] 189 * and short[] (converted from unsigned byte) 190 */ 191 if (isDisplayTypeChar && ((runtimeTypeClass == 'B') || (runtimeTypeClass == 'S'))) { 192 int n = Array.getLength(dataValue); 193 char[] charData = new char[n]; 194 for (int i = 0; i < n; i++) { 195 if (runtimeTypeClass == 'B') 196 charData[i] = (char) Array.getByte(dataValue, i); 197 else if (runtimeTypeClass == 'S') 198 charData[i] = (char) Array.getShort(dataValue, i); 199 } 200 201 dataValue = charData; 202 } 203 else if ((runtimeTypeClass == 'B') && dataObject.getDatatype().isArray()) { 204 Datatype baseType = dataObject.getDatatype().getDatatypeBase(); 205 if (baseType.isString()) 206 dataValue = Dataset.byteToString((byte[]) dataValue, (int) baseType.getDatatypeSize()); 207 } 208 } 209 210 /** 211 * Creates the menubar for the Shell. 212 */ 213 @Override 214 protected Menu createMenuBar(final Shell theShell) { 215 Menu baseMenu = super.createMenuBar(theShell); 216 MenuItem[] baseMenuItems = baseMenu.getItems(); 217 MenuItem item = null; 218 219 /***************************************************************************** 220 * * 221 * Add in a few MenuItems for importing/exporting data from/to binary files. * 222 * * 223 *****************************************************************************/ 224 225 MenuItem importExportMenuItem = null; 226 for (int i = 0; i < baseMenuItems.length; i++) 227 if (baseMenuItems[i].getText().equals("&Import/Export Data")) 228 importExportMenuItem = baseMenuItems[i]; 229 230 if (importExportMenuItem != null) { 231 Menu importExportMenu = importExportMenuItem.getMenu(); 232 MenuItem[] importExportMenuItems = importExportMenu.getItems(); 233 234 for (int i = 0; i < importExportMenuItems.length; i++) 235 if (importExportMenuItems[i].getText().equals("Export Data to")) 236 item = importExportMenuItems[i]; 237 238 if (item != null) { 239 Menu exportMenu = item.getMenu(); 240 241 MenuItem exportAsBinaryMenuItem = new MenuItem(exportMenu, SWT.CASCADE); 242 exportAsBinaryMenuItem.setText("Binary File"); 243 244 Menu exportAsBinaryMenu = new Menu(exportAsBinaryMenuItem); 245 exportAsBinaryMenuItem.setMenu(exportAsBinaryMenu); 246 247 item = new MenuItem(exportAsBinaryMenu, SWT.PUSH); 248 item.setText("Native Order"); 249 item.addSelectionListener(new SelectionAdapter() { 250 @Override 251 public void widgetSelected(SelectionEvent e) { 252 binaryOrder = 1; 253 254 try { 255 saveAsBinary(); 256 } 257 catch (Exception ex) { 258 theShell.getDisplay().beep(); 259 Tools.showError(theShell, "Export", ex.getMessage()); 260 } 261 } 262 }); 263 264 item = new MenuItem(exportAsBinaryMenu, SWT.PUSH); 265 item.setText("Little Endian"); 266 item.addSelectionListener(new SelectionAdapter() { 267 @Override 268 public void widgetSelected(SelectionEvent e) { 269 binaryOrder = 2; 270 271 try { 272 saveAsBinary(); 273 } 274 catch (Exception ex) { 275 theShell.getDisplay().beep(); 276 Tools.showError(theShell, "Export", ex.getMessage()); 277 } 278 } 279 }); 280 281 item = new MenuItem(exportAsBinaryMenu, SWT.PUSH); 282 item.setText("Big Endian"); 283 item.addSelectionListener(new SelectionAdapter() { 284 @Override 285 public void widgetSelected(SelectionEvent e) { 286 binaryOrder = 3; 287 288 try { 289 saveAsBinary(); 290 } 291 catch (Exception ex) { 292 theShell.getDisplay().beep(); 293 Tools.showError(theShell, "Export", ex.getMessage()); 294 } 295 } 296 }); 297 } 298 299 item = null; 300 for (int i = 0; i < importExportMenuItems.length; i++) 301 if (importExportMenuItems[i].getText().equals("Import Data from")) 302 item = importExportMenuItems[i]; 303 304 if (item != null) { 305 Menu importMenu = item.getMenu(); 306 307 MenuItem importAsBinaryMenuItem = new MenuItem(importMenu, SWT.CASCADE); 308 importAsBinaryMenuItem.setText("Binary File"); 309 310 Menu importAsBinaryMenu = new Menu(importAsBinaryMenuItem); 311 importAsBinaryMenuItem.setMenu(importAsBinaryMenu); 312 313 item = new MenuItem(importAsBinaryMenu, SWT.PUSH); 314 item.setText("Native Order"); 315 item.setEnabled(!isReadOnly); 316 item.addSelectionListener(new SelectionAdapter() { 317 @Override 318 public void widgetSelected(SelectionEvent e) { 319 binaryOrder = 1; 320 321 try { 322 importBinaryData(); 323 } 324 catch (Exception ex) { 325 Tools.showError(theShell, "Import", ex.getMessage()); 326 } 327 } 328 }); 329 330 item = new MenuItem(importAsBinaryMenu, SWT.PUSH); 331 item.setText("Little Endian"); 332 item.setEnabled(!isReadOnly); 333 item.addSelectionListener(new SelectionAdapter() { 334 @Override 335 public void widgetSelected(SelectionEvent e) { 336 binaryOrder = 2; 337 338 try { 339 importBinaryData(); 340 } 341 catch (Exception ex) { 342 Tools.showError(theShell, "Import", ex.getMessage()); 343 } 344 } 345 }); 346 347 item = new MenuItem(importAsBinaryMenu, SWT.PUSH); 348 item.setText("Big Endian"); 349 item.setEnabled(!isReadOnly); 350 item.addSelectionListener(new SelectionAdapter() { 351 @Override 352 public void widgetSelected(SelectionEvent e) { 353 binaryOrder = 3; 354 355 try { 356 importBinaryData(); 357 } 358 catch (Exception ex) { 359 Tools.showError(theShell, "Import", ex.getMessage()); 360 } 361 } 362 }); 363 } 364 365 new MenuItem(importExportMenu, SWT.SEPARATOR); 366 367 checkFixedDataLength = new MenuItem(importExportMenu, SWT.CHECK); 368 checkFixedDataLength.setText("Fixed Data Length"); 369 checkFixedDataLength.addSelectionListener(new SelectionAdapter() { 370 @Override 371 public void widgetSelected(SelectionEvent e) { 372 if (!checkFixedDataLength.getSelection()) { 373 fixedDataLength = -1; 374 return; 375 } 376 377 String str = new InputDialog(theShell, "", 378 "Enter fixed data length when importing text data\n\n" 379 + "For example, for a text string of \"12345678\"\n\t\tenter 2," 380 + "the data will be 12, 34, 56, 78\n\t\tenter 4, the data will be" + "1234, 5678\n") 381 .open(); 382 383 if ((str == null) || (str.length() < 1)) { 384 checkFixedDataLength.setSelection(false); 385 return; 386 } 387 388 try { 389 fixedDataLength = Integer.parseInt(str); 390 } 391 catch (Exception ex) { 392 fixedDataLength = -1; 393 } 394 395 if (fixedDataLength < 1) { 396 checkFixedDataLength.setSelection(false); 397 } 398 } 399 }); 400 } 401 402 /***************************************************************************************** 403 * * 404 * Add a section for changing the way that data is displayed, e.g. as hexadecimal values * 405 * * 406 *****************************************************************************************/ 407 408 MenuItem dataDisplayMenuItem = new MenuItem(baseMenu, SWT.CASCADE); 409 dataDisplayMenuItem.setText("Data Display"); 410 411 Menu dataDisplayMenu = new Menu(theShell, SWT.DROP_DOWN); 412 dataDisplayMenuItem.setMenu(dataDisplayMenu); 413 414 checkScientificNotation = new MenuItem(dataDisplayMenu, SWT.CHECK); 415 checkScientificNotation.setText("Show Scientific Notation"); 416 checkScientificNotation.addSelectionListener(new SelectionAdapter() { 417 @Override 418 public void widgetSelected(SelectionEvent e) { 419 if (checkScientificNotation.getSelection()) { 420 if (checkCustomNotation != null) 421 checkCustomNotation.setSelection(false); 422 if (checkEnum != null) 423 checkEnum.setSelection(false); 424 if (checkHex != null) 425 checkHex.setSelection(false); 426 if (checkBin != null) 427 checkBin.setSelection(false); 428 429 numberFormat = scientificFormat; 430 showAsHex = false; 431 showAsBin = false; 432 } 433 else { 434 numberFormat = normalFormat; 435 } 436 437 updateDataConversionSettings(); 438 439 dataTable.doCommand(new VisualRefreshCommand()); 440 441 PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition(); 442 if (lastSelectedCell != null) { 443 /* 444 * Send down a cell selection event for the current cell to update the cell 445 * value labels 446 */ 447 dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition, 448 lastSelectedCell.rowPosition, false, false)); 449 } 450 } 451 }); 452 453 checkCustomNotation = new MenuItem(dataDisplayMenu, SWT.CHECK); 454 checkCustomNotation.setText("Show Custom Notation"); 455 checkCustomNotation.addSelectionListener(new SelectionAdapter() { 456 @Override 457 public void widgetSelected(SelectionEvent e) { 458 if (checkCustomNotation.getSelection()) { 459 if (checkScientificNotation != null) 460 checkScientificNotation.setSelection(false); 461 if (checkEnum != null) 462 checkEnum.setSelection(false); 463 if (checkHex != null) 464 checkHex.setSelection(false); 465 if (checkBin != null) 466 checkBin.setSelection(false); 467 468 numberFormat = customFormat; 469 showAsHex = false; 470 showAsBin = false; 471 } 472 else { 473 numberFormat = normalFormat; 474 } 475 476 updateDataConversionSettings(); 477 478 dataTable.doCommand(new VisualRefreshCommand()); 479 480 PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition(); 481 if (lastSelectedCell != null) { 482 /* 483 * Send down a cell selection event for the current cell to update the cell 484 * value labels 485 */ 486 dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition, 487 lastSelectedCell.rowPosition, false, false)); 488 } 489 } 490 }); 491 492 item = new MenuItem(dataDisplayMenu, SWT.PUSH); 493 item.setText("Create custom notation"); 494 item.addSelectionListener(new SelectionAdapter() { 495 @Override 496 public void widgetSelected(SelectionEvent e) { 497 String msg = "Create number format by pattern \nINTEGER . FRACTION E EXPONENT\nusing # for optional digits and 0 for required digits" 498 + "\nwhere, INTEGER: the pattern for the integer part" 499 + "\n FRACTION: the pattern for the fractional part" 500 + "\n EXPONENT: the pattern for the exponent part" + "\n\nFor example, " 501 + "\n\t the normalized scientific notation format is \"#.0###E0##\"" 502 + "\n\t to make the digits required \"0.00000E000\"\n\n"; 503 504 String str = (new InputDialog(theShell, "Create a custom number format", msg, customFormat.toPattern())).open(); 505 506 if ((str == null) || (str.length() < 1)) 507 return; 508 509 try { 510 customFormat.applyPattern(str); 511 } 512 catch (Exception ex) { 513 log.debug("Invalid custom number notation format: {}:", str, ex); 514 Tools.showError(shell, "Create", "Invalid custom notation format " + str); 515 } 516 } 517 }); 518 519 char runtimeTypeClass = Utils.getJavaObjectRuntimeClass(dataValue); 520 boolean isInt = (runtimeTypeClass == 'B' || runtimeTypeClass == 'S' || runtimeTypeClass == 'I' 521 || runtimeTypeClass == 'J'); 522 523 if (isInt || dataObject.getDatatype().isBitField() || dataObject.getDatatype().isOpaque()) { 524 checkHex = new MenuItem(dataDisplayMenu, SWT.CHECK); 525 checkHex.setText("Show Hexadecimal"); 526 checkHex.addSelectionListener(new SelectionAdapter() { 527 @Override 528 public void widgetSelected(SelectionEvent e) { 529 showAsHex = checkHex.getSelection(); 530 if (showAsHex) { 531 if (checkScientificNotation != null) 532 checkScientificNotation.setSelection(false); 533 if (checkCustomNotation != null) 534 checkCustomNotation.setSelection(false); 535 if (checkEnum != null) 536 checkEnum.setSelection(false); 537 if (checkBin != null) 538 checkBin.setSelection(false); 539 540 showAsBin = false; 541 numberFormat = normalFormat; 542 } 543 544 updateDataConversionSettings(); 545 546 dataTable.doCommand(new VisualRefreshCommand()); 547 548 PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition(); 549 if (lastSelectedCell != null) { 550 /* 551 * Send down a cell selection event for the current cell to update the cell 552 * value labels 553 */ 554 dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition, 555 lastSelectedCell.rowPosition, false, false)); 556 } 557 } 558 }); 559 560 checkBin = new MenuItem(dataDisplayMenu, SWT.CHECK); 561 checkBin.setText("Show Binary"); 562 checkBin.addSelectionListener(new SelectionAdapter() { 563 @Override 564 public void widgetSelected(SelectionEvent e) { 565 showAsBin = checkBin.getSelection(); 566 if (showAsBin) { 567 if (checkScientificNotation != null) 568 checkScientificNotation.setSelection(false); 569 if (checkCustomNotation != null) 570 checkCustomNotation.setSelection(false); 571 if (checkEnum != null) 572 checkEnum.setSelection(false); 573 if (checkHex != null) 574 checkHex.setSelection(false); 575 576 showAsHex = false; 577 numberFormat = normalFormat; 578 } 579 580 updateDataConversionSettings(); 581 582 dataTable.doCommand(new VisualRefreshCommand()); 583 584 PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition(); 585 if (lastSelectedCell != null) { 586 /* 587 * Send down a cell selection event for the current cell to update the cell 588 * value labels 589 */ 590 dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition, 591 lastSelectedCell.rowPosition, false, false)); 592 } 593 } 594 }); 595 596 checkEnum = new MenuItem(dataDisplayMenu, SWT.CHECK); 597 checkEnum.setText("Show Enum Values"); 598 checkEnum.addSelectionListener(new SelectionAdapter() { 599 @Override 600 public void widgetSelected(SelectionEvent e) { 601 isEnumConverted = checkEnum.getSelection(); 602 if (isEnumConverted) { 603 if (checkScientificNotation != null) 604 checkScientificNotation.setSelection(false); 605 if (checkCustomNotation != null) 606 checkCustomNotation.setSelection(false); 607 if (checkHex != null) 608 checkHex.setSelection(false); 609 if (checkBin != null) 610 checkBin.setSelection(false); 611 612 showAsBin = false; 613 showAsHex = false; 614 numberFormat = normalFormat; 615 } 616 617 updateDataConversionSettings(); 618 619 dataTable.doCommand(new VisualRefreshCommand()); 620 621 PositionCoordinate lastSelectedCell = getSelectionLayer().getLastSelectedCellPosition(); 622 if (lastSelectedCell != null) { 623 /* 624 * Send down a cell selection event for the current cell to update the cell 625 * value labels 626 */ 627 dataTable.doCommand(new SelectCellCommand(getSelectionLayer(), lastSelectedCell.columnPosition, 628 lastSelectedCell.rowPosition, false, false)); 629 } 630 } 631 }); 632 } 633 634 return baseMenu; 635 } 636 637 /** 638 * Creates a NatTable for a Scalar dataset. 639 * 640 * @param parent 641 * The parent for the NatTable 642 * @param dataObject 643 * The Scalar dataset for the NatTable to display 644 * 645 * @return The newly created NatTable 646 */ 647 @Override 648 protected NatTable createTable(Composite parent, DataFormat dataObject) { 649 // Create body layer 650 try { 651 dataProvider = DataProviderFactory.getDataProvider(dataObject, dataValue, isDataTransposed); 652 653 log.trace("createTable(): rows={} : cols={}", dataProvider.getRowCount(), dataProvider.getColumnCount()); 654 655 dataLayer = new DataLayer(dataProvider); 656 } 657 catch (Exception ex) { 658 log.debug("createTable(): failed to retrieve DataProvider for table: ", ex); 659 return null; 660 } 661 662 selectionLayer = new SelectionLayer(dataLayer); 663 final ViewportLayer viewportLayer = new ViewportLayer(selectionLayer); 664 665 dataLayer.setDefaultColumnWidth(80); 666 667 // Create the Column Header layer 668 columnHeaderDataProvider = new ScalarDSColumnHeaderDataProvider(dataObject); 669 ColumnHeaderLayer columnHeaderLayer = new ColumnHeader(new DataLayer(columnHeaderDataProvider), viewportLayer, 670 selectionLayer); 671 672 // Create the Row Header layer 673 rowHeaderDataProvider = new RowHeaderDataProvider(dataObject); 674 675 // Try to adapt row height to current font 676 int defaultRowHeight = curFont == null ? 20 : (2 * curFont.getFontData()[0].getHeight()); 677 678 DataLayer baseLayer = new DataLayer(rowHeaderDataProvider, 40, defaultRowHeight); 679 RowHeaderLayer rowHeaderLayer = new RowHeader(baseLayer, viewportLayer, selectionLayer); 680 681 // Create the Corner Layer 682 ILayer cornerLayer = new CornerLayer( 683 new DataLayer(new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider)), 684 rowHeaderLayer, columnHeaderLayer); 685 686 // Create the Grid Layer 687 GridLayer gridLayer = new EditingGridLayer(viewportLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer); 688 689 final NatTable natTable = new NatTable(parent, gridLayer, false); 690 natTable.addConfiguration(new DefaultNatTableStyleConfiguration()); 691 natTable.addLayerListener(new ScalarDSCellSelectionListener()); 692 693 // Create popup menu for region or object ref. 694 if (isStdRef || isRegRef || isObjRef) 695 natTable.addConfiguration(new RefContextMenu(natTable)); 696 697 natTable.configure(); 698 699 return natTable; 700 } 701 702 /** 703 * Returns the selected data values of the ScalarDS 704 */ 705 @Override 706 public Object getSelectedData() { 707 Object selectedData = null; 708 709 // Since NatTable returns the selected row positions as a Set<Range>, convert 710 // this to an Integer[] 711 Set<Range> rowPositions = selectionLayer.getSelectedRowPositions(); 712 log.trace("getSelectedData() rowPositions: {}", rowPositions); 713 Set<Integer> selectedRowPos = new LinkedHashSet<>(); 714 Iterator<Range> i1 = rowPositions.iterator(); 715 while (i1.hasNext()) 716 selectedRowPos.addAll(i1.next().getMembers()); 717 718 Integer[] selectedRows = selectedRowPos.toArray(new Integer[0]); 719 int[] selectedCols = selectionLayer.getSelectedColumnPositions(); 720 721 if (selectedRows == null || selectedRows.length <= 0 || selectedCols == null || selectedCols.length <= 0) { 722 shell.getDisplay().beep(); 723 Tools.showError(shell, "Select", "No data is selected."); 724 return null; 725 } 726 727 int size = selectedCols.length * selectedRows.length; 728 log.trace("getSelectedData() data size: {}", size); 729 730 // the whole table is selected 731 if ((dataTable.getPreferredColumnCount() - 1 == selectedCols.length) 732 && (dataTable.getPreferredRowCount() - 1 == selectedRows.length)) 733 return dataValue; 734 735 if (dataObject.getDatatype().isRef()) { 736 // ref data are stored in bytes 737 selectedData = new byte[size * (int)dataObject.getDatatype().getDatatypeSize()]; 738 } 739 else { 740 switch (Utils.getJavaObjectRuntimeClass(dataValue)) { 741 case 'B': 742 selectedData = new byte[size]; 743 break; 744 case 'S': 745 selectedData = new short[size]; 746 break; 747 case 'I': 748 selectedData = new int[size]; 749 break; 750 case 'J': 751 selectedData = new long[size]; 752 break; 753 case 'F': 754 selectedData = new float[size]; 755 break; 756 case 'D': 757 selectedData = new double[size]; 758 break; 759 default: 760 selectedData = null; 761 break; 762 } 763 } 764 765 if (selectedData == null) { 766 shell.getDisplay().beep(); 767 Tools.showError(shell, "Select", "Unsupported data type."); 768 return null; 769 } 770 771 log.trace("getSelectedData(): selectedData is type {}", Utils.getJavaObjectRuntimeClass(dataValue)); 772 773 int w = dataTable.getPreferredColumnCount() - 1; 774 log.trace("getSelectedData(): getColumnCount={}", w); 775 int idxSrc = 0; 776 int idxDst = 0; 777 log.trace("getSelectedData(): Rows.length={} Cols.length={}", selectedRows.length, 778 selectedCols.length); 779 for (int i = 0; i < selectedRows.length; i++) { 780 for (int j = 0; j < selectedCols.length; j++) { 781 idxSrc = selectedRows[i] * w + selectedCols[j]; 782 Object dataArrayValue = null; 783 if (dataValue instanceof ArrayList) { 784 dataArrayValue = ((ArrayList)dataValue).get(idxSrc); 785 System.arraycopy(dataArrayValue, 0, selectedData, idxDst, (int)dataObject.getDatatype().getDatatypeSize()); 786 } 787 else { 788 dataArrayValue = Array.get(dataValue, idxSrc); 789 Array.set(selectedData, idxDst, dataArrayValue); 790 } 791 log.trace("getSelectedData()[{},{}]: dataValue[{}]={} from r{} and c{}", i, j, 792 idxSrc, dataArrayValue, selectedRows[i], selectedCols[j]); 793 idxDst++; 794 } 795 } 796 797 return selectedData; 798 } 799 800 /** 801 * Returns an IEditableRule that determines whether cells can be edited. 802 * 803 * Cells can be edited as long as the dataset is not opened in read-only mode 804 * and the data is not currently displayed in hexadecimal, binary, or character 805 * mode. 806 * 807 * @param dataObject 808 * The dataset for editing 809 * 810 * @return a new IEditableRule for the dataset 811 */ 812 @Override 813 protected IEditableRule getDataEditingRule(final DataFormat dataObject) { 814 if (dataObject == null) 815 return null; 816 817 // Only Allow editing if not in read-only mode 818 return new EditableRule() { 819 @Override 820 public boolean isEditable(int columnIndex, int rowIndex) { 821 /* 822 * TODO: Should be able to edit character-displayed types and datasets when 823 * displayed as hex/binary. 824 */ 825 return !(isReadOnly || isDisplayTypeChar || showAsBin || showAsHex); 826 } 827 }; 828 } 829 830 /** 831 * Display data pointed to by object references. Data of each object is shown in 832 * a separate spreadsheet. 833 * 834 * @param refarr 835 * the array of bytes that contain the object reference information. 836 * 837 */ 838 @Override 839 @SuppressWarnings({ "rawtypes", "unchecked" }) 840 protected void showObjRefData(byte[] refarr) { 841 log.trace("showObjRefData(): start: refarr={}", refarr); 842 843 if (refarr == null || (refarr.length <= 0) || H5Datatype.zeroArrayCheck(refarr)) { 844 Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data"); 845 log.debug("showObjRefData(): refarr is null or invalid"); 846 return; 847 } 848 849 String objref = H5Datatype.descReferenceObject(((HObject) dataObject).getFileFormat().getFID(), refarr); 850 log.trace("showObjRefData(): start: objref={}", objref); 851 852 // find the object location 853 String oidStr = objref.substring(objref.indexOf('/'), objref.indexOf("H5O_TYPE_OBJ_REF")-1); 854 HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), oidStr); 855 if (obj == null || !(obj instanceof ScalarDS)) { 856 Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data"); 857 log.debug("showObjRefData(): obj is null or not a Scalar Dataset"); 858 return; 859 } 860 861 ScalarDS dset = (ScalarDS) obj; 862 ScalarDS dsetCopy = null; 863 864 // create an instance of the dataset constructor 865 Constructor<? extends ScalarDS> constructor = null; 866 Object[] paramObj = null; 867 Object data = null; 868 869 try { 870 Class[] paramClass = { FileFormat.class, String.class, String.class }; 871 constructor = dset.getClass().getConstructor(paramClass); 872 paramObj = new Object[] { dset.getFileFormat(), dset.getName(), dset.getPath() }; 873 dsetCopy = constructor.newInstance(paramObj); 874 data = dsetCopy.getData(); 875 } 876 catch (Exception ex) { 877 log.debug("showObjRefData(): couldn't show data: ", ex); 878 Tools.showError(shell, "Select", "Object Reference: " + ex.getMessage()); 879 data = null; 880 } 881 882 if (data == null) 883 return; 884 885 Class<?> theClass = null; 886 String viewName = null; 887 888 switch (viewType) { 889 case IMAGE: 890 viewName = HDFView.getListOfImageViews().get(0); 891 break; 892 case TABLE: 893 viewName = (String) HDFView.getListOfTableViews().get(0); 894 break; 895 default: 896 viewName = null; 897 } 898 899 try { 900 theClass = Class.forName(viewName); 901 } 902 catch (Exception ex) { 903 try { 904 theClass = ViewProperties.loadExtClass().loadClass(viewName); 905 } 906 catch (Exception ex2) { 907 theClass = null; 908 } 909 } 910 911 // Use default dataview 912 if (theClass == null) { 913 switch (viewType) { 914 case IMAGE: 915 viewName = ViewProperties.DEFAULT_IMAGEVIEW_NAME; 916 break; 917 case TABLE: 918 viewName = ViewProperties.DEFAULT_SCALAR_DATASET_TABLEVIEW_NAME; 919 break; 920 default: 921 viewName = null; 922 } 923 924 try { 925 theClass = Class.forName(viewName); 926 } 927 catch (Exception ex) { 928 log.debug("showObjRefData(): no suitable display class found"); 929 Tools.showError(shell, "Select", "Could not show reference data: no suitable display class found"); 930 return; 931 } 932 } 933 934 HashMap map = new HashMap(1); 935 map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dsetCopy); 936 Object[] args = { viewer, map }; 937 938 try { 939 Tools.newInstance(theClass, args); 940 } 941 catch (Exception ex) { 942 log.debug("showObjRefData(): Could not show reference data: ", ex); 943 Tools.showError(shell, "Select", "Could not show reference data: " + ex.toString()); 944 } 945 } 946 947 /** 948 * Display data pointed to by region references. Data of each region is shown in 949 * a separate spreadsheet. 950 * 951 * @param refarr 952 * the array of bytes that contain the reg. ref information. 953 * 954 */ 955 @Override 956 @SuppressWarnings({ "rawtypes", "unchecked" }) 957 protected void showRegRefData(byte[] refarr) { 958 if (refarr == null || (refarr.length <= 0) || H5Datatype.zeroArrayCheck(refarr)) { 959 Tools.showError(shell, "Select", "Could not show region reference data: invalid or null data"); 960 log.debug("showRegRefData(): refarr is null or invalid"); 961 return; 962 } 963 964 String reg = null; 965 if (refarr.length == HDF5Constants.H5R_DSET_REG_REF_BUF_SIZE) 966 reg = H5Datatype.descRegionDataset(((HObject) dataObject).getFileFormat().getFID(), refarr); 967 else 968 reg = ((H5ReferenceType)dataObject.getDatatype()).getReferenceRegion(refarr, false); 969 970 boolean isPointSelection = (reg.indexOf('-') <= 0); 971 972 // find the object location 973 String oidStr = reg.substring(reg.indexOf('/'), reg.indexOf("REGION_TYPE")-1); 974 975 // decode the region selection 976 String regStr = reg.substring(reg.indexOf('{') + 1, reg.indexOf('}')); 977 if (regStr == null || regStr.length() <= 0) { 978 Tools.showError(shell, "Select", "Could not show region reference data: no region selection made."); 979 log.debug("showRegRefData(): no region selection made"); 980 return; // no selection 981 } 982 983 // TODO: do we need to do something with what's past the closing bracket 984 // regStr = reg.substring(reg.indexOf('}') + 1); 985 986 StringTokenizer st = new StringTokenizer(regStr); 987 int nSelections = st.countTokens(); 988 if (nSelections <= 0) { 989 Tools.showError(shell, "Select", "Could not show region reference data: no region selection made."); 990 log.debug("showRegRefData(): no region selection made"); 991 return; // no selection 992 } 993 994 HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), oidStr); 995 if (obj == null || !(obj instanceof ScalarDS)) { 996 Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data"); 997 log.debug("showRegRefData(): obj is null or not a Scalar Dataset"); 998 return; 999 } 1000 1001 ScalarDS dset = (ScalarDS) obj; 1002 ScalarDS dsetCopy = null; 1003 1004 // create an instance of the dataset constructor 1005 Constructor<? extends ScalarDS> constructor = null; 1006 Object[] paramObj = null; 1007 try { 1008 Class[] paramClass = { FileFormat.class, String.class, String.class }; 1009 constructor = dset.getClass().getConstructor(paramClass); 1010 paramObj = new Object[] { dset.getFileFormat(), dset.getName(), dset.getPath() }; 1011 } 1012 catch (Exception ex) { 1013 log.debug("showRegRefData(): constructor failure: ", ex); 1014 constructor = null; 1015 } 1016 1017 // load each selection into a separate dataset and display it in 1018 // a separate spreadsheet 1019 1020 while (st.hasMoreTokens()) { 1021 try { 1022 dsetCopy = constructor.newInstance(paramObj); 1023 } 1024 catch (Exception ex) { 1025 log.debug("showRegRefData(): constructor newInstance failure: ", ex); 1026 continue; 1027 } 1028 1029 if (dsetCopy == null) { 1030 log.debug("showRegRefData(): continue after null dataset copy"); 1031 continue; 1032 } 1033 1034 try { 1035 dsetCopy.init(); 1036 } 1037 catch (Exception ex) { 1038 log.debug("showRegRefData(): continue after copied dataset init failure: ", ex); 1039 continue; 1040 } 1041 1042 dsetCopy.getRank(); 1043 long[] start = dsetCopy.getStartDims(); 1044 long[] count = dsetCopy.getSelectedDims(); 1045 1046 // set the selected dimension sizes based on the region selection 1047 // info. 1048 int idx = 0; 1049 String sizeStr = null; 1050 String token = st.nextToken(); 1051 1052 token = token.replace('(', ' '); 1053 token = token.replace(')', ' '); 1054 if (isPointSelection) { 1055 // point selection 1056 StringTokenizer tmp = new StringTokenizer(token, ","); 1057 while (tmp.hasMoreTokens()) { 1058 count[idx] = 1; 1059 sizeStr = tmp.nextToken().trim(); 1060 start[idx] = Long.valueOf(sizeStr); 1061 idx++; 1062 } 1063 } 1064 else { 1065 // rectangle selection 1066 String startStr = token.substring(0, token.indexOf('-')); 1067 String endStr = token.substring(token.indexOf('-') + 1); 1068 StringTokenizer tmp = new StringTokenizer(startStr, ","); 1069 while (tmp.hasMoreTokens()) { 1070 sizeStr = tmp.nextToken().trim(); 1071 start[idx] = Long.valueOf(sizeStr); 1072 idx++; 1073 } 1074 1075 idx = 0; 1076 tmp = new StringTokenizer(endStr, ","); 1077 while (tmp.hasMoreTokens()) { 1078 sizeStr = tmp.nextToken().trim(); 1079 count[idx] = Long.valueOf(sizeStr) - start[idx] + 1; 1080 idx++; 1081 } 1082 } 1083 1084 try { 1085 dsetCopy.getData(); 1086 } 1087 catch (Exception ex) { 1088 log.debug("showRegRefData(): getData failure: ", ex); 1089 Tools.showError(shell, "Select", "Region Reference: " + ex.getMessage()); 1090 } 1091 1092 Class<?> theClass = null; 1093 String viewName = null; 1094 1095 switch (viewType) { 1096 case IMAGE: 1097 viewName = HDFView.getListOfImageViews().get(0); 1098 break; 1099 case TABLE: 1100 viewName = (String) HDFView.getListOfTableViews().get(0); 1101 break; 1102 default: 1103 viewName = null; 1104 } 1105 1106 try { 1107 theClass = Class.forName(viewName); 1108 } 1109 catch (Exception ex) { 1110 try { 1111 theClass = ViewProperties.loadExtClass().loadClass(viewName); 1112 } 1113 catch (Exception ex2) { 1114 theClass = null; 1115 } 1116 } 1117 1118 // Use default dataview 1119 if (theClass == null) { 1120 switch (viewType) { 1121 case IMAGE: 1122 viewName = ViewProperties.DEFAULT_IMAGEVIEW_NAME; 1123 break; 1124 case TABLE: 1125 viewName = ViewProperties.DEFAULT_SCALAR_DATASET_TABLEVIEW_NAME; 1126 break; 1127 default: 1128 viewName = null; 1129 } 1130 1131 try { 1132 theClass = Class.forName(viewName); 1133 } 1134 catch (Exception ex) { 1135 log.debug("showRegRefData(): no suitable display class found"); 1136 Tools.showError(shell, "Select", "Could not show reference data: no suitable display class found"); 1137 return; 1138 } 1139 } 1140 1141 HashMap map = new HashMap(1); 1142 map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dsetCopy); 1143 Object[] args = { viewer, map }; 1144 1145 try { 1146 Tools.newInstance(theClass, args); 1147 } 1148 catch (Exception ex) { 1149 log.debug("showRegRefData(): Could not show reference data: ", ex); 1150 Tools.showError(shell, "Select", "Could not show reference data: " + ex.toString()); 1151 } 1152 } // (st.hasMoreTokens()) 1153 } // end of showRegRefData() 1154 1155 /** 1156 * Display data pointed to by references. Data of each reference is shown in 1157 * a separate spreadsheet. The std. ref. information is stored in bytes 1158 * 1159 * @param refarr 1160 * the array of bytes that contain the std. ref information. 1161 * 1162 */ 1163 @Override 1164 @SuppressWarnings({ "rawtypes", "unchecked" }) 1165 protected void showStdRefData(byte[] refarr) { 1166 if (refarr == null || H5ReferenceType.zeroArrayCheck(refarr)) { 1167 Tools.showError(shell, "Select", "Could not show region reference data: invalid or null data"); 1168 log.debug("showStdRefData(): ref is null or invalid"); 1169 return; 1170 } 1171 1172 H5ReferenceType refType = ((H5ReferenceType) dataObject.getDatatype()); 1173 H5ReferenceData refdata = refType.getReferenceData(refarr); 1174 /* get the filename associated with the reference */ 1175 String reffile = refdata.file_name; 1176 if ((refdata.ref_type == HDF5Constants.H5R_DATASET_REGION1) || 1177 (refdata.ref_type == HDF5Constants.H5R_DATASET_REGION2)) { 1178 String ref_ptr = refType.getReferenceRegion(refarr, false); 1179 if ("REGION_TYPE UNKNOWN".equals(refdata.region_type)) { 1180 String msg = "Reference to " + ref_ptr + " cannot be displayed in a table"; 1181 Tools.showInformation(shell, "Reference", msg); 1182 } 1183 else { 1184 showRegRefData(refarr); 1185 } 1186 } 1187 if (((refdata.ref_type == HDF5Constants.H5R_OBJECT1) && (refdata.obj_type == HDF5Constants.H5O_TYPE_DATASET)) || 1188 ((refdata.ref_type == HDF5Constants.H5R_OBJECT2) && (refdata.obj_type == HDF5Constants.H5O_TYPE_DATASET))) { 1189 String ref_obj = refdata.obj_name; 1190 showObjStdRefData(ref_obj); 1191 } 1192 else if (refdata.ref_type == HDF5Constants.H5R_ATTR) { 1193 String ref_attr_name = refdata.attr_name; 1194 String ref_obj_name = refdata.obj_name; 1195 showAttrStdRefData(ref_obj_name, ref_attr_name); 1196 } 1197 else if ("H5O_TYPE_OBJ_REF".equals(refdata.region_type)) { 1198 String msg = "Reference to " + refdata.obj_name + " cannot be displayed in a table"; 1199 //String ref_ptr = refType.getObjectReferenceName(refarr); 1200 Tools.showInformation(shell, "Reference", msg); 1201 } 1202 else { 1203 // Other types 1204 } 1205 } // end of showStdRefData(byte[] refarr) 1206 1207 /** 1208 * Display data pointed to by object references. Data of each object is shown in 1209 * a separate spreadsheet. 1210 * 1211 * @param ref 1212 * the string that contain the object reference information. 1213 * 1214 */ 1215 @SuppressWarnings({ "rawtypes", "unchecked" }) 1216 protected void showObjStdRefData(String ref) { 1217 if (ref == null || (ref.length() <= 0) || (ref.compareTo("NULL") == 0)) { 1218 Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data"); 1219 log.debug("showObjStdRefData(): ref is null or invalid"); 1220 return; 1221 } 1222 1223 HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), ref); 1224 if (obj == null || !(obj instanceof ScalarDS)) { 1225 Tools.showError(shell, "Select", "Could not show object reference data: invalid or null data"); 1226 log.debug("showObjStdRefData(): obj is null or not a Scalar Dataset"); 1227 return; 1228 } 1229 1230 ScalarDS dset = (ScalarDS) obj; 1231 ScalarDS dsetCopy = null; 1232 1233 // create an instance of the dataset constructor 1234 Constructor<? extends ScalarDS> constructor = null; 1235 Object[] paramObj = null; 1236 Object data = null; 1237 1238 try { 1239 Class[] paramClass = { FileFormat.class, String.class, String.class }; 1240 constructor = dset.getClass().getConstructor(paramClass); 1241 paramObj = new Object[] { dset.getFileFormat(), dset.getName(), dset.getPath() }; 1242 dsetCopy = constructor.newInstance(paramObj); 1243 data = dsetCopy.getData(); 1244 } 1245 catch (Exception ex) { 1246 log.debug("showObjStdRefData(): couldn't show data: ", ex); 1247 Tools.showError(shell, "Select", "Object Reference: " + ex.getMessage()); 1248 data = null; 1249 } 1250 1251 if (data == null) 1252 return; 1253 1254 Class<?> theClass = null; 1255 String viewName = null; 1256 1257 switch (viewType) { 1258 case IMAGE: 1259 viewName = HDFView.getListOfImageViews().get(0); 1260 break; 1261 case TABLE: 1262 viewName = (String) HDFView.getListOfTableViews().get(0); 1263 break; 1264 default: 1265 viewName = null; 1266 } 1267 1268 try { 1269 theClass = Class.forName(viewName); 1270 } 1271 catch (Exception ex) { 1272 try { 1273 theClass = ViewProperties.loadExtClass().loadClass(viewName); 1274 } 1275 catch (Exception ex2) { 1276 theClass = null; 1277 } 1278 } 1279 1280 // Use default dataview 1281 if (theClass == null) { 1282 switch (viewType) { 1283 case IMAGE: 1284 viewName = ViewProperties.DEFAULT_IMAGEVIEW_NAME; 1285 break; 1286 case TABLE: 1287 viewName = ViewProperties.DEFAULT_SCALAR_DATASET_TABLEVIEW_NAME; 1288 break; 1289 default: 1290 viewName = null; 1291 } 1292 1293 try { 1294 theClass = Class.forName(viewName); 1295 } 1296 catch (Exception ex) { 1297 log.debug("showObjStdRefData(): no suitable display class found"); 1298 Tools.showError(shell, "Select", "Could not show reference data: no suitable display class found"); 1299 return; 1300 } 1301 } 1302 1303 HashMap map = new HashMap(1); 1304 map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, dsetCopy); 1305 Object[] args = { viewer, map }; 1306 1307 try { 1308 Tools.newInstance(theClass, args); 1309 } 1310 catch (Exception ex) { 1311 log.debug("showObjStdRefData(): Could not show reference data: ", ex); 1312 Tools.showError(shell, "Select", "Could not show reference data: " + ex.toString()); 1313 } 1314 } 1315 1316 /** 1317 * Display data pointed to by attribute references. Data of each object is shown in 1318 * a separate spreadsheet. 1319 * 1320 * @param ref_obj_name 1321 * the string that contain the attribute reference information. 1322 * @param ref_attr_name 1323 * the string that contain the attribute reference information. 1324 * 1325 */ 1326 @SuppressWarnings({ "rawtypes", "unchecked" }) 1327 protected void showAttrStdRefData(String ref_obj_name, String ref_attr_name) { 1328 if (ref_obj_name == null || (ref_obj_name.length() <= 0) || (ref_obj_name.compareTo("NULL") == 0)) { 1329 log.debug("showAttrStdRefData(): ref_obj_name is null or invalid"); 1330 Tools.showError(shell, "Select", "Could not show attribute reference data: invalid or null object name"); 1331 return; 1332 } 1333 1334 if (ref_attr_name == null || (ref_attr_name.length() <= 0) || (ref_attr_name.compareTo("NULL") == 0)) { 1335 log.debug("showAttrStdRefData(): ref_attr_name is null or invalid"); 1336 Tools.showError(shell, "Select", "Could not show attribute reference data: invalid or null attribute name"); 1337 return; 1338 } 1339 1340 // find the parent object first 1341 HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), ref_obj_name); 1342 if (obj == null) { 1343 log.debug("showAttrStdRefData(): obj is null"); 1344 Tools.showError(shell, "Select", "Could not show attribute reference data: invalid or null data"); 1345 return; 1346 } 1347 List<Attribute> attrs = H5File.getAttribute(obj); 1348 if ((attrs == null) || (attrs.size() < 1)) { 1349 log.debug("showAttrStdRefData(): attrs is null"); 1350 Tools.showError(shell, "Select", "Could not show attribute reference data: no attributes found"); 1351 return; 1352 } 1353 H5ScalarAttr attr = null; 1354 H5ScalarAttr attrCopy = null; 1355 int n = attrs.size(); 1356 for (int i = 0; i < n; i++) { 1357 attr = (H5ScalarAttr)attrs.get(i); 1358 if (attr.getAttributeName().equals(ref_attr_name)) 1359 break; 1360 else 1361 attr = null; 1362 } 1363 1364 // create an instance of the Attribute constructor 1365 Constructor<? extends H5ScalarAttr> constructor = null; 1366 Object[] paramObj = null; 1367 Object data = null; 1368 1369 try { 1370 Class[] paramClass = { HObject.class, String.class, Datatype.class, long[].class }; 1371 constructor = attr.getClass().getConstructor(paramClass); 1372 paramObj = new Object[] { obj, attr.getName(), attr.getDatatype(), null }; 1373 attrCopy = constructor.newInstance(paramObj); 1374 data = attrCopy.getData(); 1375 } 1376 catch (Exception ex) { 1377 log.debug("showAttrStdRefData(): couldn't show data: ", ex); 1378 Tools.showError(shell, "Select", "Attribute Reference: " + ex.getMessage()); 1379 data = null; 1380 } 1381 1382 if (data == null) 1383 return; 1384 1385 Class<?> theClass = null; 1386 String viewName = null; 1387 1388 switch (viewType) { 1389 case IMAGE: 1390 viewName = HDFView.getListOfImageViews().get(0); 1391 break; 1392 case TABLE: 1393 viewName = (String) HDFView.getListOfTableViews().get(0); 1394 break; 1395 default: 1396 viewName = null; 1397 } 1398 1399 try { 1400 theClass = Class.forName(viewName); 1401 } 1402 catch (Exception ex) { 1403 try { 1404 theClass = ViewProperties.loadExtClass().loadClass(viewName); 1405 } 1406 catch (Exception ex2) { 1407 theClass = null; 1408 } 1409 } 1410 1411 // Use default dataview 1412 if (theClass == null) { 1413 switch (viewType) { 1414 case IMAGE: 1415 viewName = ViewProperties.DEFAULT_IMAGEVIEW_NAME; 1416 break; 1417 case TABLE: 1418 viewName = ViewProperties.DEFAULT_SCALAR_DATASET_TABLEVIEW_NAME; 1419 break; 1420 default: 1421 viewName = null; 1422 } 1423 1424 try { 1425 theClass = Class.forName(viewName); 1426 } 1427 catch (Exception ex) { 1428 log.debug("showAttrStdRefData(): no suitable display class found"); 1429 Tools.showError(shell, "Select", "Could not show reference data: no suitable display class found"); 1430 return; 1431 } 1432 } 1433 1434 HashMap map = new HashMap(1); 1435 map.put(ViewProperties.DATA_VIEW_KEY.OBJECT, attrCopy); 1436 Object[] args = { viewer, map }; 1437 1438 try { 1439 Tools.newInstance(theClass, args); 1440 } 1441 catch (Exception ex) { 1442 log.debug("showAttrStdRefData(): Could not show reference data: ", ex); 1443 Tools.showError(shell, "Select", "Could not show reference data: " + ex.toString()); 1444 } 1445 } 1446 1447 /** 1448 * Update cell value label and cell value field when a cell is selected 1449 */ 1450 private class ScalarDSCellSelectionListener implements ILayerListener 1451 { 1452 @Override 1453 public void handleLayerEvent(ILayerEvent e) { 1454 if (e instanceof CellSelectionEvent) { 1455 CellSelectionEvent event = (CellSelectionEvent) e; 1456 Object val = dataTable.getDataValueByPosition(event.getColumnPosition(), event.getRowPosition()); 1457 String strVal = null; 1458 1459 String[] columnNames = ((ScalarDSColumnHeaderDataProvider) columnHeaderDataProvider).columnNames; 1460 int rowStart = ((RowHeaderDataProvider) rowHeaderDataProvider).start; 1461 int rowStride = ((RowHeaderDataProvider) rowHeaderDataProvider).stride; 1462 1463 cellLabel.setText(String.valueOf( 1464 rowStart + indexBase + dataTable.getRowIndexByPosition(event.getRowPosition()) * rowStride) 1465 + ", " + columnNames[dataTable.getColumnIndexByPosition(event.getColumnPosition())] + " = "); 1466 1467 if (val == null) { 1468 cellValueField.setText("Null"); 1469 ((ScrolledComposite) cellValueField.getParent()).setMinSize(cellValueField.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 1470 return; 1471 } 1472 1473 if (isStdRef) { 1474 boolean displayValues = ViewProperties.showRegRefValues(); 1475 1476 if (displayValues && val != null && !(val instanceof String)) {//((String) val).compareTo("NULL") != 0) { 1477 strVal = ((H5ReferenceType) dataObject.getDatatype()).getReferenceRegion((byte[])val, true); 1478 } 1479 } 1480 else if (isRegRef) { 1481 boolean displayValues = ViewProperties.showRegRefValues(); 1482 1483 if (displayValues && val != null && ((String) val).compareTo("NULL") != 0) { 1484 String reg = (String) val; 1485 boolean isPointSelection = (reg.indexOf('-') <= 0); 1486 1487 // find the object location 1488 String oidStr = reg.substring(reg.indexOf('/'), reg.indexOf(' ')); 1489 1490 // decode the region selection 1491 String regStr = reg.substring(reg.indexOf('{') + 1, reg.indexOf('}')); 1492 1493 // no selection 1494 if (regStr == null || regStr.length() <= 0) { 1495 log.debug("ScalarDSCellSelectionListener:RegRef CellSelected: no selection made"); 1496 strVal = null; 1497 } 1498 else { 1499 // TODO: do we need to do something with what's past the closing bracket 1500 // regStr = reg.substring(reg.indexOf('}') + 1); 1501 1502 StringTokenizer st = new StringTokenizer(regStr); 1503 int nSelections = st.countTokens(); 1504 if (nSelections <= 0) { // no selection 1505 strVal = null; 1506 } 1507 else { 1508 HObject obj = FileFormat.findObject(((HObject) dataObject).getFileFormat(), oidStr); 1509 if (obj == null || !(obj instanceof ScalarDS)) { // no selection 1510 strVal = null; 1511 } 1512 else { 1513 ScalarDS dset = (ScalarDS) obj; 1514 try { 1515 dset.init(); 1516 } 1517 catch (Exception ex) { 1518 log.debug("ScalarDSCellSelectionListener:RegRef CellSelected: reference dset did not init()", ex); 1519 } 1520 StringBuilder strvalSB = new StringBuilder(); 1521 1522 int idx = 0; 1523 while (st.hasMoreTokens()) { 1524 int space_type = dset.getSpaceType(); 1525 int rank = dset.getRank(); 1526 long[] start = dset.getStartDims(); 1527 long[] count = dset.getSelectedDims(); 1528 // long count[] = new long[rank]; 1529 1530 // set the selected dimension sizes 1531 // based on the region selection 1532 // info. 1533 String sizeStr = null; 1534 String token = st.nextToken(); 1535 1536 token = token.replace('(', ' '); 1537 token = token.replace(')', ' '); 1538 if (isPointSelection) { 1539 // point selection 1540 String[] tmp = token.split(","); 1541 for (int x = 0; x < tmp.length; x++) { 1542 count[x] = 1; 1543 sizeStr = tmp[x].trim(); 1544 start[x] = Long.valueOf(sizeStr); 1545 log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: point sel={}", tmp[x]); 1546 } 1547 } 1548 else { 1549 // rectangle selection 1550 String startStr = token.substring(0, token.indexOf('-')); 1551 String endStr = token.substring(token.indexOf('-') + 1); 1552 log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: rect sel with startStr={} endStr={}", 1553 startStr, endStr); 1554 String[] tmp = startStr.split(","); 1555 log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: tmp with length={} rank={}", 1556 tmp.length, rank); 1557 for (int x = 0; x < tmp.length; x++) { 1558 sizeStr = tmp[x].trim(); 1559 start[x] = Long.valueOf(sizeStr); 1560 log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: rect start={}", 1561 tmp[x]); 1562 } 1563 tmp = endStr.split(","); 1564 for (int x = 0; x < tmp.length; x++) { 1565 sizeStr = tmp[x].trim(); 1566 count[x] = Long.valueOf(sizeStr) - start[x] + 1; 1567 log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: rect end={} count={}", 1568 tmp[x], count[x]); 1569 } 1570 } 1571 1572 Object dbuf = null; 1573 try { 1574 dbuf = dset.getData(); 1575 } 1576 catch (Exception ex) { 1577 Tools.showError(shell, "Select", "Region Reference:" +ex.getMessage()); 1578 } 1579 1580 /* Convert dbuf to a displayable string */ 1581 char runtimeTypeClass = Utils.getJavaObjectRuntimeClass(dbuf); 1582 log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: cName={} runtimeTypeClass={}", 1583 dbuf.getClass().getName(), runtimeTypeClass); 1584 1585 if (idx > 0) strvalSB.append(','); 1586 1587 // convert numerical data into char 1588 // only possible cases are byte[] 1589 // and short[] (converted from 1590 // unsigned byte) 1591 Datatype dtype = dset.getDatatype(); 1592 Datatype baseType = dtype.getDatatypeBase(); 1593 log.trace("ScalarDSCellSelectionListener:RegRef CellSelected: dtype={} baseType={}", 1594 dtype.getDescription(), baseType); 1595 if (baseType == null) 1596 baseType = dtype; 1597 if ((dtype.isArray() && baseType.isChar()) 1598 && ((runtimeTypeClass == 'B') || (runtimeTypeClass == 'S'))) { 1599 int n = Array.getLength(dbuf); 1600 log.trace("ScalarDSCellSelectionListener:RegRef CellSelected charData length = {}", n); 1601 char[] charData = new char[n]; 1602 for (int i = 0; i < n; i++) { 1603 if (runtimeTypeClass == 'B') { 1604 charData[i] = (char) Array.getByte(dbuf, i); 1605 } 1606 else if (runtimeTypeClass == 'S') { 1607 charData[i] = (char) Array.getShort(dbuf, i); 1608 } 1609 } 1610 1611 strvalSB.append(charData); 1612 } 1613 else { 1614 // numerical values 1615 boolean isUnsigned = dtype.isUnsigned(); 1616 if (dtype.isArray()) 1617 isUnsigned = baseType.isUnsigned(); 1618 int n = Array.getLength(dbuf); 1619 if (isUnsigned) { 1620 switch (runtimeTypeClass) { 1621 case 'B': 1622 byte[] barray = (byte[]) dbuf; 1623 short sValue = barray[0]; 1624 if (sValue < 0) { 1625 sValue += 256; 1626 } 1627 strvalSB.append(sValue); 1628 for (int i = 1; i < n; i++) { 1629 strvalSB.append(','); 1630 sValue = barray[i]; 1631 if (sValue < 0) { 1632 sValue += 256; 1633 } 1634 strvalSB.append(sValue); 1635 } 1636 break; 1637 case 'S': 1638 short[] sarray = (short[]) dbuf; 1639 int iValue = sarray[0]; 1640 if (iValue < 0) { 1641 iValue += 65536; 1642 } 1643 strvalSB.append(iValue); 1644 for (int i = 1; i < n; i++) { 1645 strvalSB.append(','); 1646 iValue = sarray[i]; 1647 if (iValue < 0) { 1648 iValue += 65536; 1649 } 1650 strvalSB.append(iValue); 1651 } 1652 break; 1653 case 'I': 1654 int[] iarray = (int[]) dbuf; 1655 long lValue = iarray[0]; 1656 if (lValue < 0) { 1657 lValue += 4294967296L; 1658 } 1659 strvalSB.append(lValue); 1660 for (int i = 1; i < n; i++) { 1661 strvalSB.append(','); 1662 lValue = iarray[i]; 1663 if (lValue < 0) { 1664 lValue += 4294967296L; 1665 } 1666 strvalSB.append(lValue); 1667 } 1668 break; 1669 case 'J': 1670 long[] larray = (long[]) dbuf; 1671 Long l = larray[0]; 1672 String theValue = Long.toString(l); 1673 if (l < 0) { 1674 l = (l << 1) >>> 1; 1675 BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65 1676 BigInteger big2 = new BigInteger(l.toString()); 1677 BigInteger big = big1.add(big2); 1678 theValue = big.toString(); 1679 } 1680 strvalSB.append(theValue); 1681 for (int i = 1; i < n; i++) { 1682 strvalSB.append(','); 1683 l = larray[i]; 1684 theValue = Long.toString(l); 1685 if (l < 0) { 1686 l = (l << 1) >>> 1; 1687 BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65 1688 BigInteger big2 = new BigInteger(l.toString()); 1689 BigInteger big = big1.add(big2); 1690 theValue = big.toString(); 1691 } 1692 strvalSB.append(theValue); 1693 } 1694 break; 1695 default: 1696 strvalSB.append(Array.get(dbuf, 0)); 1697 for (int i = 1; i < n; i++) { 1698 strvalSB.append(','); 1699 strvalSB.append(Array.get(dbuf, i)); 1700 } 1701 break; 1702 } 1703 } 1704 else { 1705 for (int x = 0; x < n; x++) { 1706 Object theValue = Array.get(dbuf, x); 1707 if (x > 0) strvalSB.append(','); 1708 strvalSB.append(theValue); 1709 } 1710 } 1711 } 1712 idx++; 1713 dset.clearData(); 1714 } // (st.hasMoreTokens()) 1715 strVal = strvalSB.toString(); 1716 } 1717 } 1718 } 1719 } 1720 else { 1721 strVal = null; 1722 } 1723 } 1724 else if (isObjRef) { 1725 if (val != null && ((String) val).compareTo("NULL") != 0) { 1726 strVal = (String) val; 1727 } 1728 else { 1729 strVal = null; 1730 } 1731 } 1732 1733 if (strVal == null && val != null) 1734 strVal = dataDisplayConverter.canonicalToDisplayValue(val).toString(); 1735 1736 cellValueField.setText(strVal); 1737 ((ScrolledComposite) cellValueField.getParent()).setMinSize(cellValueField.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 1738 } 1739 } 1740 } 1741 1742 /** 1743 * Custom Column Header data provider to set column indices based on Index Base 1744 * for Scalar Datasets. 1745 */ 1746 private class ScalarDSColumnHeaderDataProvider implements IDataProvider 1747 { 1748 private final String columnNames[]; 1749 1750 private final int space_type; 1751 private final int rank; 1752 1753 private final long[] startArray; 1754 private final long[] strideArray; 1755 private final int[] selectedIndex; 1756 1757 private final int ncols; 1758 1759 public ScalarDSColumnHeaderDataProvider(DataFormat theDataObject) { 1760 space_type = theDataObject.getSpaceType(); 1761 rank = theDataObject.getRank(); 1762 1763 startArray = theDataObject.getStartDims(); 1764 strideArray = theDataObject.getStride(); 1765 selectedIndex = theDataObject.getSelectedIndex(); 1766 1767 if (rank > 1) { 1768 ncols = (int) theDataObject.getWidth(); 1769 1770 int start = (int) startArray[selectedIndex[1]]; 1771 int stride = (int) strideArray[selectedIndex[1]]; 1772 1773 columnNames = new String[ncols]; 1774 1775 for (int i = 0; i < ncols; i++) 1776 columnNames[i] = String.valueOf(start + indexBase + i * stride); 1777 } 1778 else { 1779 ncols = 1; 1780 1781 columnNames = new String[] { " " }; 1782 } 1783 } 1784 1785 @Override 1786 public int getColumnCount() { 1787 return ncols; 1788 } 1789 1790 @Override 1791 public int getRowCount() { 1792 return 1; 1793 } 1794 1795 @Override 1796 public Object getDataValue(int columnIndex, int rowIndex) { 1797 return columnNames[columnIndex]; 1798 } 1799 1800 @Override 1801 public void setDataValue(int columnIndex, int rowIndex, Object newValue) { 1802 // intentional 1803 } 1804 } 1805}