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 2005 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.event.*; 32 import javax.swing.table.*; 33 import java.awt.*; 34 import java.awt.event.*; 35 import java.util.*; 36 import java.text.*; 37 38 import com.sun.dhcpmgr.ui.*; 39 import com.sun.dhcpmgr.server.*; 40 import com.sun.dhcpmgr.data.*; 41 import com.sun.dhcpmgr.bridge.BridgeException; 42 43 /** 44 * The view for options. Only displays locally defined options. 45 */ 46 public class OptionView implements View { 47 48 // Model for the table displaying the options. 49 class OptionTableModel extends AbstractTableModel { 50 private Option [] data = null; 51 private boolean firstLoad; 52 53 public OptionTableModel() { 54 firstLoad = true; 55 } 56 57 public void load() { 58 data = null; 59 // Update status line 60 MainFrame.setStatusText( 61 ResourceStrings.getString("loading_options")); 62 fireTableDataChanged(); 63 64 // Kick off background loading 65 OptionLoader loader = new OptionLoader(); 66 } 67 68 protected void doneLoading() { 69 sortedTableModel.reallocateIndexes(); 70 if (firstLoad) { 71 sortedTableModel.sortByColumn(0); 72 firstLoad = false; 73 } 74 // Check for any ill-defined options, tell user about them 75 Vector errs = new Vector(); 76 for (int i = 0; i < data.length; ++i) { 77 if (!data[i].isValid()) { 78 errs.addElement(data[i].getKey()); 79 } 80 } 81 if (errs.size() != 0) { 82 Object [] objs = new Object[2]; 83 objs[0] = 84 ResourceStrings.getString("option_validation_warning"); 85 JList optionList = new JList(errs); 86 JScrollPane scrollPane = new JScrollPane(optionList); 87 optionList.setVisibleRowCount(4); 88 objs[1] = scrollPane; 89 JOptionPane.showMessageDialog(optionTable, objs, 90 ResourceStrings.getString("warning"), 91 JOptionPane.WARNING_MESSAGE); 92 } 93 fireTableDataChanged(); 94 } 95 96 protected void setData(Option [] newdata) { 97 data = newdata; 98 } 99 100 public int getRowCount() { 101 if (data == null) { 102 return 0; 103 } else { 104 return data.length; 105 } 106 } 107 108 public int getColumnCount() { 109 return 6; 110 } 111 112 public Object getValueAt(int row, int column) { 113 switch (column) { 114 case 0: 115 return data[row].getKey(); 116 case 1: 117 return Option.getContextString(data[row].getContext()); 118 case 2: 119 return new Integer(data[row].getCode()); 120 case 3: 121 return Option.getTypeString(data[row].getType()); 122 case 4: 123 return new Integer(data[row].getGranularity()); 124 case 5: 125 return new Integer(data[row].getMaximum()); 126 default: 127 return null; 128 } 129 } 130 131 public Class getColumnClass(int column) { 132 switch (column) { 133 case 0: 134 case 1: 135 case 3: 136 return String.class; 137 case 2: 138 case 4: 139 case 5: 140 return Integer.class; 141 default: 142 super.getColumnClass(column); 143 } 144 return null; 145 } 146 147 public String getColumnName(int column) { 148 switch (column) { 149 case 0: 150 return ResourceStrings.getString("name_column"); 151 case 1: 152 return ResourceStrings.getString("category_column"); 153 case 2: 154 return ResourceStrings.getString("code_column"); 155 case 3: 156 return ResourceStrings.getString("type_column"); 157 case 4: 158 return ResourceStrings.getString("granularity_column"); 159 case 5: 160 return ResourceStrings.getString("maximum_column"); 161 default: 162 super.getColumnName(column); 163 } 164 return null; 165 } 166 167 public Option getOptionAt(int row) { 168 return data[row]; 169 } 170 } 171 172 // Background loader for options. 173 class OptionLoader extends com.sun.dhcpmgr.ui.SwingWorker { 174 public Object construct() { 175 try { 176 return DataManager.get().getOptions(true); 177 } catch (final BridgeException e) { 178 // Since we're in a background thread, ask Swing to run ASAP. 179 SwingUtilities.invokeLater(new Runnable() { 180 Object [] args = new Object[] { e.getMessage() }; 181 public void run() { 182 MessageFormat form = new MessageFormat( 183 ResourceStrings.getString("error_loading_options")); 184 JOptionPane.showMessageDialog(null, form.format(args), 185 ResourceStrings.getString("server_error_title"), 186 JOptionPane.ERROR_MESSAGE); 187 } 188 }); 189 return null; 190 } 191 } 192 193 public void finished() { 194 Option [] options = (Option [])get(); 195 if (options == null) { 196 options = new Option[0]; 197 } 198 OptionView.optionTableModel.setData(options); 199 OptionView.optionTableModel.doneLoading(); 200 MainFrame.setStatusText(MessageFormat.format( 201 ResourceStrings.getString("option_status_message"), 202 OptionView.optionTableModel.getRowCount())); 203 optionTable.clearSelection(); 204 } 205 } 206 207 /* 208 * Reload data when any dialogs this view launches indicate they've 209 * changed the data 210 */ 211 class DialogListener implements ActionListener { 212 public void actionPerformed(ActionEvent e) { 213 if (!e.getActionCommand().equals(DialogActions.CANCEL)) { 214 reload(); 215 } 216 } 217 } 218 219 private AutosizingTable optionTable; 220 private JScrollPane optionPane; 221 protected static OptionTableModel optionTableModel = null; 222 private JCheckBoxMenuItem showGrid; 223 private JMenuItem optionHelp; 224 private Vector[] menuItems; 225 private Frame myFrame; 226 private static boolean firstview = true; 227 private Vector selectionListeners = new Vector(); 228 private TableSorter sortedTableModel; 229 230 public OptionView() { 231 // Create table to display in data area 232 optionTableModel = new OptionTableModel(); 233 sortedTableModel = new TableSorter(optionTableModel); 234 235 // Use table which resizes columns to fit data 236 optionTable = new AutosizingTable(sortedTableModel); 237 sortedTableModel.addMouseListenerToHeaderInTable(optionTable); 238 optionTable.getTableHeader().setReorderingAllowed(true); 239 optionTable.getTableHeader().setResizingAllowed(true); 240 optionTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 241 242 // Allow clicks in header to adjust sorting column 243 sortedTableModel.addActionListener(new ActionListener() { 244 private int sortModelIndex = -1; 245 private TableCellRenderer savedRenderer; 246 private SortedHeaderRenderer sortedRenderer = 247 new SortedHeaderRenderer(optionTable); 248 249 public void actionPerformed(ActionEvent e) { 250 // Clear the selection if sorting is changed 251 optionTable.clearSelection(); 252 253 // Change the header rendering to show sorting column 254 int modelIndex = Integer.parseInt(e.getActionCommand()); 255 int viewIndex = 256 optionTable.convertColumnIndexToView(modelIndex); 257 if (sortModelIndex != -1) { 258 int sortViewIndex = 259 optionTable.convertColumnIndexToView(sortModelIndex); 260 optionTable.getColumnModel().getColumn(sortViewIndex). 261 setHeaderRenderer(savedRenderer); 262 } 263 /* 264 * Save the column currently being sorted so we can restore 265 * the renderer later. We save model columns rather than 266 * view columns because model columns are invariant while 267 * view columns can be reordered with confusion resulting. 268 */ 269 TableColumn c = 270 optionTable.getColumnModel().getColumn(viewIndex); 271 savedRenderer = c.getHeaderRenderer(); 272 c.setHeaderRenderer(sortedRenderer); 273 sortModelIndex = modelIndex; 274 } 275 }); 276 277 // Make it scrollable 278 optionPane = new JScrollPane(optionTable); 279 280 // Make double-clicks the same as Edit->Properties 281 optionTable.addMouseListener(new MouseAdapter() { 282 public void mouseClicked(MouseEvent e) { 283 if (e.getClickCount() == 2) { 284 handleProperties(); 285 } 286 } 287 }); 288 289 // Create menu items 290 Mnemonic mnShowGrid = 291 new Mnemonic(ResourceStrings.getString("show_grid")); 292 showGrid = new JCheckBoxMenuItem(mnShowGrid.getString(), 293 true); 294 showGrid.setMnemonic(mnShowGrid.getMnemonic()); 295 showGrid.addActionListener(new ActionListener() { 296 public void actionPerformed(ActionEvent e) { 297 optionTable.setShowGrid(showGrid.getState()); 298 } 299 }); 300 301 Mnemonic mnOnOptions = 302 new Mnemonic(ResourceStrings.getString("on_options_item")); 303 optionHelp = new JMenuItem(mnOnOptions.getString()); 304 optionHelp.setMnemonic(mnOnOptions.getMnemonic()); 305 optionHelp.addActionListener(new ActionListener() { 306 public void actionPerformed(ActionEvent e) { 307 DhcpmgrApplet.showHelp("options_reference"); 308 } 309 }); 310 311 /* 312 * Build the sets of menu items which we'll return to 313 * MainFrame when it asks for them. 314 */ 315 menuItems = new Vector[MainFrame.MENU_COUNT]; 316 for (int i = 0; i < menuItems.length; ++i) { 317 menuItems[i] = new Vector(); 318 } 319 menuItems[MainFrame.VIEW_MENU].addElement(showGrid); 320 menuItems[MainFrame.HELP_MENU].addElement(optionHelp); 321 322 // Listen for selections events, manipulate menu item state as needed 323 optionTable.getSelectionModel().addListSelectionListener( 324 new ListSelectionListener() { 325 public void valueChanged(ListSelectionEvent e) { 326 // Notify listeners that our selection state may have changed 327 notifySelectionListeners(); 328 } 329 }); 330 } 331 332 public String getName() { 333 return ResourceStrings.getString("option_view_name"); 334 } 335 336 // Return custom menus we want added, in our case none. 337 public Enumeration menus() { 338 return null; 339 } 340 341 // Return menu items for each menu as requested by MainFrame 342 public Enumeration menuItems(int menu) { 343 return menuItems[menu].elements(); 344 } 345 346 public Component getDisplay() { 347 return optionPane; 348 } 349 350 public void setActive(boolean state) { 351 if (state) { 352 // Things we do only the first time we're displayed 353 if (firstview) { 354 myFrame = (Frame)SwingUtilities.getAncestorOfClass( 355 MainFrame.class, optionTable); 356 optionTableModel.load(); 357 String s = MessageFormat.format( 358 ResourceStrings.getString("option_status_message"), 359 sortedTableModel.getRowCount()); 360 MainFrame.setStatusText(s); 361 firstview = false; 362 } 363 } 364 } 365 366 public void find(String s) { 367 int startRow = optionTable.getSelectedRow() + 1; 368 for (int i = startRow; i < sortedTableModel.getRowCount(); ++i) { 369 if (optionTableModel.getOptionAt( 370 sortedTableModel.mapRowAt(i)).toString().indexOf(s) != -1) { 371 optionTable.setRowSelectionInterval(i, i); 372 optionTable.scrollRectToVisible(optionTable.getCellRect(i, 0, 373 false)); 374 return; 375 } 376 } 377 // Got to the end, wrap around 378 for (int i = 0; i < startRow; ++i) { 379 if (optionTableModel.getOptionAt( 380 sortedTableModel.mapRowAt(i)).toString().indexOf(s) != -1) { 381 optionTable.setRowSelectionInterval(i, i); 382 optionTable.scrollRectToVisible(optionTable.getCellRect(i, 0, 383 false)); 384 return; 385 } 386 } 387 } 388 389 public void handleCreate() { 390 CreateOptionDialog d = new CreateOptionDialog(myFrame, 391 CreateOptionDialog.CREATE); 392 d.addActionListener(new DialogListener()); 393 d.pack(); 394 d.setVisible(true); 395 } 396 397 public void handleDelete() { 398 int selectedRow = optionTable.getSelectedRow(); 399 if (selectedRow == -1) { 400 return; 401 } 402 DeleteOptionDialog d = new DeleteOptionDialog(myFrame, 403 optionTableModel.getOptionAt( 404 sortedTableModel.mapRowAt(selectedRow))); 405 d.addActionListener(new DialogListener()); 406 d.pack(); 407 d.setVisible(true); 408 } 409 410 public void handleDuplicate() { 411 int selectedRow = optionTable.getSelectedRow(); 412 if (selectedRow == -1) { 413 return; 414 } 415 CreateOptionDialog d = new CreateOptionDialog(myFrame, 416 CreateOptionDialog.DUPLICATE); 417 d.setOption(optionTableModel.getOptionAt( 418 sortedTableModel.mapRowAt(selectedRow))); 419 d.addActionListener(new DialogListener()); 420 d.pack(); 421 d.setVisible(true); 422 } 423 424 public void handleProperties() { 425 int selectedRow = optionTable.getSelectedRow(); 426 if (selectedRow == -1) { 427 return; 428 } 429 CreateOptionDialog d = new CreateOptionDialog(myFrame, 430 CreateOptionDialog.EDIT); 431 d.setOption(optionTableModel.getOptionAt( 432 sortedTableModel.mapRowAt(selectedRow))); 433 d.addActionListener(new DialogListener()); 434 d.pack(); 435 d.setVisible(true); 436 } 437 438 public void handleUpdate() { 439 reload(); 440 } 441 442 private void reload() { 443 optionTableModel.load(); 444 } 445 446 public void addSelectionListener(SelectionListener listener) { 447 selectionListeners.addElement(listener); 448 } 449 450 public void removeSelectionListener(SelectionListener listener) { 451 selectionListeners.removeElement(listener); 452 } 453 454 private void notifySelectionListeners() { 455 Enumeration en = selectionListeners.elements(); 456 while (en.hasMoreElements()) { 457 SelectionListener l = (SelectionListener)en.nextElement(); 458 l.valueChanged(); 459 } 460 } 461 462 public boolean isSelectionEmpty() { 463 return optionTable.getSelectionModel().isSelectionEmpty(); 464 } 465 466 public boolean isSelectionMultiple() { 467 return false; // Multiple selection is not allowed. 468 } 469 }