KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fo > properties > PropertyMaker


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: PropertyMaker.java 426576 2006-07-28 15:44:37Z jeremias $ */
19
20 package org.apache.fop.fo.properties;
21
22 import java.util.HashMap JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27
28 import org.apache.fop.datatypes.CompoundDatatype;
29 import org.apache.fop.datatypes.LengthBase;
30 import org.apache.fop.datatypes.PercentBase;
31 import org.apache.fop.fo.Constants;
32 import org.apache.fop.fo.FOPropertyMapping;
33 import org.apache.fop.fo.FObj;
34 import org.apache.fop.fo.PropertyList;
35 import org.apache.fop.fo.expr.PropertyException;
36 import org.apache.fop.fo.expr.PropertyInfo;
37 import org.apache.fop.fo.expr.PropertyParser;
38
39
40 /**
41  * Base class for all property makers
42  */

43 public class PropertyMaker implements Cloneable JavaDoc {
44
45     /** Logger instance */
46     private static Log log = LogFactory.getLog(PropertyMaker.class);
47
48     /** the property ID */
49     protected int propId;
50     private boolean inherited = true;
51     private Map JavaDoc enums = null;
52     private Map JavaDoc keywords = null;
53     /** the default value for the maker */
54     protected String JavaDoc defaultValue = null;
55     /** Indicates whether the property is context-dependant and therefore can't be cached. */
56     protected boolean contextDep = false;
57     /** Indicates whether the property is set through a shorthand. */
58     protected boolean setByShorthand = false;
59     private int percentBase = -1;
60     private PropertyMaker[] shorthands = null;
61     private ShorthandParser datatypeParser;
62
63     /** default property **/
64     protected Property defaultProperty;
65     /** Maker for 'corresponding' properties **/
66     protected CorrespondingPropertyMaker corresponding;
67
68     /**
69      * @return the name of the property for this Maker
70      */

71     public int getPropId() {
72         return propId;
73     }
74
75     /**
76      * Construct an instance of a Property.Maker for the given property.
77      * @param propId The Constant ID of the property to be made.
78      */

79     public PropertyMaker(int propId) {
80         this.propId = propId;
81     }
82
83     /**
84      * Copy all the values from the generic maker to this maker.
85      * @param generic a generic property maker.
86      */

87     public void useGeneric(PropertyMaker generic) {
88         contextDep = generic.contextDep;
89         inherited = generic.inherited;
90         defaultValue = generic.defaultValue;
91         percentBase = generic.percentBase;
92         if (generic.shorthands != null) {
93             shorthands = new PropertyMaker[generic.shorthands.length];
94             System.arraycopy(generic.shorthands, 0, shorthands, 0, shorthands.length);
95         }
96         if (generic.enums != null) {
97             enums = new HashMap JavaDoc(generic.enums);
98         }
99         if (generic.keywords != null) {
100             keywords = new HashMap JavaDoc(generic.keywords);
101         }
102     }
103
104     /**
105      * Set the inherited flag.
106      * @param inherited true if this is an inherited property
107      */

108     public void setInherited(boolean inherited) {
109         this.inherited = inherited;
110     }
111
112     /**
113      * Add a keyword-equiv to the maker.
114      * @param keyword the keyword
115      * @param value the value to be used when the keyword is specified
116      */

117     public void addKeyword(String JavaDoc keyword, String JavaDoc value) {
118         if (keywords == null) {
119             keywords = new HashMap JavaDoc();
120         }
121         keywords.put(keyword, value);
122     }
123
124     /**
125      * Add a enum constant.
126      * @param constant the enum constant
127      * @param value the Property value to use when the constant is specified
128      */

129     public void addEnum(String JavaDoc constant, Property value) {
130         if (enums == null) {
131             enums = new HashMap JavaDoc();
132         }
133         enums.put(constant, value);
134     }
135
136     /**
137      * Add a subproperty to this maker.
138      * @param subproperty the PropertyMaker for the subproperty
139      */

140     public void addSubpropMaker(PropertyMaker subproperty) {
141         throw new RuntimeException JavaDoc("Unable to add subproperties " + getClass());
142     }
143
144     /**
145      * Return a subproperty maker for the subpropertyId.
146      * @param subpropertyId The subpropertyId of the maker.
147      * @return The subproperty maker.
148      */

149     public PropertyMaker getSubpropMaker(int subpropertyId) {
150         throw new RuntimeException JavaDoc("Unable to add subproperties");
151     }
152
153     /**
154      * Add a shorthand to this maker. Only an Integer is added to the
155      * shorthands list. Later the Integers are replaced with references
156      * to the actual shorthand property makers.
157      * @param shorthand a property maker thar is that is checked for
158      * shorthand values.
159      */

160     public void addShorthand(PropertyMaker shorthand) {
161         if (shorthands == null) {
162             shorthands = new PropertyMaker[3];
163         }
164         for (int i = 0; i < shorthands.length; i++) {
165             if (shorthands[i] == null) {
166                 shorthands[i] = shorthand;
167                 break;
168             }
169         }
170     }
171
172     /**
173      * Set the shorthand datatype parser.
174      * @param parser the shorthand parser
175      */

176     public void setDatatypeParser(ShorthandParser parser) {
177         datatypeParser = parser;
178     }
179
180     /**
181      * Set the default value for this maker.
182      * @param defaultValue the default value.
183      */

184     public void setDefault(String JavaDoc defaultValue) {
185         this.defaultValue = defaultValue;
186     }
187
188     /**
189      * Set the default value for this maker.
190      * @param defaultValue the default value
191      * @param contextDep true when the value context dependent and
192      * must not be cached.
193      */

194     public void setDefault(String JavaDoc defaultValue, boolean contextDep) {
195         this.defaultValue = defaultValue;
196         this.contextDep = contextDep;
197     }
198
199     /**
200      * Set the percent base identifier for this maker.
201      * @param percentBase the percent base (ex. LengthBase.FONTSIZE)
202      */

203     public void setPercentBase(int percentBase) {
204         this.percentBase = percentBase;
205     }
206
207     /**
208      * Set the setByShorthand flag which only is applicable for subproperty
209      * makers. It should be true for the subproperties which must be
210      * assigned a value when the base property is assigned a attribute
211      * value directly.
212      * @param setByShorthand true if this subproperty must be set when the base property is set
213      */

214     public void setByShorthand(boolean setByShorthand) {
215         this.setByShorthand = setByShorthand;
216     }
217
218     /**
219      * Set the correspoding property information.
220      * @param corresponding a corresponding maker where the
221      * isForcedCorresponding and compute methods are delegated to.
222      */

223     public void setCorresponding(CorrespondingPropertyMaker corresponding) {
224         this.corresponding = corresponding;
225     }
226
227     /**
228      * Create a new empty property. Must be overriden in compound
229      * subclasses.
230      * @return a new instance of the Property for which this is a maker.
231      */

232     public Property makeNewProperty() {
233         return null;
234     }
235
236     /**
237      * If the property is a relative property with a corresponding absolute
238      * value specified, the absolute value is used. This is also true of
239      * the inheritance priority (I think...)
240      * If the property is an "absolute" property and it isn't specified, then
241      * we try to compute it from the corresponding relative property: this
242      * happens in computeProperty.
243      * @param propertyList the applicable property list
244      * @param tryInherit true if inherited properties should be examined.
245      * @return the property value
246      * @throws PropertyException if there is a problem evaluating the property
247      */

248     public Property findProperty(PropertyList propertyList,
249                                  boolean tryInherit)
250                 throws PropertyException {
251         Property p = null;
252         
253         if (log.isTraceEnabled()) {
254             log.trace("PropertyMaker.findProperty: "
255                   + FOPropertyMapping.getPropertyName(propId)
256                   + ", " + propertyList.getFObj().getName());
257         }
258
259         if (corresponding != null && corresponding.isCorrespondingForced(propertyList)) {
260             p = corresponding.compute(propertyList);
261         } else {
262             p = propertyList.getExplicit(propId);
263             if (p == null) { // check for shorthand specification
264
p = getShorthand(propertyList);
265             }
266             if (p == null) {
267                 p = this.compute(propertyList);
268             }
269         }
270         if (p == null && tryInherit) {
271             // else inherit (if has parent and is inheritable)
272
PropertyList parentPropertyList = propertyList.getParentPropertyList();
273             if (parentPropertyList != null && isInherited()) {
274                 p = parentPropertyList.get(propId, true, false);
275             }
276         }
277         return p;
278     }
279
280     /**
281      * Return the property on the current FlowObject. Depending on the passed flags,
282      * this will try to compute it based on other properties, or if it is
283      * inheritable, to return the inherited value. If all else fails, it returns
284      * the default value.
285      * @param subpropertyId The subproperty id of the property being retrieved.
286      * Is 0 when retriving a base property.
287      * @param propertyList The PropertyList object being built for this FO.
288      * @param tryInherit true if inherited properties should be examined.
289      * @param tryDefault true if the default value should be returned.
290      * @return the property value
291      * @throws PropertyException if there is a problem evaluating the property
292      */

293     public Property get(int subpropertyId, PropertyList propertyList,
294                         boolean tryInherit, boolean tryDefault)
295                     throws PropertyException {
296         Property p = findProperty(propertyList, tryInherit);
297
298         if (p == null && tryDefault) { // default value for this FO!
299
p = make(propertyList);
300         }
301         return p;
302     }
303
304     /**
305      * Default implementation of isInherited.
306      * @return A boolean indicating whether this property is inherited.
307      */

308     public boolean isInherited() {
309         return inherited;
310     }
311
312     /**
313      * This is used to handle properties specified as a percentage of
314      * some "base length", such as the content width of their containing
315      * box.
316      * Overridden by subclasses which allow percent specifications. See
317      * the documentation on properties.xsl for details.
318      * @param fo the FObj containing the PercentBase
319      * @param pl the PropertyList containing the property. (TODO: explain
320      * what this is used for, or remove it from the signature.)
321      * @return an object implementing the PercentBase interface.
322      * @throws PropertyException if there is a problem while evaluating the base property
323      */

324     public PercentBase getPercentBase(FObj fo, PropertyList pl) throws PropertyException {
325         if (percentBase == -1) {
326             return null;
327         } else {
328             return new LengthBase(fo, pl, percentBase);
329         }
330     }
331
332     /**
333      * Return a property value for the given component of a compound
334      * property.
335      * @param p A property value for a compound property type such as
336      * SpaceProperty.
337      * @param subpropertyId the id of the component whose value is to be
338      * returned.
339      * NOTE: this is only to ease porting when calls are made to
340      * PropertyList.get() using a component name of a compound property,
341      * such as get("space.optimum"). The recommended technique is:
342      * get("space").getOptimum().
343      * Overridden by property maker subclasses which handle
344      * compound properties.
345      * @return the Property containing the subproperty
346      */

347     public Property getSubprop(Property p, int subpropertyId) {
348         CompoundDatatype val = (CompoundDatatype) p.getObject();
349         return val.getComponent(subpropertyId);
350     }
351
352     /**
353      * Set a component in a compound property and return the modified
354      * compound property object.
355      * This default implementation returns the original base property
356      * without modifying it.
357      * It is overridden by property maker subclasses which handle
358      * compound properties.
359      * @param baseProperty The Property object representing the compound property,
360      * such as SpaceProperty.
361      * @param subpropertyId The ID of the component whose value is specified.
362      * @param subproperty A Property object holding the specified value of the
363      * component to be set.
364      * @return The modified compound property object.
365      */

366     protected Property setSubprop(Property baseProperty, int subpropertyId,
367                                   Property subproperty) {
368         CompoundDatatype val = (CompoundDatatype) baseProperty.getObject();
369         val.setComponent(subpropertyId, subproperty, false);
370         return baseProperty;
371     }
372
373     /**
374      * Return the default value.
375      * @param propertyList The PropertyList object being built for this FO.
376      * @return the Property object corresponding to the parameters
377      * @throws PropertyException for invalid or inconsisten FO input
378      */

379     public Property make(PropertyList propertyList) throws PropertyException {
380         if (defaultProperty != null) {
381             if (log.isTraceEnabled()) {
382                 log.trace("PropertyMaker.make: reusing defaultProperty, "
383                       + FOPropertyMapping.getPropertyName(propId));
384             }
385             return defaultProperty;
386         }
387         if (log.isTraceEnabled()) {
388             log.trace("PropertyMaker.make: making default property value, "
389                   + FOPropertyMapping.getPropertyName(propId)
390                   + ", " + propertyList.getFObj().getName());
391         }
392         Property p = make(propertyList, defaultValue, propertyList.getParentFObj());
393         if (!contextDep) {
394             defaultProperty = p;
395         }
396         return p;
397     }
398
399     /**
400      * Create a Property object from an attribute specification.
401      * @param propertyList The PropertyList object being built for this FO.
402      * @param value The attribute value.
403      * @param fo The parent FO for the FO whose property is being made.
404      * @return The initialized Property object.
405      * @throws PropertyException for invalid or inconsistent FO input
406      */

407      public Property make(PropertyList propertyList, String JavaDoc value,
408                          FObj fo) throws PropertyException {
409         try {
410             Property newProp = null;
411             String JavaDoc pvalue = value;
412             if ("inherit".equals(value)) {
413                 newProp = propertyList.getFromParent(this.propId & Constants.PROPERTY_MASK);
414                 if ((propId & Constants.COMPOUND_MASK) != 0) {
415                     newProp = getSubprop(newProp, propId & Constants.COMPOUND_MASK);
416                 }
417                 if (!isInherited() && log.isWarnEnabled()) {
418                     /* check whether explicit value is available on the parent
419                      * (for inherited properties, an inherited value will always
420                      * be available)
421                      */

422                     Property parentExplicit = propertyList.getParentPropertyList()
423                                                 .getExplicit(getPropId());
424                     if (parentExplicit == null) {
425                         log.warn(FOPropertyMapping.getPropertyName(getPropId())
426                                 + "=\"inherit\" on " + propertyList.getFObj().getName()
427                                 + ", but no explicit value found on the parent FO.");
428                     }
429                 }
430             } else {
431                 // Check for keyword shorthand values to be substituted.
432
pvalue = checkValueKeywords(pvalue);
433                 newProp = checkEnumValues(pvalue);
434             }
435             if (newProp == null) {
436                 // Override parsePropertyValue in each subclass of Property.Maker
437
newProp = PropertyParser.parse(pvalue,
438                                                   new PropertyInfo(this,
439                                                   propertyList, fo));
440             }
441             if (newProp != null) {
442                 newProp = convertProperty(newProp, propertyList, fo);
443             }
444             if (newProp == null) {
445                 throw new PropertyException("No conversion defined " + pvalue);
446             }
447             return newProp;
448         } catch (PropertyException propEx) {
449             propEx.setLocator(fo.getLocator());
450             propEx.setPropertyName(getName());
451             throw propEx;
452         }
453     }
454
455     /**
456      * Make a property value for a compound property. If the property
457      * value is already partially initialized, this method will modify it.
458      * @param baseProperty The Property object representing the compound property,
459      * for example: SpaceProperty.
460      * @param subpropertyId The Constants ID of the subproperty (component)
461      * whose value is specified.
462      * @param propertyList The propertyList being built.
463      * @param fo The parent FO for the FO whose property is being made.
464      * @param value the value of the
465      * @return baseProperty (or if null, a new compound property object) with
466      * the new subproperty added
467      * @throws PropertyException for invalid or inconsistent FO input
468      */

469     public Property make(Property baseProperty, int subpropertyId,
470                          PropertyList propertyList, String JavaDoc value,
471                          FObj fo) throws PropertyException {
472         //getLogger().error("compound property component "
473
// + partName + " unknown.");
474
return baseProperty;
475     }
476
477     /**
478      * Converts a shorthand property
479      *
480      * @param propertyList the propertyList for which to convert
481      * @param prop the shorthand property
482      * @param fo ...
483      * @return the converted property
484      * @throws PropertyException ...
485      */

486     public Property convertShorthandProperty(PropertyList propertyList,
487                                              Property prop, FObj fo)
488         throws PropertyException {
489         Property pret = convertProperty(prop, propertyList, fo);
490         if (pret == null) {
491             // If value is a name token, may be keyword or Enum
492
String JavaDoc sval = prop.getNCname();
493             if (sval != null) {
494                 //log.debug("Convert shorthand ncname " + sval);
495
pret = checkEnumValues(sval);
496                 if (pret == null) {
497                     /* Check for keyword shorthand values to be substituted. */
498                     String JavaDoc pvalue = checkValueKeywords(sval);
499                     if (!pvalue.equals(sval)) {
500                         //log.debug("Convert shorthand keyword" + pvalue);
501
// Substituted a value: must parse it
502
Property p = PropertyParser.parse(pvalue,
503                                                  new PropertyInfo(this,
504                                                                   propertyList,
505                                                                   fo));
506                         pret = convertProperty(p, propertyList, fo);
507                     }
508                 }
509             }
510         }
511         if (pret != null) {
512             /*
513              * log.debug("Return shorthand value " + pret.getString() +
514              * " for " + getPropName());
515              */

516         }
517         return pret;
518     }
519
520     /**
521      * For properties that contain enumerated values.
522      * This method should be overridden by subclasses.
523      * @param value the string containing the property value
524      * @return the Property encapsulating the enumerated equivalent of the
525      * input value
526      */

527     protected Property checkEnumValues(String JavaDoc value) {
528         if (enums != null) {
529             return (Property) enums.get(value);
530         }
531         return null;
532     }
533
534     /**
535      * Return a String to be parsed if the passed value corresponds to
536      * a keyword which can be parsed and used to initialize the property.
537      * For example, the border-width family of properties can have the
538      * initializers "thin", "medium", or "thick". The FOPropertyMapping
539      * file specifies a length value equivalent for these keywords,
540      * such as "0.5pt" for "thin".
541      * @param keyword the string value of property attribute.
542      * @return a String containing a parseable equivalent or null if
543      * the passed value isn't a keyword initializer for this Property
544      */

545     protected String JavaDoc checkValueKeywords(String JavaDoc keyword) {
546         if (keywords != null) {
547             String JavaDoc value = (String JavaDoc)keywords.get(keyword);
548             if (value != null) {
549                 return value;
550             }
551         }
552         // TODO: should return null here?
553
return keyword;
554     }
555
556     /**
557      * Return a Property object based on the passed Property object.
558      * This method is called if the Property object built by the parser
559      * isn't the right type for this property.
560      * It is overridden by subclasses.
561      * @param p The Property object return by the expression parser
562      * @param propertyList The PropertyList object being built for this FO.
563      * @param fo The parent FO for the FO whose property is being made.
564      * @return A Property of the correct type or null if the parsed value
565      * can't be converted to the correct type.
566      * @throws PropertyException for invalid or inconsistent FO input
567      */

568     protected Property convertProperty(Property p,
569                                     PropertyList propertyList,
570                                     FObj fo) throws PropertyException {
571         return null;
572     }
573
574     /**
575      * For properties that have more than one legal way to be specified,
576      * this routine should be overridden to attempt to set them based upon
577      * the other methods. For example, colors may be specified using an RGB
578      * model, or they may be specified using an NCname.
579      * @param p property whose datatype should be converted
580      * @param propertyList collection of properties. (TODO: explain why
581      * this is needed, or remove it from the signature.)
582      * @param fo The parent FO for the FO whose property is being made.
583      * why this is needed, or remove it from the signature).
584      * @return an Property with the appropriate datatype used
585      * @throws PropertyException for invalid or inconsistent input
586      */

587     protected Property convertPropertyDatatype(Property p,
588                                                PropertyList propertyList,
589                                                FObj fo) throws PropertyException {
590         return null;
591     }
592
593     /**
594      * Return a Property object representing the value of this property,
595      * based on other property values for this FO.
596      * A special case is properties which inherit the specified value,
597      * rather than the computed value.
598      * @param propertyList The PropertyList for the FO.
599      * @return Property A computed Property value or null if no rules
600      * are specified to compute the value.
601      * @throws PropertyException for invalid or inconsistent FO input
602      */

603     protected Property compute(PropertyList propertyList)
604             throws PropertyException {
605         if (corresponding != null) {
606             return corresponding.compute(propertyList);
607         }
608         return null; // standard
609
}
610
611     /**
612      * For properties that can be set by shorthand properties, this method
613      * should return the Property, if any, that is parsed from any
614      * shorthand properties that affect this property.
615      * This method expects to be overridden by subclasses.
616      * For example, the border-right-width property could be set implicitly
617      * from the border shorthand property, the border-width shorthand
618      * property, or the border-right shorthand property. This method should
619      * be overridden in the appropriate subclass to check each of these, and
620      * return an appropriate border-right-width Property object.
621      * @param propertyList the collection of properties to be considered
622      * @return the Property, if found, the correspons, otherwise, null
623      * @throws PropertyException if there is a problem while evaluating the shorthand
624      */

625     public Property getShorthand(PropertyList propertyList)
626                 throws PropertyException {
627         if (shorthands == null) {
628             return null;
629         }
630         Property prop;
631         int n = shorthands.length;
632         for (int i = 0; i < n && shorthands[i] != null; i++) {
633             PropertyMaker shorthand = shorthands[i];
634             prop = propertyList.getExplicit(shorthand.propId);
635             if (prop != null) {
636                 ShorthandParser parser = shorthand.datatypeParser;
637                 Property p = parser.getValueForProperty(getPropId(),
638                                         prop, this, propertyList);
639                 if (p != null) {
640                     return p;
641                 }
642             }
643         }
644         return null;
645     }
646     
647     /** @return the name of the property this maker is used for. */
648     public String JavaDoc getName() {
649         return FOPropertyMapping.getPropertyName(propId);
650     }
651
652     /**
653      * Return a clone of the makers. Used by useGeneric() to clone the
654      * subproperty makers of the generic compound makers.
655      * @see java.lang.Object#clone()
656      */

657     public Object JavaDoc clone() {
658         try {
659             return super.clone();
660         } catch (CloneNotSupportedException JavaDoc exc) {
661             return null;
662         }
663     }
664 }
665
Popular Tags