/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.gui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.GraphicsEnvironment; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.UIManager; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import com.servoy.j2db.Messages; import com.servoy.j2db.smart.WebStart; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.PersistHelper; import com.servoy.j2db.util.gui.IPropertyEditorDialog; import com.servoy.j2db.util.gui.JEscapeDialog; /** * A simple FontChooser dialog that implements similar functionality to * the JFileChooser, JOptionPane and JColorChooser components provided * with Swing.<p> * Upon initialization, the JFontChooser polls the system for all available * fonts, initializes the various JList components to the values of the * default font and provides a preview of the font. As options are changed/selected * the preview is updated to display the current font.<p> * JFileChooser can either be created and added to a GUI as a typical * JComponent or it can display a JDialog using the {@link #showDialog(Component, String) showDialog} * method (just like the <b>JFileChooser</b> component). Objects * that extend JFontChooser should use the {@link #acceptSelection() acceptSelection} and * {@link #cancelSelection() cancelSelection} methods to determine either * an accept or cancel selection.<p> * <i>Example:</i> * <blockquote> * <samp> * JFontChooser chooser = new JFontChooser(new Font("Arial", Font.BOLD, 12)); * if (chooser.showDialog(this, "Choose a font...") == JFontChooser.ACCEPT_OPTION) { * Font f = chooser.getSelectedFont(); * // Process font here... * } * </samp></blockquote> * <p> */ public class JFontChooser extends JComponent implements ActionListener, ListSelectionListener, IPropertyEditorDialog { private static final String DIALOG_NAME = "FontChooserDialog"; private static final Font DEFAULT = new Font("sansserif", Font.PLAIN, 11); //$NON-NLS-1$ private static final String DEFAULT_FONT = "sansserif"; //$NON-NLS-1$ private static Font[] availableFonts; private Font font; private JList fontNames, fontSizes, fontStyles; private JTextField currentSize; private JButton okay, cancel, copyButton, defaultButton; private JFontPreviewPanel preview; private JDialog dialog; private int returnValue; /** * Constructs a new JFontChooser component initialized to the supplied font object. * @see com.lamasoft.JFontChooser#showDialog(Component, String) */ public JFontChooser(Window parent, Font font) { super(); this.parent = parent; this.font = (font == null ? DEFAULT : font); try { setup(); } catch (Exception ex) { Debug.error(ex); } } private Window parent; public JFontChooser(Window parent) { this(parent, new Font(DEFAULT_FONT, Font.PLAIN, 11)); } public static Font[] getAvailableFonts(Vector names) { if (availableFonts == null) { try { availableFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); } catch (Exception ex) { Debug.error(ex); Debug.trace("GraphicsEnvironment only availble under 1.2"); //$NON-NLS-1$ } } if (names != null) { for (Font availableFont : availableFonts) { String fontName = availableFont.getName(); if (!names.contains(fontName)) { names.addElement(fontName); } } } return availableFonts; } private void setup() { setLayout(new BorderLayout(5, 5)); Vector names = new Vector(); availableFonts = getAvailableFonts(names); fontNames = new FixedJList(names); fontNames.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); fontNames.setCellRenderer(new DefaultListCellRenderer()); JScrollPane fontNamesScroll = new JScrollPane(fontNames); fontNames.addListSelectionListener(this); Object[] styles = { "Regular", "Bold", "Italic", "BoldItalic" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ fontStyles = new FixedJList(styles); fontStyles.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); fontStyles.setCellRenderer(new DefaultListCellRenderer()); JScrollPane fontStylesScroll = new JScrollPane(fontStyles); fontStyles.setSelectedIndex(0); fontStyles.addListSelectionListener(this); fontSizes = new FixedJList(); fontSizes.setModel(createFontSizes()); fontSizes.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); fontSizes.setCellRenderer(new DefaultListCellRenderer()); JScrollPane fontSizesScroll = new JScrollPane(fontSizes); fontSizes.addListSelectionListener(this); currentSize = new JTextField(5); currentSize.setText((new Integer(font.getSize())).toString()); currentSize.addActionListener(this); JPanel sizePane = new JPanel(new BorderLayout(5, 5)); sizePane.add(currentSize, BorderLayout.NORTH); sizePane.add(fontSizesScroll, BorderLayout.CENTER); JPanel styleSizePane = new JPanel(new BorderLayout(5, 5)); styleSizePane.add(fontStylesScroll, BorderLayout.WEST); styleSizePane.add(sizePane, BorderLayout.CENTER); preview = new JFontPreviewPanel(this.font); okay = new JButton(Messages.getString("servoy.button.ok")); //$NON-NLS-1$ okay.addActionListener(this); copyButton = new JButton(Messages.getString("servoy.button.copy")); //$NON-NLS-1$ copyButton.addActionListener(this); copyButton.setActionCommand("copy"); //$NON-NLS-1$ cancel = new JButton(Messages.getString("servoy.button.cancel")); //$NON-NLS-1$ cancel.addActionListener(this); defaultButton = new JButton(Messages.getString("servoy.button.default")); //$NON-NLS-1$ defaultButton.addActionListener(this); defaultButton.setActionCommand("default"); //$NON-NLS-1$ JPanel top = new JPanel(new BorderLayout(5, 5)); top.add(fontNamesScroll, BorderLayout.CENTER); top.add(styleSizePane, BorderLayout.EAST); preview.setBorder(preview.getBorder()); add("North", top); //$NON-NLS-1$ add("Center", preview); //$NON-NLS-1$ setSelectedFont(font); } public static DefaultComboBoxModel createFontSizes() { DefaultComboBoxModel dlm = new DefaultComboBoxModel(); for (int i = 3; i < 72; i++) dlm.addElement(new Integer(i)); return dlm; } public void setSelectedFont(Font a_font) { if (a_font == null) { a_font = UIManager.getFont("Label.font"); //$NON-NLS-1$ if (a_font == null) { a_font = new Font(DEFAULT_FONT, Font.PLAIN, 11); } } font = a_font; preview.setFont(a_font); fontSizes.setSelectedValue((new Integer(a_font.getSize())), true); fontNames.setSelectedValue(a_font.getFamily(), true); if (a_font.getStyle() == Font.PLAIN) fontStyles.setSelectedValue("Regular", false); //$NON-NLS-1$ else if (a_font.getStyle() == Font.ITALIC) fontStyles.setSelectedValue("Italic", false); //$NON-NLS-1$ else if (a_font.getStyle() == Font.BOLD) fontStyles.setSelectedValue("Bold", false); //$NON-NLS-1$ else if (a_font.getStyle() == (Font.BOLD | Font.ITALIC)) fontStyles.setSelectedValue("BoldItalic", false); //$NON-NLS-1$ } private void updateFont(Font f) { this.font = f; preview.setFont(this.font); } private void updateFontSize(int size) { Font f = new Font(font.getName(), font.getStyle(), size); updateFont(f);//font.deriveFont((new Integer(size)).floatValue())); } private void updateFontStyle(int style) { Font f = new Font(font.getName(), style, font.getSize()); updateFont(f);// font.deriveFont(style)); } /** * Returns the currently selected font. Typically called after receipt * of an ACCEPT_OPTION (using the {@link #showDialog(Component, String) showDialog} option) or from within the * approveSelection method (using the component option). * @return java.awt.Font A font class that represents the currently selected font. */ public Font getSelectedFont() { return font; } /** * Processes action events from the okay and cancel buttons * as well as the current size TextField. */ public void actionPerformed(ActionEvent e) { if (e.getSource() == okay) { returnValue = OK_OPTION; if (dialog != null) dialog.setVisible(false); } else if (e.getSource() == cancel) { returnValue = CANCEL_OPTION; if (dialog != null) dialog.setVisible(false); } else if (e.getSource() == copyButton) { copy(); } else if (e.getSource() == defaultButton) { font = null; returnValue = OK_OPTION; if (dialog != null) dialog.setVisible(false); } else if (e.getSource() == currentSize) { fontSizes.setSelectedValue(new Integer(currentSize.getText()), true); } } private void copy() { if (font != null) { String sfont = PersistHelper.createFontString(font); WebStart.setClipboardContent("'" + sfont + "'"); //$NON-NLS-1$ //$NON-NLS-2$ } } /** * Processes events received from the various JList objects. */ public void valueChanged(ListSelectionEvent e) { if (e.getSource() == fontNames) { Font f = availableFonts[fontNames.getSelectedIndex()]; if (font == null) font = DEFAULT; f = new Font(f.getName()/* Font */, font.getStyle(), font.getSize()); updateFont(f); } if (e.getSource() == fontSizes) { currentSize.setText(fontSizes.getSelectedValue().toString()); updateFontSize((new Integer(currentSize.getText())).intValue()); } if (e.getSource() == fontStyles) { int style = Font.PLAIN; String selection = (String)fontStyles.getSelectedValue(); if (selection.equals("Regular")) //$NON-NLS-1$ style = Font.PLAIN; if (selection.equals("Bold")) //$NON-NLS-1$ style = Font.BOLD; if (selection.equals("Italic")) //$NON-NLS-1$ style = Font.ITALIC; if (selection.equals("BoldItalic")) //$NON-NLS-1$ style = (Font.BOLD | Font.ITALIC); updateFontStyle(style); } } public int showDialog() { return showDialog(parent, "Font", true); //$NON-NLS-1$ } /** * Pops up a Font chooser dialog with the supplied <i>title</i>, centered * about the component <i>parent</i>. * @return int An integer that equates to the static variables <i>ERROR_OPTION</i>, <i>ACCEPT_OPTION</i> or <i>CANCEL_OPTION</i>. */ public int showDialog(Window parent, String title, boolean showDefault) { this.parent = parent; returnValue = CANCEL_OPTION; if (parent instanceof Frame) { dialog = new JEscapeDialog((Frame)parent, title, true) { @Override protected void cancel() { setVisible(false); } }; } else { dialog = new JEscapeDialog((Dialog)parent, title, true) { @Override protected void cancel() { setVisible(false); } }; } dialog.setName(DIALOG_NAME); setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); dialog.getContentPane().add(this, BorderLayout.CENTER); JPanel buttonPane = new JPanel(); buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); buttonPane.add(copyButton); buttonPane.add(Box.createHorizontalGlue()); buttonPane.add(okay); buttonPane.add(Box.createRigidArea(new Dimension(5, 0))); buttonPane.add(cancel); if (showDefault) { buttonPane.add(Box.createRigidArea(new Dimension(5, 0))); buttonPane.add(defaultButton); } dialog.getContentPane().add(buttonPane, BorderLayout.SOUTH); dialog.pack(); dialog.setLocationRelativeTo(parent); setSelectedFont(font); dialog.setVisible(true); return returnValue; } } class JFontPreviewPanel extends JLabel { public JFontPreviewPanel(Font f) { super(); setOpaque(true); setFont(f); setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), Messages.getString("servoy.general.preview"))); //$NON-NLS-1$ } @Override public void setFont(Font f) { super.setFont(f); setText(f.getName()); } @Override public Dimension getPreferredSize() { return new Dimension(getSize().width, 75); } @Override public Dimension getMinimumSize() { return getPreferredSize(); } }