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