--- /dev/null
+/*\r
+ * font chooser\r
+ *\r
+ * Copyright(c) 2008 olyutorskii\r
+ * $Id: FontChooser.java 956 2009-12-13 15:14:07Z olyutorskii $\r
+ */\r
+\r
+package jp.sourceforge.jindolf;\r
+\r
+import java.awt.BorderLayout;\r
+import java.awt.Color;\r
+import java.awt.Container;\r
+import java.awt.Dimension;\r
+import java.awt.Font;\r
+import java.awt.Graphics;\r
+import java.awt.Graphics2D;\r
+import java.awt.GridBagConstraints;\r
+import java.awt.GridBagLayout;\r
+import java.awt.Insets;\r
+import java.awt.Rectangle;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.ActionListener;\r
+import java.awt.event.ItemEvent;\r
+import java.awt.event.ItemListener;\r
+import java.awt.font.FontRenderContext;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+import java.io.IOException;\r
+import javax.swing.BorderFactory;\r
+import javax.swing.JButton;\r
+import javax.swing.JCheckBox;\r
+import javax.swing.JComboBox;\r
+import javax.swing.JComponent;\r
+import javax.swing.JLabel;\r
+import javax.swing.JList;\r
+import javax.swing.JPanel;\r
+import javax.swing.JScrollPane;\r
+import javax.swing.JTextField;\r
+import javax.swing.ListSelectionModel;\r
+import javax.swing.border.Border;\r
+import javax.swing.event.ListSelectionEvent;\r
+import javax.swing.event.ListSelectionListener;\r
+\r
+/**\r
+ * 発言表示フォント選択パネル。\r
+ */\r
+@SuppressWarnings("serial")\r
+public class FontChooser extends JPanel\r
+ implements ListSelectionListener,\r
+ ActionListener,\r
+ ItemListener{\r
+\r
+ private static final Integer[] POINT_SIZES = {\r
+ 8, 10, 12, 16, 18, 24, 32, 36, 48, 72, // TODO これで十分?\r
+ };\r
+ private static final CharSequence PREVIEW_CONTENT;\r
+\r
+ static{\r
+ CharSequence resourceText;\r
+ try{\r
+ resourceText = Jindolf.loadResourceText("resources/preview.txt");\r
+ }catch(IOException e){\r
+ resourceText = "ABC";\r
+ }\r
+ PREVIEW_CONTENT = resourceText;\r
+ }\r
+\r
+ private FontInfo fontInfo;\r
+ private FontInfo lastFontInfo;\r
+\r
+ private final JList familySelector;\r
+ private final JComboBox sizeSelector;\r
+ private final JCheckBox isBoldCheck;\r
+ private final JCheckBox isItalicCheck;\r
+ private final JCheckBox useTextAntiAliaseCheck;\r
+ private final JCheckBox useFractionalCheck;\r
+ private final JLabel maxBounds;\r
+ private final JTextField decodeName;\r
+ private final FontPreview preview;\r
+ private final JButton resetDefault;\r
+\r
+ private boolean maskListener = false;\r
+\r
+ /**\r
+ * コンストラクタ。\r
+ */\r
+ public FontChooser(){\r
+ this(FontInfo.DEFAULT_FONTINFO);\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * コンストラクタ。\r
+ * @param fontInfo 初期フォント設定\r
+ * @throws NullPointerException 引数がnull\r
+ */\r
+ public FontChooser(FontInfo fontInfo)\r
+ throws NullPointerException{\r
+ super();\r
+\r
+ if(fontInfo == null) throw new NullPointerException();\r
+ this.fontInfo = fontInfo;\r
+ this.lastFontInfo = fontInfo;\r
+\r
+ Jindolf.logger().info(\r
+ "デフォルトの発言表示フォントに"\r
+ + this.fontInfo.getFont()\r
+ + "が選択されました" );\r
+ Jindolf.logger().info(\r
+ "発言表示のアンチエイリアス指定に"\r
+ + this.fontInfo.getFontRenderContext().isAntiAliased()\r
+ + "が指定されました" );\r
+ Jindolf.logger().info(\r
+ "発言表示のFractional指定に"\r
+ + this.fontInfo.getFontRenderContext().usesFractionalMetrics()\r
+ + "が指定されました" );\r
+\r
+ this.familySelector = new JList(FontUtils.createFontSet().toArray());\r
+ this.familySelector.setVisibleRowCount(-1);\r
+ this.familySelector\r
+ .setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+\r
+ this.sizeSelector = new JComboBox();\r
+ this.sizeSelector.setEditable(true);\r
+ this.sizeSelector.setActionCommand(ActionManager.CMD_FONTSIZESEL);\r
+ for(Integer size : POINT_SIZES){\r
+ this.sizeSelector.addItem(size);\r
+ }\r
+\r
+ this.isBoldCheck = new JCheckBox("ボールド");\r
+ this.isItalicCheck = new JCheckBox("イタリック");\r
+ this.useTextAntiAliaseCheck = new JCheckBox("アンチエイリアス");\r
+ this.useFractionalCheck = new JCheckBox("サブピクセル精度");\r
+\r
+ this.maxBounds = new JLabel();\r
+\r
+ this.decodeName = new JTextField();\r
+ this.decodeName.setEditable(false);\r
+ this.decodeName.setMargin(new Insets(1, 4, 1, 4));\r
+ this.decodeName.setComponentPopupMenu(new TextPopup());\r
+ Monodizer.monodize(this.decodeName);\r
+\r
+ this.preview = new FontPreview(PREVIEW_CONTENT, this.fontInfo);\r
+\r
+ this.resetDefault = new JButton("出荷時に戻す");\r
+ this.resetDefault.addActionListener(this);\r
+\r
+ design(this);\r
+ updateControlls();\r
+ updatePreview();\r
+\r
+ this.familySelector.addListSelectionListener(this);\r
+ this.sizeSelector .addActionListener(this);\r
+\r
+ this.isBoldCheck .addItemListener(this);\r
+ this.isItalicCheck .addItemListener(this);\r
+ this.useTextAntiAliaseCheck.addItemListener(this);\r
+ this.useFractionalCheck .addItemListener(this);\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * GUIのデザイン、レイアウトを行う。\r
+ * @param content コンテナ\r
+ */\r
+ private void design(Container content){\r
+ GridBagLayout layout = new GridBagLayout();\r
+ GridBagConstraints constraints = new GridBagConstraints();\r
+\r
+ content.setLayout(layout);\r
+\r
+ Border border;\r
+ JPanel panel;\r
+\r
+ JComponent fontPref = createFontPrefPanel();\r
+\r
+ constraints.insets = new Insets(5, 5, 5, 5);\r
+\r
+ constraints.weightx = 1.0;\r
+ constraints.weighty = 0.0;\r
+ constraints.gridwidth = GridBagConstraints.REMAINDER;\r
+ constraints.fill = GridBagConstraints.BOTH;\r
+ content.add(fontPref, constraints);\r
+\r
+ constraints.weightx = 1.0;\r
+ constraints.weighty = 1.0;\r
+ constraints.gridwidth = GridBagConstraints.REMAINDER;\r
+ constraints.fill = GridBagConstraints.BOTH;\r
+ border = BorderFactory.createTitledBorder("プレビュー");\r
+ panel = new JPanel();\r
+ panel.add(this.preview);\r
+ panel.setBorder(border);\r
+ content.add(createPreviewPanel(), constraints);\r
+\r
+ constraints.weightx = 1.0;\r
+ constraints.weighty = 0.0;\r
+ constraints.gridwidth = GridBagConstraints.REMAINDER;\r
+ constraints.fill = GridBagConstraints.HORIZONTAL;\r
+ content.add(createFontDecodePanel(), constraints);\r
+\r
+ constraints.insets = new Insets(5, 5, 5, 5);\r
+ constraints.weightx = 1.0;\r
+ constraints.weighty = 0.0;\r
+ constraints.gridwidth = 1;\r
+ constraints.fill = GridBagConstraints.HORIZONTAL;\r
+ content.add(this.maxBounds, constraints);\r
+\r
+ constraints.weightx = 0.0;\r
+ constraints.weighty = 0.0;\r
+ constraints.gridwidth = GridBagConstraints.REMAINDER;\r
+ constraints.fill = GridBagConstraints.HORIZONTAL;\r
+ content.add(this.resetDefault, constraints);\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * フォント設定画面を生成する。\r
+ * @return フォント設定画面\r
+ */\r
+ private JComponent createFontPrefPanel(){\r
+ JPanel result = new JPanel();\r
+\r
+ GridBagLayout layout = new GridBagLayout();\r
+ GridBagConstraints constraints = new GridBagConstraints();\r
+ result.setLayout(layout);\r
+\r
+ Border border;\r
+\r
+ constraints.insets = new Insets(0, 0, 0, 5);\r
+ constraints.weightx = 1.0;\r
+ constraints.weighty = 0.0;\r
+ constraints.gridheight = GridBagConstraints.REMAINDER;\r
+ constraints.fill = GridBagConstraints.BOTH;\r
+ border = BorderFactory.createEmptyBorder(1, 1, 1, 1);\r
+ this.familySelector.setBorder(border);\r
+ JScrollPane familyScroller = new JScrollPane(this.familySelector);\r
+ border = BorderFactory.createTitledBorder("フォントファミリ選択");\r
+ JPanel familyPanel = new JPanel();\r
+ familyPanel.setLayout(new BorderLayout());\r
+ familyPanel.add(familyScroller, BorderLayout.CENTER);\r
+ familyPanel.setBorder(border);\r
+ result.add(familyPanel, constraints);\r
+\r
+ constraints.insets = new Insets(0, 0, 0, 0);\r
+ constraints.weightx = 0.0;\r
+ constraints.gridheight = 1;\r
+ constraints.fill = GridBagConstraints.HORIZONTAL;\r
+ constraints.anchor = GridBagConstraints.WEST;\r
+\r
+ border = BorderFactory.createTitledBorder("ポイントサイズ指定");\r
+ JPanel panel = new JPanel();\r
+ panel.add(this.sizeSelector);\r
+ panel.setBorder(border);\r
+ result.add(panel, constraints);\r
+\r
+ constraints.anchor = GridBagConstraints.NORTHWEST;\r
+ result.add(this.isBoldCheck, constraints);\r
+ result.add(this.isItalicCheck, constraints);\r
+ result.add(this.useTextAntiAliaseCheck, constraints);\r
+ result.add(this.useFractionalCheck, constraints);\r
+\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * プレビュー画面を生成する。\r
+ * @return プレビュー画面\r
+ */\r
+ private JComponent createPreviewPanel(){\r
+ JPanel result = new JPanel();\r
+\r
+ JScrollPane scroller = new JScrollPane(this.preview);\r
+ scroller.getVerticalScrollBar().setUnitIncrement(8);\r
+\r
+ Border border;\r
+ border = BorderFactory.createTitledBorder("プレビュー");\r
+ result.setBorder(border);\r
+ result.setLayout(new BorderLayout());\r
+ result.add(scroller, BorderLayout.CENTER);\r
+\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * フォントデコード名表示パネルを生成する。\r
+ * @return フォントデコード名表示パネル\r
+ */\r
+ private JComponent createFontDecodePanel(){\r
+ JPanel result = new JPanel();\r
+\r
+ GridBagLayout layout = new GridBagLayout();\r
+ GridBagConstraints constraints = new GridBagConstraints();\r
+ result.setLayout(layout);\r
+\r
+ constraints.weightx = 0.0;\r
+ constraints.weighty = 0.0;\r
+ constraints.gridwidth = 1;\r
+ constraints.fill = GridBagConstraints.NONE;\r
+ result.add(new JLabel("Font.deode() 識別名:"), constraints);\r
+\r
+ constraints.weightx = 1.0;\r
+ constraints.gridwidth = GridBagConstraints.REMAINDER;\r
+ constraints.fill = GridBagConstraints.HORIZONTAL;\r
+ result.add(this.decodeName, constraints);\r
+\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * フォント設定を返す。\r
+ * @return フォント設定\r
+ */\r
+ public FontInfo getFontInfo(){\r
+ return this.fontInfo;\r
+ }\r
+\r
+ /**\r
+ * フォント設定を適用する。\r
+ * @param newInfo 新設定\r
+ * @throws NullPointerException 引数がnull\r
+ */\r
+ public void setFontInfo(FontInfo newInfo) throws NullPointerException{\r
+ if(newInfo == null) throw new NullPointerException();\r
+\r
+ FontInfo old = this.fontInfo;\r
+ if(old.equals(newInfo)) return;\r
+\r
+ this.fontInfo = newInfo;\r
+\r
+ updateControlls();\r
+ updatePreview();\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * 選択されたフォントを返す。\r
+ * @return フォント\r
+ */\r
+ private Font getSelectedFont(){\r
+ return this.fontInfo.getFont();\r
+ }\r
+\r
+ /**\r
+ * 設定されたフォント描画設定を返す。\r
+ * @return 描画設定\r
+ */\r
+ protected FontRenderContext getFontRenderContext(){\r
+ return this.fontInfo.getFontRenderContext();\r
+ }\r
+\r
+ /**\r
+ * フォント設定に合わせてプレビュー画面を更新する。\r
+ */\r
+ private void updatePreview(){\r
+ this.preview.setFontInfo(this.fontInfo);\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * フォント設定に合わせてGUIを更新する。\r
+ */\r
+ private void updateControlls(){\r
+ this.maskListener = true;\r
+\r
+ Font currentFont = getSelectedFont();\r
+ FontRenderContext currentContext = getFontRenderContext();\r
+\r
+ String defaultFamily = currentFont.getFamily();\r
+ this.familySelector.setSelectedValue(defaultFamily, true);\r
+\r
+ Integer selectedInteger = Integer.valueOf(currentFont.getSize());\r
+ this.sizeSelector.setSelectedItem(selectedInteger);\r
+ int sizeItems = this.sizeSelector.getItemCount();\r
+ for(int index = 0; index <= sizeItems - 1; index++){\r
+ Object sizeItem = this.sizeSelector.getItemAt(index);\r
+ if(sizeItem.equals(selectedInteger)){\r
+ this.sizeSelector.setSelectedIndex(index);\r
+ break;\r
+ }\r
+ }\r
+\r
+ this.isBoldCheck .setSelected(currentFont.isBold());\r
+ this.isItalicCheck.setSelected(currentFont.isItalic());\r
+\r
+ this.useTextAntiAliaseCheck\r
+ .setSelected(currentContext.isAntiAliased());\r
+ this.useFractionalCheck\r
+ .setSelected(currentContext.usesFractionalMetrics());\r
+\r
+ this.decodeName.setText(FontUtils.getFontDecodeName(currentFont));\r
+ this.decodeName.setCaretPosition(0);\r
+\r
+ Rectangle2D r2d = currentFont.getMaxCharBounds(currentContext);\r
+ Rectangle rect = r2d.getBounds();\r
+ String boundInfo = "最大文字寸法 : "\r
+ + rect.width\r
+ + " pixel幅 × "\r
+ + rect.height\r
+ + " pixel高";\r
+ this.maxBounds.setText(boundInfo);\r
+\r
+ this.maskListener = false;\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * ダイアログの表示・非表示。\r
+ * ダイアログが閉じられるまで制御を返さない。\r
+ * @param isVisible trueなら表示 {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void setVisible(boolean isVisible){\r
+ if(isVisible){\r
+ updateControlls();\r
+ updatePreview();\r
+ }\r
+ this.lastFontInfo = this.fontInfo;\r
+\r
+ super.setVisible(isVisible);\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * チェックボックス操作のリスナ。\r
+ * @param event 操作イベント {@inheritDoc}\r
+ */\r
+ public void itemStateChanged(ItemEvent event){\r
+ if(this.maskListener) return;\r
+\r
+ Object source = event.getSource();\r
+\r
+ if( source != this.isBoldCheck\r
+ && source != this.isItalicCheck\r
+ && source != this.useTextAntiAliaseCheck\r
+ && source != this.useFractionalCheck ){\r
+ return;\r
+ }\r
+\r
+ int style = 0 | Font.PLAIN;\r
+ if(this.isBoldCheck.isSelected()){\r
+ style = style | Font.BOLD;\r
+ }\r
+ if(this.isItalicCheck.isSelected()){\r
+ style = style | Font.ITALIC;\r
+ }\r
+ Font newFont = getSelectedFont();\r
+ if(newFont.getStyle() != style){\r
+ newFont = newFont.deriveFont(style);\r
+ }\r
+\r
+ AffineTransform tx = getFontRenderContext().getTransform();\r
+ boolean isAntiAliases = this.useTextAntiAliaseCheck.isSelected();\r
+ boolean useFractional = this.useFractionalCheck .isSelected();\r
+ FontRenderContext newContext =\r
+ new FontRenderContext(tx, isAntiAliases, useFractional);\r
+\r
+ FontInfo newInfo = new FontInfo(newFont, newContext);\r
+ setFontInfo(newInfo);\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * フォントサイズ変更処理。\r
+ */\r
+ private void actionFontSizeSelected(){\r
+ Object selected = this.sizeSelector.getSelectedItem();\r
+ if(selected == null) return;\r
+\r
+ Integer selectedInteger;\r
+ if(selected instanceof Integer){\r
+ selectedInteger = (Integer) selected;\r
+ }else{\r
+ try{\r
+ selectedInteger = Integer.valueOf(selected.toString());\r
+ }catch(NumberFormatException e){\r
+ selectedInteger = Integer.valueOf(\r
+ this.lastFontInfo.getFont().getSize()\r
+ );\r
+ }\r
+ }\r
+\r
+ if(selectedInteger.intValue() <= 0){\r
+ selectedInteger =\r
+ Integer.valueOf(this.lastFontInfo.getFont().getSize());\r
+ }\r
+\r
+ float fontSize = selectedInteger.floatValue();\r
+ Font newFont = getSelectedFont().deriveFont(fontSize);\r
+ FontInfo newInfo = this.fontInfo.deriveFont(newFont);\r
+ setFontInfo(newInfo);\r
+\r
+ int sizeItems = this.sizeSelector.getItemCount();\r
+ for(int index = 0; index <= sizeItems - 1; index++){\r
+ Object sizeItem = this.sizeSelector.getItemAt(index);\r
+ if(sizeItem.equals(selectedInteger)){\r
+ this.sizeSelector.setSelectedIndex(index);\r
+ break;\r
+ }\r
+ }\r
+\r
+ updateControlls();\r
+ updatePreview();\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * ボタン操作及びフォントサイズ指定コンボボックス操作のリスナ。\r
+ * @param event 操作イベント {@inheritDoc}\r
+ */\r
+ public void actionPerformed(ActionEvent event){\r
+ if(this.maskListener) return;\r
+\r
+ String cmd = event.getActionCommand();\r
+ if(cmd.equals(ActionManager.CMD_FONTSIZESEL)){\r
+ actionFontSizeSelected();\r
+ }\r
+\r
+ Object source = event.getSource();\r
+ if(source == this.resetDefault){\r
+ setFontInfo(FontInfo.DEFAULT_FONTINFO);\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * フォントファミリリスト選択操作のリスナ。\r
+ * @param event 操作イベント {@inheritDoc}\r
+ */\r
+ public void valueChanged(ListSelectionEvent event){\r
+ if(this.maskListener) return;\r
+\r
+ if(event.getSource() != this.familySelector) return;\r
+ if(event.getValueIsAdjusting()) return;\r
+\r
+ Object selected = this.familySelector.getSelectedValue();\r
+ if(selected == null) return;\r
+\r
+ String familyName = selected.toString();\r
+ Font currentFont = getSelectedFont();\r
+ int style = currentFont.getStyle();\r
+ int size = currentFont.getSize();\r
+\r
+ Font newFont = new Font(familyName, style, size);\r
+ FontInfo newInfo = this.fontInfo.deriveFont(newFont);\r
+\r
+ setFontInfo(newInfo);\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * フォントプレビュー画面用コンポーネント。\r
+ */\r
+ private static class FontPreview extends JComponent{\r
+\r
+ private static final int MARGIN = 5;\r
+\r
+ private final GlyphDraw draw;\r
+\r
+ private FontInfo fontInfo;\r
+\r
+ /**\r
+ * コンストラクタ。\r
+ * @param source 文字列\r
+ * @param fontInfo フォント設定\r
+ */\r
+ public FontPreview(CharSequence source,\r
+ FontInfo fontInfo ){\r
+ super();\r
+\r
+ this.fontInfo = fontInfo;\r
+ this.draw = new GlyphDraw(source, this.fontInfo);\r
+ this.draw.setFontInfo(this.fontInfo);\r
+\r
+ this.draw.setPos(MARGIN, MARGIN);\r
+\r
+ this.draw.setColor(Color.BLACK);\r
+ setBackground(Color.WHITE);\r
+\r
+ updateBounds();\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * サイズ更新。\r
+ */\r
+ private void updateBounds(){\r
+ Rectangle bounds = this.draw.setWidth(Integer.MAX_VALUE);\r
+ Dimension dimension = new Dimension(bounds.width + MARGIN * 2,\r
+ bounds.height + MARGIN * 2 );\r
+ setPreferredSize(dimension);\r
+ revalidate();\r
+ repaint();\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * フォント設定の変更。\r
+ * @param newFontInfo フォント設定\r
+ */\r
+ public void setFontInfo(FontInfo newFontInfo){\r
+ this.fontInfo = newFontInfo;\r
+ this.draw.setFontInfo(this.fontInfo);\r
+\r
+ updateBounds();\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * 文字列の描画。\r
+ * @param g {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void paintComponent(Graphics g){\r
+ super.paintComponent(g);\r
+ Graphics2D g2d = (Graphics2D) g;\r
+ this.draw.paint(g2d);\r
+ return;\r
+ }\r
+ }\r
+\r
+}\r