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 }