1 package com
.intellij
.application
.options
.colors
;
3 import com
.intellij
.application
.options
.SelectFontDialog
;
4 import com
.intellij
.openapi
.application
.ApplicationBundle
;
5 import com
.intellij
.openapi
.editor
.colors
.EditorColorsScheme
;
6 import com
.intellij
.openapi
.editor
.ex
.EditorSettingsExternalizable
;
7 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
8 import com
.intellij
.openapi
.progress
.ProgressManager
;
9 import com
.intellij
.openapi
.ui
.FixedSizeButton
;
10 import com
.intellij
.ui
.DocumentAdapter
;
11 import com
.intellij
.ui
.IdeBorderFactory
;
12 import com
.intellij
.util
.EventDispatcher
;
13 import com
.intellij
.util
.containers
.HashMap
;
16 import javax
.swing
.event
.DocumentEvent
;
18 import java
.awt
.event
.ActionEvent
;
19 import java
.awt
.event
.ActionListener
;
20 import java
.util
.ArrayList
;
21 import java
.util
.HashSet
;
24 public class FontOptions
extends JPanel
implements OptionsPanel
{
25 private ColorAndFontOptions myOptions
;
27 private JTextField myEditorFontSizeField
;
29 private JTextField myLineSpacingField
;
30 private JTextField myFontNameField
;
32 private static ArrayList
<String
> myFontNamesVector
;
33 private static HashMap
<String
, Boolean
> myFontNameToIsMonospaced
;
34 private final EventDispatcher
<ColorAndFontSettingsListener
> myDispatcher
= EventDispatcher
.create(ColorAndFontSettingsListener
.class);
35 private boolean myIsInSchemeChange
= false;
38 public FontOptions(ColorAndFontOptions options
) {
39 super(new BorderLayout());
42 JPanel schemesGroup
= new JPanel(new BorderLayout());
44 JPanel panel
= new JPanel(new BorderLayout());
45 panel
.add(createFontPanel(), BorderLayout
.NORTH
);
46 schemesGroup
.add(panel
, BorderLayout
.CENTER
);
47 add(schemesGroup
, BorderLayout
.CENTER
);
50 public void updateOptionsList() {
51 myIsInSchemeChange
= true;
53 myLineSpacingField
.setText(Float
.toString(getCurrentScheme().getLineSpacing()));
54 myEditorFontSizeField
.setText(Integer
.toString(getCurrentScheme().getEditorFontSize()));
55 myFontNameField
.setText(getCurrentScheme().getEditorFontName());
57 if (ColorAndFontOptions
.isReadOnly(myOptions
.getSelectedScheme())) {
58 myLineSpacingField
.setEnabled(false);
59 myEditorFontSizeField
.setEditable(false);
60 myFontNameField
.setEnabled(false);
63 myLineSpacingField
.setEnabled(true);
64 myEditorFontSizeField
.setEditable(true);
65 myFontNameField
.setEnabled(true);
68 myIsInSchemeChange
= false;
72 public Runnable
showOption(final String option
) {
76 public void applyChangesToScheme() {
80 public void selectOption(final String typeToSelect
) {
83 private EditorColorsScheme
getCurrentScheme() {
84 return myOptions
.getSelectedScheme();
87 private JPanel
createFontPanel() {
88 JPanel editorFontPanel
= new JPanel();
89 editorFontPanel
.setBorder(IdeBorderFactory
.createTitledBorder(ApplicationBundle
.message("group.editor.font")));
90 editorFontPanel
.setLayout(new GridBagLayout());
91 GridBagConstraints gbConstraints
= new GridBagConstraints();
92 gbConstraints
.fill
= GridBagConstraints
.HORIZONTAL
;
93 gbConstraints
.weightx
= 0;
94 gbConstraints
.weighty
= 1;
95 gbConstraints
.gridx
= 0;
96 gbConstraints
.gridy
= 0;
97 gbConstraints
.gridwidth
= 1;
99 gbConstraints
.insets
= new Insets(0, 0, 0, 0);
100 gbConstraints
.gridwidth
= 1;
101 editorFontPanel
.add(new JLabel(ApplicationBundle
.message("label.font.name")), gbConstraints
);
103 myFontNameField
= new MyTextField(20);
104 myFontNameField
.setEditable(false);
105 myFontNameField
.setFocusable(false);
107 gbConstraints
.gridx
= 1;
108 gbConstraints
.insets
= new Insets(0, 0, 0, 2);
109 editorFontPanel
.add(myFontNameField
, gbConstraints
);
111 JButton myFontNameButton
= new FixedSizeButton(myFontNameField
);
112 gbConstraints
.gridx
= 2;
113 gbConstraints
.insets
= new Insets(0, 0, 0, 8);
114 editorFontPanel
.add(myFontNameButton
, gbConstraints
);
116 gbConstraints
.gridx
= 3;
117 gbConstraints
.insets
= new Insets(0, 0, 0, 0);
118 editorFontPanel
.add(new JLabel(ApplicationBundle
.message("editbox.font.size")), gbConstraints
);
119 gbConstraints
.gridx
= 4;
120 gbConstraints
.insets
= new Insets(0, 0, 0, 8);
121 myEditorFontSizeField
= new MyTextField(4);
122 gbConstraints
.gridx
= 5;
123 editorFontPanel
.add(myEditorFontSizeField
, gbConstraints
);
124 gbConstraints
.insets
= new Insets(0, 0, 0, 0);
125 gbConstraints
.gridx
= 6;
126 editorFontPanel
.add(new JLabel(ApplicationBundle
.message("editbox.line.spacing")), gbConstraints
);
127 gbConstraints
.insets
= new Insets(0, 0, 0, 0);
128 gbConstraints
.gridx
= 7;
129 myLineSpacingField
= new MyTextField(4);
130 editorFontPanel
.add(myLineSpacingField
, gbConstraints
);
131 gbConstraints
.weightx
= 1;
132 gbConstraints
.gridx
= 8;
133 editorFontPanel
.add(new TailPanel(), gbConstraints
);
135 myFontNameButton
.addActionListener(new ActionListener() {
136 public void actionPerformed(ActionEvent e
) {
137 EditorColorsScheme current
= getCurrentScheme();
138 if (ColorAndFontOptions
.isReadOnly(current
) || ColorSettingsUtil
.isSharedScheme(current
)) {
139 ColorAndFontPanel
.showReadOnlyMessage(FontOptions
.this, ColorSettingsUtil
.isSharedScheme(current
));
147 myEditorFontSizeField
.getDocument().addDocumentListener(new DocumentAdapter() {
148 public void textChanged(DocumentEvent event
) {
149 if (myIsInSchemeChange
) return;
152 fontSize
= Integer
.parseInt(myEditorFontSizeField
.getText());
154 catch (NumberFormatException e
) {
158 if (fontSize
< 1) fontSize
= 1;
159 if (fontSize
> 30) fontSize
= 30;
161 getCurrentScheme().setEditorFontSize(fontSize
);
162 updateDescription(true);
167 myLineSpacingField
.getDocument().addDocumentListener(new DocumentAdapter() {
168 public void textChanged(DocumentEvent event
) {
169 if (myIsInSchemeChange
) return;
170 float lineSpacing
= 1;
172 lineSpacing
= Float
.parseFloat(myLineSpacingField
.getText());
174 catch (NumberFormatException e
) {
178 if (lineSpacing
<= 0) lineSpacing
= 1;
179 if (lineSpacing
> 30) lineSpacing
= 30;
180 if (getCurrentScheme().getLineSpacing() != lineSpacing
) {
181 getCurrentScheme().setLineSpacing(lineSpacing
);
183 updateDescription(true);
188 return editorFontPanel
;
191 private void selectFont() {
194 java
.util
.List
<String
> fontNamesVector
= (java
.util
.List
<String
>)myFontNamesVector
.clone();
195 HashMap fontNameToIsMonospaced
= (HashMap
)myFontNameToIsMonospaced
.clone();
196 String initialFontName
= myFontNameField
.getText();
197 if (!fontNamesVector
.contains(EditorSettingsExternalizable
.DEFAULT_FONT_NAME
)) {
198 fontNamesVector
.add(0, EditorSettingsExternalizable
.DEFAULT_FONT_NAME
);
200 if (!fontNamesVector
.contains(initialFontName
)) {
201 fontNamesVector
.add(0, initialFontName
);
203 SelectFontDialog selectFontDialog
= new SelectFontDialog(this, fontNamesVector
, initialFontName
, fontNameToIsMonospaced
);
204 selectFontDialog
.show();
205 if (!selectFontDialog
.isOK()) {
208 String fontName
= selectFontDialog
.getFontName();
209 if (fontName
!= null) {
210 myFontNameField
.setText(fontName
);
211 getCurrentScheme().setEditorFontName(fontName
);
212 updateDescription(true);
216 @SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"})
217 private void initFontTables() {
218 if (myFontNamesVector
== null) {
219 myFontNamesVector
= new ArrayList
<String
>();
220 myFontNameToIsMonospaced
= new HashMap
<String
, Boolean
>();
222 ProgressManager
.getInstance()
223 .runProcessWithProgressSynchronously(new InitFontsRunnable(), ApplicationBundle
.message("progress.analyzing.fonts"), false, null);
227 public boolean updateDescription(boolean modified
) {
228 EditorColorsScheme scheme
= myOptions
.getSelectedScheme();
230 if (modified
&& (ColorAndFontOptions
.isReadOnly(scheme
) || ColorSettingsUtil
.isSharedScheme(scheme
))) {
231 ColorAndFontPanel
.showReadOnlyMessage(this, ColorSettingsUtil
.isSharedScheme(scheme
));
235 myDispatcher
.getMulticaster().fontChanged();
240 private class InitFontsRunnable
implements Runnable
{
242 ProgressIndicator progress
= ProgressManager
.getInstance().getProgressIndicator();
244 GraphicsEnvironment graphicsEnvironment
= GraphicsEnvironment
.getLocalGraphicsEnvironment();
245 String
[] fontNames
= graphicsEnvironment
.getAvailableFontFamilyNames();
246 for (final String fontName
: fontNames
) {
247 //noinspection HardCodedStringLiteral
248 if (fontName
.endsWith(".bold") || fontName
.endsWith(".italic")) {
252 Font plainFont
= new Font(fontName
, Font
.PLAIN
, 12);
253 if (plainFont
.canDisplay('W')) {
254 Font boldFont
= plainFont
.deriveFont(Font
.BOLD
);
255 if (progress
!= null) {
256 progress
.setText(ApplicationBundle
.message("progress.analysing.font", fontName
));
258 FontMetrics plainMetrics
= getFontMetrics(plainFont
);
259 FontMetrics boldMetrics
= getFontMetrics(boldFont
);
260 myFontNamesVector
.add(fontName
);
261 int plainL
= plainMetrics
.charWidth('l');
262 int boldL
= boldMetrics
.charWidth('l');
263 int plainW
= plainMetrics
.charWidth('W');
264 int boldW
= boldMetrics
.charWidth('W');
265 int plainSpace
= plainMetrics
.charWidth(' ');
266 int boldSpace
= boldMetrics
.charWidth(' ');
267 boolean isMonospaced
= plainL
== plainW
&& plainL
== boldL
&& plainW
== boldW
&& plainSpace
== boldSpace
;
268 myFontNameToIsMonospaced
.put(fontName
, isMonospaced
);
271 catch (Throwable e
) {
272 // JRE has problems working with the font. Just skip.
278 private static class MyTextField
extends JTextField
{
279 public MyTextField(int size
) {
283 public Dimension
getMinimumSize() {
284 return super.getPreferredSize();
288 public void addListener(ColorAndFontSettingsListener listener
) {
289 myDispatcher
.addListener(listener
);
292 public JPanel
getPanel() {
296 public Set
<String
> processListOptions() {
297 return new HashSet
<String
>();