package de.lmu.ifi.dbs.elki.visualization.style; /* This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures Copyright (C) 2011 Ludwig-Maximilians-Universität München Lehr- und Forschungseinheit für Datenbanksysteme ELKI Development Team This program 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. 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import java.io.File; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Properties; import de.lmu.ifi.dbs.elki.logging.Logging; import de.lmu.ifi.dbs.elki.utilities.FileUtil; import de.lmu.ifi.dbs.elki.utilities.datastructures.AnyMap; import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException; import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary; import de.lmu.ifi.dbs.elki.visualization.colors.ListBasedColorLibrary; import de.lmu.ifi.dbs.elki.visualization.style.lines.DashedLineStyleLibrary; import de.lmu.ifi.dbs.elki.visualization.style.lines.LineStyleLibrary; import de.lmu.ifi.dbs.elki.visualization.style.marker.MarkerLibrary; import de.lmu.ifi.dbs.elki.visualization.style.marker.PrettyMarkers; /** * Style library loading the parameters from a properties file. * * @author Erich Schubert */ // TODO: also use Caching for String values? public class PropertiesBasedStyleLibrary implements StyleLibrary { /** * Logger */ protected static final Logging logger = Logging.getLogger(PropertiesBasedStyleLibrary.class); /** * Name of the default color scheme. */ public static final String DEFAULT_SCHEME_NAME = "Default"; /** * File name of the default color scheme. */ public static final String DEFAULT_SCHEME_FILENAME = "default"; /** * File extension */ public static final String DEFAULT_PROPERTIES_EXTENSION = ".properties"; /** * Default properties path */ private static final String DEFAULT_PROPERTIES_PATH = PropertiesBasedStyleLibrary.class.getPackage().getName().replace('.', File.separatorChar) + File.separatorChar; /** * Separator for lists. */ public static final String LIST_SEPARATOR = ","; /** * Properties file to use. */ private Properties properties; /** * Style scheme name */ private String name; /** * Cache */ private AnyMap cache = new AnyMap(); /** * Line style library to use */ private LineStyleLibrary linelib = null; /** * Marker library to use */ private MarkerLibrary markerlib = null; /** * Constructor without a properties file name. */ public PropertiesBasedStyleLibrary() { this(DEFAULT_SCHEME_FILENAME, DEFAULT_SCHEME_NAME); } /** * Constructor with a given file name. * * @param filename Name of properties file. * @param name NAme for this style */ public PropertiesBasedStyleLibrary(String filename, String name) { this.properties = new Properties(); this.name = name; InputStream stream = null; try { stream = FileUtil.openSystemFile(filename); } catch(FileNotFoundException e) { try { stream = FileUtil.openSystemFile(filename + DEFAULT_PROPERTIES_EXTENSION); } catch(FileNotFoundException e2) { try { stream = FileUtil.openSystemFile(DEFAULT_PROPERTIES_PATH + filename + DEFAULT_PROPERTIES_EXTENSION); } catch(FileNotFoundException e3) { throw new AbortException("Could not find style scheme file '" + filename + "' for scheme '" + name + "'!"); } } } try { properties.load(stream); } catch(Exception e) { throw new AbortException("Error loading properties file " + filename + ".\n", e); } } /** * Get the style scheme name. * * @return the name */ protected String getName() { return name; } /** * Get a value from the cache (to avoid repeated parsing) * * @param Type * @param prefix Tree name * @param postfix Property name * @param cls Class restriction * @return Resulting value */ private T getCached(String prefix, String postfix, Class cls) { return cache.get(prefix + "." + postfix, cls); } /** * Set a cache value * * @param Type * @param prefix Tree name * @param postfix Property name * @param data Data */ private void setCached(String prefix, String postfix, T data) { cache.put(prefix + "." + postfix, data); } /** * Retrieve the property value for a particular path + type pair. * * @param prefix Path * @param postfix Type * @return Value */ protected String getPropertyValue(String prefix, String postfix) { String ret = properties.getProperty(prefix + "." + postfix); if(ret != null) { // logger.debugFine("Found property: "+prefix + "." + // postfix+" for "+prefix); return ret; } int pos = prefix.length(); while(pos > 0) { pos = prefix.lastIndexOf(".", pos - 1); if(pos <= 0) { break; } ret = properties.getProperty(prefix.substring(0, pos) + "." + postfix); if(ret != null) { // logger.debugFine("Found property: "+prefix.substring(0, pos) + "." + // postfix+" for "+prefix); return ret; } } ret = properties.getProperty(postfix); if(ret != null) { // logger.debugFine("Found property: "+postfix+" for "+prefix); return ret; } return null; } @Override public String getColor(String key) { return getPropertyValue(key, COLOR); } @Override public String getBackgroundColor(String key) { return getPropertyValue(key, BACKGROUND_COLOR); } @Override public String getTextColor(String key) { return getPropertyValue(key, TEXT_COLOR); } @Override public ColorLibrary getColorSet(String key) { ColorLibrary cl = getCached(key, COLORSET, ColorLibrary.class); if(cl == null) { String[] colors = getPropertyValue(key, COLORSET).split(LIST_SEPARATOR); cl = new ListBasedColorLibrary(colors, "Default"); setCached(key, COLORSET, cl); } return cl; } @Override public double getLineWidth(String key) { Double lw = getCached(key, LINE_WIDTH, Double.class); if(lw == null) { try { lw = Double.parseDouble(getPropertyValue(key, LINE_WIDTH)) * SCALE; } catch(NullPointerException e) { throw new AbortException("Missing/invalid value in style library: " + key + "." + LINE_WIDTH); } } return lw; } @Override public double getTextSize(String key) { Double lw = getCached(key, TEXT_SIZE, Double.class); if(lw == null) { try { lw = Double.parseDouble(getPropertyValue(key, TEXT_SIZE)) * SCALE; } catch(NullPointerException e) { throw new AbortException("Missing/invalid value in style library: " + key + "." + TEXT_SIZE); } } return lw; } @Override public String getFontFamily(String key) { return getPropertyValue(key, FONT_FAMILY); } @Override public double getSize(String key) { Double lw = getCached(key, GENERIC_SIZE, Double.class); if(lw == null) { try { lw = Double.parseDouble(getPropertyValue(key, GENERIC_SIZE)) * SCALE; } catch(NullPointerException e) { throw new AbortException("Missing/invalid value in style library: " + key + "." + GENERIC_SIZE); } } return lw; } @Override public double getOpacity(String key) { Double lw = getCached(key, OPACITY, Double.class); if(lw == null) { try { lw = Double.parseDouble(getPropertyValue(key, OPACITY)); } catch(NullPointerException e) { throw new AbortException("Missing/invalid value in style library: " + key + "." + OPACITY); } } return lw; } @Override public LineStyleLibrary lines() { if(linelib == null) { // FIXME: make configurable linelib = new DashedLineStyleLibrary(this); } return linelib; } @Override public MarkerLibrary markers() { if(markerlib == null) { // FIXME: make configurable markerlib = new PrettyMarkers(this); } return markerlib; } }