/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org>, Mathieu Jacomy, Julian Bilcke, Eduardo Ramos Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.ui.tools.plugin.edit; import java.awt.Color; import java.util.EnumSet; import org.gephi.data.attributes.api.AttributeColumn; import org.gephi.data.attributes.api.AttributeRow; import org.gephi.data.attributes.api.AttributeType; import org.gephi.data.attributes.api.AttributeValue; import org.gephi.data.attributes.type.DynamicType; import org.gephi.datalab.api.AttributeColumnsController; import org.gephi.dynamic.api.DynamicController; import org.gephi.dynamic.api.DynamicModel; import org.gephi.dynamic.api.DynamicModel.TimeFormat; import org.gephi.graph.api.Edge; import org.gephi.graph.api.EdgeData; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; /** * PropertySheet that allows to edit one or more edges. * If multiple node edition mode is used at first all values will be shown as blank * but will change with the editions and all edges will be set the values that the user inputs. * @author Mathieu Bastian */ public class EditEdges extends AbstractNode { private PropertySet[] propertySets; private Edge[] edges; private boolean multipleEdges; private TimeFormat currentTimeFormat=TimeFormat.DOUBLE; /** * Single edge edition mode will always be enabled with this single node constructor * @param edge */ public EditEdges(Edge edge) { super(Children.LEAF); this.edges = new Edge[]{edge}; setName(edge.getEdgeData().getLabel()); multipleEdges = false; } /** * If the edges array has more than one element, multiple edges edition mode will be enabled. * @param edges */ public EditEdges(Edge[] edges) { super(Children.LEAF); this.edges = edges; multipleEdges = edges.length > 1; if (multipleEdges) { setName(NbBundle.getMessage(EditEdges.class, "EditEdges.multiple.elements")); } else { setName(edges[0].getEdgeData().getLabel()); } } @Override public PropertySet[] getPropertySets() { propertySets = new PropertySet[]{prepareEdgesProperties(), prepareEdgesAttributes()}; return propertySets; } /** * Prepare set of attributes of the edges. * @return Set of these attributes */ private Sheet.Set prepareEdgesAttributes() { try { DynamicModel dm=Lookup.getDefault().lookup(DynamicController.class).getModel(); if(dm!=null){ currentTimeFormat=dm.getTimeFormat(); } AttributeColumnsController ac = Lookup.getDefault().lookup(AttributeColumnsController.class); Sheet.Set set = new Sheet.Set(); set.setName("attributes"); if (edges.length > 1) { set.setDisplayName(NbBundle.getMessage(EditEdges.class, "EditEdges.attributes.text.multiple")); } else { set.setDisplayName(NbBundle.getMessage(EditEdges.class, "EditEdges.attributes.text", edges[0].getEdgeData().getLabel())); } AttributeRow row = (AttributeRow) edges[0].getEdgeData().getAttributes(); AttributeValueWrapper wrap; for (AttributeValue value : row.getValues()) { if (multipleEdges) { wrap = new MultipleEdgesAttributeValueWrapper(edges, value.getColumn()); } else { wrap = new SingleEdgeAttributeValueWrapper(row, value.getColumn()); } AttributeType type = value.getColumn().getType(); Property p; if (ac.canChangeColumnData(value.getColumn())) { //Editable column, provide "set" method: if (!NotSupportedTypes.contains(type)) {//The AttributeType can be edited by default: p = new PropertySupport.Reflection(wrap, type.getType(), "getValue" + type.getType().getSimpleName(), "setValue" + type.getType().getSimpleName()); } else {//Use the AttributeType as String: p = new PropertySupport.Reflection(wrap, String.class, "getValueAsString", "setValueAsString"); } } else { //Not editable column, do not provide "set" method: if (!NotSupportedTypes.contains(type)) {//The AttributeType can be edited by default: p = new PropertySupport.Reflection(wrap, type.getType(), "getValue" + type.getType().getSimpleName(), null); } else {//Use the AttributeType as String: p = new PropertySupport.Reflection(wrap, String.class, "getValueAsString", null); } } p.setDisplayName(value.getColumn().getTitle()); p.setName(value.getColumn().getId()); set.put(p); } return set; } catch (Exception ex) { Exceptions.printStackTrace(ex); return null; } } /** * Prepare set of editable properties of the node(s): size, position. * @return Set of these properties */ private Sheet.Set prepareEdgesProperties() { try { if (multipleEdges) { MultipleEdgesPropertiesWrapper EdgesWrapper = new MultipleEdgesPropertiesWrapper(edges); Sheet.Set set = new Sheet.Set(); set.setName("properties"); set.setDisplayName(NbBundle.getMessage(EditEdges.class, "EditEdges.properties.text.multiple")); Property p; //Color: p = new PropertySupport.Reflection(EdgesWrapper, Color.class, "getEdgesColor", "setEdgesColor"); p.setDisplayName(NbBundle.getMessage(EditEdges.class, "EditEdges.color.text")); p.setName("color"); set.put(p); return set; } else { Edge edge = edges[0]; Sheet.Set set = new Sheet.Set(); set.setName("properties"); set.setDisplayName(NbBundle.getMessage(EditEdges.class, "EditEdges.properties.text", edge.getEdgeData().getLabel())); Property p; //Color: SingleEdgePropertiesWrapper EdgeWrapper = new SingleEdgePropertiesWrapper(edge); p = new PropertySupport.Reflection(EdgeWrapper, Color.class, "getEdgeColor", "setEdgeColor"); p.setDisplayName(NbBundle.getMessage(EditEdges.class, "EditEdges.color.text")); p.setName("color"); set.put(p); return set; } } catch (Exception ex) { Exceptions.printStackTrace(ex); return null; } } public class SingleEdgePropertiesWrapper { private Edge edge; public SingleEdgePropertiesWrapper(Edge Edge) { this.edge = Edge; } public Color getEdgeColor() { EdgeData data = edge.getEdgeData(); if(data.r()<0||data.g()<0||data.b()<0||data.alpha()<0){ return null;//Not specific color for edge } return new Color(data.r(), data.g(), data.b(), data.alpha()); } public void setEdgeColor(Color c) { if (c != null) { EdgeData data = edge.getEdgeData(); data.setR(c.getRed() / 255f); data.setG(c.getGreen() / 255f); data.setB(c.getBlue() / 255f); data.setAlpha(c.getAlpha() / 255f); } } } public class MultipleEdgesPropertiesWrapper { Edge[] edges; public MultipleEdgesPropertiesWrapper(Edge[] Edges) { this.edges = Edges; } //Methods and fields for multiple edges editing: private Color EdgesColor = null; public Color getEdgesColor() { return EdgesColor; } public void setEdgesColor(Color c) { if (c != null) { EdgesColor = c; EdgeData data; for (Edge edge : edges) { data = edge.getEdgeData(); data.setR(c.getRed() / 255f); data.setG(c.getGreen() / 255f); data.setB(c.getBlue() / 255f); data.setAlpha(c.getAlpha() / 255f); } } } } /** * These AttributeTypes are not supported by default by netbeans property editor. * We will use attributes of these types as Strings and parse them. */ private static EnumSet<AttributeType> NotSupportedTypes = EnumSet.of( AttributeType.BIGINTEGER, AttributeType.BIGDECIMAL, AttributeType.LIST_BIGDECIMAL, AttributeType.LIST_BIGINTEGER, AttributeType.LIST_BOOLEAN, AttributeType.LIST_BYTE, AttributeType.LIST_CHARACTER, AttributeType.LIST_DOUBLE, AttributeType.LIST_FLOAT, AttributeType.LIST_INTEGER, AttributeType.LIST_LONG, AttributeType.LIST_SHORT, AttributeType.LIST_STRING, AttributeType.TIME_INTERVAL, AttributeType.DYNAMIC_BIGDECIMAL, AttributeType.DYNAMIC_BIGINTEGER, AttributeType.DYNAMIC_BOOLEAN, AttributeType.DYNAMIC_BYTE, AttributeType.DYNAMIC_CHAR, AttributeType.DYNAMIC_DOUBLE, AttributeType.DYNAMIC_FLOAT, AttributeType.DYNAMIC_INT, AttributeType.DYNAMIC_LONG, AttributeType.DYNAMIC_SHORT, AttributeType.DYNAMIC_STRING); public interface AttributeValueWrapper { public Byte getValueByte(); public void setValueByte(Byte object); public Short getValueShort(); public void setValueShort(Short object); public Character getValueCharacter(); public void setValueCharacter(Character object); public String getValueString(); public void setValueString(String object); public Double getValueDouble(); public void setValueDouble(Double object); public Float getValueFloat(); public void setValueFloat(Float object); public Integer getValueInteger(); public void setValueInteger(Integer object); public Boolean getValueBoolean(); public void setValueBoolean(Boolean object); public Long getValueLong(); public void setValueLong(Long object); /****** Other types are not supported by property editors by default so they are used and parsed as Strings ******/ public String getValueAsString(); public void setValueAsString(String value); } public class SingleEdgeAttributeValueWrapper implements AttributeValueWrapper { private AttributeRow row; private AttributeColumn column; public SingleEdgeAttributeValueWrapper(AttributeRow row, AttributeColumn column) { this.row = row; this.column = column; } private String convertToStringIfNotNull() { Object value = row.getValue(column.getIndex()); if (value != null) { if (value instanceof DynamicType) { return ((DynamicType) value).toString(currentTimeFormat==TimeFormat.DOUBLE); } else { return value.toString(); } } else { return null; } } public Byte getValueByte() { return (Byte) row.getValue(column.getIndex()); } public void setValueByte(Byte object) { row.setValue(column.getIndex(), object); } public Short getValueShort() { return (Short) row.getValue(column.getIndex()); } public void setValueShort(Short object) { row.setValue(column.getIndex(), object); } public Character getValueCharacter() { return (Character) row.getValue(column.getIndex()); } public void setValueCharacter(Character object) { row.setValue(column.getIndex(), object); } public String getValueString() { return (String) row.getValue(column.getIndex()); } public void setValueString(String object) { row.setValue(column.getIndex(), object); } public Double getValueDouble() { return (Double) row.getValue(column.getIndex()); } public void setValueDouble(Double object) { row.setValue(column.getIndex(), object); } public Float getValueFloat() { return (Float) row.getValue(column.getIndex()); } public void setValueFloat(Float object) { row.setValue(column.getIndex(), object); } public Integer getValueInteger() { return (Integer) row.getValue(column.getIndex()); } public void setValueInteger(Integer object) { row.setValue(column.getIndex(), object); } public Boolean getValueBoolean() { return (Boolean) row.getValue(column.getIndex()); } public void setValueBoolean(Boolean object) { row.setValue(column.getIndex(), object); } public Long getValueLong() { return (Long) row.getValue(column.getIndex()); } public void setValueLong(Long object) { row.setValue(column.getIndex(), object); } public String getValueAsString() { return convertToStringIfNotNull(); } public void setValueAsString(String value) { row.setValue(column.getIndex(), column.getType().parse(value)); } } public class MultipleEdgesAttributeValueWrapper implements AttributeValueWrapper { private Edge[] edges; private AttributeColumn column; private Object value; public MultipleEdgesAttributeValueWrapper(Edge[] edges, AttributeColumn column) { this.edges = edges; this.column = column; this.value = null; } private String convertToStringIfNotNull() { if (value != null) { if (value instanceof DynamicType) { return ((DynamicType) value).toString(currentTimeFormat==TimeFormat.DOUBLE); } else { return value.toString(); } } else { return null; } } private void setValueToAllEdges(Object object) { this.value = object; for (Edge edge : edges) { edge.getEdgeData().getAttributes().setValue(column.getIndex(), value); } } public Byte getValueByte() { return (Byte) value; } public void setValueByte(Byte object) { setValueToAllEdges(object); } public Short getValueShort() { return (Short) value; } public void setValueShort(Short object) { setValueToAllEdges(object); } public Character getValueCharacter() { return (Character) value; } public void setValueCharacter(Character object) { setValueToAllEdges(object); } public String getValueString() { return (String) value; } public void setValueString(String object) { setValueToAllEdges(object); } public Double getValueDouble() { return (Double) value; } public void setValueDouble(Double object) { setValueToAllEdges(object); } public Float getValueFloat() { return (Float) value; } public void setValueFloat(Float object) { setValueToAllEdges(object); } public Integer getValueInteger() { return (Integer) value; } public void setValueInteger(Integer object) { setValueToAllEdges(object); } public Boolean getValueBoolean() { return (Boolean) value; } public void setValueBoolean(Boolean object) { setValueToAllEdges(object); } public Long getValueLong() { return (Long) value; } public void setValueLong(Long object) { setValueToAllEdges(object); } public String getValueAsString() { return convertToStringIfNotNull(); } public void setValueAsString(String value) { setValueToAllEdges(column.getType().parse(value)); } } }