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