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