/*
* Copyright 2003-2011 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 jetbrains.mps.ide.platform.ui;
import jetbrains.mps.smodel.ModelAccess;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class CheckBoxNodeRenderer implements TreeCellRenderer {
private final JPanelWithCheckBox myPanel;
public CheckBoxNodeRenderer() {
this(false);
}
public CheckBoxNodeRenderer(boolean isCheckboxLeft) {
myPanel = new JPanelWithCheckBox(isCheckboxLeft);
}
public boolean isSelected() {
return myPanel.myCheckBox.isSelected();
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, final boolean expanded, boolean leaf, int row, boolean hasFocus) {
String text = tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus);
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
myPanel.updateView(tree.isEnabled(), selected, expanded, userObject, text);
return myPanel;
}
private static class JPanelWithCheckBox extends JPanel {
private final JLabel myIconLabel = new JLabel();
private final JLabel myTextLabel = new JLabel();
private final JCheckBox myCheckBox = new JCheckBox();
public JPanelWithCheckBox(boolean isCheckboxLeft) {
super(new BorderLayout());
Font font = UIManager.getFont("Tree.font");
if (font != null) {
myTextLabel.setFont(font);
}
Boolean iconBorder = (Boolean) UIManager.get("Tree.drawsFocusBorderAroundIcon");
setOpaque(true);
myCheckBox.setFocusPainted((iconBorder != null) && iconBorder);
add(myCheckBox, isCheckboxLeft ? BorderLayout.WEST : BorderLayout.CENTER);
add(myIconLabel, isCheckboxLeft ? BorderLayout.CENTER : BorderLayout.WEST);
add(myTextLabel, BorderLayout.EAST);
}
public void addItemListener(ItemListener listener) {
myCheckBox.addItemListener(listener);
}
public void updateView(boolean enabled, boolean selected, final boolean expanded, final Object userObject, final String text) {
myCheckBox.setEnabled(enabled);
ModelAccess.instance().runReadAction(new Runnable() {
@Override
public void run() {
if (userObject instanceof NodeData) {
NodeData data = (NodeData) userObject;
myIconLabel.setIcon(data.getIcon(expanded));
Color color = data.getColor();
if (color != null) {
myCheckBox.setForeground(color);
myTextLabel.setForeground(color);
}
myTextLabel.setText(data.getText());
myCheckBox.setSelected(data.isSelected());
} else {
myIconLabel.setIcon(null);
myTextLabel.setText(text);
myCheckBox.setSelected(false);
}
}
});
myCheckBox.setForeground(getForeground(selected));
myCheckBox.setBackground(getBackground(selected));
setForeground(getForeground(selected));
setBackground(getBackground(selected));
}
private Color getBackground(boolean selected) {
return selected ? UIManager.getColor("Tree.selectionBackground") : UIManager.getColor("Tree.textBackground");
}
private Color getForeground(boolean selected) {
return selected ? UIManager.getColor("Tree.selectionForeground") : UIManager.getColor("Tree.textForeground");
}
}
public static interface NodeData {
Icon getIcon(boolean expanded);
Color getColor();
String getText();
boolean isSelected();
void setSelected(boolean selected);
}
public static abstract class CheckBoxNodeEditor<N extends NodeData> extends AbstractCellEditor implements TreeCellEditor {
private final CheckBoxNodeRenderer myRenderer;
private N myObject;
public CheckBoxNodeEditor() {
this(false);
}
public CheckBoxNodeEditor(boolean isCheckboxLeft) {
myRenderer = new CheckBoxNodeRenderer(isCheckboxLeft);
}
@Override
public Object getCellEditorValue() {
return createNodeData(myRenderer.isSelected());
}
protected abstract N createNodeData(boolean selected);
@Override
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
Component editor = myRenderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
myObject = (N) node.getUserObject();
ItemListener itemListener = new ItemListener() {
@Override
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing()) {
fireEditingStopped();
}
}
};
if (editor instanceof JPanelWithCheckBox) {
((JPanelWithCheckBox) editor).addItemListener(itemListener);
}
return editor;
}
public N getObject() {
return myObject;
}
}
}