/*
* AttributeColourController.java
*
* Copyright (C) 2006-2014 Andrew Rambaut
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package figtree.treeviewer;
import figtree.treeviewer.decorators.*;
import jam.controlpalettes.AbstractController;
import jebl.evolution.graphs.Node;
import jebl.evolution.trees.Tree;
import jebl.util.Attributable;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.*;
/**
* @author Andrew Rambaut
* @version $Id$
*
* $HeadURL$
*
* $LastChangedBy$
* $LastChangedDate$
* $LastChangedRevision$
*/
public class AttributeColourController extends AbstractController {
public static final String CONTROLLER_KEY = "colour";
public static final String SCHEME_KEY = "scheme";
public static final String ORDER_KEY = "order";
public AttributeColourController(final TreeViewer treeViewer, final JFrame frame) {
this.treeViewer = treeViewer;
this.frame = frame;
}
public void setupControls(
final JComboBox colourAttributeCombo,
final JButton colourSetupButton) {
if (colourSetupButton != null) {
colourSetupButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
ColourDecorator decorator = null;
if (colourAttributeCombo.getSelectedIndex() > 0) {
String attribute = (String) colourAttributeCombo.getSelectedItem();
decorator = getDecoratorForAttribute(attribute);
}
if (decorator == null) {
return;
}
boolean update = false;
if (decorator instanceof DiscreteColourDecorator) {
if (discreteColourScaleDialog == null) {
discreteColourScaleDialog = new DiscreteColourScaleDialog(frame);
}
discreteColourScaleDialog.setDecorator((DiscreteColourDecorator)decorator);
int result = discreteColourScaleDialog.showDialog();
if (result != JOptionPane.CANCEL_OPTION && result != JOptionPane.CLOSED_OPTION) {
decorator = discreteColourScaleDialog.getDecorator();
String attribute = (String) colourAttributeCombo.getSelectedItem();
setDecoratorForAttribute(attribute, decorator);
update = true;
}
} else if (decorator instanceof ContinuousColourDecorator) {
if (continuousColourScaleDialog == null) {
continuousColourScaleDialog = new ContinuousColourScaleDialog(frame);
}
continuousColourScaleDialog.setDecorator((ContinuousColourDecorator)decorator);
int result = continuousColourScaleDialog.showDialog();
if (result != JOptionPane.CANCEL_OPTION && result != JOptionPane.CLOSED_OPTION) {
decorator = continuousColourScaleDialog.getDecorator();
String attribute = (String) colourAttributeCombo.getSelectedItem();
setDecoratorForAttribute(attribute, decorator);
update = true;
}
} else {
throw new IllegalArgumentException("Unsupported decorator type");
}
if (update) {
if (colourAttributeCombo.getSelectedIndex() > 0) {
String attribute = (String) colourAttributeCombo.getSelectedItem();
setDecoratorForAttribute(attribute, decorator);
}
fireControllerChanged();
}
}
});
colourAttributeCombo.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent itemEvent) {
colourSetupButton.setEnabled(colourAttributeCombo.getSelectedIndex() > 0);
}
});
colourSetupButton.setEnabled(colourAttributeCombo.getSelectedIndex() > 0);
}
// I don't think this is required and it throws up many, many events (i.e., every time
// an attribute is added to the combo.
// colourAttributeCombo.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent event) {
// fireControllerChanged();
// }
// });
}
public Decorator getColourDecorator(JComboBox colourAttributeCombo, Decorator defaultDecorator) {
Decorator decorator = defaultDecorator;
if (defaultDecorator == null || colourAttributeCombo.getSelectedIndex() > 0) {
String attribute = (String) colourAttributeCombo.getSelectedItem();
if (attribute != null && attribute.length() > 0) {
decorator = getDecoratorForAttribute(attribute);
}
}
return decorator;
}
public ColourDecorator getDecoratorForAttribute(String attribute) {
ColourDecorator colourDecorator = attributeDecoratorMap.get(attribute);
Set<Attributable> items = new HashSet<Attributable>();
for (Tree tree : treeViewer.getTrees()) {
for (Node node : tree.getNodes()) {
if (node.getAttribute(attribute) != null) {
items.add(node);
}
if (tree.getTaxon(node) != null) {
items.add(tree.getTaxon(node));
}
}
}
//
if (colourDecorator == null) {
if (attribute.endsWith("*")) {
// todo reinstate branch colouring
return null;
} else if (DiscreteColourDecorator.isDiscrete(attribute, items)) {
colourDecorator = new HSBDiscreteColourDecorator(attribute, items);
} else {
ContinuousScale scale = attributeScaleMap.get(attribute);
if (scale == null) {
scale = new ContinuousScale();
attributeScaleMap.put(attribute, scale);
}
scale.setAttributes(attribute, items);
colourDecorator = new HSBContinuousColourDecorator(scale);
}
} else if (colourDecorator instanceof DiscreteColourDecorator) {
((DiscreteColourDecorator)colourDecorator).setAttributes(attribute, items);
} else if (colourDecorator instanceof ContinuousColourDecorator) {
((ContinuousColourDecorator)colourDecorator).setAttributes(attribute, items);
}
return colourDecorator;
}
private void setDecoratorForAttribute(String attribute, ColourDecorator decorator) {
attributeDecoratorMap.put(attribute, decorator);
}
@Override
public JComponent getTitleComponent() {
return null;
}
@Override
public JPanel getPanel() {
return null;
}
@Override
public boolean isInitiallyVisible() {
return false;
}
@Override
public void initialize() {
}
@Override
public void setSettings(Map<String, Object> settings) {
for (String key : settings.keySet()) {
if (key.trim().startsWith(CONTROLLER_KEY + "." + SCHEME_KEY)) {
String value = (String)settings.get(key);
if (value != null) {
String[] parts = value.split(":");
if (parts.length == 2) {
String attribute = parts[0];
ColourDecorator decorator = getDecoratorForAttribute(attribute);
String colourSettings = parts[1];
if (colourSettings.startsWith("HSBDiscrete")) {
String settingsString = colourSettings.substring("HSBDiscrete".length());
if (decorator == null || !(decorator instanceof HSBDiscreteColourDecorator)) {
decorator = new HSBDiscreteColourDecorator(attribute, settingsString);
} else {
decorator.setup(settingsString);
}
} else if (colourSettings.startsWith("FixedDiscrete")) {
String settingsString = colourSettings.substring("FixedDiscrete".length());
if (decorator == null || !(decorator instanceof FixedDiscreteColourDecorator)) {
decorator = new FixedDiscreteColourDecorator(attribute, settingsString);
} else {
decorator.setup(settingsString);
}
} else if (colourSettings.startsWith("HSBContinuous")) {
String settingsString = colourSettings.substring("HSBContinuous".length());
if (decorator == null || !(decorator instanceof HSBDiscreteColourDecorator)) {
decorator = new HSBContinuousColourDecorator(attribute, settingsString);
} else {
decorator.setup(settingsString);
}
} else if (colourSettings.startsWith("InterpolatingContinuous")) {
String settingsString = colourSettings.substring("InterpolatingContinuous".length());
if (decorator == null || !(decorator instanceof InterpolatingColourDecorator)) {
decorator = new InterpolatingColourDecorator(attribute, settingsString);
} else {
decorator.setup(settingsString);
}
} else {
// throw new IllegalArgumentException("Unrecognized colour decorator type");
}
setDecoratorForAttribute(attribute, decorator);
}
}
} else if (key.trim().startsWith(CONTROLLER_KEY + "." + ORDER_KEY)) {
String value = (String)settings.get(key);
if (value != null) {
String[] parts = value.split(":");
if (parts.length == 2) {
String attribute = parts[0];
Object[] values = parts[1].split(",");
ColourDecorator decorator = getDecoratorForAttribute(attribute);
if (decorator != null && decorator instanceof DiscreteColourDecorator) {
((DiscreteColourDecorator)decorator).setValuesOrder(Arrays.asList(values));
setDecoratorForAttribute(attribute, decorator);
}
}
}
}
}
}
@Override
public void getSettings(Map<String, Object> settings) {
for (String attribute : attributeDecoratorMap.keySet()) {
ColourDecorator decorator = attributeDecoratorMap.get(attribute);
String colourSettings = decorator.toString();
String name = "";
if (decorator instanceof HSBDiscreteColourDecorator) {
name = "HSBDiscrete";
} else if (decorator instanceof FixedDiscreteColourDecorator) {
name = "FixedDiscrete";
} else if (decorator instanceof HSBContinuousColourDecorator) {
name = "HSBContinuous";
} else if (decorator instanceof InterpolatingColourDecorator) {
name = "InterpolatingContinuous";
} else {
throw new IllegalArgumentException("Unrecognized colour decorator type");
}
settings.put(CONTROLLER_KEY + "." + SCHEME_KEY + "." + flattenName(attribute), attribute + ":" + name + colourSettings);
if (decorator instanceof DiscreteColourDecorator) {
if (((DiscreteColourDecorator)decorator).hasReorderedValues()) {
String orderString = ((DiscreteColourDecorator)decorator).getOrderString();
settings.put(CONTROLLER_KEY + "." + ORDER_KEY + "." + flattenName(attribute), attribute + ":" + orderString);
}
}
}
}
private String flattenName(String name) {
String flattened = name.trim().toLowerCase();
flattened.replaceAll(" ", "_");
flattened.replaceAll("\t", "_");
flattened.replaceAll("\r", "_");
return flattened;
}
private final TreeViewer treeViewer;
private final JFrame frame;
private Map<String, ColourDecorator> attributeDecoratorMap = new HashMap<String, ColourDecorator>();
private Map<String, ContinuousScale> attributeScaleMap = new HashMap<String, ContinuousScale>();
// private List<String> attributeNames = new ArrayList<String>();
// private boolean editingComboBox = false;
private ContinuousColourScaleDialog continuousColourScaleDialog = null;
private DiscreteColourScaleDialog discreteColourScaleDialog = null;
// // an internal listener interface
// private interface Listener {
// void attributesChanged();
// }
//
// private void addListener(Listener listener) {
// listeners.add(listener);
// }
//
// private void fireAttributesChanged() {
// for (Listener listener : listeners) {
// listener.attributesChanged();
// }
//
// }
// private final List<Listener> listeners = new ArrayList<Listener>();
}