import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

/** DemoComboBox - program to demonstrate comboboxes.<p>  
*
* This program includes two comboboxes, one presenting
* a range of font sizes, and one presenting a list of all
* fonts available on the system.  The latter list is generated via
* the <code>getAllFonts</code> method of the
* <code>GraphicsEnvironment</code> class.  <code>GraphicsEnvironment</code>
* is an abstract class; however, it includes a static method called
* <code>getLocalGraphicsEnvironment</code>.  This method returns a
* <code>GraphicsEnvironment</code> object, and it is on this returned
* object that the <code>getAllFonts</code> method is invoked. Consult the
* source code listing for further details.<p>
*
* The font size combobox includes entries ranging from 10 to 48 points.
* Rather than displaying the entries left justified
* within each cell
* (as with the font names in the font combobox), they are displayed
* centered in each cell.  This is accomplished by reconfiguring the
* combobox's default renderer and editor as follows:
* <p>
*
* <pre>
*     ((JLabel)sizeCombo.getRenderer()).setHorizontalAlignment(SwingConstants.CENTER);
*     ((JTextField)sizeCombo.getEditor().getEditorComponent()).setHorizontalAlignment(JTextField.CENTER);
* </pre>
*
* The combobox's default renderer is an instance of the
* <code>BasicComBoxRenderer</code> class.  This class extends
* <code>JLabel</code> and
* implements the
* <code>ListCellRenderer</code> interface (a requirement for a
* <code>JComboBox</code> renderer).  Since it extends <code>JLabel</code>,
* forcing center alignment of cell contents is a simple matter of
* invoking <code>setHorizontalAlignment</code> on the returned object,
* as seen above.<p>
*
* A similar sequence of steps is used to reconfigure
* the combobox's default editor.
* Consult the Java API for <code>JComboBox</code> or the JFC/Swing
* tutorial for further details.<p>
*
* <pre>
*     screen snap...
* </pre>
* <center><img src="DemoComboBox-1.gif"></center><p>
*
* @see <a href="DemoComboBox.java">source code</a>
* @author Scott MacKenzie, 2003
*/
public class DemoComboBox
{
   public static void main(String[] args)
   {
      // use look and feel for my system (Win32)
      try {
         UIManager.setLookAndFeel(
            UIManager.getSystemLookAndFeelClassName());
      } catch (Exception e) {}

      DemoComboBoxFrame frame = new DemoComboBoxFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("DemoComboBox");
      frame.pack();
      frame.show();
   }
}

