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