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 COPYING file, which can be found * 009 * at the root of the source code distribution tree, * 010 * or in https://www.hdfgroup.org/licenses. * 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.dialog; 016 017import java.util.Iterator; 018import java.util.List; 019import java.util.StringTokenizer; 020import java.util.Vector; 021 022import hdf.object.CompoundDS; 023import hdf.object.Dataset; 024import hdf.object.Datatype; 025import hdf.object.Group; 026import hdf.object.HObject; 027import hdf.object.h5.H5CompoundDS; 028import hdf.view.Tools; 029import hdf.view.ViewProperties; 030 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034import org.eclipse.swt.SWT; 035import org.eclipse.swt.custom.CCombo; 036import org.eclipse.swt.custom.TableEditor; 037import org.eclipse.swt.events.DisposeEvent; 038import org.eclipse.swt.events.DisposeListener; 039import org.eclipse.swt.events.ModifyEvent; 040import org.eclipse.swt.events.ModifyListener; 041import org.eclipse.swt.events.SelectionAdapter; 042import org.eclipse.swt.events.SelectionEvent; 043import org.eclipse.swt.events.TraverseEvent; 044import org.eclipse.swt.events.TraverseListener; 045import org.eclipse.swt.graphics.Point; 046import org.eclipse.swt.graphics.Rectangle; 047import org.eclipse.swt.layout.GridData; 048import org.eclipse.swt.layout.GridLayout; 049import org.eclipse.swt.widgets.Button; 050import org.eclipse.swt.widgets.Combo; 051import org.eclipse.swt.widgets.Composite; 052import org.eclipse.swt.widgets.Display; 053import org.eclipse.swt.widgets.Event; 054import org.eclipse.swt.widgets.Label; 055import org.eclipse.swt.widgets.Listener; 056import org.eclipse.swt.widgets.Shell; 057import org.eclipse.swt.widgets.Table; 058import org.eclipse.swt.widgets.TableColumn; 059import org.eclipse.swt.widgets.TableItem; 060import org.eclipse.swt.widgets.Text; 061 062/** 063 * NewCompoundDatasetDialog shows a message dialog requesting user input for creating 064 * a new HDF4/5 compound dataset. 065 * 066 * @author Jordan T. Henderson 067 * @version 2.4 1/7/2015 068 */ 069public class NewCompoundDatasetDialog extends NewDataObjectDialog { 070 071 private static final Logger log = LoggerFactory.getLogger(NewCompoundDatasetDialog.class); 072 073 private static final String[] DATATYPE_NAMES = { 074 "byte (8-bit)", // 0 075 "short (16-bit)", // 1 076 "int (32-bit)", // 2 077 "unsigned byte (8-bit)", // 3 078 "unsigned short (16-bit)", // 4 079 "unsigned int (32-bit)", // 5 080 "long (64-bit)", // 6 081 "float (32-bit)", // 7 082 "double (64-bit)", // 8 083 "string", // 9 084 "enum", // 10 085 "unsigned long (64-bit)", // 11 086 "float16 (16-bit)", // 12 087 "long double (128-bit)" // 13 088 }; 089 090 private Combo parentChoice, nFieldBox, templateChoice; 091 092 /** A list of current groups */ 093 private Vector<Group> groupList; 094 private Vector<CompoundDS> compoundDSList; 095 096 private int numberOfMembers; 097 098 private Table table; 099 100 private TableEditor[][] editors; 101 102 private Text nameField, currentSizeField, maxSizeField, chunkSizeField; 103 104 private Combo compressionLevel, rankChoice; 105 private Button checkCompression; 106 private Button checkContiguous, checkChunked; 107 108 /** 109 * Constructs a NewCompoundDatasetDialog with specified list of possible parent 110 * groups. 111 * 112 * @param parent 113 * the parent shell of the dialog 114 * @param pGroup 115 * the parent group which the new group is added to. 116 * @param objs 117 * the list of all objects. 118 */ 119 public NewCompoundDatasetDialog(Shell parent, Group pGroup, List<?> objs) 120 { 121 super(parent, pGroup, objs); 122 123 numberOfMembers = 2; 124 125 groupList = new Vector<>(objs.size()); 126 compoundDSList = new Vector<>(objs.size()); 127 } 128 129 /** 130 * Open the NewCompoundDatasetDialog for adding a new compound dataset. 131 */ 132 public void open() 133 { 134 Shell parent = getParent(); 135 shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 136 shell.setFont(curFont); 137 shell.setText("New Compound Dataset..."); 138 shell.setImages(ViewProperties.getHdfIcons()); 139 shell.setLayout(new GridLayout(1, false)); 140 141 // Create Name/Parent Group/Import field region 142 Composite fieldComposite = new Composite(shell, SWT.NONE); 143 GridLayout layout = new GridLayout(2, false); 144 layout.verticalSpacing = 0; 145 fieldComposite.setLayout(layout); 146 fieldComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 147 148 Label label = new Label(fieldComposite, SWT.LEFT); 149 label.setFont(curFont); 150 label.setText("Dataset name: "); 151 152 nameField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER); 153 nameField.setFont(curFont); 154 nameField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 155 156 label = new Label(fieldComposite, SWT.LEFT); 157 label.setFont(curFont); 158 label.setText("Parent group: "); 159 160 parentChoice = new Combo(fieldComposite, SWT.DROP_DOWN | SWT.READ_ONLY); 161 parentChoice.setFont(curFont); 162 parentChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 163 parentChoice.addSelectionListener(new SelectionAdapter() { 164 @Override 165 public void widgetSelected(SelectionEvent e) 166 { 167 parentObj = groupList.get(parentChoice.getSelectionIndex()); 168 } 169 }); 170 171 Object obj = null; 172 Iterator<?> iterator = objList.iterator(); 173 174 while (iterator.hasNext()) { 175 obj = iterator.next(); 176 if (obj instanceof Group) { 177 Group g = (Group)obj; 178 groupList.add(g); 179 if (g.isRoot()) { 180 parentChoice.add(HObject.SEPARATOR); 181 } 182 else { 183 parentChoice.add(g.getPath() + g.getName() + HObject.SEPARATOR); 184 } 185 } 186 else if (obj instanceof CompoundDS) { 187 compoundDSList.add((CompoundDS)obj); 188 } 189 } 190 191 if (((Group)parentObj).isRoot()) { 192 parentChoice.select(parentChoice.indexOf(HObject.SEPARATOR)); 193 } 194 else { 195 parentChoice.select( 196 parentChoice.indexOf(parentObj.getPath() + parentObj.getName() + HObject.SEPARATOR)); 197 } 198 199 label = new Label(fieldComposite, SWT.LEFT); 200 label.setFont(curFont); 201 label.setText("Import template: "); 202 203 templateChoice = new Combo(fieldComposite, SWT.DROP_DOWN | SWT.READ_ONLY); 204 templateChoice.setFont(curFont); 205 templateChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 206 templateChoice.addSelectionListener(new SelectionAdapter() { 207 @Override 208 public void widgetSelected(SelectionEvent e) 209 { 210 CompoundDS dset = null; 211 String name = templateChoice.getItem(templateChoice.getSelectionIndex()); 212 213 log.trace("templateChoice start name={}", name); 214 for (CompoundDS ds : compoundDSList) 215 if (ds.getName().equals(name)) 216 dset = ds; 217 218 if (dset == null) 219 return; 220 221 if (!dset.isInited()) 222 dset.init(); 223 224 int rank = dset.getRank(); 225 rankChoice.select(rank - 1); 226 long[] dims = dset.getDims(); 227 final String[] mNames = dset.getMemberNames(); 228 int[] mOrders = dset.getMemberOrders(); 229 Datatype[] mTypes = dset.getMemberTypes(); 230 231 String sizeStr = String.valueOf(dims[0]); 232 for (int i = 1; i < rank; i++) { 233 sizeStr += "x" + dims[i]; 234 } 235 currentSizeField.setText(sizeStr); 236 237 try { 238 ((H5CompoundDS)dset).getMetadata(); 239 } // get chunking and compression info 240 catch (Exception ex) { 241 log.debug("get chunking and compression info:", ex); 242 } 243 long[] chunks = dset.getChunkSize(); 244 if (chunks != null) { 245 checkChunked.setSelection(true); 246 sizeStr = String.valueOf(chunks[0]); 247 for (int i = 1; i < rank; i++) { 248 sizeStr += "x" + chunks[i]; 249 } 250 chunkSizeField.setText(sizeStr); 251 } 252 253 String compression = dset.getCompression(); 254 if (compression != null) { 255 int clevel = -1; 256 int comp_pos = Dataset.COMPRESSION_GZIP_TXT.length(); 257 int idx = compression.indexOf(Dataset.COMPRESSION_GZIP_TXT); 258 if (idx >= 0) { 259 try { 260 clevel = 261 Integer.parseInt(compression.substring(idx + comp_pos, idx + comp_pos + 1)); 262 } 263 catch (NumberFormatException ex) { 264 clevel = -1; 265 } 266 } 267 if (clevel > 0) { 268 checkCompression.setSelection(true); 269 compressionLevel.select(clevel); 270 } 271 } 272 273 nFieldBox.select(dset.getMemberCount() - 1); 274 nFieldBox.notifyListeners(SWT.Selection, new Event()); 275 for (int i = 0; i < numberOfMembers; i++) { 276 ((Text)editors[i][0].getEditor()).setText(mNames[i]); 277 278 log.trace("mNames[{}] = {}", i, mNames[i]); 279 int typeIdx = -1; 280 int tclass = mTypes[i].getDatatypeClass(); 281 long tsize = mTypes[i].getDatatypeSize(); 282 int tsigned = mTypes[i].getDatatypeSign(); 283 if (tclass == Datatype.CLASS_ARRAY) { 284 tclass = mTypes[i].getDatatypeBase().getDatatypeClass(); 285 tsize = mTypes[i].getDatatypeBase().getDatatypeSize(); 286 tsigned = mTypes[i].getDatatypeBase().getDatatypeSign(); 287 } 288 if (tclass == Datatype.CLASS_CHAR) { 289 if (tsigned == Datatype.SIGN_NONE) { 290 if (tsize == 1) { 291 typeIdx = 3; 292 } 293 } 294 else { 295 if (tsize == 1) { 296 typeIdx = 0; 297 } 298 } 299 } 300 if (tclass == Datatype.CLASS_INTEGER) { 301 if (tsigned == Datatype.SIGN_NONE) { 302 if (tsize == 1) { 303 typeIdx = 3; 304 } 305 else if (tsize == 2) { 306 typeIdx = 4; 307 } 308 else if (tsize == 4) { 309 typeIdx = 5; 310 } 311 else { 312 typeIdx = 11; 313 } 314 } 315 else { 316 if (tsize == 1) { 317 typeIdx = 0; 318 } 319 else if (tsize == 2) { 320 typeIdx = 1; 321 } 322 else if (tsize == 4) { 323 typeIdx = 2; 324 } 325 else { 326 typeIdx = 6; 327 } 328 } 329 } 330 else if (tclass == Datatype.CLASS_FLOAT) { 331 if (tsize == 4) { 332 typeIdx = 7; 333 } 334 else { 335 typeIdx = 8; 336 } 337 } 338 else if (tclass == Datatype.CLASS_STRING) { 339 typeIdx = 9; 340 } 341 else if (tclass == Datatype.CLASS_ENUM) { 342 typeIdx = 10; 343 } 344 if (typeIdx < 0) { 345 continue; 346 } 347 log.trace("typeIdx={}", typeIdx); 348 349 CCombo typeCombo = ((CCombo)editors[i][1].getEditor()); 350 typeCombo.select(typeIdx); 351 typeCombo.notifyListeners(SWT.Selection, new Event()); 352 353 // TODO: Array size is wrong for enums and for array types. Array types such as 8x8 354 // show as size 64, not 8x8 355 if (tclass == Datatype.CLASS_STRING) { 356 ((Text)editors[i][2].getEditor()).setText(String.valueOf(tsize)); 357 } 358 else if (tclass == Datatype.CLASS_ENUM) { 359 ((Text)editors[i][2].getEditor()).setText(mTypes[i].getEnumMembersAsString()); 360 table.getItem(i).setText(2, mTypes[i].getEnumMembersAsString()); 361 } 362 else { 363 ((Text)editors[i][2].getEditor()).setText(String.valueOf(mOrders[i])); 364 } 365 } // (int i=0; i<numberOfMembers; i++) 366 } 367 }); 368 369 Iterator<CompoundDS> it = compoundDSList.iterator(); 370 while (it.hasNext()) { 371 templateChoice.add(it.next().getName()); 372 } 373 374 // Create Dataspace region 375 org.eclipse.swt.widgets.Group dataspaceGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 376 dataspaceGroup.setLayout(new GridLayout(3, true)); 377 dataspaceGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 378 dataspaceGroup.setFont(curFont); 379 dataspaceGroup.setText("Dataspace"); 380 381 label = new Label(dataspaceGroup, SWT.LEFT); 382 label.setFont(curFont); 383 label.setText("No. of dimensions"); 384 385 label = new Label(dataspaceGroup, SWT.LEFT); 386 label.setFont(curFont); 387 label.setText("Current size"); 388 389 label = new Label(dataspaceGroup, SWT.LEFT); 390 label.setFont(curFont); 391 label.setText("Max size (-1 for unlimited)"); 392 393 rankChoice = new Combo(dataspaceGroup, SWT.DROP_DOWN | SWT.READ_ONLY); 394 rankChoice.setFont(curFont); 395 rankChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 396 rankChoice.addSelectionListener(new SelectionAdapter() { 397 @Override 398 public void widgetSelected(SelectionEvent e) 399 { 400 int rank = rankChoice.getSelectionIndex() + 1; 401 String currentSizeStr = "1"; 402 String maxSizeStr = "0"; 403 404 for (int i = 1; i < rank; i++) { 405 currentSizeStr += " x 1"; 406 maxSizeStr += " x 0"; 407 } 408 409 currentSizeField.setText(currentSizeStr); 410 maxSizeField.setText(maxSizeStr); 411 412 String currentStr = currentSizeField.getText(); 413 int idx = currentStr.lastIndexOf('x'); 414 String chunkStr = "1"; 415 416 if (rank <= 1) { 417 chunkStr = currentStr; 418 } 419 else { 420 for (int i = 1; i < rank - 1; i++) { 421 chunkStr += " x 1"; 422 } 423 if (idx > 0) { 424 chunkStr += " x " + currentStr.substring(idx + 1); 425 } 426 } 427 428 chunkSizeField.setText(chunkStr); 429 } 430 }); 431 432 for (int i = 1; i < 33; i++) { 433 rankChoice.add(String.valueOf(i)); 434 } 435 436 currentSizeField = new Text(dataspaceGroup, SWT.SINGLE | SWT.BORDER); 437 currentSizeField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 438 currentSizeField.setFont(curFont); 439 currentSizeField.setText("1"); 440 441 maxSizeField = new Text(dataspaceGroup, SWT.SINGLE | SWT.BORDER); 442 maxSizeField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 443 maxSizeField.setFont(curFont); 444 maxSizeField.setText("0"); 445 446 // Create Data Layout/Compression region 447 org.eclipse.swt.widgets.Group layoutGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 448 layoutGroup.setLayout(new GridLayout(7, false)); 449 layoutGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 450 layoutGroup.setFont(curFont); 451 layoutGroup.setText("Data Layout and Compression"); 452 453 label = new Label(layoutGroup, SWT.LEFT); 454 label.setFont(curFont); 455 label.setText("Storage layout: "); 456 457 checkContiguous = new Button(layoutGroup, SWT.RADIO); 458 checkContiguous.setFont(curFont); 459 checkContiguous.setText("Contiguous"); 460 checkContiguous.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 461 checkContiguous.addSelectionListener(new SelectionAdapter() { 462 @Override 463 public void widgetSelected(SelectionEvent e) 464 { 465 chunkSizeField.setEnabled(false); 466 } 467 }); 468 469 // Dummy labels 470 label = new Label(layoutGroup, SWT.LEFT); 471 label.setFont(curFont); 472 label.setText(""); 473 label = new Label(layoutGroup, SWT.LEFT); 474 label.setFont(curFont); 475 label.setText(""); 476 477 checkChunked = new Button(layoutGroup, SWT.RADIO); 478 checkChunked.setFont(curFont); 479 checkChunked.setText("Chunked"); 480 checkChunked.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 481 checkChunked.addSelectionListener(new SelectionAdapter() { 482 @Override 483 public void widgetSelected(SelectionEvent e) 484 { 485 chunkSizeField.setEnabled(true); 486 487 String currentStr = currentSizeField.getText(); 488 int idx = currentStr.lastIndexOf('x'); 489 String chunkStr = "1"; 490 491 int rank = rankChoice.getSelectionIndex() + 1; 492 if (rank <= 1) { 493 chunkStr = currentStr; 494 } 495 else { 496 for (int i = 1; i < rank - 1; i++) { 497 chunkStr += " x 1"; 498 } 499 if (idx > 0) { 500 chunkStr += " x " + currentStr.substring(idx + 1); 501 } 502 } 503 504 chunkSizeField.setText(chunkStr); 505 } 506 }); 507 508 label = new Label(layoutGroup, SWT.LEFT); 509 label.setFont(curFont); 510 label.setText("Size: "); 511 512 chunkSizeField = new Text(layoutGroup, SWT.SINGLE | SWT.BORDER); 513 chunkSizeField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 514 chunkSizeField.setFont(curFont); 515 chunkSizeField.setText("1"); 516 chunkSizeField.setEnabled(false); 517 518 label = new Label(layoutGroup, SWT.LEFT); 519 label.setFont(curFont); 520 label.setText("Compression: "); 521 522 checkCompression = new Button(layoutGroup, SWT.CHECK); 523 checkCompression.setFont(curFont); 524 checkCompression.setText("gzip"); 525 checkCompression.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 526 checkCompression.addSelectionListener(new SelectionAdapter() { 527 @Override 528 public void widgetSelected(SelectionEvent e) 529 { 530 boolean isCompressed = checkCompression.getSelection(); 531 532 if (isCompressed) { 533 if (!checkChunked.getSelection()) { 534 String currentStr = currentSizeField.getText(); 535 int idx = currentStr.lastIndexOf('x'); 536 String chunkStr = "1"; 537 538 int rank = rankChoice.getSelectionIndex() + 1; 539 if (rank <= 1) { 540 chunkStr = currentStr; 541 } 542 else { 543 for (int i = 1; i < rank - 1; i++) { 544 chunkStr += " x 1"; 545 } 546 if (idx > 0) { 547 chunkStr += " x " + currentStr.substring(idx + 1); 548 } 549 } 550 551 chunkSizeField.setText(chunkStr); 552 } 553 554 compressionLevel.setEnabled(true); 555 checkContiguous.setEnabled(false); 556 checkContiguous.setSelection(false); 557 checkChunked.setSelection(true); 558 chunkSizeField.setEnabled(true); 559 } 560 else { 561 compressionLevel.setEnabled(false); 562 checkContiguous.setEnabled(true); 563 } 564 } 565 }); 566 567 label = new Label(layoutGroup, SWT.LEFT); 568 label.setFont(curFont); 569 label.setText("Level: "); 570 571 compressionLevel = new Combo(layoutGroup, SWT.DROP_DOWN | SWT.READ_ONLY); 572 compressionLevel.setFont(curFont); 573 compressionLevel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 574 compressionLevel.setEnabled(false); 575 576 for (int i = 0; i < 10; i++) { 577 compressionLevel.add(String.valueOf(i)); 578 } 579 580 label = new Label(layoutGroup, SWT.LEFT); 581 label.setFont(curFont); 582 label.setText(""); 583 584 label = new Label(layoutGroup, SWT.LEFT); 585 label.setFont(curFont); 586 label.setText(""); 587 588 label = new Label(layoutGroup, SWT.LEFT); 589 label.setFont(curFont); 590 label.setText(""); 591 592 // Create Properties region 593 org.eclipse.swt.widgets.Group propertiesGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 594 propertiesGroup.setLayout(new GridLayout(2, false)); 595 propertiesGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 596 propertiesGroup.setFont(curFont); 597 propertiesGroup.setText("Compound Datatype Properties"); 598 599 label = new Label(propertiesGroup, SWT.LEFT); 600 label.setFont(curFont); 601 label.setText("Number of Members:"); 602 603 nFieldBox = new Combo(propertiesGroup, SWT.DROP_DOWN); 604 nFieldBox.setFont(curFont); 605 nFieldBox.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 606 nFieldBox.addSelectionListener(new SelectionAdapter() { 607 @Override 608 public void widgetSelected(SelectionEvent e) 609 { 610 updateMemberTableItems(); 611 } 612 }); 613 nFieldBox.addTraverseListener(new TraverseListener() { 614 @Override 615 public void keyTraversed(TraverseEvent e) 616 { 617 if (e.detail == SWT.TRAVERSE_RETURN) 618 updateMemberTableItems(); 619 } 620 }); 621 622 for (int i = 1; i <= 100; i++) { 623 nFieldBox.add(String.valueOf(i)); 624 } 625 626 table = new Table(propertiesGroup, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); 627 table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); 628 table.setLinesVisible(false); 629 table.setHeaderVisible(true); 630 table.setFont(curFont); 631 632 editors = new TableEditor[nFieldBox.getItemCount()][3]; 633 634 String[] colNames = {"Name", "Datatype", "Array size / String length / Enum names"}; 635 636 TableColumn column = new TableColumn(table, SWT.NONE); 637 column.setText(colNames[0]); 638 639 column = new TableColumn(table, SWT.NONE); 640 column.setText(colNames[1]); 641 642 column = new TableColumn(table, SWT.NONE); 643 column.setText(colNames[2]); 644 645 for (int i = 0; i < 2; i++) { 646 TableEditor[] editor = addMemberTableItem(table); 647 editors[i][0] = editor[0]; 648 editors[i][1] = editor[1]; 649 editors[i][2] = editor[2]; 650 } 651 652 for (int i = 0; i < table.getColumnCount(); i++) { 653 table.getColumn(i).pack(); 654 } 655 656 // Last table column always expands to fill remaining table size 657 table.addListener(SWT.Resize, new Listener() { 658 @Override 659 public void handleEvent(Event e) 660 { 661 Table table = (Table)e.widget; 662 Rectangle area = table.getClientArea(); 663 int columnCount = table.getColumnCount(); 664 int totalGridLineWidth = (columnCount - 1) * table.getGridLineWidth(); 665 666 int totalColumnWidth = 0; 667 for (TableColumn column : table.getColumns()) { 668 totalColumnWidth += column.getWidth(); 669 } 670 671 int diff = area.width - (totalColumnWidth + totalGridLineWidth); 672 673 TableColumn col = table.getColumns()[columnCount - 1]; 674 col.setWidth(diff + col.getWidth()); 675 } 676 }); 677 678 // Disable table selection highlighting 679 table.addListener(SWT.EraseItem, new Listener() { 680 @Override 681 public void handleEvent(Event e) 682 { 683 if ((e.detail & SWT.SELECTED) != 0) { 684 e.detail &= ~SWT.SELECTED; 685 } 686 } 687 }); 688 689 // Create Ok/Cancel button region 690 Composite buttonComposite = new Composite(shell, SWT.NONE); 691 buttonComposite.setLayout(new GridLayout(2, true)); 692 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 693 694 Button okButton = new Button(buttonComposite, SWT.PUSH); 695 okButton.setFont(curFont); 696 okButton.setText(" &OK "); 697 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 698 okButton.addSelectionListener(new SelectionAdapter() { 699 @Override 700 public void widgetSelected(SelectionEvent e) 701 { 702 try { 703 newObject = createCompoundDS(); 704 } 705 catch (Exception ex) { 706 Tools.showError(shell, "Create", ex.getMessage()); 707 } 708 709 if (newObject != null) { 710 shell.dispose(); 711 } 712 } 713 }); 714 715 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 716 cancelButton.setFont(curFont); 717 cancelButton.setText(" &Cancel "); 718 cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 719 cancelButton.addSelectionListener(new SelectionAdapter() { 720 @Override 721 public void widgetSelected(SelectionEvent e) 722 { 723 newObject = null; 724 shell.dispose(); 725 (groupList).setSize(0); 726 } 727 }); 728 729 templateChoice.deselectAll(); 730 rankChoice.select(0); 731 checkContiguous.setSelection(true); 732 compressionLevel.select(6); 733 nFieldBox.select(nFieldBox.indexOf(String.valueOf(numberOfMembers))); 734 735 shell.pack(); 736 737 table.getColumn(0).setWidth(table.getClientArea().width / 3); 738 table.getColumn(1).setWidth(table.getClientArea().width / 3); 739 740 shell.addDisposeListener(new DisposeListener() { 741 @Override 742 public void widgetDisposed(DisposeEvent e) 743 { 744 if (curFont != null) 745 curFont.dispose(); 746 } 747 }); 748 749 shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 750 751 Rectangle parentBounds = parent.getBounds(); 752 Point shellSize = shell.getSize(); 753 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 754 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 755 756 shell.open(); 757 758 Display display = shell.getDisplay(); 759 while (!shell.isDisposed()) 760 if (!display.readAndDispatch()) 761 display.sleep(); 762 } 763 764 private HObject createCompoundDS() throws Exception 765 { 766 HObject obj = null; 767 long dims[], maxdims[], chunks[]; 768 int rank; 769 770 maxdims = chunks = null; 771 String dname = nameField.getText(); 772 if ((dname == null) || (dname.length() <= 0)) { 773 throw new IllegalArgumentException("Dataset name is empty"); 774 } 775 776 Group pgroup = groupList.get(parentChoice.getSelectionIndex()); 777 if (pgroup == null) { 778 throw new IllegalArgumentException("Invalid parent group"); 779 } 780 781 int n = table.getItemCount(); 782 if (n <= 0) { 783 return null; 784 } 785 786 String[] mNames = new String[n]; 787 Datatype[] mDatatypes = new Datatype[n]; 788 int[] mOrders = new int[n]; 789 790 for (int i = 0; i < n; i++) { 791 String name = (String)table.getItem(i).getData("MemberName"); 792 if ((name == null) || (name.length() <= 0)) { 793 throw new IllegalArgumentException("Member name is empty"); 794 } 795 mNames[i] = name; 796 log.trace("createCompoundDS member[{}] name = {}", i, mNames[i]); 797 798 int order = 1; 799 String orderStr = (String)table.getItem(i).getData("MemberSize"); 800 if (orderStr != null) { 801 try { 802 order = Integer.parseInt(orderStr); 803 } 804 catch (Exception ex) { 805 log.debug("compound order:", ex); 806 } 807 } 808 mOrders[i] = order; 809 810 String typeName = (String)table.getItem(i).getData("MemberType"); 811 log.trace("createCompoundDS type[{}] name = {}", i, typeName); 812 Datatype type = null; 813 try { 814 if (DATATYPE_NAMES[0].equals(typeName)) { 815 type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 1, Datatype.NATIVE, 816 Datatype.NATIVE); 817 } 818 else if (DATATYPE_NAMES[1].equals(typeName)) { 819 type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 2, Datatype.NATIVE, 820 Datatype.NATIVE); 821 } 822 else if (DATATYPE_NAMES[2].equals(typeName)) { 823 type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, 824 Datatype.NATIVE); 825 } 826 else if (DATATYPE_NAMES[3].equals(typeName)) { 827 type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 1, Datatype.NATIVE, 828 Datatype.SIGN_NONE); 829 } 830 else if (DATATYPE_NAMES[4].equals(typeName)) { 831 type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 2, Datatype.NATIVE, 832 Datatype.SIGN_NONE); 833 } 834 else if (DATATYPE_NAMES[5].equals(typeName)) { 835 type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, 836 Datatype.SIGN_NONE); 837 } 838 else if (DATATYPE_NAMES[6].equals(typeName)) { 839 type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 8, Datatype.NATIVE, 840 Datatype.NATIVE); 841 } 842 else if (DATATYPE_NAMES[7].equals(typeName)) { 843 type = 844 fileFormat.createDatatype(Datatype.CLASS_FLOAT, 4, Datatype.NATIVE, Datatype.NATIVE); 845 } 846 else if (DATATYPE_NAMES[8].equals(typeName)) { 847 type = 848 fileFormat.createDatatype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE); 849 } 850 else if (DATATYPE_NAMES[9].equals(typeName)) { 851 type = fileFormat.createDatatype(Datatype.CLASS_STRING, order, Datatype.NATIVE, 852 Datatype.NATIVE); 853 } 854 else if (DATATYPE_NAMES[10].equals(typeName)) { // enum 855 type = 856 fileFormat.createDatatype(Datatype.CLASS_ENUM, 4, Datatype.NATIVE, Datatype.NATIVE); 857 if ((orderStr == null) || (orderStr.length() < 1) || orderStr.endsWith("...")) { 858 shell.getDisplay().beep(); 859 Tools.showError(shell, "Create", "Invalid member values: " + orderStr); 860 return null; 861 } 862 else { 863 type.setEnumMembers(orderStr); 864 } 865 } 866 else if (DATATYPE_NAMES[11].equals(typeName)) { 867 type = fileFormat.createDatatype(Datatype.CLASS_INTEGER, 8, Datatype.NATIVE, 868 Datatype.SIGN_NONE); 869 } 870 else if (DATATYPE_NAMES[12].equals(typeName)) { 871 type = 872 fileFormat.createDatatype(Datatype.CLASS_FLOAT, 2, Datatype.NATIVE, Datatype.NATIVE); 873 } 874 else if (DATATYPE_NAMES[13].equals(typeName)) { 875 type = 876 fileFormat.createDatatype(Datatype.CLASS_FLOAT, 16, Datatype.NATIVE, Datatype.NATIVE); 877 } 878 else { 879 throw new IllegalArgumentException("Invalid data type."); 880 } 881 mDatatypes[i] = type; 882 } 883 catch (Exception ex) { 884 Tools.showError(shell, "Create", ex.getMessage()); 885 log.debug("createAttribute(): ", ex); 886 return null; 887 } 888 } // (int i=0; i<n; i++) 889 890 rank = rankChoice.getSelectionIndex() + 1; 891 log.trace("createCompoundDS rank={}", rank); 892 StringTokenizer st = new StringTokenizer(currentSizeField.getText(), "x"); 893 if (st.countTokens() < rank) { 894 shell.getDisplay().beep(); 895 Tools.showError(shell, "Create", 896 "Number of values in the current dimension size is less than " + rank); 897 return null; 898 } 899 900 long l = 0; 901 dims = new long[rank]; 902 String token = null; 903 for (int i = 0; i < rank; i++) { 904 token = st.nextToken().trim(); 905 try { 906 l = Long.parseLong(token); 907 } 908 catch (NumberFormatException ex) { 909 shell.getDisplay().beep(); 910 Tools.showError(shell, "Create", "Invalid dimension size: " + currentSizeField.getText()); 911 return null; 912 } 913 914 if (l <= 0) { 915 shell.getDisplay().beep(); 916 Tools.showError(shell, "Create", "Dimension size must be greater than zero."); 917 return null; 918 } 919 920 dims[i] = l; 921 } 922 923 st = new StringTokenizer(maxSizeField.getText(), "x"); 924 if (st.countTokens() < rank) { 925 shell.getDisplay().beep(); 926 Tools.showError(shell, "Create", 927 "Number of values in the max dimension size is less than " + rank); 928 return null; 929 } 930 931 l = 0; 932 maxdims = new long[rank]; 933 for (int i = 0; i < rank; i++) { 934 token = st.nextToken().trim(); 935 try { 936 l = Long.parseLong(token); 937 } 938 catch (NumberFormatException ex) { 939 shell.getDisplay().beep(); 940 Tools.showError(shell, "Create", "Invalid max dimension size: " + maxSizeField.getText()); 941 return null; 942 } 943 944 if (l < -1) { 945 shell.getDisplay().beep(); 946 Tools.showError(shell, "Create", "Dimension size cannot be less than -1."); 947 return null; 948 } 949 else if (l == 0) { 950 l = dims[i]; 951 } 952 953 maxdims[i] = l; 954 } 955 956 chunks = null; 957 if (checkChunked.getSelection()) { 958 st = new StringTokenizer(chunkSizeField.getText(), "x"); 959 if (st.countTokens() < rank) { 960 shell.getDisplay().beep(); 961 Tools.showError(shell, "Create", "Number of values in the chunk size is less than " + rank); 962 return null; 963 } 964 965 l = 0; 966 chunks = new long[rank]; 967 token = null; 968 for (int i = 0; i < rank; i++) { 969 token = st.nextToken().trim(); 970 try { 971 l = Long.parseLong(token); 972 } 973 catch (NumberFormatException ex) { 974 shell.getDisplay().beep(); 975 Tools.showError(shell, "Create", 976 "Invalid chunk dimension size: " + chunkSizeField.getText()); 977 return null; 978 } 979 980 if (l < 1) { 981 shell.getDisplay().beep(); 982 Tools.showError(shell, "Create", "Chunk size cannot be less than 1."); 983 return null; 984 } 985 986 chunks[i] = l; 987 } // (int i=0; i<rank; i++) 988 989 long tchunksize = 1, tdimsize = 1; 990 for (int i = 0; i < rank; i++) { 991 tchunksize *= chunks[i]; 992 tdimsize *= dims[i]; 993 } 994 995 if (tchunksize >= tdimsize) { 996 shell.getDisplay().beep(); 997 if (!Tools.showConfirm(shell, "Create", 998 "Chunk size is equal/greater than the current size. " 999 + "\nAre you sure you want to set chunk size to " + 1000 chunkSizeField.getText() + "?")) { 1001 return null; 1002 } 1003 } 1004 1005 if (tchunksize == 1) { 1006 shell.getDisplay().beep(); 1007 if (!Tools.showConfirm( 1008 shell, "Create", 1009 "Chunk size is one, which may cause large memory overhead for large dataset." 1010 + "\nAre you sure you want to set chunk size to " + chunkSizeField.getText() + 1011 "?")) { 1012 return null; 1013 } 1014 } 1015 1016 } // (checkChunked.getSelection()) 1017 1018 int gzip = 0; 1019 if (checkCompression.getSelection()) { 1020 gzip = compressionLevel.getSelectionIndex(); 1021 } 1022 1023 if (checkChunked.getSelection()) { 1024 obj = fileFormat.createCompoundDS(dname, pgroup, dims, maxdims, chunks, gzip, mNames, mDatatypes, 1025 mOrders, null); 1026 } 1027 else { 1028 obj = fileFormat.createCompoundDS(dname, pgroup, dims, maxdims, null, -1, mNames, mDatatypes, 1029 mOrders, null); 1030 } 1031 return obj; 1032 } 1033 1034 private void updateMemberTableItems() 1035 { 1036 int n = 0; 1037 1038 try { 1039 n = Integer.valueOf(nFieldBox.getItem(nFieldBox.getSelectionIndex())).intValue(); 1040 } 1041 catch (Exception ex) { 1042 log.debug("Change number of members:", ex); 1043 return; 1044 } 1045 1046 if (n == numberOfMembers) { 1047 return; 1048 } 1049 1050 if (n > numberOfMembers) { 1051 try { 1052 for (int i = numberOfMembers; i < n; i++) { 1053 TableEditor[] editor = addMemberTableItem(table); 1054 editors[i][0] = editor[0]; 1055 editors[i][1] = editor[1]; 1056 editors[i][2] = editor[2]; 1057 } 1058 } 1059 catch (Exception ex) { 1060 log.debug("Error adding member table items: ", ex); 1061 return; 1062 } 1063 } 1064 else { 1065 try { 1066 for (int i = numberOfMembers - 1; i >= n; i--) { 1067 table.remove(i); 1068 } 1069 } 1070 catch (Exception ex) { 1071 log.debug("Error removing member table items: ", ex); 1072 return; 1073 } 1074 } 1075 1076 table.setItemCount(n); 1077 numberOfMembers = n; 1078 } 1079 1080 private TableEditor[] addMemberTableItem(Table table) 1081 { 1082 final TableItem item = new TableItem(table, SWT.NONE); 1083 final TableEditor[] editor = new TableEditor[3]; 1084 1085 for (int i = 0; i < editor.length; i++) 1086 editor[i] = new TableEditor(table); 1087 1088 final Text nameText = new Text(table, SWT.SINGLE | SWT.BORDER); 1089 nameText.setFont(curFont); 1090 1091 editor[0].grabHorizontal = true; 1092 editor[0].grabVertical = true; 1093 editor[0].horizontalAlignment = SWT.LEFT; 1094 editor[0].verticalAlignment = SWT.TOP; 1095 editor[0].setEditor(nameText, item, 0); 1096 1097 nameText.addModifyListener(new ModifyListener() { 1098 @Override 1099 public void modifyText(ModifyEvent e) 1100 { 1101 Text text = (Text)e.widget; 1102 item.setData("MemberName", text.getText()); 1103 } 1104 }); 1105 1106 final CCombo typeCombo = new CCombo(table, SWT.DROP_DOWN | SWT.READ_ONLY); 1107 typeCombo.setFont(curFont); 1108 typeCombo.setItems(DATATYPE_NAMES); 1109 1110 editor[1].grabHorizontal = true; 1111 editor[1].grabVertical = true; 1112 editor[1].horizontalAlignment = SWT.LEFT; 1113 editor[1].verticalAlignment = SWT.TOP; 1114 editor[1].setEditor(typeCombo, item, 1); 1115 1116 typeCombo.addSelectionListener(new SelectionAdapter() { 1117 @Override 1118 public void widgetSelected(SelectionEvent e) 1119 { 1120 CCombo combo = (CCombo)e.widget; 1121 item.setData("MemberType", combo.getItem(combo.getSelectionIndex())); 1122 } 1123 }); 1124 1125 final Text sizeText = new Text(table, SWT.SINGLE | SWT.BORDER); 1126 sizeText.setFont(curFont); 1127 1128 editor[2].grabHorizontal = true; 1129 editor[2].grabVertical = true; 1130 editor[2].horizontalAlignment = SWT.LEFT; 1131 editor[2].verticalAlignment = SWT.TOP; 1132 editor[2].setEditor(sizeText, item, 2); 1133 1134 sizeText.addModifyListener(new ModifyListener() { 1135 @Override 1136 public void modifyText(ModifyEvent e) 1137 { 1138 Text text = (Text)e.widget; 1139 item.setData("MemberSize", text.getText()); 1140 } 1141 }); 1142 1143 item.setData("MemberName", ""); 1144 item.setData("MemberType", ""); 1145 item.setData("MemberSize", ""); 1146 1147 item.addDisposeListener(new DisposeListener() { 1148 @Override 1149 public void widgetDisposed(DisposeEvent e) 1150 { 1151 editor[0].dispose(); 1152 editor[1].dispose(); 1153 editor[2].dispose(); 1154 nameText.dispose(); 1155 typeCombo.dispose(); 1156 sizeText.dispose(); 1157 } 1158 }); 1159 1160 return editor; 1161 } 1162}