/** * FontChooser - Swing dialog for choosing font, size and styles. * * Copyright 2006 Oleg Kobchenko, http://olegykj.sourceforge.net * * Licensed under the GNU LGPL License, Version 2.1 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/copyleft/lesser.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Revision history * 09/05/06 Oleg Kobchenko - original release * */ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.GraphicsEnvironment; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; import java.util.StringTokenizer; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.text.AttributeSet; import javax.swing.text.MutableAttributeSet; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; /** * FontChooser provides a pane of controls and a dialog * designed to allow a user to manipulate and select font, size and styles. * * @author Oleg Kobchenko, http://olegykj.sourceforge.net */ public class FontChooser extends JPanel implements ListSelectionListener, ItemListener, ActionListener, HierarchyListener { AttributeSet initialAttrs = null; AttributeSet currentAttrs = null; AttributeSet resultAttrs = null; int MIN_SIZE = 4; int MAX_SIZE = 72; JButton okButton; JList familyList; JList sizeList; JCheckBox boldStyle; JCheckBox italicStyle; JCheckBox underlineStyle; JCheckBox strikeStyle; JTextPane previewText; boolean isAdjusted = true; String familyArray[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); String fontChooserString = "Font Chooser"; String okString = "OK"; String cancelString = "Cancel"; String resetString = "Reset"; String familyString = "Family"; String sizeString = "Size"; String styleString = "Style"; String previewString = "Preview"; String boldString = "Bold"; String italicString = "Italic"; String underlineString = "Underline"; String strikeString = "Strike"; static final String previewSample = "AaBbCc GgJjYy\r\n012345 iiiwww"; static final String spaceString = " "; static final String quoteString = "\""; public static final String BOLD = "bold"; public static final String ITALIC = "italic"; public static final String UNDERLINE = "underline"; /** * Creates a font chooser pane with specified style attributes */ public FontChooser(AttributeSet initialAttrs) { MutableAttributeSet attrs = initialAttrs == null ? new SimpleAttributeSet() : new SimpleAttributeSet(initialAttrs); if (Arrays.binarySearch(familyArray, StyleConstants.getFontFamily(attrs)) < 0) attrs.removeAttribute(StyleConstants.FontFamily); int size = StyleConstants.getFontSize(attrs); if (size < MIN_SIZE || size > MAX_SIZE) attrs.removeAttribute(StyleConstants.FontSize); this.initialAttrs = attrs; buildUI(); setAttributes(null); } protected void buildUI() { this.addHierarchyListener(this); this.setBorder(BorderFactory.createEmptyBorder(8, 10, 6, 10)); this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); JPanel fontPanel = new JPanel(); fontPanel.setLayout(new BoxLayout(fontPanel, BoxLayout.LINE_AXIS)); // Font Family JPanel familyPanel = new JPanel(); familyPanel.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(), familyString)); familyPanel.setLayout(new BoxLayout(familyPanel, BoxLayout.PAGE_AXIS)); familyList = new JList(familyArray); JScrollPane familyScroller = new JScrollPane(familyList); familyScroller.getVerticalScrollBar().setFocusable(false); familyScroller.getHorizontalScrollBar().setFocusable(false); familyPanel.add(familyScroller); fontPanel.add(familyPanel); // Font Size JPanel sizePanel = new JPanel(); sizePanel.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(), sizeString)); sizePanel.setLayout(new BoxLayout(sizePanel, BoxLayout.PAGE_AXIS)); String sizeArray[] = new String[MAX_SIZE-MIN_SIZE+1]; for (int i = MIN_SIZE; i <= MAX_SIZE; i++) sizeArray[i-MIN_SIZE] = String.valueOf(i); sizeList = new JList(sizeArray); JScrollPane sizeScroller = new JScrollPane(sizeList); sizeScroller.getVerticalScrollBar().setFocusable(false); sizeScroller.getHorizontalScrollBar().setFocusable(false); sizePanel.add(sizeScroller); fontPanel.add(sizePanel); // Font Style JPanel stylePanel = new JPanel(); stylePanel.setBorder(BorderFactory.createTitledBorder(styleString)); stylePanel.setLayout(new BoxLayout(stylePanel, BoxLayout.PAGE_AXIS)); stylePanel.setMaximumSize(new Dimension(100, Integer.MAX_VALUE)); boldStyle = new JCheckBox(boldString); stylePanel.add(boldStyle); italicStyle = new JCheckBox(italicString); stylePanel.add(italicStyle); underlineStyle = new JCheckBox(underlineString); underlineStyle.setVisible(initialAttrs.isDefined(StyleConstants.Underline)); stylePanel.add(underlineStyle); strikeStyle = new JCheckBox(strikeString); strikeStyle.setVisible(initialAttrs.isDefined(StyleConstants.StrikeThrough)); stylePanel.add(strikeStyle); fontPanel.add(stylePanel); this.add(fontPanel); // end Font Panel this.add(Box.createRigidArea(new Dimension(0, 5))); // Preview previewText = new JTextPane(); previewText.setText(previewSample); previewText.setEditable(false); previewText.setFocusable(false); previewText.setBackground(getBackground()); JScrollPane previewPane = new JScrollPane(previewText, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); previewPane.setBackground(getBackground()); previewPane.setBorder(BorderFactory.createTitledBorder(previewString)); previewPane.setPreferredSize(new Dimension(Integer.MAX_VALUE, 100)); this.add(previewPane); this.add(Box.createRigidArea(new Dimension(0, 8))); // Buttons JPanel buttonPanel = new JPanel(); okButton = new JButton(okString); okButton.setPreferredSize(new Dimension(80, okButton.getMinimumSize().height)); okButton.addActionListener(this); buttonPanel.add(okButton); JButton cancelButton = new JButton(cancelString); cancelButton.setPreferredSize(new Dimension(80, cancelButton.getMinimumSize().height)); cancelButton.addActionListener(this); buttonPanel.add(cancelButton); buttonPanel.add(Box.createRigidArea(new Dimension(20, 0))); JButton resetButton = new JButton(resetString); resetButton.setPreferredSize(new Dimension(80, resetButton.getMinimumSize().height)); resetButton.addActionListener(this); buttonPanel.add(resetButton); this.add(buttonPanel); } //////////////////////////////////////////////////////////////////////////////// // Events public void hierarchyChanged(HierarchyEvent e) { if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0) { SwingUtilities.getRootPane(this).setDefaultButton(okButton); } } public void valueChanged(ListSelectionEvent e) { updateText(); } public void itemStateChanged(ItemEvent e) { updateText(); } public void actionPerformed(ActionEvent e) { if (e.getActionCommand() == resetString) { setAttributes(null); return; } if (e.getActionCommand() == okString) { resultAttrs = currentAttrs; } SwingUtilities.getRoot(this).setVisible(false); } //////////////////////////////////////////////////////////////////////////////// // Operations void updateText() { MutableAttributeSet attrs = previewText.getInputAttributes(); StyleConstants.setFontFamily(attrs, familyList.getSelectedValue().toString()); int size = Integer.parseInt(sizeList.getSelectedValue().toString()); StyleConstants.setFontSize(attrs, size); StyleConstants.setBold(attrs, boldStyle.isSelected()); StyleConstants.setItalic(attrs, italicStyle.isSelected()); StyleConstants.setUnderline(attrs, underlineStyle.isSelected()); StyleConstants.setStrikeThrough(attrs, strikeStyle.isSelected()); currentAttrs = new SimpleAttributeSet(attrs); if (isAdjusted) { StyleConstants.setFontSize(attrs, adjustSize(size)); } StyledDocument doc = previewText.getStyledDocument(); doc.setCharacterAttributes(0, doc.getLength()+1, attrs, false); MutableAttributeSet para = new SimpleAttributeSet(previewText.getParagraphAttributes()); StyleConstants.setAlignment(para, StyleConstants.ALIGN_CENTER); doc.setParagraphAttributes(0, doc.getLength()+1, para, false); } //////////////////////////////////////////////////////////////////////////////// // Public API /** * Shows a modal dialog on top of specified parentFrame with * optional title and initial attributes. * * @param parentFrame * the parent window or null * @param title * specified dialog title or null * @param initialAttrs * the initial font and style attributes as defined with * StyleConstants or null. * Presence (either true or false) of Underline * and StrikeThrough attributes enables * corresponding optional checkboxes. * * @return the selected attributes or null if the user * canceled * * @see javax.swing.text.StyleConstants */ public static AttributeSet showDialog(Frame parentFrame, String title, AttributeSet initialAttrs) { JDialog chooserFrame = createDialog(parentFrame, title, initialAttrs); chooserFrame.setVisible(true); return ((FontChooser)chooserFrame.getContentPane().getComponent(0)).getAttributes(); } public static JDialog createDialog(Frame parentFrame, String title, AttributeSet initialAttrs) { FontChooser chooserPanel = new FontChooser(initialAttrs); if (title == null) title = chooserPanel.fontChooserString; JDialog chooserFrame = new JDialog(parentFrame, title, true); chooserFrame.getContentPane().add(chooserPanel); chooserFrame.setSize(420, 380); chooserFrame.setLocationRelativeTo(parentFrame); return chooserFrame; } public void setAdjusted(boolean flag) { isAdjusted = flag; } public static int adjustSize(int size) { return Math.round(size * 4.0f / 3.0f); } public void setAttributes(AttributeSet attributes) { familyList.removeListSelectionListener(this); sizeList.removeListSelectionListener(this); boldStyle.removeItemListener(this); italicStyle.removeItemListener(this); underlineStyle.removeItemListener(this); strikeStyle.removeItemListener(this); if (attributes != null) initialAttrs = attributes; currentAttrs = initialAttrs; familyList.setSelectedValue(StyleConstants.getFontFamily(currentAttrs), true); sizeList.setSelectedValue(String.valueOf(StyleConstants.getFontSize(currentAttrs)), true); boldStyle.setSelected(StyleConstants.isBold(currentAttrs)); italicStyle.setSelected(StyleConstants.isItalic(currentAttrs)); underlineStyle.setSelected(StyleConstants.isUnderline(currentAttrs)); strikeStyle.setSelected(StyleConstants.isStrikeThrough(currentAttrs)); updateText(); familyList.addListSelectionListener(this); sizeList.addListSelectionListener(this); boldStyle.addItemListener(this); italicStyle.addItemListener(this); underlineStyle.addItemListener(this); strikeStyle.addItemListener(this); } public AttributeSet getAttributes() { return resultAttrs; } public static MutableAttributeSet attributesFromString(String str) { MutableAttributeSet attrs = new SimpleAttributeSet(); if (str == null) return attrs; str = str.trim(); if (str.length() == 0) return attrs; if (str.charAt(0) == '"') { int i = str.indexOf('"', 1); if (i == -1) return attrs; StyleConstants.setFontFamily(attrs, str.substring(1, i)); str = str.substring(i+1); } else { int i = str.indexOf(' ', 1); if (i == -1) i = str.length(); StyleConstants.setFontFamily(attrs, str.substring(0, i)); str = str.substring(i); } StringTokenizer st = new StringTokenizer(str, " "); if (st.hasMoreTokens()) { try { StyleConstants.setFontSize(attrs, Integer.parseInt(st.nextToken())); } catch (Exception ex) { return attrs; } } StyleConstants.setUnderline(attrs, false); while (st.hasMoreTokens()) { String tok = st.nextToken(); if (tok.equals(BOLD)) { StyleConstants.setBold(attrs, true); } else if (tok.equals(ITALIC)) { StyleConstants.setItalic(attrs, true); } else if (tok.equals(UNDERLINE)) { StyleConstants.setUnderline(attrs, true); } } return attrs; } public static String stringFromAttributes(AttributeSet attrs) { if (attrs == null) return ""; StringBuffer str = new StringBuffer(); str.append(quoteString); str.append(StyleConstants.getFontFamily(attrs)); str.append(quoteString).append(spaceString); str.append(StyleConstants.getFontSize(attrs)); if (StyleConstants.isBold(attrs)) str.append(spaceString).append(BOLD); if (StyleConstants.isItalic(attrs)) str.append(spaceString).append(ITALIC); if (StyleConstants.isUnderline(attrs)) str.append(spaceString).append(UNDERLINE); return str.toString(); } //////////////////////////////////////////////////////////////////////////////// // Example public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { } JFrame f = new JFrame("Font Chooser Test"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(new BorderLayout(10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); JTextField selectedAttrs = new JTextField("..."); panel.add(selectedAttrs, BorderLayout.NORTH); JTextArea textArea = new JTextArea(FontChooser.previewSample); textArea.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); panel.add(new JScrollPane(textArea), BorderLayout.CENTER); f.getContentPane().add(panel); f.setSize(560, 460); f.setLocationRelativeTo(null); f.setVisible(true); MutableAttributeSet initAttrs = FontChooser.attributesFromString("Arial 12 bold"); // enable optional styles StyleConstants.setStrikeThrough(initAttrs, StyleConstants.isStrikeThrough(initAttrs)); AttributeSet attrs = FontChooser.showDialog(f, null, initAttrs); if (attrs != null) { textArea.setFont(new Font(StyleConstants.getFontFamily(attrs), (StyleConstants.isBold(attrs) ? Font.BOLD : 0) | (StyleConstants.isItalic(attrs) ? Font.ITALIC : 0), FontChooser.adjustSize(StyleConstants.getFontSize(attrs)) )); // adjusted size } String result = FontChooser.stringFromAttributes(attrs); selectedAttrs.setText(result); //f.dispose(); } }