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