// BlogBridge -- RSS feed reader, manager, and web based service // Copyright (C) 2002-2006 by R. Pito Salas // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software Foundation; // either version 2 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 General Public License for more details. // // You should have received a copy of the GNU General Public License along with this program; // if not, write to the Free Software Foundation, Inc., 59 Temple Place, // Suite 330, Boston, MA 02111-1307 USA // // Contact: R. Pito Salas // mailto:pitosalas@users.sourceforge.net // More information: about BlogBridge // http://www.blogbridge.com // http://sourceforge.net/projects/blogbridge // // $Id: AbstractStylesheet.java,v 1.5 2007/10/01 17:03:27 spyromus Exp $ // package com.salas.bb.views.stylesheets; import com.salas.bb.views.stylesheets.domain.IRule; import com.salas.bb.views.stylesheets.domain.Rule; import com.salas.bb.views.stylesheets.loader.DirectLoader; import com.salas.bb.views.stylesheets.loader.ILoader; import com.salas.bb.views.stylesheets.parser.Parser; import com.salas.bb.utils.StringUtils; import javax.swing.*; import java.awt.*; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.Map; /** * The stylesheet that knows how to update itself. */ abstract class AbstractStylesheet implements IStylesheet { /** Default font, color and icon */ private static final IRule EMPTY_RULE = new Rule(); /** The map [element_name:map[class:rule]] */ private Map rules = new HashMap(); /** Default loader. */ private static final ILoader DEFAULT_LOADER = new DirectLoader(); /** * Checks for updates of the stylesheet and prerequisites. * * @throws IOException if loading failed. */ public void update() throws IOException { String newSS = getUpdatedStylesheet(); if (newSS != null) applyChanges(newSS); } /** * Gets updated stylesheet. * * @return new stylesheet or <code>NULL</code> if nothing changed. * * @throws IOException if loading failed. */ protected abstract String getUpdatedStylesheet() throws IOException; /** * Parses the stylesheet and applies. * * @param newSS new stylesheet text. */ protected void applyChanges(String newSS) { rules = Parser.parse(newSS); } /** * Returns the font for the element with the given set of classes. * * @param el element. * @param classes classes. * * @return the font object or <code>NULL</code> if the default should be used. */ public Font getFont(String el, String[] classes) { return getRule(el, classes).getFont(); } /** * Returns the color for the element with the given set of classes. * * @param el element. * @param classes classes. * * @return the color or <code>NULL</code> if the default should be used. */ public Color getColor(String el, String[] classes) { return getRule(el, classes).getColor(); } /** * Returns the icon for the element with the given set of classes. * * @param el element. * @param classes classes. * * @return the icon or <code>NULL</code> if the default should be used. * * @throws IOException if loading of icon failed. */ public Icon getIcon(String el, String[] classes) throws IOException { IRule rule = getRule(el, classes); return rule != null ? rule.getIcon() : null; } /** * Returns base URL of this stylesheet to resolveURI relative icon addresses (can be <code>NULL</code>). * * @return base URL. */ protected URL getStylesheetBaseURL() { return null; } /** * Returns the loader to use. * * @return loader. */ protected ILoader getLoader() { return DEFAULT_LOADER; } // ---------------------------------------------------------------------------------- // Rules map methods // ---------------------------------------------------------------------------------- /** * Returns the consolidated rule for the given set of classes. * * @param el element. * @param classes classes. * * @return rule. */ public IRule getRule(String el, String[] classes) { IRule rule; if (classes == null || classes.length == 0) { rule = getRule(el); } else { IRule rootClass; IRule elemDef, elemClass; Map rootClasses = getElementClasses(null, false); // Get root rules rule = getRule(rootClasses, null); for (int i = 0; i < classes.length; i++) { rootClass = getRule(rootClasses, classes[i]); rule = rule.overrideWith(rootClass); } // Get element rules if (el != null) { Map elemClasses = getElementClasses(el, false); elemDef = getRule(elemClasses, null); rule = rule.overrideWith(elemDef); for (int i = 0; i < classes.length; i++) { elemClass = getRule(elemClasses, classes[i]); rule = rule.overrideWith(elemClass); } } } return rule == null ? null : new AutoImageRule(rule); } /** * Gets no-class rule. * * @param el element. * * @return rule. */ private IRule getRule(String el) { IRule rule; Map rootClasses = getElementClasses(null, false); // Get root rules rule = getRule(rootClasses, null); // Get element rules if (el != null) { Map elemClasses = getElementClasses(el, false); rule = rule.overrideWith(getRule(elemClasses, null)); } return rule; } /** * Takes the rule from the classes. If classes are not defined, or the rule isn't set, * the result will be <code>EMPTY_RULE</code>. * * @param classes classes map for some element. * @param clazz class name. * * @return rule. */ private IRule getRule(Map classes, String clazz) { IRule rule = null; if (classes != null) { rule = (IRule)classes.get(clazz); } return rule == null ? EMPTY_RULE : rule; } /** * Returns the element classes to rules map. * * @param el element. * @param createIfMissing when <code>TRUE</code> and the map is missing, it's created. * * @return map. */ private Map getElementClasses(String el, boolean createIfMissing) { Map m = (Map)rules.get(el); if (m == null && createIfMissing) { m = new HashMap(); rules.put(el, m); } return m; } // ---------------------------------------------------------------------------------- // Loading icons // ---------------------------------------------------------------------------------- private final Map cachedIcons = new HashMap(); private Icon loadIcon(String url) { if (StringUtils.isEmpty(url)) return null; url = url.trim(); // Check the icons cache first Icon icon; synchronized (cachedIcons) { icon = (Icon)cachedIcons.get(url); } // If there's no icon yet in the cache, load it if (icon == null) { try { icon = getLoader().loadIcon(getStylesheetBaseURL(), url); synchronized (cachedIcons) { cachedIcons.put(url, icon); } } catch (IOException e) { icon = null; } } return icon; } /** * Resets the cache. */ public void resetIconsCache() { synchronized (cachedIcons) { cachedIcons.clear(); } } // ---------------------------------------------------------------------------------- // Convenience classes // ---------------------------------------------------------------------------------- /** * The automatic image loading rule. */ private class AutoImageRule implements IRule { private IRule subrule; /** * Creates a rule. * * @param subrule sub-rule. */ public AutoImageRule(IRule subrule) { this.subrule = subrule; } /** * Returns the font. * * @return font. */ public Font getFont() { return subrule == null ? null : subrule.getFont(); } /** * Returns the color. * * @return color. */ public Color getColor() { return subrule == null ? null : subrule.getColor(); } /** * Returns the icon URL. * * @return icon URL. */ public String getIconURL() { return subrule == null ? null : subrule.getIconURL(); } /** * Creates an overriden copy of itself. * * @param rule rule to override with. * * @return rule. */ public IRule overrideWith(IRule rule) { if (subrule == null) subrule = rule; else subrule.overrideWith(rule); return this; } /** * Returns icon from cached storage. * * @return icon. */ public Icon getIcon() { Icon icon = subrule.getIcon(); if (icon == null) { String url = subrule.getIconURL(); if (url != null) { icon = loadIcon(url); subrule.setIcon(icon); } } return icon; } /** * Sets icon for cached storage. * * @param icon icon. */ public void setIcon(Icon icon) { } } }