Source for javax.swing.text.html.StyleSheet

   1: /* StyleSheet.java -- 
   2:    Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.text.html;
  40: 
  41: import gnu.javax.swing.text.html.CharacterAttributeTranslator;
  42: 
  43: import java.awt.Color;
  44: import java.awt.Font;
  45: import java.awt.Graphics;
  46: 
  47: import java.io.IOException;
  48: import java.io.Reader;
  49: import java.io.Serializable;
  50: import java.io.StringReader;
  51: 
  52: import java.net.MalformedURLException;
  53: import java.net.URL;
  54: 
  55: import java.util.Enumeration;
  56: import java.util.Vector;
  57: 
  58: import javax.swing.text.AttributeSet;
  59: import javax.swing.text.Element;
  60: import javax.swing.text.MutableAttributeSet;
  61: import javax.swing.text.SimpleAttributeSet;
  62: import javax.swing.text.Style;
  63: import javax.swing.text.StyleContext;
  64: import javax.swing.text.View;
  65: 
  66: 
  67: /**
  68:  * This class adds support for defining the visual characteristics of HTML views
  69:  * being rendered. This enables views to be customized by a look-and-feel, mulitple
  70:  * views over the same model can be rendered differently. Each EditorPane has its 
  71:  * own StyleSheet, but by default one sheet will be shared by all of the HTMLEditorKit
  72:  * instances. An HTMLDocument can also have a StyleSheet, which holds specific CSS
  73:  * specs. 
  74:  * 
  75:  *  In order for Views to store less state and therefore be more lightweight, 
  76:  *  the StyleSheet can act as a factory for painters that handle some of the 
  77:  *  rendering tasks. Since the StyleSheet may be used by views over multiple
  78:  *  documents the HTML attributes don't effect the selector being used.
  79:  *  
  80:  *  The rules are stored as named styles, and other information is stored to 
  81:  *  translate the context of an element to a rule.
  82:  * 
  83:  * @author Lillian Angel (langel@redhat.com)
  84:  */
  85: public class StyleSheet extends StyleContext
  86: {
  87: 
  88:   /** The base URL */
  89:   URL base;
  90:   
  91:   /** Base font size (int) */
  92:   int baseFontSize;
  93:   
  94:   /** The style sheets stored. */
  95:   StyleSheet[] styleSheet;
  96:   
  97:   /**
  98:    * Constructs a StyleSheet.
  99:    */
 100:   public StyleSheet()
 101:   {
 102:     super();
 103:     baseFontSize = 4; // Default font size from CSS
 104:   }
 105: 
 106:   /**
 107:    * Gets the style used to render the given tag. The element represents the tag
 108:    * and can be used to determine the nesting, where the attributes will differ
 109:    * if there is nesting inside of elements.
 110:    * 
 111:    * @param t - the tag to translate to visual attributes
 112:    * @param e - the element representing the tag
 113:    * @return the set of CSS attributes to use to render the tag.
 114:    */
 115:   public Style getRule(HTML.Tag t, Element e)
 116:   {
 117:     // FIXME: Not implemented.
 118:     return null;
 119:   }
 120:   
 121:   /**
 122:    * Gets the rule that best matches the selector. selector is a space
 123:    * separated String of element names. The attributes of the returned 
 124:    * Style will change as rules are added and removed.
 125:    * 
 126:    * @param selector - the element names separated by spaces
 127:    * @return the set of CSS attributes to use to render
 128:    */
 129:   public Style getRule(String selector)
 130:   {
 131:     // FIXME: Not implemented.
 132:     return null; 
 133:   }
 134:   
 135:   /**
 136:    * Adds a set if rules to the sheet. The rules are expected to be in valid
 137:    * CSS format. This is called as a result of parsing a <style> tag
 138:    * 
 139:    * @param rule - the rule to add to the sheet
 140:    */
 141:   public void addRule(String rule)
 142:   {
 143:     CssParser cp = new CssParser();
 144:     try
 145:     {
 146:       cp.parse(base, new StringReader(rule), false, false);
 147:     }
 148:     catch (IOException io)
 149:     {
 150:       // Do nothing here.
 151:     }
 152:   }
 153:   
 154:   /**
 155:    * Translates a CSS declaration into an AttributeSet. This is called
 156:    * as a result of encountering an HTML style attribute.
 157:    * 
 158:    * @param decl - the declaration to get
 159:    * @return the AttributeSet representing the declaration
 160:    */
 161:   public AttributeSet getDeclaration(String decl)
 162:   {
 163:     if (decl == null)
 164:       return SimpleAttributeSet.EMPTY;
 165:     // FIXME: Not implemented.
 166:     return null;     
 167:   }
 168:   
 169:   /**
 170:    * Loads a set of rules that have been specified in terms of CSS grammar.
 171:    * If there are any conflicts with existing rules, the new rule is added.
 172:    * 
 173:    * @param in - the stream to read the CSS grammar from.
 174:    * @param ref - the reference URL. It is the location of the stream, it may
 175:    * be null. All relative URLs specified in the stream will be based upon this
 176:    * parameter.
 177:    * @throws IOException - For any IO error while reading
 178:    */
 179:   public void loadRules(Reader in, URL ref) throws IOException
 180:   {
 181:     CssParser cp = new CssParser();
 182:     cp.parse(ref, in, false, false);
 183:   }
 184:   
 185:   /**
 186:    * Gets a set of attributes to use in the view. This is a set of
 187:    * attributes that can be used for View.getAttributes
 188:    * 
 189:    * @param v - the view to get the set for
 190:    * @return the AttributeSet to use in the view.
 191:    */
 192:   public AttributeSet getViewAttributes(View v)
 193:   {
 194:     // FIXME: Not implemented.
 195:     return null;
 196:   }
 197:   
 198:   /**
 199:    * Removes a style previously added.
 200:    * 
 201:    * @param nm - the name of the style to remove
 202:    */
 203:   public void removeStyle(String nm)
 204:   {
 205:     // FIXME: Not implemented.
 206:     super.removeStyle(nm);
 207:   }
 208:   
 209:   /**
 210:    * Adds the rules from ss to those of the receiver. ss's rules will
 211:    * override the old rules. An added StyleSheet will never override the rules
 212:    * of the receiving style sheet.
 213:    * 
 214:    * @param ss - the new StyleSheet.
 215:    */
 216:   public void addStyleSheet(StyleSheet ss)
 217:   {
 218:     if (styleSheet == null)
 219:       styleSheet = new StyleSheet[] {ss};
 220:     else
 221:       System.arraycopy(new StyleSheet[] {ss}, 0, styleSheet, 
 222:                        styleSheet.length, 1);
 223:   }
 224:   
 225:   /**
 226:    * Removes ss from those of the receiver
 227:    * 
 228:    * @param ss - the StyleSheet to remove.
 229:    */
 230:   public void removeStyleSheet(StyleSheet ss)
 231:   {
 232:     if (styleSheet.length == 1 && styleSheet[0].equals(ss))
 233:       styleSheet = null;
 234:     else
 235:       {
 236:         for (int i = 0; i < styleSheet.length; i++)
 237:           {
 238:             StyleSheet curr = styleSheet[i];
 239:             if (curr.equals(ss))
 240:               {
 241:                 StyleSheet[] tmp = new StyleSheet[styleSheet.length - 1];
 242:                 if (i != 0 && i != (styleSheet.length - 1))
 243:                   {
 244:                     System.arraycopy(styleSheet, 0, tmp, 0, i);
 245:                     System.arraycopy(styleSheet, i + 1, tmp, i,
 246:                                      styleSheet.length - i - 1);
 247:                   }
 248:                 else if (i == 0)
 249:                   System.arraycopy(styleSheet, 1, tmp, 0, styleSheet.length - 1);
 250:                 else
 251:                   System.arraycopy(styleSheet, 0, tmp, 0, styleSheet.length - 1);
 252:                 
 253:                 styleSheet = tmp;
 254:                 break;
 255:               }
 256:           }
 257:       }
 258:   }
 259:   
 260:   /**
 261:    * Returns an array of the linked StyleSheets. May return null.
 262:    * 
 263:    * @return - An array of the linked StyleSheets.
 264:    */
 265:   public StyleSheet[] getStyleSheets()
 266:   {
 267:     return styleSheet;
 268:   }
 269:   
 270:   /**
 271:    * Imports a style sheet from the url. The rules are directly added to the
 272:    * receiver.
 273:    * 
 274:    * @param url - the URL to import the StyleSheet from.
 275:    */
 276:   public void importStyleSheet(URL url)
 277:   {
 278:     // FIXME: Not implemented
 279:   }
 280:   
 281:   /**
 282:    * Sets the base url. All import statements that are relative, will be
 283:    * relative to base.
 284:    * 
 285:    * @param base -
 286:    *          the base URL.
 287:    */
 288:   public void setBase(URL base)
 289:   {
 290:     this.base = base;
 291:   }
 292:   
 293:   /**
 294:    * Gets the base url.
 295:    * 
 296:    * @return - the base
 297:    */
 298:   public URL getBase()
 299:   {
 300:     return base;
 301:   }
 302:   
 303:   /**
 304:    * Adds a CSS attribute to the given set.
 305:    * 
 306:    * @param attr - the attribute set
 307:    * @param key - the attribute to add
 308:    * @param value - the value of the key
 309:    */
 310:   public void addCSSAttribute(MutableAttributeSet attr, CSS.Attribute key,
 311:                               String value)
 312:   {
 313:     attr.addAttribute(key, value);
 314:   }
 315:   
 316:   /**
 317:    * Adds a CSS attribute to the given set.
 318:    * This method parses the value argument from HTML based on key. 
 319:    * Returns true if it finds a valid value for the given key, 
 320:    * and false otherwise.
 321:    * 
 322:    * @param attr - the attribute set
 323:    * @param key - the attribute to add
 324:    * @param value - the value of the key
 325:    * @return true if a valid value was found.
 326:    */
 327:   public boolean addCSSAttributeFromHTML(MutableAttributeSet attr, CSS.Attribute key,
 328:                                          String value)
 329:   {
 330:     // FIXME: Need to parse value from HTML based on key.
 331:     attr.addAttribute(key, value);
 332:     return attr.containsAttribute(key, value);
 333:   }
 334:   
 335:   /**
 336:    * Converts a set of HTML attributes to an equivalent set of CSS attributes.
 337:    * 
 338:    * @param htmlAttrSet - the set containing the HTML attributes.
 339:    * @return the set of CSS attributes
 340:    */
 341:   public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet)
 342:   {
 343:     // FIXME: Not implemented.
 344:     return null;    
 345:   }
 346: 
 347:   /**
 348:    * Adds an attribute to the given set and returns a new set. This is implemented
 349:    * to convert StyleConstants attributes to CSS before forwarding them to the superclass.
 350:    * The StyleConstants attribute do not have corresponding CSS entry, the attribute
 351:    * is stored (but will likely not be used).
 352:    * 
 353:    * @param old - the old set
 354:    * @param key - the non-null attribute key
 355:    * @param value - the attribute value
 356:    * @return the updated set 
 357:    */
 358:   public AttributeSet addAttribute(AttributeSet old, Object key,
 359:                                    Object value)
 360:   {
 361:     // FIXME: Not implemented.
 362:     return super.addAttribute(old, key, value);       
 363:   }
 364:   
 365:   /**
 366:    * Adds a set of attributes to the element. If any of these attributes are
 367:    * StyleConstants, they will be converted to CSS before forwarding to the 
 368:    * superclass.
 369:    * 
 370:    * @param old - the old set
 371:    * @param attr - the attributes to add
 372:    * @return the updated attribute set
 373:    */
 374:   public AttributeSet addAttributes(AttributeSet old, AttributeSet attr)
 375:   {
 376:     // FIXME: Not implemented.
 377:     return super.addAttributes(old, attr);           
 378:   }
 379:   
 380:   /**
 381:    * Removes an attribute from the set. If the attribute is a
 382:    * StyleConstants, it will be converted to CSS before forwarding to the 
 383:    * superclass.
 384:    * 
 385:    * @param old - the old set
 386:    * @param key - the non-null attribute key
 387:    * @return the updated set 
 388:    */
 389:   public AttributeSet removeAttribute(AttributeSet old, Object key)
 390:   {
 391:     // FIXME: Not implemented.
 392:     return super.removeAttribute(old, key);    
 393:   }
 394:   
 395:   /**
 396:    * Removes an attribute from the set. If any of the attributes are
 397:    * StyleConstants, they will be converted to CSS before forwarding to the 
 398:    * superclass.
 399:    * 
 400:    * @param old - the old set
 401:    * @param attrs - the attributes to remove
 402:    * @return the updated set 
 403:    */
 404:   public AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs)
 405:   {
 406:     // FIXME: Not implemented.
 407:     return super.removeAttributes(old, attrs);    
 408:   }
 409:   
 410:   /**
 411:    * Removes a set of attributes for the element. If any of the attributes is a
 412:    * StyleConstants, they will be converted to CSS before forwarding to the 
 413:    * superclass.
 414:    * 
 415:    * @param old - the old attribute set
 416:    * @param names - the attribute names
 417:    * @return the update attribute set
 418:    */
 419:   public AttributeSet removeAttributes(AttributeSet old, Enumeration names)
 420:   {
 421:     // FIXME: Not implemented.
 422:     return super.removeAttributes(old, names);        
 423:   }
 424:   
 425:   /**
 426:    * Creates a compact set of attributes that might be shared. This is a hook
 427:    * for subclasses that want to change the behaviour of SmallAttributeSet.
 428:    * 
 429:    * @param a - the set of attributes to be represented in the compact form.
 430:    * @return the set of attributes created
 431:    */
 432:   protected StyleContext.SmallAttributeSet createSmallAttributeSet(AttributeSet a)
 433:   {
 434:     return super.createSmallAttributeSet(a);     
 435:   }
 436:   
 437:   /**
 438:    * Creates a large set of attributes. This set is not shared. This is a hook
 439:    * for subclasses that want to change the behaviour of the larger attribute
 440:    * storage format.
 441:    * 
 442:    * @param a - the set of attributes to be represented in the larger form.
 443:    * @return the large set of attributes.
 444:    */
 445:   protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
 446:   {
 447:     return super.createLargeAttributeSet(a);     
 448:   }
 449:   
 450:   /**
 451:    * Gets the font to use for the given set.
 452:    * 
 453:    * @param a - the set to get the font for.
 454:    * @return the font for the set
 455:    */
 456:   public Font getFont(AttributeSet a)
 457:   {
 458:     return super.getFont(a);    
 459:   }
 460:   
 461:   /**
 462:    * Takes a set of attributes and turns it into a foreground
 463:    * color specification. This is used to specify things like, brigher, more hue
 464:    * etc.
 465:    * 
 466:    * @param a - the set to get the foreground color for
 467:    * @return the foreground color for the set
 468:    */
 469:   public Color getForeground(AttributeSet a)
 470:   {
 471:     return super.getForeground(a);     
 472:   }
 473:   
 474:   /**
 475:    * Takes a set of attributes and turns it into a background
 476:    * color specification. This is used to specify things like, brigher, more hue
 477:    * etc.
 478:    * 
 479:    * @param a - the set to get the background color for
 480:    * @return the background color for the set
 481:    */
 482:   public Color getBackground(AttributeSet a)
 483:   {
 484:     return super.getBackground(a);     
 485:   }
 486:   
 487:   /**
 488:    * Gets the box formatter to use for the given set of CSS attributes.
 489:    * 
 490:    * @param a - the given set
 491:    * @return the box formatter
 492:    */
 493:   public BoxPainter getBoxPainter(AttributeSet a)
 494:   {
 495:     return new BoxPainter(a);     
 496:   }
 497:   
 498:   /**
 499:    * Gets the list formatter to use for the given set of CSS attributes.
 500:    * 
 501:    * @param a - the given set
 502:    * @return the list formatter
 503:    */
 504:   public ListPainter getListPainter(AttributeSet a)
 505:   {
 506:     return new ListPainter(a);         
 507:   }
 508:   
 509:   /**
 510:    * Sets the base font size between 1 and 7.
 511:    * 
 512:    * @param sz - the new font size for the base.
 513:    */
 514:   public void setBaseFontSize(int sz)
 515:   {
 516:     if (sz <= 7 && sz >= 1)
 517:       baseFontSize = sz;
 518:   }
 519:   
 520:   /**
 521:    * Sets the base font size from the String. It can either identify
 522:    * a specific font size (between 1 and 7) or identify a relative
 523:    * font size such as +1 or -2.
 524:    * 
 525:    * @param size - the new font size as a String.
 526:    */
 527:   public void setBaseFontSize(String size)
 528:   {
 529:     size.trim();
 530:     int temp = 0;
 531:     try
 532:       {
 533:         if (size.length() == 2)
 534:           {
 535:             int i = new Integer(size.substring(1)).intValue();
 536:             if (size.startsWith("+"))
 537:               temp = baseFontSize + i;
 538:             else if (size.startsWith("-"))
 539:               temp = baseFontSize - i;
 540:           }
 541:         else if (size.length() == 1)
 542:           temp = new Integer(size.substring(0)).intValue();
 543: 
 544:         if (temp <= 7 && temp >= 1)
 545:           baseFontSize = temp;
 546:       }
 547:     catch (NumberFormatException nfe)
 548:       {
 549:         // Do nothing here
 550:       }
 551:   }
 552:   
 553:   /**
 554:    * TODO
 555:    * 
 556:    * @param pt - TODO
 557:    * @return TODO
 558:    */
 559:   public static int getIndexOfSize(float pt)
 560:   {
 561:     // FIXME: Not implemented.
 562:     return 0;
 563:   }
 564:   
 565:   /**
 566:    * Gets the point size, given a size index.
 567:    * 
 568:    * @param index - the size index
 569:    * @return the point size.
 570:    */
 571:   public float getPointSize(int index)
 572:   {
 573:     // FIXME: Not implemented.
 574:     return 0;    
 575:   }
 576:   
 577:   /**
 578:    * Given the string of the size, returns the point size value.
 579:    * 
 580:    * @param size - the string representation of the size.
 581:    * @return - the point size value.
 582:    */
 583:   public float getPointSize(String size)
 584:   {
 585:     // FIXME: Not implemented.
 586:     return 0;    
 587:   }
 588:   
 589:   /**
 590:    * Convert the color string represenation into java.awt.Color. The valid
 591:    * values are like "aqua" , "#00FFFF" or "rgb(1,6,44)".
 592:    * 
 593:    * @param colorName the color to convert.
 594:    * @return the matching java.awt.color
 595:    */
 596:   public Color stringToColor(String colorName)
 597:   {
 598:     return CharacterAttributeTranslator.getColor(colorName);
 599:   }
 600:   
 601:   /**
 602:    * This class carries out some of the duties of CSS formatting. This enables views
 603:    * to present the CSS formatting while not knowing how the CSS values are cached.
 604:    * 
 605:    * This object is reponsible for the insets of a View and making sure
 606:    * the background is maintained according to the CSS attributes.
 607:    * 
 608:    * @author Lillian Angel (langel@redhat.com)
 609:    */
 610:   public static class BoxPainter extends Object implements Serializable
 611:   {
 612:     
 613:     /**
 614:      * Attribute set for painter
 615:      */
 616:     AttributeSet as;
 617:     
 618:     /**
 619:      * Package-private constructor.
 620:      * 
 621:      * @param as - AttributeSet for painter
 622:      */
 623:     BoxPainter(AttributeSet as)
 624:     {
 625:       this.as = as;
 626:     }
 627:     
 628:     /**
 629:      * Gets the inset needed on a given side to account for the margin, border
 630:      * and padding.
 631:      * 
 632:      * @param size - the size of the box to get the inset for. View.TOP, View.LEFT,
 633:      * View.BOTTOM or View.RIGHT.
 634:      * @param v - the view making the request. This is used to get the AttributeSet,
 635:      * amd may be used to resolve percentage arguments.
 636:      * @return the inset
 637:      * @throws IllegalArgumentException - for an invalid direction.
 638:      */
 639:     public float getInset(int size, View v)
 640:     {
 641:       // FIXME: Not implemented.
 642:       return 0;       
 643:     }
 644:     
 645:     /**
 646:      * Paints the CSS box according to the attributes given. This should
 647:      * paint the border, padding and background.
 648:      * 
 649:      * @param g - the graphics configuration
 650:      * @param x - the x coordinate
 651:      * @param y - the y coordinate
 652:      * @param w - the width of the allocated area
 653:      * @param h - the height of the allocated area
 654:      * @param v - the view making the request
 655:      */
 656:     public void paint(Graphics g, float x, float y, float w, float h, View v)
 657:     {
 658:       // FIXME: Not implemented.
 659:     }
 660:   }
 661:   
 662:   /**
 663:    * This class carries out some of the CSS list formatting duties. Implementations
 664:    * of this class enable views to present the CSS formatting while not knowing anything
 665:    * about how the CSS values are being cached.
 666:    * 
 667:    * @author Lillian Angel (langel@redhat.com)
 668:    */
 669:   public static class ListPainter extends Object implements Serializable
 670:   {
 671:     
 672:     /**
 673:      * Attribute set for painter
 674:      */
 675:     AttributeSet as;
 676:     
 677:     /**
 678:      * Package-private constructor.
 679:      * 
 680:      * @param as - AttributeSet for painter
 681:      */
 682:     ListPainter(AttributeSet as)
 683:     {
 684:       this.as = as;
 685:     }
 686:     
 687:     /**
 688:      * Paints the CSS list decoration according to the attributes given.
 689:      * 
 690:      * @param g - the graphics configuration
 691:      * @param x - the x coordinate
 692:      * @param y - the y coordinate
 693:      * @param w - the width of the allocated area
 694:      * @param h - the height of the allocated area
 695:      * @param v - the view making the request
 696:      * @param item - the list item to be painted >=0.
 697:      */
 698:     public void paint(Graphics g, float x, float y, float w, float h, View v,
 699:                       int item)
 700:     {
 701:       // FIXME: Not implemented.
 702:     }
 703:   }
 704:   
 705:   /**
 706:    * The parser callback for the CSSParser.
 707:    */
 708:   class CssParser implements CSSParser.CSSParserCallback
 709:   {
 710:     /** 
 711:      * A vector of all the selectors. 
 712:      * Each element is an array of all the selector tokens 
 713:      * in a single rule. 
 714:      */
 715:     Vector selectors;
 716: 
 717:     /** A vector of all the selector tokens in a rule. */
 718:     Vector selectorTokens;
 719: 
 720:     /**  Name of the current property. */
 721:     String propertyName;
 722: 
 723:     /** The set of CSS declarations */
 724:     MutableAttributeSet declaration;
 725: 
 726:     /** 
 727:      * True if parsing a declaration, that is the Reader will not 
 728:      * contain a selector. 
 729:      */
 730:     boolean parsingDeclaration;
 731: 
 732:     /** True if the attributes are coming from a linked/imported style. */
 733:     boolean isLink;
 734: 
 735:     /** The base URL */
 736:     URL base;
 737: 
 738:     /** The parser */
 739:     CSSParser parser;
 740: 
 741:     /**
 742:      * Constructor
 743:      */
 744:     CssParser()
 745:     {
 746:       selectors = new Vector();
 747:       selectorTokens = new Vector();
 748:       parser = new CSSParser();
 749:       base = StyleSheet.this.base;
 750:       declaration = new SimpleAttributeSet();
 751:     }
 752: 
 753:     /**
 754:      * Parses the passed in CSS declaration into an AttributeSet.
 755:      * 
 756:      * @param s - the declaration
 757:      * @return the set of attributes containing the property and value.
 758:      */
 759:     public AttributeSet parseDeclaration(String s)
 760:     {
 761:       try
 762:       {
 763:         return parseDeclaration(new StringReader(s));
 764:       }
 765:       catch (IOException e)
 766:       {
 767:          // Do nothing here.
 768:       }
 769:       return null;
 770:     }
 771: 
 772:     /**
 773:      * Parses the passed in CSS declaration into an AttributeSet.
 774:      * 
 775:      * @param r - the reader
 776:      * @return the attribute set
 777:      * @throws IOException from the reader
 778:      */
 779:     public AttributeSet parseDeclaration(Reader r) throws IOException
 780:     {
 781:       parse(base, r, true, false);
 782:       return declaration;
 783:     }
 784: 
 785:     /**
 786:      * Parse the given CSS stream
 787:      * 
 788:      * @param base - the url
 789:      * @param r - the reader
 790:      * @param parseDec - True if parsing a declaration
 791:      * @param isLink - True if parsing a link
 792:      */
 793:    public void parse(URL base, Reader r, boolean parseDec, boolean isLink) throws IOException
 794:    {
 795:      parsingDeclaration = parseDec;
 796:      this.isLink = isLink;
 797:      this.base = base;
 798:      
 799:      // flush out all storage
 800:      propertyName = null;
 801:      selectors.clear();
 802:      selectorTokens.clear();
 803:      declaration.removeAttributes(declaration);
 804:      
 805:      parser.parse(r, this, parseDec);
 806:    }
 807: 
 808:    /**
 809:     * Invoked when a valid @import is encountered, 
 810:     * will call importStyleSheet if a MalformedURLException 
 811:     * is not thrown in creating the URL.
 812:     *
 813:     * @param s - the string after @import
 814:     */ 
 815:    public void handleImport(String s)
 816:     {
 817:       if (s != null)
 818:         {
 819:           try
 820:             {
 821:               if (s.startsWith("url(") && s.endsWith(")"))
 822:                 s = s.substring(4, s.length() - 1);
 823:               if (s.indexOf("\"") >= 0)
 824:                 s = s.replaceAll("\"","");
 825: 
 826:               URL url = new URL(s);
 827:               if (url == null && base != null)
 828:                 url = new URL(base, s);
 829:               
 830:               importStyleSheet(url);
 831:             }
 832:           catch (MalformedURLException e)
 833:             {
 834:               // Do nothing here.
 835:             }
 836:         }
 837:     }
 838: 
 839:    /**
 840:      * A selector has been encountered.
 841:      * 
 842:      * @param s - a selector (e.g. P or UL or even P,)
 843:      */
 844:    public void handleSelector(String s)
 845:    {
 846:      if (s.endsWith(","))
 847:        s = s.substring(0, s.length() - 1);
 848:      
 849:      selectorTokens.addElement(s);
 850:      addSelector();
 851:    }
 852: 
 853:    /**
 854:     * Invoked when the start of a rule is encountered.
 855:     */
 856:    public void startRule()
 857:    {
 858:      addSelector();
 859:    }
 860: 
 861:    /**
 862:     * Invoked when a property name is encountered.
 863:     *
 864:     * @param s - the property
 865:     */
 866:    public void handleProperty(String s)
 867:    {
 868:      propertyName = s;
 869:    }
 870: 
 871:   /**
 872:    * Invoked when a property value is encountered.
 873:    *
 874:    * @param s - the value
 875:    */
 876:    public void handleValue(String s)
 877:    {
 878:      // call addCSSAttribute
 879:      // FIXME: Not implemented
 880:    }
 881:    
 882:    /**
 883:     * Invoked when the end of a rule is encountered.
 884:     */
 885:    public void endRule()
 886:    {
 887:      // FIXME: Not implemented
 888:      // add rules
 889:      propertyName = null;
 890:    }
 891: 
 892:    /**
 893:     * Adds the selector to the vector.
 894:     */
 895:    private void addSelector()
 896:    {
 897:      int length = selectorTokens.size();
 898:      if (length > 0)
 899:        {
 900:          Object[] sel = new Object[length];
 901:          System.arraycopy(selectorTokens.toArray(), 0, sel, 0, length);
 902:          selectors.add(sel);
 903:          selectorTokens.clear();
 904:        }
 905:    }
 906:   }
 907: }