4 * License : The MIT License
5 * Copyright(c) 2009 olyutorskii
8 package jp.sfjp.jindolf.util;
10 import java.awt.Component;
12 import java.awt.font.TextAttribute;
13 import java.beans.PropertyChangeEvent;
14 import java.beans.PropertyChangeListener;
15 import java.util.Collections;
17 import javax.swing.ComboBoxEditor;
18 import javax.swing.JComboBox;
19 import javax.swing.JComponent;
20 import javax.swing.text.JTextComponent;
23 * Swingコンポーネントのフォント等幅化。
26 public final class Monodizer implements PropertyChangeListener{
28 /** フォント変更時のプロパティ名。 */
29 public static final String PROPNAME_FONT = "font";
31 public static final String PROPNAME_UI = "UI";
32 /** Font.MONOSPACED代替品。 */
33 public static final String FAMILY_MONO = "Monospaced";
35 private static final Map<TextAttribute, String> TEXTATTR_MONO =
36 Collections.singletonMap(TextAttribute.FAMILY, FAMILY_MONO);
38 private static final Monodizer CHANGER = new Monodizer();
53 * @return 等幅フォントならtrue
55 public static boolean isMonospaced(Font font){
56 Map<TextAttribute, ?> attrMap = font.getAttributes();
58 Object attr = attrMap.get(TextAttribute.FAMILY);
59 if( ! (attr instanceof String) ) return false;
61 String family = (String) attr;
62 if(family.equals(FAMILY_MONO)) return true;
73 public static Font deriveMonoFont(Font font){
74 Font monofont = font.deriveFont(TEXTATTR_MONO);
79 * 任意のコンポーネントをフォント等幅化する。
80 * L&F変更に対処するためのリスナ組み込みも行われる。
83 public static void monodize(JComponent comp){
84 Font oldFont = comp.getFont();
85 Font newFont = deriveMonoFont(oldFont);
86 comp.setFont(newFont);
88 modifyComponent(comp);
90 comp.addPropertyChangeListener(PROPNAME_FONT, CHANGER);
91 comp.addPropertyChangeListener(PROPNAME_UI, CHANGER);
100 * @param comp コンポーネント
102 private static void modifyComponent(JComponent comp){
103 if(comp instanceof JTextComponent){
104 JTextComponent textComp = (JTextComponent) comp;
105 modifyTextComponent(textComp);
106 }else if(comp instanceof JComboBox){
107 JComboBox combo = (JComboBox) comp;
108 modifyComboBox(combo);
115 * テキストコンポーネントへの微修正を行う。
116 * @param textComp テキストコンポーネント
118 private static void modifyTextComponent(JTextComponent textComp){
119 if(textComp.isEditable()) return;
120 if(textComp.getCaret() == null) return;
122 textComp.setCaretPosition(0);
128 * コンボボックスのエディタを等幅化する。
129 * @param comboBox コンボボックス
131 private static void modifyComboBox(JComboBox comboBox){
132 ComboBoxEditor editor = comboBox.getEditor();
133 if(editor == null) return;
135 Component editComp = editor.getEditorComponent();
136 if( ! (editComp instanceof JTextComponent) ) return;
137 JTextComponent textEditor = (JTextComponent) editComp;
139 Font oldFont = textEditor.getFont();
140 Font newFont = deriveMonoFont(oldFont);
141 textEditor.setFont(newFont);
143 modifyTextComponent(textEditor);
150 * @param event フォント変更イベント
152 public void propertyChange(PropertyChangeEvent event){
153 Object source = event.getSource();
154 if( ! (source instanceof JComponent) ) return;
155 JComponent comp = (JComponent) source;
157 String propName = event.getPropertyName();
160 if(PROPNAME_FONT.equals(propName)){
161 Object newValue = event.getNewValue();
162 if( ! (newValue instanceof Font) ) return;
163 newFont = (Font) newValue;
164 }else if(PROPNAME_UI.equals(propName)){
165 newFont = comp.getFont();
170 Font monoFont = deriveMonoFont(newFont);
171 comp.setFont(monoFont); // 再帰は起きないはず…
173 modifyComponent(comp);