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 }