cdc.gv.support.GvBaseAttributes Maven / Gradle / Ivy
package cdc.gv.support;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Base class used to define a set of attributes.
*
* This is used for:
*
* - node, edge, graph, sub-graph and cluster attributes.
* - cell and table attributes
*
*
*
* @author Damien Carbonne
* @param Concrete implementation type of this class.
* @param Enumeration of possible attributes.
* @param Enumeration of possible usages.
*
*/
public abstract class GvBaseAttributes, N extends Enum>, U extends Enum>> {
/**
* Usage for which the set of attributes is dedicated.
*/
private final U usage;
/**
* Array of standard values. Its length matches the number of attribute
* names. This array is indexed by attribute names.
*/
private final String[] values;
/**
* Handling of attributes that are not directly supported by the library.
*/
private Map extensions = null;
private static final Set NO_NAMES = new HashSet<>();
/**
* Creates a set of GvAttributes for a given usage.
*
* @param nameClass Attributes enumeration class.
* @param usageClass Usage enumeration class.
* @param usage The particular usage (enumeration value) for which this set
* of attributes is intended.
*/
protected GvBaseAttributes(Class nameClass,
Class usageClass,
U usage) {
this.usage = usage;
this.values = new String[nameClass.getEnumConstants().length];
}
protected abstract A self();
/**
* Returns whether an attribute is supported for a usage, or not
*
* @param name The attribute.
* @param usage The usage.
* @return If Attribute named name is supported for usage.
*/
protected abstract boolean isSupported(N name,
U usage);
/**
* Encodes a list of GvEncodables, separating each code by a comma.
*
* @param sep The separator to use.
* @param encodables The list of GvEncodables.
* @return The corresponding code.
*/
protected static String encode(String sep,
GvEncodable... encodables) {
final StringBuilder builder = new StringBuilder();
boolean first = true;
for (final GvEncodable encodable : encodables) {
if (!first) {
builder.append(sep);
}
builder.append(encodable.encode());
first = false;
}
return builder.toString();
}
protected static String encode(String sep,
double... values) {
final StringBuilder builder = new StringBuilder();
boolean first = true;
for (final double value : values) {
if (!first) {
builder.append(sep);
}
builder.append(value);
first = false;
}
return builder.toString();
}
protected enum EscapeContext {
STANDARD,
TOOLTIP
}
protected static String escapeString(String s,
EscapeContext context) {
final StringBuilder builder = new StringBuilder();
final boolean isHtml = s.startsWith("<");
if (isHtml) {
builder.append(s);
} else {
for (int i = 0; i < s.length(); i++) {
final char c = s.charAt(i);
switch (c) {
case '"':
builder.append("\\\"");
break;
case '\n':
if (context == EscapeContext.TOOLTIP) {
builder.append(" ");
} else {
builder.append("\\n");
}
break;
default:
builder.append(c);
break;
}
}
}
return builder.toString();
}
/**
* Returns the code value associated to an attribute name.
*
* @param name Name of the searched attribute.
* @return The value associated to name, possibly null.
*/
public final String getValue(N name) {
return values[name.ordinal()];
}
/**
* Returns the set of extension names defined for this set of attributes
*
* @return The set of extension names defined for this set of attributes
*/
public final Set getExtensionNames() {
if (extensions == null) {
return NO_NAMES;
} else {
return extensions.keySet();
}
}
/**
* Returns the value associated to a given extension (or null).
*
* @param name Extension name.
* @return The value associated to name.
*/
public final String getExtensionValue(String name) {
if (extensions != null) {
return extensions.get(name);
} else {
return null;
}
}
/**
* Sets the value associated to an extension.
*
* @param name Extension name.
* @param value Extension value.
* @return This object.
*/
public final A setExtensionValue(String name,
String value) {
if (name != null) {
if (extensions == null) {
extensions = new HashMap<>();
}
extensions.put(name, value);
}
return self();
}
/**
* Clears all attributes.
*
* @return This object.
*/
protected final A clear() {
for (int index = 0; index < values.length; index++) {
values[index] = null;
}
if (extensions != null) {
extensions.clear();
}
return self();
}
/**
* Sets the string value associated to an attribute name. If the attribute is
* not supported, nothing is done.
*
* @param name The attribute name.
* @param value The associated value.
* @return This object.
*/
protected final A setValue(N name,
String value) {
if (isSupported(name, usage)) {
values[name.ordinal()] = value;
}
return self();
}
/**
* Sets the double value associated to an attribute name. If the attribute is
* not supported, nothing is done.
*
* @param name The attribute name.
* @param value The associated value.
* @return This object.
*/
protected final A setValue(N name,
double value) {
return setValue(name, Double.toString(value));
}
protected final A setValue(N name,
double value1,
double value2) {
return setValue(name, value1 + "," + value2);
}
/**
* Sets the boolean value associated to an attribute name. If the attribute
* is not supported, nothing is done.
*
* @param name The attribute name.
* @param value The associated value.
* @return This object.
*/
protected final A setValue(N name,
boolean value) {
return setValue(name, Boolean.toString(value));
}
/**
* Sets the long value associated to an attribute name. If the attribute is
* not supported, nothing is done.
*
* @param name The attribute name.
* @param value The associated value.
* @return This object.
*/
protected final A setValue(N name,
long value) {
return setValue(name, Long.toString(value));
}
}