2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.application
.options
;
18 import com
.intellij
.ide
.highlighter
.JavaHighlighterFactory
;
19 import com
.intellij
.openapi
.application
.ApplicationBundle
;
20 import com
.intellij
.openapi
.diagnostic
.Logger
;
21 import com
.intellij
.openapi
.editor
.colors
.EditorColorsScheme
;
22 import com
.intellij
.openapi
.editor
.highlighter
.EditorHighlighter
;
23 import com
.intellij
.openapi
.fileTypes
.FileType
;
24 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
25 import com
.intellij
.pom
.java
.LanguageLevel
;
26 import com
.intellij
.psi
.codeStyle
.CodeStyleSettings
;
27 import com
.intellij
.psi
.PsiFile
;
28 import com
.intellij
.psi
.util
.PsiUtil
;
29 import com
.intellij
.ui
.IdeBorderFactory
;
30 import com
.intellij
.ui
.treeStructure
.Tree
;
31 import com
.intellij
.util
.containers
.HashMap
;
32 import com
.intellij
.util
.ui
.UIUtil
;
33 import com
.intellij
.util
.ui
.tree
.TreeUtil
;
34 import org
.jetbrains
.annotations
.NonNls
;
35 import org
.jetbrains
.annotations
.NotNull
;
38 import javax
.swing
.tree
.*;
40 import java
.awt
.event
.KeyAdapter
;
41 import java
.awt
.event
.KeyEvent
;
42 import java
.awt
.event
.MouseAdapter
;
43 import java
.awt
.event
.MouseEvent
;
44 import java
.lang
.reflect
.Field
;
45 import java
.util
.ArrayList
;
46 import java
.util
.Arrays
;
51 public abstract class OptionTreeWithPreviewPanel
extends CodeStyleAbstractPanel
{
52 private static final Logger LOG
= Logger
.getInstance("#com.intellij.application.options.CodeStyleSpacesPanel");
53 private final JTree myOptionsTree
;
54 private final HashMap myKeyToFieldMap
= new HashMap();
55 private final ArrayList myKeys
= new ArrayList();
56 private final JPanel myPanel
= new JPanel(new GridBagLayout());
58 public OptionTreeWithPreviewPanel(CodeStyleSettings settings
) {
63 myOptionsTree
= createOptionsTree();
64 myOptionsTree
.setCellRenderer(new MyTreeCellRenderer());
65 myPanel
.add(new JScrollPane(myOptionsTree
),
66 new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints
.WEST
, GridBagConstraints
.BOTH
,
67 new Insets(7, 7, 3, 4), 0, 0));
69 JPanel previewPanel
= new JPanel(new BorderLayout()) {
70 public Dimension
getPreferredSize() {
71 return new Dimension(200, 0);
74 previewPanel
.setBorder(IdeBorderFactory
.createTitledBorder(ApplicationBundle
.message("title.preview")));
76 myPanel
.add(previewPanel
,
77 new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints
.WEST
, GridBagConstraints
.BOTH
,
78 new Insets(0, 0, 0, 4), 0, 0));
80 installPreviewPanel(previewPanel
);
81 addPanelToWatch(myPanel
);
85 protected JTree
createOptionsTree() {
86 DefaultMutableTreeNode rootNode
= new DefaultMutableTreeNode();
87 String groupName
= "";
88 DefaultMutableTreeNode groupNode
= null;
89 for (int i
= 0; i
< myKeys
.size(); i
++) {
90 if (myKeys
.get(i
) instanceof BooleanOptionKey
) {
91 BooleanOptionKey key
= (BooleanOptionKey
)myKeys
.get(i
);
92 String newGroupName
= key
.groupName
;
93 if (!newGroupName
.equals(groupName
) || groupNode
== null) {
94 groupName
= newGroupName
;
95 groupNode
= new DefaultMutableTreeNode(newGroupName
);
96 rootNode
.add(groupNode
);
98 groupNode
.add(new MyToggleTreeNode(key
, key
.cbName
));
100 else if (myKeys
.get(i
) instanceof IntSelectionOptionKey
) {
101 IntSelectionOptionKey key
= (IntSelectionOptionKey
)myKeys
.get(i
);
102 String newGroupName
= key
.groupName
;
103 if (!newGroupName
.equals(groupName
) || groupNode
== null) {
104 groupName
= newGroupName
;
105 groupNode
= new DefaultMutableTreeNode(newGroupName
);
106 rootNode
.add(groupNode
);
108 MyToggleTreeNode
[] nodes
= new MyToggleTreeNode
[key
.rbNames
.length
];
109 for (int j
= 0; j
< nodes
.length
; j
++) {
110 nodes
[j
] = new MyToggleTreeNode(key
, key
.rbNames
[j
]);
111 groupNode
.add(nodes
[j
]);
113 key
.setCreatedNodes(nodes
);
117 DefaultTreeModel model
= new DefaultTreeModel(rootNode
);
119 final Tree optionsTree
= new Tree(model
);
120 TreeUtil
.installActions(optionsTree
);
121 optionsTree
.setRootVisible(false);
122 UIUtil
.setLineStyleAngled(optionsTree
);
123 optionsTree
.setShowsRootHandles(true);
126 optionsTree
.addKeyListener(new KeyAdapter() {
127 public void keyPressed(KeyEvent e
) {
128 if (!optionsTree
.isEnabled()) return;
129 if (e
.getKeyCode() == KeyEvent
.VK_SPACE
) {
130 TreePath treePath
= optionsTree
.getLeadSelectionPath();
131 selectCheckbox(treePath
);
137 optionsTree
.addMouseListener(new MouseAdapter() {
138 public void mouseClicked(MouseEvent e
) {
139 if (!optionsTree
.isEnabled()) return;
140 TreePath treePath
= optionsTree
.getPathForLocation(e
.getX(), e
.getY());
141 selectCheckbox(treePath
);
146 while (row
< optionsTree
.getRowCount()) {
147 optionsTree
.expandRow(row
);
154 private void selectCheckbox(TreePath treePath
) {
155 if (treePath
== null) {
158 Object o
= treePath
.getLastPathComponent();
159 if (o
instanceof MyToggleTreeNode
) {
160 MyToggleTreeNode node
= (MyToggleTreeNode
)o
;
161 if (node
.isCheckbox()) {
162 node
.setSelected(!node
.isSelected());
165 MyToggleTreeNode
[] group
= node
.getGroup();
166 for (int i
= 0; i
< group
.length
; i
++) {
167 MyToggleTreeNode groupNode
= group
[i
];
168 groupNode
.setSelected(false);
169 int row
= myOptionsTree
.getRowForPath(new TreePath(groupNode
.getPath()));
170 myOptionsTree
.repaint(myOptionsTree
.getRowBounds(row
));
172 node
.setSelected(true);
174 int row
= myOptionsTree
.getRowForPath(treePath
);
175 myOptionsTree
.repaint(myOptionsTree
.getRowBounds(row
));
181 protected EditorHighlighter
createHighlighter(final EditorColorsScheme scheme
) {
182 return JavaHighlighterFactory
.createJavaHighlighter(scheme
, LanguageLevel
.HIGHEST
);
185 protected abstract void initTables();
187 protected int getRightMargin() {
192 protected abstract String
getPreviewText();
194 protected void resetImpl(final CodeStyleSettings settings
) {
195 TreeModel treeModel
= myOptionsTree
.getModel();
196 TreeNode root
= (TreeNode
)treeModel
.getRoot();
197 resetNode(root
, settings
);
200 private void resetNode(TreeNode node
, final CodeStyleSettings settings
) {
201 if (node
instanceof MyToggleTreeNode
) {
202 resetMyTreeNode((MyToggleTreeNode
)node
, settings
);
205 for (int j
= 0; j
< node
.getChildCount(); j
++) {
206 TreeNode child
= node
.getChildAt(j
);
207 resetNode(child
, settings
);
211 private void resetMyTreeNode(MyToggleTreeNode childNode
, final CodeStyleSettings settings
) {
213 if (childNode
.getKey() instanceof BooleanOptionKey
) {
214 BooleanOptionKey key
= (BooleanOptionKey
)childNode
.getKey();
215 Field field
= (Field
)myKeyToFieldMap
.get(key
);
216 childNode
.setSelected(field
.getBoolean(settings
));
218 else if (childNode
.getKey() instanceof IntSelectionOptionKey
) {
219 IntSelectionOptionKey key
= (IntSelectionOptionKey
)childNode
.getKey();
220 Field field
= (Field
)myKeyToFieldMap
.get(key
);
221 int fieldValue
= field
.getInt(settings
);
222 for (int i
= 0; i
< key
.rbNames
.length
; i
++) {
223 if (childNode
.getText().equals(key
.rbNames
[i
])) {
224 childNode
.setSelected(fieldValue
== key
.values
[i
]);
229 catch (IllegalArgumentException e
) {
232 catch (IllegalAccessException e
) {
237 public void apply(CodeStyleSettings settings
) {
238 TreeModel treeModel
= myOptionsTree
.getModel();
239 TreeNode root
= (TreeNode
)treeModel
.getRoot();
240 applyNode(root
, settings
);
243 private void applyNode(TreeNode node
, final CodeStyleSettings settings
) {
244 if (node
instanceof MyToggleTreeNode
) {
245 applyToggleNode((MyToggleTreeNode
)node
, settings
);
248 for (int j
= 0; j
< node
.getChildCount(); j
++) {
249 TreeNode child
= node
.getChildAt(j
);
250 applyNode(child
, settings
);
254 private void applyToggleNode(MyToggleTreeNode childNode
, final CodeStyleSettings settings
) {
256 if (childNode
.getKey() instanceof BooleanOptionKey
) {
257 BooleanOptionKey key
= (BooleanOptionKey
)childNode
.getKey();
258 Field field
= (Field
)myKeyToFieldMap
.get(key
);
259 field
.set(settings
, childNode
.isSelected() ? Boolean
.TRUE
: Boolean
.FALSE
);
261 else if (childNode
.getKey() instanceof IntSelectionOptionKey
) {
262 if (!childNode
.isSelected()) return;
263 IntSelectionOptionKey key
= (IntSelectionOptionKey
)childNode
.getKey();
264 Field field
= (Field
)myKeyToFieldMap
.get(key
);
265 for (int i
= 0; i
< key
.rbNames
.length
; i
++) {
266 if (childNode
.getText().equals(key
.rbNames
[i
])) {
267 field
.set(settings
, new Integer(key
.values
[i
]));
273 catch (IllegalArgumentException e
) {
276 catch (IllegalAccessException e
) {
281 public boolean isModified(CodeStyleSettings settings
) {
282 TreeModel treeModel
= myOptionsTree
.getModel();
283 TreeNode root
= (TreeNode
)treeModel
.getRoot();
284 if (isModified(root
, settings
)) {
291 private boolean isModified(TreeNode node
, final CodeStyleSettings settings
) {
292 if (node
instanceof MyToggleTreeNode
) {
293 if (isToggleNodeModified((MyToggleTreeNode
)node
, settings
)) {
297 for (int j
= 0; j
< node
.getChildCount(); j
++) {
298 TreeNode child
= node
.getChildAt(j
);
299 if (isModified(child
, settings
)) {
306 private boolean isToggleNodeModified(MyToggleTreeNode childNode
, final CodeStyleSettings settings
) {
308 if (childNode
.getKey() instanceof BooleanOptionKey
) {
309 BooleanOptionKey key
= (BooleanOptionKey
)childNode
.getKey();
310 Field field
= (Field
)myKeyToFieldMap
.get(key
);
311 return childNode
.isSelected() != field
.getBoolean(settings
);
313 else if (childNode
.getKey() instanceof IntSelectionOptionKey
) {
314 if (!childNode
.isSelected()) return false;
315 IntSelectionOptionKey key
= (IntSelectionOptionKey
)childNode
.getKey();
316 Field field
= (Field
)myKeyToFieldMap
.get(key
);
317 for (int i
= 0; i
< key
.rbNames
.length
; i
++) {
318 if (childNode
.getText().equals(key
.rbNames
[i
])) {
319 return field
.getInt(settings
) != key
.values
[i
];
324 catch (IllegalArgumentException e
) {
327 catch (IllegalAccessException e
) {
333 protected void initBooleanField(@NonNls String fieldName
, String cbName
, String groupName
) {
335 Class styleSettingsClass
= CodeStyleSettings
.class;
336 Field field
= styleSettingsClass
.getField(fieldName
);
337 BooleanOptionKey key
= new BooleanOptionKey(groupName
, cbName
);
338 myKeyToFieldMap
.put(key
, field
);
341 catch (NoSuchFieldException e
) {
343 catch (SecurityException e
) {
347 protected void initRadioGroupField(String fieldName
, String groupName
, String
[] rbNames
, int[] values
) {
349 Class styleSettingsClass
= CodeStyleSettings
.class;
350 Field field
= styleSettingsClass
.getField(fieldName
);
351 IntSelectionOptionKey key
= new IntSelectionOptionKey(groupName
, rbNames
, values
);
352 myKeyToFieldMap
.put(key
, field
);
355 catch (NoSuchFieldException e
) {
357 catch (SecurityException e
) {
361 protected void prepareForReformat(final PsiFile psiFile
) {
362 psiFile
.putUserData(PsiUtil
.FILE_LANGUAGE_LEVEL_KEY
, LanguageLevel
.HIGHEST
);
365 protected class MyTreeCellRenderer
implements TreeCellRenderer
{
366 private final MyLabelPanel myLabel
;
367 private final JCheckBox myCheckBox
;
368 private final JRadioButton myRadioButton
;
370 public MyTreeCellRenderer() {
371 myLabel
= new MyLabelPanel();
372 myCheckBox
= new JCheckBox();
373 myRadioButton
= new JRadioButton();
374 myCheckBox
.setMargin(new Insets(0, 0, 0, 0));
377 public Component
getTreeCellRendererComponent(JTree tree
, Object value
, boolean isSelected
, boolean expanded
,
378 boolean leaf
, int row
, boolean hasFocus
) {
380 if (value
instanceof MyToggleTreeNode
) {
381 MyToggleTreeNode treeNode
= (MyToggleTreeNode
)value
;
382 JToggleButton button
= treeNode
.isCheckbox() ?
(JToggleButton
)myCheckBox
: (JToggleButton
)myRadioButton
;
383 button
.setText(treeNode
.getText());
384 button
.setSelected(treeNode
.isSelected
);
386 button
.setForeground(UIUtil
.getTreeSelectionForeground());
387 button
.setBackground(UIUtil
.getTreeSelectionBackground());
390 button
.setForeground(UIUtil
.getTreeTextForeground());
391 button
.setBackground(UIUtil
.getTreeTextBackground());
394 button
.setEnabled(tree
.isEnabled());
399 Font font
= tree
.getFont();
400 Font boldFont
= new Font(font
.getName(), Font
.BOLD
, font
.getSize());
401 myLabel
.setFont(boldFont
);
402 myLabel
.setText(value
.toString());
405 myLabel
.setForeground(UIUtil
.getTreeSelectionForeground());
406 myLabel
.setBackground(UIUtil
.getTreeSelectionBackground());
409 myLabel
.setForeground(UIUtil
.getTreeTextForeground());
410 myLabel
.setBackground(UIUtil
.getTreeTextBackground());
413 myLabel
.setEnabled(tree
.isEnabled());
420 private static class MyLabelPanel
extends JPanel
{
421 private String myText
= "";
422 private final boolean hasFocus
= false;
424 public MyLabelPanel() {
427 public void setText(String text
) {
429 if (myText
== null) {
434 protected void paintComponent(Graphics g
) {
435 g
.setFont(getMyFont());
436 FontMetrics fontMetrics
= getFontMetrics(getMyFont());
437 int h
= fontMetrics
.getHeight();
438 int w
= fontMetrics
.charsWidth(myText
.toCharArray(), 0, myText
.length());
439 g
.setColor(getBackground());
440 g
.fillRect(0, 1, w
+ 2, h
);
442 g
.setColor(UIUtil
.getTreeTextBackground());
443 g
.drawRect(0, 1, w
+ 2, h
);
445 g
.setColor(getForeground());
446 g
.drawString(myText
, 2, h
- fontMetrics
.getDescent() + 1);
449 private Font
getMyFont() {
450 Font font
= UIUtil
.getTreeFont();
451 return new Font(font
.getName(), Font
.BOLD
, font
.getSize());
454 public Dimension
getPreferredSize() {
455 FontMetrics fontMetrics
= getFontMetrics(getMyFont());
456 if (fontMetrics
== null) {
457 return new Dimension(0, 0);
459 int h
= fontMetrics
.getHeight();
460 int w
= fontMetrics
.charsWidth(myText
.toCharArray(), 0, myText
.length());
461 return new Dimension(w
+ 4, h
+ 2);
465 private static class BooleanOptionKey
{
466 final String groupName
;
469 public BooleanOptionKey(String groupName
, String cbName
) {
470 this.groupName
= groupName
;
471 this.cbName
= cbName
;
474 public boolean equals(Object obj
) {
475 if (!(obj
instanceof BooleanOptionKey
)) return false;
476 BooleanOptionKey key
= (BooleanOptionKey
)obj
;
477 return groupName
.equals(key
.groupName
) && cbName
.equals(key
.cbName
);
480 public int hashCode() {
481 return cbName
.hashCode();
485 private static class IntSelectionOptionKey
{
486 final String groupName
;
487 final String
[] rbNames
;
489 private MyToggleTreeNode
[] myNodes
;
491 public IntSelectionOptionKey(String groupName
, String
[] rbNames
, int[] values
) {
492 this.groupName
= groupName
;
493 this.rbNames
= rbNames
;
494 this.values
= values
;
497 public boolean equals(Object o
) {
498 if (this == o
) return true;
499 if (!(o
instanceof IntSelectionOptionKey
)) return false;
501 final IntSelectionOptionKey intSelectionOptionKey
= (IntSelectionOptionKey
)o
;
503 if (!groupName
.equals(intSelectionOptionKey
.groupName
)) return false;
504 if (!Arrays
.equals(rbNames
, intSelectionOptionKey
.rbNames
)) return false;
509 public int hashCode() {
510 return groupName
.hashCode() + rbNames
[0].hashCode() * 29;
513 public void setCreatedNodes(MyToggleTreeNode
[] nodes
) { myNodes
= nodes
; }
515 public MyToggleTreeNode
[] getNodes() { return myNodes
; }
518 private static class MyToggleTreeNode
extends DefaultMutableTreeNode
{
519 private final Object myKey
;
520 private final String myText
;
521 private boolean isSelected
;
522 private final boolean isCheckbox
;
524 public MyToggleTreeNode(Object key
, String text
) {
530 public Object
getKey() { return myKey
; }
532 public String
getText() { return myText
; }
534 public boolean isCheckbox() { return isCheckbox
; }
536 public void setSelected(boolean val
) { isSelected
= val
; }
538 public boolean isSelected() { return isSelected
; }
540 public MyToggleTreeNode
[] getGroup() {
541 return ((IntSelectionOptionKey
)myKey
).getNodes();
546 protected FileType
getFileType() {
547 return StdFileTypes
.JAVA
;
550 public JComponent
getInternalPanel() {