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