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 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28 package com.sun.dhcpmgr.ui;
29
30 import javax.swing.*;
31 import javax.swing.event.*;
32 import java.awt.*;
33 import java.awt.event.*;
34 import java.util.*;
35 import java.net.URL;
36
37 /**
38 * A main window container for an application which glues together multiple sets
39 * of functionality (called Views) into a whole with a single menu bar,
40 * status bar, and search functionality.
41 * @see View
42 */
43 public class MainFrame extends JFrame {
44
45 class StatusBar extends JPanel {
46 private JLabel data;
47 private FindPanel finder;
48
49 public StatusBar() {
50 super(new BorderLayout());
51 setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
52 data = new JLabel("", SwingConstants.LEFT);
53 Font f = data.getFont();
54 Font f2 = new Font(f.getName(), Font.PLAIN, f.getSize());
55 data.setFont(f2);
56 data.setForeground(Color.black);
57 data.setLabelFor(this);
58 add(data, BorderLayout.WEST);
59 finder = new FindPanel();
60 add(finder, BorderLayout.EAST);
61 }
62
63 public void setText(String s) {
64 data.setText(s);
65 data.setToolTipText(s);
66 // Force a relayout to avoid truncating text if longer
67 invalidate();
68 validate();
69 }
70
71 public String getText() {
72 return data.getText();
73 }
74 }
75
76 /**
77 * The panel with the Find control
78 */
79 class FindPanel extends JPanel implements ActionListener {
80 private JTextField text;
81 private JButton button;
82
83 public void actionPerformed(ActionEvent e) {
84 activeView.find(text.getText());
85 }
86
87 public FindPanel() {
88 text = new JTextField("", 20);
89
90 Mnemonic mnNext =
91 new Mnemonic(ResourceStrings.getString("next_button"));
92 button = new JButton(mnNext.getString());
93 button.setToolTipText(mnNext.getString());
94 button.setMnemonic(mnNext.getMnemonic());
95
96 button.addActionListener(this);
97 text.addActionListener(this);
98
99 Mnemonic mnFind =
100 new Mnemonic(ResourceStrings.getString("find_label"));
101 JLabel findLbl = new JLabel(mnFind.getString());
102 findLbl.setLabelFor(text);
103 findLbl.setToolTipText(mnFind.getString());
104 findLbl.setDisplayedMnemonic(mnFind.getMnemonic());
105 add(findLbl);
106
107 add(text);
108 add(button);
109 }
110 }
111
112 // Handler for the File->Exit menu item
113 class ExitAction extends MnemonicAction {
114 public ExitAction() {
115 super(ResourceStrings.getString("exit_item"));
116 }
117
118 public void actionPerformed(ActionEvent e) {
119 setVisible(false);
120 dispose();
121 }
122 }
123
124 // Handler for Edit->Create menu item
125 class CreateAction extends MnemonicAction {
126 public CreateAction() {
127 super(ResourceStrings.getString("create_item"));
128 }
129
130 public void actionPerformed(ActionEvent e) {
131 activeView.handleCreate();
132 }
133 }
134
135 // Handler for the Edit->Delete menu item
136 class DeleteAction extends MnemonicAction {
137 public DeleteAction() {
138 super(ResourceStrings.getString("delete_item"));
139 }
140
141 public void actionPerformed(ActionEvent e) {
142 activeView.handleDelete();
143 }
144 }
145
146 // Handler for the Edit->Duplicate menu item
147 class DuplicateAction extends MnemonicAction {
148 public DuplicateAction() {
149 super(ResourceStrings.getString("duplicate_item"));
150 }
151
152 public void actionPerformed(ActionEvent e) {
153 activeView.handleDuplicate();
154 }
155 }
156
157 // Handler for the Edit->Properties menu item
158 class PropertiesAction extends MnemonicAction {
159 public PropertiesAction() {
160 super(ResourceStrings.getString("properties_item"));
161 }
162
163 public void actionPerformed(ActionEvent e) {
164 activeView.handleProperties();
165 }
166 }
167
168 // Handler for the View->Update menu item
169 class UpdateAction extends MnemonicAction {
170 public UpdateAction() {
171 super(ResourceStrings.getString("update_item"));
172 }
173
174 public void actionPerformed(ActionEvent e) {
175 activeView.handleUpdate();
176 }
177 }
178
179 // Listener for selection events from the views
180 class ViewSelectionListener implements SelectionListener {
181 public void valueChanged() {
182 // Set menu item state on edit menu
183 for (int i = 1; i < menuActions[EDIT_MENU].length; ++i) {
184 if (i == 2) {
185 // Duplicate can only be active for a single selection
186 menuActions[EDIT_MENU][i].setEnabled(
187 !activeView.isSelectionEmpty()
188 && !activeView.isSelectionMultiple());
189 } else {
190 menuActions[EDIT_MENU][i].setEnabled(
191 !activeView.isSelectionEmpty());
192 }
193 }
194 }
195 }
196
197 public static final int FILE_MENU = 0;
198 public static final int EDIT_MENU = 1;
199 public static final int VIEW_MENU = 2;
200 public static final int ACTIONS_MENU = 3;
201 public static final int HELP_MENU = 4;
202 public static final int MENU_COUNT = 5;
203 // The set of menus for the application
204 private static String menuKeys[] = { "file_menu", "edit_menu", "view_menu",
205 "actions_menu", "help_menu" };
206 /*
207 * Table of all the menu actions owned by MainFrame; some end up
208 * delegating to the View.
209 */
210 private Action [] [] menuActions = {
211 // File Menu
212 { new ExitAction() },
213
214 // Edit Menu
215 { new CreateAction(), new DeleteAction(), new DuplicateAction(),
216 new PropertiesAction() },
217 // View Menu
218 { new UpdateAction() },
219
220 // Actions Menu
221 { },
222
223 // Help Menu
224 { }
225 };
226 private JMenuBar menuBar;
227 private JMenu menuList[];
228 private static StatusBar statusBar;
229 private Component display = null;
230 private JTabbedPane displayPanel;
231 private View activeView, initialView;
232 private Vector views;
233 private int [] separatorIndex = new int[MENU_COUNT];
234 private ButtonGroup viewButtonGroup = new ButtonGroup();
235 private ViewSelectionListener viewSelectionListener =
236 new ViewSelectionListener();
237 private boolean initialized = false;
238
239 public MainFrame() {
240 this("");
241 }
242
243 public MainFrame(String title) {
244 super(title);
245 views = new Vector();
246 Container contentPane = getContentPane();
247 // Create basic menu structure
248 menuBar = new JMenuBar();
249 menuList = new JMenu[menuKeys.length];
250 // First the menus
251 for (int i = 0; i < menuList.length; ++i) {
252 Mnemonic m = new Mnemonic(ResourceStrings.getString(menuKeys[i]));
253 menuList[i] = (JMenu)menuBar.add(new JMenu(m.getString()));
254 menuList[i].setMnemonic(m.getMnemonic());
255 }
256 // Now the items on each menu
257 for (int i = 0; i < menuActions.length; ++i) {
258 for (int j = 0; j < menuActions[i].length; ++j) {
259 menuList[i].add(menuActions[i][j]);
260 }
261 }
262
263 // separatorIndex will remember where we automatically put separators
264 for (int i = 0; i < MENU_COUNT; ++i) {
265 separatorIndex[i] = -1;
266 }
267
268 setJMenuBar(menuBar);
269 contentPane.setLayout(new BorderLayout());
270
271 // Status bar for messages
272 statusBar = new StatusBar();
273 contentPane.add(statusBar, BorderLayout.SOUTH);
274
275 // Display panel is the area for the view's main display
276 displayPanel = new JTabbedPane();
277 displayPanel.addChangeListener(new ChangeListener() {
278 public void stateChanged(ChangeEvent e) {
279 /*
280 * Prevent premature activation of a view which would otherwise
281 * happen as a byproduct of adding views to the tabbed pane.
282 */
283 if (initialized) {
284 try {
285 setActiveView((View)views.elementAt(
286 displayPanel.getSelectedIndex()));
287 } catch (Throwable t) {
288 t.printStackTrace();
289 }
290 }
291 }
292 });
293 contentPane.add(displayPanel, BorderLayout.CENTER);
294 activeView = null;
295 }
296
297 public static String getStatusText() {
298 return statusBar.getText();
299 }
300
301 public static void setStatusText(String text) {
302 statusBar.setText(text);
303 }
304
305 // Add a global menu
306 public void addMenuAction(int menu, Action action) {
307 menuList[menu].add(action);
308 }
309
310 // Add a view to the system
311 public void addView(View v, boolean isInitial) {
312 views.addElement(v);
313 displayPanel.addTab(v.getName(), v.getDisplay());
314 if (isInitial) {
315 initialView = v;
316 }
317
318 /*
319 * Listen to selection events from the view, update menu state
320 * accordingly
321 */
322 v.addSelectionListener(viewSelectionListener);
323 }
324
325 // Delete a view
326 public void deleteView(View v) {
327 views.removeElement(v);
328 /*
329 * If we're deleting the currently active view, need to activate
330 * another one; default to the initial view, unless that is also
331 * the one we're deleting, in which case just pick the first view.
332 */
333 if (v == activeView) {
334 if (v != initialView) {
335 setActiveView(initialView);
336 } else {
337 setActiveView((View)views.firstElement());
338 }
339 }
340 displayPanel.remove(v.getDisplay());
341 v.removeSelectionListener(viewSelectionListener);
342 }
343
344 // Select the view to be shown
345 public void setActiveView(View v) {
346 if (activeView != null) {
347 activeView.setActive(false);
348 }
349 // Remove custom menus from existing active view
350 for (int i = MENU_COUNT + 1; i < menuBar.getMenuCount(); ++i) {
351 menuBar.remove(i);
352 }
353 /*
354 * Remove menu items on standard menus from existing active view,
355 * add those from new view
356 */
357 for (int i = 0; i < menuList.length; ++i) {
358 JMenu m = menuBar.getMenu(i);
359 if (activeView != null) {
360 Enumeration e = activeView.menuItems(i);
361 if (e != null) {
362 if (separatorIndex[i] != -1) {
363 m.remove(separatorIndex[i]);
364 separatorIndex[i] = -1;
365 }
366 while (e.hasMoreElements()) {
367 JMenuItem mi = (JMenuItem)e.nextElement();
368 if (mi != null) {
369 m.remove((Component)mi);
370 }
371 }
372 }
373 }
374 Enumeration e = v.menuItems(i);
375 if (e != null) {
376 while (e.hasMoreElements()) {
377 /*
378 * This test here so separator is only added if we
379 * actually get a menu item from the view, protecting
380 * against an empty enumeration causing a stray separator.
381 */
382 if (separatorIndex[i] == -1) {
383 separatorIndex[i] = m.getItemCount();
384 m.addSeparator();
385 }
386 JMenuItem mi = (JMenuItem)e.nextElement();
387 if (mi != null) {
388 m.add(mi);
389 }
390 }
391 }
392 }
393
394 // Add view's menus
395 Enumeration e = v.menus();
396 while ((e != null) && e.hasMoreElements()) {
397 JMenu m = (JMenu)e.nextElement();
398 if (m != null) {
399 menuBar.add(m);
400 }
401 }
402 activeView = v;
403 activeView.setActive(true);
404 viewSelectionListener.valueChanged();
405 invalidate();
406 validate();
407 }
408
409 // Call this to get things started
410 public void initialize() {
411 if (initialView != null) {
412 setActiveView(initialView);
413 initialized = true;
414 }
415 }
416
417 // Set enabled/disabled state for menus
418 public void setMenuEnabled(int menu, boolean state) {
419 menuList[menu].setEnabled(state);
420 }
421
422 // Refresh all views, including those not currently active
423 public void refreshAllViews() {
424 for (Enumeration en = views.elements(); en.hasMoreElements(); ) {
425 View v = (View)en.nextElement();
426 v.handleUpdate();
427 }
428 }
429 }