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.ArrayList; 018import java.util.Iterator; 019import java.util.List; 020import org.eclipse.swt.SWT; 021import org.eclipse.swt.events.DisposeEvent; 022import org.eclipse.swt.events.DisposeListener; 023import org.eclipse.swt.events.SelectionAdapter; 024import org.eclipse.swt.events.SelectionEvent; 025import org.eclipse.swt.events.VerifyEvent; 026import org.eclipse.swt.events.VerifyListener; 027import org.eclipse.swt.graphics.Point; 028import org.eclipse.swt.graphics.Rectangle; 029import org.eclipse.swt.layout.GridData; 030import org.eclipse.swt.layout.GridLayout; 031import org.eclipse.swt.widgets.Button; 032import org.eclipse.swt.widgets.Combo; 033import org.eclipse.swt.widgets.Composite; 034import org.eclipse.swt.widgets.Display; 035import org.eclipse.swt.widgets.Label; 036import org.eclipse.swt.widgets.Shell; 037import org.eclipse.swt.widgets.Text; 038 039import hdf.object.Group; 040import hdf.object.HObject; 041import hdf.view.Tools; 042import hdf.view.ViewProperties; 043 044/** 045 * NewGroupDialog shows a message dialog requesting user input for creating a new HDF4/5 group. 046 * 047 * @author Jordan T. Henderson 048 * @version 2.4 12/30/2015 049 */ 050public class NewGroupDialog extends NewDataObjectDialog { 051 052 /* Used to restore original size after click "less" button */ 053 private Point originalSize; 054 055 private Text nameField; 056 private Text compactField; 057 private Text indexedField; 058 059 private Combo parentChoice; 060 private Combo orderFlags; 061 062 private Button useCreationOrder; 063 private Button setLinkStorage; 064 private Button creationOrderHelpButton; 065 private Button storageTypeHelpButton; 066 private Button okButton; 067 private Button cancelButton; 068 private Button moreButton; 069 070 private Composite moreOptionsComposite; 071 private Composite creationOrderComposite; 072 private Composite storageTypeComposite; 073 private Composite dummyComposite; 074 private Composite buttonComposite; 075 076 private List<Group> groupList; 077 078 private int creationOrder; 079 080 private boolean moreOptionsEnabled; 081 082 /** 083 * Constructs a NewGroupDialog with specified list of possible parent groups. 084 * 085 * @param parent 086 * the parent shell of the dialog 087 * @param pGroup 088 * the parent group which the new group is added to. 089 * @param objs 090 * the list of all objects. 091 */ 092 public NewGroupDialog(Shell parent, Group pGroup, List<?> objs) { 093 super(parent, pGroup, objs); 094 095 moreOptionsEnabled = false; 096 } 097 098 /** 099 * Open the NewGroupDialog for adding a new group. 100 */ 101 public void open() { 102 Shell parent = getParent(); 103 shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 104 shell.setFont(curFont); 105 shell.setText("New Group..."); 106 shell.setImage(ViewProperties.getHdfIcon()); 107 GridLayout layout = new GridLayout(1, false); 108 layout.verticalSpacing = 0; 109 shell.setLayout(layout); 110 111 Composite fieldComposite = new Composite(shell, SWT.NONE); 112 fieldComposite.setLayout(new GridLayout(2, false)); 113 fieldComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 114 115 Label groupNameLabel = new Label(fieldComposite, SWT.LEFT); 116 groupNameLabel.setFont(curFont); 117 groupNameLabel.setText("Group name:"); 118 119 nameField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER); 120 nameField.setFont(curFont); 121 GridData fieldData = new GridData(SWT.FILL, SWT.FILL, true, false); 122 fieldData.minimumWidth = 250; 123 nameField.setLayoutData(fieldData); 124 125 Label parentGroupLabel = new Label(fieldComposite, SWT.LEFT); 126 parentGroupLabel.setFont(curFont); 127 parentGroupLabel.setText("Parent group:"); 128 parentGroupLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); 129 130 parentChoice = new Combo(fieldComposite, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY); 131 parentChoice.setFont(curFont); 132 parentChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 133 parentChoice.addSelectionListener(new SelectionAdapter() { 134 @Override 135 public void widgetSelected(SelectionEvent e) { 136 parentObj = groupList.get(parentChoice.getSelectionIndex()); 137 } 138 }); 139 140 groupList = new ArrayList<>(); 141 Object obj = null; 142 Iterator<?> iterator = objList.iterator(); 143 while (iterator.hasNext()) { 144 obj = iterator.next(); 145 if (obj instanceof Group) { 146 Group g = (Group) obj; 147 groupList.add(g); 148 if (g.isRoot()) { 149 parentChoice.add(HObject.SEPARATOR); 150 } 151 else { 152 parentChoice.add(g.getPath() + g.getName() + HObject.SEPARATOR); 153 } 154 } 155 } 156 157 if (((Group) parentObj).isRoot()) { 158 parentChoice.select(parentChoice.indexOf(HObject.SEPARATOR)); 159 } 160 else { 161 parentChoice.select(parentChoice.indexOf(parentObj.getPath() + 162 parentObj.getName() + HObject.SEPARATOR)); 163 } 164 165 // Only add "More" button if file is H5 type 166 if(isH5) { 167 moreOptionsComposite = new Composite(shell, SWT.NONE); 168 moreOptionsComposite.setLayout(new GridLayout(2, false)); 169 moreOptionsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); 170 171 moreButton = new Button(moreOptionsComposite, SWT.PUSH); 172 moreButton.setFont(curFont); 173 moreButton.setText(" More "); 174 moreButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); 175 moreButton.addSelectionListener(new SelectionAdapter() { 176 @Override 177 public void widgetSelected(SelectionEvent e) { 178 moreOptionsEnabled = !moreOptionsEnabled; 179 180 if(moreOptionsEnabled) { 181 addMoreOptions(); 182 } 183 else { 184 removeMoreOptions(); 185 } 186 } 187 }); 188 189 dummyComposite = new Composite(moreOptionsComposite, SWT.NONE); 190 dummyComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 191 } 192 else { 193 // Add dummy label to take up space as dialog is resized 194 new Label(shell, SWT.NONE).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 195 } 196 197 buttonComposite = new Composite(shell, SWT.NONE); 198 buttonComposite.setLayout(new GridLayout(2, true)); 199 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 200 201 okButton = new Button(buttonComposite, SWT.PUSH); 202 okButton.setFont(curFont); 203 okButton.setText(" &OK "); 204 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 205 okButton.addSelectionListener(new SelectionAdapter() { 206 @Override 207 public void widgetSelected(SelectionEvent e) { 208 newObject = create(); 209 if (newObject != null) { 210 shell.dispose(); 211 } 212 } 213 }); 214 215 cancelButton = new Button(buttonComposite, SWT.PUSH); 216 cancelButton.setFont(curFont); 217 cancelButton.setText(" &Cancel "); 218 cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 219 cancelButton.addSelectionListener(new SelectionAdapter() { 220 @Override 221 public void widgetSelected(SelectionEvent e) { 222 newObject = null; 223 shell.dispose(); 224 } 225 }); 226 227 shell.pack(); 228 229 shell.addDisposeListener(new DisposeListener() { 230 @Override 231 public void widgetDisposed(DisposeEvent e) { 232 if (curFont != null) curFont.dispose(); 233 } 234 }); 235 236 shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 237 238 originalSize = shell.getSize(); 239 240 Rectangle parentBounds = parent.getBounds(); 241 Point shellSize = shell.getSize(); 242 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 243 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 244 245 shell.open(); 246 247 Display display = shell.getDisplay(); 248 while (!shell.isDisposed()) 249 if (!display.readAndDispatch()) 250 display.sleep(); 251 } 252 253 private HObject create() { 254 String name = null; 255 Group pgroup = null; 256 long gcpl = 0; 257 258 name = nameField.getText(); 259 if (name == null || name.length() == 0) { 260 shell.getDisplay().beep(); 261 Tools.showError(shell, "Create", "Group name is not specified."); 262 return null; 263 } 264 265 if (name.indexOf(HObject.SEPARATOR) >= 0) { 266 shell.getDisplay().beep(); 267 Tools.showError(shell, "Create", "Group name cannot contain path."); 268 return null; 269 } 270 271 pgroup = groupList.get(parentChoice.getSelectionIndex()); 272 273 if (pgroup == null) { 274 shell.getDisplay().beep(); 275 Tools.showError(shell, "Create", "Parent group is null."); 276 return null; 277 } 278 279 Group obj = null; 280 281 if (orderFlags != null && orderFlags.isEnabled()) { 282 String order = orderFlags.getItem(orderFlags.getSelectionIndex()); 283 if (order.equals("Tracked")) 284 creationOrder = Group.CRT_ORDER_TRACKED; 285 else if (order.equals("Tracked+Indexed")) 286 creationOrder = Group.CRT_ORDER_INDEXED; 287 } 288 else 289 creationOrder = 0; 290 291 if ((orderFlags != null) && ((orderFlags.isEnabled()) || (setLinkStorage.getSelection()))) { 292 int maxCompact = Integer.parseInt(compactField.getText()); 293 int minDense = Integer.parseInt(indexedField.getText()); 294 295 if ((maxCompact <= 0) || (maxCompact > 65536) || (minDense > 65536)) { 296 shell.getDisplay().beep(); 297 Tools.showError(shell, "Create", "Max Compact and Min Indexed should be > 0 and < 65536."); 298 return null; 299 } 300 301 if (maxCompact < minDense) { 302 shell.getDisplay().beep(); 303 Tools.showError(shell, "Create", "Min Indexed should be <= Max Compact"); 304 return null; 305 } 306 307 try { 308 gcpl = fileFormat.createGcpl(creationOrder, maxCompact, minDense); 309 } 310 catch (Exception ex) { 311 ex.printStackTrace(); 312 } 313 } 314 315 try { 316 if (isH5) 317 obj = fileFormat.createGroup(name, pgroup, 0, gcpl); 318 else 319 obj = fileFormat.createGroup(name, pgroup); 320 } 321 catch (Exception ex) { 322 shell.getDisplay().beep(); 323 Tools.showError(shell, "Create", ex.getMessage()); 324 return null; 325 } 326 327 return obj; 328 } 329 330 private void addMoreOptions() { 331 moreButton.setText(" Less "); 332 333 creationOrderComposite = new Composite(moreOptionsComposite, SWT.BORDER); 334 creationOrderComposite.setLayout(new GridLayout(4, true)); 335 creationOrderComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); 336 337 creationOrderHelpButton = new Button(creationOrderComposite, SWT.PUSH); 338 creationOrderHelpButton.setImage(ViewProperties.getHelpIcon()); 339 creationOrderHelpButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); 340 creationOrderHelpButton.setToolTipText("Help on Creation Order"); 341 creationOrderHelpButton.addSelectionListener(new SelectionAdapter() { 342 @Override 343 public void widgetSelected(SelectionEvent e) { 344 final String msg = "Use Creation Order allows the user to set the creation order \n" 345 + "of links in a group, so that tracking, indexing, and iterating over links\n" 346 + "in groups can be possible. \n\n" 347 + "If the order flag Tracked is selected, links in a group can now \n" 348 + "be explicitly tracked by the order that they were created. \n\n" 349 + "If the order flag Tracked+Indexed is selected, links in a group can \n" 350 + "now be explicitly tracked and indexed in the order that they were created. \n\n" 351 + "The default order in which links in a group are listed is alphanumeric-by-name. \n\n\n"; 352 353 Tools.showInformation(shell, "Create", msg); 354 } 355 }); 356 357 useCreationOrder = new Button(creationOrderComposite, SWT.CHECK); 358 useCreationOrder.setFont(curFont); 359 useCreationOrder.setText("Use Creation Order"); 360 useCreationOrder.addSelectionListener(new SelectionAdapter() { 361 @Override 362 public void widgetSelected(SelectionEvent e) { 363 boolean isOrder = useCreationOrder.getSelection(); 364 365 if (isOrder) 366 orderFlags.setEnabled(true); 367 else 368 orderFlags.setEnabled(false); 369 } 370 }); 371 372 Label label = new Label(creationOrderComposite, SWT.RIGHT); 373 label.setFont(curFont); 374 label.setText("Order Flags: "); 375 label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); 376 377 orderFlags = new Combo(creationOrderComposite, SWT.DROP_DOWN | SWT.READ_ONLY); 378 orderFlags.setFont(curFont); 379 orderFlags.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); 380 orderFlags.add("Tracked"); 381 orderFlags.add("Tracked+Indexed"); 382 orderFlags.select(orderFlags.indexOf("Tracked")); 383 orderFlags.setEnabled(false); 384 385 386 storageTypeComposite = new Composite(moreOptionsComposite, SWT.BORDER); 387 storageTypeComposite.setLayout(new GridLayout(3, true)); 388 storageTypeComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); 389 390 storageTypeHelpButton = new Button(storageTypeComposite, SWT.PUSH); 391 storageTypeHelpButton.setImage(ViewProperties.getHelpIcon()); 392 storageTypeHelpButton.setToolTipText("Help on set Link Storage"); 393 storageTypeHelpButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); 394 storageTypeHelpButton.addSelectionListener(new SelectionAdapter() { 395 @Override 396 public void widgetSelected(SelectionEvent e) { 397 final String msg = "Set Link Storage allows the users to explicitly set the storage \n" 398 + "type of a group to be Compact or Indexed. \n\n" 399 + "Compact Storage: For groups with only a few links, compact link storage\n" 400 + "allows groups containing only a few links to take up much less space \n" + "in the file. \n\n" 401 + "Indexed Storage: For groups with large number of links, indexed link storage \n" 402 + "provides a faster and more scalable method for storing and working with \n" 403 + "large groups containing many links. \n\n" 404 + "The threshold for switching between the compact and indexed storage \n" 405 + "formats is either set to default values or can be set by the user. \n\n" 406 + "<html><b>Max Compact</b></html> \n" 407 + "Max Compact is the maximum number of links to store in the group in a \n" 408 + "compact format, before converting the group to the Indexed format. Groups \n" 409 + "that are in compact format and in which the number of links rises above \n" 410 + " this threshold are automatically converted to indexed format. \n\n" 411 + "<html><b>Min Indexed</b></html> \n" 412 + "Min Indexed is the minimum number of links to store in the Indexed format. \n" 413 + "Groups which are in indexed format and in which the number of links falls \n" 414 + "below this threshold are automatically converted to compact format. \n\n\n"; 415 416 Tools.showInformation(shell, "Create", msg); 417 } 418 }); 419 420 setLinkStorage = new Button(storageTypeComposite, SWT.CHECK); 421 setLinkStorage.setFont(curFont); 422 setLinkStorage.setText("Set Link Storage"); 423 setLinkStorage.addSelectionListener(new SelectionAdapter() { 424 @Override 425 public void widgetSelected(SelectionEvent e) { 426 if (setLinkStorage.getSelection()) { 427 compactField.setEnabled(true); 428 indexedField.setEnabled(true); 429 } 430 else { 431 compactField.setText("8"); 432 compactField.setEnabled(false); 433 indexedField.setText("6"); 434 indexedField.setEnabled(false); 435 } 436 } 437 }); 438 439 Composite indexedComposite = new Composite(storageTypeComposite, SWT.NONE); 440 indexedComposite.setLayout(new GridLayout(2, true)); 441 indexedComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); 442 443 Label minLabel = new Label(indexedComposite, SWT.LEFT); 444 minLabel.setFont(curFont); 445 minLabel.setText("Min Indexed: "); 446 447 Label maxLabel = new Label(indexedComposite, SWT.LEFT); 448 maxLabel.setFont(curFont); 449 maxLabel.setText("Max Compact: "); 450 451 indexedField = new Text(indexedComposite, SWT.SINGLE | SWT.BORDER); 452 indexedField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); 453 indexedField.setFont(curFont); 454 indexedField.setText("6"); 455 indexedField.setTextLimit(5); 456 indexedField.setEnabled(false); 457 indexedField.addVerifyListener(new VerifyListener() { 458 @Override 459 public void verifyText(VerifyEvent e) { 460 String input = e.text; 461 462 char[] chars = new char[input.length()]; 463 input.getChars(0, chars.length, chars, 0); 464 for (int i = 0; i < chars.length; i++) { 465 if (!('0' <= chars[i] && chars[i] <= '9')) { 466 e.doit = false; 467 return; 468 } 469 } 470 } 471 }); 472 473 compactField = new Text(indexedComposite, SWT.SINGLE | SWT.BORDER); 474 compactField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); 475 compactField.setFont(curFont); 476 compactField.setText("8"); 477 compactField.setTextLimit(5); 478 compactField.setEnabled(false); 479 compactField.addVerifyListener(new VerifyListener() { 480 @Override 481 public void verifyText(VerifyEvent e) { 482 String input = e.text; 483 484 char[] chars = new char[input.length()]; 485 input.getChars(0, chars.length, chars, 0); 486 for (int i = 0; i < chars.length; i++) { 487 if (!('0' <= chars[i] && chars[i] <= '9')) { 488 e.doit = false; 489 return; 490 } 491 } 492 } 493 }); 494 495 shell.pack(); 496 497 shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 498 499 Rectangle parentBounds = shell.getParent().getBounds(); 500 Point shellSize = shell.getSize(); 501 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 502 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 503 } 504 505 private void removeMoreOptions() { 506 moreButton.setText(" More "); 507 508 creationOrderHelpButton.dispose(); 509 storageTypeHelpButton.dispose(); 510 511 creationOrderComposite.dispose(); 512 storageTypeComposite.dispose(); 513 514 shell.layout(true, true); 515 shell.pack(); 516 517 shell.setMinimumSize(originalSize); 518 shell.setSize(originalSize); 519 520 Rectangle parentBounds = shell.getParent().getBounds(); 521 Point shellSize = shell.getSize(); 522 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 523 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 524 } 525}