/*
* Copyright 2004-2010 Information & Software Engineering Group (188/1)
* Institute of Software Technology and Interactive Systems
* Vienna University of Technology, Austria
*
* 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.ifs.tuwien.ac.at/dm/somtoolbox/license.html
*
* 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 at.tuwien.ifs.somtoolbox.visualization;
import java.awt.Color;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.jar.JarFile;
import org.jdom.Comment;
import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import at.tuwien.ifs.commons.util.MathUtils;
import at.tuwien.ifs.somtoolbox.SOMToolboxException;
import at.tuwien.ifs.somtoolbox.util.StringUtils;
/**
* This class represents a palette for the visualization.
*
* @author Rudolf Mayer
* @author Jakob Frank
* @version $Id: Palette.java 3888 2010-11-02 17:42:53Z frank $
*/
public class Palette implements Comparable<Palette> {
private String name;
private String description;
private String paletteGroup = "";
private Color[] colors;
private ColorGradient gradient;
private int numberOfGradientColours;
private String shortName;
private boolean hidden = false;
private boolean reversed = false;
public Palette() {
this("", "", "", new Color[] { Color.WHITE, Color.BLACK });
}
public Palette(String name, String shortName, String description, ColorGradient gradient,
int numberOfGradientColours) {
this(name, shortName, description, gradient.toPalette(numberOfGradientColours));
this.gradient = gradient;
this.numberOfGradientColours = numberOfGradientColours;
}
public Palette(String name, String shortName, String description, Color[] colors) {
this.name = name;
this.shortName = shortName;
this.description = description;
this.colors = colors;
this.paletteGroup = "";
}
public String getPaletteGroup() {
return paletteGroup;
}
public void setPaletteGroup(String paletteGroup) {
this.paletteGroup = paletteGroup;
}
public void deleteColor(int pos) {
if (gradient != null) {
gradient.deleteGradientPoing(pos);
colors = gradient.toPalette(numberOfGradientColours);
} else {
if (colors.length < 3) {
return;
}
Color[] c2 = new Color[colors.length - 1];
for (int i = 0, j = 0; i < c2.length && j < colors.length; i++, j++) {
if (i == pos) {
j++;
}
c2[i] = colors[j];
}
colors = c2;
}
}
public void insertColor(int pos, Color c) {
if (gradient != null) {
gradient.insertGradientPoint(pos + 1, c);
colors = gradient.toPalette(numberOfGradientColours);
} else {
Color[] c2 = new Color[colors.length + 1];
for (int i = 0, j = 0; i < c2.length && j < colors.length; i++, j++) {
c2[i] = colors[j];
if (i == pos) {
i++;
c2[i] = c;
}
}
colors = c2;
}
}
public Color[] getColors() {
return colors;
}
public Color getColor(int index) {
return colors[index];
}
public Color getColorConstrained(int index) {
return colors[MathUtils.constrainWithin(index, 0, maxColourIndex())];
}
public String getDescription() {
return description;
}
public String getName() {
return name;
}
public String getShortName() {
return shortName;
}
/**
* Compares palette objects by name.
*/
@Override
public int compareTo(Palette other) {
return getName().compareTo(other.getName());
}
@Override
public String toString() {
return getName() + (reversed ? " (reversed)" : "");
}
public String getCacheKey() {
return getShortName() + (reversed ? " (reversed)" : "");
}
public String getLongDescription() {
return getName() + "-" + getDescription() + "[" + colors.length + " colours]";
}
public int getNumberOfGradientColours() {
return numberOfGradientColours;
}
public ColorGradient getGradient() {
return gradient;
}
public void setColor(int index, Color c) {
if (gradient != null) {
gradient.setGradientPoint(index, -1, c);
} else {
if (c != null) {
colors[index] = c;
}
}
}
public void setGradient(ColorGradient gradient) {
setGradient(gradient, numberOfGradientColours);
}
private void setGradient(ColorGradient gradient, int numberOfGradientColours) {
this.gradient = gradient;
this.numberOfGradientColours = numberOfGradientColours;
this.colors = gradient.toPalette(numberOfGradientColours);
}
/**
* Sets the number of gradient colours to be used, and generates the palette colours ({@link #colors}) new.
*/
public void setNumberOfGradientColours(int numberOfGradientColours) {
this.numberOfGradientColours = numberOfGradientColours;
if (gradient != null) {
this.colors = gradient.toPalette(numberOfGradientColours);
}
}
public static Palette loadPaletteFromXML(InputStream in) throws JDOMException, IOException {
Document doc;
SAXBuilder b = new SAXBuilder(true);
doc = b.build(in, Palette.class.getResource("/rsc/palettes/somtoolboxPalette.dtd").toExternalForm());
return loadPaletteFromXML(doc);
}
public static Palette loadPaletteFromXML(File file) throws SOMToolboxException {
try {
return loadPaletteFromXML(new FileInputStream(file));
} catch (Exception e) {
throw new SOMToolboxException("Could not load \"" + file.getName() + "\"", e);
}
}
public static Palette loadPaletteFromXML(JarFile jarFile, String name) throws SOMToolboxException {
try {
return loadPaletteFromXML(jarFile.getInputStream(jarFile.getEntry(name)));
} catch (Exception e) {
e.printStackTrace();
}
throw new SOMToolboxException("Could not load \"" + name + "\" (not a valid palette)");
}
private static Palette loadPaletteFromXML(Document doc) throws JDOMException {
Element root = doc.getRootElement();
String version = root.getAttributeValue("version");
if (version == null || version.equalsIgnoreCase("1.0")) {
return loadPaletteFromXML_v1x0(root);
}
throw new JDOMException("Unknown Palette-Version");
}
@SuppressWarnings("rawtypes")
private static Palette loadPaletteFromXML_v1x0(Element root) {
String shortName, name, desc, group;
shortName = root.getChildTextNormalize("shortName");
name = root.getChildTextNormalize("longName");
desc = root.getChildTextNormalize("description");
group = root.getAttributeValue("group");
int colorCount = -1;
Element colors = root.getChild("colors");
try {
colorCount = Integer.parseInt(colors.getAttributeValue("colorCount"));
} catch (NumberFormatException e) {
colorCount = -1;
}
boolean isRealRepresentation = StringUtils.equals(colors.getAttributeValue("representation"), "real");
List colorList = colors.getChildren();
int c = colorList.size();
boolean useGradientPoints = true;
double[] gradientPoints = new double[c];
Color[] gradientColors = new Color[c];
for (int i = 0; i < c; i++) {
Element color = (Element) colorList.get(i);
try {
String gPoint = color.getChildTextNormalize("gradientPoint");
if (gPoint != null) {
gradientPoints[i] = Double.parseDouble(gPoint);
} else {
useGradientPoints = false;
}
} catch (NumberFormatException e) {
useGradientPoints = false;
}
if (isRealRepresentation) {
int r = (int) Math.round(255 * Double.parseDouble(color.getChildTextNormalize("red")));
int g = (int) Math.round(255 * Double.parseDouble(color.getChildTextNormalize("green")));
int b = (int) Math.round(255 * Double.parseDouble(color.getChildTextNormalize("blue")));
gradientColors[i] = new Color(r, g, b);
} else {
int r = Integer.parseInt(color.getChildTextNormalize("red"));
int g = Integer.parseInt(color.getChildTextNormalize("green"));
int b = Integer.parseInt(color.getChildTextNormalize("blue"));
gradientColors[i] = new Color(r, g, b);
}
}
Palette res = null;
if (colorCount > 0) {
if (!useGradientPoints) {
for (int i = 0; i < gradientColors.length; i++) {
gradientPoints[i] = (double) i / (double) (gradientColors.length - 1);
}
}
try {
ColorGradient gradient = new ColorGradient(gradientPoints, gradientColors);
res = new Palette(name, shortName, desc, gradient, colorCount);
} catch (SOMToolboxException e) {
// This does not happen!
e.printStackTrace();
}
} else {
res = new Palette(name, shortName, desc, gradientColors);
}
if (group != null) {
res.setPaletteGroup(group);
}
res.setHidden(Boolean.parseBoolean(root.getAttributeValue("hidden")));
return res;
}
/**
* Save the Palette as Matlab code to the given file.
*
* @param file The file to save to or <c>null</c> to write to <c>System.out</c>
*/
public void savePaletteToMatlab(File file) {
try {
PrintStream printStream = System.out;
if (file != null) {
if (file.exists()) {
String p = file.getAbsolutePath();
String newName = file.getName() + new SimpleDateFormat("yyyyMMdd_hhmm_ss").format(new Date());
file.renameTo(new File(file.getParentFile(), newName));
file = new File(p);
}
printStream = new PrintStream(new FileOutputStream(file));
}
printStream.println("% Colormap for " + getName() + " (" + getDescription() + ")");
Color[] colors = getColors();
for (Color element : colors) {
printStream.println((double) element.getRed() / 255 + " " + (double) element.getGreen() / 255 + " "
+ (double) element.getBlue() / 255);
}
if (file != null) {
printStream.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
* Save the Palette as Javacode to the given file.
*
* @param file The file to save to or <c>null</c> to write to <c>System.out</c>
*/
public void savePaletteAsJavaCode(File file) {
PrintStream printStream = System.out;
if (file != null) {
try {
printStream = new PrintStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
ColorGradient g = getGradient();
printStream.println();
printStream.println("// Java Code for Palette " + getName() + " (" + getDescription() + ")"
+ ", generated by Palette Editor");
String paletteVarName = StringUtils.escapeString(getName()).toLowerCase();
if (g != null) {
String pointsVarName = paletteVarName + "_points";
printStream.print("double[] " + pointsVarName + " = new double[] { ");
for (int i = 0; i < g.getNumberOfPoints(); i++) {
printStream.print(g.getGradientPoint(i));
if (i + 1 < g.getNumberOfPoints()) {
printStream.print(", ");
}
}
printStream.println(" };");
String colorsVarName = paletteVarName + "_colors";
printStream.print("Color[] " + colorsVarName + " = new Color[] {");
for (int i = 0; i < g.getNumberOfPoints(); i++) {
printStream.print("new Color(" + g.getGradientColor(i).getRed() + ", "
+ g.getGradientColor(i).getGreen() + ", " + g.getGradientColor(i).getBlue() + ")");
if (i + 1 < g.getNumberOfPoints()) {
printStream.print(", ");
}
}
printStream.println(" };");
printStream.println("try {");
printStream.println(" ColorGradient gradient = new ColorGradient(" + pointsVarName + ", "
+ colorsVarName + ");");
printStream.println(" Palette " + paletteVarName + " = new Palette(\"" + getName() + "\", \""
+ getShortName() + "\", \"" + getDescription() + "\", gradient, " + getNumberOfGradientColours()
+ "); ");
printStream.println(" " + paletteVarName + ".setHidden(" + (isHidden() ? "true" : "false") + ");");
printStream.println(" paletteList.add(" + paletteVarName + ");");
printStream.println("} catch (SOMToolboxException e) {");
printStream.println(" // TODO Auto-generated catch block");
printStream.println(" e.printStackTrace();");
printStream.println("}");
} else {
String colorsVarName = paletteVarName + "_colors";
printStream.print("Color[] " + colorsVarName + " = new Color[] {");
Color[] cls = getColors();
for (int i = 0; i < cls.length; i++) {
printStream.print("new Color(" + cls[i].getRed() + ", " + cls[i].getGreen() + ", " + cls[i].getBlue()
+ ")");
if (i + 1 < cls.length) {
printStream.print(", ");
}
}
printStream.println(" };");
printStream.println("Palette " + paletteVarName + " = new Palette(\"" + getName() + "\", \""
+ getShortName() + "\", \"" + getDescription() + "\", " + colorsVarName + "); ");
printStream.println("paletteList.add(" + paletteVarName + ");");
}
printStream.println("// End generated Code");
printStream.println();
if (file != null) {
printStream.close();
}
}
public void savePaletteToXML(File file) {
Document doc = new Document();
doc.setDocType(new DocType("palette", "somtoolboxPalette.dtd"));
Comment comment = new Comment(" Color-Palette for SOMViewer ");
doc.addContent(comment);
doc.setRootElement(getPaletteAsXML());
try {
OutputStream os = new FileOutputStream(file);
XMLOutputter out = new XMLOutputter();
out.setFormat(Format.getPrettyFormat());
out.output(doc, os);
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @return The root element <code><palette>...</palette></code>
*/
public Element getPaletteAsXML() {
Element root = new Element("palette");
root.setAttribute("version", "1.0");
root.setAttribute("hidden", isHidden() ? "true" : "false");
if (this.getPaletteGroup().length() > 0) {
root.setAttribute("group", this.getPaletteGroup());
}
Element shortName = new Element("shortName");
shortName.setText(this.getShortName());
root.addContent(shortName);
Element longName = new Element("longName");
longName.setText(this.getName());
root.addContent(longName);
Element desc = new Element("description");
desc.setText(this.getDescription());
root.addContent(desc);
// The Colors
Element colorsElement = new Element("colors");
if (this.getNumberOfGradientColours() > 0) {
colorsElement.setAttribute("colorCount", this.getNumberOfGradientColours() + "");
}
ColorGradient cg = this.getGradient();
if (cg != null) {
for (int i = 0; i < cg.getNumberOfPoints(); i++) {
Element color = new Element("color");
// Point
color.addContent(new Element("gradientPoint").setText(cg.getGradientPoint(i) + ""));
// Color
Color c = cg.getGradientColor(i);
color.addContent(new Element("red").setText(c.getRed() + ""));
color.addContent(new Element("green").setText(c.getGreen() + ""));
color.addContent(new Element("blue").setText(c.getBlue() + ""));
colorsElement.addContent(color);
}
} else {
Color[] colors = this.getColors();
for (Color c : colors) {
Element color = new Element("color");
color.addContent(new Element("red").setText(c.getRed() + ""));
color.addContent(new Element("green").setText(c.getGreen() + ""));
color.addContent(new Element("blue").setText(c.getBlue() + ""));
colorsElement.addContent(color);
}
}
root.addContent(colorsElement);
return root;
}
public void setDescription(String description) {
this.description = description;
}
public void setName(String name) {
this.name = name;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
public void reverse() {
this.reversed = !this.reversed;
colors = reverseColors();
}
public boolean isReversed() {
return reversed;
}
public Color[] reverseColors() {
return Palettes.reversePalette(this);
}
public int getNumberOfColours() {
return colors.length;
}
public double maxColourIndex() {
return colors.length - 1;
}
/**
* Returns true if the palette should not be shown in the Palettes menu.
*
* @return <code>true</code> iff the palette is secret.
*/
public boolean isHidden() {
return hidden;
}
public void setHidden(boolean hidden) {
this.hidden = hidden;
}
}