All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.css.CSS Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.css;

import java.awt.Color;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.*;

import com.hfg.html.HTMLTag;
import com.hfg.html.attribute.Align;
import com.hfg.html.attribute.VAlign;
import com.hfg.svg.SvgNode;
import com.hfg.util.*;
import com.hfg.util.collection.CollectionUtil;

//------------------------------------------------------------------------------
/**
 Class to define some css style shortcuts.

 Use example:
 
 span.setStyle(CSS.BOLD + CSS.color(Color.red) + CSS.ITALIC);
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg XML/HTML Coding Library // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class CSS { //########################################################################### // PUBLIC FIELDS //########################################################################### public static final String STYLE = "style"; /** Shortcut for 'font-weight:bold;' */ public static final String BOLD = "font-weight:bold;"; /** Shortcut for 'font-style:italic;' */ public static final String ITALIC = "font-style:italic;"; /** Shortcut for 'text-decoration:underline;' */ public static final String UNDERLINE = "text-decoration:underline;"; /** Shortcut for 'font-size:small;' */ public static final String SMALL_FONT = "font-size:small;"; /** Shortcut for 'font-family:monospace;' */ public static final String MONOSPACE = "font-family:monospace;"; /** Shortcut for 'vertical-align:super;' */ public static final String SUPER = "vertical-align:super;"; //########################################################################### // PRIVATE FIELDS //########################################################################### private List mCSSRules; //########################################################################### // CONSTRUCTORS //########################################################################### //-------------------------------------------------------------------------- public CSS() { } //-------------------------------------------------------------------------- /** Parses CSS text into rules. @param inCss CSS text @throws IOException if a problem is encountered while processing the CSS text */ public CSS(CharSequence inCss) throws IOException { this(new StringReader(inCss.toString())); } //-------------------------------------------------------------------------- /** Parses CSS text into rules. @param inCss CSS InputStream @throws IOException if a problem is encountered while processing the CSS text */ public CSS(InputStream inCss) throws IOException { this(new InputStreamReader(inCss)); } //-------------------------------------------------------------------------- /** Parses CSS text into rules. @param inReader CSS text @throws IOException if a problem is encountered while processing the CSS text from the specified Reader */ public CSS(Reader inReader) throws IOException { mCSSRules = parse(inReader); } //########################################################################### // PUBLIC METHODS //########################################################################### //-------------------------------------------------------------------------- @Override public String toString() { StringBuilderPlus buffer = new StringBuilderPlus(); if (CollectionUtil.hasValues(getCSSRules())) { for (CSSRule rule : getCSSRules()) { buffer.appendln(rule.toString()); } } return buffer.toString(); } //-------------------------------------------------------------------------- public CSSRule addRule() { CSSRule rule = new CSSRule(); addRule(rule); return rule; } //-------------------------------------------------------------------------- public CSS addRule(CSSRule inRule) { if (null == mCSSRules) { mCSSRules = new ArrayList<>(); } mCSSRules.add(inRule); return this; } //-------------------------------------------------------------------------- public CSS addRules(Collection inRules) { if (null == mCSSRules) { mCSSRules = new ArrayList<>(inRules); } else { mCSSRules.addAll(inRules); } return this; } //-------------------------------------------------------------------------- public List getCSSRules() { return mCSSRules; } //-------------------------------------------------------------------------- /** Returns CSS declarations that apply to the specified HTML tag. Useful for fusing HTML and CSS before conversion (to WordprocessingML for example). NOTE: This initial implementation does not handle complex selectors. @param inHTML top tag in a chunk of HTML DOM @param inMediaType CSS media type @return List of CSS declarations */ //TODO: improve selector matching public List getCSSDeclarationsForHTMLTag(HTMLTag inHTML, CSSMediaType inMediaType) { List declarations = new ArrayList<>(5); for (CSSRule cssRule : mCSSRules) { // Does this CSS rule apply to this tag? if (cssRule.appliesTo(inMediaType)) { for (CSSSelector selector : cssRule.getSelectors()) { if (selector.appliesTo(inHTML)) { if (CollectionUtil.hasValues(cssRule.getDeclarations())) { declarations.addAll(cssRule.getDeclarations()); } } } } } return declarations; } //-------------------------------------------------------------------------- /** Returns CSS declarations that apply to the specified SVG tag. Useful when converting SVG to an image format via a Graphics2D object. NOTE: This initial implementation does not handle complex selectors. @param inSvgNode top tag in a chunk of SVG DOM @param inMediaType CSS media type @return List of CSS declarations */ //TODO: improve selector matching public List getCSSDeclarationsForSvgNode(SvgNode inSvgNode, CSSMediaType inMediaType) { List declarations = new ArrayList<>(5); for (CSSRule cssRule : mCSSRules) { // Does this CSS rule apply to this tag? if (cssRule.appliesTo(inMediaType)) { for (CSSSelector selector : cssRule.getSelectors()) { if (selector.appliesTo(inSvgNode)) { if (CollectionUtil.hasValues(cssRule.getDeclarations())) { declarations.addAll(cssRule.getDeclarations()); } } } } } return declarations; } //-------------------------------------------------------------------------- /** Where specified CSS rules apply, the styling is placed in the tag's style attribute. Useful for fusing HTML and CSS before conversion (to WordprocessingML for example). NOTE: This initial implementation does not handle complex selectors. @param inHTML top tag in a chunk of HTML DOM @param inMediaType CSS media type */ //TODO: improve selector matching public void localizeStyles(HTMLTag inHTML, CSSMediaType inMediaType) { for (CSSRule cssRule : mCSSRules) { // Does this CSS rule apply to this tag? if (cssRule.appliesTo(inMediaType)) { for (CSSSelector selector : cssRule.getSelectors()) { if (selector.appliesTo(inHTML)) { // Since the local style css should override the stylesheet css we need to (re)add it last. String tagStyle = inHTML.getStyle(); inHTML.setStyle(cssRule.getDeclarationString()); if (StringUtil.isSet(tagStyle)) { inHTML.addStyle(tagStyle); } } } } } // Recurse thru subtags List subtags = inHTML.getSubtags(); if (CollectionUtil.hasValues(subtags)) { for (HTMLTag subtag : subtags) { localizeStyles(subtag, inMediaType); } } } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS color declaration for the specified color. @param inColor the specified color string @return the CSS declaration (ex: 'color:#cccccc;') */ public static String color(String inColor) { return CSSProperty.color + ":" + (HexUtil.isHex(inColor) && ! inColor.startsWith("#") ? "#" : "") + inColor + ";"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS color declaration for the specified color. @param inColor the specified color value @return the CSS declaration (ex: 'color:#cccccc;') */ public static String color(Color inColor) { return CSSProperty.color + ":" + CssUtil.colorToCssValue(inColor) + ";"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS background color declaration for the specified color. @param inColor the specified color value @return the CSS declaration (ex: 'background-color:#cccccc;') */ public static String bgColor(String inColor) { return CSSProperty.background_color + ":" + (HexUtil.isHex(inColor) && ! inColor.startsWith("#") ? "#" : "") + inColor + ";"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS background color declaration for the specified color. @param inColor the specified color value @return the CSS declaration (ex: 'background-color:#cccccc;') */ public static String bgColor(Color inColor) { return CSSProperty.background_color + ":" + CssUtil.colorToCssValue(inColor) + ";"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS font-size declaration in points. @param inPtSize the specified CSS font size value @return the CSS declaration (ex: 'font-size:11pt;') */ public static String fontSize(int inPtSize) { return CSSProperty.font_size + ":" + inPtSize + "pt;"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS font-size declaration in em units. @param inValue the specified CSS font size value @return the CSS declaration (ex: 'font-size:2.5em;') */ public static String fontSizeEm(int inValue) { return CSSProperty.font_size + ":" + inValue + "em;"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS width declaration. @param inValue the specified CSS width value @return the CSS declaration (ex: 'width:100%;') */ public static String width(String inValue) { return CSSProperty.width + ":" + inValue + ";"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS height declaration. @param inValue the specified CSS height value @return the CSS declaration (ex: 'height:100%;') */ public static String height(String inValue) { return CSSProperty.height + ":" + inValue + ";"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS text-align declaration. @param inValue the specified CSS text alignment value @return the CSS declaration (ex: 'text-align:center;') */ public static String textAlign(Align inValue) { return CSSProperty.text_align + ":" + inValue + ";"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS vertical-align declaration. @param inValue the specified CSS vertical alignment value @return the CSS declaration (ex: 'vertical-align:top;') */ public static String verticalAlign(VAlign inValue) { return CSSProperty.vertical_align + ":" + inValue + ";"; } //-------------------------------------------------------------------------- /** Convenience function for composing a CSS display declaration. @param inValue the specified CSS display value @return the CSS declaration (ex: 'display:none;') */ public static String display(CSSDisplayValue inValue) { return CSSProperty.display + ":" + inValue.getDisplayString() + ";"; } //########################################################################### // PRIVATE METHODS //########################################################################### //-------------------------------------------------------------------------- private List parse(Reader inReader) throws IOException { List cssRules = new ArrayList<>(); CSSRule currentCSSRule = null; Set currentMediaQueries = null; boolean parsingMediaQueryList = false; boolean parsingSelector = true; boolean parsingDeclaration = false; boolean inBlockComment = false; StringBuilder mediaQueryListBuffer = new StringBuilder(); StringBuilder selectorBuffer = new StringBuilder(); StringBuilder declarationBuffer = new StringBuilder(); Character prevChar = null; int currentChar; while ((currentChar = inReader.read()) != -1) { if (inBlockComment) { if (currentChar == '/' && prevChar == '*') { inBlockComment = false; } } else if (parsingMediaQueryList) { if (currentChar == '{') { parsingSelector = true; parsingMediaQueryList = false; String[] mediaQueries = mediaQueryListBuffer.toString().split(","); currentMediaQueries = new HashSet(mediaQueries.length); for (String mediaQueryString : mediaQueries) { currentMediaQueries.add(new CSSMediaQuery(mediaQueryString)); } } else { mediaQueryListBuffer.append((char)currentChar); } } else if (parsingSelector && currentChar == 'a' && selectorBuffer.toString().trim().equals("@medi")) { parsingSelector = false; parsingMediaQueryList = true; selectorBuffer.setLength(0); } else if (currentChar == '*' && prevChar == '/') { inBlockComment = true; // Back out the slash from the buffer if (parsingSelector) { selectorBuffer.setLength(selectorBuffer.length() - 1); } else if (parsingDeclaration) { declarationBuffer.setLength(declarationBuffer.length() - 1); } } else if (parsingSelector) { if (currentChar == ',' || currentChar == '{') { if (null == currentCSSRule) { currentCSSRule = new CSSRule().setMediaQueries(currentMediaQueries); } currentCSSRule.addSelector(new CSSSelector(selectorBuffer.toString().trim())); selectorBuffer.setLength(0); if (currentChar == '{') { parsingSelector = false; parsingDeclaration = true; } } else if (currentChar == '}' && CollectionUtil.hasValues(currentMediaQueries)) { currentMediaQueries = null; mediaQueryListBuffer.setLength(0); selectorBuffer.setLength(0); } else { selectorBuffer.append((char)currentChar); } } else if (parsingDeclaration) { if (currentChar == ';' || currentChar == '}') { String declaration = declarationBuffer.toString().trim(); if (StringUtil.isSet(declaration)) { String[] pieces = declaration.split(":"); if (2 == pieces.length) { CSSProperty cssProperty = CSSProperty.valueOf(pieces[0]); currentCSSRule.addDeclaration(new CSSDeclaration(cssProperty, pieces[1])); } declarationBuffer.setLength(0); } if (currentChar == '}') { parsingSelector = true; parsingDeclaration = false; cssRules.add(currentCSSRule); currentCSSRule = null; } } else { declarationBuffer.append((char)currentChar); } } prevChar = (char) currentChar; } return cssRules; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy