001: package org.tigris.scarab.screens;
002:
003: /* ================================================================
004: * Copyright (c) 2003 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by CollabNet <http://www.collab.net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of CollabNet.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of CollabNet.
047: */
048:
049: import java.util.Date;
050: import java.util.List;
051: import java.util.Iterator;
052: import java.text.DateFormat;
053: import java.text.SimpleDateFormat;
054:
055: import org.apache.commons.lang.StringUtils;
056:
057: import org.apache.turbine.RunData;
058: import org.apache.turbine.TemplateContext;
059:
060: import org.tigris.scarab.om.ScarabUser;
061: import org.tigris.scarab.reports.ReportBridge;
062: import org.tigris.scarab.reports.ReportDate;
063: import org.tigris.scarab.reports.ReportGroup;
064: import org.tigris.scarab.reports.ReportOptionAttribute;
065: import org.tigris.scarab.reports.ReportHeading;
066: import org.tigris.scarab.reports.ReportTableModel;
067: import org.tigris.scarab.reports.ReportUserAttribute;
068: import org.tigris.scarab.tools.Format;
069: import org.tigris.scarab.tools.ScarabRequestTool;
070: import org.tigris.scarab.tools.ScarabLocalizationTool;
071: import org.tigris.scarab.util.Log;
072:
073: /**
074: * Handles export of a report to non-web formats.
075: *
076: * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
077: * @version $Id: ReportExport.java 8704 2003-10-17 10:02:07Z dep4b $
078: * @see org.tigris.scarab.screens.DataExport
079: * @since Scarab 1.0
080: */
081: public class ReportExport extends DataExport {
082: /**
083: * What to show if a header cell is empty.
084: */
085: private static final String NO_HEADER = "=======";
086:
087: /**
088: * Writes the response.
089: *
090: * Modelled after the <code>#reportTable()</code> Velocimacro.
091: */
092: public void doBuildTemplate(RunData data, TemplateContext context)
093: throws Exception {
094: super .doBuildTemplate(data, context);
095:
096: ScarabLocalizationTool l10n = getLocalizationTool(context);
097: ScarabUser user = (ScarabUser) data.getUser();
098: TSVPrinter printer = new TSVPrinter(getWriter(data));
099:
100: ScarabRequestTool scarabR = getScarabRequestTool(context);
101: ReportBridge report = scarabR.getReport();
102:
103: // --------------------------------------------------------
104: // This code is not generally excercised as the action will
105: // not redirect to this screen if the following conditions are
106: // present. But is here to protect against url hacking.
107: try {
108: String message = (String) scarabR.getInfoMessage();
109: if (message != null && message.length() > 0) {
110: printer.print(message);
111: }
112: } catch (Exception e) {
113: printer.print(l10n.get("ErrorOccurredCheckingMessage"));
114: }
115:
116: if (!report.isReadyForCalculation()) {
117: printer.print(l10n.get("IncompleteReportDefinition"));
118: return;
119: }
120:
121: if (report.getReportDefinition().reportQueryIsExpensive()) {
122: printer.print(l10n.format("ReportIsTooExpensive", String
123: .valueOf(report.getReportDefinition()
124: .maximumHeadings())));
125: return;
126: }
127: // --------------------------------------------------------
128:
129: ReportTableModel model = report.getModel(user);
130:
131: List rowHeadings = model.getRowHeadings();
132: List columnHeadings = model.getColumnHeadings();
133: int multiplier = 1;
134: for (int level = 0; level < columnHeadings.size(); level++) {
135: ReportHeading columnHeadingLevel = (ReportHeading) columnHeadings
136: .get(level);
137: int maxBlank = rowHeadings.size() - 1;
138: if (maxBlank > 0) {
139: for (int i = 1; i <= maxBlank; i++) {
140: // Empty heading cell.
141: printer.print(NO_HEADER);
142: }
143: }
144:
145: boolean singleAttribute = columnHeadingLevel
146: .singleAttribute();
147: // It would be preferable to concatenate an arrow
148: // pointing to the right to the return value of
149: // displayAttribute(), but I wasn't able to come up with a
150: // good "down arrow" for the X-axis headings.
151: printer.print(singleAttribute ? model
152: .displayAttribute(columnHeadingLevel.get(0))
153: : NO_HEADER);
154: int colspan = model.getColspan(level);
155: for (int i = 1; i <= multiplier; i++) {
156: for (int nextIndex = 1; nextIndex <= columnHeadingLevel
157: .size(); nextIndex++) {
158: Object heading = columnHeadingLevel
159: .get(nextIndex - 1);
160: printer.print(reportLabel(model, heading,
161: singleAttribute, l10n));
162: }
163: if (colspan > 1) {
164: for (int j = 2; j <= colspan; j++) {
165: printer.print(NO_HEADER);
166: }
167: }
168: }
169:
170: // End of first heading row.
171: printer.println();
172: multiplier *= columnHeadingLevel.size();
173: }
174:
175: for (Iterator i = rowHeadings.iterator(); i.hasNext();) {
176: i.next();
177: printer.print(NO_HEADER);
178: }
179: int nbrColumns = model.getColumnCount();
180: for (int i = 0; i < nbrColumns; i++) {
181: printer.print(NO_HEADER);
182: }
183: printer.println();
184:
185: int nbrRows = model.getRowCount();
186:
187: if (rowHeadings.size() > 1
188: || ((ReportHeading) rowHeadings.get(0))
189: .singleAttribute()) {
190: for (int level = 0; level < rowHeadings.size(); level++) {
191: ReportHeading curHeading = (ReportHeading) rowHeadings
192: .get(level);
193: boolean singleAttribute = curHeading.singleAttribute();
194: // "Down arrow" is prepend to displayAttribute() in
195: // web view.
196: printer.print(singleAttribute ? model
197: .displayAttribute(curHeading.get(0))
198: : NO_HEADER);
199:
200: }
201: for (int i = 0; i < nbrRows; i++) {
202: printer.print(NO_HEADER);
203: }
204: printer.println();
205: }
206:
207: DateFormat dateFormat = new SimpleDateFormat(
208: Format.DATE_TIME_FMT);
209: for (int rowIndex = 0; rowIndex < nbrRows; rowIndex++) {
210: for (int level = 0; level < rowHeadings.size(); level++) {
211: ReportHeading curHeading = (ReportHeading) rowHeadings
212: .get(level);
213: boolean singleAttribute = curHeading.singleAttribute();
214: int rowspan = model.getRowspan(level);
215: if ((rowIndex % rowspan) == 0) {
216: int index = (rowIndex / rowspan)
217: % curHeading.size();
218: printer.print(reportLabel(model, curHeading
219: .get(index), singleAttribute, l10n));
220: } else {
221: printer.print(NO_HEADER);
222: }
223: }
224:
225: for (int columnIndex = 0; columnIndex < nbrColumns; columnIndex++) {
226: Object cell = model.getValueAt(rowIndex, columnIndex);
227: String cellData = (ReportTableModel.isDate(cell) ? dateFormat
228: .format((Date) cell)
229: : cell.toString());
230: if (StringUtils.isEmpty(cellData)) {
231: cellData = NO_CONTENT;
232: }
233: printer.print(cellData);
234: }
235:
236: printer.println();
237: }
238: }
239:
240: /**
241: * Makes a report label. Modelled after the
242: * <code>#reportLabel()</code> Velocimacro.
243: */
244: private String reportLabel(ReportTableModel model,
245: Object cellLabel, boolean singleAttribute,
246: ScarabLocalizationTool l10n) {
247: if (model.isReportDate(cellLabel)) {
248: return Format.getDate(Format.DATE_TIME_FMT,
249: ((ReportDate) cellLabel).dateValue());
250: } else if (model.isOption(cellLabel)) {
251: ReportOptionAttribute roa = (ReportOptionAttribute) cellLabel;
252: return (singleAttribute ? model.displayOption(roa) : model
253: .displayAttribute(roa)
254: + ": " + model.displayOption(roa));
255: } else if (model.isOptionGroup(cellLabel)) {
256: return ((ReportGroup) cellLabel).getName();
257: } else if (model.isAttributeAndUser(cellLabel)) {
258: ReportUserAttribute rua = (ReportUserAttribute) cellLabel;
259: return (singleAttribute ? model.displayUser(rua) : model
260: .displayAttribute(rua)
261: + ": " + model.displayUser(rua));
262: } else if (model.isUser(cellLabel)) {
263: return l10n.get("Author") + ": "
264: + ((ScarabUser) cellLabel).getUserName();
265: } else {
266: Log.get().debug(
267: "Unhandled cell label type: "
268: + cellLabel.getClass().getName());
269: return cellLabel.toString();
270: }
271: }
272: }
|