1 /*
2  * JasperReports - Free Java Reporting Library.
3  * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
4  * http://www.jaspersoft.com
5  *
6  * Unless you have purchased a commercial license agreement from Jaspersoft,
7  * the following license terms apply:
8  *
9  * This program is part of JasperReports.
10  *
11  * JasperReports is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * JasperReports is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
23  */

24 package net.sf.jasperreports.engine.fill;
25
26 import java.awt.Color;
27 import java.io.Serializable;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.TimeZone;
38 import java.util.UUID;
39
40 import net.sf.jasperreports.engine.JRConditionalStyle;
41 import net.sf.jasperreports.engine.JRConstants;
42 import net.sf.jasperreports.engine.JRDefaultStyleProvider;
43 import net.sf.jasperreports.engine.JRElement;
44 import net.sf.jasperreports.engine.JRElementGroup;
45 import net.sf.jasperreports.engine.JRException;
46 import net.sf.jasperreports.engine.JRExpression;
47 import net.sf.jasperreports.engine.JRExpressionChunk;
48 import net.sf.jasperreports.engine.JRGroup;
49 import net.sf.jasperreports.engine.JROrigin;
50 import net.sf.jasperreports.engine.JRPrintElement;
51 import net.sf.jasperreports.engine.JRPropertiesHolder;
52 import net.sf.jasperreports.engine.JRPropertiesMap;
53 import net.sf.jasperreports.engine.JRPropertyExpression;
54 import net.sf.jasperreports.engine.JRStyle;
55 import net.sf.jasperreports.engine.JRStyleSetter;
56 import net.sf.jasperreports.engine.JasperPrint;
57 import net.sf.jasperreports.engine.base.JRBaseStyle;
58 import net.sf.jasperreports.engine.design.JRDesignPropertyExpression;
59 import net.sf.jasperreports.engine.style.StyleProvider;
60 import net.sf.jasperreports.engine.style.StyleProviderFactory;
61 import net.sf.jasperreports.engine.type.CalculationEnum;
62 import net.sf.jasperreports.engine.type.EvaluationTimeEnum;
63 import net.sf.jasperreports.engine.type.ModeEnum;
64 import net.sf.jasperreports.engine.type.PositionTypeEnum;
65 import net.sf.jasperreports.engine.type.StretchTypeEnum;
66 import net.sf.jasperreports.engine.util.StyleResolver;
67 import net.sf.jasperreports.engine.util.StyleUtil;
68
69
70 /**
71  * @author Teodor Danciu (teodord@users.sourceforge.net)
72  */

