001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 The ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package org.conqat.lib.commons.html; 018 019import static org.conqat.lib.commons.html.ECSSProperty.BORDER_BOTTOM_COLOR; 020import static org.conqat.lib.commons.html.ECSSProperty.BORDER_BOTTOM_STYLE; 021import static org.conqat.lib.commons.html.ECSSProperty.BORDER_BOTTOM_WIDTH; 022import static org.conqat.lib.commons.html.ECSSProperty.BORDER_LEFT_COLOR; 023import static org.conqat.lib.commons.html.ECSSProperty.BORDER_LEFT_STYLE; 024import static org.conqat.lib.commons.html.ECSSProperty.BORDER_LEFT_WIDTH; 025import static org.conqat.lib.commons.html.ECSSProperty.BORDER_RIGHT_COLOR; 026import static org.conqat.lib.commons.html.ECSSProperty.BORDER_RIGHT_STYLE; 027import static org.conqat.lib.commons.html.ECSSProperty.BORDER_RIGHT_WIDTH; 028import static org.conqat.lib.commons.html.ECSSProperty.BORDER_TOP_COLOR; 029import static org.conqat.lib.commons.html.ECSSProperty.BORDER_TOP_STYLE; 030import static org.conqat.lib.commons.html.ECSSProperty.BORDER_TOP_WIDTH; 031import static org.conqat.lib.commons.html.ECSSProperty.MARGIN_BOTTOM; 032import static org.conqat.lib.commons.html.ECSSProperty.MARGIN_LEFT; 033import static org.conqat.lib.commons.html.ECSSProperty.MARGIN_RIGHT; 034import static org.conqat.lib.commons.html.ECSSProperty.MARGIN_TOP; 035import static org.conqat.lib.commons.html.ECSSProperty.PADDING_BOTTOM; 036import static org.conqat.lib.commons.html.ECSSProperty.PADDING_LEFT; 037import static org.conqat.lib.commons.html.ECSSProperty.PADDING_RIGHT; 038import static org.conqat.lib.commons.html.ECSSProperty.PADDING_TOP; 039 040import java.io.PrintStream; 041import java.util.ArrayList; 042import java.util.EnumMap; 043import java.util.List; 044import java.util.Map; 045 046/** 047 * This class describes a set of CSS declarations (property value pairs). 048 * Additionally it allows for simple multiple inheritance, where the properties 049 * of all inherited blocks are merged (including the block itself). The classes 050 * coming later in the inheritance list and the block itself will overwrite any 051 * properties defined multiple times. 052 */ 053public class CSSDeclarationBlock { 054 055 /** The properties and the values */ 056 private final Map<ECSSProperty, String> properties = new EnumMap<ECSSProperty, String>(ECSSProperty.class); 057 058 /** The list of blocks we inherit from. */ 059 private final List<CSSDeclarationBlock> inheritsFrom = new ArrayList<CSSDeclarationBlock>(); 060 061 /** 062 * Create new declaration block. 063 * 064 * @param values 065 * the property value pairs to add (so the number must be even). 066 */ 067 public CSSDeclarationBlock(Object... values) { 068 if (values.length % 2 != 0) { 069 throw new IllegalArgumentException("Expected even number of arguments"); 070 } 071 for (int i = 0; i < values.length; i += 2) { 072 if (!(values[i] instanceof ECSSProperty)) { 073 throw new IllegalArgumentException( 074 "Expected CSS property as parameter " + i + " instead of " + values[i].getClass()); 075 } 076 if (!(values[i + 1] instanceof String)) { 077 throw new IllegalArgumentException("Expected property value (String) as parameter " + (i + 1) 078 + " instead of " + values[i + 1].getClass()); 079 } 080 081 setProperty((ECSSProperty) values[i], (String) values[i + 1]); 082 } 083 } 084 085 /** 086 * Create new declaration block. 087 * 088 * @param superBlock 089 * the block to inherit from. 090 * @param values 091 * the property value pairs to add (so the number must be even). 092 */ 093 public CSSDeclarationBlock(CSSDeclarationBlock superBlock, Object... values) { 094 this(values); 095 inheritFrom(superBlock); 096 } 097 098 /** 099 * Adds a property to this block. Is a property with this name exists, it 100 * will be overwritten. 101 * 102 * @return this 103 */ 104 public CSSDeclarationBlock setProperty(ECSSProperty property, String value) { 105 properties.put(property, value); 106 return this; 107 } 108 109 /** 110 * Sets all given properties to the same value. 111 * 112 * @return this 113 */ 114 private CSSDeclarationBlock setProperties(String value, ECSSProperty... properties) { 115 for (ECSSProperty p : properties) { 116 setProperty(p, value); 117 } 118 return this; 119 } 120 121 /** 122 * Sets the margin to the given value. 123 * 124 * @return this 125 */ 126 public CSSDeclarationBlock setMargin(String value) { 127 return setProperties(value, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP); 128 } 129 130 /** 131 * Sets the padding to the given value. 132 * 133 * @return this 134 */ 135 public CSSDeclarationBlock setPadding(String value) { 136 return setProperties(value, PADDING_BOTTOM, PADDING_LEFT, PADDING_RIGHT, PADDING_TOP); 137 } 138 139 /** 140 * Sets the border to the given values. 141 * 142 * @return this 143 */ 144 public CSSDeclarationBlock setBorder(String width, String style, String color) { 145 setBorderWidth(width); 146 setBorderStyle(style); 147 setBorderColor(color); 148 return this; 149 } 150 151 /** 152 * Sets the border width to the given value. 153 * 154 * @return this 155 */ 156 public CSSDeclarationBlock setBorderWidth(String width) { 157 return setProperties(width, BORDER_BOTTOM_WIDTH, BORDER_LEFT_WIDTH, BORDER_RIGHT_WIDTH, BORDER_TOP_WIDTH); 158 } 159 160 /** 161 * Sets the border style to the given value. 162 * 163 * @return this 164 */ 165 public CSSDeclarationBlock setBorderStyle(String style) { 166 return setProperties(style, BORDER_BOTTOM_STYLE, BORDER_LEFT_STYLE, BORDER_RIGHT_STYLE, BORDER_TOP_STYLE); 167 } 168 169 /** 170 * Sets the border color to the given value. 171 * 172 * @return this 173 */ 174 public CSSDeclarationBlock setBorderColor(String color) { 175 return setProperties(color, BORDER_BOTTOM_COLOR, BORDER_LEFT_COLOR, BORDER_RIGHT_COLOR, BORDER_TOP_COLOR); 176 } 177 178 /** 179 * Removes the property from this block (whether it exists or not). 180 * 181 * @return this 182 */ 183 public CSSDeclarationBlock removeProperty(ECSSProperty property) { 184 properties.remove(property); 185 return this; 186 } 187 188 /** 189 * Returns the value of the property (or null if it is not defined for this 190 * block). 191 */ 192 public String getProperty(ECSSProperty property) { 193 return properties.get(property); 194 } 195 196 /** 197 * Adds another block to inherit from. 198 * 199 * @return this 200 */ 201 public CSSDeclarationBlock inheritFrom(CSSDeclarationBlock css) { 202 inheritsFrom.add(css); 203 return this; 204 } 205 206 /** 207 * Adds all properties (including those inherited) to the given map. Calling 208 * this with an empty map will result in a map containing the actual 209 * properties of this block. 210 */ 211 private void fillFullPropertyMap(Map<ECSSProperty, String> map) { 212 for (CSSDeclarationBlock block : inheritsFrom) { 213 block.fillFullPropertyMap(map); 214 } 215 map.putAll(properties); 216 } 217 218 /** 219 * Writes the full (including inherited) properties into the given stream 220 * using the format for CSS files, i.e. one property in each line followed 221 * by a colon, the value, and a semicolon. 222 */ 223 public void writeOut(PrintStream ps, String indent) { 224 Map<ECSSProperty, String> result = new EnumMap<ECSSProperty, String>(ECSSProperty.class); 225 fillFullPropertyMap(result); 226 227 for (ECSSProperty property : result.keySet()) { 228 ps.println(indent + property.getName() + ": " + result.get(property) + ";"); 229 } 230 } 231 232 /** 233 * Returns the full (including inherited) properties as a single line string 234 * using the format suitable for inline styles as used in HTML. 235 */ 236 public String toInlineStyle() { 237 StringBuilder sb = new StringBuilder(); 238 Map<ECSSProperty, String> result = new EnumMap<ECSSProperty, String>(ECSSProperty.class); 239 fillFullPropertyMap(result); 240 241 for (ECSSProperty property : result.keySet()) { 242 sb.append(property.getName() + ": " + result.get(property) + "; "); 243 } 244 return sb.toString(); 245 } 246}