class DemoComboBoxFrame extends JFrame
implements ActionListener, ItemListener
{
   final int DEFAULT_STYLE = Font.PLAIN;
   final int DEFAULT_SIZE = 22;
   final int DEFAULT_SIZE_INDEX = 3;
   final String[] SZ = { "10", "14", "18", "22", "26", "32", "38", "48" };

   private JTextField message;
   private JButton exitButton;
   private JButton restoreButton;
   private JCheckBox italicCheckBox;
   private JCheckBox boldCheckBox;
   private JComboBox sizeCombo;
   private JComboBox fontCombo;

   private String fontFamily;
   private int fontSize;
   private int fontStyle;
   private String[] fontList;
   private String defaultFamily;
   private int defaultFamilyIndex;

   public DemoComboBoxFrame()
   {
      // fill a string array with the names of all the fonts on this system

      GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      fontList = ge.getAvailableFontFamilyNames();

      // find index of default font family (let's try for 'serif')
      defaultFamilyIndex = -1;
      for (int i = 0; i < fontList.length; ++i)
      {
         if (fontList[i].toLowerCase().equals("serif"))
         {
            defaultFamilyIndex = i;
            break;
         }
      }
      if (defaultFamilyIndex == -1) // not found!
      {
         JOptionPane.showMessageDialog(this,
            "Default font family ('serif') not found!\n" +
            "Will use '" + fontList[0] + "' as default.",
            "Information Message",
            JOptionPane.INFORMATION_MESSAGE
         );
         defaultFamilyIndex = 0;
      }
      defaultFamily = fontList[defaultFamilyIndex];

      fontFamily = defaultFamily;
      fontStyle = DEFAULT_STYLE;
      fontSize = DEFAULT_SIZE;
                                
      // ----------------------------------
      // construct and configure components
      // ----------------------------------

      message = new JTextField("Hello Java World");
      message.setFont(new Font(defaultFamily, DEFAULT_STYLE, DEFAULT_SIZE));
      message.setEditable(false);
      message.setBackground(Color.pink);
      message.setForeground(Color.blue);
      message.setHorizontalAlignment(SwingConstants.CENTER);
      message.setPreferredSize(new Dimension(300, 150));

      restoreButton = new JButton("Restore");
      exitButton = new JButton("Exit");

      italicCheckBox = new JCheckBox("Italic");
      boldCheckBox = new JCheckBox("Bold");

      // create the size combo box, using the size array as the list

      sizeCombo = new JComboBox(SZ);

      // center align the entries

      // Note: this must be done twice, once for the entries in the popup
      // list, which are instances of JLabel, and once for the selected
      // item, which is an instance of JTextField (because the JComboBox
      // is editable).

      ((JLabel)sizeCombo.getRenderer()).setHorizontalAlignment(SwingConstants.CENTER);
      ((JTextField)sizeCombo.getEditor().getEditorComponent()).setHorizontalAlignment(JTextField.CENTER);

      sizeCombo.setSelectedIndex(DEFAULT_SIZE_INDEX);
      sizeCombo.setPreferredSize(new Dimension(50, 1));

      // create the font combobox

      fontCombo = new JComboBox(fontList);
      fontCombo.setSelectedIndex(defaultFamilyIndex);
      fontCombo.setPreferredSize(new Dimension(150, 1));

      // -------------
      // add listeners
      // -------------

      restoreButton.addActionListener(this);
      exitButton.addActionListener(this);
      italicCheckBox.addItemListener(this);
      boldCheckBox.addItemListener(this);
      sizeCombo.addActionListener(this);
      fontCombo.addActionListener(this);

      // ------------------
      // arrange components
      // ------------------

      // add components to panels
      
      JPanel commandPanel = new JPanel();
      commandPanel.setLayout(new GridLayout(2, 1));
      commandPanel.add(restoreButton);
      commandPanel.add(exitButton);
      commandPanel.setBorder(new TitledBorder(new EtchedBorder(), "Commands"));

      Dimension d = commandPanel.getPreferredSize();

      JPanel sizePanel = new JPanel();
      sizePanel.setLayout(new GridLayout(2, 1));
      sizePanel.add(sizeCombo);
      sizePanel.setBorder(new TitledBorder(new EtchedBorder(), "Size"));
      sizePanel.setPreferredSize(d);

      JPanel stylePanel = new JPanel();
      stylePanel.setLayout(new GridLayout(2, 1));
      stylePanel.add(italicCheckBox);
      stylePanel.add(boldCheckBox);
      stylePanel.setBorder(new TitledBorder(new EtchedBorder(), "Style"));
      stylePanel.setPreferredSize(d);

      JPanel fontPanel = new JPanel();
      fontPanel.setLayout(new GridLayout(2, 1));
      fontPanel.add(fontCombo);
      fontPanel.setBorder(new TitledBorder(new EtchedBorder(), "Font"));
      fontPanel.setPreferredSize(new Dimension(d.width * 2, d.height));

      // arrange panels

      JPanel southPanel = new JPanel();
      southPanel.add(commandPanel);
      southPanel.add(sizePanel);
      southPanel.add(stylePanel);
      southPanel.add(fontPanel);

      // add panels to content pane

      Container contentPane = getContentPane();
      contentPane.add(message, "Center");
      contentPane.add(southPanel, "South");
   }

   // -------------------------------
   // implement ActionListener method
   // -------------------------------

   public void actionPerformed(ActionEvent ae)
   {
      Object source = ae.getSource();

      // 'Command' - check if a command button was pressed
      if (source == restoreButton)
      {
         fontFamily = fontList[defaultFamilyIndex];
         fontStyle = DEFAULT_STYLE;
         fontSize = DEFAULT_SIZE;
         sizeCombo.setSelectedIndex(DEFAULT_SIZE_INDEX);
         italicCheckBox.setSelected(false);
         boldCheckBox.setSelected(false);
         fontCombo.setSelectedIndex(defaultFamilyIndex);
      }
      else if (source == exitButton)
         System.exit(0);

      // 'Size' - check if the font size was changed via the combobox
      else if (source == sizeCombo)
         fontSize = Integer.parseInt((String)sizeCombo.getSelectedItem());

      // 'Font' - check if the font family was changed via the combobox
      else if (source == fontCombo)
         fontFamily = fontList[fontCombo.getSelectedIndex()];

      // update message size and style
      message.setFont(new Font(fontFamily, fontStyle, fontSize));
   }

   // -----------------------------
   // implement ItemListener method
   // -----------------------------

   public void itemStateChanged(ItemEvent ie)
   {
      Object source = ie.getSource();

      // 'Style' - check if the font style was change via a checkbox
      if (source == italicCheckBox)
      {
         if (italicCheckBox.isSelected())
            fontStyle = fontStyle | Font.ITALIC;  // turn italic on
         else
            fontStyle = fontStyle & ~Font.ITALIC; // turn italic off
      }
      else if (source == boldCheckBox)
      {
         if (boldCheckBox.isSelected())
            fontStyle = fontStyle | Font.BOLD;    // turn bold on
         else
            fontStyle = fontStyle & ~Font.BOLD;   // turn bold off
      }

      // update message size and style
      message.setFont(new Font(fontFamily, fontStyle, fontSize));
  }
}

