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.awt.Toolkit; 018import java.awt.datatransfer.Clipboard; 019import java.awt.datatransfer.DataFlavor; 020import java.awt.datatransfer.StringSelection; 021import java.io.BufferedReader; 022import java.io.BufferedWriter; 023import java.io.DataOutputStream; 024import java.io.File; 025import java.io.FileNotFoundException; 026import java.io.FileOutputStream; 027import java.io.FileReader; 028import java.io.FileWriter; 029import java.io.IOException; 030import java.io.PrintWriter; 031import java.lang.reflect.Array; 032import java.lang.reflect.Constructor; 033import java.nio.ByteOrder; 034import java.text.DecimalFormat; 035import java.text.NumberFormat; 036import java.util.ArrayList; 037import java.util.BitSet; 038import java.util.HashMap; 039import java.util.Iterator; 040import java.util.LinkedHashSet; 041import java.util.List; 042import java.util.Set; 043import java.util.StringTokenizer; 044 045import org.slf4j.Logger; 046import org.slf4j.LoggerFactory; 047 048import org.eclipse.nebula.widgets.nattable.NatTable; 049import org.eclipse.nebula.widgets.nattable.command.StructuralRefreshCommand; 050import org.eclipse.nebula.widgets.nattable.command.VisualRefreshCommand; 051import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration; 052import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration; 053import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes; 054import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; 055import org.eclipse.nebula.widgets.nattable.config.IEditableRule; 056import org.eclipse.nebula.widgets.nattable.coordinate.Range; 057import org.eclipse.nebula.widgets.nattable.data.IDataProvider; 058import org.eclipse.nebula.widgets.nattable.data.validate.DataValidator; 059import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; 060import org.eclipse.nebula.widgets.nattable.edit.action.KeyEditAction; 061import org.eclipse.nebula.widgets.nattable.edit.action.MouseEditAction; 062import org.eclipse.nebula.widgets.nattable.edit.config.DefaultEditConfiguration; 063import org.eclipse.nebula.widgets.nattable.edit.config.DialogErrorHandling; 064import org.eclipse.nebula.widgets.nattable.grid.command.ClientAreaResizeCommand; 065import org.eclipse.nebula.widgets.nattable.grid.GridRegion; 066import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer; 067import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer; 068import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer; 069import org.eclipse.nebula.widgets.nattable.layer.DataLayer; 070import org.eclipse.nebula.widgets.nattable.layer.ILayer; 071import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer; 072import org.eclipse.nebula.widgets.nattable.layer.config.DefaultColumnHeaderLayerConfiguration; 073import org.eclipse.nebula.widgets.nattable.layer.config.DefaultColumnHeaderStyleConfiguration; 074import org.eclipse.nebula.widgets.nattable.layer.config.DefaultRowHeaderLayerConfiguration; 075import org.eclipse.nebula.widgets.nattable.layer.config.DefaultRowHeaderStyleConfiguration; 076import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter; 077import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.BeveledBorderDecorator; 078import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.LineBorderDecorator; 079import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; 080import org.eclipse.nebula.widgets.nattable.selection.command.SelectAllCommand; 081import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; 082import org.eclipse.nebula.widgets.nattable.style.DisplayMode; 083import org.eclipse.nebula.widgets.nattable.style.HorizontalAlignmentEnum; 084import org.eclipse.nebula.widgets.nattable.style.Style; 085import org.eclipse.nebula.widgets.nattable.ui.action.IMouseAction; 086import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry; 087import org.eclipse.nebula.widgets.nattable.ui.matcher.CellEditorMouseEventMatcher; 088import org.eclipse.nebula.widgets.nattable.ui.matcher.LetterOrDigitKeyEventMatcher; 089import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher; 090import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuAction; 091import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder; 092import org.eclipse.nebula.widgets.nattable.viewport.command.ShowRowInViewportCommand; 093import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer; 094 095import org.eclipse.swt.SWT; 096import org.eclipse.swt.custom.SashForm; 097import org.eclipse.swt.custom.ScrolledComposite; 098import org.eclipse.swt.events.DisposeEvent; 099import org.eclipse.swt.events.DisposeListener; 100import org.eclipse.swt.events.MouseEvent; 101import org.eclipse.swt.events.SelectionAdapter; 102import org.eclipse.swt.events.SelectionEvent; 103import org.eclipse.swt.events.TraverseEvent; 104import org.eclipse.swt.events.TraverseListener; 105import org.eclipse.swt.graphics.Color; 106import org.eclipse.swt.graphics.Font; 107import org.eclipse.swt.graphics.Point; 108import org.eclipse.swt.graphics.Rectangle; 109import org.eclipse.swt.layout.FillLayout; 110import org.eclipse.swt.layout.GridData; 111import org.eclipse.swt.layout.GridLayout; 112import org.eclipse.swt.widgets.Button; 113import org.eclipse.swt.widgets.Combo; 114import org.eclipse.swt.widgets.Composite; 115import org.eclipse.swt.widgets.Dialog; 116import org.eclipse.swt.widgets.Display; 117import org.eclipse.swt.widgets.FileDialog; 118import org.eclipse.swt.widgets.Label; 119import org.eclipse.swt.widgets.Menu; 120import org.eclipse.swt.widgets.MenuItem; 121import org.eclipse.swt.widgets.Shell; 122import org.eclipse.swt.widgets.Text; 123import org.eclipse.swt.widgets.ToolBar; 124import org.eclipse.swt.widgets.ToolItem; 125 126import hdf.hdf5lib.HDF5Constants; 127 128import hdf.object.CompoundDS; 129import hdf.object.DataFormat; 130import hdf.object.Dataset; 131import hdf.object.Datatype; 132import hdf.object.FileFormat; 133import hdf.object.Group; 134import hdf.object.HObject; 135import hdf.object.ScalarDS; 136 137import hdf.object.h5.H5Datatype; 138import hdf.object.h5.H5ReferenceType; 139 140import hdf.view.Chart; 141import hdf.view.DefaultFileFilter; 142import hdf.view.HDFView; 143import hdf.view.Tools; 144import hdf.view.ViewProperties; 145import hdf.view.ViewProperties.BITMASK_OP; 146import hdf.view.DataView.DataViewManager; 147import hdf.view.TableView.DataDisplayConverterFactory.HDFDisplayConverter; 148import hdf.view.TableView.DataProviderFactory.HDFDataProvider; 149import hdf.view.TreeView.TreeView; 150import hdf.view.dialog.InputDialog; 151import hdf.view.dialog.MathConversionDialog; 152import hdf.view.dialog.NewDatasetDialog; 153 154/** 155 * DefaultBaseTableView serves as the base class for a DataView that displays 156 * HDF data in a tabular format. This class is used for internal bookkeeping and 157 * as a place to store higher-level data manipulation functions, whereas its 158 * subclasses are responsible for setting up the actual GUI components. 159 * 160 * @author jhenderson 161 * @version 1.0 4/13/2018 162 */ 163public abstract class DefaultBaseTableView implements TableView 164{ 165 166 private static final Logger log = LoggerFactory.getLogger(DefaultBaseTableView.class); 167 168 private final Display display = Display.getDefault(); 169 /** The reference to the display shell used */ 170 protected final Shell shell; 171 /** The current font */ 172 protected Font curFont; 173 174 /** The main HDFView */ 175 protected final DataViewManager viewer; 176 177 /** The reference to the NAT table used */ 178 protected NatTable dataTable; 179 180 /** The data object to be displayed in the Table */ 181 protected final DataFormat dataObject; 182 183 /** The data value of the data object */ 184 protected Object dataValue; 185 186 /** The value used for fill */ 187 protected Object fillValue; 188 189 /** the valid types of tableviews */ 190 protected enum ViewType { 191 /** The data view is of type spreadsheet */ 192 TABLE, 193 /** The data view is of type image */ 194 IMAGE 195 }; 196 197 /** The type of view */ 198 protected ViewType viewType = ViewType.TABLE; 199 200 /** Changed to use normalized scientific notation (1 is less than coefficient is less than 10). */ 201 protected final DecimalFormat scientificFormat = new DecimalFormat("0.0###E0###"); 202 /** custom format pattern */ 203 protected DecimalFormat customFormat = new DecimalFormat("###.#####"); 204 /** the normal format to be used for numbers */ 205 protected final NumberFormat normalFormat = null; 206 /** the format to be used for numbers */ 207 protected NumberFormat numberFormat = normalFormat; 208 209 /** Used for bitmask operations on data */ 210 protected BitSet bitmask = null; 211 /** Used for the type of bitmask operation */ 212 protected BITMASK_OP bitmaskOP = BITMASK_OP.EXTRACT; 213 214 /** Fields to keep track of which 'frame' of 3 dimensional data is being displayed */ 215 private Text frameField; 216 private long curDataFrame = 0; 217 private long maxDataFrame = 1; 218 219 /** The index base used for display row and column numbers of data */ 220 protected int indexBase = 0; 221 222 /** size of default data length */ 223 protected int fixedDataLength = -1; 224 225 /** default binary order */ 226 protected int binaryOrder; 227 228 /** status if file is read only */ 229 protected boolean isReadOnly = false; 230 231 /** status if the enums are to display converted */ 232 protected boolean isEnumConverted = false; 233 234 /** status if the display type is a char */ 235 protected boolean isDisplayTypeChar; 236 237 /** status if the data is transposed */ 238 protected boolean isDataTransposed; 239 240 /** reference status */ 241 protected boolean isRegRef = false, isObjRef = false, isStdRef = false; 242 /** show data as status */ 243 protected boolean showAsHex = false, showAsBin = false; 244 245 /** Keep references to the selection layers for ease of access */ 246 protected SelectionLayer selectionLayer; 247 /** Keep references to the data layers for ease of access */ 248 protected DataLayer dataLayer; 249 250 /** reference to the data provider for the row */ 251 protected IDataProvider rowHeaderDataProvider; 252 /** reference to the data provider for the column */ 253 protected IDataProvider columnHeaderDataProvider; 254 255 /** reference to the data provider */ 256 protected HDFDataProvider dataProvider; 257 /** reference to the display converter */ 258 protected HDFDisplayConverter dataDisplayConverter; 259 260 /** 261 * Global variables for GUI components on the default to show data 262 */ 263 /** Checkbox menu item for Fixed Data Length default*/ 264 protected MenuItem checkFixedDataLength = null; 265 /** Checkbox menu item for Custom Notation default*/ 266 protected MenuItem checkCustomNotation = null; 267 /** Checkbox menu item for Scientific Notation default */ 268 protected MenuItem checkScientificNotation = null; 269 /** Checkbox menu item for hex default */ 270 protected MenuItem checkHex = null; 271 /** Checkbox menu item for binary default */ 272 protected MenuItem checkBin = null; 273 /** Checkbox menu item for enum default*/ 274 protected MenuItem checkEnum = null; 275 276 /** Labeled Group to display the index base */ 277 protected org.eclipse.swt.widgets.Group indexBaseGroup; 278 279 /** Text field to display the value of the currently selected table cell */ 280 protected Text cellValueField; 281 282 /** Label to indicate the current cell location */ 283 protected Label cellLabel; 284 285 286 /** 287 * Constructs a base TableView with no additional data properties. 288 * 289 * @param theView 290 * the main HDFView. 291 */ 292 public DefaultBaseTableView(DataViewManager theView) { 293 this(theView, null); 294 } 295 296 /** 297 * Constructs a base TableView with the specified data properties. 298 * 299 * @param theView 300 * the main HDFView. 301 * 302 * @param dataPropertiesMap 303 * the properties on how to show the data. The map is used to allow 304 * applications to pass properties on how to display the data, such 305 * as: transposing data, showing data as characters, applying a 306 * bitmask, and etc. Predefined keys are listed at 307 * ViewProperties.DATA_VIEW_KEY. 308 */ 309 @SuppressWarnings("rawtypes") 310 public DefaultBaseTableView(DataViewManager theView, HashMap dataPropertiesMap) { 311 shell = new Shell(display, SWT.SHELL_TRIM); 312 313 shell.setData(this); 314 315 shell.setLayout(new GridLayout(1, true)); 316 317 /* 318 * When the table is closed, make sure to prompt the user about saving their 319 * changes, then do any pending cleanup work. 320 */ 321 shell.addDisposeListener(new DisposeListener() { 322 @Override 323 public void widgetDisposed(DisposeEvent e) { 324 if (dataProvider != null) { 325 if (dataProvider.getIsValueChanged() && !isReadOnly) { 326 if (Tools.showConfirm(shell, "Changes Detected", "\"" + ((HObject) dataObject).getName() 327 + "\" has changed.\nDo you want to save the changes?")) 328 updateValueInFile(); 329 else 330 dataObject.clearData(); 331 } 332 } 333 334 dataValue = null; 335 dataTable = null; 336 337 if (curFont != null) 338 curFont.dispose(); 339 340 viewer.removeDataView(DefaultBaseTableView.this); 341 } 342 }); 343 344 /* Grab the current font to be used for all GUI components */ 345 try { 346 curFont = new Font(display, ViewProperties.getFontType(), ViewProperties.getFontSize(), SWT.NORMAL); 347 } 348 catch (Exception ex) { 349 curFont = null; 350 } 351 352 viewer = theView; 353 354 /* Retrieve any display properties passed in via the HashMap parameter */ 355 HObject hObject = null; 356 357 if (ViewProperties.isIndexBase1()) 358 indexBase = 1; 359 360 if (dataPropertiesMap != null) { 361 hObject = (HObject) dataPropertiesMap.get(ViewProperties.DATA_VIEW_KEY.OBJECT); 362 363 bitmask = (BitSet) dataPropertiesMap.get(ViewProperties.DATA_VIEW_KEY.BITMASK); 364 bitmaskOP = (BITMASK_OP) dataPropertiesMap.get(ViewProperties.DATA_VIEW_KEY.BITMASKOP); 365 366 Boolean b = (Boolean) dataPropertiesMap.get(ViewProperties.DATA_VIEW_KEY.CHAR); 367 if (b != null) isDisplayTypeChar = b.booleanValue(); 368 369 b = (Boolean) dataPropertiesMap.get(ViewProperties.DATA_VIEW_KEY.TRANSPOSED); 370 if (b != null) isDataTransposed = b.booleanValue(); 371 372 b = (Boolean) dataPropertiesMap.get(ViewProperties.DATA_VIEW_KEY.INDEXBASE1); 373 if (b != null) { 374 if (b.booleanValue()) 375 indexBase = 1; 376 else 377 indexBase = 0; 378 } 379 } 380 381 if (hObject == null) 382 hObject = viewer.getTreeView().getCurrentObject(); 383 384 /* Only edit objects which actually contain editable data */ 385 if ((hObject == null) || !(hObject instanceof DataFormat)) { 386 log.debug("data object is null or not an instanceof DataFormat"); 387 dataObject = null; 388 shell.dispose(); 389 return; 390 } 391 392 dataObject = (DataFormat) hObject; 393 if (((HObject) dataObject).getFileFormat() == null) { 394 log.debug("DataFormat object cannot access FileFormat"); 395 shell.dispose(); 396 return; 397 } 398 399 isReadOnly = ((HObject) dataObject).getFileFormat().isReadOnly(); 400 401 if (((HObject) dataObject).getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4)) 402 && (dataObject instanceof CompoundDS)) { 403 /* Cannot edit HDF4 VData */ 404 isReadOnly = true; 405 } 406 407 /* Disable edit feature for SZIP compression when encode is not enabled */ 408 if (!isReadOnly) { 409 String compression = dataObject.getCompression(); 410 if ((compression != null) && compression.startsWith("SZIP")) { 411 if (!compression.endsWith("ENCODE_ENABLED")) 412 isReadOnly = true; 413 } 414 } 415 416 log.trace("dataObject({}) isReadOnly={}", dataObject, isReadOnly); 417 418 long[] dims = dataObject.getDims(); 419 long tsize = 1; 420 421 if (dims == null) { 422 log.debug("data object has null dimensions"); 423 viewer.showError("Error: Data object '" + ((HObject) dataObject).getName() + "' has null dimensions."); 424 shell.dispose(); 425 Tools.showError(display.getActiveShell(), "Error", "Could not open data object '" + ((HObject) dataObject).getName() 426 + "'. Data object has null dimensions."); 427 return; 428 } 429 430 for (int i = 0; i < dims.length; i++) 431 tsize *= dims[i]; 432 433 log.trace("Data object Size={} Height={} Width={}", tsize, dataObject.getHeight(), dataObject.getWidth()); 434 435 if (dataObject.getHeight() <= 0 || dataObject.getWidth() <= 0 || tsize <= 0) { 436 log.debug("data object has dimension of size 0"); 437 viewer.showError("Error: Data object '" + ((HObject) dataObject).getName() + "' has dimension of size 0."); 438 shell.dispose(); 439 Tools.showError(display.getActiveShell(), "Error", "Could not open data object '" + ((HObject) dataObject).getName() 440 + "'. Data object has dimension of size 0."); 441 return; 442 } 443 444 /* 445 * Determine whether the data is to be displayed as characters and whether or 446 * not enum data is to be converted. 447 */ 448 Datatype dtype = dataObject.getDatatype(); 449 450 log.trace("Data object getDatatypeClass()={}", dtype.getDatatypeClass()); 451 isDisplayTypeChar = (isDisplayTypeChar 452 && (dtype.getDatatypeSize() == 1 || (dtype.isArray() && dtype.getDatatypeBase().isChar()))); 453 454 isEnumConverted = ViewProperties.isConvertEnum(); 455 456 log.trace("Data object isDisplayTypeChar={} isEnumConverted={}", isDisplayTypeChar, isEnumConverted); 457 458 if (dtype.isRef()) { 459 if (((HObject) dataObject).getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) { 460 isStdRef = ((H5Datatype)dtype).isStdRef(); 461 isRegRef = ((H5Datatype)dtype).isRegRef(); 462 isObjRef = ((H5Datatype)dtype).isRefObj(); 463 } 464 } 465 466 467 // Setup subset information 468 int space_type = dataObject.getSpaceType(); 469 int rank = dataObject.getRank(); 470 int[] selectedIndex = dataObject.getSelectedIndex(); 471 long[] count = dataObject.getSelectedDims(); 472 long[] stride = dataObject.getStride(); 473 long[] start = dataObject.getStartDims(); 474 int n = Math.min(3, rank); 475 476 if (rank > 2) { 477 curDataFrame = start[selectedIndex[2]] + indexBase; 478 maxDataFrame = (indexBase == 1) ? dims[selectedIndex[2]] : dims[selectedIndex[2]] - 1; 479 } 480 481 /* Create the toolbar area that contains useful shortcuts */ 482 ToolBar toolBar = createToolbar(shell); 483 toolBar.setSize(shell.getSize().x, 30); 484 toolBar.setLocation(0, 0); 485 486 /* 487 * Create the group that contains the text fields for displaying the value and 488 * location of the current cell, as well as the index base. 489 */ 490 indexBaseGroup = new org.eclipse.swt.widgets.Group(shell, SWT.SHADOW_ETCHED_OUT); 491 indexBaseGroup.setFont(curFont); 492 indexBaseGroup.setText(indexBase + "-based"); 493 indexBaseGroup.setLayout(new GridLayout(1, true)); 494 indexBaseGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 495 496 SashForm content = new SashForm(indexBaseGroup, SWT.VERTICAL); 497 content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 498 content.setSashWidth(10); 499 500 SashForm cellValueComposite = new SashForm(content, SWT.HORIZONTAL); 501 cellValueComposite.setSashWidth(8); 502 503 cellLabel = new Label(cellValueComposite, SWT.RIGHT | SWT.BORDER); 504 cellLabel.setAlignment(SWT.CENTER); 505 cellLabel.setFont(curFont); 506 507 final ScrolledComposite cellValueFieldScroller = new ScrolledComposite(cellValueComposite, SWT.V_SCROLL | SWT.H_SCROLL); 508 cellValueFieldScroller.setLayout(new FillLayout()); 509 510 cellValueField = new Text(cellValueFieldScroller, SWT.MULTI | SWT.BORDER | SWT.WRAP); 511 cellValueField.setEditable(false); 512 cellValueField.setBackground(new Color(display, 255, 255, 240)); 513 cellValueField.setEnabled(false); 514 cellValueField.setFont(curFont); 515 516 cellValueFieldScroller.setContent(cellValueField); 517 cellValueFieldScroller.setExpandHorizontal(true); 518 cellValueFieldScroller.setExpandVertical(true); 519 cellValueFieldScroller.setMinSize(cellValueField.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 520 521 cellValueComposite.setWeights(new int[] { 1, 5 }); 522 523 /* Make sure that the Dataset's data value is accessible for conditionally adding GUI components */ 524 try { 525 loadData(dataObject); 526 if (isStdRef) { 527 if (dataObject.getRank() > 2) 528 ((H5ReferenceType)dtype).setRefSize((int)dataObject.getWidth() * (int)dataObject.getWidth()); 529 ((H5ReferenceType)dtype).setData(dataValue); 530 } 531 } 532 catch (Exception ex) { 533 log.debug("loadData(): data not loaded: ", ex); 534 viewer.showError("Error: unable to load table data"); 535 shell.dispose(); 536 Tools.showError(display.getActiveShell(), "Open", "An error occurred while loading data for the table:\n\n" + ex.getMessage()); 537 return; 538 } 539 540 /* Create the Shell's MenuBar */ 541 shell.setMenuBar(createMenuBar(shell)); 542 543 /* 544 * Set the default selection on the "Show Hexadecimal/Show Binary", etc. MenuItems. 545 * This step must be done after the menu bar has actually been created. 546 */ 547 if (dataObject.getDatatype().isBitField() || dataObject.getDatatype().isOpaque()) { 548 showAsHex = true; 549 checkHex.setSelection(true); 550 checkScientificNotation.setSelection(false); 551 checkCustomNotation.setSelection(false); 552 checkBin.setSelection(false); 553 showAsBin = false; 554 numberFormat = normalFormat; 555 } 556 557 /* 558 * Set the default selection on the "Show Enum", etc. MenuItems. 559 * This step must be done after the menu bar has actually been created. 560 */ 561 if (dataObject.getDatatype().isEnum()) { 562 checkEnum.setSelection(isEnumConverted); 563 checkScientificNotation.setSelection(false); 564 checkCustomNotation.setSelection(false); 565 checkBin.setSelection(false); 566 checkHex.setSelection(false); 567 showAsBin = false; 568 showAsHex = false; 569 numberFormat = normalFormat; 570 } 571 572 /* Create the actual NatTable */ 573 log.debug("table creation {}", ((HObject) dataObject).getName()); 574 try { 575 dataTable = createTable(content, dataObject); 576 if (dataTable == null) { 577 log.debug("table creation for object {} failed", ((HObject) dataObject).getName()); 578 viewer.showError("Creating table for object '" + ((HObject) dataObject).getName() + "' failed."); 579 shell.dispose(); 580 Tools.showError(display.getActiveShell(), "Open", "Failed to create Table object"); 581 return; 582 } 583 } 584 catch (UnsupportedOperationException ex) { 585 log.debug("Subclass does not implement createTable()"); 586 shell.dispose(); 587 return; 588 } 589 590 /* 591 * Set the default data display conversion settings. 592 */ 593 updateDataConversionSettings(); 594 595 dataTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 596 597 /* 598 * Set the Shell's title using the object path and name 599 */ 600 StringBuilder sb = new StringBuilder(hObject.getName()); 601 602 if (((HObject) dataObject).getFileFormat() != null) { 603 sb.append(" at ") 604 .append(hObject.getPath()) 605 .append(" [") 606 .append(((HObject) dataObject).getFileFormat().getName()) 607 .append(" in ") 608 .append(((HObject) dataObject).getFileFormat().getParent()) 609 .append("]"); 610 } 611 612 shell.setText(sb.toString()); 613 614 /* 615 * Append subsetting information and show this as a status message in the 616 * HDFView main window 617 */ 618 sb.append(" [ dims"); 619 sb.append(selectedIndex[0]); 620 for (int i = 1; i < n; i++) { 621 sb.append("x"); 622 sb.append(selectedIndex[i]); 623 } 624 sb.append(", start"); 625 sb.append(start[selectedIndex[0]]); 626 for (int i = 1; i < n; i++) { 627 sb.append("x"); 628 sb.append(start[selectedIndex[i]]); 629 } 630 sb.append(", count"); 631 sb.append(count[selectedIndex[0]]); 632 for (int i = 1; i < n; i++) { 633 sb.append("x"); 634 sb.append(count[selectedIndex[i]]); 635 } 636 sb.append(", stride"); 637 sb.append(stride[selectedIndex[0]]); 638 for (int i = 1; i < n; i++) { 639 sb.append("x"); 640 sb.append(stride[selectedIndex[i]]); 641 } 642 sb.append(" ] "); 643 644 if (log.isTraceEnabled()) 645 log.trace("subset={}", sb); 646 647 viewer.showStatus(sb.toString()); 648 649 indexBaseGroup.pack(); 650 651 content.setWeights(new int[] { 1, 12 }); 652 653 shell.pack(); 654 655 int width = 700 + (ViewProperties.getFontSize() - 12) * 15; 656 int height = 500 + (ViewProperties.getFontSize() - 12) * 10; 657 shell.setSize(width, height); 658 } 659 660 /** 661 * Creates the toolbar for the Shell. 662 */ 663 private ToolBar createToolbar(final Shell shell) { 664 ToolBar toolbar = new ToolBar(shell, SWT.HORIZONTAL | SWT.RIGHT | SWT.BORDER); 665 toolbar.setFont(curFont); 666 toolbar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 667 668 // Chart button 669 ToolItem item = new ToolItem(toolbar, SWT.PUSH); 670 item.setImage(ViewProperties.getChartIcon()); 671 item.setToolTipText("Line Plot"); 672 item.addSelectionListener(new SelectionAdapter() { 673 @Override 674 public void widgetSelected(SelectionEvent e) { 675 showLineplot(); 676 } 677 }); 678 679 if (dataObject.getRank() > 2) { 680 new ToolItem(toolbar, SWT.SEPARATOR).setWidth(20); 681 682 // First frame button 683 item = new ToolItem(toolbar, SWT.PUSH); 684 item.setImage(ViewProperties.getFirstIcon()); 685 item.setToolTipText("First Frame"); 686 item.addSelectionListener(new SelectionAdapter() { 687 @Override 688 public void widgetSelected(SelectionEvent e) { 689 firstFrame(); 690 } 691 }); 692 693 // Previous frame button 694 item = new ToolItem(toolbar, SWT.PUSH); 695 item.setImage(ViewProperties.getPreviousIcon()); 696 item.setToolTipText("Previous Frame"); 697 item.addSelectionListener(new SelectionAdapter() { 698 @Override 699 public void widgetSelected(SelectionEvent e) { 700 previousFrame(); 701 } 702 }); 703 704 ToolItem separator = new ToolItem(toolbar, SWT.SEPARATOR); 705 706 frameField = new Text(toolbar, SWT.SINGLE | SWT.BORDER | SWT.CENTER); 707 frameField.setFont(curFont); 708 frameField.setText(String.valueOf(curDataFrame)); 709 frameField.addTraverseListener(new TraverseListener() { 710 @Override 711 public void keyTraversed(TraverseEvent e) { 712 if (e.detail == SWT.TRAVERSE_RETURN) { 713 try { 714 int frame = 0; 715 716 try { 717 frame = Integer.parseInt(frameField.getText().trim()) - indexBase; 718 } 719 catch (Exception ex) { 720 frame = -1; 721 } 722 723 gotoFrame(frame); 724 } 725 catch (Exception ex) { 726 log.debug("Frame change failure: ", ex); 727 } 728 } 729 } 730 }); 731 732 frameField.pack(); 733 734 separator.setWidth(frameField.getSize().x + 30); 735 separator.setControl(frameField); 736 737 separator = new ToolItem(toolbar, SWT.SEPARATOR); 738 739 Text maxFrameText = new Text(toolbar, SWT.SINGLE | SWT.BORDER | SWT.CENTER); 740 maxFrameText.setFont(curFont); 741 maxFrameText.setText(String.valueOf(maxDataFrame)); 742 maxFrameText.setEditable(false); 743 maxFrameText.setEnabled(false); 744 745 maxFrameText.pack(); 746 747 separator.setWidth(maxFrameText.getSize().x + 30); 748 separator.setControl(maxFrameText); 749 750 new ToolItem(toolbar, SWT.SEPARATOR).setWidth(10); 751 752 // Next frame button 753 item = new ToolItem(toolbar, SWT.PUSH); 754 item.setImage(ViewProperties.getNextIcon()); 755 item.setToolTipText("Next Frame"); 756 item.addSelectionListener(new SelectionAdapter() { 757 @Override 758 public void widgetSelected(SelectionEvent e) { 759 nextFrame(); 760 } 761 }); 762 763 // Last frame button 764 item = new ToolItem(toolbar, SWT.PUSH); 765 item.setImage(ViewProperties.getLastIcon()); 766 item.setToolTipText("Last Frame"); 767 item.addSelectionListener(new SelectionAdapter() { 768 @Override 769 public void widgetSelected(SelectionEvent e) { 770 lastFrame(); 771 } 772 }); 773 } 774 775 return toolbar; 776 } 777 778 /** 779 * Creates the menubar for the Shell. 780 * 781 * @param theShell 782 * the reference to the display shell 783 * 784 * @return the newly created menu 785 */ 786 protected Menu createMenuBar(final Shell theShell) { 787 Menu menuBar = new Menu(theShell, SWT.BAR); 788 boolean isEditable = !isReadOnly; 789 790 MenuItem tableMenuItem = new MenuItem(menuBar, SWT.CASCADE); 791 tableMenuItem.setText("&Table"); 792 793 Menu tableMenu = new Menu(theShell, SWT.DROP_DOWN); 794 tableMenuItem.setMenu(tableMenu); 795 796 MenuItem item = new MenuItem(tableMenu, SWT.PUSH); 797 item.setText("Select All"); 798 item.setAccelerator(SWT.CTRL | 'A'); 799 item.addSelectionListener(new SelectionAdapter() { 800 @Override 801 public void widgetSelected(SelectionEvent e) { 802 try { 803 dataTable.doCommand(new SelectAllCommand()); 804 } 805 catch (Exception ex) { 806 theShell.getDisplay().beep(); 807 Tools.showError(theShell, "Select", ex.getMessage()); 808 } 809 } 810 }); 811 812 item = new MenuItem(tableMenu, SWT.PUSH); 813 item.setText("Copy"); 814 item.setAccelerator(SWT.CTRL | 'C'); 815 item.addSelectionListener(new SelectionAdapter() { 816 @Override 817 public void widgetSelected(SelectionEvent e) { 818 copyData(); 819 } 820 }); 821 822 item = new MenuItem(tableMenu, SWT.PUSH); 823 item.setText("Paste"); 824 item.setAccelerator(SWT.CTRL | 'V'); 825 item.setEnabled(isEditable); 826 item.addSelectionListener(new SelectionAdapter() { 827 @Override 828 public void widgetSelected(SelectionEvent e) { 829 pasteData(); 830 } 831 }); 832 833 new MenuItem(tableMenu, SWT.SEPARATOR); 834 835 item = new MenuItem(tableMenu, SWT.PUSH); 836 item.setText("Copy to New Dataset"); 837 item.setEnabled(isEditable && (dataObject instanceof ScalarDS)); 838 item.addSelectionListener(new SelectionAdapter() { 839 @Override 840 public void widgetSelected(SelectionEvent e) { 841 if ((selectionLayer.getSelectedColumnPositions().length <= 0) 842 || (selectionLayer.getSelectedRowCount() <= 0)) { 843 Tools.showInformation(theShell, "Copy", "Select table cells to write."); 844 return; 845 } 846 847 TreeView treeView = viewer.getTreeView(); 848 Group pGroup = (Group) (treeView.findTreeItem((HObject) dataObject).getParentItem().getData()); 849 HObject root = ((HObject) dataObject).getFileFormat().getRootObject(); 850 851 if (root == null) return; 852 853 ArrayList<HObject> list = new ArrayList<>(((HObject) dataObject).getFileFormat().getNumberOfMembers() + 5); 854 Iterator<HObject> it = ((Group) root).depthFirstMemberList().iterator(); 855 856 while (it.hasNext()) 857 list.add(it.next()); 858 list.add(root); 859 860 NewDatasetDialog dialog = new NewDatasetDialog(theShell, pGroup, list, DefaultBaseTableView.this); 861 dialog.open(); 862 863 HObject obj = dialog.getObject(); 864 if (obj != null) { 865 Group pgroup = dialog.getParentGroup(); 866 try { 867 treeView.addObject(obj, pgroup); 868 } 869 catch (Exception ex) { 870 log.debug("Write selection to dataset:", ex); 871 } 872 } 873 874 list.clear(); 875 } 876 }); 877 878 item = new MenuItem(tableMenu, SWT.PUSH); 879 item.setText("Save Changes to File"); 880 item.setAccelerator(SWT.CTRL | 'U'); 881 item.setEnabled(isEditable); 882 item.addSelectionListener(new SelectionAdapter() { 883 @Override 884 public void widgetSelected(SelectionEvent e) { 885 try { 886 updateValueInFile(); 887 } 888 catch (Exception ex) { 889 theShell.getDisplay().beep(); 890 Tools.showError(theShell, "Save", ex.getMessage()); 891 } 892 } 893 }); 894 895 new MenuItem(tableMenu, SWT.SEPARATOR); 896 897 item = new MenuItem(tableMenu, SWT.PUSH); 898 item.setText("Show Lineplot"); 899 item.addSelectionListener(new SelectionAdapter() { 900 @Override 901 public void widgetSelected(SelectionEvent e) { 902 showLineplot(); 903 } 904 }); 905 906 item = new MenuItem(tableMenu, SWT.PUSH); 907 item.setText("Show Statistics"); 908 item.addSelectionListener(new SelectionAdapter() { 909 @Override 910 public void widgetSelected(SelectionEvent e) { 911 try { 912 Object theData = getSelectedData(); 913 914 if (dataObject instanceof CompoundDS) { 915 int cols = selectionLayer.getFullySelectedColumnPositions().length; 916 if (cols != 1) { 917 Tools.showError(theShell, "Statistics", "Please select one column at a time for compound dataset."); 918 return; 919 } 920 } 921 else if (theData == null) { 922 theData = dataValue; 923 } 924 925 double[] minmax = new double[2]; 926 double[] stat = new double[2]; 927 928 Tools.findMinMax(theData, minmax, fillValue); 929 if (Tools.computeStatistics(theData, stat, fillValue) > 0) { 930 String stats = "Min = " + minmax[0] + "\nMax = " 931 + minmax[1] + "\nMean = " + stat[0] + "\nStandard deviation = " 932 + stat[1]; 933 Tools.showInformation(theShell, "Statistics", stats); 934 } 935 936 System.gc(); 937 } 938 catch (Exception ex) { 939 theShell.getDisplay().beep(); 940 Tools.showError(shell, "Statistics", ex.getMessage()); 941 } 942 } 943 }); 944 945 new MenuItem(tableMenu, SWT.SEPARATOR); 946 947 item = new MenuItem(tableMenu, SWT.PUSH); 948 item.setText("Math Conversion"); 949 item.setEnabled(isEditable); 950 item.addSelectionListener(new SelectionAdapter() { 951 @Override 952 public void widgetSelected(SelectionEvent e) { 953 try { 954 mathConversion(); 955 } 956 catch (Exception ex) { 957 shell.getDisplay().beep(); 958 Tools.showError(theShell, "Convert", ex.getMessage()); 959 } 960 } 961 }); 962 963 new MenuItem(tableMenu, SWT.SEPARATOR); 964 965 item = new MenuItem(tableMenu, SWT.PUSH); 966 item.setText("Close"); 967 item.addSelectionListener(new SelectionAdapter() { 968 @Override 969 public void widgetSelected(SelectionEvent e) { 970 theShell.dispose(); 971 } 972 }); 973 974 /******************************************************************** 975 * * 976 * Set up MenuItems for refreshing the TableView * 977 * * 978 ********************************************************************/ 979 item = new MenuItem(tableMenu, SWT.PUSH); 980 item.setText("Start Timer"); 981 item.addSelectionListener(new SelectionAdapter() { 982 @Override 983 public void widgetSelected(SelectionEvent e) { 984 viewer.executeTimer(true); 985 } 986 }); 987 988 item = new MenuItem(tableMenu, SWT.PUSH); 989 item.setText("Stop Timer"); 990 item.addSelectionListener(new SelectionAdapter() { 991 @Override 992 public void widgetSelected(SelectionEvent e) { 993 viewer.executeTimer(false); 994 } 995 }); 996 997 998 /******************************************************************** 999 * * 1000 * Set up MenuItems for Importing/Exporting Data from the TableView * 1001 * * 1002 ********************************************************************/ 1003 MenuItem importExportMenuItem = new MenuItem(menuBar, SWT.CASCADE); 1004 importExportMenuItem.setText("&Import/Export Data"); 1005 1006 Menu importExportMenu = new Menu(theShell, SWT.DROP_DOWN); 1007 importExportMenuItem.setMenu(importExportMenu); 1008 1009 item = new MenuItem(importExportMenu, SWT.CASCADE); 1010 item.setText("Export Data to"); 1011 1012 Menu exportMenu = new Menu(item); 1013 item.setMenu(exportMenu); 1014 1015 item = new MenuItem(exportMenu, SWT.PUSH); 1016 item.setText("Text File"); 1017 item.addSelectionListener(new SelectionAdapter() { 1018 @Override 1019 public void widgetSelected(SelectionEvent e) { 1020 try { 1021 saveAsText(); 1022 } 1023 catch (Exception ex) { 1024 theShell.getDisplay().beep(); 1025 Tools.showError(theShell, "Save", ex.getMessage()); 1026 } 1027 } 1028 }); 1029 1030 item = new MenuItem(importExportMenu, SWT.CASCADE); 1031 item.setText("Import Data from"); 1032 1033 Menu importMenu = new Menu(item); 1034 item.setMenu(importMenu); 1035 1036 item = new MenuItem(importMenu, SWT.PUSH); 1037 item.setText("Text File"); 1038 item.setEnabled(!isReadOnly); 1039 item.addSelectionListener(new SelectionAdapter() { 1040 @Override 1041 public void widgetSelected(SelectionEvent e) { 1042 String currentDir = ((HObject) dataObject).getFileFormat().getParent(); 1043 1044 String filename = null; 1045 if (((HDFView) viewer).getTestState()) { 1046 filename = currentDir + File.separator + new InputDialog(theShell, "Enter a file name", "").open(); 1047 } 1048 else { 1049 FileDialog fChooser = new FileDialog(theShell, SWT.OPEN); 1050 fChooser.setFilterPath(currentDir); 1051 1052 DefaultFileFilter filter = DefaultFileFilter.getFileFilterText(); 1053 fChooser.setFilterExtensions(new String[] { "*", filter.getExtensions() }); 1054 fChooser.setFilterNames(new String[] { "All Files", filter.getDescription() }); 1055 fChooser.setFilterIndex(1); 1056 1057 filename = fChooser.open(); 1058 } 1059 1060 if (filename == null) 1061 return; 1062 1063 File chosenFile = new File(filename); 1064 if (!chosenFile.exists()) { 1065 Tools.showError(theShell, "Import Data From Text File", "Data import error: " + filename + " does not exist."); 1066 return; 1067 } 1068 1069 if (!Tools.showConfirm(theShell, "Import Data From Text File", "Do you want to paste selected data?")) 1070 return; 1071 1072 importTextData(chosenFile.getAbsolutePath()); 1073 } 1074 }); 1075 1076 return menuBar; 1077 } 1078 1079 /** 1080 * Loads the data buffer of an object. 1081 * 1082 * @param dataObject 1083 * the object that has the buffer for the data. 1084 * 1085 * @throws Exception if a failure occurred 1086 */ 1087 protected void loadData(DataFormat dataObject) throws Exception { 1088 if (!dataObject.isInited()) { 1089 try { 1090 dataObject.init(); 1091 } 1092 catch (Exception ex) { 1093 dataValue = null; 1094 log.debug("loadData(): ", ex); 1095 throw ex; 1096 } 1097 } 1098 1099 // use lazy convert for large number of strings 1100 if (dataObject.getHeight() > 10000 && dataObject instanceof CompoundDS) { 1101 ((CompoundDS) dataObject).setConvertByteToString(false); 1102 } 1103 1104 // Make sure entire dataset is not loaded when looking at 3D 1105 // datasets using the default display mode (double clicking the 1106 // data object) 1107 if (dataObject.getRank() > 2) 1108 dataObject.getSelectedDims()[dataObject.getSelectedIndex()[2]] = 1; 1109 1110 dataValue = null; 1111 try { 1112 log.trace("loadData(): call getData()"); 1113 dataValue = dataObject.getData(); 1114 } 1115 catch (Exception ex) { 1116 dataValue = null; 1117 log.debug("loadData(): ", ex); 1118 throw ex; 1119 } 1120 } 1121 1122 /** 1123 * Create a data table for a data object. 1124 * 1125 * @param parent 1126 * the parent object this table will be associated with. 1127 * @param dataObject 1128 * the data object this table will be associated with. 1129 * 1130 * @return the newly created data table 1131 */ 1132 protected abstract NatTable createTable(Composite parent, DataFormat dataObject); 1133 1134 /** 1135 * Show the object reference data. 1136 * 1137 * @param ref 1138 * the identifer for the object reference. 1139 */ 1140 protected abstract void showObjRefData(byte[] ref); 1141 1142 /** 1143 * Show the region reference data. 1144 * 1145 * @param reg 1146 * the identifier for the region reference. 1147 */ 1148 protected abstract void showRegRefData(byte[] reg); 1149 1150 /** 1151 * Show the standard reference data. 1152 * 1153 * @param reg 1154 * the identifier for the standard reference. 1155 */ 1156 protected abstract void showStdRefData(byte[] reg); 1157 1158 /** 1159 * Get the data editing rule for the object. 1160 * 1161 * @param dataObject 1162 * the data object 1163 * 1164 * @return the rule 1165 */ 1166 protected abstract IEditableRule getDataEditingRule(DataFormat dataObject); 1167 1168 /** 1169 * Update the display converters. 1170 */ 1171 protected void updateDataConversionSettings() { 1172 if (dataDisplayConverter != null) { 1173 dataDisplayConverter.setShowAsHex(showAsHex); 1174 dataDisplayConverter.setShowAsBin(showAsBin); 1175 dataDisplayConverter.setNumberFormat(numberFormat); 1176 dataDisplayConverter.setConvertEnum(isEnumConverted); 1177 } 1178 } 1179 1180 /** 1181 * Update dataset's value in file. The changes will go to the file. 1182 */ 1183 @Override 1184 public void updateValueInFile() { 1185 1186 if (isReadOnly || !dataProvider.getIsValueChanged() || showAsBin || showAsHex) { 1187 log.debug("updateValueInFile(): file not updated; read-only or unchanged data or displayed as hex or binary"); 1188 return; 1189 } 1190 1191 try { 1192 dataObject.write(); 1193 } 1194 catch (Exception ex) { 1195 shell.getDisplay().beep(); 1196 Tools.showError(shell, "Update", ex.getMessage()); 1197 log.debug("updateValueInFile(): ", ex); 1198 return; 1199 } 1200 1201 dataProvider.setIsValueChanged(false); 1202 } 1203 1204 @Override 1205 public HObject getDataObject() { 1206 return (HObject) dataObject; 1207 } 1208 1209 @Override 1210 public Object getTable() { 1211 return dataTable; 1212 } 1213 1214 @Override 1215 public int getSelectedRowCount() { 1216 return selectionLayer.getSelectedRowCount(); 1217 } 1218 1219 @Override 1220 public int getSelectedColumnCount() { 1221 return selectionLayer.getSelectedColumnPositions().length; 1222 } 1223 1224 /** @return the selection layer */ 1225 public SelectionLayer getSelectionLayer() { 1226 return selectionLayer; 1227 } 1228 1229 /** @return the data layer */ 1230 public DataLayer getDataLayer() { 1231 return dataLayer; 1232 } 1233 1234 /** refresh the data table */ 1235 @Override 1236 public void refreshDataTable() { 1237 log.trace("refreshDataTable()"); 1238 1239 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 1240 dataValue = dataObject.refreshData(); 1241 shell.setCursor(null); 1242 1243 long[] dims = dataObject.getDims(); 1244 log.trace("refreshDataTable() dims:{}", dims); 1245 dataProvider.updateDataBuffer(dataValue); 1246 ((RowHeaderDataProvider)rowHeaderDataProvider).updateRows(dataObject); 1247 log.trace("refreshDataTable(): rows={} : cols={}", dataProvider.getRowCount(), dataProvider.getColumnCount()); 1248 1249 dataTable.doCommand(new StructuralRefreshCommand()); 1250 final ViewportLayer viewportLayer = new ViewportLayer(selectionLayer); 1251 dataTable.doCommand(new ShowRowInViewportCommand(dataProvider.getRowCount()-1)); 1252 log.trace("refreshDataTable() finish"); 1253 } 1254 1255 // Flip to previous 'frame' of Table data 1256 private void previousFrame() { 1257 // Only valid operation if data object has 3 or more dimensions 1258 if (dataObject.getRank() < 3) 1259 return; 1260 1261 long[] start = dataObject.getStartDims(); 1262 int[] selectedIndex = dataObject.getSelectedIndex(); 1263 long curFrame = start[selectedIndex[2]]; 1264 1265 if (curFrame == 0) 1266 return; // Current frame is the first frame 1267 1268 gotoFrame(curFrame - 1); 1269 } 1270 1271 // Flip to next 'frame' of Table data 1272 private void nextFrame() { 1273 // Only valid operation if data object has 3 or more dimensions 1274 if (dataObject.getRank() < 3) 1275 return; 1276 1277 long[] start = dataObject.getStartDims(); 1278 int[] selectedIndex = dataObject.getSelectedIndex(); 1279 long[] dims = dataObject.getDims(); 1280 long curFrame = start[selectedIndex[2]]; 1281 1282 if (curFrame == dims[selectedIndex[2]] - 1) 1283 return; // Current frame is the last frame 1284 1285 gotoFrame(curFrame + 1); 1286 } 1287 1288 // Flip to the first 'frame' of Table data 1289 private void firstFrame() { 1290 // Only valid operation if data object has 3 or more dimensions 1291 if (dataObject.getRank() < 3) 1292 return; 1293 1294 long[] start = dataObject.getStartDims(); 1295 int[] selectedIndex = dataObject.getSelectedIndex(); 1296 long curFrame = start[selectedIndex[2]]; 1297 1298 if (curFrame == 0) 1299 return; // Current frame is the first frame 1300 1301 gotoFrame(0); 1302 } 1303 1304 // Flip to the last 'frame' of Table data 1305 private void lastFrame() { 1306 // Only valid operation if data object has 3 or more dimensions 1307 if (dataObject.getRank() < 3) 1308 return; 1309 1310 long[] start = dataObject.getStartDims(); 1311 int[] selectedIndex = dataObject.getSelectedIndex(); 1312 long[] dims = dataObject.getDims(); 1313 long curFrame = start[selectedIndex[2]]; 1314 1315 if (curFrame == dims[selectedIndex[2]] - 1) 1316 return; // Current page is the last page 1317 1318 gotoFrame(dims[selectedIndex[2]] - 1); 1319 } 1320 1321 // Flip to the specified 'frame' of Table data 1322 private void gotoFrame(long idx) { 1323 // Only valid operation if data object has 3 or more dimensions 1324 if (dataObject.getRank() < 3 || idx == (curDataFrame - indexBase)) 1325 return; 1326 1327 // Make sure to save any changes to this frame of data before changing frames 1328 if (dataProvider.getIsValueChanged()) 1329 updateValueInFile(); 1330 1331 long[] start = dataObject.getStartDims(); 1332 int[] selectedIndex = dataObject.getSelectedIndex(); 1333 long[] dims = dataObject.getDims(); 1334 1335 // Do a bit of frame index validation 1336 if ((idx < 0) || (idx >= dims[selectedIndex[2]])) { 1337 shell.getDisplay().beep(); 1338 Tools.showError(shell, "Select", 1339 "Frame number must be between " + indexBase + " and " + (dims[selectedIndex[2]] - 1 + indexBase)); 1340 return; 1341 } 1342 1343 start[selectedIndex[2]] = idx; 1344 curDataFrame = idx + indexBase; 1345 frameField.setText(String.valueOf(curDataFrame)); 1346 1347 dataObject.clearData(); 1348 1349 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 1350 1351 try { 1352 dataValue = dataObject.getData(); 1353 1354 /* 1355 * TODO: Converting data from unsigned C integers to Java integers 1356 * is currently unsupported for Compound Datasets. 1357 */ 1358 if (!(dataObject instanceof CompoundDS)) 1359 dataObject.convertFromUnsignedC(); 1360 1361 dataValue = dataObject.getData(); 1362 } 1363 catch (Exception ex) { 1364 shell.getDisplay().beep(); 1365 Tools.showError(shell, "Error loading data", "Dataset getData: " + ex.getMessage()); 1366 log.debug("gotoFrame(): ", ex); 1367 dataValue = null; 1368 } 1369 finally { 1370 shell.setCursor(null); 1371 } 1372 1373 dataProvider.updateDataBuffer(dataValue); 1374 1375 dataTable.doCommand(new VisualRefreshCommand()); 1376 } 1377 1378 /** 1379 * Copy data from the spreadsheet to the system clipboard. 1380 */ 1381 private void copyData() { 1382 StringBuilder sb = new StringBuilder(); 1383 1384 Rectangle selection = selectionLayer.getLastSelectedRegion(); 1385 if (selection == null) { 1386 Tools.showError(shell, "Copy", "Select data to copy."); 1387 return; 1388 } 1389 1390 int r0 = selectionLayer.getLastSelectedRegion().y; // starting row 1391 int c0 = selectionLayer.getLastSelectedRegion().x; // starting column 1392 1393 if ((r0 < 0) || (c0 < 0)) 1394 return; 1395 1396 int nr = selectionLayer.getSelectedRowCount(); 1397 int nc = selectionLayer.getSelectedColumnPositions().length; 1398 int r1 = r0 + nr; // finish row 1399 int c1 = c0 + nc; // finishing column 1400 1401 try { 1402 for (int i = r0; i < r1; i++) { 1403 sb.append(selectionLayer.getDataValueByPosition(c0, i).toString()); 1404 for (int j = c0 + 1; j < c1; j++) 1405 sb.append("\t").append(selectionLayer.getDataValueByPosition(j, i).toString()); 1406 sb.append("\n"); 1407 } 1408 } 1409 catch (java.lang.OutOfMemoryError err) { 1410 shell.getDisplay().beep(); 1411 Tools.showError(shell, "Copy", 1412 "Copying data to system clipboard failed. \nUse \"export/import data\" for copying/pasting large data."); 1413 return; 1414 } 1415 1416 Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); 1417 StringSelection contents = new StringSelection(sb.toString()); 1418 cb.setContents(contents, null); 1419 } 1420 1421 /** 1422 * Paste data from the system clipboard to the spreadsheet. 1423 */ 1424 private void pasteData() { 1425 if (!Tools.showConfirm(shell, "Clipboard Data", "Do you want to paste selected data?")) 1426 return; 1427 1428 int cols = selectionLayer.getPreferredColumnCount(); 1429 int rows = selectionLayer.getPreferredRowCount(); 1430 int r0 = 0; 1431 int c0 = 0; 1432 1433 Rectangle selection = selectionLayer.getLastSelectedRegion(); 1434 if (selection != null) { 1435 r0 = selection.y; 1436 c0 = selection.x; 1437 } 1438 1439 if (c0 < 0) 1440 c0 = 0; 1441 if (r0 < 0) 1442 r0 = 0; 1443 int r = r0; 1444 int c = c0; 1445 1446 Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); 1447 String line = ""; 1448 try { 1449 String s = (String) cb.getData(DataFlavor.stringFlavor); 1450 1451 StringTokenizer st = new StringTokenizer(s, "\n"); 1452 // read line by line 1453 while (st.hasMoreTokens() && (r < rows)) { 1454 line = st.nextToken(); 1455 1456 if (fixedDataLength < 1) { 1457 // separate by delimiter 1458 StringTokenizer lt = new StringTokenizer(line, "\t"); 1459 while (lt.hasMoreTokens() && (c < cols)) { 1460 try { 1461 dataProvider.setDataValue(c, r, lt.nextToken()); 1462 } 1463 catch (Exception ex) { 1464 continue; 1465 } 1466 c++; 1467 } 1468 r = r + 1; 1469 c = c0; 1470 } 1471 else { 1472 // the data has fixed length 1473 int n = line.length(); 1474 String theVal; 1475 for (int i = 0; i < n; i = i + fixedDataLength) { 1476 try { 1477 theVal = line.substring(i, i + fixedDataLength); 1478 dataProvider.setDataValue(c, r, theVal); 1479 } 1480 catch (Exception ex) { 1481 continue; 1482 } 1483 c++; 1484 } 1485 } 1486 } 1487 } 1488 catch (Exception ex) { 1489 shell.getDisplay().beep(); 1490 Tools.showError(shell, "Paste", ex.getMessage()); 1491 } 1492 } 1493 1494 /** 1495 * Save data as text. 1496 * 1497 * @throws Exception 1498 * if a failure occurred 1499 */ 1500 protected void saveAsText() throws Exception { 1501 String currentDir = ((HObject) dataObject).getFileFormat().getParent(); 1502 1503 String filename = null; 1504 if (((HDFView) viewer).getTestState()) { 1505 filename = currentDir + File.separator + new InputDialog(shell, "Enter a file name", "").open(); 1506 } 1507 else { 1508 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 1509 fChooser.setFilterPath(currentDir); 1510 1511 DefaultFileFilter filter = DefaultFileFilter.getFileFilterText(); 1512 fChooser.setFilterExtensions(new String[] { "*", filter.getExtensions() }); 1513 fChooser.setFilterNames(new String[] { "All Files", filter.getDescription() }); 1514 fChooser.setFilterIndex(1); 1515 fChooser.setText("Save Current Data To Text File --- " + ((HObject) dataObject).getName()); 1516 1517 filename = fChooser.open(); 1518 } 1519 if (filename == null) 1520 return; 1521 1522 File chosenFile = new File(filename); 1523 String fname = chosenFile.getAbsolutePath(); 1524 1525 log.trace("saveAsText: file={}", fname); 1526 1527 // Check if the file is in use and prompt for overwrite 1528 if (chosenFile.exists()) { 1529 List<?> fileList = viewer.getTreeView().getCurrentFiles(); 1530 if (fileList != null) { 1531 FileFormat theFile = null; 1532 Iterator<?> iterator = fileList.iterator(); 1533 while (iterator.hasNext()) { 1534 theFile = (FileFormat) iterator.next(); 1535 if (theFile.getFilePath().equals(fname)) { 1536 shell.getDisplay().beep(); 1537 Tools.showError(shell, "Save", 1538 "Unable to save data to file \"" + fname + "\". \nThe file is being used."); 1539 return; 1540 } 1541 } 1542 } 1543 1544 if (!Tools.showConfirm(shell, "Save", "File exists. Do you want to replace it?")) 1545 return; 1546 } 1547 1548 PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(chosenFile))); 1549 1550 String delName = ViewProperties.getDataDelimiter(); 1551 String delimiter = ""; 1552 1553 // delimiter must include a tab to be consistent with copy/paste for 1554 // compound fields 1555 if (dataObject instanceof CompoundDS) 1556 delimiter = "\t"; 1557 1558 if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_TAB)) 1559 delimiter = "\t"; 1560 else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_SPACE)) 1561 delimiter = " " + delimiter; 1562 else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_COMMA)) 1563 delimiter = "," + delimiter; 1564 else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_COLON)) 1565 delimiter = ":" + delimiter; 1566 else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_SEMI_COLON)) 1567 delimiter = ";" + delimiter; 1568 1569 int cols = selectionLayer.getPreferredColumnCount(); 1570 int rows = selectionLayer.getPreferredRowCount(); 1571 1572 for (int i = 0; i < rows; i++) { 1573 out.print(selectionLayer.getDataValueByPosition(0, i)); 1574 for (int j = 1; j < cols; j++) { 1575 out.print(delimiter); 1576 out.print(selectionLayer.getDataValueByPosition(j, i)); 1577 } 1578 out.println(); 1579 } 1580 1581 out.flush(); 1582 out.close(); 1583 1584 viewer.showStatus("Data saved to: " + fname); 1585 } 1586 1587 /** Save data as text (from TextView). */ 1588 // private void saveAsTextTextView() throws Exception { 1589 // FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 1590 // fChooser.setText("Save Current Data To Text File --- " + dataset.getName()); 1591 // fChooser.setFilterPath(dataset.getFileFormat().getParent()); 1592 // 1593 // DefaultFileFilter filter = DefaultFileFilter.getFileFilterText(); 1594 // fChooser.setFilterExtensions(new String[] {"*", filter.getExtensions()}); 1595 // fChooser.setFilterNames(new String[] {"All Files", filter.getDescription()}); 1596 // fChooser.setFilterIndex(1); 1597 // 1598 // // fchooser.changeToParentDirectory(); 1599 // fChooser.setFileName(dataset.getName() + ".txt"); 1600 // fChooser.setOverwrite(true); 1601 // 1602 // String filename = fChooser.open(); 1603 // 1604 // (filename == null) return; 1605 // 1606 // File chosenFile = new File(filename); 1607 // 1608 // // check if the file is in use 1609 // String fname = chosenFile.getAbsolutePath(); 1610 // List<FileFormat> fileList = viewer.getTreeView().getCurrentFiles(); 1611 // (fileList != null) { 1612 // FileFormat theFile = null; 1613 // Iterator<FileFormat> iterator = fileList.iterator(); 1614 // while (iterator.hasNext()) { 1615 // theFile = iterator.next(); 1616 // (theFile.getFilePath().equals(fname)) { 1617 // Tools.showError(shell, "Save", "Unable to save data to file \"" + fname 1618 // + "\". \nThe file is being used."); 1619 // return; 1620 // } 1621 // } 1622 // } 1623 // 1624 // PrintWriter out = new PrintWriter(new BufferedWriter(new 1625 // FileWriter(chosenFile))); 1626 // 1627 // int rows = text.length; 1628 // (int i = 0; i < rows; i++) { 1629 // out.print(text[i].trim()); 1630 // out.println(); 1631 // out.println(); 1632 // } 1633 // 1634 // out.flush(); 1635 // out.close(); 1636 // 1637 // viewer.showStatus("Data saved to: " + fname); 1638 // 1639 // try { 1640 // RandomAccessFile rf = new RandomAccessFile(chosenFile, "r"); 1641 // long size = rf.length(); 1642 // rf.close(); 1643 // viewer.showStatus("File size (bytes): " + size); 1644 // } 1645 // catch (Exception ex) { 1646 // log.debug("raf file size:", ex); 1647 // } 1648 // } 1649 1650 // print the table (from TextView) 1651 // private void print() { 1652 // // StreamPrintServiceFactory[] spsf = StreamPrintServiceFactory 1653 // // .lookupStreamPrintServiceFactories(null, null); 1654 // // (int i = 0; i < spsf.length; i++) { 1655 // // System.out.println(spsf[i]); 1656 // // } 1657 // // DocFlavor[] docFlavors = spsf[0].getSupportedDocFlavors(); 1658 // // (int i = 0; i < docFlavors.length; i++) { 1659 // // System.out.println(docFlavors[i]); 1660 // // } 1661 // 1662 // // TODO: windows url 1663 // // Get a text DocFlavor 1664 // InputStream is = null; 1665 // try { 1666 // is = new BufferedInputStream(new java.io.FileInputStream( 1667 // "e:\\temp\\t.html")); 1668 // } 1669 // catch (Exception ex) { 1670 // log.debug("Get a text DocFlavor:", ex); 1671 // } 1672 // DocFlavor flavor = DocFlavor.STRING.TEXT_HTML; 1673 // 1674 // // Get all available print services 1675 // PrintService[] services = PrintServiceLookup.lookupPrintServices(null, 1676 // null); 1677 // 1678 // // Print it 1679 // try { 1680 // // Print this job on the first print server 1681 // DocPrintJob job = services[0].createPrintJob(); 1682 // Doc doc = new SimpleDoc(is, flavor, null); 1683 // 1684 // job.print(doc, null); 1685 // } 1686 // catch (Exception ex) { 1687 // log.debug("print(): failure: ", ex); 1688 // } 1689 // } 1690 1691 /** 1692 * Save data as binary. 1693 * 1694 * @throws Exception 1695 * if a failure occurred 1696 */ 1697 protected void saveAsBinary() throws Exception { 1698 String currentDir = ((HObject) dataObject).getFileFormat().getParent(); 1699 1700 String filename = null; 1701 if (((HDFView) viewer).getTestState()) { 1702 filename = currentDir + File.separator + new InputDialog(shell, "Enter a file name", "").open(); 1703 } 1704 else { 1705 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 1706 fChooser.setFilterPath(currentDir); 1707 1708 DefaultFileFilter filter = DefaultFileFilter.getFileFilterBinary(); 1709 fChooser.setFilterExtensions(new String[] { "*", filter.getExtensions() }); 1710 fChooser.setFilterNames(new String[] { "All Files", filter.getDescription() }); 1711 fChooser.setFilterIndex(1); 1712 fChooser.setText("Save Current Data To Binary File --- " + ((HObject) dataObject).getName()); 1713 1714 filename = fChooser.open(); 1715 } 1716 if (filename == null) 1717 return; 1718 1719 File chosenFile = new File(filename); 1720 String fname = chosenFile.getAbsolutePath(); 1721 1722 log.trace("saveAsBinary: file={}", fname); 1723 1724 // Check if the file is in use and prompt for overwrite 1725 if (chosenFile.exists()) { 1726 List<?> fileList = viewer.getTreeView().getCurrentFiles(); 1727 if (fileList != null) { 1728 FileFormat theFile = null; 1729 Iterator<?> iterator = fileList.iterator(); 1730 while (iterator.hasNext()) { 1731 theFile = (FileFormat) iterator.next(); 1732 if (theFile.getFilePath().equals(fname)) { 1733 shell.getDisplay().beep(); 1734 Tools.showError(shell, "Save", 1735 "Unable to save data to file \"" + fname + "\". \nThe file is being used."); 1736 return; 1737 } 1738 } 1739 } 1740 1741 if (!Tools.showConfirm(shell, "Save", "File exists. Do you want to replace it?")) 1742 return; 1743 } 1744 1745 try (DataOutputStream out = new DataOutputStream(new FileOutputStream(chosenFile))) { 1746 if (dataObject instanceof ScalarDS) { 1747 ((ScalarDS) dataObject).convertToUnsignedC(); 1748 Object data = dataObject.getData(); 1749 ByteOrder bo = ByteOrder.nativeOrder(); 1750 1751 if (binaryOrder == 1) 1752 bo = ByteOrder.nativeOrder(); 1753 else if (binaryOrder == 2) 1754 bo = ByteOrder.LITTLE_ENDIAN; 1755 else if (binaryOrder == 3) 1756 bo = ByteOrder.BIG_ENDIAN; 1757 1758 Tools.saveAsBinary(out, data, bo); 1759 1760 viewer.showStatus("Data saved to: " + fname); 1761 } 1762 else 1763 viewer.showError("Data not saved - not a ScalarDS"); 1764 } 1765 } 1766 1767 /** 1768 * Import data values from text file. 1769 * 1770 * @param fname 1771 * the file to import text from 1772 */ 1773 protected void importTextData(String fname) { 1774 int cols = selectionLayer.getPreferredColumnCount(); 1775 int rows = selectionLayer.getPreferredRowCount(); 1776 int r0; 1777 int c0; 1778 1779 Rectangle lastSelection = selectionLayer.getLastSelectedRegion(); 1780 if (lastSelection != null) { 1781 r0 = lastSelection.y; 1782 c0 = lastSelection.x; 1783 1784 if (c0 < 0) 1785 c0 = 0; 1786 if (r0 < 0) 1787 r0 = 0; 1788 } 1789 else { 1790 r0 = 0; 1791 c0 = 0; 1792 } 1793 1794 // Start at the first column for compound datasets 1795 if (dataObject instanceof CompoundDS) 1796 c0 = 0; 1797 1798 String importLine = null; 1799 StringTokenizer tokenizer1 = null; 1800 try (BufferedReader in = new BufferedReader(new FileReader(fname))) { 1801 try { 1802 importLine = in.readLine(); 1803 } 1804 catch (FileNotFoundException ex) { 1805 log.debug("import data values from text file {}:", fname, ex); 1806 return; 1807 } 1808 catch (IOException ex) { 1809 log.debug("read text file {}:", fname, ex); 1810 return; 1811 } 1812 1813 String delName = ViewProperties.getDataDelimiter(); 1814 String delimiter = ""; 1815 1816 if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_TAB)) 1817 delimiter = "\t"; 1818 else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_SPACE)) 1819 delimiter = " " + delimiter; 1820 else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_COMMA)) 1821 delimiter = ","; 1822 else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_COLON)) 1823 delimiter = ":"; 1824 else if (delName.equalsIgnoreCase(ViewProperties.DELIMITER_SEMI_COLON)) 1825 delimiter = ";"; 1826 String token = null; 1827 int r = r0; 1828 int c = c0; 1829 while ((importLine != null) && (r < rows)) { 1830 if (fixedDataLength > 0) { 1831 // the data has fixed length 1832 int n = importLine.length(); 1833 String theVal; 1834 for (int i = 0; i < n; i = i + fixedDataLength) { 1835 try { 1836 theVal = importLine.substring(i, i + fixedDataLength); 1837 dataProvider.setDataValue(c, r, theVal); 1838 } 1839 catch (Exception ex) { 1840 continue; 1841 } 1842 c++; 1843 } 1844 } 1845 else { 1846 try { 1847 tokenizer1 = new StringTokenizer(importLine, delimiter); 1848 while (tokenizer1.hasMoreTokens() && (c < cols)) { 1849 token = tokenizer1.nextToken(); 1850 StringTokenizer tokenizer2 = new StringTokenizer(token); 1851 if (tokenizer2.hasMoreTokens()) { 1852 while (tokenizer2.hasMoreTokens() && (c < cols)) { 1853 dataProvider.setDataValue(c, r, tokenizer2.nextToken()); 1854 c++; 1855 } 1856 } 1857 else 1858 c++; 1859 } 1860 } 1861 catch (Exception ex) { 1862 Tools.showError(shell, "Import", ex.getMessage()); 1863 return; 1864 } 1865 } 1866 1867 try { 1868 importLine = in.readLine(); 1869 } 1870 catch (IOException ex) { 1871 log.debug("read text file {}:", fname, ex); 1872 importLine = null; 1873 } 1874 1875 // Start at the first column for compound datasets 1876 if (dataObject instanceof CompoundDS) 1877 c = 0; 1878 else 1879 c = c0; 1880 1881 r++; 1882 } // ((line != null) && (r < rows)) 1883 } 1884 catch (IOException ex) { 1885 log.debug("import text file {}:", fname, ex); 1886 } 1887 } 1888 1889 /** 1890 * Import data values from binary file. 1891 */ 1892 protected void importBinaryData() { 1893 String currentDir = ((HObject) dataObject).getFileFormat().getParent(); 1894 1895 String filename = null; 1896 if (((HDFView) viewer).getTestState()) { 1897 filename = currentDir + File.separator + new InputDialog(shell, "Enter a file name", "").open(); 1898 } 1899 else { 1900 FileDialog fChooser = new FileDialog(shell, SWT.OPEN); 1901 fChooser.setFilterPath(currentDir); 1902 1903 DefaultFileFilter filter = DefaultFileFilter.getFileFilterBinary(); 1904 fChooser.setFilterExtensions(new String[] { "*", filter.getExtensions() }); 1905 fChooser.setFilterNames(new String[] { "All Files", filter.getDescription() }); 1906 fChooser.setFilterIndex(1); 1907 1908 filename = fChooser.open(); 1909 } 1910 1911 if (filename == null) 1912 return; 1913 1914 File chosenFile = new File(filename); 1915 if (!chosenFile.exists()) { 1916 Tools.showError(shell, "Import Data from Binary File", "Data import error: " + chosenFile.getName() + " does not exist."); 1917 return; 1918 } 1919 1920 if (!Tools.showConfirm(shell, "Import Data from Binary File", "Do you want to paste selected data?")) 1921 return; 1922 1923 ByteOrder bo = ByteOrder.nativeOrder(); 1924 if (binaryOrder == 1) 1925 bo = ByteOrder.nativeOrder(); 1926 else if (binaryOrder == 2) 1927 bo = ByteOrder.LITTLE_ENDIAN; 1928 else if (binaryOrder == 3) 1929 bo = ByteOrder.BIG_ENDIAN; 1930 1931 try { 1932 if (Tools.getBinaryDataFromFile(dataValue, chosenFile.getAbsolutePath(), bo)) 1933 dataProvider.setIsValueChanged(true); 1934 1935 dataTable.doCommand(new StructuralRefreshCommand()); 1936 } 1937 catch (Exception ex) { 1938 log.debug("importBinaryData():", ex); 1939 } 1940 catch (OutOfMemoryError e) { 1941 log.debug("importBinaryData(): Out of memory"); 1942 } 1943 } 1944 1945 /** 1946 * Convert selected data based on predefined math functions. 1947 */ 1948 private void mathConversion() throws Exception { 1949 if (isReadOnly) { 1950 log.debug("mathConversion(): can't convert read-only data"); 1951 return; 1952 } 1953 1954 int cols = selectionLayer.getSelectedColumnPositions().length; 1955 if ((dataObject instanceof CompoundDS) && (cols > 1)) { 1956 shell.getDisplay().beep(); 1957 Tools.showError(shell, "Convert", "Please select one column at a time for math conversion" + "for compound dataset."); 1958 log.debug("mathConversion(): more than one column selected for CompoundDS"); 1959 return; 1960 } 1961 1962 Object theData = getSelectedData(); 1963 if (theData == null) { 1964 shell.getDisplay().beep(); 1965 Tools.showError(shell, "Convert", "No data is selected."); 1966 log.debug("mathConversion(): no data selected"); 1967 return; 1968 } 1969 1970 MathConversionDialog dialog = new MathConversionDialog(shell, theData); 1971 dialog.open(); 1972 1973 if (dialog.isConverted()) { 1974 if (dataObject instanceof CompoundDS) { 1975 Object colData = null; 1976 try { 1977 colData = ((List<?>) dataObject.getData()).get(selectionLayer.getSelectedColumnPositions()[0]); 1978 } 1979 catch (Exception ex) { 1980 log.debug("mathConversion(): ", ex); 1981 } 1982 1983 if (colData != null) { 1984 int size = Array.getLength(theData); 1985 System.arraycopy(theData, 0, colData, 0, size); 1986 } 1987 } 1988 else { 1989 int rows = selectionLayer.getSelectedRowCount(); 1990 1991 // Since NatTable returns the selected row positions as a Set<Range>, convert 1992 // this to 1993 // an Integer[] 1994 Set<Range> rowPositions = selectionLayer.getSelectedRowPositions(); 1995 Set<Integer> selectedRowPos = new LinkedHashSet<>(); 1996 Iterator<Range> i1 = rowPositions.iterator(); 1997 while (i1.hasNext()) 1998 selectedRowPos.addAll(i1.next().getMembers()); 1999 2000 int r0 = selectedRowPos.toArray(new Integer[0])[0]; 2001 int c0 = selectionLayer.getSelectedColumnPositions()[0]; 2002 2003 int w = dataTable.getPreferredColumnCount() - 1; 2004 int idxSrc = 0; 2005 int idxDst = 0; 2006 2007 for (int i = 0; i < rows; i++) { 2008 idxDst = (r0 + i) * w + c0; 2009 System.arraycopy(theData, idxSrc, dataValue, idxDst, cols); 2010 idxSrc += cols; 2011 } 2012 } 2013 2014 System.gc(); 2015 2016 dataProvider.setIsValueChanged(true); 2017 } 2018 } 2019 2020 private void showLineplot() { 2021 // Since NatTable returns the selected row positions as a Set<Range>, convert 2022 // this to 2023 // an Integer[] 2024 Set<Range> rowPositions = selectionLayer.getSelectedRowPositions(); 2025 Set<Integer> selectedRowPos = new LinkedHashSet<>(); 2026 Iterator<Range> i1 = rowPositions.iterator(); 2027 while (i1.hasNext()) { 2028 selectedRowPos.addAll(i1.next().getMembers()); 2029 } 2030 2031 Integer[] rows = selectedRowPos.toArray(new Integer[0]); 2032 int[] cols = selectionLayer.getSelectedColumnPositions(); 2033 2034 if ((rows == null) || (cols == null) || (rows.length <= 0) || (cols.length <= 0)) { 2035 shell.getDisplay().beep(); 2036 Tools.showError(shell, "Select", "Select rows/columns to draw line plot."); 2037 return; 2038 } 2039 2040 int nrow = dataTable.getPreferredRowCount() - 1; 2041 int ncol = dataTable.getPreferredColumnCount() - 1; 2042 2043 log.trace("DefaultTableView showLineplot: {} - {}", nrow, ncol); 2044 LinePlotOption lpo = new LinePlotOption(shell, SWT.NONE, nrow, ncol); 2045 lpo.open(); 2046 2047 int plotType = lpo.getPlotBy(); 2048 if (plotType == LinePlotOption.NO_PLOT) 2049 return; 2050 2051 boolean isRowPlot = (plotType == LinePlotOption.ROW_PLOT); 2052 int xIndex = lpo.getXindex(); 2053 2054 // figure out to plot data by row or by column 2055 // Plot data by rows if all columns are selected and part of 2056 // rows are selected, otherwise plot data by column 2057 double[][] data = null; 2058 int nLines = 0; 2059 String title = "Lineplot - " + ((HObject) dataObject).getPath() + ((HObject) dataObject).getName(); 2060 String[] lineLabels = null; 2061 double[] yRange = { Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY }; 2062 double[] xData = null; 2063 2064 if (isRowPlot) { 2065 title += " - by row"; 2066 nLines = rows.length; 2067 if (nLines > 10) { 2068 shell.getDisplay().beep(); 2069 nLines = 10; 2070 Tools.showWarning(shell, "Select", 2071 "More than 10 rows are selected.\n" + "The first 10 rows will be displayed."); 2072 } 2073 lineLabels = new String[nLines]; 2074 data = new double[nLines][cols.length]; 2075 2076 double value = 0.0; 2077 for (int i = 0; i < nLines; i++) { 2078 lineLabels[i] = String.valueOf(rows[i] + indexBase); 2079 for (int j = 0; j < cols.length; j++) { 2080 data[i][j] = 0; 2081 try { 2082 value = Double.parseDouble(selectionLayer.getDataValueByPosition(cols[j], rows[i]).toString()); 2083 data[i][j] = value; 2084 yRange[0] = Math.min(yRange[0], value); 2085 yRange[1] = Math.max(yRange[1], value); 2086 } 2087 catch (NumberFormatException ex) { 2088 log.debug("rows[{}]:", i, ex); 2089 } 2090 } 2091 } 2092 2093 if (xIndex >= 0) { 2094 xData = new double[cols.length]; 2095 for (int j = 0; j < cols.length; j++) { 2096 xData[j] = 0; 2097 try { 2098 value = Double.parseDouble(selectionLayer.getDataValueByPosition(cols[j], xIndex).toString()); 2099 xData[j] = value; 2100 } 2101 catch (NumberFormatException ex) { 2102 log.debug("xIndex of {}:", xIndex, ex); 2103 } 2104 } 2105 } 2106 } 2107 else { 2108 title += " - by column"; 2109 nLines = cols.length; 2110 if (nLines > 10) { 2111 shell.getDisplay().beep(); 2112 nLines = 10; 2113 Tools.showWarning(shell, "Select", 2114 "More than 10 columns are selected.\n" + "The first 10 columns will be displayed."); 2115 } 2116 lineLabels = new String[nLines]; 2117 data = new double[nLines][rows.length]; 2118 double value = 0.0; 2119 for (int j = 0; j < nLines; j++) { 2120 lineLabels[j] = columnHeaderDataProvider.getDataValue(cols[j] + indexBase, 0).toString(); 2121 for (int i = 0; i < rows.length; i++) { 2122 data[j][i] = 0; 2123 try { 2124 value = Double.parseDouble(selectionLayer.getDataValueByPosition(cols[j], rows[i]).toString()); 2125 data[j][i] = value; 2126 yRange[0] = Math.min(yRange[0], value); 2127 yRange[1] = Math.max(yRange[1], value); 2128 } 2129 catch (NumberFormatException ex) { 2130 log.debug("cols[{}]:", j, ex); 2131 } 2132 } 2133 } 2134 2135 if (xIndex >= 0) { 2136 xData = new double[rows.length]; 2137 for (int j = 0; j < rows.length; j++) { 2138 xData[j] = 0; 2139 try { 2140 value = Double.parseDouble(selectionLayer.getDataValueByPosition(xIndex, rows[j]).toString()); 2141 xData[j] = value; 2142 } 2143 catch (NumberFormatException ex) { 2144 log.debug("xIndex of {}:", xIndex, ex); 2145 } 2146 } 2147 } 2148 } 2149 2150 int n = removeInvalidPlotData(data, xData, yRange); 2151 if (n < data[0].length) { 2152 double[][] dataNew = new double[data.length][n]; 2153 for (int i = 0; i < data.length; i++) 2154 System.arraycopy(data[i], 0, dataNew[i], 0, n); 2155 2156 data = dataNew; 2157 2158 if (xData != null) { 2159 double[] xDataNew = new double[n]; 2160 System.arraycopy(xData, 0, xDataNew, 0, n); 2161 xData = xDataNew; 2162 } 2163 } 2164 2165 // allow to draw a flat line: all values are the same 2166 if (yRange[0] == yRange[1]) { 2167 yRange[1] += 1; 2168 yRange[0] -= 1; 2169 } 2170 else if (yRange[0] > yRange[1]) { 2171 shell.getDisplay().beep(); 2172 Tools.showError(shell, "Select", "Cannot show line plot for the selected data. \n" + "Please check the data range: (" 2173 + yRange[0] + ", " + yRange[1] + ")."); 2174 return; 2175 } 2176 if (xData == null) { // use array index and length for x data range 2177 xData = new double[2]; 2178 xData[0] = indexBase; // 1- or zero-based 2179 xData[1] = data[0].length + (double) indexBase - 1; // maximum index 2180 } 2181 2182 Chart cv = new Chart(shell, title, Chart.LINEPLOT, data, xData, yRange); 2183 cv.setLineLabels(lineLabels); 2184 2185 String cname = dataValue.getClass().getName(); 2186 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 2187 if ((dname == 'B') || (dname == 'S') || (dname == 'I') || (dname == 'J')) 2188 cv.setTypeToInteger(); 2189 2190 cv.open(); 2191 } 2192 2193 /** 2194 * Remove values of NaN, INF from the array. 2195 * 2196 * @param data 2197 * the data array 2198 * @param xData 2199 * the x-axis data points 2200 * @param yRange 2201 * the range of data values 2202 * 2203 * @return number of data points in the plot data if successful; otherwise, 2204 * returns false. 2205 */ 2206 private int removeInvalidPlotData(double[][] data, double[] xData, double[] yRange) { 2207 int idx = 0; 2208 boolean hasInvalid = false; 2209 2210 if (data == null || yRange == null) 2211 return -1; 2212 2213 yRange[0] = Double.POSITIVE_INFINITY; 2214 yRange[1] = Double.NEGATIVE_INFINITY; 2215 2216 for (int i = 0; i < data[0].length; i++) { 2217 hasInvalid = false; 2218 2219 for (int j = 0; j < data.length; j++) { 2220 hasInvalid = Tools.isNaNINF(data[j][i]); 2221 if (xData != null) 2222 hasInvalid = hasInvalid || Tools.isNaNINF(xData[i]); 2223 2224 if (hasInvalid) 2225 break; 2226 else { 2227 data[j][idx] = data[j][i]; 2228 if (xData != null) 2229 xData[idx] = xData[i]; 2230 yRange[0] = Math.min(yRange[0], data[j][idx]); 2231 yRange[1] = Math.max(yRange[1], data[j][idx]); 2232 } 2233 } 2234 2235 if (!hasInvalid) 2236 idx++; 2237 } 2238 2239 return idx; 2240 } 2241 2242 /** 2243 * An implementation of a GridLayer with support for column grouping and with 2244 * editing triggered by a double click instead of a single click. 2245 */ 2246 protected class EditingGridLayer extends GridLayer 2247 { 2248 /** Create the Grid Layer with editing triggered by a 2249 * double click instead of a single click. 2250 * 2251 * @param bodyLayer 2252 * the body layer 2253 * @param columnHeaderLayer 2254 * the Column Header layer 2255 * @param rowHeaderLayer 2256 * the Row Header layer 2257 * @param cornerLayer 2258 * the Corner Layer 2259 */ 2260 public EditingGridLayer(ILayer bodyLayer, ILayer columnHeaderLayer, ILayer rowHeaderLayer, ILayer cornerLayer) { 2261 super(bodyLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer, false); 2262 2263 // Left-align cells, change font for rendering cell text 2264 // and add cell data display converter for displaying as 2265 // Hexadecimal, Binary, etc. 2266 this.addConfiguration(new AbstractRegistryConfiguration() { 2267 @Override 2268 public void configureRegistry(IConfigRegistry configRegistry) { 2269 Style cellStyle = new Style(); 2270 2271 cellStyle.setAttributeValue(CellStyleAttributes.HORIZONTAL_ALIGNMENT, HorizontalAlignmentEnum.LEFT); 2272 cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, 2273 Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); 2274 2275 if (curFont != null) 2276 cellStyle.setAttributeValue(CellStyleAttributes.FONT, curFont); 2277 else 2278 cellStyle.setAttributeValue(CellStyleAttributes.FONT, Display.getDefault().getSystemFont()); 2279 2280 configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, cellStyle, 2281 DisplayMode.NORMAL, GridRegion.BODY); 2282 2283 configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, cellStyle, 2284 DisplayMode.SELECT, GridRegion.BODY); 2285 2286 // Add data display conversion capability 2287 try { 2288 dataDisplayConverter = DataDisplayConverterFactory.getDataDisplayConverter(dataObject); 2289 2290 configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER, 2291 dataDisplayConverter, DisplayMode.NORMAL, GridRegion.BODY); 2292 } 2293 catch (Exception ex) { 2294 log.debug("EditingGridLayer: failed to retrieve a DataDisplayConverter: ", ex); 2295 dataDisplayConverter = null; 2296 } 2297 } 2298 }); 2299 2300 if (isStdRef || isRegRef || isObjRef) { 2301 // Show data pointed to by reference on double click 2302 this.addConfiguration(new AbstractUiBindingConfiguration() { 2303 @Override 2304 public void configureUiBindings(UiBindingRegistry uiBindingRegistry) { 2305 uiBindingRegistry.registerDoubleClickBinding(new MouseEventMatcher(), new IMouseAction() { 2306 @Override 2307 public void run(NatTable table, MouseEvent event) { 2308 if (!(isStdRef || isRegRef || isObjRef)) 2309 return; 2310 2311 viewType = ViewType.TABLE; 2312 2313 Object theData = null; 2314 try { 2315 theData = ((Dataset) getDataObject()).getData(); 2316 } 2317 catch (Exception ex) { 2318 log.debug("show reference data: ", ex); 2319 theData = null; 2320 Tools.showError(shell, "Select", ex.getMessage()); 2321 } 2322 2323 if (theData == null) { 2324 shell.getDisplay().beep(); 2325 Tools.showError(shell, "Select", "No data selected."); 2326 return; 2327 } 2328 2329 // Since NatTable returns the selected row positions as a Set<Range>, convert 2330 // this to an Integer[] 2331 Set<Range> rowPositions = selectionLayer.getSelectedRowPositions(); 2332 Set<Integer> selectedRowPos = new LinkedHashSet<>(); 2333 Iterator<Range> i1 = rowPositions.iterator(); 2334 while (i1.hasNext()) { 2335 selectedRowPos.addAll(i1.next().getMembers()); 2336 } 2337 2338 Integer[] selectedRows = selectedRowPos.toArray(new Integer[0]); 2339 if (selectedRows == null || selectedRows.length <= 0) { 2340 log.debug("show reference data: no data selected"); 2341 Tools.showError(shell, "Select", "No data selected."); 2342 return; 2343 } 2344 int len = Array.getLength(selectedRows); 2345 for (int i = 0; i < len; i++) { 2346 byte[] rElements = null; 2347 if (theData instanceof ArrayList) 2348 rElements = (byte[]) ((ArrayList) theData).get(selectedRows[i]); 2349 else 2350 rElements = (byte[]) theData; 2351 2352 if (isStdRef) 2353 showStdRefData(rElements); 2354 else if (isRegRef) 2355 showRegRefData(rElements); 2356 else if (isObjRef) 2357 showObjRefData(rElements); 2358 } 2359 } 2360 }); 2361 } 2362 }); 2363 } 2364 else { 2365 // Add default bindings for editing 2366 this.addConfiguration(new DefaultEditConfiguration()); 2367 2368 // Register cell editing rules with the table and add 2369 // data validation 2370 this.addConfiguration(new AbstractRegistryConfiguration() { 2371 @Override 2372 public void configureRegistry(IConfigRegistry configRegistry) { 2373 IEditableRule editingRule = getDataEditingRule(dataObject); 2374 if (editingRule != null) { 2375 // Register cell editing rules with table 2376 configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, 2377 editingRule, DisplayMode.EDIT); 2378 } 2379 2380 // Add data validator and validation error handler 2381 DataValidator validator = null; 2382 try { 2383 validator = DataValidatorFactory.getDataValidator(dataObject); 2384 } 2385 catch (Exception ex) { 2386 log.debug("EditingGridLayer: no DataValidator retrieved, data editing will be disabled"); 2387 } 2388 2389 if (validator != null) { 2390 configRegistry.registerConfigAttribute(EditConfigAttributes.DATA_VALIDATOR, validator, 2391 DisplayMode.EDIT, GridRegion.BODY); 2392 } 2393 2394 configRegistry.registerConfigAttribute(EditConfigAttributes.VALIDATION_ERROR_HANDLER, 2395 new DialogErrorHandling(), DisplayMode.EDIT, GridRegion.BODY); 2396 } 2397 }); 2398 2399 // Change cell editing to be on double click rather than single click 2400 // and allow editing of cells by pressing keys as well 2401 this.addConfiguration(new AbstractUiBindingConfiguration() { 2402 @Override 2403 public void configureUiBindings(UiBindingRegistry uiBindingRegistry) { 2404 uiBindingRegistry.registerFirstKeyBinding(new LetterOrDigitKeyEventMatcher(), new KeyEditAction()); 2405 uiBindingRegistry.registerFirstDoubleClickBinding( 2406 new CellEditorMouseEventMatcher(), new MouseEditAction()); 2407 } 2408 }); 2409 } 2410 } 2411 } 2412 2413 /** 2414 * An implementation of the table's Row Header which adapts to the current font. 2415 */ 2416 protected class RowHeader extends RowHeaderLayer 2417 { 2418 /** Create the RowHeader which adapts to the current font. 2419 * 2420 * @param baseLayer 2421 * the base layer 2422 * @param verticalLayerDependency 2423 * the vertical layer dependency 2424 * @param selectionLayer 2425 * the selection layer 2426 */ 2427 public RowHeader(IUniqueIndexLayer baseLayer, ILayer verticalLayerDependency, SelectionLayer selectionLayer) { 2428 super(baseLayer, verticalLayerDependency, selectionLayer); 2429 2430 this.addConfiguration(new DefaultRowHeaderLayerConfiguration() { 2431 @Override 2432 public void addRowHeaderStyleConfig() { 2433 this.addConfiguration(new DefaultRowHeaderStyleConfiguration() { 2434 { 2435 this.cellPainter = new LineBorderDecorator(new TextPainter(false, true, 2, true)); 2436 this.bgColor = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); 2437 this.font = (curFont == null) ? Display.getDefault().getSystemFont() : curFont; 2438 } 2439 }); 2440 } 2441 }); 2442 } 2443 } 2444 2445 /** 2446 * Custom Row Header data provider to set row indices based on Index Base for 2447 * both Scalar Datasets and Compound Datasets. 2448 */ 2449 protected class RowHeaderDataProvider implements IDataProvider 2450 { 2451 private int rank; 2452 private int space_type; 2453 private long[] dims; 2454 private long[] startArray; 2455 private long[] strideArray; 2456 private int[] selectedIndex; 2457 2458 /** the start value. */ 2459 protected int start; 2460 /** the stride value. */ 2461 protected int stride; 2462 2463 private int nrows; 2464 2465 /** Create the Row Header data provider to set row indices based on Index Base for 2466 * both Scalar Datasets and Compound Datasets. 2467 * 2468 * @param theDataObject 2469 * the data object 2470 */ 2471 public RowHeaderDataProvider(DataFormat theDataObject) { 2472 this.space_type = theDataObject.getSpaceType(); 2473 this.rank = theDataObject.getRank(); 2474 this.dims = theDataObject.getSelectedDims(); 2475 this.startArray = theDataObject.getStartDims(); 2476 this.strideArray = theDataObject.getStride(); 2477 this.selectedIndex = theDataObject.getSelectedIndex(); 2478 2479 if (rank > 1) 2480 this.nrows = (int) theDataObject.getHeight(); 2481 else 2482 this.nrows = (int) dims[0]; 2483 2484 start = (int) startArray[selectedIndex[0]]; 2485 stride = (int) strideArray[selectedIndex[0]]; 2486 } 2487 2488 2489 /** Update the Row Header data provider to set row indices based on Index Base for 2490 * both Scalar Datasets and Compound Datasets. 2491 * 2492 * @param theDataObject 2493 * the data object 2494 */ 2495 public void updateRows(DataFormat theDataObject) { 2496 this.rank = theDataObject.getRank(); 2497 this.dims = theDataObject.getSelectedDims(); 2498 this.selectedIndex = theDataObject.getSelectedIndex(); 2499 2500 if (rank > 1) 2501 this.nrows = (int) theDataObject.getHeight(); 2502 else 2503 this.nrows = (int) dims[0]; 2504 } 2505 2506 @Override 2507 public int getColumnCount() { 2508 return 1; 2509 } 2510 2511 @Override 2512 public int getRowCount() { 2513 return nrows; 2514 } 2515 2516 @Override 2517 public Object getDataValue(int columnIndex, int rowIndex) { 2518 return String.valueOf(start + indexBase + (rowIndex * stride)); 2519 } 2520 2521 @Override 2522 public void setDataValue(int columnIndex, int rowIndex, Object newValue) { 2523 // Intentional 2524 } 2525 } 2526 2527 /** 2528 * An implementation of the table's Column Header which adapts to the current 2529 * font. 2530 */ 2531 protected class ColumnHeader extends ColumnHeaderLayer 2532 { 2533 /** Create the ColumnHeader which adapts to the current font. 2534 * 2535 * @param baseLayer 2536 * the base layer 2537 * @param horizontalLayerDependency 2538 * the horizontal layer dependency 2539 * @param selectionLayer 2540 * the selection layer 2541 */ 2542 public ColumnHeader(IUniqueIndexLayer baseLayer, ILayer horizontalLayerDependency, 2543 SelectionLayer selectionLayer) { 2544 super(baseLayer, horizontalLayerDependency, selectionLayer); 2545 2546 this.addConfiguration(new DefaultColumnHeaderLayerConfiguration() { 2547 @Override 2548 public void addColumnHeaderStyleConfig() { 2549 this.addConfiguration(new DefaultColumnHeaderStyleConfiguration() { 2550 { 2551 this.cellPainter = new BeveledBorderDecorator(new TextPainter(false, true, 2, true)); 2552 this.bgColor = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW); 2553 this.font = (curFont == null) ? Display.getDefault().getSystemFont() : curFont; 2554 } 2555 }); 2556 } 2557 }); 2558 } 2559 } 2560 2561 /** Context-menu for dealing with region and object references */ 2562 protected class RefContextMenu extends AbstractUiBindingConfiguration 2563 { 2564 private final Menu contextMenu; 2565 2566 /** Create the Context-menu for dealing with region and object references. 2567 * 2568 * @param table 2569 * the NatTable object 2570 */ 2571 public RefContextMenu(NatTable table) { 2572 this.contextMenu = createMenu(table).build(); 2573 } 2574 2575 private void showRefTable() { 2576 log.trace("show reference data: Show data as {}", viewType); 2577 2578 Object theData = getSelectedData(); 2579 if (theData == null) { 2580 shell.getDisplay().beep(); 2581 Tools.showError(shell, "Select", "No data selected."); 2582 return; 2583 } 2584 if (!(theData instanceof byte[]) && !(theData instanceof ArrayList)) { 2585 shell.getDisplay().beep(); 2586 Tools.showError(shell, "Select", "Data selected is not a reference."); 2587 return; 2588 } 2589 log.trace("show reference data: Data is {}", theData); 2590 2591 // Since NatTable returns the selected row positions as a Set<Range>, convert 2592 // this to an Integer[] 2593 Set<Range> rowPositions = selectionLayer.getSelectedRowPositions(); 2594 Set<Integer> selectedRowPos = new LinkedHashSet<>(); 2595 Iterator<Range> i1 = rowPositions.iterator(); 2596 while (i1.hasNext()) 2597 selectedRowPos.addAll(i1.next().getMembers()); 2598 2599 Integer[] selectedRows = selectedRowPos.toArray(new Integer[0]); 2600 int[] selectedCols = selectionLayer.getSelectedColumnPositions(); 2601 if (selectedRows == null || selectedRows.length <= 0) { 2602 shell.getDisplay().beep(); 2603 Tools.showError(shell, "Select", "No data selected."); 2604 log.trace("show reference data: Show data as {}: selectedRows is empty", viewType); 2605 return; 2606 } 2607 2608 int len = Array.getLength(selectedRows) * Array.getLength(selectedCols); 2609 log.trace("show reference data: Show data as {}: len={}", viewType, len); 2610 if (len > 1) { 2611 shell.getDisplay().beep(); 2612 Tools.showError(shell, "Select", "Reference selection must be one cell."); 2613 log.trace("show reference data: Show data as {}: Too much data", viewType); 2614 return; 2615 } 2616 2617 for (int i = 0; i < len; i++) { 2618 byte[] rElements = null; 2619 if (theData instanceof ArrayList) 2620 rElements = (byte[]) ((ArrayList) theData).get(i); 2621 else 2622 rElements = (byte[]) theData; 2623 2624 if (rElements.length == HDF5Constants.H5R_DSET_REG_REF_BUF_SIZE) { 2625 showRegRefData(rElements); 2626 } 2627 else if (rElements.length == HDF5Constants.H5R_OBJ_REF_BUF_SIZE) { 2628 showObjRefData(rElements); 2629 } 2630 else { 2631 showStdRefData(rElements); 2632 } 2633 } 2634 } 2635 2636 private PopupMenuBuilder createMenu(NatTable table) { 2637 Menu menu = new Menu(table); 2638 2639 MenuItem item = new MenuItem(menu, SWT.PUSH); 2640 item.setText("Show As &Table"); 2641 item.addSelectionListener(new SelectionAdapter() { 2642 @Override 2643 public void widgetSelected(SelectionEvent e) { 2644 viewType = ViewType.TABLE; 2645 showRefTable(); 2646 } 2647 }); 2648 2649 item = new MenuItem(menu, SWT.PUSH); 2650 item.setText("Show As &Image"); 2651 item.addSelectionListener(new SelectionAdapter() { 2652 @Override 2653 public void widgetSelected(SelectionEvent e) { 2654 viewType = ViewType.IMAGE; 2655 showRefTable(); 2656 } 2657 }); 2658 2659 return new PopupMenuBuilder(table, menu); 2660 } 2661 2662 @Override 2663 public void configureUiBindings(UiBindingRegistry uiBindingRegistry) { 2664 uiBindingRegistry.registerMouseDownBinding( 2665 new MouseEventMatcher(SWT.NONE, GridRegion.BODY, MouseEventMatcher.RIGHT_BUTTON), 2666 new PopupMenuAction(this.contextMenu)); 2667 } 2668 } 2669 2670 private class LinePlotOption extends Dialog 2671 { 2672 private Shell linePlotOptionShell; 2673 2674 private Button rowButton, colButton; 2675 2676 private Combo rowBox, colBox; 2677 2678 public static final int NO_PLOT = -1; 2679 public static final int ROW_PLOT = 0; 2680 public static final int COLUMN_PLOT = 1; 2681 2682 private int nrow, ncol; 2683 2684 private int idx_xaxis = -1; 2685 private int plotType = -1; 2686 2687 public LinePlotOption(Shell parent, int style, int nrow, int ncol) { 2688 super(parent, style); 2689 2690 this.nrow = nrow; 2691 this.ncol = ncol; 2692 } 2693 2694 public void open() { 2695 Shell parent = getParent(); 2696 linePlotOptionShell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 2697 linePlotOptionShell.setFont(curFont); 2698 linePlotOptionShell.setText("Line Plot Options -- " + ((HObject) dataObject).getName()); 2699 linePlotOptionShell.setImages(ViewProperties.getHdfIcons()); 2700 linePlotOptionShell.setLayout(new GridLayout(1, true)); 2701 2702 Label label = new Label(linePlotOptionShell, SWT.RIGHT); 2703 label.setFont(curFont); 2704 label.setText("Select Line Plot Options:"); 2705 2706 Composite content = new Composite(linePlotOptionShell, SWT.BORDER); 2707 content.setLayout(new GridLayout(3, false)); 2708 content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 2709 2710 label = new Label(content, SWT.RIGHT); 2711 label.setFont(curFont); 2712 label.setText(" Series in:"); 2713 2714 colButton = new Button(content, SWT.RADIO); 2715 colButton.setFont(curFont); 2716 colButton.setText("Column"); 2717 colButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 2718 colButton.addSelectionListener(new SelectionAdapter() { 2719 @Override 2720 public void widgetSelected(SelectionEvent e) { 2721 colBox.setEnabled(true); 2722 rowBox.setEnabled(false); 2723 } 2724 }); 2725 2726 rowButton = new Button(content, SWT.RADIO); 2727 rowButton.setFont(curFont); 2728 rowButton.setText("Row"); 2729 rowButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 2730 rowButton.addSelectionListener(new SelectionAdapter() { 2731 @Override 2732 public void widgetSelected(SelectionEvent e) { 2733 rowBox.setEnabled(true); 2734 colBox.setEnabled(false); 2735 } 2736 }); 2737 2738 label = new Label(content, SWT.RIGHT); 2739 label.setFont(curFont); 2740 label.setText(" For abscissa use:"); 2741 2742 long[] startArray = dataObject.getStartDims(); 2743 long[] strideArray = dataObject.getStride(); 2744 int[] selectedIndex = dataObject.getSelectedIndex(); 2745 int start = (int) startArray[selectedIndex[0]]; 2746 int stride = (int) strideArray[selectedIndex[0]]; 2747 2748 colBox = new Combo(content, SWT.SINGLE | SWT.READ_ONLY); 2749 colBox.setFont(curFont); 2750 GridData colBoxData = new GridData(SWT.FILL, SWT.FILL, true, false); 2751 colBoxData.minimumWidth = 100; 2752 colBox.setLayoutData(colBoxData); 2753 2754 colBox.add("array index"); 2755 2756 for (int i = 0; i < ncol; i++) 2757 colBox.add("column " + columnHeaderDataProvider.getDataValue(i, 0)); 2758 2759 rowBox = new Combo(content, SWT.SINGLE | SWT.READ_ONLY); 2760 rowBox.setFont(curFont); 2761 GridData rowBoxData = new GridData(SWT.FILL, SWT.FILL, true, false); 2762 rowBoxData.minimumWidth = 100; 2763 rowBox.setLayoutData(rowBoxData); 2764 2765 rowBox.add("array index"); 2766 2767 for (int i = 0; i < nrow; i++) 2768 rowBox.add("row " + (start + indexBase + i * stride)); 2769 2770 // Create Ok/Cancel button region 2771 Composite buttonComposite = new Composite(linePlotOptionShell, SWT.NONE); 2772 buttonComposite.setLayout(new GridLayout(2, true)); 2773 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 2774 2775 Button okButton = new Button(buttonComposite, SWT.PUSH); 2776 okButton.setFont(curFont); 2777 okButton.setText(" &OK "); 2778 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 2779 okButton.addSelectionListener(new SelectionAdapter() { 2780 @Override 2781 public void widgetSelected(SelectionEvent e) { 2782 if (colButton.getSelection()) { 2783 idx_xaxis = colBox.getSelectionIndex() - 1; 2784 plotType = COLUMN_PLOT; 2785 } 2786 else { 2787 idx_xaxis = rowBox.getSelectionIndex() - 1; 2788 plotType = ROW_PLOT; 2789 } 2790 2791 linePlotOptionShell.dispose(); 2792 } 2793 }); 2794 2795 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 2796 cancelButton.setFont(curFont); 2797 cancelButton.setText(" &Cancel "); 2798 cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 2799 cancelButton.addSelectionListener(new SelectionAdapter() { 2800 @Override 2801 public void widgetSelected(SelectionEvent e) { 2802 plotType = NO_PLOT; 2803 linePlotOptionShell.dispose(); 2804 } 2805 }); 2806 2807 colButton.setSelection(true); 2808 rowButton.setSelection(false); 2809 2810 colBox.select(0); 2811 rowBox.select(0); 2812 2813 colBox.setEnabled(colButton.getSelection()); 2814 rowBox.setEnabled(rowButton.getSelection()); 2815 2816 linePlotOptionShell.pack(); 2817 2818 linePlotOptionShell.setMinimumSize(linePlotOptionShell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 2819 2820 Rectangle parentBounds = parent.getBounds(); 2821 Point shellSize = linePlotOptionShell.getSize(); 2822 linePlotOptionShell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 2823 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 2824 2825 linePlotOptionShell.open(); 2826 2827 Display display = parent.getDisplay(); 2828 while (!linePlotOptionShell.isDisposed()) 2829 if (!display.readAndDispatch()) display.sleep(); 2830 } 2831 2832 int getXindex() { 2833 return idx_xaxis; 2834 } 2835 2836 int getPlotBy() { 2837 return plotType; 2838 } 2839 } 2840}