73 public abstract class JRFillElement implements JRElement, JRFillCloneable, JRStyleSetter, DynamicPropertiesHolder
74 {
75     /**
76      *
77      */

78     public static final String EXCEPTION_MESSAGE_KEY_INVALID_BOOKMARK_LEVEL = "fill.anchor.bookmark.level.invalid";
79
80
81     /**
82      *
83      */

84     protected JRElement parent;
85     protected List<JRPropertyExpression> propertyExpressions;
86     protected List<String> dynamicTransferProperties;
87     protected JRStyle providerStyle;
88     protected Map<JRStyle,JRTemplateElement> templates = new HashMap<JRStyle,JRTemplateElement>();
89     protected List<StyleProvider> styleProviders;
90
91     /**
92      *
93      */

94     protected JRBaseFiller filler;
95     protected JRFillExpressionEvaluator expressionEvaluator;
96
97     protected JRDefaultStyleProvider defaultStyleProvider;
98     
99     /**
100      *
101      */

102     protected JRGroup printWhenGroupChanges;
103     protected JRFillElementGroup elementGroup;
104
105     /**
106      *
107      */

108     protected JRFillBand band;
109     
110     protected JROriginProvider originProvider;
111     
112     protected PrintElementOriginator printElementOriginator;
113
114     /**
115      *
116      */

117     private boolean isPrintWhenExpressionNull = true;
118     private boolean isPrintWhenTrue = true;
119     private boolean isToPrint = true;
120     private boolean isReprinted;
121     private boolean isAlreadyPrinted;
122     private Collection<JRFillElement> dependantElements = new ArrayList<JRFillElement>();
123     private int relativeY;
124     private int collapsedHeightAbove;
125     private int collapsedHeightBelow;
126     /**
127      * Keeps total stretch height, including forced stretch after honoring the stretchType property of the element. 
128      */

129     private int stretchHeight;
130     /**
131      * Keeps the natural stretch height calculated during element prepare. 
132      */

133     private int prepareHeight;
134
135     private int x;
136     private int y;
137     private int width;
138     private int height;
139     
140     private boolean isValueRepeating;
141     
142     protected byte currentEvaluation;
143     
144     // used by elements that support evaluationTime=Auto
145     protected Map<JREvaluationTime,DelayedEvaluations> delayedEvaluationsMap;
146
147     protected JRFillElementContainer conditionalStylesContainer;
148     protected FillContainerContext fillContainerContext;
149     
150     protected JRStyle initStyle;
151     
152     protected JRStyle currentStyle;
153     
154     /**
155      * Flag indicating whether the element is shrinkable.
156      * @see #setShrinkable(boolean)
157      */

158     private boolean shrinkable;
159
160     protected JRPropertiesMap staticProperties;
161     protected JRPropertiesMap dynamicProperties;
162     protected JRPropertiesMap mergedProperties;
163     
164     /**
165      *
166      *
167     private JRElement topElementInGroup;
168     private JRElement bottomElementInGroup;
169
170
171     /**
172      *
173      */

174     protected JRFillElement(
175         JRBaseFiller filler,
176         JRElement element,
177         JRFillObjectFactory factory
178         )
179     {
180         factory.put(element, this);
181
182         this.parent = element;
183         this.filler = filler;
184         this.expressionEvaluator = factory.getExpressionEvaluator();
185         this.defaultStyleProvider = factory.getDefaultStyleProvider();
186         
187         printElementOriginator = filler.assignElementId(this);
188
189         /*   */
190         printWhenGroupChanges = factory.getGroup(element.getPrintWhenGroupChanges());
191         elementGroup = (JRFillElementGroup)factory.getVisitResult(element.getElementGroup());
192         
193         x = element.getX();
194         y = element.getY();
195         width = element.getWidth();
196         height = element.getHeight();
197         
198         staticProperties = element.hasProperties() ? element.getPropertiesMap().cloneProperties() : null;
199         mergedProperties = staticProperties;
200         
201         JRPropertyExpression[] elementPropertyExpressions = element.getPropertyExpressions();
202         propertyExpressions = elementPropertyExpressions == null ? new ArrayList<JRPropertyExpression>(0)
203                 : new ArrayList<JRPropertyExpression>(Arrays.asList(elementPropertyExpressions));
204         
205         dynamicTransferProperties = findDynamicTransferProperties();
206         
207         factory.registerDelayedStyleSetter(this, parent);
208         
209         initStyleProviders();
210     }
211
212
213     protected JRFillElement(JRFillElement element, JRFillCloneFactory factory)
214     {
215         factory.put(element, this);
216
217         this.parent = element.parent;
218         this.filler = element.filler;
219         this.expressionEvaluator = element.expressionEvaluator;
220         this.defaultStyleProvider = element.defaultStyleProvider;
221         this.originProvider = element.originProvider;
222         
223         printElementOriginator = element.printElementOriginator;
224
225         /*   */
226         printWhenGroupChanges = element.printWhenGroupChanges;
227         elementGroup = (JRFillElementGroup) factory.getClone((JRFillElementGroup) element.getElementGroup());
228
229         x = element.getX();
230         y = element.getY();
231         width = element.getWidth();
232         height = element.getHeight();
233         
234         templates = element.templates;
235         
236         initStyle = element.initStyle;
237         
238         shrinkable = element.shrinkable;
239         
240         staticProperties = element.staticProperties == null ? null : element.staticProperties.cloneProperties();
241         mergedProperties = staticProperties;
242         this.propertyExpressions = new ArrayList<JRPropertyExpression>(element.propertyExpressions);
243         this.dynamicTransferProperties = element.dynamicTransferProperties;
244         
245         // we need a style provider context for this element instance
246         initStyleProviders();
247     }
248     
249     private List<String> findDynamicTransferProperties()
250     {
251         if (propertyExpressions.isEmpty())
252         {
253             return null;
254         }
255         
256         List<String> prefixes = filler.getPrintTransferPropertyPrefixes();
257         List<String> transferProperties = new ArrayList<String>(propertyExpressions.size());
258         for (JRPropertyExpression propertyExpression : propertyExpressions)
259         {
260             String propertyName = propertyExpression.getName();
261             for (String prefix : prefixes)
262             {
263                 if (propertyName.startsWith(prefix))
264                 {
265                     transferProperties.add(propertyName);
266                     break;
267                 }
268             }
269         }
270         return transferProperties;
271     }
272
273
274     @Override
275     public JRDefaultStyleProvider getDefaultStyleProvider()
276     {
277         return defaultStyleProvider;
278     }
279
280     /**
281      *
282      */

283     protected StyleResolver getStyleResolver() 
284     {
285         return getDefaultStyleProvider().getStyleResolver();
286     }
287
288     @Override
289     public UUID getUUID()
290     {
291         return parent.getUUID();
292     }
293     
294     @Override
295     public String getKey()
296     {
297         return parent.getKey();
298     }
299
300     @Override
301     public PositionTypeEnum getPositionTypeValue()
302     {
303         return parent.getPositionTypeValue();//FIXME optimize this by consolidating style properties
304     }
305
306     @Override
307     public void setPositionType(PositionTypeEnum positionType)
308     {
309         throw new UnsupportedOperationException();
310     }
311
312     @Override
313     public StretchTypeEnum getStretchTypeValue()
314     {
315         return parent.getStretchTypeValue();
316     }
317
318     @Override
319     public void setStretchType(StretchTypeEnum stretchType)
320     {
321         throw new UnsupportedOperationException();
322     }
323
324     @Override
325     public boolean isPrintRepeatedValues()
326     {
327         return parent.isPrintRepeatedValues();
328     }
329
330     @Override
331     public void setPrintRepeatedValues(boolean isPrintRepeatedValues)
332     {
333     }
334
335     @Override
336     public ModeEnum getModeValue()
337     {
338         return getStyleResolver().getMode(this, ModeEnum.OPAQUE);
339     }
340
341     @Override
342     public ModeEnum getOwnModeValue()
343     {
344         return providerStyle == null || providerStyle.getOwnModeValue() == null ? parent.getOwnModeValue() : providerStyle.getOwnModeValue();
345     }
346
347     @Override
348     public void setMode(ModeEnum modeValue)
349     {
350     }
351
352     @Override
353     public int getX()
354     {
355         return x;
356     }
357
358     @Override
359     public void setX(int x)
360     {
361         this.x = x;
362     }
363     
364     /**
365      *
366      */

367     public void setY(int y)
368     {
369         this.y = y;
370     }
371
372     @Override
373     public int getY()
374     {
375         return y;
376     }
377
378     @Override
379     public int getWidth()
380     {
381         return width;
382     }
383
384     @Override
385     public void setWidth(int width)
386     {
387         this.width = width;
388     }
389     
390     /**
391      *
392      */

393     public void setHeight(int height)
394     {
395         this.height = height;
396     }
397
398     @Override
399     public int getHeight()
400     {
401         return height;
402     }
403
404     @Override
405     public boolean isRemoveLineWhenBlank()
406     {
407         return parent.isRemoveLineWhenBlank();
408     }
409
410     @Override
411     public void setRemoveLineWhenBlank(boolean isRemoveLine)
412     {
413     }
414
415     @Override
416     public boolean isPrintInFirstWholeBand()
417     {
418         return parent.isPrintInFirstWholeBand();
419     }
420
421     @Override
422     public void setPrintInFirstWholeBand(boolean isPrint)
423     {
424     }
425
426     @Override
427     public boolean isPrintWhenDetailOverflows()
428     {
429         return parent.isPrintWhenDetailOverflows();
430     }
431
432     @Override
433     public void setPrintWhenDetailOverflows(boolean isPrint)
434     {
435     }
436
437     @Override
438     public Color getForecolor()
439     {
440         return getStyleResolver().getForecolor(this);
441     }
442
443     @Override
444     public Color getOwnForecolor()
445     {
446         return providerStyle == null || providerStyle.getOwnForecolor() == null ? parent.getOwnForecolor() : providerStyle.getOwnForecolor();
447     }
448
449     @Override
450     public void setForecolor(Color forecolor)
451     {
452     }
453
454     @Override
455     public Color getBackcolor()
456     {
457         return getStyleResolver().getBackcolor(this);
458     }
459
460     @Override
461     public Color getOwnBackcolor()
462     {
463         return providerStyle == null || providerStyle.getOwnBackcolor() == null ? parent.getOwnBackcolor() : providerStyle.getOwnBackcolor();
464     }
465
466     @Override
467     public void setBackcolor(Color backcolor)
468     {
469     }
470
471     @Override
472     public JRExpression getPrintWhenExpression()
473     {
474         return parent.getPrintWhenExpression();
475     }
476
477     @Override
478     public JRGroup getPrintWhenGroupChanges()
479     {
480         return printWhenGroupChanges;
481     }
482
483     @Override
484     public JRElementGroup getElementGroup()
485     {
486         return elementGroup;
487     }
488
489     /**
490      *
491      */

492     protected boolean isPrintWhenExpressionNull()
493     {
494         return isPrintWhenExpressionNull;
495     }
496
497     /**
498      *
499      */

500     protected void setPrintWhenExpressionNull(boolean isPrintWhenExpressionNull)
501     {
502         this.isPrintWhenExpressionNull = isPrintWhenExpressionNull;
503     }
504
505     /**
506      *
507      */

508     protected boolean isPrintWhenTrue()
509     {
510         return isPrintWhenTrue;
511     }
512
513     /**
514      *
515      */

516     protected void setPrintWhenTrue(boolean isPrintWhenTrue)
517     {
518         this.isPrintWhenTrue = isPrintWhenTrue;
519     }
520
521     /**
522      *
523      */

524     public boolean isToPrint()
525     {
526         return isToPrint;
527     }
528
529     /**
530      *
531      */

532     protected void setToPrint(boolean isToPrint)
533     {
534         this.isToPrint = isToPrint;
535     }
536
537     /**
538      *
539      */

540     protected boolean isReprinted()
541     {
542         return isReprinted;
543     }
544
545     /**
546      *
547      */

548     protected void setReprinted(boolean isReprinted)
549     {
550         this.isReprinted = isReprinted;
551     }
552
553     /**
554      *
555      */

556     public boolean isAlreadyPrinted()
557     {
558         return isAlreadyPrinted;
559     }
560
561     /**
562      *
563      */

564     public void setAlreadyPrinted(boolean isAlreadyPrinted)
565     {
566         this.isAlreadyPrinted = isAlreadyPrinted;
567     }
568
569     /**
570      *
571      */

572     protected JRElement[] getGroupElements()
573     {
574         JRElement[] groupElements = null;
575
576         if (elementGroup != null)
577         {
578             groupElements = elementGroup.getElements();
579         }
580
581         return groupElements;
582     }
583
584     /**
585      *
586      */

587     protected Collection<JRFillElement> getDependantElements()
588     {
589         return dependantElements;
590     }
591
592     /**
593      *
594      */

595     protected void addDependantElement(JRFillElement element)
596     {
597         dependantElements.add(element);
598     }
599
600     /**
601      *
602      */

603     protected int getRelativeY()
604     {
605         return relativeY;
606     }
607
608     /**
609      *
610      */

611     protected void setRelativeY(int relativeY)
612     {
613         this.relativeY = relativeY;
614     }
615
616     /**
617      *
618      */

619     protected int getCollapsedHeightAbove()
620     {
621         return collapsedHeightAbove;
622     }
623
624     /**
625      *
626      */

627     protected void setCollapsedHeightAbove(int collapsedHeightAbove)
628     {
629         this.collapsedHeightAbove = collapsedHeightAbove;
630     }
631
632      /**
633      *
634      */

635     protected int getCollapsedHeightBelow()
636     {
637         return collapsedHeightBelow;
638     }
639
640     /**
641      *
642      */

643     protected void setCollapsedHeightBelow(int collapsedHeightBelow)
644     {
645         this.collapsedHeightBelow = collapsedHeightBelow;
646     }
647
648     /**
649      *
650      */

651     public int getStretchHeight()
652     {
653         return stretchHeight;
654     }
655
656     /**
657      *
658      */

659     protected void setStretchHeight(int stretchHeight)
660     {
661         if (stretchHeight > getHeight() || (shrinkable && isRemoveLineWhenBlank()))
662         {
663             this.stretchHeight = stretchHeight;
664         }
665         else
666         {
667             this.stretchHeight = getHeight();
668         }
669     }
670
671     /**
672      *
673      */

674     public int getPrepareHeight()
675     {
676         return prepareHeight;
677     }
678
679     /**
680      * Element height is calculated in two phases. 
681      * First, the element stretches on its own during prepare, to accommodate all its content.
682      * This is the natural stretch and we keep track of the calculated height in prepareHeight.
683      * Secondly, the element stretches further in accordance with its stretchType property.
684      * This forced stretch occurs at a later time and the amount of stretch is kept in stretchHeight. 
685      */

686     protected void setPrepareHeight(int prepareHeight)
687     {
688         this.prepareHeight = prepareHeight;
689         
690         setStretchHeight(prepareHeight);
691     }
692
693     /**
694      *
695      */

696     protected JRFillBand getBand()
697     {
698         return band;
699     }
700
701     /**
702      *
703      */

704     protected void setBand(JRFillBand band)
705     {
706         this.band = band;
707         
708         if (this.originProvider == null)
709         {
710             setOriginProvider(band);
711         }
712     }
713
714
715     /**
716      *
717      */

718     protected void initStyleProviders()
719     {
720         List<StyleProviderFactory> styleProviderFactories = filler.getJasperReportsContext().getExtensions(StyleProviderFactory.class);
721         if (styleProviderFactories != null && styleProviderFactories.size() > 0)
722         {
723             FillStyleProviderContext styleProviderContext = new FillStyleProviderContext(this);
724             for (StyleProviderFactory styleProviderFactory : styleProviderFactories)
725             {
726                 StyleProvider styleProvider = styleProviderFactory.getStyleProvider(styleProviderContext, filler.getJasperReportsContext());
727                 if (styleProvider != null)
728                 {
729                     if (styleProviders == null)
730                     {
731                         styleProviders = new ArrayList<StyleProvider>();
732                     }
733                     styleProviders.add(styleProvider);
734                 }
735             }
736         }
737     }
738
739     
740     /**
741      *
742      */

743     protected void reset()
744     {
745         relativeY = y;
746         collapsedHeightAbove = 0;
747         collapsedHeightBelow = 0;
748         stretchHeight = height;
749         prepareHeight = height;
750
751         if (elementGroup != null)
752         {
753             elementGroup.reset();
754         }
755     }
756
757     protected void setCurrentEvaluation(byte evaluation)
758     {
759         currentEvaluation = evaluation;
760     }
761
762     /**
763      *
764      */

765     protected abstract void evaluate(
766         byte evaluation
767         ) throws JRException;
768
769
770     /**
771      *
772      */

773     protected void evaluateStyle(
774         byte evaluation
775         ) throws JRException
776     {
777         providerStyle = null;
778
779         if (styleProviders != null && styleProviders.size() > 0)
780         {
781             for (StyleProvider styleProvider : styleProviders)
782             {
783                 JRStyle style = styleProvider.getStyle(evaluation);
784                 if (style != null)
785                 {
786                     if (providerStyle == null)
787                     {
788                         providerStyle = new JRBaseStyle();
789                     }
790                     StyleUtil.appendStyle(providerStyle, style);
791                 }
792             }
793         }
794     }
795
796     protected TimeZone getTimeZone()
797     {
798         return filler.getTimeZone();
799     }
800
801     /**
802      *
803      */

804     protected void evaluatePrintWhenExpression(
805         byte evaluation
806         ) throws JRException
807     {
808         boolean isExprNull = true;
809         boolean isExprTrue = false;
810
811         JRExpression expression = getPrintWhenExpression();
812         if (expression != null)
813         {
814             isExprNull = false;
815             Boolean printWhenExpressionValue = (Boolean) evaluateExpression(expression, evaluation);
816             if (printWhenExpressionValue == null)
817             {
818                 isExprTrue = false;
819             }
820             else
821             {
822                 isExprTrue = printWhenExpressionValue;
823             }
824         }
825
826         setPrintWhenExpressionNull(isExprNull);
827         setPrintWhenTrue(isExprTrue);
828     }
829
830
831     /**
832      *
833      */

834     protected abstract void rewind() throws JRException;
835
836
837     /**
838      *
839      */

840     protected abstract JRPrintElement fill() throws JRException;
841
842     protected JRTemplateElement getElementTemplate()
843     {
844         JRTemplateElement template = null;
845         JRStyle style = null;
846         
847         if (providerStyle == null)
848         {
849             // no style provider has been used so we can use cache template per style below
850             style = getStyle();
851             template = getTemplate(style);
852         }
853         
854         if (template == null)
855         {
856             template = createElementTemplate();
857             transferProperties(template);
858             
859             // deduplicate to previously created identical objects
860             template = filler.fillContext.deduplicate(template);
861             
862             if (providerStyle == null)
863             {
864                 registerTemplate(style, template);
865             }
866         }
867         return template;
868     }
869
870     protected abstract JRTemplateElement createElementTemplate();
871     
872     /**
873      *
874      */

875     protected boolean prepare(
876         int availableHeight,
877         boolean isOverflow
878         ) throws JRException
879     {
880         if (
881             isPrintWhenExpressionNull() ||
882             ( !isPrintWhenExpressionNull() &&
883               isPrintWhenTrue() )
884             )
885         {
886             setToPrint(true);
887         }
888         else
889         {
890             setToPrint(false);
891         }
892
893         setReprinted(false);
894
895         return false;
896     }
897
898
899     /**
900      * @deprecated To be removed.
901      */

902     protected void _stretchElement(int bandStretch)
903     {
904         switch (getStretchTypeValue())
905         {
906             case RELATIVE_TO_BAND_HEIGHT :
907             case CONTAINER_HEIGHT :
908             case CONTAINER_BOTTOM :
909             {
910                 _stretchElementToHeight(getHeight() + bandStretch);
911                 break;
912             }
913             case RELATIVE_TO_TALLEST_OBJECT :
914             case ELEMENT_GROUP_HEIGHT :
915             case ELEMENT_GROUP_BOTTOM :
916             {
917                 if (elementGroup != null)
918                 {
919                     //setStretchHeight(getHeight() + getStretchHeightDiff());
920                     _stretchElementToHeight(getHeight() + elementGroup.getStretchHeightDiff());
921                 }
922
923                 break;
924             }
925             case NO_STRETCH :
926             default :
927             {
928                 break;
929             }
930         }
931     }
932     
933     /**
934      * @deprecated To be removed.
935      */

936     protected void _stretchElementToHeight(int stretchHeight)
937     {
938         if (stretchHeight > getStretchHeight())
939         {
940             setStretchHeight(stretchHeight);
941         }
942     }
943
944
945     /**
946      *
947      */

948     @SuppressWarnings("deprecation")
949     protected boolean stretchElement(int containerStretch)
950     {
951         boolean applied = false;
952         switch (getStretchTypeValue())
953         {
954             case RELATIVE_TO_BAND_HEIGHT :
955             case CONTAINER_HEIGHT :
956             case CONTAINER_BOTTOM :
957             {
958                 applied = stretchElementToContainer(containerStretch);
959                 break;
960             }
961             case RELATIVE_TO_TALLEST_OBJECT :
962             case ELEMENT_GROUP_HEIGHT :
963             case ELEMENT_GROUP_BOTTOM :
964             {
965                 applied = stretchElementToElementGroup();
966                 break;
967             }
968             case NO_STRETCH :
969             default :
970             {
971                 break;
972             }
973         }
974         return applied;
975     }
976
977
978     /**
979      *
980      */

981     @SuppressWarnings("deprecation")
982     protected boolean stretchElementToContainer(int containerStretch)//TODO subtract firstY?
983     {
984         boolean applied = false;
985         switch (getStretchTypeValue())
986         {
987             case RELATIVE_TO_BAND_HEIGHT :
988             case CONTAINER_HEIGHT :
989             {
990                 applied = stretchElementToHeight(getHeight() + containerStretch);
991                 break;
992             }
993             case CONTAINER_BOTTOM :
994             {
995                 applied = stretchElementToHeight(getY() - getRelativeY() + getHeight() + containerStretch);
996                 break;
997             }
998         }
999         return applied;
1000     }
1001
1002
1003     /**
1004      *
1005      */

1006     @SuppressWarnings("deprecation")
1007     protected boolean stretchElementToElementGroup()
1008     {
1009         boolean applied = false;
1010         if (elementGroup != null)
1011         {
1012             switch (getStretchTypeValue())
1013             {
1014                 case RELATIVE_TO_TALLEST_OBJECT :
1015                 case ELEMENT_GROUP_HEIGHT :
1016                 {
1017                     applied = stretchElementToHeight(getHeight() + elementGroup.getStretchHeightDiff());
1018                     break;
1019                 }
1020                 case ELEMENT_GROUP_BOTTOM :
1021                 {
1022                     applied = stretchElementToHeight(getY() - getRelativeY() + getHeight() + elementGroup.getStretchHeightDiff());
1023                     break;
1024                 }
1025             }
1026         }
1027         return applied;
1028     }
1029
1030
1031     /**
1032      * This method returns a boolean signaling if any stretch change occurred.
1033      * It does not say which amount of stretch was applied, but that is OK, because the only place where this is checked
1034      * is during frame cascading stretch, where the stretchHeight field of the frame (set here) is used directly.
1035      */

1036     protected boolean stretchElementToHeight(int stretchHeight)
1037     {
1038         // cannot force the element to shrink below its natural stretch calculated during prepare;
1039         // such situation could occur when the container breaks and overflows
1040         boolean applied = false;
1041         if (stretchHeight > getPrepareHeight())
1042         {
1043             // any new stretchHeight that is greater than element's natural growth is fine
1044             setStretchHeight(stretchHeight);
1045             applied = true;
1046         }
1047         return applied;
1048     }
1049
1050
1051     /**
1052      * @deprecated To be removed.
1053      */

1054     protected void _moveDependantElements()
1055     {
1056         Collection<JRFillElement> elements = getDependantElements();
1057         if (elements != null && elements.size() > 0)
1058         {
1059             for (JRFillElement element : elements)
1060             {
1061                 int newRelativeY = 
1062                     getRelativeY() + getStretchHeight() //pusher element current bottom edge
1063                     + (element.getY() - (getY() + getHeight())); //design time distance between elements; difference between float element top edge and pusher element bottom edge
1064
1065                 if (newRelativeY > element.getRelativeY())
1066                 {
1067                     element.setRelativeY(newRelativeY);
1068                 }
1069             }
1070         }
1071     }
1072
1073
1074     /**
1075      *
1076      */

1077     protected void moveDependantElements()
1078     {
1079         Collection<JRFillElement> elements = getDependantElements();
1080         if (elements != null && elements.size() > 0)
1081         {
1082             for (JRFillElement element : elements)
1083             {
1084                 int newRelativeY = 
1085                     getRelativeY() + getStretchHeight() //pusher element current bottom edge
1086                     + (element.getY() - (getY() + getHeight())) //design time distance between elements; difference between float element top edge and pusher element bottom edge
1087                     - (element.getCollapsedHeightAbove() - getCollapsedHeightAbove()); //difference in collapsedY amount, meaning the elements could only have become closer together due to blank element removal
1088
1089                 if (newRelativeY > element.getRelativeY())
1090                 {
1091                     element.setRelativeY(newRelativeY);
1092
1093                     element.moveDependantElements();
1094                 }
1095             }
1096         }
1097     }
1098
1099
1100     /**
1101      * Resolves an element.
1102      * 
1103      * @param element the element
1104      * @param evaluation the evaluation type
1105      */

1106     protected abstract void resolveElement (JRPrintElement element, byte evaluation) throws JRException;
1107     
1108     protected void performDelayedEvaluation(JRPrintElement element, byte evaluation) 
1109             throws JRException
1110     {
1111         boolean updateTemplate = false;
1112
1113         JRStyle printStyle = element.getStyle();
1114         if (isDelayedStyleEvaluation())
1115         {
1116             JRStyle elementStyle = initStyle;
1117             if (elementStyle == null)
1118             {
1119                 elementStyle = filler.getDefaultStyle();
1120             }
1121             
1122             if (elementStyle != null)
1123             {
1124                 JRStyle evaluatedStyle = conditionalStylesContainer.evaluateConditionalStyle(
1125                         elementStyle, evaluation);
1126                 // if the evaluated style differs from the existing style
1127                 if (evaluatedStyle != printStyle)
1128                 {
1129                     // set the evaluated style as element style
1130                     printStyle = evaluatedStyle;
1131                     
1132                     updateTemplate = true;
1133                 }
1134             }
1135         }
1136         
1137         // set the current element style
1138         this.currentStyle = printStyle;
1139         
1140         resolveElement(element, evaluation);
1141         
1142         if (updateTemplate || providerStyle != null
1143                 || delayedEvaluationUpdatesTemplate())
1144         {
1145             // get/create an element template that corresponds to the
1146             // current style
1147             JRTemplateElement newTemplate = getElementTemplate();
1148             ((JRTemplatePrintElement) element).updateElementTemplate(
1149                     newTemplate);
1150         }
1151         
1152         // reset the current style
1153         this.currentStyle = null;
1154         //this.providerStyle = null;
1155     }
1156
1157     protected boolean delayedEvaluationUpdatesTemplate()
1158     {
1159         return false;
1160     }
1161
1162
1163     /**
1164      * Evaluates an expression.
1165      * 
1166      * @param expression the expression
1167      * @param evaluation the evaluation type
1168      * @return the evaluation result
1169      * @throws JRException
1170      */

1171     public final Object evaluateExpression(JRExpression expression, byte evaluation) throws JRException
1172     {
1173         return expressionEvaluator.evaluate(expression, evaluation);
1174     }
1175
1176
1177     /**
1178      * Decides whether the value for this element is repeating.
1179      * <p>
1180      * Dynamic elements should call {@link #setValueRepeating(boolean) setValueRepeating(boolean)} on
1181      * {@link #evaluate(byte) evaluate(byte)}.  Static elements don't have to do anything, this method
1182      * will return <code>true</code> by default.
1183      * 
1184      * @return whether the value for this element is repeating
1185      * @see #setValueRepeating(boolean)
1186      */

1187     protected boolean isValueRepeating()
1188     {
1189         return isValueRepeating;
1190     }
1191
1192
1193     /**
1194      * Sets the repeating flag for this element.
1195      * <p>
1196      * This method should be called by dynamic elements on {@link #evaluate(byte) evaluate(byte)}.
1197      * 
1198      * @param isValueRepeating whether the value of the element is repeating
1199      * @see #isValueRepeating()
1200      */

1201     protected void setValueRepeating(boolean isValueRepeating)
1202     {
1203         this.isValueRepeating = isValueRepeating;
1204     }
1205
1206
1207     protected JRFillVariable getVariable(String variableName)
1208     {
1209         return filler.getVariable(variableName);
1210     }
1211
1212
1213     protected JRFillField getField(String fieldName)
1214     {
1215         return filler.getField(fieldName);
1216     }
1217     
1218     // default for elements not supporting evaluationTime
1219     protected EvaluationTimeEnum getEvaluationTimeValue()
1220     {
1221         return EvaluationTimeEnum.NOW;
1222     }
1223
1224     /**
1225      * Resolves an element.
1226      * 
1227      * @param element the element
1228      * @param evaluation the evaluation type
1229      * @param evaluationTime the current evaluation time
1230      */

1231     protected void resolveElement (JRPrintElement element, byte evaluation, JREvaluationTime evaluationTime) throws JRException
1232     {
1233         EvaluationTimeEnum evaluationTimeType = getEvaluationTimeValue();
1234         switch (evaluationTimeType)
1235         {
1236             case NOW:
1237                 break;
1238             case AUTO:
1239                 delayedEvaluate((JRRecordedValuesPrintElement) element, evaluationTime, evaluation);
1240                 break;
1241             default:
1242                 performDelayedEvaluation(element, evaluation);
1243                 break;
1244         }
1245     }
1246
1247     private static class DelayedEvaluations implements Serializable
1248     {
1249         private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID;
1250
1251         final Set<String> fields;
1252         final Set<String> variables;
1253
1254         DelayedEvaluations()
1255         {
1256             fields = new HashSet<String>();
1257             variables = new HashSet<String>();
1258         }
1259     }
1260
1261     protected void initDelayedEvaluations()
1262     {
1263         if (getEvaluationTimeValue() == EvaluationTimeEnum.AUTO && delayedEvaluationsMap == null)
1264         {
1265             delayedEvaluationsMap = new HashMap<JREvaluationTime,DelayedEvaluations>();
1266             collectDelayedEvaluations();
1267         }
1268     }
1269     
1270     protected void collectDelayedEvaluations()
1271     {
1272         if (isDelayedStyleEvaluation())
1273         {
1274             collectStyleDelayedEvaluations();
1275             collectStyleProviderDelayedEvaluations();
1276         }
1277     }
1278
1279     protected void collectStyleDelayedEvaluations()
1280     {
1281         JRStyle elementStyle = initStyle;
1282         if (elementStyle == null)
1283         {
1284             elementStyle = filler.getDefaultStyle();
1285         }
1286         
1287         if (elementStyle != null)
1288         {
1289             JRStyle style = elementStyle;
1290             while (style != null)
1291             {
1292                 collectDelayedEvaluations(style);
1293                 
1294                 // proceed to the parent style
1295                 style = style.getStyle();
1296             }
1297         }
1298     }
1299
1300     protected void collectDelayedEvaluations(JRStyle style)
1301     {
1302         JRConditionalStyle[] conditionalStyles = style.getConditionalStyles();
1303         // collect delayed evaluations from conditional style expressions
1304         if (conditionalStyles != null && conditionalStyles.length > 0)
1305         {
1306             for (int i = 0; i < conditionalStyles.length; i++)
1307             {
1308                 collectDelayedEvaluations(
1309                         conditionalStyles[i].getConditionExpression());
1310             }
1311         }
1312     }
1313
1314
1315     protected void collectDelayedEvaluations(JRExpression expression)
1316     {
1317         if (expression != null)
1318         {
1319             JRExpressionChunk[] chunks = expression.getChunks();
1320             if (chunks != null)
1321             {
1322                 for (int i = 0; i < chunks.length; i++)
1323                 {
1324                     JRExpressionChunk chunk = chunks[i];
1325                     switch (chunk.getType())
1326                     {
1327                         case JRExpressionChunk.TYPE_FIELD:
1328                         {
1329                             DelayedEvaluations delayedEvaluations = getDelayedEvaluations(JREvaluationTime.EVALUATION_TIME_NOW);
1330                             delayedEvaluations.fields.add(chunk.getText());
1331                             break;
1332                         }
1333                         case JRExpressionChunk.TYPE_VARIABLE:
1334                         {
1335                             JREvaluationTime time = autogetVariableEvaluationTime(chunk.getText());
1336                             DelayedEvaluations delayedEvaluations = getDelayedEvaluations(time);
1337                             delayedEvaluations.variables.add(chunk.getText());
1338                             break;
1339                         }
1340                     }
1341                 }
1342             }
1343         }
1344     }
1345
1346     
1347     protected void collectStyleProviderDelayedEvaluations()
1348     {
1349         if (styleProviders != null && styleProviders.size() > 0)
1350         {
1351             for (StyleProvider styleProvider : styleProviders)
1352             {
1353                 String[] fields = styleProvider.getFields();
1354                 if (fields != null && fields.length > 0)
1355                 {
1356                     DelayedEvaluations delayedEvaluations = getDelayedEvaluations(JREvaluationTime.EVALUATION_TIME_NOW);
1357                     for (String field : fields)
1358                     {
1359                         delayedEvaluations.fields.add(field);
1360                     }
1361                 }
1362                 String[] variables = styleProvider.getVariables();
1363                 if (variables != null && variables.length > 0)
1364                 {
1365                     for (String variable : variables)
1366                     {
1367                         JREvaluationTime time = autogetVariableEvaluationTime(variable);
1368                         DelayedEvaluations delayedEvaluations = getDelayedEvaluations(time);
1369                         delayedEvaluations.variables.add(variable);
1370                     }
1371                 }
1372             }
1373         }
1374     }
1375
1376
1377     private DelayedEvaluations getDelayedEvaluations(JREvaluationTime time)
1378     {
1379         DelayedEvaluations delayedEvaluations = delayedEvaluationsMap.get(time);
1380         if (delayedEvaluations == null)
1381         {
1382             delayedEvaluations = new DelayedEvaluations();
1383             delayedEvaluationsMap.put(time, delayedEvaluations);
1384         }
1385         return delayedEvaluations;
1386     }
1387
1388
1389     private JREvaluationTime autogetVariableEvaluationTime(String variableName)
1390     {
1391         JRFillVariable variable = getVariable(variableName);
1392         JREvaluationTime evaluationTime;
1393         switch (variable.getResetTypeValue())
1394         {
1395             case REPORT:
1396                 evaluationTime = JREvaluationTime.EVALUATION_TIME_REPORT;
1397                 break;
1398             case MASTER:
1399                 evaluationTime = JREvaluationTime.EVALUATION_TIME_MASTER;
1400                 break;
1401             case PAGE:
1402                 evaluationTime = JREvaluationTime.EVALUATION_TIME_PAGE;
1403                 break;
1404             case COLUMN:
1405                 evaluationTime = JREvaluationTime.EVALUATION_TIME_COLUMN;
1406                 break;
1407             case GROUP:
1408                 evaluationTime = JREvaluationTime.getGroupEvaluationTime(variable.getResetGroup().getName());
1409                 break;
1410             default:
1411                 evaluationTime = JREvaluationTime.EVALUATION_TIME_NOW;
1412                 break;
1413         }
1414         
1415         if (!evaluationTime.equals(JREvaluationTime.EVALUATION_TIME_NOW) &&
1416                 band.isNowEvaluationTime(evaluationTime))
1417         {
1418             evaluationTime = JREvaluationTime.EVALUATION_TIME_NOW;
1419         }
1420         
1421         if (variable.getCalculationValue() == CalculationEnum.SYSTEM &&
1422                 evaluationTime.equals(JREvaluationTime.EVALUATION_TIME_NOW) &&
1423                 band.isVariableUsedInReturns(variableName))
1424         {
1425             evaluationTime = JREvaluationTime.getBandEvaluationTime(band);
1426         }
1427
1428         return evaluationTime;
1429     }
1430     
1431     
1432     protected void initDelayedEvaluationPrint(JRRecordedValuesPrintElement printElement) throws JRException
1433     {
1434         for (Iterator<JREvaluationTime> it = delayedEvaluationsMap.keySet().iterator(); it.hasNext();)
1435         {
1436             JREvaluationTime evaluationTime = it.next();
1437             if (!evaluationTime.equals(JREvaluationTime.EVALUATION_TIME_NOW))
1438             {
1439                 filler.addBoundElement(this, printElement, evaluationTime);
1440             }
1441         }
1442         
1443         printElement.initRecordedValues(delayedEvaluationsMap.keySet());
1444         
1445         if (delayedEvaluationsMap.containsKey(JREvaluationTime.EVALUATION_TIME_NOW))
1446         {
1447             delayedEvaluate(printElement, JREvaluationTime.EVALUATION_TIME_NOW, currentEvaluation);
1448         }
1449     }
1450
1451
1452     protected void delayedEvaluate(JRRecordedValuesPrintElement printElement, JREvaluationTime evaluationTime, byte evaluation) throws JRException
1453     {
1454         JRRecordedValues recordedValues = printElement.getRecordedValues();
1455         if (!recordedValues.lastEvaluationTime())
1456         {
1457             DelayedEvaluations delayedEvaluations = delayedEvaluationsMap.get(evaluationTime);
1458             
1459             for (Iterator<String> it = delayedEvaluations.fields.iterator(); it.hasNext();)
1460             {
1461                 String fieldName = it.next();
1462                 JRFillField field = getField(fieldName);
1463                 recordedValues.recordFieldValue(fieldName, field.getValue(evaluation));
1464             }
1465
1466             for (Iterator<String> it = delayedEvaluations.variables.iterator(); it.hasNext();)
1467             {
1468                 String variableName = it.next();
1469                 JRFillVariable variable = getVariable(variableName);
1470                 recordedValues.recordVariableValue(variableName, variable.getValue(evaluation));
1471             }
1472         }
1473
1474         recordedValues.doneEvaluation(evaluationTime);
1475         
1476         if (recordedValues.finishedEvaluations())
1477         {
1478             overwriteWithRecordedValues(recordedValues, evaluation);
1479             performDelayedEvaluation(printElement, evaluation);
1480             restoreValues(recordedValues, evaluation);
1481             printElement.deleteRecordedValues();
1482         }
1483     }
1484
1485     
1486     private void overwriteWithRecordedValues(JRRecordedValues recordedValues, byte evaluation)
1487     {
1488         Map<String,Object> fieldValues = recordedValues.getRecordedFieldValues();
1489         if (fieldValues != null)
1490         {
1491             for (Iterator<Map.Entry<String,Object>> it = fieldValues.entrySet().iterator(); it.hasNext();)
1492             {
1493                 Map.Entry<String,Object> entry = it.next();
1494                 String fieldName = entry.getKey();
1495                 Object fieldValue = entry.getValue();
1496                 JRFillField field = getField(fieldName);
1497                 field.overwriteValue(fieldValue, evaluation);
1498             }
1499         }
1500         
1501         Map<String,Object> variableValues = recordedValues.getRecordedVariableValues();
1502         if (variableValues != null)
1503         {
1504             for (Iterator<Map.Entry<String,Object>> it = variableValues.entrySet().iterator(); it.hasNext();)
1505             {
1506                 Map.Entry<String,Object> entry = it.next();
1507                 String variableName = entry.getKey();
1508                 Object variableValue = entry.getValue();
1509                 JRFillVariable variable = getVariable(variableName);
1510                 variable.overwriteValue(variableValue, evaluation);
1511             }
1512         }
1513     }
1514
1515     private void restoreValues(JRRecordedValues recordedValues, byte evaluation)
1516     {
1517         Map<String,Object> fieldValues = recordedValues.getRecordedFieldValues();
1518         if (fieldValues != null)
1519         {
1520             for (Iterator<String> it = fieldValues.keySet().iterator(); it.hasNext();)
1521             {
1522                 String fieldName = it.next();
1523                 JRFillField field = getField(fieldName);
1524                 field.restoreValue(evaluation);
1525             }
1526         }
1527         
1528         Map<String,Object> variableValues = recordedValues.getRecordedVariableValues();
1529         if (variableValues != null)
1530         {
1531             for (Iterator<String> it = variableValues.keySet().iterator(); it.hasNext();)
1532             {
1533                 String variableName = it.next();
1534                 JRFillVariable variable = getVariable(variableName);
1535                 variable.restoreValue(evaluation);
1536             }
1537         }
1538     }
1539
1540     /**
1541      * 
1542      */

1543     public void setConditionalStylesContainer(JRFillElementContainer conditionalStylesContainer)
1544     {
1545         this.conditionalStylesContainer = conditionalStylesContainer;
1546         if (fillContainerContext == null)
1547         {
1548             fillContainerContext = conditionalStylesContainer;
1549         }
1550     }
1551
1552     /**
1553      * 
1554      */

1555     public JRFillElementContainer getConditionalStylesContainer()
1556     {
1557         return conditionalStylesContainer;
1558     }
1559
1560     @Override
1561     public JRStyle getStyle()
1562     {
1563         // the current style overrides other style objects
1564         if (currentStyle != null)
1565         {
1566             return currentStyle;
1567         }
1568         
1569         JRStyle crtStyle = initStyle;
1570         
1571         boolean isUsingDefaultStyle = false;
1572
1573         if (crtStyle == null)
1574         {
1575             crtStyle = filler.getDefaultStyle();
1576             isUsingDefaultStyle = true;
1577         }
1578
1579         JRStyle evalStyle = crtStyle;
1580
1581         if (conditionalStylesContainer != null)
1582         {
1583             evalStyle = conditionalStylesContainer.getEvaluatedConditionalStyle(crtStyle);
1584         }
1585         if (isUsingDefaultStyle && evalStyle == crtStyle)
1586         {
1587             evalStyle = null;
1588         }
1589         
1590         return evalStyle;
1591     }
1592     
1593     /**
1594      * 
1595      */

1596     protected JRTemplateElement getTemplate(JRStyle style)
1597     {
1598         return templates.get(style);
1599     }
1600
1601     /**
1602      * 
1603      */

1604     protected void registerTemplate(JRStyle style, JRTemplateElement template)
1605     {
1606         templates.put(style, template);
1607     }
1608     
1609     
1610     /**
1611      * Indicates whether an element is shrinkable.
1612      * <p>
1613      * This flag is only effective when {@link #isRemoveLineWhenBlank() isRemoveLineWhenBlank} is also set.
1614      * 
1615      * @param shrinkable whether the element is shrinkable
1616      */

1617     protected final void setShrinkable(boolean shrinkable)
1618     {
1619         this.shrinkable = shrinkable;
1620     }
1621
1622
1623     /**
1624      * Called when the stretch height of an element is final so that
1625      * the element can perform any adjustments.
1626      * @deprecated To be removed.
1627      */

1628     protected void stretchHeightFinal()
1629     {
1630         // nothing        
1631     }
1632     
1633     
1634     protected boolean isEvaluateNow()
1635     {
1636         boolean evaluateNow;
1637         switch (getEvaluationTimeValue())
1638         {
1639             case NOW:
1640                 evaluateNow = true;
1641                 break;
1642
1643             case AUTO:
1644                 evaluateNow = isAutoEvaluateNow();
1645                 break;
1646
1647             default:
1648                 evaluateNow = false;
1649                 break;
1650         }
1651         return evaluateNow;
1652     }
1653     
1654     
1655     protected boolean isAutoEvaluateNow()
1656     {
1657         return delayedEvaluationsMap == null || delayedEvaluationsMap.isEmpty() 
1658                 || (delayedEvaluationsMap.size() == 1 
1659                         && delayedEvaluationsMap.containsKey(JREvaluationTime.EVALUATION_TIME_NOW));
1660     }
1661     
1662     
1663     protected boolean isEvaluateAuto()
1664     {
1665         return getEvaluationTimeValue() == EvaluationTimeEnum.AUTO && !isAutoEvaluateNow();
1666     }
1667
1668     @Override
1669     public String getStyleNameReference()
1670     {
1671         return null;
1672     }
1673
1674     @Override
1675     public void setStyle(JRStyle style)
1676     {
1677         initStyle = style;
1678         if (conditionalStylesContainer != null)
1679         {
1680             conditionalStylesContainer.collectConditionalStyle(style);
1681         }
1682     }
1683
1684     @Override
1685     public void setStyleNameReference(String name)
1686     {
1687         throw new UnsupportedOperationException("Style name references not allowed at fill time");
1688     }
1689     
1690     @Override
1691     public Object clone() 
1692     {
1693         throw new UnsupportedOperationException();
1694     }
1695
1696     @Override
1697     public Object clone(JRElementGroup parentGroup) 
1698     {
1699         throw new UnsupportedOperationException();
1700     }
1701
1702     @Override
1703     public JRElement clone(JRElementGroup parentGroup, int y)
1704     {
1705         throw new UnsupportedOperationException();
1706     }
1707
1708     @Override
1709     public boolean hasProperties()
1710     {
1711         return mergedProperties != null && mergedProperties.hasProperties();
1712     }
1713
1714     @Override
1715     public JRPropertiesMap getPropertiesMap()
1716     {
1717         return mergedProperties;
1718     }
1719
1720     @Override
1721     public JRPropertiesHolder getParentProperties()
1722     {
1723         //element properties default to report properties
1724         return filler.getMainDataset();
1725     }
1726
1727
1728     @Override
1729     public JRPropertyExpression[] getPropertyExpressions()
1730     {
1731         return propertyExpressions.toArray(new JRPropertyExpression[propertyExpressions.size()]);
1732     }
1733     
1734     protected void transferProperties(JRTemplateElement template)
1735     {
1736         filler.getPropertiesUtil().transferProperties(parent, template, 
1737                 JasperPrint.PROPERTIES_PRINT_TRANSFER_PREFIX);
1738     }
1739     
1740     protected void transferProperties(JRPrintElement element)
1741     {
1742         filler.getPropertiesUtil().transferProperties(dynamicProperties, element, 
1743                 dynamicTransferProperties);
1744     }
1745     
1746     protected JRPropertiesMap getEvaluatedProperties()
1747     {
1748         return mergedProperties;
1749     }
1750     
1751     protected void evaluateProperties(byte evaluation) throws JRException
1752     {
1753         if (propertyExpressions.isEmpty())
1754         {
1755             dynamicProperties = null;
1756             mergedProperties = staticProperties;
1757         }
1758         else
1759         {
1760             dynamicProperties = new JRPropertiesMap();
1761             
1762             for (JRPropertyExpression prop : propertyExpressions)
1763             {
1764                 String value = (String) evaluateExpression(prop.getValueExpression(), evaluation);
1765                 //if (value != null) //for some properties such as data properties in metadata exporters, the null value is significant
1766                 {
1767                     dynamicProperties.setProperty(prop.getName(), value);
1768                 }
1769             }
1770             
1771             mergedProperties = dynamicProperties.cloneProperties();
1772             mergedProperties.setBaseProperties(staticProperties);
1773         }
1774     }
1775     
1776     protected void setOriginProvider(JROriginProvider originProvider)
1777     {
1778         this.originProvider = originProvider;
1779     }
1780
1781     protected JROrigin getElementOrigin()
1782     {
1783         JROrigin elementOrigin = null;
1784         if (originProvider != null)
1785         {
1786             elementOrigin = originProvider.getOrigin();
1787         }
1788         return elementOrigin;
1789     }
1790     
1791     protected boolean isDelayedStyleEvaluation()
1792     {
1793         return filler.getPropertiesUtil().getBooleanProperty(this
1794                 JRStyle.PROPERTY_EVALUATION_TIME_ENABLED, false);
1795     }
1796     
1797     public JRBaseFiller getFiller()
1798     {
1799         return filler;
1800     }
1801
1802
1803     @Override
1804     public boolean hasDynamicProperties()
1805     {
1806         return !propertyExpressions.isEmpty();
1807     }
1808
1809     @Override
1810     public boolean hasDynamicProperty(String name)
1811     {
1812         // not called very often for now so doing linear search in array
1813         for (JRPropertyExpression prop : propertyExpressions)
1814         {
1815             if (prop.getName().equals(name))
1816             {
1817                 return true;
1818             }
1819         }
1820         return false;
1821     }
1822
1823     @Override
1824     public JRPropertiesMap getDynamicProperties()
1825     {
1826         return dynamicProperties;
1827     }
1828
1829     protected JRStyle getInitStyle()
1830     {
1831         return initStyle;
1832     }
1833
1834     protected JRElement getParent()
1835     {
1836         return parent;
1837     }
1838     
1839     protected void addDynamicProperty(String name, JRExpression expression)
1840     {
1841         JRDesignPropertyExpression prop = new JRDesignPropertyExpression();
1842         prop.setName(name);
1843         prop.setValueExpression(expression);
1844         
1845         propertyExpressions.add(prop);
1846         // recomputing
1847         dynamicTransferProperties = findDynamicTransferProperties();
1848     }
1849     
1850     protected void setExpressionEvaluator(JRFillExpressionEvaluator expressionEvaluator)
1851     {
1852         this.expressionEvaluator = expressionEvaluator;
1853     }
1854
1855
1856     /**
1857      *
1858      */

1859     public static Integer getBookmarkLevel(Object value) throws JRException
1860     {
1861         Integer level = null;
1862         
1863         if (value != null)
1864         {
1865             if (value instanceof Number)
1866             {
1867                 level = ((Number)value).intValue();
1868             }
1869             else
1870             {
1871                 try
1872                 {
1873                     level = Integer.parseInt(value.toString());
1874                 }
1875                 catch (NumberFormatException e)
1876                 {
1877                     //do nothing
1878                 }
1879             }
1880             
1881             if (level == null || level < 0)
1882             {
1883                 throw 
1884                     new JRException(
1885                         EXCEPTION_MESSAGE_KEY_INVALID_BOOKMARK_LEVEL,  
1886                         new Object[] {value} 
1887                         );
1888             }
1889         }
1890         
1891         return level;
1892     }
1893 }
1894