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