package viz.panel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JCheckBox;
import viz.DensiTree;
import viz.DensiTree.LineColorMode;
import viz.DensiTree.MetaDataType;
import viz.util.Util;
import java.awt.GridBagConstraints;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import java.awt.Insets;
import java.util.List;
import java.util.ArrayList;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ColorPanel extends JPanel implements ChangeListener {
final public static String HELP_LINE_COLOR = "Determines line color for the complete tree set. " +
"So, this does not affect the consensus trees or root canal tree.\n" +
"DEFAULT: color 1 for most frequently occurring topology, color 2 for the second most popular, " +
"color 3 for the third, and color 4 for the remaining trees. Colors can be changed using the " +
"line colors button.\n" +
"COLOR_BY_CLADE: draw clades in one color.\n" +
"COLOR_BY_META_DATA_PATTERN: draw trees matching the regular expression specified in the pattern entry below.\n" +
"meta data attribute: only available if any meta data attribute is specified. Use value of the attribute to color branches.";
final public static String HELP_SHOW_LEGEND = "Show legend mapping colors to attribute values in the DensiTree. " +
"This only works when a discrete attribute is selected for line coloring.";
final public static String HELP_MULTI_COLOR_CONSENSUS_TREES = "Use different colours for consensus trees instead of the " +
"standard color.";
final public static String HELP_CATEGORICAL = "Interpret value of attribute as categorical data.";
final public static String HELP_PATTERN = "Regular expression used for coloring trees when COLOR_BY_META_DATA_PATTERN " +
"is chosen. The string of the pattern between brackets is selected as value.";
final public static String HELP_LINE_COLORS = "Specify custom colors.";
private static final long serialVersionUID = 1L;
DensiTree m_dt;
JComboBox<String> comboBox;
private JTextField txtPattern;
private JButton btnLineColors;
private JCheckBox chckbxShowLegend;
private JCheckBox chckbxCategorical;
public ColorPanel(DensiTree dt) {
m_dt = dt;
m_dt.addChangeListener(this);
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[]{0, 0, 0};
gridBagLayout.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0};
gridBagLayout.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
gridBagLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE, 0.0};
setLayout(gridBagLayout);
comboBox = new JComboBox<>();
stateChanged(null);
comboBox.setSelectedItem(m_dt.m_lineColorMode);
comboBox.setPreferredSize(new Dimension(130,20));
comboBox.setMaximumSize(new Dimension(130,200));
comboBox.addActionListener(e-> {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
String selected = comboBox.getSelectedItem().toString();
LineColorMode oldMode = m_dt.m_lineColorMode;
String oldTag = m_dt.m_lineColorTag;
if (selected.equals(LineColorMode.DEFAULT.toString())) {
m_dt.m_lineColorMode = LineColorMode.DEFAULT;
} else if (selected.equals(LineColorMode.BY_METADATA_PATTERN.toString())) {
m_dt.m_lineColorMode = LineColorMode.BY_METADATA_PATTERN;
} else if (selected.equals(LineColorMode.COLOR_BY_CLADE.toString())) {
m_dt.m_lineColorMode = LineColorMode.COLOR_BY_CLADE;
} else {
m_dt.m_lineColorTag = selected;
m_dt.m_lineColorMode = LineColorMode.COLOR_BY_METADATA_TAG;
}
txtPattern.setEnabled(m_dt.m_lineColorMode == LineColorMode.BY_METADATA_PATTERN);
chckbxShowLegend.setEnabled(m_dt.m_lineColorMode == LineColorMode.BY_METADATA_PATTERN
|| m_dt.m_lineColorMode == LineColorMode.COLOR_BY_METADATA_TAG);
chckbxCategorical.setEnabled(m_dt.m_lineColorMode == LineColorMode.COLOR_BY_METADATA_TAG);
if (m_dt.m_lineColorMode != oldMode || (m_dt.m_lineColorTag != null && !m_dt.m_lineColorTag.equals(oldTag))) {
m_dt.calcColors(false);
m_dt.makeDirty();
}
}
});
});
GridBagConstraints gbc_comboBox = new GridBagConstraints();
gbc_comboBox.gridwidth = 2;
gbc_comboBox.insets = new Insets(0, 0, 5, 5);
//gbc_comboBox.fill = GridBagConstraints.HORIZONTAL;
gbc_comboBox.gridx = 0;
gbc_comboBox.gridy = 0;
add(comboBox, gbc_comboBox);
chckbxShowLegend = new JCheckBox("Show legend");
chckbxShowLegend.addActionListener(e-> {
m_dt.m_showLegend = !m_dt.m_showLegend;
m_dt.makeDirty();
});
chckbxShowLegend.setEnabled(false);
GridBagConstraints gbc_chckbxShowLegend = new GridBagConstraints();
gbc_chckbxShowLegend.anchor = GridBagConstraints.WEST;
gbc_chckbxShowLegend.gridwidth = 2;
gbc_chckbxShowLegend.insets = new Insets(0, 0, 5, 5);
gbc_chckbxShowLegend.gridx = 0;
gbc_chckbxShowLegend.gridy = 1;
add(chckbxShowLegend, gbc_chckbxShowLegend);
JCheckBox chckbxMultiColorConsensus = new JCheckBox("<html>Multi color<br>cons-trees</html>");
chckbxMultiColorConsensus.addActionListener(e-> {
m_dt.m_bViewMultiColor = ((JCheckBox) e.getSource()).isSelected();
m_dt.makeDirty();
});
GridBagConstraints gbc_chckbxMultiColorConsensus = new GridBagConstraints();
gbc_chckbxMultiColorConsensus.anchor = GridBagConstraints.WEST;
gbc_chckbxMultiColorConsensus.gridwidth = 3;
gbc_chckbxMultiColorConsensus.insets = new Insets(0, 0, 5, 0);
gbc_chckbxMultiColorConsensus.gridx = 0;
gbc_chckbxMultiColorConsensus.gridy = 2;
add(chckbxMultiColorConsensus, gbc_chckbxMultiColorConsensus);
txtPattern = new JTextField(m_dt.m_sLineColorPattern);
txtPattern.addActionListener(e-> {
String oldPattern = m_dt.m_sLineColorPattern;
m_dt.m_sLineColorPattern = txtPattern.getText();
if (oldPattern.equals(m_dt.m_sLineColorPattern)) {
m_dt.calcColors(false);
m_dt.makeDirty();
}
});
chckbxCategorical = new JCheckBox("categorical");
chckbxCategorical.addActionListener(e-> {
m_dt.m_bColorByCategory = ((JCheckBox) e.getSource()).isSelected();
m_dt.calcColors(true);
m_dt.makeDirty();
});
chckbxCategorical.setToolTipText("indicate that the meta data item shoud be interpreted as categorical");
chckbxCategorical.setEnabled(false);
GridBagConstraints gbc_chckbxNewCheckBox = new GridBagConstraints();
gbc_chckbxNewCheckBox.anchor = GridBagConstraints.WEST;
gbc_chckbxNewCheckBox.gridwidth = 2;
gbc_chckbxNewCheckBox.insets = new Insets(0, 0, 5, 5);
gbc_chckbxNewCheckBox.gridx = 0;
gbc_chckbxNewCheckBox.gridy = 3;
add(chckbxCategorical, gbc_chckbxNewCheckBox);
JLabel lblPattern = new JLabel("pattern:");
GridBagConstraints gbc_lblPattern = new GridBagConstraints();
gbc_lblPattern.anchor = GridBagConstraints.EAST;
gbc_lblPattern.insets = new Insets(0, 0, 5, 5);
gbc_lblPattern.gridx = 0;
gbc_lblPattern.gridy = 4;
add(lblPattern, gbc_lblPattern);
GridBagConstraints gbc_txtPattern = new GridBagConstraints();
gbc_txtPattern.gridwidth = 2;
gbc_txtPattern.insets = new Insets(0, 0, 5, 5);
gbc_txtPattern.fill = GridBagConstraints.HORIZONTAL;
gbc_txtPattern.gridx = 0;
gbc_txtPattern.gridy = 5;
add(txtPattern, gbc_txtPattern);
txtPattern.setColumns(10);
txtPattern.setEnabled(false);
btnLineColors = new RoundedButton("Line colors");
btnLineColors.addActionListener(e-> {
new ColorDialog(m_dt);
});
GridBagConstraints gbc_btnLineColors = new GridBagConstraints();
gbc_btnLineColors.gridwidth = 2;
gbc_btnLineColors.fill = GridBagConstraints.HORIZONTAL;
gbc_btnLineColors.insets = new Insets(0, 0, 0, 5);
gbc_btnLineColors.gridx = 0;
gbc_btnLineColors.gridy = 6;
add(btnLineColors, gbc_btnLineColors);
comboBox.setToolTipText(Util.formatToolTipAsHtml(HELP_LINE_COLOR));
txtPattern.setToolTipText(Util.formatToolTipAsHtml(HELP_PATTERN));
btnLineColors.setToolTipText(Util.formatToolTipAsHtml(HELP_LINE_COLORS));
chckbxShowLegend.setToolTipText(Util.formatToolTipAsHtml(HELP_SHOW_LEGEND));
chckbxCategorical.setToolTipText(Util.formatToolTipAsHtml(HELP_CATEGORICAL));
chckbxMultiColorConsensus.setToolTipText(Util.formatToolTipAsHtml(HELP_MULTI_COLOR_CONSENSUS_TREES));
}
public class ColorDialog extends JDialog {
private static final long serialVersionUID = 1L;
DensiTree m_dt;
public ColorDialog(DensiTree dt) {
m_dt = dt;
getContentPane().setLayout(new GridLayout(0, 3, 0, 0));
addColorAction("Color 1", "Color of most popular topolgy", 0);
addColorAction("Color 2", "Color of second most popular topolgy", 1);
addColorAction("Color 3", "Color of third most popular topolgy", 2);
addColorAction("Default", "Default color ", 3);
addColorAction("Consensus", "Consensus tree color ", DensiTree.CONSCOLOR);
addColorAction("Background", "Background color ", DensiTree.BGCOLOR);
addColorAction("Root canal", "Root canal color ", DensiTree.ROOTCANALCOLOR);
for (int k = 9; k < m_dt.m_color.length; k++) {
addColorAction("Color " + k, "Custom line color " + k, k);
}
JButton button = new RoundedButton("Close");
button.addActionListener(e-> {
dispose();
});
add(button);
setPreferredSize(new Dimension(300,600));
setSize(new Dimension(300,600));
setLocation(300, 600);
setModal(true);
setVisible(true);
}
private void addColorAction(String label, String tiptext, int colorID) {
JButton button = new ColorButton(label, m_dt.m_color[colorID]);
button.setToolTipText(tiptext);
button.addActionListener(new ColorActionListener(colorID, tiptext));
JButton btnColors = new JButton("colors");
btnColors.addActionListener(e-> {
new ColorDialog(m_dt);
});
add(button);
}
class ColorButton extends RoundedButton {
private static final long serialVersionUID = 1L;
Color m_color;
ColorButton(String label, Color color) {
super(label);
m_color = color;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(m_color);
g.fillRect(3, 3, 10, getHeight() - 6);
}
}
class ColorActionListener implements ActionListener {
int m_colorID;
String m_sName;
public ColorActionListener(int colorID, String name) {
m_colorID = colorID;
m_sName = name;
}
@Override
public void actionPerformed(ActionEvent e) {
Color newColor = JColorChooser.showDialog(m_dt.m_Panel, m_sName, m_dt.m_color[m_colorID]);
if (newColor != null && m_dt.m_color[m_colorID] != newColor) {
ColorButton button = ((ColorButton)e.getSource());
button.m_color = newColor;
button.repaint();
m_dt.m_color[m_colorID] = newColor;
m_dt.calcColors(true);
m_dt.makeDirty();
}
m_dt.repaint();
}
}
}
@Override
public void stateChanged(ChangeEvent e) {
List<String> selection = new ArrayList<String>();
selection.add(LineColorMode.DEFAULT.toString());
if (m_dt.m_bMetaDataReady) {
selection.add(LineColorMode.COLOR_BY_CLADE.toString());
selection.add(LineColorMode.BY_METADATA_PATTERN.toString());
for (int i = 0; i < m_dt.m_metaDataTags.size(); i++) {
if (!m_dt.m_metaDataTypes.get(i).equals(MetaDataType.SET)) {
selection.add(m_dt.m_metaDataTags.get(i));
}
}
}
ComboBoxModel<String> model = new DefaultComboBoxModel<>(selection.toArray(new String[0]));
comboBox.setModel(model);
if (m_dt.m_lineColorMode == LineColorMode.DEFAULT) {
comboBox.setSelectedItem(LineColorMode.DEFAULT.toString());
} else if (m_dt.m_lineColorMode == LineColorMode.BY_METADATA_PATTERN) {
comboBox.setSelectedItem(LineColorMode.BY_METADATA_PATTERN.toString());
} else if (m_dt.m_lineColorMode == LineColorMode.COLOR_BY_CLADE) {
comboBox.setSelectedItem(LineColorMode.COLOR_BY_CLADE.toString());
} else {
comboBox.setSelectedItem(m_dt.m_lineColorTag);
}
}
}