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 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 package com.sun.dhcpmgr.client; 27 28 import com.sun.dhcpmgr.ui.*; 29 import com.sun.dhcpmgr.data.*; 30 import com.sun.dhcpmgr.bridge.BridgeException; 31 import com.sun.dhcpmgr.bridge.NoEntryException; 32 import com.sun.dhcpmgr.bridge.ExistsException; 33 import com.sun.dhcpmgr.bridge.HostExistsException; 34 import com.sun.dhcpmgr.bridge.NoTableException; 35 import com.sun.dhcpmgr.server.DhcpNetMgr; 36 37 import javax.swing.*; 38 import javax.swing.table.*; 39 import javax.swing.event.*; 40 import javax.swing.border.*; 41 42 import java.awt.*; 43 import java.awt.event.*; 44 import java.util.*; 45 import java.text.MessageFormat; 46 import java.net.*; 47 48 /** 49 * A wizard to configure a group of addresses. 50 */ 51 public class AddressWizard extends Wizard { 52 private Network network; 53 private int number = 10; 54 private String comment = ""; 55 private String server = DataManager.get().getShortServerName(); 56 private IPAddress serverIP; 57 private IPAddress startAddress; 58 private String macro = DataManager.get().getShortServerName(); 59 private boolean unusable = false; 60 private boolean dynamic = true; 61 private WizardTableModel addressTableModel; 62 private Macro noMacro; 63 64 class Address { 65 IPAddress addr; 66 String name; 67 68 public Address() { 69 addr = null; 70 name = ""; 71 } 72 73 public Address(int a, String n) { 74 name = n; 75 setAddr(a); 76 } 77 78 public Address(String a, String n) { 79 name = n; 80 setAddr(a); 81 } 82 83 public void setAddr(int a) { 84 addr = new IPAddress(a); 85 } 86 87 public void setAddr(String a) { 88 try { 89 addr = new IPAddress(a); 90 } catch (ValidationException e) { 91 // Do nothing 92 } 93 } 94 95 public String toString() { 96 return addr.getHostAddress(); 97 } 98 } 99 100 class WizardTableModel extends AbstractTableModel { 101 private Vector addrs = new Vector(); 102 103 public int getRowCount() { 104 return addrs.size(); 105 } 106 107 public int getColumnCount() { 108 return 2; 109 } 110 111 public Object getValueAt(int row, int column) { 112 if (column == 0) { 113 return ((Address)addrs.elementAt(row)).addr; 114 } else { 115 return ((Address)addrs.elementAt(row)).name; 116 } 117 } 118 119 public Class getColumnClass(int column) { 120 if (column == 0) { 121 return IPAddress.class; 122 } else { 123 return String.class; 124 } 125 } 126 127 public String getColumnName(int column) { 128 if (column == 0) { 129 return ResourceStrings.getString("address_column"); 130 } else { 131 return ResourceStrings.getString("client_name_column"); 132 } 133 } 134 135 public long generateAddresses() { 136 if (!network.containsAddress(startAddress)) { 137 return 0; 138 } 139 140 int net = network.getAddress().intValue(); 141 int mask = network.getMask().intValue(); 142 int start = startAddress.intValue(); 143 144 addrs.removeAllElements(); 145 long max = (long)(net + ~mask) & 0xffffffffL; 146 int count = 0; 147 int index = start - net; 148 if (index == 0) { 149 // Don't try allocating the network address as a client address 150 ++index; 151 } 152 DhcpClientRecord [] clients = null; 153 try { 154 /* 155 * Sort the data so we can generate the list of addresses 156 * with a minimal number of comparisons here. First, though, 157 * clone the array so that sorting won't affect the original 158 * data set and throw off the main display. 159 */ 160 clients = (DhcpClientRecord [])DataManager.get().getClients( 161 network.getAddress().toString(), false).clone(); 162 Arrays.sort(clients); 163 } catch (Throwable e) { 164 // XXX What to do here??? 165 e.printStackTrace(); 166 } 167 int base = 0; 168 long searchAddress = 0; 169 while (count < number) { 170 long address = (long)(net + index) & 0xffffffffL; 171 if (address == max) { 172 // We finished searching before satisfying the request 173 break; 174 } 175 /* 176 * If clients == null then this is an empty network, 177 * so searching for holes is unnecessary 178 */ 179 if (clients != null) { 180 // Advance search pointer past lower-numbered addresses 181 while ((base < clients.length) 182 && ((searchAddress = 183 clients[base].getBinaryAddress()) < address)) { 184 ++base; 185 } 186 } 187 if (searchAddress != address) { 188 // found an empty slot; create the address 189 addrs.addElement(new Address((int)address, "")); 190 ++count; 191 } 192 ++index; 193 } 194 195 // Inform UI that the data is ready. 196 fireTableDataChanged(); 197 return count; 198 } 199 200 public Address getAddressAt(int index) { 201 return (Address)addrs.elementAt(index); 202 } 203 } 204 205 // This step selects the number of addresses and a comment 206 class NumberStep implements WizardStep { 207 private Box stepBox; 208 private IntegerField addressCount; 209 private JTextField commentField; 210 211 public NumberStep() { 212 stepBox = Box.createVerticalBox(); 213 214 // Explanatory text at the top 215 stepBox.add(Wizard.createTextArea( 216 ResourceStrings.getString("add_wiz_explain"), 4, 45)); 217 stepBox.add(Box.createVerticalStrut(10)); 218 stepBox.add(Box.createVerticalGlue()); 219 220 // Get the number of addresses to create 221 stepBox.add(Wizard.createTextArea( 222 ResourceStrings.getString("add_wiz_count_explain"), 1, 45)); 223 224 Mnemonic mnCount = 225 new Mnemonic(ResourceStrings.getString("add_wiz_count_label")); 226 JLabel label = new JLabel(mnCount.getString()); 227 addressCount = new IntegerField(); // Ensure numeric input 228 addressCount.setMaximumSize(addressCount.getPreferredSize()); 229 230 label.setLabelFor(addressCount); 231 label.setToolTipText(mnCount.getString()); 232 label.setDisplayedMnemonic(mnCount.getMnemonic()); 233 234 Box box = Box.createHorizontalBox(); 235 box.add(Box.createHorizontalStrut(10)); 236 box.add(label); 237 box.add(Box.createHorizontalStrut(5)); 238 box.add(addressCount); 239 box.add(Box.createHorizontalGlue()); 240 stepBox.add(box); 241 242 stepBox.add(Box.createVerticalStrut(10)); 243 stepBox.add(Box.createVerticalGlue()); 244 stepBox.add(Wizard.createTextArea( 245 ResourceStrings.getString("add_wiz_comment_explain"), 2, 45)); 246 247 // Let user supply a comment 248 Mnemonic mnComm = 249 new Mnemonic(ResourceStrings.getString( 250 "add_wiz_comment_label")); 251 label = new JLabel(mnComm.getString()); 252 commentField = new JTextField("", 20); 253 254 label.setLabelFor(commentField); 255 label.setToolTipText(mnComm.getString()); 256 label.setDisplayedMnemonic(mnComm.getMnemonic()); 257 258 commentField.setMaximumSize(commentField.getPreferredSize()); 259 box = Box.createHorizontalBox(); 260 box.add(Box.createHorizontalStrut(10)); 261 box.add(label); 262 box.add(Box.createHorizontalStrut(5)); 263 box.add(commentField); 264 stepBox.add(box); 265 stepBox.add(Box.createVerticalGlue()); 266 267 /* 268 * This listener ensures that the forward button is enabled only 269 * when there is a count of addresses in the addressCount field. 270 */ 271 addressCount.getDocument().addDocumentListener( 272 new DocumentListener() { 273 public void insertUpdate(DocumentEvent e) { 274 setForwardEnabled(e.getDocument().getLength() != 0); 275 } 276 public void changedUpdate(DocumentEvent e) { 277 insertUpdate(e); 278 } 279 public void removeUpdate(DocumentEvent e) { 280 insertUpdate(e); 281 } 282 }); 283 } 284 285 public String getDescription() { 286 return ResourceStrings.getString("add_wiz_number_desc"); 287 } 288 289 public Component getComponent() { 290 return stepBox; 291 } 292 293 public void setActive(int direction) { 294 addressCount.setValue(number); 295 commentField.setText(comment); 296 setForwardEnabled(addressCount.getValue() != 0); 297 } 298 299 public boolean setInactive(int direction) { 300 number = addressCount.getValue(); 301 if (number == 0) { 302 /* 303 * Going forward with 0 addresses makes no sense, 304 * display error and veto the move. 305 */ 306 JOptionPane.showMessageDialog(AddressWizard.this, 307 ResourceStrings.getString("add_wiz_count_error"), 308 ResourceStrings.getString("error_message"), 309 JOptionPane.ERROR_MESSAGE); 310 return false; 311 } 312 comment = commentField.getText(); 313 return true; 314 } 315 } 316 317 // This step selects the server and starting address 318 class ServerStep implements WizardStep { 319 private Box stepBox; 320 private IPAddressField startField; 321 private HostnameField serverField; 322 323 public ServerStep() { 324 stepBox = Box.createVerticalBox(); 325 326 // Explanatory text at the top 327 stepBox.add(Wizard.createTextArea( 328 ResourceStrings.getString("add_wiz_server_explain"), 1, 45)); 329 330 // Server to own these addresses 331 Mnemonic mnMan = 332 new Mnemonic(ResourceStrings.getString("add_wiz_server_label")); 333 JLabel jl = new JLabel(mnMan.getString()); 334 Box box = Box.createHorizontalBox(); 335 box.add(jl); 336 box.add(Box.createHorizontalStrut(5)); 337 serverField = new HostnameField("", 15); 338 jl.setLabelFor(serverField); 339 jl.setToolTipText(mnMan.getString()); 340 jl.setDisplayedMnemonic(mnMan.getMnemonic()); 341 342 serverField.setMaximumSize(serverField.getPreferredSize()); 343 box.add(serverField); 344 box.add(Box.createHorizontalGlue()); 345 stepBox.add(box); 346 347 // Add some spacing 348 stepBox.add(Box.createVerticalStrut(5)); 349 stepBox.add(Box.createVerticalGlue()); 350 351 // Starting address 352 stepBox.add(Wizard.createTextArea( 353 ResourceStrings.getString("add_wiz_start_explain"), 2, 45)); 354 box = Box.createHorizontalBox(); 355 356 Mnemonic mnStart = 357 new Mnemonic(ResourceStrings.getString("add_wiz_start_label")); 358 JLabel startLbl = new JLabel(mnStart.getString()); 359 box.add(startLbl); 360 box.add(Box.createHorizontalStrut(5)); 361 startField = new IPAddressField(); // Ensure it's an IP address 362 startLbl.setLabelFor(startField); 363 startLbl.setToolTipText(mnStart.getString()); 364 startLbl.setDisplayedMnemonic(mnStart.getMnemonic()); 365 366 startField.setMaximumSize(startField.getPreferredSize()); 367 box.add(startField); 368 stepBox.add(box); 369 370 DocumentListener docListener = new DocumentListener() { 371 public void insertUpdate(DocumentEvent e) { 372 setForwardEnabled((startField.getText().length() != 0) 373 && (serverField.getText().length() != 0)); 374 } 375 public void changedUpdate(DocumentEvent e) { 376 insertUpdate(e); 377 } 378 public void removeUpdate(DocumentEvent e) { 379 insertUpdate(e); 380 } 381 }; 382 383 startField.getDocument().addDocumentListener(docListener); 384 serverField.getDocument().addDocumentListener(docListener); 385 } 386 387 public String getDescription() { 388 return ResourceStrings.getString("add_wiz_server_desc"); 389 } 390 391 public Component getComponent() { 392 return stepBox; 393 } 394 395 public void setActive(int direction) { 396 serverField.setText(server); 397 startField.setValue(startAddress); 398 setForwardEnabled(true); 399 } 400 401 public boolean setInactive(int direction) { 402 if (direction == FORWARD) { 403 // Validate that address is on the network we're working on 404 IPAddress a = startField.getValue(); 405 if (a == null) { 406 // Not a valid address at all 407 MessageFormat form = new MessageFormat( 408 ResourceStrings.getString("add_wiz_invalid_address")); 409 Object [] args = new Object[1]; 410 args[0] = startField.getText(); 411 JOptionPane.showMessageDialog(AddressWizard.this, 412 form.format(args), 413 ResourceStrings.getString("input_error"), 414 JOptionPane.ERROR_MESSAGE); 415 return false; 416 } else if (!network.containsAddress(a)) { 417 // Address is not on network 418 MessageFormat form = new MessageFormat( 419 ResourceStrings.getString("bad_network_address")); 420 Object [] args = new Object[2]; 421 args[0] = startField.getText(); 422 args[1] = network.getAddress(); 423 JOptionPane.showMessageDialog(AddressWizard.this, 424 form.format(args), 425 ResourceStrings.getString("input_error"), 426 JOptionPane.ERROR_MESSAGE); 427 return false; 428 } 429 try { 430 serverIP = new IPAddress(serverField.getText()); 431 } catch (Throwable e) { 432 /* 433 * Unknown hostname, probably, so put up the message and 434 * decline to continue 435 */ 436 MessageFormat form = new MessageFormat( 437 ResourceStrings.getString("bad_server_name")); 438 Object [] args = new Object[1]; 439 args[0] = serverField.getText(); 440 JOptionPane.showMessageDialog(AddressWizard.this, 441 form.format(args), 442 ResourceStrings.getString("error_message"), 443 JOptionPane.ERROR_MESSAGE); 444 return false; 445 } 446 } 447 server = serverField.getText(); 448 startAddress = startField.getValue(); 449 return true; 450 } 451 } 452 453 // This step confirms the list of addresses to be generated 454 class ConfirmStep implements WizardStep { 455 private JPanel stepPanel; 456 private JTable addressTable; 457 458 public ConfirmStep() { 459 stepPanel = new JPanel(new BorderLayout(10, 10)); 460 461 // Explanatory text at the top 462 stepPanel.add(Wizard.createTextArea( 463 ResourceStrings.getString("add_wiz_confirm_explain"), 3, 45), 464 BorderLayout.NORTH); 465 466 // Label the table 467 JPanel panel = new JPanel(new BorderLayout()); 468 panel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15)); 469 Mnemonic mnIP = 470 new Mnemonic(ResourceStrings.getString( 471 "add_wiz_confirm_label")); 472 JLabel label = new JLabel(mnIP.getString()); 473 panel.add(label, BorderLayout.NORTH); 474 475 // Display the addresses in a table 476 addressTable = new JTable(addressTableModel); 477 478 label.setLabelFor(addressTable); 479 label.setToolTipText(mnIP.getString()); 480 label.setDisplayedMnemonic(mnIP.getMnemonic()); 481 482 addressTable.setDefaultRenderer(IPAddress.class, 483 new ExtendedCellRenderer()); 484 485 // Table is not selectable in any way 486 addressTable.setRowSelectionAllowed(false); 487 addressTable.setColumnSelectionAllowed(false); 488 addressTable.setCellSelectionEnabled(false); 489 490 // Wrap in a scroll pane so column headings display 491 JScrollPane scrollPane = new JScrollPane(addressTable); 492 panel.add(scrollPane, BorderLayout.CENTER); 493 stepPanel.add(panel, BorderLayout.CENTER); 494 } 495 496 public String getDescription() { 497 return ResourceStrings.getString("add_wiz_confirm_desc"); 498 } 499 500 public Component getComponent() { 501 return stepPanel; 502 } 503 504 public void setActive(int direction) { 505 /* 506 * If we're activating coming from the previous step, 507 * generate the address list 508 */ 509 if (direction == FORWARD) { 510 long count = addressTableModel.generateAddresses(); 511 // Error if no addresses could be generated 512 if (count == 0) { 513 JOptionPane.showMessageDialog(AddressWizard.this, 514 ResourceStrings.getString("add_wiz_none_available"), 515 ResourceStrings.getString("error_message"), 516 JOptionPane.ERROR_MESSAGE); 517 setForwardEnabled(false); 518 } else { 519 if (count != number) { 520 /* 521 * Warn if we couldn't generate the number of addresses 522 * requested 523 */ 524 MessageFormat form = new MessageFormat( 525 ResourceStrings.getString( 526 "generate_addresses_warning")); 527 Object [] args = new Object[2]; 528 args[0] = new Long(count); 529 args[1] = new Long(number); 530 JOptionPane.showMessageDialog(AddressWizard.this, 531 form.format(args), 532 ResourceStrings.getString("warning"), 533 JOptionPane.WARNING_MESSAGE); 534 } 535 setForwardEnabled(true); 536 } 537 } else { 538 setForwardEnabled(true); 539 } 540 } 541 542 public boolean setInactive(int direction) { 543 return true; // Nothing to do when leaving 544 } 545 } 546 547 // This step selects the macro and flags 548 class ConfigureStep implements WizardStep { 549 550 // Model class for the macro list 551 class MacroListModel extends AbstractListModel 552 implements ComboBoxModel { 553 private Object currentValue; 554 private Macro data[] = null; 555 556 public int getSize() { 557 if (data == null) { 558 try { 559 // If we don't have data yet, grab currently cached list 560 data = DataManager.get().getMacros(false); 561 } catch (NoTableException e) { 562 // can function without table 563 } catch (Throwable e) { 564 e.printStackTrace(); 565 } 566 } 567 568 if (data == null || data.length == 0) { 569 return 1; 570 } else { 571 return data.length+1; 572 } 573 } 574 575 public Object getElementAt(int index) { 576 if (data == null) { 577 try { 578 // If we don't have data yet, grab currently cached list 579 data = DataManager.get().getMacros(false); 580 } catch (NoTableException e) { 581 // can function without table 582 } catch (Throwable e) { 583 e.printStackTrace(); 584 } 585 } 586 if (index == 0) { 587 return noMacro.getKey(); 588 } else { 589 return data[index-1].getKey(); 590 } 591 } 592 593 public void setSelectedItem(Object anItem) { 594 currentValue = noMacro.getKey(); 595 for (int i = 0; data != null && i < data.length; i++) { 596 if (((String)(anItem)).equals(((Macro)data[i]).getKey())) { 597 currentValue = anItem; 598 } 599 } 600 fireContentsChanged(this, -1, -1); 601 } 602 603 public Object getSelectedItem() { 604 return currentValue; 605 } 606 607 public Macro getMacroAt(int index) { 608 if (index == 0) { 609 return noMacro; 610 } else { 611 return data[index-1]; 612 } 613 } 614 } 615 616 private Box stepBox; 617 private JComboBox macroBox; 618 private MacroListModel macroBoxModel; 619 private JButton viewButton; 620 private JCheckBox unusableBox; 621 622 public ConfigureStep() { 623 stepBox = Box.createVerticalBox(); 624 625 // Start with some explanatory text 626 JComponent component = Wizard.createTextArea( 627 ResourceStrings.getString("add_wiz_macro_explain"), 3, 45); 628 component.setAlignmentX(Component.LEFT_ALIGNMENT); 629 stepBox.add(component); 630 // Add some spacing 631 stepBox.add(Box.createVerticalStrut(10)); 632 633 // Let 'em select the macro to use 634 Mnemonic mnConf = 635 new Mnemonic(ResourceStrings.getString("add_wiz_macro_label")); 636 JLabel label = new JLabel(mnConf.getString()); 637 label.setAlignmentX(Component.LEFT_ALIGNMENT); 638 stepBox.add(label); 639 JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); 640 macroBoxModel = new MacroListModel(); 641 macroBox = new JComboBox(macroBoxModel); 642 643 label.setLabelFor(macroBox); 644 label.setToolTipText(mnConf.getString()); 645 label.setDisplayedMnemonic(mnConf.getMnemonic()); 646 647 panel.add(macroBox); 648 // Button to view the contents of the selected macro 649 650 Mnemonic mnView = 651 new Mnemonic(ResourceStrings.getString("add_wiz_view_button")); 652 viewButton = new JButton(mnView.getString()); 653 viewButton.setToolTipText(mnView.getString()); 654 viewButton.setMnemonic(mnView.getMnemonic()); 655 656 panel.add(viewButton); 657 panel.setAlignmentX(Component.LEFT_ALIGNMENT); 658 stepBox.add(panel); 659 660 // Give the option to mark them unusable for now 661 component = Wizard.createTextArea( 662 ResourceStrings.getString("add_wiz_flag_explain"), 2, 45); 663 component.setAlignmentX(Component.LEFT_ALIGNMENT); 664 stepBox.add(component); 665 unusableBox = new JCheckBox( 666 ResourceStrings.getString("add_wiz_unusable_label")); 667 unusableBox.setAlignmentX(Component.LEFT_ALIGNMENT); 668 stepBox.add(unusableBox); 669 stepBox.add(Box.createVerticalGlue()); 670 671 // When user presses View, show the macro's contents 672 viewButton.addActionListener(new ActionListener() { 673 public void actionPerformed(ActionEvent e) { 674 /* 675 * viewButton is passed as component relative to which the 676 * dialog should be displayed, keeping user more in 677 * context with the task. 678 */ 679 ViewMacroDialog d = new ViewMacroDialog( 680 AddressWizard.this, viewButton, 681 macroBoxModel.getMacroAt(macroBox.getSelectedIndex())); 682 d.pack(); 683 d.setVisible(true); 684 } 685 }); 686 } 687 688 public String getDescription() { 689 return ResourceStrings.getString("add_wiz_configure_desc"); 690 } 691 692 public Component getComponent() { 693 return stepBox; 694 } 695 696 public void setActive(int direction) { 697 macroBox.setSelectedItem(macro); 698 unusableBox.setSelected(unusable); 699 setForwardEnabled(true); 700 } 701 702 public boolean setInactive(int direction) { 703 macro = (String)macroBox.getSelectedItem(); 704 unusable = unusableBox.isSelected(); 705 return true; 706 } 707 } 708 709 // This step selects the lease type 710 class LeaseStep implements WizardStep { 711 private Box stepBox; 712 private JRadioButton dynamicButton, permanentButton; 713 private ButtonGroup buttonGroup; 714 715 public LeaseStep() { 716 stepBox = Box.createVerticalBox(); 717 718 // Start with explanatory text 719 JComponent component = Wizard.createTextArea( 720 ResourceStrings.getString("add_wiz_lease_explain"), 0, 45); 721 component.setAlignmentX(Component.LEFT_ALIGNMENT); 722 stepBox.add(component); 723 stepBox.add(Box.createVerticalStrut(10)); 724 725 // User has choice of dynamic or permanent leases 726 Mnemonic mnLease = 727 new Mnemonic(ResourceStrings.getString("add_wiz_lease_label")); 728 JLabel label = new JLabel(mnLease.getString()); 729 JPanel panel = new JPanel(new FieldLayout(10, 0)); 730 label.setToolTipText(mnLease.getString()); 731 label.setDisplayedMnemonic(mnLease.getMnemonic()); 732 733 panel.add(FieldLayout.LABEL, label); 734 buttonGroup = new ButtonGroup(); 735 dynamicButton = new JRadioButton( 736 ResourceStrings.getString("dynamic"), true); 737 buttonGroup.add(dynamicButton); 738 permanentButton = new JRadioButton( 739 ResourceStrings.getString("permanent"), false); 740 buttonGroup.add(permanentButton); 741 label.setLabelFor(dynamicButton); 742 panel.add(FieldLayout.FIELD, dynamicButton); 743 panel.add(FieldLayout.LABEL, new JLabel("")); 744 panel.add(FieldLayout.FIELD, permanentButton); 745 panel.setAlignmentX(Component.LEFT_ALIGNMENT); 746 stepBox.add(panel); 747 stepBox.add(Box.createVerticalGlue()); 748 } 749 750 public String getDescription() { 751 return ResourceStrings.getString("add_wiz_lease_desc"); 752 } 753 754 public Component getComponent() { 755 return stepBox; 756 } 757 758 public void setActive(int direction) { 759 dynamicButton.setSelected(dynamic); 760 setForwardEnabled(true); 761 } 762 763 public boolean setInactive(int direction) { 764 dynamic = dynamicButton.isSelected(); 765 return true; 766 } 767 } 768 769 // Last chance to check work before committing to it 770 class ReviewStep implements WizardStep { 771 private Box stepBox; 772 private JPanel panel; 773 private JTable addressTable; 774 private JLabel numberLabel; 775 private JLabel commentLabel; 776 private JLabel serverLabel; 777 private JLabel macroLabel; 778 private JLabel flagLabel; 779 private JLabel leaseLabel; 780 781 public ReviewStep() { 782 stepBox = Box.createVerticalBox(); 783 stepBox.add(Wizard.createTextArea( 784 ResourceStrings.getString("add_wiz_review_explain"), 4, 45)); 785 786 panel = new JPanel(new FieldLayout()); 787 JLabel tmpL; 788 789 tmpL = addLabelMnemonic("add_wiz_count_label"); 790 numberLabel = addField("20"); 791 tmpL.setLabelFor(numberLabel); 792 793 tmpL = addLabelMnemonic("add_wiz_comment_label"); 794 commentLabel = addField("Marketing"); 795 tmpL.setLabelFor(commentLabel); 796 797 tmpL = addLabelMnemonic("add_wiz_server_label"); 798 serverLabel = addField("atlantic"); 799 tmpL.setLabelFor(serverLabel); 800 801 tmpL = addLabelMnemonic("add_wiz_macro_label"); 802 macroLabel = addField("atlantic"); 803 tmpL.setLabelFor(macroLabel); 804 805 tmpL = addLabel("add_wiz_review_unusable"); 806 flagLabel = addField("Yes"); 807 tmpL.setLabelFor(flagLabel); 808 tmpL.setToolTipText( 809 ResourceStrings.getString("add_wiz_review_unusable")); 810 811 tmpL = addLabelMnemonic("add_wiz_lease_label"); 812 leaseLabel = addField(ResourceStrings.getString("dynamic")); 813 tmpL.setLabelFor(leaseLabel); 814 815 panel.setAlignmentX(Component.LEFT_ALIGNMENT); 816 stepBox.add(panel); 817 818 stepBox.add(Box.createVerticalStrut(5)); 819 820 Mnemonic mnAdd = 821 new Mnemonic(ResourceStrings.getString( 822 "add_wiz_confirm_label")); 823 JLabel label = new JLabel(mnAdd.getString()); 824 stepBox.add(label); 825 stepBox.add(Box.createVerticalStrut(2)); 826 addressTable = new JTable(addressTableModel); 827 label.setLabelFor(addressTable); 828 label.setToolTipText(mnAdd.getString()); 829 label.setDisplayedMnemonic(mnAdd.getMnemonic()); 830 831 addressTable.setDefaultRenderer(IPAddress.class, 832 new ExtendedCellRenderer()); 833 834 // Table should not be selectable in any way 835 addressTable.setRowSelectionAllowed(false); 836 addressTable.setColumnSelectionAllowed(false); 837 addressTable.setCellSelectionEnabled(false); 838 JScrollPane scrollPane = new JScrollPane(addressTable); 839 Dimension d = addressTable.getPreferredScrollableViewportSize(); 840 d.height = 50; 841 addressTable.setPreferredScrollableViewportSize(d); 842 stepBox.add(scrollPane); 843 stepBox.add(Box.createVerticalGlue()); 844 } 845 846 private JLabel addLabel(String s) { 847 JLabel l = new JLabel(ResourceStrings.getString(s)); 848 panel.add(FieldLayout.LABEL, l); 849 return l; 850 } 851 852 private JLabel addLabelMnemonic(String s) { 853 Mnemonic mnStr = 854 new Mnemonic(ResourceStrings.getString(s)); 855 JLabel l = new JLabel(mnStr.getString()); 856 l.setToolTipText(mnStr.getString()); 857 panel.add(FieldLayout.LABEL, l); 858 return l; 859 } 860 861 private JLabel addField(String s) { 862 JLabel l = new JLabel(s); 863 l.setForeground(Color.black); 864 panel.add(FieldLayout.FIELD, l); 865 return l; 866 } 867 868 public String getDescription() { 869 return ResourceStrings.getString("add_wiz_review_desc"); 870 } 871 872 public Component getComponent() { 873 return stepBox; 874 } 875 876 public void setActive(int direction) { 877 // Use number of addresses actually generated, not requested 878 numberLabel.setText( 879 String.valueOf(addressTableModel.getRowCount())); 880 commentLabel.setText(comment); 881 serverLabel.setText(server); 882 macroLabel.setText(macro); 883 if (unusable) { 884 flagLabel.setText(ResourceStrings.getString("yes")); 885 } else { 886 flagLabel.setText(ResourceStrings.getString("no")); 887 } 888 if (dynamic) { 889 leaseLabel.setText(ResourceStrings.getString("dynamic")); 890 } else { 891 leaseLabel.setText(ResourceStrings.getString("permanent")); 892 } 893 setFinishEnabled(true); 894 } 895 896 public boolean setInactive(int direction) { 897 // Nothing to do 898 return true; 899 } 900 } 901 902 public AddressWizard(Frame owner, Network net) { 903 super(owner, ""); 904 setTitle(MessageFormat.format( 905 ResourceStrings.getString("address_wizard_title"), net.toString())); 906 907 network = net; 908 startAddress = network.getAddress(); 909 910 try { 911 noMacro = new Macro(ResourceStrings.getString("no_macro_item")); 912 } catch (ValidationException e) { 913 // this should never happen! 914 System.err.println(e.getMessage()); 915 } 916 addressTableModel = new WizardTableModel(); 917 918 // Create steps in order of appearance 919 addStep(new NumberStep()); 920 addStep(new ServerStep()); 921 addStep(new ConfirmStep()); 922 addStep(new ConfigureStep()); 923 addStep(new LeaseStep()); 924 addStep(new ReviewStep()); 925 showFirstStep(); 926 } 927 928 public void doFinish() { 929 /* 930 * Method here is as follows: 931 * 1. Create a ProgressManager which will apprise user of our progress 932 * 2. Create a background thread to execute the add operations 933 * 3. Within the background thread, update the progress monitor 934 * as each address is created. 935 * 4. At completion, the background thread displays the error 936 * output, if any, before it invokes one last runnable which pops 937 * down and cleans up. 938 */ 939 // final so that ProgressUpdater can access it 940 final ProgressManager progress = new ProgressManager(this, 941 ResourceStrings.getString("add_wiz_progress"), "", 0, 942 addressTableModel.getRowCount()); 943 final Runnable finisher = new Runnable() { 944 public void run() { 945 reallyFinish(); 946 } 947 }; 948 949 // Here's the thread which does the adds 950 Thread addThread = new Thread() { 951 public void run() { 952 DhcpNetMgr server = DataManager.get().getDhcpNetMgr(); 953 // Create a template object which we'll use for all the adds 954 DhcpClientRecord rec = new DhcpClientRecord(); 955 rec.setExpiration(new Date(0)); 956 rec.setUnusable(unusable); 957 rec.setPermanent(!dynamic); 958 try { 959 rec.setServerIP(serverIP); 960 } catch (ValidationException e) { 961 // Should never happen as we have a valid IP already 962 } 963 if (macro.equals(noMacro.getKey())) { 964 rec.setMacro(""); 965 } else { 966 rec.setMacro(macro); 967 } 968 rec.setComment(comment); 969 970 // This is final so it can be used in the errorDisplay Runnable 971 final ErrorTable failedTable = new ErrorTable( 972 ResourceStrings.getString("address_column"), 973 IPAddress.class); 974 975 /* 976 * For each address, create a client record and possibly a 977 * hosts record, log any errors for later consumption. 978 */ 979 for (int i = 0; i < addressTableModel.getRowCount(); ++i) { 980 Address addr = addressTableModel.getAddressAt(i); 981 try { 982 rec.setClientIP(addr.addr); 983 rec.setClientName(addr.name); 984 server.addClient(rec, network.toString()); 985 progress.update(i+1, addr.addr.toString()); 986 } catch (InterruptedException e) { 987 SwingUtilities.invokeLater(finisher); 988 return; 989 } catch (Throwable e) { 990 // Pick the best message for the exception thrown 991 String msg; 992 if (e instanceof ExistsException) { 993 msg = ResourceStrings.getString("address_exists"); 994 } else if (e instanceof HostExistsException) { 995 msg = ResourceStrings.getString("host_exists"); 996 } else { 997 msg = e.getMessage(); 998 } 999 failedTable.addError(addr.addr, msg); 1000 } 1001 } 1002 1003 // If any errors occurred, display them all at once. 1004 if (!failedTable.isEmpty()) { 1005 Runnable errorDisplay = new Runnable() { 1006 public void run() { 1007 Object [] objs = new Object[2]; 1008 objs[0] = 1009 ResourceStrings.getString("add_wiz_error"); 1010 JScrollPane scrollPane = 1011 new JScrollPane(failedTable); 1012 // Resize the table to something kind of small 1013 Dimension d = 1014 failedTable. 1015 getPreferredScrollableViewportSize(); 1016 d.height = 80; 1017 failedTable.setPreferredScrollableViewportSize(d); 1018 objs[1] = scrollPane; 1019 JOptionPane.showMessageDialog(AddressWizard.this, 1020 objs, 1021 ResourceStrings.getString("server_error_title"), 1022 JOptionPane.ERROR_MESSAGE); 1023 } 1024 }; 1025 try { 1026 SwingUtilities.invokeAndWait(errorDisplay); 1027 } catch (Throwable e) { 1028 e.printStackTrace(); 1029 } 1030 } 1031 SwingUtilities.invokeLater(finisher); 1032 } 1033 }; 1034 addThread.start(); 1035 } 1036 1037 protected void reallyFinish() { 1038 super.doFinish(); 1039 } 1040 1041 public void doHelp() { 1042 DhcpmgrApplet.showHelp("address_wizard"); 1043 } 1044 }