1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright 1998-2002 by Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 package com.sun.dhcpmgr.client; 29 30 import javax.swing.*; 31 import javax.swing.border.*; 32 import javax.swing.event.*; 33 import javax.swing.table.*; 34 35 import java.awt.*; 36 import java.awt.event.*; 37 import java.text.MessageFormat; 38 import java.util.*; 39 40 import com.sun.dhcpmgr.server.*; 41 import com.sun.dhcpmgr.data.*; 42 import com.sun.dhcpmgr.ui.*; 43 import com.sun.dhcpmgr.bridge.NotRunningException; 44 45 46 /** 47 * Dialog to create/duplicate/edit an option. 48 */ 49 public class CreateOptionDialog extends JDialog implements ButtonPanelListener { 50 public static final int CREATE = 0; 51 public static final int EDIT = 1; 52 public static final int DUPLICATE = 2; 53 54 private int mode = CREATE; 55 private OptionNameField name; 56 private JComboBox category; 57 private IntegerField code; 58 private JComboBox type; 59 private JList classList; 60 private JTextField clientClass; 61 private IntegerField granularity; 62 private IntegerField maximum; 63 private JCheckBox signalBox; 64 private Vector listeners; 65 private Option option, originalOption; 66 private ButtonPanel buttonPanel; 67 private ClassListModel classListModel; 68 private JButton add, delete; 69 private UpButton moveUp; 70 private DownButton moveDown; 71 private OptionContext [] categories = { 72 Option.ctxts[Option.EXTEND], 73 Option.ctxts[Option.VENDOR], 74 Option.ctxts[Option.SITE] 75 }; 76 77 // Model for the list of vendor classes 78 class ClassListModel extends AbstractListModel { 79 80 public ClassListModel() { 81 super(); 82 } 83 84 public int getSize() { 85 return option.getVendorCount(); 86 } 87 88 public Object getElementAt(int index) { 89 return option.getVendorAt(index); 90 } 91 92 public void addElement(String v) throws ValidationException { 93 option.addVendor(v); 94 fireIntervalAdded(this, option.getVendorCount()-1, 95 option.getVendorCount()-1); 96 } 97 98 public void removeElementAt(int index) { 99 option.removeVendorAt(index); 100 fireIntervalRemoved(this, index, index); 101 } 102 103 public void moveUp(int index) { 104 String t = (String)option.getVendorAt(index-1); 105 option.setVendorAt(option.getVendorAt(index), index-1); 106 option.setVendorAt(t, index); 107 fireContentsChanged(this, index-1, index); 108 } 109 110 public void moveDown(int index) { 111 String t = (String)option.getVendorAt(index+1); 112 option.setVendorAt(option.getVendorAt(index), index+1); 113 option.setVendorAt(t, index); 114 fireContentsChanged(this, index, index+1); 115 } 116 117 public void reset() { 118 fireContentsChanged(this, 0, getSize()); 119 } 120 } 121 122 public CreateOptionDialog(Frame f, int mode) { 123 super(f); 124 setLocationRelativeTo(f); 125 JPanel classPanel; 126 127 listeners = new Vector(); 128 129 this.mode = mode; 130 switch (mode) { 131 case CREATE: 132 setTitle(ResourceStrings.getString("create_option_title")); 133 break; 134 case EDIT: 135 setTitle(ResourceStrings.getString("edit_option_title")); 136 break; 137 case DUPLICATE: 138 setTitle(ResourceStrings.getString("duplicate_option_title")); 139 break; 140 default: 141 break; 142 } 143 144 getContentPane().setLayout(new BoxLayout(getContentPane(), 145 BoxLayout.Y_AXIS)); 146 147 JPanel mainPanel = new JPanel(new BorderLayout()); 148 mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 149 150 JPanel fieldPanel = new JPanel(); 151 GridBagLayout bag = new GridBagLayout(); 152 fieldPanel.setLayout(bag); 153 154 // Initialize constraints 155 GridBagConstraints c = new GridBagConstraints(); 156 c.gridx = c.gridy = 0; 157 c.gridwidth = c.gridheight = 1; 158 c.fill = GridBagConstraints.HORIZONTAL; 159 c.insets = new Insets(5, 5, 5, 5); 160 c.weightx = c.weighty = 1.0; 161 162 // Label and text field for name 163 Mnemonic mnOname = 164 new Mnemonic(ResourceStrings.getString("op_name")); 165 JLabel l = new JLabel(mnOname.getString(), SwingConstants.RIGHT); 166 167 bag.setConstraints(l, c); 168 fieldPanel.add(l); 169 name = new OptionNameField(""); 170 171 l.setLabelFor(name); 172 l.setToolTipText(mnOname.getString()); 173 l.setDisplayedMnemonic(mnOname.getMnemonic()); 174 175 l.setLabelFor(name); 176 ++c.gridx; 177 bag.setConstraints(name, c); 178 fieldPanel.add(name); 179 180 // Label and combo box for category 181 Mnemonic mnCat = 182 new Mnemonic(ResourceStrings.getString("category_label")); 183 l = new JLabel(mnCat.getString(), SwingConstants.RIGHT); 184 185 c.gridx = 0; 186 ++c.gridy; 187 bag.setConstraints(l, c); 188 fieldPanel.add(l); 189 category = new JComboBox(categories); 190 191 l.setLabelFor(category); 192 l.setToolTipText(mnCat.getString()); 193 l.setDisplayedMnemonic(mnCat.getMnemonic()); 194 195 category.setEditable(false); 196 ++c.gridx; 197 bag.setConstraints(category, c); 198 fieldPanel.add(category); 199 200 // Label and text field for code 201 Mnemonic mnCode = 202 new Mnemonic(ResourceStrings.getString("option_code_label")); 203 l = new JLabel(mnCode.getString(), SwingConstants.RIGHT); 204 205 c.gridx = 0; 206 ++c.gridy; 207 bag.setConstraints(l, c); 208 fieldPanel.add(l); 209 code = new IntegerField(); 210 211 l.setLabelFor(code); 212 l.setToolTipText(mnCode.getString()); 213 l.setDisplayedMnemonic(mnCode.getMnemonic()); 214 215 ++c.gridx; 216 bag.setConstraints(code, c); 217 fieldPanel.add(code); 218 219 // Label and combo box for data type 220 Mnemonic mnType = 221 new Mnemonic(ResourceStrings.getString("data_type_label")); 222 l = new JLabel(mnType.getString(), SwingConstants.RIGHT); 223 224 c.gridx = 0; 225 ++c.gridy; 226 bag.setConstraints(l, c); 227 fieldPanel.add(l); 228 type = new JComboBox(Option.types); 229 230 l.setLabelFor(type); 231 l.setToolTipText(mnType.getString()); 232 l.setDisplayedMnemonic(mnType.getMnemonic()); 233 234 type.setEditable(false); 235 ++c.gridx; 236 bag.setConstraints(type, c); 237 fieldPanel.add(type); 238 239 // Label and text field for granularity 240 Mnemonic mnGran = 241 new Mnemonic(ResourceStrings.getString("granularity_label")); 242 l = new JLabel(mnGran.getString(), SwingConstants.RIGHT); 243 244 c.gridx = 0; 245 ++c.gridy; 246 bag.setConstraints(l, c); 247 fieldPanel.add(l); 248 granularity = new IntegerField(5); 249 250 l.setLabelFor(granularity); 251 l.setToolTipText(mnGran.getString()); 252 l.setDisplayedMnemonic(mnGran.getMnemonic()); 253 254 ++c.gridx; 255 bag.setConstraints(granularity, c); 256 fieldPanel.add(granularity); 257 258 // Label and text field for maximum 259 Mnemonic mnMax = 260 new Mnemonic(ResourceStrings.getString("maximum_label")); 261 l = new JLabel(mnMax.getString(), SwingConstants.RIGHT); 262 263 c.gridx = 0; 264 ++c.gridy; 265 bag.setConstraints(l, c); 266 fieldPanel.add(l); 267 maximum = new IntegerField(5); 268 269 l.setLabelFor(maximum); 270 l.setToolTipText(mnMax.getString()); 271 l.setDisplayedMnemonic(mnMax.getMnemonic()); 272 273 ++c.gridx; 274 bag.setConstraints(maximum, c); 275 fieldPanel.add(maximum); 276 277 mainPanel.add(fieldPanel, BorderLayout.WEST); 278 279 // Editing controls for client classes 280 bag = new GridBagLayout(); 281 classPanel = new JPanel(bag); 282 Border tb = BorderFactory.createTitledBorder( 283 BorderFactory.createLineBorder(Color.black), 284 ResourceStrings.getString("client_classes_label")); 285 classPanel.setBorder(BorderFactory.createCompoundBorder(tb, 286 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 287 288 c = new GridBagConstraints(); 289 c.gridx = c.gridy = 0; 290 c.weightx = c.weighty = 1.0; 291 c.gridheight = 1; 292 c.gridwidth = 1; 293 294 // Field to type in new classes 295 clientClass = new JTextField("", 20); 296 c.fill = GridBagConstraints.HORIZONTAL; 297 bag.setConstraints(clientClass, c); 298 classPanel.add(clientClass); 299 300 // Button for Add operation 301 Mnemonic mnAdd = 302 new Mnemonic(ResourceStrings.getString("add")); 303 add = new JButton(mnAdd.getString()); 304 add.setToolTipText(mnAdd.getString()); 305 add.setMnemonic(mnAdd.getMnemonic()); 306 307 c.fill = GridBagConstraints.NONE; 308 ++c.gridx; 309 c.weightx = 0.5; 310 bag.setConstraints(add, c); 311 classPanel.add(add); 312 313 // List for classes 314 classListModel = new ClassListModel(); 315 classList = new JList(classListModel); 316 317 // Make sure it's approximately wide enough for our purposes, 20 chars 318 classList.setPrototypeCellValue("abcdefghijklmnopqrst"); 319 classList.setSelectionMode( 320 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 321 JScrollPane scrollPane = new JScrollPane(classList); 322 c.fill = GridBagConstraints.BOTH; 323 c.gridx = 0; 324 ++c.gridy; 325 c.weightx = 1.0; 326 bag.setConstraints(scrollPane, c); 327 classPanel.add(scrollPane); 328 329 // Buttons to manipulate the list contents 330 JPanel editButtonPanel = new JPanel(new VerticalButtonLayout()); 331 moveUp = new UpButton(); 332 editButtonPanel.add(moveUp); 333 moveDown = new DownButton(); 334 editButtonPanel.add(moveDown); 335 336 Mnemonic mnDelete = 337 new Mnemonic(ResourceStrings.getString("delete")); 338 delete = new JButton(mnDelete.getString()); 339 delete.setToolTipText(mnDelete.getString()); 340 delete.setMnemonic(mnDelete.getMnemonic()); 341 342 editButtonPanel.add(delete); 343 ++c.gridx; 344 c.weightx = 0.5; 345 bag.setConstraints(editButtonPanel, c); 346 classPanel.add(editButtonPanel); 347 348 /* 349 * Disable all buttons to start; selection changes will adjust button 350 * state as necessary 351 */ 352 add.setEnabled(false); 353 delete.setEnabled(false); 354 moveUp.setEnabled(false); 355 moveDown.setEnabled(false); 356 357 // Create listener for button presses, take action as needed 358 ActionListener al = new ActionListener() { 359 public void actionPerformed(ActionEvent e) { 360 if (e.getSource() == add || e.getSource() == clientClass) { 361 try { 362 classListModel.addElement(clientClass.getText()); 363 } catch (ValidationException ex) { 364 // Something wrong with class name 365 MessageFormat form = new MessageFormat( 366 ResourceStrings.getString("invalid_client_class")); 367 Object [] args = new Object[] { clientClass.getText() }; 368 JOptionPane.showMessageDialog(CreateOptionDialog.this, 369 form.format(args), 370 ResourceStrings.getString("input_error"), 371 JOptionPane.ERROR_MESSAGE); 372 return; 373 } 374 } else if (e.getSource() == delete) { 375 int [] indices = classList.getSelectedIndices(); 376 if (indices.length > 1) { 377 /* 378 * Need to sort them so that the delete's don't 379 * interfere with each other 380 */ 381 for (int i = 0; i < indices.length; ++i) { 382 for (int j = i; j < indices.length; ++j) { 383 if (indices[i] > indices[j]) { 384 int k = indices[i]; 385 indices[i] = indices[j]; 386 indices[j] = k; 387 } 388 } 389 } 390 } 391 // Now delete from high index to low 392 for (int i = indices.length - 1; i >= 0; --i) { 393 classListModel.removeElementAt(indices[i]); 394 } 395 if (indices.length > 1) { 396 // Clear selection if multiple deleted 397 classList.clearSelection(); 398 /* 399 * XXX We don't get a selection event for some reason, 400 * make it work for now 401 */ 402 delete.setEnabled(false); 403 } else { 404 // Make sure to select something in the list 405 if (classListModel.getSize() == 0) { 406 // List is empty, so disable delete 407 delete.setEnabled(false); 408 } else if (indices[0] >= classListModel.getSize()) { 409 // Select last one if we're off the end 410 classList.setSelectedIndex( 411 classListModel.getSize()-1); 412 } else { 413 // Select next one in list 414 classList.setSelectedIndex(indices[0]); 415 } 416 } 417 } else if (e.getSource() == moveUp) { 418 int i = classList.getSelectedIndex(); 419 classListModel.moveUp(i); 420 // Keep item selected so repeated moveUp's affect same item 421 classList.setSelectedIndex(i-1); 422 } else if (e.getSource() == moveDown) { 423 int i = classList.getSelectedIndex(); 424 classListModel.moveDown(i); 425 // Keep item selected so repeated moveDowns affect same item 426 classList.setSelectedIndex(i+1); 427 } 428 } 429 }; 430 clientClass.addActionListener(al); 431 add.addActionListener(al); 432 delete.addActionListener(al); 433 moveUp.addActionListener(al); 434 moveDown.addActionListener(al); 435 436 // Put a selection listener on the list to enable buttons appropriately 437 classList.addListSelectionListener(new ListSelectionListener() { 438 public void valueChanged(ListSelectionEvent e) { 439 int [] indices = classList.getSelectedIndices(); 440 switch (indices.length) { 441 case 0: 442 // Nothing selected; disable them all 443 delete.setEnabled(false); 444 moveUp.setEnabled(false); 445 moveDown.setEnabled(false); 446 break; 447 case 1: 448 delete.setEnabled(true); 449 // Can't move first one up 450 moveUp.setEnabled(indices[0] != 0); 451 // Can't move last one down 452 if (indices[0] == (classListModel.getSize() - 1)) { 453 moveDown.setEnabled(false); 454 } else { 455 moveDown.setEnabled(true); 456 } 457 break; 458 default: 459 // More than one; only delete is allowed 460 delete.setEnabled(true); 461 moveUp.setEnabled(false); 462 moveDown.setEnabled(false); 463 } 464 } 465 }); 466 // Enable Add when class is not empty. 467 clientClass.getDocument().addDocumentListener(new DocumentListener() { 468 public void insertUpdate(DocumentEvent e) { 469 add.setEnabled(clientClass.getText().length() != 0); 470 } 471 public void changedUpdate(DocumentEvent e) { 472 insertUpdate(e); 473 } 474 public void removeUpdate(DocumentEvent e) { 475 insertUpdate(e); 476 } 477 }); 478 479 mainPanel.add(classPanel, BorderLayout.CENTER); 480 481 signalBox = new JCheckBox(ResourceStrings.getString("signal_server"), 482 true); 483 signalBox.setToolTipText( 484 ResourceStrings.getString("signal_server")); 485 signalBox.setHorizontalAlignment(SwingConstants.CENTER); 486 JPanel signalPanel = new JPanel(); 487 signalPanel.add(signalBox); 488 mainPanel.add(signalPanel, BorderLayout.SOUTH); 489 490 getContentPane().add(mainPanel); 491 getContentPane().add(new JSeparator()); 492 493 buttonPanel = new ButtonPanel(true); 494 buttonPanel.addButtonPanelListener(this); 495 getContentPane().add(buttonPanel); 496 497 setOption(new Option()); 498 499 if (mode == EDIT) { 500 buttonPanel.setOkEnabled(true); 501 } 502 503 // Enable OK when there is data in the name field 504 name.getDocument().addDocumentListener(new DocumentListener() { 505 public void insertUpdate(DocumentEvent e) { 506 buttonPanel.setOkEnabled(e.getDocument().getLength() != 0); 507 } 508 public void changedUpdate(DocumentEvent e) { 509 insertUpdate(e); 510 } 511 public void removeUpdate(DocumentEvent e) { 512 insertUpdate(e); 513 } 514 }); 515 516 // If category != VENDOR you can't mess with the client class data 517 category.addItemListener(new ItemListener() { 518 public void itemStateChanged(ItemEvent e) { 519 OptionContext ctxt = categories[category.getSelectedIndex()]; 520 boolean isVendor = 521 (ctxt.getCode() == Option.ctxts[Option.VENDOR].getCode()); 522 if (!isVendor) { 523 option.clearVendors(); 524 clientClass.setText(""); 525 } 526 clientClass.setEnabled(isVendor); 527 classList.setEnabled(isVendor); 528 } 529 }); 530 531 // Update state of granularity & maximum depending on data type selected 532 type.addItemListener(new ItemListener() { 533 public void itemStateChanged(ItemEvent e) { 534 OptionType stype = Option.types[type.getSelectedIndex()]; 535 byte code = stype.getCode(); 536 // Set granularity to correct minimum for type 537 if (code == Option.types[Option.BOOLEAN].getCode()) { 538 granularity.setText("0"); 539 } else if ("0".equals(granularity.getText())) { 540 granularity.setText("1"); 541 } 542 // Now set editability of the granularity and max fields 543 if (code == Option.types[Option.ASCII].getCode() || 544 code == Option.types[Option.OCTET].getCode()) { 545 granularity.setEditable(false); 546 maximum.setEditable(true); 547 } else if (code == Option.types[Option.BOOLEAN].getCode()) { 548 granularity.setEditable(false); 549 // Also reset maximum value in this case 550 maximum.setText("0"); 551 maximum.setEditable(false); 552 } else if (code == Option.types[Option.NUMBER].getCode() || 553 code == Option.types[Option.UNUMBER8].getCode() || 554 code == Option.types[Option.UNUMBER16].getCode() || 555 code == Option.types[Option.UNUMBER32].getCode() || 556 code == Option.types[Option.UNUMBER64].getCode() || 557 code == Option.types[Option.SNUMBER8].getCode() || 558 code == Option.types[Option.SNUMBER16].getCode() || 559 code == Option.types[Option.SNUMBER32].getCode() || 560 code == Option.types[Option.SNUMBER64].getCode() || 561 code == Option.types[Option.IP].getCode()) { 562 granularity.setEditable(true); 563 maximum.setEditable(true); 564 } 565 } 566 }); 567 } 568 569 public void setOption(Option o) { 570 originalOption = o; // Keep a copy so reset will work 571 option = (Option)o.clone(); 572 resetValues(); 573 } 574 575 private void resetValues() { 576 if (mode == DUPLICATE) { 577 name.setText(""); 578 } else { 579 name.setText(option.getKey()); 580 } 581 for (int i = 0; i < categories.length; i++) { 582 if (categories[i].getCode() == option.getContext()) { 583 category.setSelectedIndex(i); 584 break; 585 } 586 } 587 588 for (int i = 0; i < Option.types.length; i++) { 589 if (Option.types[i].getCode() == option.getType()) { 590 type.setSelectedIndex(i); 591 break; 592 } 593 } 594 595 code.setValue(option.getCode()); 596 granularity.setValue(option.getGranularity()); 597 maximum.setValue(option.getMaximum()); 598 classListModel.reset(); 599 signalBox.setSelected(true); 600 } 601 602 public void buttonPressed(int buttonId) { 603 switch (buttonId) { 604 case OK: 605 try { 606 OptionContext sctxt = categories[category.getSelectedIndex()]; 607 OptionType stype = Option.types[type.getSelectedIndex()]; 608 option.setKey(name.getText()); 609 option.setContext(sctxt.getCode()); 610 option.setCode((short)code.getValue()); 611 option.setType(stype.getCode()); 612 option.setGranularity(granularity.getValue()); 613 option.setMaximum(maximum.getValue()); 614 if (sctxt.getCode() == Option.ctxts[Option.VENDOR].getCode() && 615 option.getVendorCount() == 0) { 616 JOptionPane.showMessageDialog(this, 617 ResourceStrings.getString("empty_vendor_error"), 618 ResourceStrings.getString("server_error_title"), 619 JOptionPane.ERROR_MESSAGE); 620 return; 621 } 622 DhcptabMgr server = DataManager.get().getDhcptabMgr(); 623 if ((mode == CREATE) || (mode == DUPLICATE)) { 624 server.createRecord(option, signalBox.isSelected()); 625 } else if (mode == EDIT) { 626 server.modifyRecord(originalOption, option, 627 signalBox.isSelected()); 628 } 629 fireActionPerformed(); 630 setVisible(false); 631 dispose(); 632 } catch (NotRunningException e) { 633 // Server not running, put up a warning 634 JOptionPane.showMessageDialog(this, 635 ResourceStrings.getString("server_not_running"), 636 ResourceStrings.getString("warning"), 637 JOptionPane.WARNING_MESSAGE); 638 fireActionPerformed(); 639 setVisible(false); 640 dispose(); 641 } catch (Exception e) { 642 MessageFormat form = null; 643 Object [] args = new Object[2]; 644 switch (mode) { 645 case CREATE: 646 case DUPLICATE: 647 form = new MessageFormat( 648 ResourceStrings.getString("create_option_error")); 649 args[0] = option.getKey(); 650 break; 651 case EDIT: 652 form = new MessageFormat( 653 ResourceStrings.getString("edit_option_error")); 654 args[0] = originalOption.getKey(); 655 break; 656 } 657 args[1] = e.getMessage(); 658 JOptionPane.showMessageDialog(this, form.format(args), 659 ResourceStrings.getString("server_error_title"), 660 JOptionPane.ERROR_MESSAGE); 661 } 662 break; 663 case CANCEL: 664 setVisible(false); 665 dispose(); 666 break; 667 case HELP: 668 String helpTag = null; 669 switch (mode) { 670 case CREATE: 671 helpTag = "create_option"; 672 break; 673 case DUPLICATE: 674 helpTag = "duplicate_option"; 675 break; 676 case EDIT: 677 helpTag = "modify_option"; 678 break; 679 } 680 DhcpmgrApplet.showHelp(helpTag); 681 break; 682 case RESET: 683 setOption(originalOption); 684 break; 685 } 686 } 687 688 public void addActionListener(ActionListener l) { 689 listeners.addElement(l); 690 } 691 692 public void removeActionListener(ActionListener l) { 693 listeners.removeElement(l); 694 } 695 696 protected void fireActionPerformed() { 697 String command = null; 698 switch (mode) { 699 case CREATE: 700 command = DialogActions.CREATE; 701 case DUPLICATE: 702 command = DialogActions.DUPLICATE; 703 break; 704 case EDIT: 705 command = DialogActions.EDIT; 706 break; 707 } 708 ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 709 command); 710 Enumeration en = listeners.elements(); 711 while (en.hasMoreElements()) { 712 ActionListener l = (ActionListener)en.nextElement(); 713 l.actionPerformed(e); 714 } 715 } 716 }