KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > lobobrowser > html > style > StyleSheetAggregator


1 /*
2     GNU LESSER GENERAL PUBLIC LICENSE
3     Copyright (C) 2006 The Lobo Project
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19     Contact info: xamjadmin@users.sourceforge.net
20 */

21
22 package org.lobobrowser.html.style;
23
24 import java.net.MalformedURLException JavaDoc;
25 import java.util.*;
26
27 import org.lobobrowser.html.domimpl.HTMLDocumentImpl;
28 import org.lobobrowser.html.domimpl.HTMLElementImpl;
29 import org.w3c.dom.css.CSSImportRule;
30 import org.w3c.dom.css.CSSRule;
31 import org.w3c.dom.css.CSSRuleList;
32 import org.w3c.dom.css.CSSStyleRule;
33 import org.w3c.dom.css.CSSStyleSheet;
34
35 /**
36  * Aggregates all style sheets in a document.
37  * Every time a new STYLE element is found, it is
38  * added to the style sheet aggreagator by means
39  * of the {@link #addStyleSheet(CSSStyleSheet)} method.
40  * HTML elements have a <code>style</code> object
41  * that has a list of <code>CSSStyleDeclaration</code>
42  * instances. The instances inserted in that list
43  * are obtained by means of the {@link #getStyleDeclarations(HTMLElementImpl, String, String, String)}
44  * method.
45  * @author user
46  *
47  */

