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