| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.fo.properties; |
| |
| import org.apache.fop.datatypes.CompoundDatatype; |
| import org.apache.fop.fo.Constants; |
| import org.apache.fop.fo.FObj; |
| import org.apache.fop.fo.PropertyList; |
| import org.apache.fop.fo.expr.PropertyException; |
| |
| /** |
| * This class extends Property.Maker with support for sub-properties. |
| */ |
| public class CompoundPropertyMaker extends PropertyMaker { |
| /** |
| * The list of subproperty makers supported by this compound maker. |
| */ |
| private PropertyMaker[] subproperties |
| = new PropertyMaker[Constants.COMPOUND_COUNT]; |
| |
| /** |
| * The first subproperty maker which has a setByShorthand of true. |
| */ |
| private PropertyMaker shorthandMaker; |
| |
| /** |
| * Construct an instance of a CompoundPropertyMaker for the given property. |
| * @param propId The Constant ID of the property to be made. |
| */ |
| public CompoundPropertyMaker(int propId) { |
| super(propId); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void useGeneric(PropertyMaker generic) { |
| super.useGeneric(generic); |
| if (generic instanceof CompoundPropertyMaker) { |
| CompoundPropertyMaker compoundGeneric = (CompoundPropertyMaker) generic; |
| for (int i = 0; i < Constants.COMPOUND_COUNT; i++) { |
| PropertyMaker submaker = compoundGeneric.subproperties[i]; |
| if (submaker != null) { |
| addSubpropMaker((PropertyMaker) submaker.clone()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Add a subproperty to this maker. |
| * @param subproperty the sub property |
| */ |
| public void addSubpropMaker(PropertyMaker subproperty) { |
| // Place the base propId in the propId of the subproperty. |
| subproperty.propId &= Constants.COMPOUND_MASK; |
| subproperty.propId |= propId; |
| |
| subproperties[getSubpropIndex(subproperty.getPropId())] = subproperty; |
| |
| // Store the first subproperty with a setByShorthand. That subproperty |
| // will be used for converting a value set on the base property. |
| if (shorthandMaker == null && subproperty.setByShorthand) { |
| shorthandMaker = subproperty; |
| } |
| } |
| |
| |
| /** |
| * Return a Maker object which is used to set the values on components |
| * of compound property types, such as "space". |
| * Overridden by property maker subclasses which handle |
| * compound properties. |
| * @param subpropertyId the id of the component for which a Maker is to |
| * returned, for example CP_OPTIMUM, if the FO attribute is |
| * space.optimum='10pt'. |
| * @return the Maker object specified |
| */ |
| public PropertyMaker getSubpropMaker(int subpropertyId) { |
| return subproperties[getSubpropIndex(subpropertyId)]; |
| } |
| |
| /** |
| * Calculate the real value of a subproperty by unmasking and shifting |
| * the value into the range [0 - (COMPOUND_COUNT-1)]. |
| * The value is used as index into the subproperties array. |
| * @param subpropertyId the property id of the sub property. |
| * @return the array index. |
| */ |
| private int getSubpropIndex(int subpropertyId) { |
| return ((subpropertyId & Constants.COMPOUND_MASK) >> Constants.COMPOUND_SHIFT) - 1; |
| } |
| |
| /** |
| * For compound properties which can take enumerate values. |
| * Delegate the enumeration check to one of the subpropeties. |
| * @param value the string containing the property value |
| * @return the Property encapsulating the enumerated equivalent of the |
| * input value |
| */ |
| protected Property checkEnumValues(String value) { |
| Property result = null; |
| if (shorthandMaker != null) { |
| result = shorthandMaker.checkEnumValues(value); |
| } |
| if (result == null) { |
| result = super.checkEnumValues(value); |
| } |
| return result; |
| } |
| |
| /** |
| * Return the property on the current FlowObject. Depending on the passed flags, |
| * this will try to compute it based on other properties, or if it is |
| * inheritable, to return the inherited value. If all else fails, it returns |
| * the default value. |
| * @param subpropertyId The subproperty id of the property being retrieved. |
| * Is 0 when retriving a base property. |
| * @param propertyList The PropertyList object being built for this FO. |
| * @param tryInherit true if inherited properties should be examined. |
| * @param tryDefault true if the default value should be returned. |
| * @return the property |
| * @throws PropertyException if a property exception occurs |
| */ |
| public Property get(int subpropertyId, PropertyList propertyList, boolean tryInherit, |
| boolean tryDefault) throws PropertyException { |
| Property p = super.get(subpropertyId, propertyList, tryInherit, tryDefault); |
| if (subpropertyId != 0 && p != null) { |
| p = getSubprop(p, subpropertyId); |
| } |
| return p; |
| } |
| |
| /** |
| * Return a Property object based on the passed Property object. |
| * This method is called if the Property object built by the parser |
| * isn't the right type for this compound property. |
| * @param p The Property object return by the expression parser |
| * @param propertyList The PropertyList object being built for this FO. |
| * @param fo The parent FO for the FO whose property is being made. |
| * @return A Property of the correct type or null if the parsed value |
| * can't be converted to the correct type. |
| * @throws PropertyException for invalid or inconsistent FO input |
| */ |
| protected Property convertProperty(Property p, |
| PropertyList propertyList, |
| FObj fo) throws PropertyException { |
| // Delegate to the subproperty maker to do conversions. |
| p = shorthandMaker.convertProperty(p, propertyList, fo); |
| |
| if (p != null) { |
| Property prop = makeCompound(propertyList, fo); |
| CompoundDatatype pval = (CompoundDatatype) prop.getObject(); |
| for (int i = 0; i < Constants.COMPOUND_COUNT; i++) { |
| PropertyMaker submaker = subproperties[i]; |
| if (submaker != null && submaker.setByShorthand) { |
| pval.setComponent(submaker.getPropId() & Constants.COMPOUND_MASK, p, false); |
| } |
| } |
| return prop; |
| } |
| return null; |
| } |
| |
| /** |
| * Make a compound property with default values. |
| * @param propertyList The PropertyList object being built for this FO. |
| * @return the Property object corresponding to the parameters |
| * @throws PropertyException for invalid or inconsisten FO input |
| */ |
| public Property make(PropertyList propertyList) throws PropertyException { |
| if (defaultValue != null) { |
| return make(propertyList, defaultValue, propertyList.getParentFObj()); |
| } else { |
| return makeCompound(propertyList, propertyList.getParentFObj()); |
| } |
| } |
| |
| /** |
| * Create a Property object from an attribute specification. |
| * @param propertyList The PropertyList object being built for this FO. |
| * @param value The attribute value. |
| * @param fo The parent FO for the FO whose property is being made. |
| * @return The initialized Property object. |
| * @throws PropertyException for invalid or inconsistent FO input |
| */ |
| public Property make(PropertyList propertyList, String value, |
| FObj fo) throws PropertyException { |
| Property p = super.make(propertyList, value, fo); |
| p = convertProperty(p, propertyList, fo); |
| return p; |
| } |
| |
| /** |
| * Return a property value for a compound property. If the property |
| * value is already partially initialized, this method will modify it. |
| * @param baseProperty The Property object representing the compound property, |
| * for example: SpaceProperty. |
| * @param subpropertyId The Constants ID of the subproperty (component) |
| * whose value is specified. |
| * @param propertyList The propertyList being built. |
| * @param fo The parent FO for the FO whose property is being made. |
| * @param value the value of the |
| * @return baseProperty (or if null, a new compound property object) with |
| * the new subproperty added |
| * @throws PropertyException for invalid or inconsistent FO input |
| */ |
| public Property make(Property baseProperty, int subpropertyId, |
| PropertyList propertyList, String value, |
| FObj fo) throws PropertyException { |
| if (baseProperty == null) { |
| baseProperty = makeCompound(propertyList, fo); |
| } |
| |
| PropertyMaker spMaker = getSubpropMaker(subpropertyId); |
| |
| if (spMaker != null) { |
| Property p = spMaker.make(propertyList, value, fo); |
| if (p != null) { |
| return setSubprop(baseProperty, subpropertyId & Constants.COMPOUND_MASK, p); |
| } |
| } else { |
| //getLogger().error("compound property component " |
| // + partName + " unknown."); |
| } |
| return baseProperty; |
| } |
| |
| /** |
| * Create a empty compound property and fill it with default values for |
| * the subproperties. |
| * @param propertyList The propertyList being built. |
| * @param parentFO The parent FO for the FO whose property is being made. |
| * @return a Property subclass object holding a "compound" property object |
| * initialized to the default values for each component. |
| * @throws PropertyException ... |
| */ |
| protected Property makeCompound(PropertyList propertyList, FObj parentFO) |
| throws PropertyException { |
| Property p = makeNewProperty(); |
| CompoundDatatype data = (CompoundDatatype) p.getObject(); |
| for (int i = 0; i < Constants.COMPOUND_COUNT; i++) { |
| PropertyMaker subpropertyMaker = subproperties[i]; |
| if (subpropertyMaker != null) { |
| Property subproperty = subpropertyMaker.make(propertyList); |
| data.setComponent(subpropertyMaker.getPropId() |
| & Constants.COMPOUND_MASK, subproperty, true); |
| } |
| } |
| return p; |
| } |
| } |