| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.application.options.codeStyle; |
| |
| import com.intellij.lang.Language; |
| import com.intellij.openapi.application.ApplicationBundle; |
| import com.intellij.psi.codeStyle.CodeStyleSettings; |
| import com.intellij.psi.codeStyle.CommonCodeStyleSettings; |
| import com.intellij.psi.codeStyle.CustomCodeStyleSettings; |
| import com.intellij.ui.SpeedSearchComparator; |
| import com.intellij.ui.TreeTableSpeedSearch; |
| import com.intellij.ui.components.JBScrollPane; |
| import com.intellij.ui.components.editors.JBComboBoxTableCellEditorComponent; |
| import com.intellij.ui.treeStructure.treetable.ListTreeTableModel; |
| import com.intellij.ui.treeStructure.treetable.TreeTable; |
| import com.intellij.ui.treeStructure.treetable.TreeTableCellRenderer; |
| import com.intellij.ui.treeStructure.treetable.TreeTableModel; |
| import com.intellij.util.containers.ContainerUtil; |
| import com.intellij.util.ui.AbstractTableCellEditor; |
| import com.intellij.util.ui.ColumnInfo; |
| import com.intellij.util.ui.UIUtil; |
| import gnu.trove.THashMap; |
| import gnu.trove.THashSet; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.table.TableCellEditor; |
| import javax.swing.table.TableCellRenderer; |
| import javax.swing.table.TableColumn; |
| import javax.swing.tree.*; |
| import java.awt.*; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.lang.reflect.Field; |
| import java.util.*; |
| import java.util.List; |
| |
| /** |
| * @author max |
| */ |
| public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyleAbstractPanel { |
| private TreeTable myTreeTable; |
| private final JPanel myPanel = new JPanel(); |
| |
| private final List<Option> myOptions = new ArrayList<Option>(); |
| private final List<Option> myCustomOptions = new ArrayList<Option>(); |
| private final Set<String> myAllowedOptions = new THashSet<String>(); |
| private final Map<String, String> myRenamedFields = new THashMap<String, String>(); |
| private boolean myShowAllStandardOptions; |
| private boolean isFirstUpdate = true; |
| |
| |
| public OptionTableWithPreviewPanel(CodeStyleSettings settings) { |
| super(settings); |
| } |
| |
| @Override |
| protected void init() { |
| super.init(); |
| |
| myPanel.setLayout(new GridBagLayout()); |
| initTables(); |
| |
| myTreeTable = createOptionsTree(getSettings()); |
| JBScrollPane scrollPane = new JBScrollPane(myTreeTable) { |
| @Override |
| public Dimension getMinimumSize() { |
| return super.getPreferredSize(); |
| } |
| }; |
| myPanel.add(scrollPane |
| , new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, |
| new Insets(0, 0, 0, 8), 0, 0)); |
| |
| final JPanel previewPanel = createPreviewPanel(); |
| myPanel.add(previewPanel, |
| new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, |
| new Insets(0, 0, 0, 0), 0, 0)); |
| |
| installPreviewPanel(previewPanel); |
| addPanelToWatch(myPanel); |
| |
| isFirstUpdate = false; |
| } |
| |
| @Override |
| protected void onLanguageChange(Language language) { |
| if (myTreeTable.isEditing()) { |
| myTreeTable.getCellEditor().stopCellEditing(); |
| } |
| resetImpl(getSettings()); |
| myTreeTable.repaint(); |
| } |
| |
| @Override |
| protected void resetDefaultNames() { |
| myRenamedFields.clear(); |
| } |
| |
| @Override |
| public void showAllStandardOptions() { |
| myShowAllStandardOptions = true; |
| for (Option each : myOptions) { |
| each.setEnabled(true); |
| } |
| for (Option each : myCustomOptions) { |
| each.setEnabled(false); |
| } |
| } |
| |
| @Override |
| public void showStandardOptions(String... optionNames) { |
| Collections.addAll(myAllowedOptions, optionNames); |
| for (Option each : myOptions) { |
| each.setEnabled(false); |
| for (String optionName : optionNames) { |
| if (each.field.getName().equals(optionName)) { |
| each.setEnabled(true); |
| } |
| } |
| } |
| for (Option each : myCustomOptions) { |
| each.setEnabled(false); |
| } |
| } |
| |
| @Override |
| public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass, |
| String fieldName, |
| String title, |
| String groupName, Object... options) { |
| showCustomOption(settingsClass, fieldName, title, groupName, null, null, options); |
| } |
| |
| |
| @Override |
| public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass, |
| String fieldName, |
| String title, |
| String groupName, |
| @Nullable OptionAnchor anchor, |
| @Nullable String anchorFieldName, |
| Object... options) { |
| if (isFirstUpdate) { |
| Option option; |
| if (options.length == 2) { |
| option = |
| new SelectionOption(settingsClass, fieldName, title, groupName, anchor, anchorFieldName, (String[])options[0], (int[])options[1]); |
| } |
| else { |
| option = new BooleanOption(settingsClass, fieldName, title, groupName, anchor, anchorFieldName); |
| } |
| myCustomOptions.add(option); |
| option.setEnabled(true); |
| } |
| else { |
| for (Option each : myCustomOptions) { |
| if (each.clazz == settingsClass && each.field.getName().equals(fieldName)) { |
| each.setEnabled(true); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void renameStandardOption(String fieldName, String newTitle) { |
| myRenamedFields.put(fieldName, newTitle); |
| } |
| |
| protected TreeTable createOptionsTree(CodeStyleSettings settings) { |
| DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(); |
| Map<String, DefaultMutableTreeNode> groupsMap = new THashMap<String, DefaultMutableTreeNode>(); |
| |
| List<Option> sorted = sortOptions(ContainerUtil.concat(myOptions, myCustomOptions)); |
| for (Option each : sorted) { |
| if (!(myCustomOptions.contains(each) || myAllowedOptions.contains(each.field.getName()) || myShowAllStandardOptions)) continue; |
| |
| String group = each.groupName; |
| MyTreeNode newNode = new MyTreeNode(each, each.title, settings); |
| |
| DefaultMutableTreeNode groupNode = groupsMap.get(group); |
| if (groupNode != null) { |
| groupNode.add(newNode); |
| } |
| else { |
| String groupName; |
| |
| if (group == null) { |
| groupName = each.title; |
| groupNode = newNode; |
| } |
| else { |
| groupName = group; |
| groupNode = new DefaultMutableTreeNode(groupName); |
| groupNode.add(newNode); |
| } |
| groupsMap.put(groupName, groupNode); |
| rootNode.add(groupNode); |
| } |
| } |
| |
| ListTreeTableModel model = new ListTreeTableModel(rootNode, COLUMNS); |
| TreeTable treeTable = new TreeTable(model) { |
| @Override |
| public TreeTableCellRenderer createTableRenderer(TreeTableModel treeTableModel) { |
| TreeTableCellRenderer tableRenderer = super.createTableRenderer(treeTableModel); |
| UIUtil.setLineStyleAngled(tableRenderer); |
| tableRenderer.setRootVisible(false); |
| tableRenderer.setShowsRootHandles(true); |
| |
| return tableRenderer; |
| } |
| |
| @Override |
| public TableCellRenderer getCellRenderer(int row, int column) { |
| TreePath treePath = getTree().getPathForRow(row); |
| if (treePath == null) return super.getCellRenderer(row, column); |
| |
| Object node = treePath.getLastPathComponent(); |
| |
| TableCellRenderer renderer = COLUMNS[column].getRenderer(node); |
| return renderer == null ? super.getCellRenderer(row, column) : renderer; |
| } |
| |
| @Override |
| public TableCellEditor getCellEditor(int row, int column) { |
| TreePath treePath = getTree().getPathForRow(row); |
| if (treePath == null) return super.getCellEditor(row, column); |
| |
| Object node = treePath.getLastPathComponent(); |
| TableCellEditor editor = COLUMNS[column].getEditor(node); |
| return editor == null ? super.getCellEditor(row, column) : editor; |
| } |
| }; |
| new TreeTableSpeedSearch(treeTable).setComparator(new SpeedSearchComparator(false)); |
| |
| treeTable.setRootVisible(false); |
| |
| final JTree tree = treeTable.getTree(); |
| tree.setCellRenderer(myTitleRenderer); |
| tree.setShowsRootHandles(true); |
| //myTreeTable.setRowHeight(new JComboBox(new String[]{"Sample Text"}).getPreferredSize().height); |
| treeTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); |
| treeTable.setTableHeader(null); |
| |
| expandTree(tree); |
| |
| int maxWidth = tree.getPreferredScrollableViewportSize().width + 10; |
| final TableColumn titleColumn = treeTable.getColumnModel().getColumn(0); |
| titleColumn.setPreferredWidth(maxWidth); |
| titleColumn.setMinWidth(maxWidth); |
| titleColumn.setMaxWidth(maxWidth); |
| titleColumn.setResizable(false); |
| |
| final TableColumn levelColumn = treeTable.getColumnModel().getColumn(1); |
| //TODO[max]: better preffered size... |
| //TODO[kb]: Did I fixed it by making the last column floating? |
| //levelColumn.setPreferredWidth(valueSize.width); |
| //levelColumn.setMaxWidth(valueSize.width); |
| //levelColumn.setMinWidth(valueSize.width); |
| //levelColumn.setResizable(false); |
| |
| final Dimension valueSize = new JLabel(ApplicationBundle.message("option.table.sizing.text")).getPreferredSize(); |
| treeTable.setPreferredScrollableViewportSize(new Dimension(maxWidth + valueSize.width + 10, 20)); |
| |
| return treeTable; |
| } |
| |
| private String getRenamedTitle(String fieldOrGroupName, String defaultName) { |
| String result = myRenamedFields.get(fieldOrGroupName); |
| return result == null ? defaultName : result; |
| } |
| |
| private void expandTree(final JTree tree) { |
| int oldRowCount = 0; |
| do { |
| int rowCount = tree.getRowCount(); |
| if (rowCount == oldRowCount) break; |
| oldRowCount = rowCount; |
| for (int i = 0; i < rowCount; i++) { |
| tree.expandRow(i); |
| } |
| } |
| while (true); |
| } |
| |
| protected abstract void initTables(); |
| |
| private void resetNode(TreeNode node, CodeStyleSettings settings) { |
| if (node instanceof MyTreeNode) { |
| ((MyTreeNode)node).reset(settings); |
| } |
| for (int j = 0; j < node.getChildCount(); j++) { |
| TreeNode child = node.getChildAt(j); |
| resetNode(child, settings); |
| } |
| } |
| |
| private void applyNode(TreeNode node, final CodeStyleSettings settings) { |
| if (node instanceof MyTreeNode) { |
| ((MyTreeNode)node).apply(settings); |
| } |
| for (int j = 0; j < node.getChildCount(); j++) { |
| TreeNode child = node.getChildAt(j); |
| applyNode(child, settings); |
| } |
| } |
| |
| private boolean isModified(TreeNode node, final CodeStyleSettings settings) { |
| if (node instanceof MyTreeNode) { |
| if (((MyTreeNode)node).isModified(settings)) return true; |
| } |
| for (int j = 0; j < node.getChildCount(); j++) { |
| TreeNode child = node.getChildAt(j); |
| if (isModified(child, settings)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| protected void addOption(@NotNull String fieldName, @NotNull String title) { |
| addOption(fieldName, title, null); |
| } |
| |
| protected void addOption(@NotNull String fieldName, @NotNull String title, @NotNull String[] options, @NotNull int[] values) { |
| addOption(fieldName, title, null, options, values); |
| } |
| |
| protected void addOption(@NotNull String fieldName, |
| @NotNull String title, |
| @Nullable String groupName, |
| int minValue, |
| int maxValue, |
| int defaultValue, |
| String defaultValueText) { |
| myOptions.add(new IntOption(null, fieldName, title, groupName, null, null, minValue, maxValue, defaultValue, defaultValueText)); |
| } |
| |
| protected void addOption(@NotNull String fieldName, @NotNull String title, @Nullable String groupName) { |
| myOptions.add(new BooleanOption(null, fieldName, title, groupName, null, null)); |
| } |
| |
| protected void addOption(@NotNull String fieldName, @NotNull String title, @Nullable String groupName, |
| @NotNull String[] options, @NotNull int[] values) { |
| myOptions.add(new SelectionOption(null, fieldName, title, groupName, null, null, options, values)); |
| } |
| |
| private abstract class Option extends OrderedOption { |
| @Nullable final Class<? extends CustomCodeStyleSettings> clazz; |
| @NotNull final Field field; |
| @NotNull final String title; |
| @Nullable final String groupName; |
| private boolean myEnabled = false; |
| |
| public Option(Class<? extends CustomCodeStyleSettings> clazz, |
| @NotNull String fieldName, |
| @NotNull String title, |
| @Nullable String groupName, |
| @Nullable OptionAnchor anchor, |
| @Nullable String anchorFiledName) { |
| super(fieldName, anchor, anchorFiledName); |
| this.clazz = clazz; |
| this.title = title; |
| this.groupName = groupName; |
| |
| try { |
| Class styleSettingsClass = clazz == null ? CommonCodeStyleSettings.class : clazz; |
| this.field = styleSettingsClass.getField(fieldName); |
| } |
| catch (NoSuchFieldException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public void setEnabled(boolean enabled) { |
| myEnabled = enabled; |
| } |
| |
| public boolean isEnabled() { |
| return myEnabled; |
| } |
| |
| public abstract Object getValue(CodeStyleSettings settings); |
| |
| public abstract void setValue(Object value, CodeStyleSettings settings); |
| |
| protected Object getSettings(CodeStyleSettings settings) { |
| if (clazz != null) return settings.getCustomSettings(clazz); |
| return settings.getCommonSettings(getSelectedLanguage()); |
| } |
| } |
| |
| private class BooleanOption extends Option { |
| private BooleanOption(Class<? extends CustomCodeStyleSettings> clazz, |
| @NotNull String fieldName, |
| @NotNull String title, |
| @Nullable String groupName, |
| @Nullable OptionAnchor anchor, |
| @Nullable String anchorFiledName) { |
| super(clazz, fieldName, title, groupName, anchor, anchorFiledName); |
| } |
| |
| @Override |
| public Object getValue(CodeStyleSettings settings) { |
| try { |
| return field.getBoolean(getSettings(settings)) ? Boolean.TRUE : Boolean.FALSE; |
| } |
| catch (IllegalAccessException ignore) { |
| return null; |
| } |
| } |
| |
| @Override |
| public void setValue(Object value, CodeStyleSettings settings) { |
| try { |
| field.setBoolean(getSettings(settings), ((Boolean)value).booleanValue()); |
| } |
| catch (IllegalAccessException ignored) { |
| } |
| } |
| } |
| |
| private class SelectionOption extends Option { |
| @NotNull final String[] options; |
| @NotNull final int[] values; |
| |
| public SelectionOption(Class<? extends CustomCodeStyleSettings> clazz, |
| @NotNull String fieldName, |
| @NotNull String title, |
| @Nullable String groupName, |
| @Nullable OptionAnchor anchor, |
| @Nullable String anchorFiledName, |
| @NotNull String[] options, |
| @NotNull int[] values) { |
| super(clazz, fieldName, title, groupName, anchor, anchorFiledName); |
| this.options = options; |
| this.values = values; |
| } |
| |
| @Override |
| public Object getValue(CodeStyleSettings settings) { |
| try { |
| int value = field.getInt(getSettings(settings)); |
| for (int i = 0; i < values.length; i++) { |
| if (values[i] == value) return options[i]; |
| } |
| } |
| catch (IllegalAccessException ignore) { |
| } |
| return null; |
| } |
| |
| @Override |
| public void setValue(Object value, CodeStyleSettings settings) { |
| try { |
| for (int i = 0; i < values.length; i++) { |
| if (options[i].equals(value)) { |
| field.setInt(getSettings(settings), values[i]); |
| return; |
| } |
| } |
| } |
| catch (IllegalAccessException e) { |
| } |
| } |
| } |
| |
| private class IntOption extends Option { |
| |
| private final int myMinValue; |
| private final int myMaxValue; |
| private final int myDefaultValue; |
| @Nullable private String myDefaultValueText; |
| |
| public IntOption(Class<? extends CustomCodeStyleSettings> clazz, |
| @NotNull String fieldName, |
| @NotNull String title, |
| @Nullable String groupName, |
| @Nullable OptionAnchor anchor, |
| @Nullable String anchorFiledName, |
| int minValue, |
| int maxValue, |
| int defaultValue, |
| @Nullable String defaultValueText) { |
| super(clazz, fieldName, title, groupName, anchor, anchorFiledName); |
| myMinValue = minValue; |
| myMaxValue = maxValue; |
| myDefaultValue = defaultValue; |
| myDefaultValueText = defaultValueText; |
| } |
| |
| @Override |
| public Object getValue(CodeStyleSettings settings) { |
| try { |
| int value = field.getInt(getSettings(settings)); |
| return value == myDefaultValue && myDefaultValueText != null ? myDefaultValueText : value; |
| } |
| catch (IllegalAccessException e) { |
| return null; |
| } |
| } |
| |
| @Override |
| public void setValue(Object value, CodeStyleSettings settings) { |
| //noinspection EmptyCatchBlock |
| try { |
| if (myDefaultValueText != null && !myDefaultValueText.equals(value)) { |
| field.setInt(getSettings(settings), ((Integer)value).intValue()); |
| } |
| else { |
| field.setInt(getSettings(settings), -1); |
| } |
| } |
| catch (IllegalAccessException e) { |
| } |
| } |
| |
| public int getMinValue() { |
| return myMinValue; |
| } |
| |
| public int getMaxValue() { |
| return myMaxValue; |
| } |
| |
| public int getDefaultValue() { |
| return myDefaultValue; |
| } |
| |
| public boolean isDefaultText(Object value) { |
| return myDefaultValueText != null && myDefaultValueText.equals(value); |
| } |
| |
| @Nullable |
| public String getDefaultValueText() { |
| return myDefaultValueText; |
| } |
| } |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| public final ColumnInfo TITLE = new ColumnInfo("TITLE") { |
| @Override |
| public Object valueOf(Object o) { |
| if (o instanceof MyTreeNode) { |
| MyTreeNode node = (MyTreeNode)o; |
| return node.getText(); |
| } |
| return o.toString(); |
| } |
| |
| @Override |
| public Class getColumnClass() { |
| return TreeTableModel.class; |
| } |
| }; |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| public final ColumnInfo VALUE = new ColumnInfo("VALUE") { |
| private final TableCellEditor myEditor = new MyValueEditor(); |
| private final TableCellRenderer myRenderer = new MyValueRenderer(); |
| |
| @Override |
| public Object valueOf(Object o) { |
| if (o instanceof MyTreeNode) { |
| MyTreeNode node = (MyTreeNode)o; |
| return node.getValue(); |
| } |
| |
| return null; |
| } |
| |
| @Override |
| public TableCellRenderer getRenderer(Object o) { |
| return myRenderer; |
| } |
| |
| @Override |
| public TableCellEditor getEditor(Object item) { |
| return myEditor; |
| } |
| |
| @Override |
| public boolean isCellEditable(Object o) { |
| return (o instanceof MyTreeNode) && (((MyTreeNode)o).isEnabled()); |
| } |
| |
| @Override |
| public void setValue(Object o, Object o1) { |
| MyTreeNode node = (MyTreeNode)o; |
| node.setValue(o1); |
| } |
| }; |
| |
| public final ColumnInfo[] COLUMNS = new ColumnInfo[]{TITLE, VALUE}; |
| |
| private final TreeCellRenderer myTitleRenderer = new TreeCellRenderer() { |
| private final JLabel myLabel = new JLabel(); |
| |
| @Override |
| public Component getTreeCellRendererComponent(JTree tree, |
| Object value, |
| boolean selected, |
| boolean expanded, |
| boolean leaf, |
| int row, |
| boolean hasFocus) { |
| if (value instanceof MyTreeNode) { |
| MyTreeNode node = (MyTreeNode)value; |
| myLabel.setText(getRenamedTitle(node.getKey().field.getName(), node.getText())); |
| myLabel.setFont(myLabel.getFont().deriveFont(node.getKey().groupName == null ? Font.BOLD : Font.PLAIN)); |
| myLabel.setEnabled(node.isEnabled()); |
| } |
| else { |
| myLabel.setText(getRenamedTitle(value.toString(), value.toString())); |
| myLabel.setFont(myLabel.getFont().deriveFont(Font.BOLD)); |
| myLabel.setEnabled(true); |
| } |
| |
| Color foreground = selected ? UIUtil.getTableSelectionForeground() : UIUtil.getTableForeground(); |
| myLabel.setForeground(foreground); |
| |
| return myLabel; |
| } |
| }; |
| |
| private class MyTreeNode extends DefaultMutableTreeNode { |
| private final Option myKey; |
| private final String myText; |
| private Object myValue; |
| |
| public MyTreeNode(Option key, String text, CodeStyleSettings settings) { |
| myKey = key; |
| myText = text; |
| myValue = key.getValue(settings); |
| setUserObject(myText); |
| } |
| |
| public Option getKey() { |
| return myKey; |
| } |
| |
| public String getText() { |
| return myText; |
| } |
| |
| public Object getValue() { |
| return myValue; |
| } |
| |
| public void setValue(Object value) { |
| myValue = value; |
| } |
| |
| public void reset(CodeStyleSettings settings) { |
| setValue(myKey.getValue(settings)); |
| } |
| |
| public boolean isModified(final CodeStyleSettings settings) { |
| return !myValue.equals(myKey.getValue(settings)); |
| } |
| |
| public void apply(final CodeStyleSettings settings) { |
| myKey.setValue(myValue, settings); |
| } |
| |
| public boolean isEnabled() { |
| return myKey.isEnabled(); |
| } |
| } |
| |
| private class MyValueRenderer implements TableCellRenderer { |
| private final JLabel myComboBox = new JLabel(); |
| private final JCheckBox myCheckBox = new JCheckBox(); |
| private final JPanel myEmptyLabel = new JPanel(); |
| private final JLabel myIntLabel = new JLabel(); |
| |
| @Override |
| public Component getTableCellRendererComponent(JTable table, |
| Object value, |
| boolean isSelected, |
| boolean hasFocus, |
| int row, |
| int column) { |
| boolean isEnabled = true; |
| final DefaultMutableTreeNode node = (DefaultMutableTreeNode)((TreeTable)table).getTree(). |
| getPathForRow(row).getLastPathComponent(); |
| if (node instanceof MyTreeNode) { |
| isEnabled = ((MyTreeNode)node).isEnabled(); |
| } |
| |
| Color background = table.getBackground(); |
| if (value instanceof Boolean) { |
| myCheckBox.setSelected(((Boolean)value).booleanValue()); |
| myCheckBox.setBackground(background); |
| myCheckBox.setEnabled(isEnabled); |
| return myCheckBox; |
| } |
| else if (value instanceof String) { |
| /* |
| myComboBox.removeAllItems(); |
| myComboBox.addItem(value); |
| */ |
| myComboBox.setText((String)value); |
| myComboBox.setBackground(background); |
| myComboBox.setEnabled(isEnabled); |
| return myComboBox; |
| } |
| else if (value instanceof Integer) { |
| myIntLabel.setText(value.toString()); |
| return myIntLabel; |
| } |
| |
| myCheckBox.putClientProperty("JComponent.sizeVariant", "small"); |
| myComboBox.putClientProperty("JComponent.sizeVariant", "small"); |
| |
| myEmptyLabel.setBackground(background); |
| return myEmptyLabel; |
| } |
| } |
| |
| private static class MyIntOptionEditor extends JTextField { |
| private int myMinValue; |
| private int myMaxValue; |
| private int myDefaultValue; |
| private String myDefaultValueText; |
| |
| private MyIntOptionEditor() { |
| super(); |
| } |
| |
| public Object getPresentableValue() { |
| int value = validateAndGetIntOption(); |
| return value == myDefaultValue && myDefaultValueText != null ? myDefaultValueText : value; |
| } |
| |
| private int validateAndGetIntOption() { |
| try { |
| int value = Integer.parseInt(getText()); |
| return value >= myMinValue && value <= myMaxValue ? value : myDefaultValue; |
| } |
| catch (NumberFormatException nfe) { |
| return myDefaultValue; |
| } |
| } |
| |
| public void setMinValue(int minValue) { |
| myMinValue = minValue; |
| } |
| |
| public void setMaxValue(int maxValue) { |
| myMaxValue = maxValue; |
| } |
| |
| public void setDefaultValue(int defaultValue) { |
| myDefaultValue = defaultValue; |
| } |
| |
| public void setDefaultValueText(String defaultValueText) { |
| myDefaultValueText = defaultValueText; |
| } |
| } |
| |
| /** |
| * @author Konstantin Bulenkov |
| */ |
| private class MyValueEditor extends AbstractTableCellEditor { |
| private final JCheckBox myBooleanEditor = new JCheckBox(); |
| private JBComboBoxTableCellEditorComponent myOptionsEditor = new JBComboBoxTableCellEditorComponent(); |
| private MyIntOptionEditor myIntOptionsEditor = new MyIntOptionEditor(); |
| private Component myCurrentEditor = null; |
| private MyTreeNode myCurrentNode = null; |
| |
| public MyValueEditor() { |
| final ActionListener itemChoosen = new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| if (myCurrentNode != null) { |
| myCurrentNode.setValue(getCellEditorValue()); |
| somethingChanged(); |
| } |
| } |
| }; |
| myBooleanEditor.addActionListener(itemChoosen); |
| myOptionsEditor.addActionListener(itemChoosen); |
| myBooleanEditor.putClientProperty("JComponent.sizeVariant", "small"); |
| myOptionsEditor.putClientProperty("JComponent.sizeVariant", "small"); |
| } |
| |
| @Override |
| public Object getCellEditorValue() { |
| if (myCurrentEditor == myOptionsEditor) { |
| //new Alarm(Alarm.ThreadToUse.SWING_THREAD).addRequest(new Runnable() { |
| // @Override |
| // public void run() { |
| // somethingChanged(); |
| // } |
| // }, 100); |
| return myOptionsEditor.getEditorValue(); |
| } |
| else if (myCurrentEditor == myBooleanEditor) { |
| return myBooleanEditor.isSelected() ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if (myCurrentEditor == myIntOptionsEditor) { |
| return myIntOptionsEditor.getPresentableValue(); |
| } |
| |
| return null; |
| } |
| |
| @Override |
| public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { |
| final DefaultMutableTreeNode defaultNode = (DefaultMutableTreeNode)((TreeTable)table).getTree(). |
| getPathForRow(row).getLastPathComponent(); |
| myCurrentEditor = null; |
| myCurrentNode = null; |
| if (defaultNode instanceof MyTreeNode) { |
| MyTreeNode node = (MyTreeNode)defaultNode; |
| myCurrentNode = node; |
| if (node.getKey() instanceof BooleanOption) { |
| myCurrentEditor = myBooleanEditor; |
| myBooleanEditor.setSelected(node.getValue() == Boolean.TRUE); |
| myBooleanEditor.setEnabled(node.isEnabled()); |
| } |
| else if (node.getKey() instanceof IntOption) { |
| IntOption intOption = (IntOption)node.getKey(); |
| myCurrentEditor = myIntOptionsEditor; |
| myIntOptionsEditor.setText(intOption.isDefaultText(node.getValue()) ? "" : node.getValue().toString()); |
| myIntOptionsEditor.setMinValue(intOption.getMinValue()); |
| myIntOptionsEditor.setMaxValue(intOption.getMaxValue()); |
| myIntOptionsEditor.setDefaultValue(intOption.getDefaultValue()); |
| myIntOptionsEditor.setDefaultValueText(intOption.getDefaultValueText()); |
| } |
| else { |
| myCurrentEditor = myOptionsEditor; |
| myOptionsEditor.setCell(table, row, column); |
| myOptionsEditor.setText(String.valueOf(node.getValue())); |
| myOptionsEditor.setOptions(((SelectionOption)node.getKey()).options); |
| myOptionsEditor.setDefaultValue(node.getValue()); |
| } |
| } |
| |
| myCurrentEditor.setBackground(table.getBackground()); |
| return myCurrentEditor; |
| } |
| } |
| |
| @Override |
| public void apply(CodeStyleSettings settings) { |
| TreeModel treeModel = myTreeTable.getTree().getModel(); |
| TreeNode root = (TreeNode)treeModel.getRoot(); |
| applyNode(root, settings); |
| } |
| |
| @Override |
| public boolean isModified(CodeStyleSettings settings) { |
| TreeModel treeModel = myTreeTable.getTree().getModel(); |
| TreeNode root = (TreeNode)treeModel.getRoot(); |
| if (isModified(root, settings)) { |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public JComponent getPanel() { |
| return myPanel; |
| } |
| |
| @Override |
| protected void resetImpl(final CodeStyleSettings settings) { |
| TreeModel treeModel = myTreeTable.getTree().getModel(); |
| TreeNode root = (TreeNode)treeModel.getRoot(); |
| resetNode(root, settings); |
| } |
| |
| @Override |
| public Set<String> processListOptions() { |
| Set<String> options = new HashSet<String>(); |
| collectOptions(options, myOptions); |
| collectOptions(options, myCustomOptions); |
| return options; |
| } |
| |
| private void collectOptions(Set<String> optionNames, final List<Option> optionList) { |
| for (Option option : optionList) { |
| if (option.groupName != null) { |
| optionNames.add(option.groupName); |
| } |
| optionNames.add(option.title); |
| } |
| } |
| } |