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