001: /*
002: * ============================================================================
003: * GNU Lesser General Public License
004: * ============================================================================
005: *
006: * JasperReports - Free Java report-generating library.
007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * JasperSoft Corporation
024: * 303 Second Street, Suite 450 North
025: * San Francisco, CA 94107
026: * http://www.jaspersoft.com
027: */
028: package net.sf.jasperreports.engine.design;
029:
030: import java.util.ArrayList;
031: import java.util.Collection;
032: import java.util.HashMap;
033: import java.util.HashSet;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.Map;
037:
038: import net.sf.jasperreports.crosstabs.JRCrosstab;
039: import net.sf.jasperreports.crosstabs.design.JRDesignCrosstab;
040: import net.sf.jasperreports.engine.JRBand;
041: import net.sf.jasperreports.engine.JRConstants;
042: import net.sf.jasperreports.engine.JRDataset;
043: import net.sf.jasperreports.engine.JRElement;
044: import net.sf.jasperreports.engine.JRException;
045: import net.sf.jasperreports.engine.JRExpression;
046: import net.sf.jasperreports.engine.JRExpressionCollector;
047: import net.sf.jasperreports.engine.JRField;
048: import net.sf.jasperreports.engine.JRFrame;
049: import net.sf.jasperreports.engine.JRGroup;
050: import net.sf.jasperreports.engine.JRParameter;
051: import net.sf.jasperreports.engine.JRReportFont;
052: import net.sf.jasperreports.engine.JRReportTemplate;
053: import net.sf.jasperreports.engine.JRSortField;
054: import net.sf.jasperreports.engine.JRStyle;
055: import net.sf.jasperreports.engine.JRVariable;
056: import net.sf.jasperreports.engine.base.JRBaseReport;
057:
058: /**
059: * JasperDesign is used for in-memory representation of a report design. Instances of this class can be easily
060: * created from an XML template and viceversa. It contains all report properties and report elements in their design time
061: * state.
062: * <p>
063: * The main reason for using this class is for modifying report templates at run time. Although using compiled reports
064: * is usually recommended, sometimes people need to dinamically change a report design.
065: *
066: * @see net.sf.jasperreports.engine.xml.JRXmlLoader
067: * @author Teodor Danciu (teodord@users.sourceforge.net)
068: * @version $Id: JasperDesign.java 1795 2007-07-30 09:18:47Z teodord $
069: */
070: public class JasperDesign extends JRBaseReport {
071: /**
072: *
073: */
074: private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID;
075:
076: /**
077: * Report templates.
078: */
079: private List templateList = new ArrayList();
080:
081: private Map fontsMap = new HashMap();
082: private List fontsList = new ArrayList();
083: private Map stylesMap = new HashMap();
084: private List stylesList = new ArrayList();
085:
086: /**
087: * Main report dataset.
088: */
089: private JRDesignDataset mainDesignDataset;
090:
091: /**
092: * Report sub datasets indexed by name.
093: */
094: private Map datasetMap = new HashMap();
095: private List datasetList = new ArrayList();
096:
097: private transient List crosstabs;
098:
099: /**
100: * Constructs a JasperDesign object and fills it with the default variables and parameters.
101: */
102: public JasperDesign() {
103: setMainDataset(new JRDesignDataset(true));
104: }
105:
106: /**
107: * Sets the report name. It is strongly recommended that the report name matches the .jrxml file name, since report compilers
108: * usually use this name for the compiled .jasper file.
109: */
110: public void setName(String name) {
111: this .name = name;
112: this .mainDesignDataset.setName(name);
113: }
114:
115: /**
116: * Specifies the language used for report expressions (Java or Groovy). The default is Java.
117: */
118: public void setLanguage(String language) {
119: this .language = language;
120: }
121:
122: /**
123: * Specifies the number of report columns.
124: */
125: public void setColumnCount(int columnCount) {
126: this .columnCount = columnCount;
127: }
128:
129: /**
130: * Sets the print order. In case of multiple column reports, the engine can perform vertical or horizontal fill.
131: * @see net.sf.jasperreports.engine.JRReport PRINT_ORDER_VERTICAL,
132: * @see net.sf.jasperreports.engine.JRReport PRINT_ORDER_HORIZONTAL
133: */
134: public void setPrintOrder(byte printOrder) {
135: this .printOrder = printOrder;
136: }
137:
138: /**
139: * Sets page width (including margins etc.). Default is 595.
140: */
141: public void setPageWidth(int pageWidth) {
142: this .pageWidth = pageWidth;
143: }
144:
145: /**
146: * Sets page height (including margins etc.). Default is 842.
147: */
148: public void setPageHeight(int pageHeight) {
149: this .pageHeight = pageHeight;
150: }
151:
152: /**
153: * Sets the report orientation.
154: * @see net.sf.jasperreports.engine.JRReport ORIENTATION_PORTRAIT,
155: * @see net.sf.jasperreports.engine.JRReport ORIENTATION_LANDSCAPE
156: */
157: public void setOrientation(byte orientation) {
158: this .orientation = orientation;
159: }
160:
161: /**
162: * Sets the column width.
163: */
164: public void setColumnWidth(int columnWidth) {
165: this .columnWidth = columnWidth;
166: }
167:
168: /**
169: * Sets the spacing between columns.
170: */
171: public void setColumnSpacing(int columnSpacing) {
172: this .columnSpacing = columnSpacing;
173: }
174:
175: /**
176: * Sets the left margin. The working space is calculated by subtracting the margins from the page width.
177: */
178: public void setLeftMargin(int leftMargin) {
179: this .leftMargin = leftMargin;
180: }
181:
182: /**
183: * Sets the right margin. The working space is calculated by subtracting the margins from the page width.
184: */
185: public void setRightMargin(int rightMargin) {
186: this .rightMargin = rightMargin;
187: }
188:
189: /**
190: * Sets the top margin. The working space is calculated by subtracting the margins from the page height.
191: */
192: public void setTopMargin(int topMargin) {
193: this .topMargin = topMargin;
194: }
195:
196: /**
197: * Sets the top margin. The working space is calculated by subtracting the margins from the page height.
198: */
199: public void setBottomMargin(int bottomMargin) {
200: this .bottomMargin = bottomMargin;
201: }
202:
203: /**
204: * Sets the background band.
205: */
206: public void setBackground(JRBand background) {
207: this .background = background;
208: }
209:
210: /**
211: * Sets the title band.
212: */
213: public void setTitle(JRBand title) {
214: this .title = title;
215: }
216:
217: /**
218: * Flag used to specify if the title section should be printed on a separate initial page.
219: *
220: * @param isTitleNewPage true if the title section should be displayed on a separate initial page, false if
221: * it will be displayed on the first page along with other sections.
222: */
223: public void setTitleNewPage(boolean isTitleNewPage) {
224: this .isTitleNewPage = isTitleNewPage;
225: }
226:
227: /**
228: * Sets the summary band.
229: */
230: public void setSummary(JRBand summary) {
231: this .summary = summary;
232: }
233:
234: /**
235: * Sets the noData band.
236: */
237: public void setNoData(JRBand noData) {
238: this .noData = noData;
239: }
240:
241: /**
242: * Flag used to specify if the summary section should be printed on a separate last page.
243: *
244: * @param isSummaryNewPage true if the summary section should be displayed on a separate last page, false if
245: * it will be displayed on the last page along with other sections, if there is enough space.
246: */
247: public void setSummaryNewPage(boolean isSummaryNewPage) {
248: this .isSummaryNewPage = isSummaryNewPage;
249: }
250:
251: /**
252: * Flag used to specify if the column footer section should be printed at the bottom of the column or if it
253: * should immediately follow the last detail or group footer printed on the current column.
254: */
255: public void setFloatColumnFooter(boolean isFloatColumnFooter) {
256: this .isFloatColumnFooter = isFloatColumnFooter;
257: }
258:
259: /**
260: * Sets the page header band.
261: */
262: public void setPageHeader(JRBand pageHeader) {
263: this .pageHeader = pageHeader;
264: }
265:
266: /**
267: * Sets the page footer band.
268: */
269: public void setPageFooter(JRBand pageFooter) {
270: this .pageFooter = pageFooter;
271: }
272:
273: /**
274: * Sets the last page footer band.
275: */
276: public void setLastPageFooter(JRBand lastPageFooter) {
277: this .lastPageFooter = lastPageFooter;
278: }
279:
280: /**
281: * Sets the column header band.
282: */
283: public void setColumnHeader(JRBand columnHeader) {
284: this .columnHeader = columnHeader;
285: }
286:
287: /**
288: * Sets the column footer band.
289: */
290: public void setColumnFooter(JRBand columnFooter) {
291: this .columnFooter = columnFooter;
292: }
293:
294: /**
295: * Sets the detail band.
296: */
297: public void setDetail(JRBand detail) {
298: this .detail = detail;
299: }
300:
301: /**
302: *
303: */
304: public void setScriptletClass(String scriptletClass) {
305: mainDesignDataset.setScriptletClass(scriptletClass);
306: }
307:
308: /**
309: *
310: */
311: public void setFormatFactoryClass(String formatFactoryClass) {
312: this .formatFactoryClass = formatFactoryClass;
313: }
314:
315: /**
316: * Sets the base name of the report associated resource bundle.
317: */
318: public void setResourceBundle(String resourceBundle) {
319: mainDesignDataset.setResourceBundle(resourceBundle);
320: }
321:
322: /**
323: * Adds an import (needed if report expression require additional classes in order to compile).
324: */
325: public void addImport(String value) {
326: if (importsSet == null) {
327: importsSet = new HashSet();
328: }
329: importsSet.add(value);
330: }
331:
332: /**
333: * Removes an import.
334: */
335: public void removeImport(String value) {
336: if (importsSet != null) {
337: importsSet.remove(value);
338: }
339: }
340:
341: /**
342: * @deprecated
343: */
344: public void setDefaultFont(JRReportFont font) {
345: this .defaultFont = font;
346: }
347:
348: /**
349: * Gets an array of report level fonts. These fonts can be referenced by text elements.
350: * @deprecated
351: */
352: public JRReportFont[] getFonts() {
353: JRReportFont[] fontsArray = new JRReportFont[fontsList.size()];
354:
355: fontsList.toArray(fontsArray);
356:
357: return fontsArray;
358: }
359:
360: /**
361: * Gets a list of report level fonts. These fonts can be referenced by text elements.
362: * @deprecated
363: */
364: public List getFontsList() {
365: return fontsList;
366: }
367:
368: /**
369: * @deprecated
370: */
371: public Map getFontsMap() {
372: return fontsMap;
373: }
374:
375: /**
376: * Adds a report font, that can be referenced by text elements.
377: * @deprecated
378: */
379: public void addFont(JRReportFont reportFont) throws JRException {
380: if (fontsMap.containsKey(reportFont.getName())) {
381: throw new JRException(
382: "Duplicate declaration of report font : "
383: + reportFont.getName());
384: }
385:
386: fontsList.add(reportFont);
387: fontsMap.put(reportFont.getName(), reportFont);
388:
389: if (reportFont.isDefault()) {
390: setDefaultFont(reportFont);
391: }
392: }
393:
394: /**
395: * Removes a report font from the list, based on the font name.
396: * @deprecated
397: */
398: public JRReportFont removeFont(String propName) {
399: return removeFont((JRReportFont) fontsMap.get(propName));
400: }
401:
402: /**
403: * Removes a report font from the list.
404: * @deprecated
405: */
406: public JRReportFont removeFont(JRReportFont reportFont) {
407: if (reportFont != null) {
408: if (reportFont.isDefault()) {
409: setDefaultFont(null);
410: }
411:
412: fontsList.remove(reportFont);
413: fontsMap.remove(reportFont.getName());
414: }
415:
416: return reportFont;
417: }
418:
419: /**
420: *
421: */
422: public void setDefaultStyle(JRStyle style) {
423: this .defaultStyle = style;
424: }
425:
426: /**
427: * Gets an array of report level styles. These styles can be referenced by report elements.
428: */
429: public JRStyle[] getStyles() {
430: JRStyle[] stylesArray = new JRStyle[stylesList.size()];
431:
432: stylesList.toArray(stylesArray);
433:
434: return stylesArray;
435: }
436:
437: /**
438: * Gets a list of report level styles. These styles can be referenced by report elements.
439: */
440: public List getStylesList() {
441: return stylesList;
442: }
443:
444: /**
445: *
446: */
447: public Map getStylesMap() {
448: return stylesMap;
449: }
450:
451: /**
452: * Adds a report style, that can be referenced by report elements.
453: */
454: public void addStyle(JRStyle style) throws JRException {
455: if (stylesMap.containsKey(style.getName())) {
456: throw new JRException(
457: "Duplicate declaration of report style : "
458: + style.getName());
459: }
460:
461: stylesList.add(style);
462: stylesMap.put(style.getName(), style);
463:
464: if (style.isDefault()) {
465: setDefaultStyle(style);
466: }
467: }
468:
469: /**
470: * Removes a report style from the list, based on the style name.
471: */
472: public JRStyle removeStyle(String styleName) {
473: return removeStyle((JRStyle) stylesMap.get(styleName));
474: }
475:
476: /**
477: * Removes a report style from the list.
478: */
479: public JRStyle removeStyle(JRStyle style) {
480: if (style != null) {
481: if (style.isDefault()) {
482: setDefaultStyle(null);
483: }
484:
485: stylesList.remove(style);
486: stylesMap.remove(style.getName());
487: }
488:
489: return style;
490: }
491:
492: /**
493: * Gets a list of report parameters (including built-in ones).
494: */
495: public List getParametersList() {
496: return mainDesignDataset.getParametersList();
497: }
498:
499: /**
500: * Gets a map of report parameters (including built-in ones).
501: */
502: public Map getParametersMap() {
503: return mainDesignDataset.getParametersMap();
504: }
505:
506: /**
507: * Adds a report parameter.
508: */
509: public void addParameter(JRParameter parameter) throws JRException {
510: mainDesignDataset.addParameter(parameter);
511: }
512:
513: /**
514: * Removes a report parameter, based on its name.
515: */
516: public JRParameter removeParameter(String parameterName) {
517: return mainDesignDataset.removeParameter(parameterName);
518: }
519:
520: /**
521: * Removes a report parameter.
522: */
523: public JRParameter removeParameter(JRParameter parameter) {
524: return mainDesignDataset.removeParameter(parameter);
525: }
526:
527: /**
528: * Specifies the report query. This is used only when datasource type is JDBC (a <tt>java.sql.Connection</tt>).
529: */
530: public void setQuery(JRDesignQuery query) {
531: mainDesignDataset.setQuery(query);
532: }
533:
534: /**
535: * Gets a list of report fields.
536: */
537: public List getFieldsList() {
538: return mainDesignDataset.getFieldsList();
539: }
540:
541: /**
542: * Gets a map of report fields.
543: */
544: public Map getFieldsMap() {
545: return mainDesignDataset.getFieldsMap();
546: }
547:
548: /**
549: *
550: */
551: public void addField(JRField field) throws JRException {
552: mainDesignDataset.addField(field);
553: }
554:
555: /**
556: *
557: */
558: public JRField removeField(String fieldName) {
559: return mainDesignDataset.removeField(fieldName);
560: }
561:
562: /**
563: *
564: */
565: public JRField removeField(JRField field) {
566: return mainDesignDataset.removeField(field);
567: }
568:
569: /**
570: * Gets a list of sort report fields.
571: */
572: public List getSortFieldsList() {
573: return mainDesignDataset.getSortFieldsList();
574: }
575:
576: /**
577: *
578: */
579: public void addSortField(JRSortField sortField) throws JRException {
580: mainDesignDataset.addSortField(sortField);
581: }
582:
583: /**
584: *
585: */
586: public JRSortField removeSortField(String fieldName) {
587: return mainDesignDataset.removeSortField(fieldName);
588: }
589:
590: /**
591: *
592: */
593: public JRSortField removeSortField(JRSortField sortField) {
594: return mainDesignDataset.removeSortField(sortField);
595: }
596:
597: /**
598: * Gets a list of report variables.
599: */
600: public List getVariablesList() {
601: return mainDesignDataset.getVariablesList();
602: }
603:
604: /**
605: * Gets a map of report variables.
606: */
607: public Map getVariablesMap() {
608: return mainDesignDataset.getVariablesMap();
609: }
610:
611: /**
612: *
613: */
614: public void addVariable(JRDesignVariable variable)
615: throws JRException {
616: mainDesignDataset.addVariable(variable);
617: }
618:
619: /**
620: *
621: */
622: public JRVariable removeVariable(String variableName) {
623: return mainDesignDataset.removeVariable(variableName);
624: }
625:
626: /**
627: *
628: */
629: public JRVariable removeVariable(JRVariable variable) {
630: return mainDesignDataset.removeVariable(variable);
631: }
632:
633: /**
634: * Gets an array of report groups.
635: */
636: public List getGroupsList() {
637: return mainDesignDataset.getGroupsList();
638: }
639:
640: /**
641: * Gets a list of report groups.
642: */
643: public Map getGroupsMap() {
644: return mainDesignDataset.getGroupsMap();
645: }
646:
647: /**
648: * Gets a map of report groups.
649: */
650: public void addGroup(JRDesignGroup group) throws JRException {
651: mainDesignDataset.addGroup(group);
652: }
653:
654: /**
655: * Adds a new group to the report design. Groups are nested.
656: */
657: public JRGroup removeGroup(String groupName) {
658: return mainDesignDataset.removeGroup(groupName);
659: }
660:
661: /**
662: *
663: */
664: public JRGroup removeGroup(JRGroup group) {
665: return mainDesignDataset.removeGroup(group);
666: }
667:
668: /**
669: * Returns a collection of all report expressions.
670: */
671: public Collection getExpressions() {
672: return JRExpressionCollector.collectExpressions(this );
673: }
674:
675: public JRDataset[] getDatasets() {
676: JRDataset[] datasetArray = new JRDataset[datasetList.size()];
677: datasetList.toArray(datasetArray);
678: return datasetArray;
679: }
680:
681: /**
682: * Returns the list of report sub datasets.
683: *
684: * @return list of {@link JRDesignDataset JRDesignDataset} objects
685: */
686: public List getDatasetsList() {
687: return datasetList;
688: }
689:
690: /**
691: * Returns the sub datasets of the report indexed by name.
692: *
693: * @return the sub datasets of the report indexed by name
694: */
695: public Map getDatasetMap() {
696: return datasetMap;
697: }
698:
699: /**
700: * Adds a sub dataset to the report.
701: *
702: * @param dataset the dataset
703: * @throws JRException
704: */
705: public void addDataset(JRDesignDataset dataset) throws JRException {
706: if (datasetMap.containsKey(dataset.getName())) {
707: throw new JRException("Duplicate declaration of dataset : "
708: + dataset.getName());
709: }
710:
711: datasetList.add(dataset);
712: datasetMap.put(dataset.getName(), dataset);
713: }
714:
715: /**
716: * Removes a sub dataset from the report.
717: *
718: * @param datasetName the dataset name
719: * @return the removed dataset
720: */
721: public JRDataset removeDataset(String datasetName) {
722: return removeDataset((JRDataset) datasetMap.get(datasetName));
723: }
724:
725: /**
726: * Removes a sub dataset from the report.
727: *
728: * @param dataset the dataset to be removed
729: * @return the dataset
730: */
731: public JRDataset removeDataset(JRDataset dataset) {
732: if (dataset != null) {
733: datasetList.remove(dataset);
734: datasetMap.remove(dataset.getName());
735: }
736:
737: return dataset;
738: }
739:
740: /**
741: * Returns the main report dataset.
742: *
743: * @return the main report dataset
744: */
745: public JRDesignDataset getMainDesignDataset() {
746: return mainDesignDataset;
747: }
748:
749: /**
750: * Sets the main report dataset.
751: * <p>
752: * This method can be used as an alternative to setting the parameters, fields, etc directly on the report.
753: *
754: * @param dataset the dataset
755: */
756: public void setMainDataset(JRDesignDataset dataset) {
757: this .mainDataset = this .mainDesignDataset = dataset;
758: this .mainDesignDataset.setName(getName());
759: }
760:
761: /**
762: * Performs preliminary processing and calculations prior to compilation.
763: */
764: public void preprocess() {
765: collectCrosstabs();
766:
767: for (Iterator it = crosstabs.iterator(); it.hasNext();) {
768: JRDesignCrosstab crosstab = (JRDesignCrosstab) it.next();
769: crosstab.preprocess();
770: }
771: }
772:
773: protected List getCrosstabs() {
774: if (crosstabs == null) {
775: collectCrosstabs();
776: }
777:
778: return crosstabs;
779: }
780:
781: protected List collectCrosstabs() {
782: crosstabs = new ArrayList();
783: collectCrosstabs(background);
784: collectCrosstabs(title);
785: collectCrosstabs(pageHeader);
786: collectCrosstabs(columnHeader);
787: collectCrosstabs(detail);
788: collectCrosstabs(columnFooter);
789: collectCrosstabs(pageFooter);
790: collectCrosstabs(lastPageFooter);
791: collectCrosstabs(summary);
792: collectCrosstabs(noData);
793:
794: JRGroup[] groups = getGroups();
795: if (groups != null) {
796: for (int i = 0; i < groups.length; i++) {
797: collectCrosstabs(groups[i].getGroupHeader());
798: collectCrosstabs(groups[i].getGroupFooter());
799: }
800: }
801:
802: return crosstabs;
803: }
804:
805: protected void collectCrosstabs(JRBand band) {
806: if (band != null) {
807: collectCrosstabs(band.getElements());
808: }
809: }
810:
811: protected void collectCrosstabs(JRElement[] elements) {
812: if (elements != null) {
813: for (int i = 0; i < elements.length; i++) {
814: JRElement element = elements[i];
815: if (element instanceof JRCrosstab) {
816: crosstabs.add(element);
817: } else if (element instanceof JRFrame) {
818: JRFrame frame = (JRFrame) element;
819: collectCrosstabs(frame.getElements());
820: }
821: }
822: }
823: }
824:
825: /**
826: * Sets the value of the ignore pagination flag.
827: *
828: * @param ignorePagination whether to ignore pagination when generating the report
829: * @see net.sf.jasperreports.engine.JRReport#isIgnorePagination()
830: */
831: public void setIgnorePagination(boolean ignorePagination) {
832: this .ignorePagination = ignorePagination;
833: }
834:
835: /**
836: * Returns the main dataset filter expression.
837: *
838: * @return the main dataset filter expression
839: * @see JRDataset#getFilterExpression()
840: */
841: public JRExpression getFilterExpression() {
842: return mainDesignDataset.getFilterExpression();
843: }
844:
845: /**
846: * Sets the main dataset filter expression.
847: *
848: * @param expression the boolean expression to use as main dataset filter expression
849: * @see JRDesignDataset#setFilterExpression(JRExpression)
850: * @see JRDataset#getFilterExpression()
851: */
852: public void setFilterExpression(JRExpression expression) {
853: mainDesignDataset.setFilterExpression(expression);
854: }
855:
856: /**
857: * Adds a report template.
858: *
859: * @param template the template to add.
860: * @see #getTemplates()
861: */
862: public void addTemplate(JRReportTemplate template) {
863: templateList.add(template);
864: }
865:
866: /**
867: * Removes a report template.
868: *
869: * @param template the template to remove
870: * @return <code>true</code> iff the template has been found and removed
871: */
872: public boolean removeTemplate(JRReportTemplate template) {
873: return templateList.remove(template);
874: }
875:
876: public JRReportTemplate[] getTemplates() {
877: return (JRReportTemplate[]) templateList
878: .toArray(new JRReportTemplate[templateList.size()]);
879: }
880:
881: }
|