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 }