48 public class StyleSheetAggregator {
49     private final HTMLDocumentImpl document;
50     private final Map classMapsByElement = new HashMap();
51     private final Map idMapsByElement = new HashMap();
52     private final Map rulesByElement = new HashMap();
53     
54     public StyleSheetAggregator(HTMLDocumentImpl document) {
55         this.document = document;
56     }
57     
58     public final void addStyleSheets(Collection styleSheets) throws MalformedURLException JavaDoc {
59         Iterator i = styleSheets.iterator();
60         while(i.hasNext()) {
61             CSSStyleSheet sheet = (CSSStyleSheet) i.next();
62             this.addStyleSheet(sheet);
63         }
64     }
65
66     private final void addStyleSheet(CSSStyleSheet styleSheet) throws MalformedURLException JavaDoc {
67         CSSRuleList ruleList = styleSheet.getCssRules();
68         int length = ruleList.getLength();
69         HTMLDocumentImpl document = this.document;
70         for(int i = 0; i < length; i++) {
71             CSSRule rule = ruleList.item(i);
72             if(rule instanceof CSSStyleRule) {
73                 CSSStyleRule sr = (CSSStyleRule) rule;
74                 String JavaDoc selectorText = sr.getSelectorText();
75                 StringTokenizer commaTok = new StringTokenizer(selectorText, ",");
76                 while(commaTok.hasMoreTokens()) {
77                     String JavaDoc selectorPart = commaTok.nextToken().toLowerCase();
78                     ArrayList ancestorSelectors = null;
79                     String JavaDoc selector = null;
80                     StringTokenizer tok = new StringTokenizer(selectorPart, " \t\r\n");
81                     while(tok.hasMoreTokens()) {
82                         String JavaDoc token = tok.nextToken();
83                         if(tok.hasMoreTokens()) {
84                             if(ancestorSelectors == null) {
85                                 ancestorSelectors = new ArrayList();
86                             }
87                             ancestorSelectors.add(token);
88                         }
89                         else {
90                             selector = token;
91                             break;
92                         }
93                     }
94                     if(selector != null) {
95                         int dotIdx = selector.indexOf('.');
96                         if(dotIdx != -1) {
97                             String JavaDoc elemtl = selector.substring(0, dotIdx);
98                             String JavaDoc classtl = selector.substring(dotIdx+1);
99                             this.addClassRule(elemtl, classtl, sr, ancestorSelectors);
100                         }
101                         else {
102                             int poundIdx = selector.indexOf('#');
103                             if(poundIdx != -1) {
104                                 String JavaDoc elemtl = selector.substring(0, poundIdx);
105                                 String JavaDoc idtl = selector.substring(poundIdx+1);
106                                 this.addIdRule(elemtl, idtl, sr, ancestorSelectors);
107                             }
108                             else {
109                                 String JavaDoc elemtl = selector;
110                                 this.addElementRule(elemtl, sr, ancestorSelectors);
111                             }
112                         }
113                     }
114                 }
115                 //TODO: Other types of selectors
116
//TODO: Stuff such as navbar:hover.
117
}
118             else if(rule instanceof CSSImportRule) {
119                 CSSImportRule importRule = (CSSImportRule) rule;
120                 if(CSSUtilities.matchesMedia(importRule.getMedia(), document.getHtmlRendererContext())) {
121                     String JavaDoc href = importRule.getHref();
122                     String JavaDoc styleHref = styleSheet.getHref();
123                     String JavaDoc baseHref = styleHref == null ? this.document.getBaseURI() : styleHref;
124                     CSSStyleSheet sheet = CSSUtilities.parse(href, this.document, baseHref, false);
125                     if(sheet != null) {
126                         this.addStyleSheet(sheet);
127                     }
128                 }
129             }
130         }
131     }
132
133     private final void addClassRule(String JavaDoc elemtl, String JavaDoc classtl, CSSStyleRule styleRule, ArrayList ancestorSelectors) {
134         Map classMap = (Map) this.classMapsByElement.get(elemtl);
135         if(classMap == null) {
136             classMap = new HashMap();
137             this.classMapsByElement.put(elemtl, classMap);
138         }
139         Collection rules = (Collection) classMap.get(classtl);
140         if(rules == null) {
141             rules = new LinkedList();
142             classMap.put(classtl, rules);
143         }
144         rules.add(new StyleRuleInfo(ancestorSelectors, styleRule));
145     }
146     
147     private final void addIdRule(String JavaDoc elemtl, String JavaDoc idtl, CSSStyleRule styleRule, ArrayList ancestorSelectors) {
148         Map idsMap = (Map) this.idMapsByElement.get(elemtl);
149         if(idsMap == null) {
150             idsMap = new HashMap();
151             this.idMapsByElement.put(elemtl, idsMap);
152         }
153         Collection rules = (Collection) idsMap.get(idtl);
154         if(rules == null) {
155             rules = new LinkedList();
156             idsMap.put(idtl, rules);
157         }
158         rules.add(new StyleRuleInfo(ancestorSelectors, styleRule));
159     }
160     
161     private final void addElementRule(String JavaDoc elemtl, CSSStyleRule styleRule, ArrayList ancestorSelectors) {
162         Collection rules = (Collection) this.rulesByElement.get(elemtl);
163         if(rules == null) {
164             rules = new LinkedList();
165             this.rulesByElement.put(elemtl, rules);
166         }
167         rules.add(new StyleRuleInfo(ancestorSelectors, styleRule));
168     }
169     
170     
171     public final Collection getStyleDeclarations(HTMLElementImpl element, String JavaDoc elementName, String JavaDoc elementId, String JavaDoc className) {
172         Collection styleDeclarations = null;
173         String JavaDoc elementTL = elementName.toLowerCase();
174         Collection elementRules = (Collection) this.rulesByElement.get(elementTL);
175         if(elementRules != null) {
176             Iterator i = elementRules.iterator();
177             while(i.hasNext()) {
178                 StyleRuleInfo styleRuleInfo = (StyleRuleInfo) i.next();
179                 if(styleRuleInfo.matches(element)) {
180                     CSSStyleRule styleRule = styleRuleInfo.styleRule;
181                     if(styleDeclarations == null) {
182                         styleDeclarations = new LinkedList();
183                     }
184                     styleDeclarations.add(styleRule.getStyle());
185                 }
186                 else {
187                 }
188             }
189         }
190         elementRules = (Collection) this.rulesByElement.get("*");
191         if(elementRules != null) {
192             Iterator i = elementRules.iterator();
193             while(i.hasNext()) {
194                 StyleRuleInfo styleRuleInfo = (StyleRuleInfo) i.next();
195                 if(styleRuleInfo.matches(element)) {
196                     CSSStyleRule styleRule = styleRuleInfo.styleRule;
197                     if(styleDeclarations == null) {
198                         styleDeclarations = new LinkedList();
199                     }
200                     styleDeclarations.add(styleRule.getStyle());
201                 }
202             }
203         }
204         if(className != null) {
205             String JavaDoc classNameTL = className.toLowerCase();
206             Map classMaps = (Map) this.classMapsByElement.get(elementTL);
207             if(classMaps != null) {
208                 Collection classRules = (Collection) classMaps.get(classNameTL);
209                 if(classRules != null) {
210                     Iterator i = classRules.iterator();
211                     while(i.hasNext()) {
212                         StyleRuleInfo styleRuleInfo = (StyleRuleInfo) i.next();
213                         if(styleRuleInfo.matches(element)) {
214                             CSSStyleRule styleRule = styleRuleInfo.styleRule;
215                             if(styleDeclarations == null) {
216                                 styleDeclarations = new LinkedList();
217                             }
218                             styleDeclarations.add(styleRule.getStyle());
219                         }
220                     }
221                 }
222             }
223             classMaps = (Map) this.classMapsByElement.get("*");
224             if(classMaps != null) {
225                 Collection classRules = (Collection) classMaps.get(classNameTL);
226                 if(classRules != null) {
227                     Iterator i = classRules.iterator();
228                     while(i.hasNext()) {
229                         StyleRuleInfo styleRuleInfo = (StyleRuleInfo) i.next();
230                         if(styleRuleInfo.matches(element)) {
231                             CSSStyleRule styleRule = styleRuleInfo.styleRule;
232                             if(styleDeclarations == null) {
233                                 styleDeclarations = new LinkedList();
234                             }
235                             styleDeclarations.add(styleRule.getStyle());
236                         }
237                     }
238                 }
239             }
240         }
241         if(elementId != null) {
242             Map idMaps = (Map) this.idMapsByElement.get(elementTL);
243             if(idMaps != null) {
244                 String JavaDoc elementIdTL = elementId.toLowerCase();
245                 Collection idRules = (Collection) idMaps.get(elementIdTL);
246                 if(idRules != null) {
247                     Iterator i = idRules.iterator();
248                     while(i.hasNext()) {
249                         StyleRuleInfo styleRuleInfo = (StyleRuleInfo) i.next();
250                         if(styleRuleInfo.matches(element)) {
251                             CSSStyleRule styleRule = styleRuleInfo.styleRule;
252                             if(styleDeclarations == null) {
253                                 styleDeclarations = new LinkedList();
254                             }
255                             styleDeclarations.add(styleRule.getStyle());
256                         }
257                     }
258                 }
259             }
260             idMaps = (Map) this.idMapsByElement.get("*");
261             if(idMaps != null) {
262                 String JavaDoc elementIdTL = elementId.toLowerCase();
263                 Collection idRules = (Collection) idMaps.get(elementIdTL);
264                 if(idRules != null) {
265                     Iterator i = idRules.iterator();
266                     while(i.hasNext()) {
267                         StyleRuleInfo styleRuleInfo = (StyleRuleInfo) i.next();
268                         if(styleRuleInfo.matches(element)) {
269                             CSSStyleRule styleRule = styleRuleInfo.styleRule;
270                             if(styleDeclarations == null) {
271                                 styleDeclarations = new LinkedList();
272                             }
273                             styleDeclarations.add(styleRule.getStyle());
274                         }
275                     }
276                 }
277             }
278         }
279         return styleDeclarations;
280     }
281     
282     private static class StyleRuleInfo {
283         private final CSSStyleRule styleRule;
284         private final ArrayList ancestorSelectors;
285
286         /**
287          * @param selectors A collection of selectors already in lower case.
288          * @param rule A CSS rule.
289          */

290         public StyleRuleInfo(ArrayList selectors, CSSStyleRule rule) {
291             super();
292             ancestorSelectors = selectors;
293             styleRule = rule;
294         }
295         
296         public boolean matches(HTMLElementImpl element) {
297             //TODO: This method might be inefficient.
298
ArrayList as = this.ancestorSelectors;
299             if(as == null) {
300                 return true;
301             }
302             HTMLElementImpl currentElement = element;
303             int size = as.size();
304             for(int i = size; --i >= 0;) {
305                 String JavaDoc selector = (String JavaDoc) as.get(i);
306                 int dotIdx = selector.indexOf('.');
307                 if(dotIdx != -1) {
308                     String JavaDoc elemtl = selector.substring(0, dotIdx);
309                     String JavaDoc classtl = selector.substring(dotIdx+1);
310                     HTMLElementImpl ancestor = currentElement.getAncestorWithClass(elemtl, classtl);
311                     if(ancestor == null) {
312                         return false;
313                     }
314                     currentElement = ancestor;
315                 }
316                 else {
317                     int poundIdx = selector.indexOf('#');
318                     if(poundIdx != -1) {
319                         String JavaDoc elemtl = selector.substring(0, poundIdx);
320                         String JavaDoc idtl = selector.substring(poundIdx+1);
321                         HTMLElementImpl ancestor = currentElement.getAncestorWithId(elemtl, idtl);
322                         if(ancestor == null) {
323                             return false;
324                         }
325                         currentElement = ancestor;
326                     }
327                     else {
328                         String JavaDoc elemtl = selector;
329                         HTMLElementImpl ancestor = currentElement.getAncestor(elemtl);
330                         if(ancestor == null) {
331                             return false;
332                         }
333                         currentElement = ancestor;
334                     }
335                 }
336             }
337             return true;
338         }
339     }
340     
341 }
342
Popular Tags