001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: LengthRangeProperty.java 454018 2006-10-07 21:00:13Z pietsch $ */
019:
020: package org.apache.fop.fo.properties;
021:
022: import org.apache.fop.datatypes.CompoundDatatype;
023: import org.apache.fop.datatypes.Length;
024: import org.apache.fop.datatypes.PercentBaseContext;
025: import org.apache.fop.fo.FObj;
026: import org.apache.fop.fo.PropertyList;
027: import org.apache.fop.fo.expr.PropertyException;
028:
029: /**
030: * Superclass for properties that contain LengthRange values
031: */
032: public class LengthRangeProperty extends Property implements
033: CompoundDatatype {
034: private Property minimum;
035: private Property optimum;
036: private Property maximum;
037: private static final int MINSET = 1;
038: private static final int OPTSET = 2;
039: private static final int MAXSET = 4;
040: private int bfSet = 0; // bit field
041: private boolean consistent = false;
042:
043: /**
044: * Inner class for a Maker for LengthProperty objects
045: */
046: public static class Maker extends CompoundPropertyMaker {
047:
048: /**
049: * @param propId the id of the property for which a Maker should be created
050: */
051: public Maker(int propId) {
052: super (propId);
053: }
054:
055: /**
056: * Create a new empty instance of LengthRangeProperty.
057: * @return the new instance.
058: */
059: public Property makeNewProperty() {
060: return new LengthRangeProperty();
061: }
062:
063: private boolean isNegativeLength(Length len) {
064: return ((len instanceof PercentLength && ((PercentLength) len)
065: .getPercentage() < 0) || (len.isAbsolute() && len
066: .getValue() < 0));
067: }
068:
069: /**
070: * @see CompoundPropertyMaker#convertProperty
071: */
072: public Property convertProperty(Property p,
073: PropertyList propertyList, FObj fo)
074: throws PropertyException {
075:
076: if (p instanceof LengthRangeProperty) {
077: return p;
078: }
079:
080: if (this .propId == PR_BLOCK_PROGRESSION_DIMENSION
081: || this .propId == PR_INLINE_PROGRESSION_DIMENSION) {
082: Length len = p.getLength();
083: if (len != null) {
084: if (isNegativeLength(len)) {
085: log.warn(FObj.decorateWithContextInfo(
086: "Replaced negative value (" + len
087: + ") for " + getName()
088: + " with 0mpt", fo));
089: p = new FixedLength(0);
090: }
091: }
092: }
093:
094: return super .convertProperty(p, propertyList, fo);
095: }
096:
097: /**
098: * @see org.apache.fop.fo.properties.PropertyMaker#getSubprop(Property, int, Property)
099: */
100: protected Property setSubprop(Property baseProperty,
101: int subpropertyId, Property subproperty) {
102: CompoundDatatype val = (CompoundDatatype) baseProperty
103: .getObject();
104: if (this .propId == PR_BLOCK_PROGRESSION_DIMENSION
105: || this .propId == PR_INLINE_PROGRESSION_DIMENSION) {
106: Length len = subproperty.getLength();
107: if (len != null) {
108: if (isNegativeLength(len)) {
109: log.warn("Replaced negative value (" + len
110: + ") for " + getName() + " with 0mpt");
111: val.setComponent(subpropertyId,
112: new FixedLength(0), false);
113: return baseProperty;
114: }
115: }
116: }
117: val.setComponent(subpropertyId, subproperty, false);
118: return baseProperty;
119: }
120:
121: }
122:
123: /**
124: * @see org.apache.fop.datatypes.CompoundDatatype#setComponent(int, Property, boolean)
125: */
126: public void setComponent(int cmpId, Property cmpnValue,
127: boolean bIsDefault) {
128: if (cmpId == CP_MINIMUM) {
129: setMinimum(cmpnValue, bIsDefault);
130: } else if (cmpId == CP_OPTIMUM) {
131: setOptimum(cmpnValue, bIsDefault);
132: } else if (cmpId == CP_MAXIMUM) {
133: setMaximum(cmpnValue, bIsDefault);
134: }
135: }
136:
137: /**
138: * @see org.apache.fop.datatypes.CompoundDatatype#getComponent(int)
139: */
140: public Property getComponent(int cmpId) {
141: if (cmpId == CP_MINIMUM) {
142: return getMinimum(null);
143: } else if (cmpId == CP_OPTIMUM) {
144: return getOptimum(null);
145: } else if (cmpId == CP_MAXIMUM) {
146: return getMaximum(null);
147: } else {
148: return null; // SHOULDN'T HAPPEN
149: }
150: }
151:
152: /**
153: * Set minimum value to min.
154: * @param minimum A Length value specifying the minimum value for this
155: * LengthRange.
156: * @param bIsDefault If true, this is set as a "default" value
157: * and not a user-specified explicit value.
158: */
159: protected void setMinimum(Property minimum, boolean bIsDefault) {
160: this .minimum = minimum;
161: if (!bIsDefault) {
162: bfSet |= MINSET;
163: }
164: consistent = false;
165: }
166:
167: /**
168: * Set maximum value to max if it is >= optimum or optimum isn't set.
169: * @param max A Length value specifying the maximum value for this
170: * @param bIsDefault If true, this is set as a "default" value
171: * and not a user-specified explicit value.
172: */
173: protected void setMaximum(Property max, boolean bIsDefault) {
174: maximum = max;
175: if (!bIsDefault) {
176: bfSet |= MAXSET;
177: }
178: consistent = false;
179: }
180:
181: /**
182: * Set the optimum value.
183: * @param opt A Length value specifying the optimum value for this
184: * @param bIsDefault If true, this is set as a "default" value
185: * and not a user-specified explicit value.
186: */
187: protected void setOptimum(Property opt, boolean bIsDefault) {
188: optimum = opt;
189: if (!bIsDefault) {
190: bfSet |= OPTSET;
191: }
192: consistent = false;
193: }
194:
195: // Minimum is prioritaire, if explicit
196: private void checkConsistency(PercentBaseContext context) {
197: if (consistent) {
198: return;
199: }
200: if (context == null) {
201: return;
202: }
203: // Make sure max >= min
204: // Must also control if have any allowed enum values!
205:
206: if (!minimum.isAuto()
207: && !maximum.isAuto()
208: && minimum.getLength().getValue(context) > maximum
209: .getLength().getValue(context)) {
210: if ((bfSet & MINSET) != 0) {
211: // if minimum is explicit, force max to min
212: if ((bfSet & MAXSET) != 0) {
213: // Warning: min>max, resetting max to min
214: log.error("forcing max to min in LengthRange");
215: }
216: maximum = minimum;
217: } else {
218: minimum = maximum; // minimum was default value
219: }
220: }
221: // Now make sure opt <= max and opt >= min
222: if (!optimum.isAuto()
223: && !maximum.isAuto()
224: && optimum.getLength().getValue(context) > maximum
225: .getLength().getValue(context)) {
226: if ((bfSet & OPTSET) != 0) {
227: if ((bfSet & MAXSET) != 0) {
228: // Warning: opt > max, resetting opt to max
229: log.error("forcing opt to max in LengthRange");
230: optimum = maximum;
231: } else {
232: maximum = optimum; // maximum was default value
233: }
234: } else {
235: // opt is default and max is explicit or default
236: optimum = maximum;
237: }
238: } else if (!optimum.isAuto()
239: && !minimum.isAuto()
240: && optimum.getLength().getValue(context) < minimum
241: .getLength().getValue(context)) {
242: if ((bfSet & MINSET) != 0) {
243: // if minimum is explicit, force opt to min
244: if ((bfSet & OPTSET) != 0) {
245: log.error("forcing opt to min in LengthRange");
246: }
247: optimum = minimum;
248: } else {
249: minimum = optimum; // minimum was default value
250: }
251: }
252:
253: consistent = true;
254: }
255:
256: /**
257: * @param context Percentage evaluation context
258: * @return minimum length
259: */
260: public Property getMinimum(PercentBaseContext context) {
261: checkConsistency(context);
262: return this .minimum;
263: }
264:
265: /**
266: * @param context Percentage evaluation context
267: * @return maximum length
268: */
269: public Property getMaximum(PercentBaseContext context) {
270: checkConsistency(context);
271: return this .maximum;
272: }
273:
274: /**
275: * @param context Percentage evaluation context
276: * @return optimum length
277: */
278: public Property getOptimum(PercentBaseContext context) {
279: checkConsistency(context);
280: return this .optimum;
281: }
282:
283: /** @see java.lang.Object#toString() */
284: public String toString() {
285: return "LengthRange[" + "min:" + getMinimum(null).getObject()
286: + ", max:" + getMaximum(null).getObject() + ", opt:"
287: + getOptimum(null).getObject() + "]";
288: }
289:
290: /**
291: * @return this.lengthRange
292: */
293: public LengthRangeProperty getLengthRange() {
294: return this ;
295: }
296:
297: /**
298: * @return this.lengthRange cast as an Object
299: */
300: public Object getObject() {
301: return this;
302: }
303:
304: }
|