1 /* |
|
2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: This class gets notified during the CSS file parsing |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 package com.nokia.tools.themeinstaller.cssparser; |
|
20 |
|
21 import java.awt.Color; |
|
22 import java.io.File; |
|
23 import java.io.FileReader; |
|
24 import java.io.Reader; |
|
25 import java.util.HashMap; |
|
26 import java.util.Vector; |
|
27 |
|
28 import org.w3c.css.sac.CSSException; |
|
29 import org.w3c.css.sac.DocumentHandler; |
|
30 import org.w3c.css.sac.InputSource; |
|
31 import org.w3c.css.sac.LexicalUnit; |
|
32 import org.w3c.css.sac.Parser; |
|
33 import org.w3c.css.sac.SACMediaList; |
|
34 import org.w3c.css.sac.SelectorList; |
|
35 import org.w3c.css.sac.helpers.ParserFactory; |
|
36 import org.w3c.dom.Document; |
|
37 |
|
38 import com.nokia.tools.themeinstaller.logger.LogWriter; |
|
39 |
|
40 /** |
|
41 * The Class CSSHandler. Informs application of basic parsing events. This |
|
42 * should be registered with CSS Parser with setDocumentHandler method. |
|
43 * |
|
44 * Handler gets notified during the CSS parsing: |
|
45 * 1. startSelector(), when new selector is noticed |
|
46 * 2. property(), when new property is noticed |
|
47 * 3. lexicalValue() is used to calculate the values of the parsed property |
|
48 * |
|
49 * If you are using CSS import with paths relative to main CSS, you need to |
|
50 * set the path of main CSS using setImportDirectory( String aImportDirectory ) |
|
51 */ |
|
52 |
|
53 public class CSSHandler implements DocumentHandler |
|
54 { |
|
55 |
|
56 /** The style map for style property. */ |
|
57 private HashMap iStyleMap; |
|
58 |
|
59 /** List of parsed rules. */ |
|
60 private Vector iRuleList; |
|
61 |
|
62 /** The DOM document. */ |
|
63 private Document iDocument; |
|
64 |
|
65 /** Color resolver for resolving colors in string form */ |
|
66 private ColorResolver iColorResolver; |
|
67 |
|
68 /** The main CSS directory for finding imported CSS File's relative path. */ |
|
69 private String iImportDirectory; |
|
70 |
|
71 /** The Constant FUNCTION_HSL. */ |
|
72 public static final String FUNCTION_HSL = "hsl"; |
|
73 |
|
74 /** The Constant COMMA. */ |
|
75 public static final String COMMA = ","; |
|
76 |
|
77 /** The Constant CHAR_APOSTROPHE. */ |
|
78 private static final char CHAR_APOSTROPHE = '"'; |
|
79 |
|
80 /** The Constant CHAR_SPACE. */ |
|
81 private static final char CHAR_SPACE = ' '; |
|
82 |
|
83 /** The Constant CHAR_COLON. */ |
|
84 private static final char CHAR_COLON = ':'; |
|
85 |
|
86 /** The Constant SEPARATOR. */ |
|
87 public static final String SEPARATOR = "|"; |
|
88 |
|
89 /** The Constant FORWARD_SLASH. */ |
|
90 public static final String FORWARD_SLASH = "/"; |
|
91 |
|
92 /** The Constant BACKWARD_SLASH. */ |
|
93 public static final String BACKWARD_SLASH = "\\"; |
|
94 |
|
95 /** The CSS to DOM Processor for applying changes to DOM. */ |
|
96 private CSSDOMProcessor iCSSDOMProcessor; |
|
97 |
|
98 /** |
|
99 * Instantiates a new CSS handler. |
|
100 */ |
|
101 public CSSHandler() |
|
102 { |
|
103 super(); |
|
104 iCSSDOMProcessor = new CSSDOMProcessor(); |
|
105 iStyleMap = new HashMap(); |
|
106 iRuleList = new Vector(); |
|
107 iColorResolver = new ColorResolver(); |
|
108 } |
|
109 |
|
110 /** |
|
111 * Instantiates a new CSS handler. This one is used for handling imported |
|
112 * CSS files |
|
113 * |
|
114 * @param aHandler The handler to retrieve previous rule list and DOM document |
|
115 * from |
|
116 */ |
|
117 private CSSHandler( CSSHandler aHandler ) |
|
118 { |
|
119 super(); |
|
120 iCSSDOMProcessor = new CSSDOMProcessor(); |
|
121 iStyleMap = new HashMap(); |
|
122 |
|
123 iRuleList = aHandler.iRuleList; |
|
124 iDocument = aHandler.iDocument; |
|
125 iColorResolver = new ColorResolver(); |
|
126 } |
|
127 |
|
128 /** |
|
129 * Sets the document. |
|
130 * |
|
131 * @param aDocument The new document |
|
132 */ |
|
133 public void setDocument( Document aDocument ) |
|
134 { |
|
135 iDocument = aDocument; |
|
136 } |
|
137 |
|
138 /** |
|
139 * Gets the document. |
|
140 * |
|
141 * @return the document |
|
142 */ |
|
143 public Document getDocument() |
|
144 { |
|
145 return iDocument; |
|
146 } |
|
147 |
|
148 /** |
|
149 * Sets the directory of main CSS. |
|
150 * |
|
151 * @param aImportDirectory The directory of main CSS |
|
152 */ |
|
153 public void setImportDirectory( String aImportDirectory ) |
|
154 { |
|
155 iImportDirectory = aImportDirectory; |
|
156 } |
|
157 |
|
158 /* |
|
159 * (non-Javadoc) |
|
160 * |
|
161 * @see org.w3c.css.sac.DocumentHandler#startDocument(org.w3c.css.sac.InputSource) |
|
162 */ |
|
163 public void startDocument( InputSource arg0 ) throws CSSException |
|
164 { |
|
165 iRuleList = new Vector(); |
|
166 } |
|
167 |
|
168 /* |
|
169 * (non-Javadoc) |
|
170 * |
|
171 * @see org.w3c.css.sac.DocumentHandler#startSelector(org.w3c.css.sac.SelectorList) |
|
172 */ |
|
173 public void startSelector( SelectorList aSelectorList ) throws CSSException |
|
174 { |
|
175 iStyleMap = new HashMap(); |
|
176 } |
|
177 |
|
178 /* |
|
179 * (non-Javadoc) |
|
180 * |
|
181 * @see org.w3c.css.sac.DocumentHandler#endSelector(org.w3c.css.sac.SelectorList) |
|
182 */ |
|
183 public void endSelector( SelectorList aSelectors ) throws CSSException |
|
184 { |
|
185 if ( iStyleMap.size() != 0 ) |
|
186 { |
|
187 for ( int i = 0; i < aSelectors.getLength(); i++ ) |
|
188 { |
|
189 // System.out.println("CSSHandler Selectors --> "+aSelectors.item(i)); |
|
190 CSSRule rule = new CSSRule( aSelectors.item( i ), iStyleMap ); |
|
191 iRuleList.add( rule ); |
|
192 } |
|
193 } |
|
194 } |
|
195 |
|
196 /* |
|
197 * (non-Javadoc) |
|
198 * |
|
199 * @see org.w3c.css.sac.DocumentHandler#property(java.lang.String, |
|
200 * org.w3c.css.sac.LexicalUnit, boolean) |
|
201 */ |
|
202 public void property( String aName, LexicalUnit aLexicalUnit, |
|
203 boolean aImportant ) throws CSSException |
|
204 { |
|
205 Vector propertyValues = new Vector(); |
|
206 lexicalValue( aLexicalUnit, propertyValues ); |
|
207 iStyleMap.put( aName, new CSSStyleProperty( propertyValues, aImportant ) ); |
|
208 } |
|
209 |
|
210 /* |
|
211 * (non-Javadoc) |
|
212 * |
|
213 * @see org.w3c.css.sac.DocumentHandler#endDocument(org.w3c.css.sac.InputSource) |
|
214 */ |
|
215 public void endDocument( InputSource aInputSource ) throws CSSException |
|
216 { |
|
217 if ( iDocument == null ) |
|
218 { |
|
219 throw new IllegalStateException( "CSSHandler has null DOM Document" ); |
|
220 } |
|
221 |
|
222 iCSSDOMProcessor.applyRulesToDom( iDocument, iRuleList ); |
|
223 } |
|
224 |
|
225 |
|
226 /** |
|
227 * Finds out the property values and adds them into a Vector |
|
228 * aPropertyValues. Property types that are taken into account are |
|
229 * from Symbian side: ...\Xuikon\Dom\src\xndompropertyvalue.cpp |
|
230 * |
|
231 * @param aLexicalUnit Value |
|
232 * @param aPropertyValues Vector for Property values |
|
233 */ |
|
234 public void lexicalValue( LexicalUnit aLexicalUnit, |
|
235 Vector aPropertyValues ) |
|
236 { |
|
237 while ( aLexicalUnit != null ) |
|
238 { |
|
239 switch ( aLexicalUnit.getLexicalUnitType() ) |
|
240 { |
|
241 case LexicalUnit.SAC_OPERATOR_COMMA: |
|
242 break; |
|
243 // Allowed cases for integer value |
|
244 case LexicalUnit.SAC_INTEGER: |
|
245 aPropertyValues |
|
246 .add( new CSSPropertyValue( |
|
247 LexicalUnit.SAC_INTEGER, Integer |
|
248 .toString( aLexicalUnit |
|
249 .getIntegerValue() ) ) ); |
|
250 break; |
|
251 // Allowed cases for real value |
|
252 // Fallthrough |
|
253 case LexicalUnit.SAC_REAL: |
|
254 case LexicalUnit.SAC_DIMENSION: |
|
255 case LexicalUnit.SAC_EM: |
|
256 case LexicalUnit.SAC_EX: |
|
257 case LexicalUnit.SAC_INCH: |
|
258 case LexicalUnit.SAC_PIXEL: |
|
259 case LexicalUnit.SAC_CENTIMETER: |
|
260 case LexicalUnit.SAC_MILLIMETER: |
|
261 case LexicalUnit.SAC_POINT: |
|
262 case LexicalUnit.SAC_PICA: |
|
263 case LexicalUnit.SAC_PERCENTAGE: |
|
264 case LexicalUnit.SAC_DEGREE: |
|
265 case LexicalUnit.SAC_GRADIAN: |
|
266 case LexicalUnit.SAC_RADIAN: |
|
267 case LexicalUnit.SAC_MILLISECOND: |
|
268 case LexicalUnit.SAC_SECOND: |
|
269 case LexicalUnit.SAC_HERTZ: |
|
270 case LexicalUnit.SAC_KILOHERTZ: |
|
271 aPropertyValues.add( new CSSPropertyValue( aLexicalUnit |
|
272 .getLexicalUnitType(), Float.toString( aLexicalUnit |
|
273 .getFloatValue() ) ) ); |
|
274 break; |
|
275 // RGB Values |
|
276 case LexicalUnit.SAC_RGBCOLOR: |
|
277 //Using StringBuffer to store values of RGB property |
|
278 //in order to handle values (R,G and B) as one value |
|
279 StringBuffer sb = new StringBuffer(); |
|
280 colorValue( aLexicalUnit.getParameters(), sb ); |
|
281 aPropertyValues.add( new CSSPropertyValue( aLexicalUnit |
|
282 .getLexicalUnitType(), sb.toString() ) ); |
|
283 break; |
|
284 // Allowed cases for string values |
|
285 // Fallthrough |
|
286 case LexicalUnit.SAC_URI: |
|
287 case LexicalUnit.SAC_IDENT: |
|
288 case LexicalUnit.SAC_STRING_VALUE: |
|
289 case LexicalUnit.SAC_ATTR: |
|
290 // Color value as string |
|
291 if ( iColorResolver.get( aLexicalUnit.getStringValue() ) != null ) |
|
292 { |
|
293 Color color = ( Color ) iColorResolver.get( aLexicalUnit |
|
294 .getStringValue() ); |
|
295 aPropertyValues.add( new CSSPropertyValue( |
|
296 LexicalUnit.SAC_RGBCOLOR, |
|
297 LexicalUnit.SAC_INTEGER + SEPARATOR |
|
298 + color.getRed() + COMMA |
|
299 + LexicalUnit.SAC_INTEGER + SEPARATOR |
|
300 + color.getGreen() + COMMA |
|
301 + LexicalUnit.SAC_INTEGER + SEPARATOR |
|
302 + color.getBlue() ) ); |
|
303 } |
|
304 // Space |
|
305 else if ( aLexicalUnit.getStringValue() |
|
306 .indexOf( CHAR_SPACE ) != -1 ) |
|
307 { |
|
308 aPropertyValues.add( new CSSPropertyValue( aLexicalUnit |
|
309 .getLexicalUnitType(), CHAR_APOSTROPHE |
|
310 + aLexicalUnit.getStringValue() |
|
311 + CHAR_APOSTROPHE ) ); |
|
312 } |
|
313 // Text |
|
314 else |
|
315 { |
|
316 aPropertyValues.add( new CSSPropertyValue( aLexicalUnit |
|
317 .getLexicalUnitType(), aLexicalUnit |
|
318 .getStringValue() ) ); |
|
319 } |
|
320 break; |
|
321 // In case value is set as "inherit" already in CSS -file |
|
322 // This sets it to DOM as Ident value that is "inherit" |
|
323 case LexicalUnit.SAC_INHERIT: |
|
324 aPropertyValues.add( new CSSPropertyValue( |
|
325 LexicalUnit.SAC_IDENT, |
|
326 CSSDOMProcessor.STRING_INHERIT ) ); |
|
327 break; |
|
328 case LexicalUnit.SAC_FUNCTION: |
|
329 String functionName = aLexicalUnit.getFunctionName(); |
|
330 if ( functionName.equals( FUNCTION_HSL ) ) |
|
331 { |
|
332 Color color = colorFromHsl( aLexicalUnit |
|
333 .getParameters() ); |
|
334 aPropertyValues.add( new CSSPropertyValue( |
|
335 LexicalUnit.SAC_RGBCOLOR, |
|
336 LexicalUnit.SAC_INTEGER + SEPARATOR |
|
337 + color.getRed() + COMMA |
|
338 + LexicalUnit.SAC_INTEGER + SEPARATOR |
|
339 + color.getGreen() + COMMA |
|
340 + LexicalUnit.SAC_INTEGER + SEPARATOR |
|
341 + color.getBlue() ) ); |
|
342 |
|
343 } |
|
344 else |
|
345 { |
|
346 throw new IllegalStateException( |
|
347 "Unknown CSS Function : " + functionName ); |
|
348 } |
|
349 break; |
|
350 default: |
|
351 break; |
|
352 } |
|
353 aLexicalUnit = aLexicalUnit.getNextLexicalUnit(); |
|
354 } |
|
355 } |
|
356 |
|
357 /** |
|
358 * Parses HSL Function using ColorResolver. |
|
359 * |
|
360 * @param aLexicalUnit Parameters containing color values |
|
361 * |
|
362 * @return the color |
|
363 */ |
|
364 private Color colorFromHsl( LexicalUnit aLexicalUnit ) |
|
365 { |
|
366 float h = 0; |
|
367 float s = 0; |
|
368 float l = 0; |
|
369 try |
|
370 { |
|
371 h = ( float ) aLexicalUnit.getIntegerValue(); |
|
372 aLexicalUnit = aLexicalUnit.getNextLexicalUnit() |
|
373 .getNextLexicalUnit(); |
|
374 s = aLexicalUnit.getFloatValue(); |
|
375 aLexicalUnit = aLexicalUnit.getNextLexicalUnit() |
|
376 .getNextLexicalUnit(); |
|
377 l = aLexicalUnit.getFloatValue(); |
|
378 } |
|
379 catch ( RuntimeException e ) |
|
380 { |
|
381 throw new IllegalStateException( "Illegal HSL Color values" ); |
|
382 } |
|
383 if ( aLexicalUnit.getNextLexicalUnit() != null ) |
|
384 { |
|
385 throw new IllegalStateException( "Too many parameters in HSL color" ); |
|
386 } |
|
387 return iColorResolver.hslToRgb( h, s, l ); |
|
388 } |
|
389 |
|
390 /** |
|
391 * Finds out the property values for RGB color and adds them into a |
|
392 * StringBuffer aProperty. |
|
393 * |
|
394 * @param aLexicalUnit Parameters containing color values |
|
395 * @param aProperty StringBuffer for storing property information |
|
396 */ |
|
397 public void colorValue( LexicalUnit aLexicalUnit, StringBuffer aProperty ) |
|
398 { |
|
399 while ( aLexicalUnit != null ) |
|
400 { |
|
401 switch ( aLexicalUnit.getLexicalUnitType() ) |
|
402 { |
|
403 // Operator "," |
|
404 case LexicalUnit.SAC_OPERATOR_COMMA: |
|
405 aProperty.append( COMMA ); |
|
406 break; |
|
407 case LexicalUnit.SAC_INTEGER: |
|
408 aProperty.append( aLexicalUnit.getLexicalUnitType() ); |
|
409 aProperty.append( SEPARATOR ); |
|
410 aProperty.append( aLexicalUnit.getIntegerValue() ); |
|
411 break; |
|
412 case LexicalUnit.SAC_PERCENTAGE: |
|
413 aProperty.append( LexicalUnit.SAC_INTEGER ); |
|
414 aProperty.append( SEPARATOR ); |
|
415 aProperty.append( iColorResolver |
|
416 .getColorValueFromPercentage( aLexicalUnit |
|
417 .getFloatValue() ) ); |
|
418 break; |
|
419 default: |
|
420 break; |
|
421 } |
|
422 aLexicalUnit = aLexicalUnit.getNextLexicalUnit(); |
|
423 } |
|
424 } |
|
425 |
|
426 /* |
|
427 * (non-Javadoc) |
|
428 * |
|
429 * @see org.w3c.css.sac.DocumentHandler#startFontFace () |
|
430 */ |
|
431 public void startFontFace() throws CSSException |
|
432 { |
|
433 } |
|
434 |
|
435 /* |
|
436 * (non-Javadoc) |
|
437 * |
|
438 * @see org.w3c.css.sac.DocumentHandler#startPage(java.lang.String, |
|
439 * java.lang.String) |
|
440 */ |
|
441 public void startPage( String arg0, String arg1 ) throws CSSException |
|
442 { |
|
443 } |
|
444 |
|
445 /* |
|
446 * (non-Javadoc) |
|
447 * |
|
448 * @see org.w3c.css.sac.DocumentHandler#endFontFace () |
|
449 */ |
|
450 public void endFontFace() throws CSSException |
|
451 { |
|
452 } |
|
453 |
|
454 /* |
|
455 * (non-Javadoc) |
|
456 * |
|
457 * @see org.w3c.css.sac.DocumentHandler#endPage(java.lang.String, |
|
458 * java.lang.String) |
|
459 */ |
|
460 public void endPage( String arg0, String arg1 ) throws CSSException |
|
461 { |
|
462 } |
|
463 |
|
464 /* |
|
465 * (non-Javadoc) |
|
466 * |
|
467 * @see org.w3c.css.sac.DocumentHandler#comment (java.lang.String) |
|
468 */ |
|
469 public void comment( String arg0 ) throws CSSException |
|
470 { |
|
471 } |
|
472 |
|
473 /* |
|
474 * (non-Javadoc) |
|
475 * |
|
476 * @see org.w3c.css.sac.DocumentHandler#endMedia (org.w3c.css.sac.SACMediaList) |
|
477 */ |
|
478 public void endMedia( SACMediaList arg0 ) throws CSSException |
|
479 { |
|
480 } |
|
481 |
|
482 /* |
|
483 * (non-Javadoc) |
|
484 * |
|
485 * @see org.w3c.css.sac.DocumentHandler#ignorableAtRule (java.lang.String) |
|
486 */ |
|
487 public void ignorableAtRule( String arg0 ) throws CSSException |
|
488 { |
|
489 } |
|
490 |
|
491 /* |
|
492 * (non-Javadoc) |
|
493 * |
|
494 * @see org.w3c.css.sac.DocumentHandler#importStyle (java.lang.String, |
|
495 * org.w3c.css.sac.SACMediaList, java.lang.String) |
|
496 */ |
|
497 public void importStyle( String aCSSFileName, SACMediaList aMedia, |
|
498 String aNameSpaceUri ) throws CSSException |
|
499 { |
|
500 try |
|
501 { |
|
502 CSSHandler handler = new CSSHandler( this ); |
|
503 ParserFactory factory = new ParserFactory(); |
|
504 |
|
505 Parser parser = factory.makeParser(); |
|
506 parser.setDocumentHandler( handler ); |
|
507 Reader r = null; |
|
508 |
|
509 File cssImport = new File( aCSSFileName ); |
|
510 if ( isAbsolutePath( aCSSFileName ) && cssImport.exists() ) |
|
511 { |
|
512 // The imported CSS file is given with absolute path |
|
513 r = new FileReader( aCSSFileName ); |
|
514 LogWriter.getInstance().logInfo( |
|
515 "Imported CSS : " + cssImport.getAbsolutePath() ); |
|
516 } |
|
517 else if ( !isAbsolutePath( aCSSFileName ) |
|
518 && iImportDirectory != null ) |
|
519 { |
|
520 // If the given imported CSS File is not found, |
|
521 // try to locate it using path relative to main CSS |
|
522 File relativeCSS = new File( iImportDirectory + File.separator |
|
523 + aCSSFileName ); |
|
524 r = new FileReader( relativeCSS ); |
|
525 LogWriter.getInstance().logInfo( |
|
526 "Imported CSS : " + relativeCSS.getAbsolutePath() ); |
|
527 } |
|
528 else |
|
529 { |
|
530 throw new IllegalStateException( |
|
531 "Can't resolve imported CSS File: " + aCSSFileName ); |
|
532 } |
|
533 |
|
534 InputSource is = new InputSource( r ); |
|
535 parser.parseStyleSheet( is ); |
|
536 } |
|
537 catch ( Exception e ) |
|
538 { |
|
539 throw new CSSException( e.getMessage() ); |
|
540 } |
|
541 } |
|
542 |
|
543 /** |
|
544 * Checks if path is absolute path. |
|
545 * Path is absolute if it starts with '/', '\' |
|
546 * or is of form [drive]:[path] |
|
547 * @param aFilePath the a file path |
|
548 * |
|
549 * @return true, if is absolute path |
|
550 */ |
|
551 private boolean isAbsolutePath( String aFilePath ) |
|
552 { |
|
553 if ( aFilePath.startsWith( FORWARD_SLASH ) ) |
|
554 { |
|
555 return true; |
|
556 } |
|
557 if ( aFilePath.startsWith( BACKWARD_SLASH ) ) |
|
558 { |
|
559 return true; |
|
560 } |
|
561 if ( aFilePath.length() > 1 && aFilePath.charAt( 1 ) == CHAR_COLON ) |
|
562 { |
|
563 return true; |
|
564 } |
|
565 return false; |
|
566 } |
|
567 |
|
568 /* |
|
569 * (non-Javadoc) |
|
570 * |
|
571 * @see org.w3c.css.sac.DocumentHandler#namespaceDeclaration(java.lang.String, |
|
572 * java.lang.String) |
|
573 */ |
|
574 public void namespaceDeclaration( String arg0, String arg1 ) |
|
575 throws CSSException |
|
576 { |
|
577 } |
|
578 |
|
579 /* |
|
580 * (non-Javadoc) |
|
581 * |
|
582 * @see org.w3c.css.sac.DocumentHandler#startMedia(org.w3c.css.sac.SACMediaList) |
|
583 */ |
|
584 public void startMedia( SACMediaList arg0 ) throws CSSException |
|
585 { |
|
586 } |
|
587 |
|
588 } |
|