001 /*--------------------------------------------------------------------------+
002 $Id: CSSManagerBase.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 java.io.PrintStream;
021 import java.util.IdentityHashMap;
022 import java.util.Map;
023
024 import edu.tum.cs.commons.collections.TwoDimHashMap;
025
026 /**
027 * This class is used for managing cascading style sheets. It keeps track of all
028 * declaration blocks and selectors used.
029 *
030 * @author hummelb
031 * @author $Author: juergens $
032 * @version $Rev: 26283 $
033 * @levd.rating GREEN Hash: D0645454B949512DFB3949CF2F8C7055
034 */
035 public abstract class CSSManagerBase {
036
037 /** Default declarations for elements (i.e. without class). */
038 private final TwoDimHashMap<EHTMLElement, ECSSPseudoClass, CSSDeclarationBlock> defaultDeclarations = new TwoDimHashMap<EHTMLElement, ECSSPseudoClass, CSSDeclarationBlock>();
039
040 /** The names the declaration blocks are registered with. */
041 private final Map<CSSDeclarationBlock, String> classNames = new IdentityHashMap<CSSDeclarationBlock, String>();
042
043 /** Counter used for generating unique CSS class names. */
044 private static int classCounter = 0;
045
046 /** Returns whether there is a default declaration for the given element. */
047 public boolean hasDefaultDeclaration(EHTMLElement element) {
048 return hasDefaultDeclaration(element, ECSSPseudoClass.NONE);
049 }
050
051 /** Returns whether there is a default declaration for the given element. */
052 public boolean hasDefaultDeclaration(EHTMLElement element,
053 ECSSPseudoClass pseudoClass) {
054 return defaultDeclarations.containsKey(element, pseudoClass);
055 }
056
057 /** Adds a single selector and its block to this manager. */
058 public final void addDefaultDeclaration(EHTMLElement element,
059 CSSDeclarationBlock block) {
060 addDefaultDeclaration(element, ECSSPseudoClass.NONE, block);
061 }
062
063 /** Adds a single selector and its block to this manager. */
064 public void addDefaultDeclaration(EHTMLElement element,
065 ECSSPseudoClass pseudoClass, CSSDeclarationBlock block) {
066 if (defaultDeclarations.containsKey(element, pseudoClass)) {
067 throw new IllegalStateException("May not add element " + element
068 + " twice.");
069 }
070 if (!element.allowsAttribute(EHTMLAttribute.STYLE)) {
071 throw new IllegalArgumentException("The given element "
072 + element.getName() + " does not support styles!");
073 }
074 defaultDeclarations.putValue(element, pseudoClass, block);
075 }
076
077 /**
078 * Returns the name of the CSS class used for this block. If the block is
079 * not yet known, it is registered with this manager.
080 */
081 public String getCSSClassName(CSSDeclarationBlock block) {
082 String name = classNames.get(block);
083 if (name == null) {
084 name = generateCSSClassName();
085 classNames.put(block, name);
086 }
087 return name;
088 }
089
090 /**
091 * Generates a suitable name for a CSS class. This may be overridden by
092 * subclasses. However it must be made sure, that the class names returned
093 * are unique and do not overlap with HTML element names.
094 */
095 protected String generateCSSClassName() {
096 return "CSSCLASS" + ++classCounter;
097 }
098
099 /**
100 * Write all selectors with their blocks to the given stream. The format is
101 * the one usually used in CSS files. This merely calls
102 * {@link #writeOutDefaultDeclarations(PrintStream)} and
103 * {@link #writeOutDeclarations(PrintStream)}.
104 */
105 protected void writeOut(PrintStream ps) {
106
107 writeOutDefaultDeclarations(ps);
108 writeOutDeclarations(ps);
109 }
110
111 /** Write out default declarations for element (i.e. without specific class). */
112 protected void writeOutDefaultDeclarations(PrintStream ps) {
113 for (EHTMLElement element : defaultDeclarations.getFirstKeys()) {
114 for (ECSSPseudoClass pseudocssClass : defaultDeclarations
115 .getSecondKeys(element)) {
116 String selector = element.getName() + pseudocssClass.getName();
117 writeBlock(defaultDeclarations
118 .getValue(element, pseudocssClass), selector, ps);
119 }
120 }
121 }
122
123 /** Write out declarations. */
124 protected void writeOutDeclarations(PrintStream ps) {
125 for (Map.Entry<CSSDeclarationBlock, String> entry : classNames
126 .entrySet()) {
127 writeBlock(entry.getKey(), "." + entry.getValue(), ps);
128 }
129 }
130
131 /** Writes a single block/selector pair to the given stream. */
132 private void writeBlock(CSSDeclarationBlock block, String selector,
133 PrintStream ps) {
134 ps.print(selector);
135 ps.println(" {");
136 block.writeOut(ps, " ");
137 ps.println("}");
138 ps.println();
139 }
140 }