/******************************************************************************* * Copyright (c) 2012-2015 INRIA. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Generoso Pagano - initial API and implementation ******************************************************************************/ package fr.inria.soctrace.framesoc.ui.colors; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.eclipse.core.runtime.Platform; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.inria.soctrace.framesoc.ui.Activator; import fr.inria.soctrace.lib.model.EventProducer; import fr.inria.soctrace.lib.model.EventType; import fr.inria.soctrace.lib.model.utils.SoCTraceException; /** * Singleton for color management in Framesoc. * * <p> * The typical user code usage of this class implies * getting or setting colors for entities. * * <p> * An entity is identified by a string: * <ul> * <li> for {@link EventType} this string shall be the result of {@link EventType#getName()} * <li> for {@link EventProducer} this string shall be the result of {@link EventProducer#getWholeName()} * </ul> * * <p> * Note that when you request a color for an unknown * entity, a random color is generated. If you want * to save these randomly generated colors, remember * to explicitly call the save methods provided. * * @author "Generoso Pagano <generoso.pagano@inria.fr>" */ public class FramesocColorManager { /** * Logger */ private final static Logger logger = LoggerFactory.getLogger(FramesocColorManager.class); public final static String SEPARATOR = ","; public final static String EQUAL = "="; private final static String CONF_DIR = "configuration" + File.separator + Activator.PLUGIN_ID + File.separator; private final static String ET_FILE = CONF_DIR + "event_type_colors"; private final static String EP_FILE = CONF_DIR + "event_producer_colors"; private final static String ERROR_NEAR = "Color configuration file error near: "; private Map<String, FramesocColor> etColors = new HashMap<String, FramesocColor>(); private Map<String, FramesocColor> epColors = new HashMap<String, FramesocColor>(); private static FramesocColorManager instance = new FramesocColorManager(); private boolean dirtyTypes = false; private boolean dirtyProducers = false; private FramesocColorManager() { try { loadFile(etColors, ET_FILE); loadFile(epColors, EP_FILE); } catch (SoCTraceException e) { e.printStackTrace(); } } /* * Public API */ /** * Singleton instance getter * @return the instance of the manager */ public static FramesocColorManager getInstance() { return instance; } /** * Add the event type colors that are NOT already known to * the system. * * This method is used by importers to set default colors. * * @param colors map between event type names and colors */ public void addEventTypeColors(Map<String, FramesocColor> colors) { addColors(colors, etColors); updateFile(etColors, ET_FILE); } /** * Add the event producer colors that are NOT already known to * the system. * * This method is used by importers to set default colors. * * @param colors map between event producer names and colors */ public void addEventProducerColors(Map<String, FramesocColor> colors) { addColors(colors, epColors); updateFile(epColors, EP_FILE); } /** * Get the event type color, given the name. * @param name event type name, defined as the return of {@link EventType#getName()} * @return the event type color */ public FramesocColor getEventTypeColor(String name) { return getColor(name, etColors); } /** * Get the event producer color, given the name. * @param name event producer name, defined as the return of {@link EventProducer#getWholeName()} * @return the event producer name */ public FramesocColor getEventProducerColor(String name) { return getColor(name, epColors); } /** * Set the event type color. * @param name event type name, defined as the return of {@link EventType#getName()} * @param color Framesoc color for the event type */ public void setEventTypeColor(String name, FramesocColor color) { setColor(name, color, etColors); } /** * Set the event producer color. * @param name event producer name, defined as the return of {@link EventProducer#getWholeName()} * @param color Framesoc color for the event producer */ public void setEventProducerColor(String name, FramesocColor color) { setColor(name, color, epColors); } /** * Remove the event type color. * @param name event type name, defined as the return of {@link EventType#getName()} */ public void removeEventTypeColor(String name) { removeColor(name, etColors); } /** * Remove the event producer color. * @param name event producer name, defined as the return of {@link EventProducer#getWholeName()} */ public void removeEventProducerColor(String name) { removeColor(name, epColors); } /** * Save the event type colors on the configuration file. */ public void saveEventTypeColors() { updateFile(etColors, ET_FILE); } /** * Save the event producer colors on the configuration file. */ public void saveEventProducerColors() { updateFile(epColors, EP_FILE); } /** * Load the event type colors configuration file from disk. */ public void loadEventTypeColors() { try { loadFile(etColors, ET_FILE); } catch (SoCTraceException e) { e.printStackTrace(); } } /** * Load the event producer colors configuration file from disk. */ public void loadEventProducerColors() { try { loadFile(etColors, ET_FILE); } catch (SoCTraceException e) { e.printStackTrace(); } } /** * Get a collection of all known event type names associated * with colors. * @return A collection of event type names */ public Collection<String> getEventTypeNames() { return Collections.unmodifiableCollection(etColors.keySet()); } /** * Get a collection of all known event producer names associated * with colors. * @return A collection of event producer names */ public Collection<String> getEventProducerNames() { return Collections.unmodifiableCollection(epColors.keySet()); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Event Type Colors\n"); builder.append(printMap(etColors)); builder.append("Event Producer Colors\n"); builder.append(printMap(epColors)); return builder.toString(); } /* * utilities */ private void setDirty(Map<String, FramesocColor> colors, boolean dirty) { if (colors.equals(etColors)) dirtyTypes = dirty; else dirtyProducers = dirty; } private boolean isDirty(Map<String, FramesocColor> colors) { if (colors.equals(etColors)) return dirtyTypes; else return dirtyProducers; } private String printMap(Map<String, FramesocColor> colors) { StringBuilder builder = new StringBuilder(); Iterator<Entry<String, FramesocColor>> it = colors.entrySet().iterator(); while (it.hasNext()) { Entry<String, FramesocColor> e = it.next(); builder.append(e.getKey()); builder.append("="); builder.append(e.getValue().toString()); builder.append("\n"); } return builder.toString(); } private void addColors(Map<String, FramesocColor> newColors, Map<String, FramesocColor> colors) { for (String newName: newColors.keySet()) { if (!colors.containsKey(newName)) { colors.put(newName, newColors.get(newName)); setDirty(colors, true); } } } private FramesocColor getColor(String name, Map<String, FramesocColor> colors) { if (!colors.containsKey(name)) { colors.put(name, FramesocColor.generateFramesocColor(name)); setDirty(colors, true); } return colors.get(name); } private void setColor(String name, FramesocColor color, Map<String, FramesocColor> colors) { if (colors.containsKey(name)) colors.get(name).dispose(); colors.put(name, color); setDirty(colors, true); } private void removeColor(String name, Map<String, FramesocColor> colors) { if (colors.containsKey(name)) { colors.remove(name); setDirty(colors, true); } } private synchronized void loadFile(Map<String, FramesocColor> colors, String path) throws SoCTraceException { disposeColors(colors); try { File dir = new File(Platform.getInstallLocation().getURL().getPath() + CONF_DIR); if (!dir.exists()) dir.mkdir(); String absolutePath = Platform.getInstallLocation().getURL().getPath() + path; File file = new File(absolutePath); if (!file.exists()) { logger.debug("Configuration file not found. Create an empty one: {}", absolutePath); file.createNewFile(); } else { logger.debug("Configuration file found: {}", absolutePath); BufferedReader br = new BufferedReader(new FileReader(file)); String line = ""; while ( (line = br.readLine()) != null ) { if( line.equals("") ) continue; if( line.startsWith("#") ) continue; String [] prop = line.split(EQUAL); if (prop.length!=2) { br.close(); throw new SoCTraceException(ERROR_NEAR + line); } colors.put(prop[0], getFramesocColor(prop[1])); } br.close(); } setDirty(colors, false); } catch (IOException e) { logger.error(e.getMessage()); e.printStackTrace(); } } private synchronized void updateFile(Map<String, FramesocColor> colors, String path) { if (!isDirty(colors)) return; try { File file = new File(Platform.getInstallLocation().getURL().getPath() + path); file.delete(); file.createNewFile(); BufferedWriter bw = new BufferedWriter(new FileWriter(file)); Iterator<Entry<String, FramesocColor>> it = colors.entrySet().iterator(); while (it.hasNext()) { Entry<String, FramesocColor> entry = it.next(); bw.write(entry.getKey()+EQUAL+getString(entry.getValue())+"\n"); } bw.close(); setDirty(colors, false); } catch (IOException e) { logger.error(e.getMessage()); e.printStackTrace(); } } private FramesocColor getFramesocColor(String color) throws SoCTraceException { String [] colors = color.split(SEPARATOR); if (colors.length != 3) throw new SoCTraceException(ERROR_NEAR + color); try { int r = Integer.valueOf(colors[0]); int g = Integer.valueOf(colors[1]); int b = Integer.valueOf(colors[2]); return new FramesocColor(r, g, b); } catch (NumberFormatException e) { throw new SoCTraceException(ERROR_NEAR + color); } } private String getString(FramesocColor color) { return color.red + SEPARATOR + color.green + SEPARATOR + color.blue; } private void disposeColors(Map<String, FramesocColor> colors) { for (FramesocColor c: colors.values()) c.dispose(); colors.clear(); } }