update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / application / options / OptionTreeWithPreviewPanel.java
blobc09e615a44ff98d9526aeb694a676936506ffb2f
1 /*
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;
37 import javax.swing.*;
38 import javax.swing.tree.*;
39 import java.awt.*;
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;
48 /**
49 * @author max
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) {
59 super(settings);
61 initTables();
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);
132 e.consume();
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);
145 int row = 0;
146 while (row < optionsTree.getRowCount()) {
147 optionsTree.expandRow(row);
148 row++;
151 return optionsTree;
154 private void selectCheckbox(TreePath treePath) {
155 if (treePath == null) {
156 return;
158 Object o = treePath.getLastPathComponent();
159 if (o instanceof MyToggleTreeNode) {
160 MyToggleTreeNode node = (MyToggleTreeNode)o;
161 if (node.isCheckbox()) {
162 node.setSelected(!node.isSelected());
164 else {
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));
176 //updatePreview();
177 somethingChanged();
181 protected EditorHighlighter createHighlighter(final EditorColorsScheme scheme) {
182 return JavaHighlighterFactory.createJavaHighlighter(scheme, LanguageLevel.HIGHEST);
185 protected abstract void initTables();
187 protected int getRightMargin() {
188 return -1;
191 @NonNls
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);
203 return;
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) {
212 try {
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) {
230 LOG.error(e);
232 catch (IllegalAccessException e) {
233 LOG.error(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);
246 return;
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) {
255 try {
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]));
268 break;
273 catch (IllegalArgumentException e) {
274 LOG.error(e);
276 catch (IllegalAccessException e) {
277 LOG.error(e);
281 public boolean isModified(CodeStyleSettings settings) {
282 TreeModel treeModel = myOptionsTree.getModel();
283 TreeNode root = (TreeNode)treeModel.getRoot();
284 if (isModified(root, settings)) {
285 return true;
287 return false;
291 private boolean isModified(TreeNode node, final CodeStyleSettings settings) {
292 if (node instanceof MyToggleTreeNode) {
293 if (isToggleNodeModified((MyToggleTreeNode)node, settings)) {
294 return true;
297 for (int j = 0; j < node.getChildCount(); j++) {
298 TreeNode child = node.getChildAt(j);
299 if (isModified(child, settings)) {
300 return true;
303 return false;
306 private boolean isToggleNodeModified(MyToggleTreeNode childNode, final CodeStyleSettings settings) {
307 try {
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) {
325 LOG.error(e);
327 catch (IllegalAccessException e) {
328 LOG.error(e);
330 return false;
333 protected void initBooleanField(@NonNls String fieldName, String cbName, String groupName) {
334 try {
335 Class styleSettingsClass = CodeStyleSettings.class;
336 Field field = styleSettingsClass.getField(fieldName);
337 BooleanOptionKey key = new BooleanOptionKey(groupName, cbName);
338 myKeyToFieldMap.put(key, field);
339 myKeys.add(key);
341 catch (NoSuchFieldException e) {
343 catch (SecurityException e) {
347 protected void initRadioGroupField(String fieldName, String groupName, String[] rbNames, int[] values) {
348 try {
349 Class styleSettingsClass = CodeStyleSettings.class;
350 Field field = styleSettingsClass.getField(fieldName);
351 IntSelectionOptionKey key = new IntSelectionOptionKey(groupName, rbNames, values);
352 myKeyToFieldMap.put(key, field);
353 myKeys.add(key);
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);
385 if (isSelected) {
386 button.setForeground(UIUtil.getTreeSelectionForeground());
387 button.setBackground(UIUtil.getTreeSelectionBackground());
389 else {
390 button.setForeground(UIUtil.getTreeTextForeground());
391 button.setBackground(UIUtil.getTreeTextBackground());
394 button.setEnabled(tree.isEnabled());
396 return button;
398 else {
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());
404 if (isSelected) {
405 myLabel.setForeground(UIUtil.getTreeSelectionForeground());
406 myLabel.setBackground(UIUtil.getTreeSelectionBackground());
408 else {
409 myLabel.setForeground(UIUtil.getTreeTextForeground());
410 myLabel.setBackground(UIUtil.getTreeTextBackground());
413 myLabel.setEnabled(tree.isEnabled());
415 return myLabel;
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) {
428 myText = text;
429 if (myText == null) {
430 myText = "";
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);
441 if (hasFocus) {
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;
467 final String cbName;
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;
488 final int[] values;
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;
506 return true;
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) {
525 myKey = key;
526 myText = text;
527 isCheckbox = true;
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();
545 @NotNull
546 protected FileType getFileType() {
547 return StdFileTypes.JAVA;
550 public JComponent getInternalPanel() {
551 return myPanel;