KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jimm > datavision > Report


1 package jimm.datavision;
2 import jimm.datavision.field.*;
3 import jimm.datavision.layout.LayoutEngine;
4 import jimm.datavision.source.*;
5 import jimm.datavision.source.sql.Database;
6 import jimm.datavision.gui.sql.DbPasswordDialog;
7 import jimm.datavision.gui.Designer;
8 import jimm.datavision.gui.StatusDialog;
9 import jimm.datavision.gui.parameter.ParamAskWin;
10 import jimm.util.I18N;
11 import jimm.util.XMLWriter;
12 import java.awt.Frame JavaDoc;
13 import java.io.*;
14 import java.util.*;
15 import java.sql.*;
16 import javax.swing.JOptionPane JavaDoc;
17 import javax.swing.JFileChooser JavaDoc;
18 import org.xml.sax.*;
19 import org.apache.bsf.BSFException;
20
21 /**
22  * A report holds data source information, accepts parameters from the user,
23  * runs a query, and uses a layout engine to format the output. It may
24  * contain many different sections, each of which can contain logic for
25  * surpressing itself.
26  *
27  * @author Jim Menard, <a HREF="mailto:jimm@io.com">jimm@io.com</a>
28  */

29 public class Report implements Nameable, Writeable {
30
31 /**
32  * The string to use when reading and writing XML files. Pass it to
33  * OutputStreamWriters and InputStreamReaders.
34  */

35 public static final String JavaDoc XML_JAVA_ENCODING = "UTF8";
36 /**
37  * The string to write at the top of an XML file in the XML decl.
38  */

39 public static final String JavaDoc XML_ENCODING_ATTRIBUTE = "UTF-8";
40
41 protected static final double OUTPUT_DTD_VERSION = 1.2;
42
43 protected String JavaDoc name;
44 protected String JavaDoc title;
45 protected String JavaDoc author;
46 protected String JavaDoc description;
47 protected Formula startFormula;
48 protected DataSource dataSource;
49 protected HashMap formulas;
50 protected HashMap parameters;
51 protected HashMap usercols;
52 protected HashMap subreports;
53 protected ArrayList groups;
54 protected SectionArea reportHeaders;
55 protected SectionArea reportFooters;
56 protected SectionArea pageHeaders;
57 protected SectionArea pageFooters;
58 protected SectionArea details;
59 protected DataCursor rset;
60 protected LayoutEngine layoutEngine;
61 protected PaperFormat paperFormat;
62 protected Collection aggregateFields;
63 protected String JavaDoc databasePassword;
64 protected boolean askedForParameters;
65 protected boolean parametersHaveValues;
66 protected boolean paramsSetManually;
67 protected boolean dataSourceHasFile;
68 protected ParameterReader paramReader;
69 /** Flag for Database data sources. */
70 protected boolean caseSensitiveDatabaseNames;
71 protected Scripting scripting;
72 /**
73  * This field holds default format, border, and bounds values for all fields.
74  * For all format ivars, if the value of the ivar is null then the value is
75  * obtained from this default field's format.
76  */

77 protected Field defaultField;
78
79 /**
80  * Constructs an empty report.
81  */

82 public Report() {
83     formulas = new HashMap();
84     parameters = new HashMap();
85     usercols = new HashMap();
86     subreports = new HashMap();
87     groups = new ArrayList();
88     name = I18N.get("Report.default_name");
89     title = I18N.get("Report.default_title");
90     askedForParameters = false;
91     parametersHaveValues = false;
92     paramsSetManually = false;
93     dataSourceHasFile = false;
94     caseSensitiveDatabaseNames = true;
95     paperFormat = PaperFormat.getDefault();
96     scripting = new Scripting(this);
97
98     defaultField = Field.create(new Long JavaDoc(0), this, null, "text",
99                 I18N.get("Report.default_field_name"), true);
100     defaultField.setFormat(Format.createDefaultFormat());
101     defaultField.setBorder(new Border(defaultField));
102
103     initializeSections();
104 }
105
106 public void initializeSections() {
107     reportHeaders = new SectionArea(SectionArea.REPORT_HEADER);
108     reportFooters = new SectionArea(SectionArea.REPORT_FOOTER);
109     pageHeaders = new SectionArea(SectionArea.PAGE_HEADER);
110     pageFooters = new SectionArea(SectionArea.PAGE_FOOTER);
111     details = new SectionArea(SectionArea.DETAIL);
112
113     reportHeaders.add(new Section(this));
114     pageHeaders.add(new Section(this));
115     pageFooters.add(new Section(this));
116     reportFooters.add(new Section(this));
117     details.add(new Section(this));
118 }
119
120 /**
121  * Sets the layout engine to use.
122  *
123  * @param layoutEngine a layout engine
124  */

125 public void setLayoutEngine(LayoutEngine layoutEngine) {
126     this.layoutEngine = layoutEngine;
127     this.layoutEngine.setReport(this);
128 }
129
130 /**
131  * Generates and returns a new unique id number. The number is one larger
132  * than the largest in a given list of {@link Identity} objects whose
133  * identifiers must be <code>Long</code> objects.
134  *
135  * @param iter an iterator over a collection if <code>Identity</code>
136  * objects whose identifiers must be <code>Long</code>s
137  * @return a <code>Long</code>
138  */

139 protected Long JavaDoc generateNewId(Iterator iter) {
140     long max = 0;
141     while (iter.hasNext()) {
142     Object JavaDoc id = ((Identity)iter.next()).getId();
143     long longVal = ((Long JavaDoc)id).longValue();
144     if (longVal > max)
145         max = longVal;
146     }
147     return new Long JavaDoc(max + 1);
148 }
149
150 /**
151  * Generates and returns a new unique formula id number.
152  *
153  * @return a long id
154  */

155 public Long JavaDoc generateNewFormulaId() {
156     return generateNewId(formulas.values().iterator());
157 }
158
159 /**
160  * Generates and returns a new unique parameter id number.
161  *
162  * @return a long id
163  */

164 public Long JavaDoc generateNewParameterId() {
165     return generateNewId(parameters.values().iterator());
166 }
167
168 /**
169  * Generates and returns a new unique user column id number.
170  *
171  * @return a long id
172  */

173 public Long JavaDoc generateNewUserColumnId() {
174     return generateNewId(usercols.values().iterator());
175 }
176
177 /**
178  * Generates and returns a new unique user column id number.
179  *
180  * @return a long id
181  */

182 public Long JavaDoc generateNewSubreportId() {
183     return generateNewId(subreports.values().iterator());
184 }
185
186 /**
187  * Given an id, returns the field that has that id. If no field with the
188  * specified id exists, returns <code>null</code>.
189  *
190  * @return a field, or <code>null</code> if no field with the specified
191  * id exists
192  */

193 public Field findField(final Object JavaDoc id) {
194     final Field listOfOne[] = new Field[1];
195     listOfOne[0] = null;
196     withSectionsDo(new SectionWalker() {
197     public void step(Section s) {
198         Field f = s.findField(id);
199         if (f != null) listOfOne[0] = f;
200     }
201     });
202     return listOfOne[0];
203 }
204
205 public String JavaDoc getName() { return name; }
206 public void setName(String JavaDoc newName) { name = newName; }
207
208 public String JavaDoc getTitle() { return title; }
209 public void setTitle(String JavaDoc newTitle) { title = newTitle; }
210
211 public String JavaDoc getAuthor() { return author; }
212 public void setAuthor(String JavaDoc newAuthor) { author = newAuthor; }
213
214 public String JavaDoc getDescription() { return description; }
215 public void setDescription(String JavaDoc newDescription) {
216     description = newDescription;
217 }
218
219 /**
220  * Returns the report's start formula; may be <code>null</code>.
221  *
222  * @return the report's start formula; may be <code>null</code>
223  */

224 public Formula getStartFormula() { return startFormula; }
225 public void setStartFormula(Formula newStartFormula) {
226     startFormula = newStartFormula;
227 }
228
229 public Scripting getScripting() { return scripting; }
230
231 /**
232  * Evaluates an <var>evalString</var> using <var>language</var> and returns
233  * the results. Called by {@link Formula#evaluate} after it has created the
234  * <var>evalString</var>.
235  *
236  * @param language the language to use
237  * @param evalString the string to evaluate
238  * @param displayName a name (for example, a formula name) to display with
239  * error messages
240  * @return the result
241  */

242 public Object JavaDoc eval(String JavaDoc language, String JavaDoc evalString, String JavaDoc displayName)
243     throws BSFException
244 {
245     return scripting.eval(language, evalString, displayName);
246 }
247
248 /**
249  * Returns the value of the object ({@link Column}, {@link Formula},
250  * {@link Parameter}, {@link UserColumn}, or {@link SpecialField})
251  * identified by <var>labelOrId</var>.
252  *
253  * @param labelOrId the label or id of a
254  */

255 public Object JavaDoc value(String JavaDoc labelOrId) {
256   if (labelOrId == null)
257     return null;
258
259   labelOrId = labelOrId.trim();
260   if (labelOrId.length() == 0)
261     return null;
262
263   if (labelOrId.charAt(0) == '{') {
264     if (labelOrId.length() == 1)
265       return null;
266     int endPos = labelOrId.indexOf('}');
267     switch (labelOrId.charAt(1)) {
268     case '@':
269       Formula f = findFormulaByName(labelOrId.substring(2, endPos));
270       if (f == null) return null;
271       return f.evaluate(null); // TODO: can we pass in field?
272
case '?':
273       Parameter p = findParameterByName(labelOrId.substring(2, endPos));
274       if (p == null) return null;
275       return p.getValue();
276     case '%':
277       // TODO: first arg is field; can we pass it in?
278
return SpecialField.value(null, labelOrId.substring(2, endPos), this);
279     case '!':
280       UserColumn uc = findUserColumnByName(labelOrId.substring(2, endPos));
281       if (uc == null) return null;
282       return uc.getValue(this);
283     }
284   }
285
286   if (labelOrId.startsWith("{") && labelOrId.endsWith("}"))
287     labelOrId = labelOrId.substring(1, labelOrId.length() - 1);
288   Column col = findColumn(labelOrId);
289   if (col == null)
290     return null;
291   else
292     return columnValue(col);
293 }
294
295 /**
296  * Returns the field that holds default format, border, and bounds values for
297  * all fields. For all format ivars, if the value of the ivar is null then the
298  * value is obtained from this default field's format. If you need those
299  * values, clone them before using them.
300  *
301  * @return the default field
302  */

303 public Field getDefaultField() { return defaultField; }
304
305 public DataSource getDataSource() { return dataSource; }
306
307 public boolean hasDataSource() {
308     return dataSource != null;
309 }
310
311 /**
312  * Sets the data source. Called by {@link ReportReader#database}, {@link
313  * ReportReader#charSepSource}, or user code.
314  * <p>
315  * If we already have a data source (for example, someone has called {@link
316  * #setDatabaseConnection}), the existing data source will be stomped on. Both
317  * {@link ReportReader#database} and {@link ReportReader#charSepSource} call
318  * {@link #hasDataSource} to check first.
319  *
320  * @param newDataSource a new data source
321  */

322 public void setDataSource(DataSource newDataSource) {
323     dataSource = newDataSource;
324 }
325
326 /**
327  * Sets the database connection. If this is called before reading a
328  * report XML file, then this connection will be used instead of
329  * the connection information specified in the report.
330  * <p>
331  * <em>Note:</em> this connection will <em>not</em> be closed when
332  * the report finishes or even if the database object's connection
333  * is reset.
334  *
335  * @param conn a database connection
336  */

337 public void setDatabaseConnection(Connection conn) throws SQLException {
338     dataSource = new Database(conn, this);
339     databasePassword = ""; // So user won't be asked for password
340
}
341
342 /**
343  * Returns the value of the <var>caseSensitiveDatabaseNames</var> flag.
344  * By default, this flag is <code>true</code>.
345  *
346  * @return <code>true</code> if all mixed-case names should be quoted when
347  * appropriate
348  */

349 public boolean caseSensitiveDatabaseNames() {
350     return caseSensitiveDatabaseNames;
351 }
352
353 /**
354  * Sets the value of <var>caseSensitiveDatabaseNames</var>.
355  * Normally, any database data sources' query objects quote all mixed-case
356  * names where appropriate.
357  */

358 public void setCaseSensitiveDatabaseNames(boolean val) {
359     caseSensitiveDatabaseNames = val;
360 }
361
362 /**
363  * Tells this report to reload all references to column objects. Called
364  * by a database when it resets its connection.
365  *
366  * @see Database#reset
367  */

368 public void reloadColumns() {
369     for (Iterator iter = groups(); iter.hasNext(); ) {
370     Group g = (Group)iter.next();
371     g.reloadSelectable(dataSource);
372     }
373     withFieldsDo(new FieldWalker() {
374     public void step(Field f) {
375         if (f instanceof ColumnField) {
376         ColumnField cf = (ColumnField)f;
377         cf.setColumn(dataSource.findColumn(cf.getColumn().getId()));
378         }
379     }
380     });
381
382     // Let the data source tell its ancillary objects (such as the query)
383
// to reload its columns.
384
dataSource.reloadColumns();
385 }
386
387 /**
388  * Given an id (a column name), returns the column that has that id. If no
389  * column with the specified id exists, returns <code>null</code>. Calls
390  * {@link DataSource#findColumn}.
391  *
392  * @return a column, or <code>null</code> if no column with the specified
393  * id exists
394  */

395 public Column findColumn(String JavaDoc id) { return dataSource.findColumn(id); }
396
397 public PaperFormat getPaperFormat() { return paperFormat; }
398 public void setPaperFormat(PaperFormat newPaperFormat) {
399     paperFormat = newPaperFormat;
400 }
401
402 /**
403  * Figure out what <var>obj</var> is and add it.
404  */

405 public void add(Object JavaDoc obj) {
406     if (obj instanceof Parameter) addParameter((Parameter)obj);
407     else if (obj instanceof Formula) addFormula((Formula)obj);
408     else if (obj instanceof UserColumn) addUserColumn((UserColumn)obj);
409     else if (obj instanceof Group) addGroup((Group)obj);
410     else // Shouldn't happen
411
ErrorHandler.error(I18N.get("Report.add_err_1") + ' '
412                + obj.getClass().getName() + ' '
413                + I18N.get("Report.add_err_2"));
414 }
415
416 /**
417  * Figure out what <var>obj</var> is and remove it.
418  */

419 public void remove(Object JavaDoc obj) {
420     if (obj instanceof Field)
421     removeField((Field)obj);
422     else if (obj instanceof Formula)
423     removeFormula((Formula)obj);
424     else if (obj instanceof Parameter)
425     removeParameter((Parameter)obj);
426     else if (obj instanceof UserColumn)
427     removeUserColumn((UserColumn)obj);
428     else if (obj instanceof Group)
429     removeGroup((Group)obj);
430     else if (obj instanceof Section)
431     removeSection((Section)obj);
432     else
433     ErrorHandler.error(I18N.get("Report.remove_err_1") + ' '
434                + obj.getClass().getName()
435                + I18N.get("Report.remove_err_2"));
436 }
437
438 // ---------------- parameters
439

440 /**
441  * Returns the parameter with the specified id or <code>null</code> if one is
442  * not found. <em>Note</em>: don't use this method if you need a parameter's
443  * value. That value is supplied by the user. Call {@link
444  * Report#getParameterValue} instead, which asks the user to supply the value.
445  *
446  * @param id the parameter id
447  * @return the parameter with that id or <code>null</code> if one is not found
448  */

449 public Parameter findParameter(Object JavaDoc id) {
450     if (id instanceof String JavaDoc)
451     id = new Long JavaDoc((String JavaDoc)id);
452     return (Parameter)parameters.get(id);
453 }
454
455 /**
456  * Returns the parameter with the specified name or <code>null</code>
457  * if one is not found.
458  *
459  * @param name the name string
460  * @return the parameter with that name or <code>null</code> if one is not
461  * found
462  */

463 public Parameter findParameterByName(String JavaDoc name) {
464     if (name == null || name.length() == 0)
465     return null;
466
467     name = name.toLowerCase();
468     for (Iterator iter = parameters.values().iterator(); iter.hasNext(); ) {
469     Parameter p = (Parameter)iter.next();
470     if (name.equals(p.getName().toLowerCase()))
471         return p;
472     }
473     return null;
474 }
475
476 public void addParameter(Parameter p) {
477     parameters.put(p.getId(), p);
478 }
479 public void removeParameter(Parameter p) {
480     parameters.remove(p.getId());
481 }
482 public Iterator parameters() { return parameters.values().iterator(); }
483
484 // ---------------- formulas
485

486 /**
487  * Returns the formula with the specified id or <code>null</code>
488  * if one is not found.
489  *
490  * @param id the formula id
491  * @return the formula with that id or <code>null</code> if one is not found
492  */

493 public Formula findFormula(Object JavaDoc id) {
494     if (id instanceof String JavaDoc)
495     id = new Long JavaDoc((String JavaDoc)id);
496     return (Formula)formulas.get(id);
497 }
498
499 /**
500  * Returns the formula with the specified name or <code>null</code>
501  * if one is not found.
502  *
503  * @param name the name string
504  * @return the formula with that name or <code>null</code> if one is not found
505  */

506 public Formula findFormulaByName(String JavaDoc name) {
507     if (name == null || name.length() == 0)
508     return null;
509
510     name = name.toLowerCase();
511     for (Iterator iter = formulas.values().iterator(); iter.hasNext(); ) {
512     Formula f = (Formula)iter.next();
513     if (name.equals(f.getName().toLowerCase()))
514         return f;
515     }
516     return null;
517 }
518
519 public void addFormula(Formula f) {
520     formulas.put(f.getId(), f);
521 }
522 public void removeFormula(Formula f) {
523     formulas.remove(f.getId());
524 }
525 public Iterator formulas() { return formulas.values().iterator(); }
526
527 // ---------------- user columns
528

529 /**
530  * Returns the user column with the specified id or <code>null</code>
531  * if one is not found.
532  *
533  * @param id the user column id
534  * @return the user column with that id or <code>null</code> if one
535  * is not found
536  */

537 public UserColumn findUserColumn(Object JavaDoc id) {
538     if (id instanceof String JavaDoc)
539     id = new Long JavaDoc((String JavaDoc)id);
540     return (UserColumn)usercols.get(id);
541 }
542
543 /**
544  * Returns the user column with the specified name or <code>null</code>
545  * if one is not found.
546  *
547  * @param name the name string
548  * @return the user column with that name or <code>null</code> if one
549  * is not found
550  */

551 public UserColumn findUserColumnByName(String JavaDoc name) {
552     if (name == null || name.length() == 0)
553     return null;
554
555     name = name.toLowerCase();
556     for (Iterator iter = usercols.values().iterator(); iter.hasNext(); ) {
557     UserColumn f = (UserColumn)iter.next();
558     if (name.equals(f.getName().toLowerCase()))
559         return f;
560     }
561     return null;
562 }
563
564 public void addUserColumn(UserColumn uc) {
565     usercols.put(uc.getId(), uc);
566 }
567 public void removeUserColumn(UserColumn uc) {
568     usercols.remove(uc.getId());
569 }
570 public Iterator userColumns() { return usercols.values().iterator(); }
571
572 // ---------------- subreports
573

574 /**
575  * Returns the subreport with the specified id or <code>null</code>
576  * if one is not found.
577  *
578  * @param id the subreport id
579  * @return the subreport with that id or <code>null</code> if one is not found
580  */

581 public Subreport findSubreport(Object JavaDoc id) {
582     if (id instanceof String JavaDoc)
583     id = new Long JavaDoc((String JavaDoc)id);
584     return (Subreport)subreports.get(id);
585 }
586
587 public void addSubreport(Subreport sub) {
588     subreports.put(sub.getId(), sub);
589 }
590 public void removeSubreport(Subreport sub) {
591     subreports.remove(sub.getId());
592 }
593 public Iterator subreports() { return subreports.values().iterator(); }
594
595 // ---------------- selectable methods
596

597 public Selectable findSelectable(Object JavaDoc id, String JavaDoc type) {
598     if ("column".equals(type))
599     return findColumn(id.toString());
600     else // "usercol"
601
return findUserColumn(id);
602 }
603
604 // ---------------- section manipulation
605

606 /**
607  * Returns the section area corresponding to <var>area</var>, but
608  * <em>only</em> if <var>area</var> is not group header or group footer. Both
609  * of those possibly apply to multiple groups, so we can't tell which one is
610  * desired.
611  *
612  * @param area one of the <code>SectionArea.*</code> constants
613  * @return the section area corresponding to <var>area</var>
614  */

615 public SectionArea getSectionArea(int area) {
616     switch (area) {
617     case SectionArea.REPORT_HEADER: return reportHeaders;
618     case SectionArea.REPORT_FOOTER: return reportFooters;
619     case SectionArea.PAGE_HEADER: return pageHeaders;
620     case SectionArea.PAGE_FOOTER: return pageFooters;
621     case SectionArea.DETAIL: return details;
622     default:
623     return null;
624     }
625 }
626
627 /**
628  * Returns <code>true</code> if this report contains the specified section.
629  *
630  * @return <code>true</code> if this report contains the specified section
631  */

632 public boolean contains(Section s) {
633     return s.getArea() != null;
634 }
635
636 /**
637  * Returns the first section in the list of the specified type. If the
638  * type is <code>GROUP_HEADER</code> or <code>GROUP_FOOTER</code>, return
639  * (a) <code>null</code> if there are no groups in the report or
640  * (b) the first header or footer of the first group.
641  * <p>
642  * Used by {@link jimm.datavision.gui.cmd.FieldClipping} when trying to paste
643  * a field into either some other report or the same report if the original
644  * section is no longer in that report.
645  *
646  * @return a section; may be <code>null</code>
647  */

648 public Section getFirstSectionByArea(int area) {
649     switch (area) {
650     case SectionArea.GROUP_HEADER:
651     if (groups.isEmpty()) return null;
652     return ((Group)groups.get(0)).headers().first();
653     case SectionArea.GROUP_FOOTER:
654     if (groups.isEmpty()) return null;
655     return ((Group)groups.get(0)).footers().first();
656     default:
657     return getSectionArea(area).first();
658     }
659 }
660
661 /**
662  * Returns a structure useful only by this report for re-inserting a section.
663  * This structure may later be passed to {@link #reinsertSection}. Used by
664  * {@link jimm.datavision.gui.cmd.DeleteSectionCommand}.
665  * <p>
666  * We assume that <var>s</var> is contained within some {@link SectionArea}.
667  *
668  * @param s the section in question
669  * @return section location information
670  */

671 public ReportSectionLoc getSectionLocation(Section s) {
672     SectionArea area = s.getArea();
673     return new ReportSectionLoc(s, area, area.indexOf(s));
674 }
675
676 /**
677  * Reinserts a section based on the location information previously retrieved
678  * by a call to {@link #getSectionLocation}. Used by {@link
679  * jimm.datavision.gui.cmd.DeleteSectionCommand}.
680  *
681  * @param loc a section locatction
682  */

683 public void reinsertSection(ReportSectionLoc loc) {
684     loc.area.add(loc.index, loc.section);
685 }
686
687 // ---------------- section areas
688

689 public SectionArea headers() { return reportHeaders; }
690 public SectionArea footers() { return reportFooters; }
691 public SectionArea pageHeaders() { return pageHeaders; }
692 public SectionArea pageFooters() { return pageFooters; }
693 public SectionArea details() { return details; }
694
695 // ---------------- groups
696

697 public void addGroup(Group g) {
698     groups.add(g);
699     dataSource.removeSort(g.getSelectable());
700 }
701 public void removeGroup(Group g) { groups.remove(g); }
702 public void removeAllGroups() { groups.clear(); }
703 public Iterator groups() { return groups.iterator(); }
704 public int countGroups() { return groups.size(); }
705 public boolean hasGroups() { return countGroups() > 0; }
706
707 /**
708  * Returns the last (innermost) group in the report, or <code>null</code>
709  * if there are no groups.
710  *
711  * @return the last (innermost) group in the report, or <code>null</code>
712  * if there are no groups.
713  */

714 public Group innermostGroup() {
715     return groups.size() > 0 ? (Group)groups.get(groups.size() - 1) : null;
716 }
717
718 /**
719  * Returns an iterator over the groups in reverse order. Useful when
720  * displaying group footers.
721  *
722  * @return an iterator over the groups, in reverse order
723  */

724 public Iterator groupsReversed() {
725     ArrayList reversed = (ArrayList)groups.clone();
726     Collections.reverse(reversed);
727     return reversed.iterator();
728 }
729
730 public void removeField(Field f) {
731     Section s = sectionContaining(f);
732     if (s != null)
733     s.removeField(f);
734 }
735
736 /**
737  * Returns <code>true</code> if the specified field exists within this
738  * report.
739  *
740  * @param f a field
741  * @return <code>true</code> if the specified field exists within this
742  * report
743  */

744 public boolean contains(Field f) {
745     return sectionContaining(f) != null;
746 }
747
748 /**
749  * Returns the section containing the specified field, or <code>null</code>
750  * if the field is not in the report.
751  *
752  * @param f a field
753  * @return the section containing the specified field, or <code>null</code>
754  * if the field is not in the report
755  */

756 public Section sectionContaining(Field f) {
757     Section s;
758     Iterator iter, iter2;
759     for (iter = reportHeaders.iterator(); iter.hasNext(); ) {
760     s = (Section)iter.next();
761     if (s.contains(f)) return s;
762     }
763     for (iter = pageHeaders.iterator(); iter.hasNext(); ) {
764     s = (Section)iter.next();
765     if (s.contains(f)) return s;
766     }
767     for (iter = groups.iterator(); iter.hasNext(); ) {
768     for (iter2 = ((Group)iter.next()).headers().iterator();
769          iter2.hasNext(); ) {
770         s = (Section)iter2.next();
771         if (s.contains(f)) return s;
772     }
773     }
774     for (iter = details.iterator(); iter.hasNext(); ) {
775     s = (Section)iter.next();
776     if (s.contains(f)) return s;
777     }
778     for (iter = groups.iterator(); iter.hasNext(); ) {
779     for (iter2 = ((Group)iter.next()).footers().iterator();
780          iter2.hasNext(); ) {
781         s = (Section)iter2.next();
782         if (s.contains(f)) return s;
783     }
784     }
785     for (iter = reportFooters.iterator(); iter.hasNext(); ) {
786     s = (Section)iter.next();
787     if (s.contains(f)) return s;
788     }
789     for (iter = pageFooters.iterator(); iter.hasNext(); ) {
790     s = (Section)iter.next();
791     if (s.contains(f)) return s;
792     }
793
794     return null;
795 }
796
797 /**
798  * Returns <code>true</code> if the specified field exists within this
799  * report either directly (as a field) or indirectly (as a formula used
800  * by a aggregate, parameter, user column, or another formula).
801  *
802  * @param f a field
803  * @return <code>true</code> if the specified field exists within this
804  * report
805  */

806 public boolean containsReferenceTo(final Field f) {
807     if (startFormula != null && startFormula.refersTo(f))
808     return true;
809
810     final boolean[] answer = new boolean[1];
811     answer[0] = false;
812
813     withSectionsDo(new SectionWalker() {
814     public void step(Section s) {
815         if (s.containsReferenceTo(f))
816         answer[0] = true;
817     }
818     });
819
820     return answer[0];
821 }
822
823 /**
824  * Returns <code>true</code> if the specified formula exists within this
825  * report either directly (as a formula field) or indirectly (as a formula
826  * used by a aggregate or by another formula). This is not the same as
827  * answering the question, "Does this report contain this formula?" because
828  * we want to know if the visual portion of the report or some other formula
829  * accesses the specified formula.
830  *
831  * @param f a formula
832  * @return <code>true</code> if the specified parameter exists within some
833  * visual element of the report or within some formula
834  */

835 public boolean containsReferenceTo(final Formula f) {
836     if (startFormula != null && startFormula.refersTo(f))
837     return true;
838
839     final boolean[] answer = new boolean[1];
840     answer[0] = false;
841
842     withSectionsDo(new SectionWalker() {
843     public void step(Section s) {
844         if (s.containsReferenceTo(f))
845         answer[0] = true;
846     }
847     });
848
849     return answer[0];
850 }
851
852 /**
853  * Returns <code>true</code> if the specified user column exists within
854  * this report either directly (as a user column field) or indirectly
855  * (inside a aggregate or formula). This is not the same as answering the
856  * question, "Does this report contain this user column?" because we want
857  * to know if the visual portion of the report or some formula accesses the
858  * specified user column.
859  *
860  * @param uc a user column
861  * @return <code>true</code> if the specified parameter exists within some
862  * visual element of the report or within some formula
863  */

864 public boolean containsReferenceTo(final UserColumn uc) {
865     if (startFormula != null && startFormula.refersTo(uc))
866     return true;
867
868     final boolean[] answer = new boolean[1];
869     answer[0] = false;
870
871     withSectionsDo(new SectionWalker() {
872     public void step(Section s) {
873         if (s.containsReferenceTo(uc))
874         answer[0] = true;
875     }
876     });
877
878     return answer[0];
879 }
880
881 /**
882  * Returns <code>true</code> if the specified parameter exists within this
883  * report either directly (as a parameter field) or indirectly (as a
884  * parameter used by a aggregate or by another parameter or in the query's
885  * where clause). This is not the same as answering the question, "Does
886  * this report contain this parameter?" because we want to know if the
887  * visual portion of the report or some formula accesses the specified
888  * parameter.
889  *
890  * @param p a parameter
891  * @return <code>true</code> if the specified parameter exists within some
892  * visual element of the report or within some formula or within the
893  * query's where clause
894  */

895 public boolean containsReferenceTo(final Parameter p) {
896     if (startFormula != null && startFormula.refersTo(p))
897     return true;
898
899     if (dataSource.containsReferenceTo(p))
900     return true;
901
902     final boolean[] answer = new boolean[1];
903     answer[0] = false;
904
905     withSectionsDo(new SectionWalker() {
906     public void step(Section s) {
907         if (s.containsReferenceTo(p))
908         answer[0] = true;
909     }
910     });
911
912     return answer[0];
913 }
914
915 /**
916  * Returns a list of all the parameters actually used in the report.
917  *
918  * @return a list of parameters
919  */

920 protected List collectUsedParameters() {
921     ArrayList list = new ArrayList();
922     for (Iterator iter = parameters.values().iterator(); iter.hasNext(); ) {
923     Parameter p = (Parameter)iter.next();
924     if (containsReferenceTo(p))
925         list.add(p);
926     }
927     return list;
928 }
929
930 /**
931  * Returns the group associated with the specified column, or
932  * <code>null</code> if there isn't one.
933  *
934  * @param selectable a selectable field
935  * @return the group associated with this column, or <code>null</code>
936  * if there isn't one
937  */

938 public Group findGroup(Selectable selectable) {
939     for (Iterator iter = groups(); iter.hasNext(); ) {
940     Group g = (Group)iter.next();
941     if (g.getSelectable() == selectable)
942         return g;
943     }
944     return null;
945 }
946
947 /**
948  * Returns the group associated with the specified section, or
949  * <code>null</code> if there isn't one.
950  *
951  * @param section a section
952  * @return the group associated with this section, or <code>null</code>
953  * if there isn't one
954  */

955 public Group findGroup(Section section) {
956     for (Iterator iter = groups(); iter.hasNext(); ) {
957     Group group = (Group)iter.next();
958     if (group.contains(section))
959         return group;
960     }
961     return null;
962 }
963
964 /**
965  * Returns <code>true</code> if the specified section is contained in
966  * any group. The section may be either a header or a footer section.
967  *
968  * @param section a section
969  * @return <code>true</code> if the section is within some group
970  */

971 public boolean isInsideGroup(Section section) {
972     return findGroup(section) != null;
973 }
974
975 /**
976  * Returns <code>true</code> if the specified data source column is a
977  * group column.
978  *
979  * @return <code>true</code> if the specified data source column is a
980  * group column
981  */

982 public boolean isUsedBySomeGroup(Selectable g) {
983     return findGroup(g) != null;
984 }
985
986 /**
987  * Creates and returns a new section below the specified one.
988  *
989  * @param goBelowThis a section
990  * @return a new section
991  */

992 public Section insertSectionBelow(Section goBelowThis) {
993     return insertSectionBelow(null, goBelowThis);
994 }
995
996 /**
997  * Inserts a (possibly newly created) section below the specified one.
998  * Returns the inserted section.
999  *
1000 * @param section the section to insert
1001 * @param goBelowThis <var>section</var> goes below this one;
1002 * @return a new section
1003 */

1004public Section insertSectionBelow(Section section, Section goBelowThis) {
1005    if (section == null)
1006    section = new Section(this);
1007
1008    if (goBelowThis == null)
1009    return reportHeaders.insertAfter(section, null);
1010
1011    if (reportHeaders.contains(goBelowThis))
1012    return reportHeaders.insertAfter(section, goBelowThis);
1013    else if (reportFooters.contains(goBelowThis))
1014    return reportFooters.insertAfter(section, goBelowThis);
1015    else if (pageHeaders.contains(goBelowThis))
1016    return pageHeaders.insertAfter(section, goBelowThis);
1017    else if (pageFooters.contains(goBelowThis))
1018    return pageFooters.insertAfter(section, goBelowThis);
1019    else if (details.contains(goBelowThis))
1020    return details.insertAfter(section, goBelowThis);
1021
1022    for (Iterator iter = groups(); iter.hasNext(); ) {
1023    Group g = (Group)iter.next();
1024    if (g.headers().contains(goBelowThis))
1025        return g.headers().insertAfter(section, goBelowThis);
1026    else if (g.footers().contains(goBelowThis))
1027        return g.footers().insertAfter(section, goBelowThis);
1028    }
1029
1030    return null; // Should not happen
1031
}
1032
1033/**
1034 * Removes the specified section.
1035 *
1036 * @param s a section
1037 */

1038public void removeSection(Section s) {
1039    if (reportHeaders.contains(s))
1040    reportHeaders.remove(s);
1041    else if (reportFooters.contains(s))
1042    reportFooters.remove(s);
1043    else if (pageHeaders.contains(s))
1044    pageHeaders.remove(s);
1045    else if (pageFooters.contains(s))
1046    pageFooters.remove(s);
1047    else if (details.contains(s))
1048    details.remove(s);
1049    else {
1050    for (Iterator iter = groups(); iter.hasNext(); ) {
1051        Group g = (Group)iter.next();
1052        if (g.headers().contains(s)) {
1053        g.headers().remove(s);
1054        return;
1055        }
1056        else if (g.footers().contains(s)) {
1057        g.footers().remove(s);
1058        return;
1059        }
1060    }
1061    }
1062}
1063
1064/**
1065 * Returns <code>true</code> if this report contains some field anywhere.
1066 * Useful when the GUI is enabling menu items, for example.
1067 *
1068 * @return <code>true</code> if this report contains some field anywhere
1069 */

1070public boolean hasFields() {
1071    final boolean[] answer = new boolean[1];
1072    answer[0] = false;
1073    withFieldsDo(new FieldWalker() {
1074    public void step(Field f) {
1075        answer[0] = true;
1076    }
1077    });
1078    return answer[0];
1079}
1080
1081/**
1082 * Returns <code>true</code> if this report contains some parameter field
1083 * anywhere. This doesn't determine if any parameters have been created,
1084 * but rather if any of the parameters are actually used in the report.
1085 * <p>
1086 * This method is not used by DataVision, but is useful for apps embedding
1087 * DataVision that want to answer the question, "Do I have to read in
1088 * a parameter XML file?"
1089 *
1090 * @return <code>true</code> if this report contains some parameter field
1091 * anywhere
1092 */

1093public boolean hasParameterFields() {
1094    final boolean answer[] = new boolean[1];
1095    answer[0] = false;
1096    withFieldsDo(new FieldWalker() {
1097    public void step(Field f) {
1098        if (f instanceof ParameterField) answer[0] = true;
1099    }
1100    });
1101    return answer[0];
1102}
1103
1104/**
1105 * Returns <code>true</code> if the specified section is the only section
1106 * of its kind; that is, the only section in the collection in which it
1107 * is contained.
1108 *
1109 * @param s a report section
1110 * @return <code>true</code> if this section is a loner
1111 */

1112public boolean isOneOfAKind(Section s) {
1113    if (reportHeaders.contains(s))
1114    return reportHeaders.size() == 1;
1115    if (reportFooters.contains(s))
1116    return reportFooters.size() == 1;
1117    if (pageHeaders.contains(s))
1118    return pageHeaders.size() == 1;
1119    if (pageFooters.contains(s))
1120    return pageFooters.size() == 1;
1121    if (details.contains(s))
1122    return details.size() == 1;
1123
1124    for (Iterator iter = groups(); iter.hasNext(); ) {
1125    Group g = (Group)iter.next();
1126    if (g.headers().contains(s))
1127        return g.headers().size() == 1;
1128    if (g.footers().contains(s))
1129        return g.footers().size() == 1;
1130    }
1131
1132    return false;
1133}
1134
1135/**
1136 * Sets the database password.
1137 */

1138public void setDatabasePassword(String JavaDoc pwd) { databasePassword = pwd; }
1139
1140/**
1141 * Sets a database's user name and password. Called from {@link
1142 * Database#initializeConnection}. If we already have the password, give it to
1143 * the database. If we don't, ask the user for both the user name (supplied to
1144 * us) and the password and give them to the database.
1145 *
1146 * @param db the database
1147 */

1148public void askForPassword(Database db) {
1149    if (databasePassword != null) {
1150    db.setPassword(databasePassword);
1151    return;
1152    }
1153
1154    if (ErrorHandler.usingGUI()) {
1155    DbPasswordDialog dialog =
1156        new DbPasswordDialog(getDesignFrame(), db.getName(),
1157                 db.getUserName());
1158    // This dialog is modal, so when we return the values have been
1159
// filled.
1160
db.setUserName(dialog.getUserName());
1161    db.setPassword(dialog.getPassword());
1162    }
1163    else {
1164    System.out.print(I18N.get("Report.user_name") + " ["
1165             + db.getUserName() + "]: ");
1166    System.out.flush();
1167    try {
1168        BufferedReader in =
1169        new BufferedReader(new InputStreamReader(System.in));
1170        String JavaDoc username = in.readLine();
1171        if (username.length() > 0)
1172        db.setUserName(username);
1173    }
1174    catch (IOException e) {
1175        ErrorHandler.error(I18N.get("Report.user_name_err"));
1176    }
1177
1178    System.out.print(I18N.get("Report.password") + ' ' + db.getUserName()
1179             + ": ");
1180    System.out.flush();
1181    try {
1182        BufferedReader in =
1183        new BufferedReader(new InputStreamReader(System.in));
1184        databasePassword = in.readLine();
1185        db.setPassword(databasePassword);
1186    }
1187    catch (IOException e) {
1188        ErrorHandler.error(I18N.get("Report.password_err"));
1189    }
1190    }
1191}
1192
1193/**
1194 * Returns the value of the specified parameter. First time at the start
1195 * of each report run, asks user for parameter values.
1196 *
1197 * @param paramId a parameter id
1198 */

1199public Object JavaDoc getParameterValue(Object JavaDoc paramId) {
1200    if (!askedForParameters)
1201    askForParameters();
1202
1203    return findParameter(paramId).getValue();
1204}
1205
1206/**
1207 * Lets the caller tell the report to ask for parameters (<var>val</var> is
1208 * <code>false</code>, the default value) or to not ask (<var>val</var> is
1209 * <code>true</code>). Call this method with <var>val</var> <code>=
1210 * true</code> when you set the parameters in your Java code manually.
1211 */

1212public void parametersSetManually(boolean val) { paramsSetManually = val; }
1213
1214/**
1215 * Asks the user for parameter values. If the user cancels, we throw a
1216 * <code>UserCancellationException</code>.
1217 */

1218protected void askForParameters() throws UserCancellationException {
1219    List usedParameters = null;
1220    if (askedForParameters || paramsSetManually
1221    || (usedParameters = collectUsedParameters()).isEmpty())
1222    {
1223    askedForParameters = true;
1224    return;
1225    }
1226
1227    if (ErrorHandler.usingGUI()) {
1228    if (parametersHaveValues) {
1229        // Ask user about re-using the previous values
1230
String JavaDoc msg = I18N.get("Report.use_prev_param_vals");
1231        if (JOptionPane.showConfirmDialog(getDesignFrame(), msg,
1232                          I18N.get("Report.use_prev_title"),
1233                          JOptionPane.YES_NO_OPTION)
1234        == JOptionPane.YES_OPTION)
1235        {
1236            askedForParameters = true;
1237            parametersHaveValues = true;
1238            return;
1239        }
1240    }
1241
1242    // This dialog is modal. By the time it returns, the parameters
1243
// have their new values.
1244

1245    if (new ParamAskWin(getDesignFrame(), usedParameters).userCancelled())
1246        throw new UserCancellationException(I18N.get("Report.user_cancelled"));
1247    }
1248    else {
1249    if (paramReader == null) {
1250        ErrorHandler.error(I18N.get("Report.missing_param_xml_file"));
1251        throw new UserCancellationException(I18N.get("Report.missing_param_xml_file_short"));
1252    }
1253    try {
1254        paramReader.read();
1255        paramReader = null;
1256    }
1257    catch (Exception JavaDoc ex) {
1258        ErrorHandler.error(I18N.get("Report.param_file_err_1") + ' '
1259                   + paramReader.getInputName()
1260                   + I18N.get("Report.param_file_err_2"), ex);
1261        throw new UserCancellationException(I18N.get("Report.param_file_err_short"));
1262    }
1263    }
1264
1265    askedForParameters = true;
1266    parametersHaveValues = true;
1267}
1268
1269/**
1270 * Asks the user for a data source file if necessary. If the user cancels,
1271 * we throw a <code>UserCancellationException</code>.
1272 */

1273protected void askForDataSourceFile()
1274    throws UserCancellationException, FileNotFoundException
1275{
1276    if (!dataSource.needsSourceFile() || !ErrorHandler.usingGUI())
1277    return;
1278
1279    if (dataSourceHasFile) {
1280    // Ask user about re-using the previous values
1281
String JavaDoc msg = I18N.get("Report.use_prev_data_source_file");
1282    if (JOptionPane.showConfirmDialog(getDesignFrame(), msg,
1283                      I18N.get("Report.use_prev_data_source_title"),
1284                      JOptionPane.YES_NO_OPTION)
1285        == JOptionPane.YES_OPTION)
1286        {
1287        dataSource.reuseSourceFile();
1288        return;
1289        }
1290    }
1291
1292    Frame JavaDoc frame = Designer.findWindowFor(this) == null ? null
1293    : Designer.findWindowFor(this).getFrame();
1294    JFileChooser JavaDoc chooser = Designer.getChooser();
1295    int returnVal = chooser.showOpenDialog(frame);
1296    if (returnVal == JFileChooser.APPROVE_OPTION)
1297    dataSource.setSourceFile(chooser.getSelectedFile().getPath());
1298    else
1299    throw new UserCancellationException(I18N.get("Report.user_cancelled"));
1300
1301    dataSourceHasFile = true;
1302}
1303
1304/**
1305 * Spawns a new thread that runs the report, using the layout engine to
1306 * generate output. The new thread runs the method {@link #runReport}.
1307 * <p>
1308 * You may ask why this method is called <code>run</code> and it runs another
1309 * method called <code>runReport</code> when the normal convention is for a
1310 * thread to run a {@link Runnable} object that has a <code>run</code> method.
1311 * The reason is purely historical. This method started non-threaded, and I
1312 * don't want anyone else who relies on this method to have to change their
1313 * code.
1314 *
1315 * @see #runReport
1316 */

1317public void run() {
1318    new Thread JavaDoc(new Runnable JavaDoc() {
1319    public void run() { runReport(); }
1320    }).start();
1321}
1322
1323/**
1324 * Runs the data source's query and hands rows to the layout engine. This
1325 * method is called from {@link #run}, which spawns a new thread in which this
1326 * method is run. If you want to run a report, decide if you want it to run in
1327 * a separate thread or not. If so, call <code>run</code>. If not, use this
1328 * method.
1329 */

1330public void runReport() {
1331    // Parameters
1332
askedForParameters = false; // Ask user again
1333
try {
1334    askForDataSourceFile();
1335    askForParameters();
1336    }
1337    catch (UserCancellationException e) { // Ignore
1338
return;
1339    }
1340    catch (IOException ioe) { // Handled when parsed as XML
1341
return;
1342    }
1343
1344    // Pre-report initialization
1345
for (Iterator iter = groups.iterator(); iter.hasNext(); )
1346    ((Group)iter.next()).reset();
1347    collectAggregateFields();
1348    if (startFormula != null)
1349    startFormula.eval();
1350    for (Iterator iter = formulas(); iter.hasNext(); )
1351    ((Formula)iter.next()).useCache();
1352    resetCachedValues();
1353
1354    rset = null;
1355    StatusDialog statusDialog = null;
1356
1357    try {
1358    if (ErrorHandler.usingGUI()) {
1359        statusDialog = new StatusDialog(getDesignFrame(),
1360                        I18N.get("Report.status_title"),
1361                        true,
1362                        I18N.get("Report.status_running"));
1363    }
1364
1365    if (!layoutEngine.wantsMoreData())
1366        return;
1367
1368    rset = dataSource.execute();
1369
1370    boolean layoutStarted = false;
1371    while (layoutEngine.wantsMoreData() && rset.next()) {
1372        if (statusDialog != null) {
1373        if (statusDialog.isCancelled())
1374            throw new UserCancellationException();
1375        statusDialog.update(I18N.get("Report.processing_row") + ' '
1376                    + rowNumber());
1377        }
1378
1379        if (!layoutStarted) {
1380        layoutEngine.start();
1381        layoutStarted = true;
1382        }
1383        processResultRow();
1384    }
1385
1386    rset.last(); // Recall last row so we can access the data
1387
if (!layoutStarted) { // No rows in report
1388
layoutEngine.start();
1389        layoutEngine.end();
1390    }
1391    else { // Output group footers and end of report
1392
layoutEngine.groupFooters(true);
1393        layoutEngine.end();
1394    }
1395    }
1396    catch (UserCancellationException uce) {
1397    layoutEngine.cancel();
1398    }
1399    catch (SQLException sqle) {
1400    layoutEngine.cancel();
1401    ErrorHandler.error(dataSource.getQuery().toString(), sqle);
1402    }
1403    catch (Exception JavaDoc e) {
1404    layoutEngine.cancel();
1405    ErrorHandler.error(e);
1406    }
1407    finally {
1408    if (rset != null) rset.close();
1409
1410    aggregateFields = null;
1411    for (Iterator iter = groups.iterator(); iter.hasNext(); )
1412      ((Group)iter.next()).reset();
1413    resetCachedValues();
1414
1415    if (statusDialog != null)
1416        statusDialog.dispose();
1417    }
1418}
1419
1420/**
1421 * Returns the <code>Frame</code> associated with the design window for
1422 * this report; may be <code>null</code>.
1423 *
1424 * @return a <code>Frame</code>; may be <code>null</code>
1425 */

1426protected Frame JavaDoc getDesignFrame() {
1427    Designer d = Designer.findWindowFor(this);
1428    return d == null ? null : d.getFrame();
1429}
1430
1431/**
1432 * Processes a single data source row. Note that the <code>next</code>
1433 * method of the result set has already been called.
1434 */

1435protected void processResultRow() throws java.sql.SQLException JavaDoc {
1436    resetCachedValues();
1437    updateGroups();
1438
1439    // To output footers, bring back the previous row of data
1440
if (!rset.isFirst()) {
1441    rset.previous();
1442    layoutEngine.groupFooters(false);
1443    rset.next();
1444    resetCachedValues();
1445    }
1446
1447    updateGroupCounters();
1448    updateAggregates();
1449
1450    boolean isLastRow = rset.isLast();
1451    layoutEngine.groupHeaders(isLastRow);
1452    layoutEngine.detail(isLastRow);
1453}
1454
1455/**
1456 * Tells each formula that it should re-evaluate.
1457 */

1458protected void resetCachedValues() {
1459    for (Iterator iter = formulas(); iter.hasNext(); )
1460    ((Formula)iter.next()).shouldEvaluate();
1461    for (Iterator iter = subreports(); iter.hasNext(); )
1462    ((Subreport)iter.next()).clearCache();
1463}
1464
1465/**
1466 * Evalues the formulas in the specified section. This is called by the
1467 * layout engine just before the section gets output.
1468 *
1469 * @param s a section
1470 */

1471public void evaluateFormulasIn(Section s) {
1472    for (Iterator iter = s.fields(); iter.hasNext(); ) {
1473    Field f = (Field)iter.next();
1474    if (f instanceof FormulaField)
1475        ((FormulaField)f).getValue(); // Force evaluation
1476
}
1477}
1478
1479/**
1480 * Returns the current value of the specified selectable. Only defined
1481 * when running a report.
1482 *
1483 * @return the string or Double value of the column
1484 */

1485public Object JavaDoc columnValue(Selectable selectable) {
1486    // Ask data source for field number, then get value of that column
1487
return rset.getObject(dataSource.indexOfSelectable(selectable) + 1);
1488}
1489
1490/**
1491 * Returns the current page number. Asks the layout engine. Only defined
1492 * when running a report.
1493 *
1494 * @return a page number
1495 */

1496public int pageNumber() {
1497    return layoutEngine.pageNumber();
1498}
1499
1500/**
1501 * Returns the current data row number. Only defined when running a report.
1502 */

1503public int rowNumber() {
1504    return rset.getRow();
1505}
1506
1507/**
1508 * Returns the current row of data. Only defined when running a report.
1509 */

1510public DataCursor getCurrentRow() {
1511    return rset;
1512}
1513
1514/**
1515 * Iterates over all sections in the report, passing the section to the
1516 * specified <code>SectionWalker</code>. The sections are visited in the
1517 * order in which they will be displayed.
1518 *
1519 * @param s a section walker
1520 */

1521public void withSectionsDo(SectionWalker s) {
1522    reportHeaders.withSectionsDo(s);
1523    pageHeaders.withSectionsDo(s);
1524    for (Iterator iter = groups.iterator(); iter.hasNext(); )
1525    ((Group)iter.next()).headers().withSectionsDo(s);
1526    details.withSectionsDo(s);
1527    for (Iterator iter = groups.iterator(); iter.hasNext(); )
1528    ((Group)iter.next()).footers().withSectionsDo(s);
1529    reportFooters.withSectionsDo(s);
1530    pageFooters.withSectionsDo(s);
1531}
1532
1533/**
1534 * Iterates over all fields in the report, passing the section to the
1535 * specified <code>FieldWalker</code>.
1536 *
1537 * @param f a field walker
1538 */

1539public void withFieldsDo(final FieldWalker f) {
1540    withSectionsDo(new SectionWalker() {
1541    public void step(Section s) {
1542        for (Iterator it = s.fields(); it.hasNext(); )
1543        f.step((Field)it.next());
1544    }
1545    });
1546}
1547
1548/**
1549 * Collects all aggregate fields and lets each one initialize itself.
1550 * Used once at the beginning of each run.
1551 */

1552protected void collectAggregateFields() {
1553    aggregateFields = new ArrayList();
1554    withFieldsDo(new FieldWalker() {
1555    public void step(Field f) {
1556        if (f instanceof AggregateField) {
1557        ((AggregateField)f).initialize();
1558        aggregateFields.add(f);
1559        }
1560    }
1561    });
1562}
1563
1564/**
1565 * Collects all aggregate fields that are aggregating the specified field.
1566 * Used by the report design GUI.
1567 *
1568 * @param field a field
1569 * @return a list of aggregate fields
1570 */

1571public AbstractList getAggregateFieldsFor(final Field field) {
1572    final ArrayList subs = new ArrayList();
1573    withFieldsDo(new FieldWalker() {
1574    public void step(Field f) {
1575        if (f instanceof AggregateField
1576        && ((AggregateField)f).getField() == field)
1577        {
1578        subs.add(f);
1579        }
1580    }
1581    });
1582    return subs;
1583}
1584
1585/**
1586 * Updates each aggregate field.
1587 */

1588protected void updateAggregates() {
1589    for (Iterator iter = aggregateFields.iterator(); iter.hasNext(); )
1590    ((AggregateField)iter.next()).updateAggregate();
1591}
1592
1593/**
1594 * Updates each group's value based on the current value of the column
1595 * each group uses.
1596 */

1597protected void updateGroups() {
1598    for (Iterator iter = groups.iterator(); iter.hasNext(); ) {
1599    Group g = (Group)iter.next();
1600    g.setValue(this);
1601    }
1602}
1603
1604/**
1605 * Lets each group update its line counter.
1606 */

1607protected void updateGroupCounters() {
1608    for (Iterator iter = groups.iterator(); iter.hasNext(); ) {
1609    Group g = (Group)iter.next();
1610    g.updateCounter();
1611    }
1612}
1613
1614/**
1615 * Remembers name of parameter XML file.
1616 *
1617 * @param f an XML file
1618 */

1619public void setParameterXMLInput(File f) {
1620    paramReader = new ParameterReader(this, f);
1621}
1622
1623/**
1624 * Remembers an input source and reads parameter values from it later. To
1625 * speicfy a URL, use InputSource("http://...")</code>.
1626 *
1627 * @param in the input source
1628 */

1629public void setParameterXMLInput(InputSource in) {
1630    paramReader = new ParameterReader(this, in);
1631}
1632
1633/**
1634 * Reads an XML file and builds the contents of this report. Uses a
1635 * <code>ReportReader</code>.
1636 *
1637 * @param f a report XML file
1638 */

1639public void read(File f) throws Exception JavaDoc {
1640    new ReportReader(this).read(f);
1641}
1642
1643/**
1644 * Reads an XML stream using a <code>org.xml.sax.InputSource</code> and
1645 * builds the contents of this report. Uses a <code>ReportReader</code>.
1646 * To specify a URL, use <code>new InputSource("http://...")</code>.
1647 *
1648 * @param in a reader
1649 * @see ReportReader#read(org.xml.sax.InputSource)
1650 */

1651public void read(org.xml.sax.InputSource JavaDoc in) throws Exception JavaDoc {
1652    new ReportReader(this).read(in);
1653}
1654
1655/**
1656 * Writes the contents of this report as an XML file.
1657 *
1658 * @param fileName a file name string
1659 */

1660public void writeFile(String JavaDoc fileName) {
1661    XMLWriter out = null;
1662    try {
1663    out = new XMLWriter(new OutputStreamWriter(new FileOutputStream(fileName),
1664                              XML_JAVA_ENCODING));
1665    writeXML(out);
1666    out.close();
1667    }
1668    catch (IOException ioe) {
1669    ErrorHandler.error(I18N.get("Report.write_err") + ' ' + fileName, ioe,
1670               I18N.get("Report.write_err_title"));
1671    }
1672    finally {
1673    if (out != null) out.close();
1674    }
1675}
1676
1677/**
1678 * Writes the contents of this report as an XML file.
1679 *
1680 * @param out an indent writer
1681 */

1682public void writeXML(XMLWriter out) {
1683    writeXMLDecl(out);
1684    writeComment(out);
1685    writeReport(out);
1686}
1687
1688protected void writeXMLDecl(XMLWriter out) {
1689    out.xmlDecl(XML_ENCODING_ATTRIBUTE);
1690}
1691
1692protected void writeComment(XMLWriter out) {
1693    out.comment("Generated by DataVision version " + info.Version);
1694    out.comment(info.URL);
1695}
1696
1697protected void writeReport(XMLWriter out) {
1698    out.startElement("report");
1699    out.attr("dtd-version", OUTPUT_DTD_VERSION);
1700    out.attr("name", name);
1701    out.attr("title", title);
1702    out.attr("author", author);
1703
1704    writeDescription(out);
1705    scripting.writeXML(out);
1706    writeStartFormula(out);
1707    paperFormat.writeXML(out);
1708    defaultField.writeXML(out);
1709    ListWriter.writeList(out, usercols.values(), "usercols");
1710    dataSource.writeXML(out);
1711    ListWriter.writeList(out, subreports.values(), "subreports");
1712    ListWriter.writeList(out, parameters.values(), "parameters");
1713    ListWriter.writeList(out, formulas.values(), "formulas");
1714    ListWriter.writeList(out, reportHeaders.sections(), "headers");
1715    ListWriter.writeList(out, reportFooters.sections(), "footers");
1716    writePage(out);
1717    ListWriter.writeList(out, groups, "groups");
1718    ListWriter.writeList(out, details.sections(), "details");
1719
1720    out.endElement();
1721}
1722
1723protected void writeDescription(XMLWriter out) {
1724    out.cdataElement("description", description);
1725}
1726
1727protected void writeStartFormula(XMLWriter out) {
1728    if (startFormula != null)
1729    startFormula.writeXML(out);
1730}
1731
1732protected void writePage(XMLWriter out) {
1733    if (pageHeaders.isEmpty() && pageFooters.isEmpty())
1734    return;
1735
1736    out.startElement("page");
1737    ListWriter.writeList(out, pageHeaders.sections(), "headers");
1738    ListWriter.writeList(out, pageFooters.sections(), "footers");
1739    out.endElement();
1740}
1741
1742}
1743
Popular Tags