Source Code Cross Referenced for Report.java in  » Report » datavision-1.1.0 » jimm » datavision » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Report » datavision 1.1.0 » jimm.datavision 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package jimm.datavision;
0002:
0003:        import jimm.datavision.field.*;
0004:        import jimm.datavision.layout.LayoutEngine;
0005:        import jimm.datavision.source.*;
0006:        import jimm.datavision.source.sql.Database;
0007:        import jimm.datavision.gui.sql.DbPasswordDialog;
0008:        import jimm.datavision.gui.Designer;
0009:        import jimm.datavision.gui.StatusDialog;
0010:        import jimm.datavision.gui.parameter.ParamAskWin;
0011:        import jimm.util.I18N;
0012:        import jimm.util.XMLWriter;
0013:        import java.awt.Frame;
0014:        import java.io.*;
0015:        import java.util.*;
0016:        import java.sql.*;
0017:        import javax.swing.JOptionPane;
0018:        import javax.swing.JFileChooser;
0019:        import org.xml.sax.*;
0020:        import org.apache.bsf.BSFException;
0021:
0022:        /**
0023:         * A report holds data source information, accepts parameters from the user,
0024:         * runs a query, and uses a layout engine to format the output. It may
0025:         * contain many different sections, each of which can contain logic for
0026:         * surpressing itself.
0027:         *
0028:         * @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
0029:         */
0030:        public class Report implements  Nameable, Writeable {
0031:
0032:            /**
0033:             * The string to use when reading and writing XML files. Pass it to
0034:             * OutputStreamWriters and InputStreamReaders.
0035:             */
0036:            public static final String XML_JAVA_ENCODING = "UTF8";
0037:            /**
0038:             * The string to write at the top of an XML file in the XML decl.
0039:             */
0040:            public static final String XML_ENCODING_ATTRIBUTE = "UTF-8";
0041:
0042:            protected static final double OUTPUT_DTD_VERSION = 1.2;
0043:
0044:            protected String name;
0045:            protected String title;
0046:            protected String author;
0047:            protected String description;
0048:            protected Formula startFormula;
0049:            protected DataSource dataSource;
0050:            protected HashMap formulas;
0051:            protected TreeMap parameters;
0052:            protected HashMap usercols;
0053:            protected HashMap subreports;
0054:            protected ArrayList groups;
0055:            protected SectionArea reportHeaders;
0056:            protected SectionArea reportFooters;
0057:            protected SectionArea pageHeaders;
0058:            protected SectionArea pageFooters;
0059:            protected SectionArea details;
0060:            protected DataCursor rset;
0061:            protected LayoutEngine layoutEngine;
0062:            protected PaperFormat paperFormat;
0063:            protected Collection aggregateFields;
0064:            protected String databasePassword;
0065:            protected boolean askedForParameters;
0066:            protected boolean parametersHaveValues;
0067:            protected boolean paramsSetManually;
0068:            protected ParameterReader paramReader;
0069:            /** Flag for Database data sources. */
0070:            protected boolean caseSensitiveDatabaseNames;
0071:            protected Scripting scripting;
0072:            /**
0073:             * This field holds default format, border, and bounds values for all fields.
0074:             * For all format ivars, if the value of the ivar is null then the value is
0075:             * obtained from this default field's format.
0076:             */
0077:            protected Field defaultField;
0078:
0079:            /**
0080:             * Constructs an empty report.
0081:             */
0082:            public Report() {
0083:                formulas = new HashMap();
0084:                parameters = new TreeMap();
0085:                usercols = new HashMap();
0086:                subreports = new HashMap();
0087:                groups = new ArrayList();
0088:                name = I18N.get("Report.default_name");
0089:                title = I18N.get("Report.default_title");
0090:                askedForParameters = false;
0091:                parametersHaveValues = false;
0092:                paramsSetManually = false;
0093:                caseSensitiveDatabaseNames = true;
0094:                paperFormat = PaperFormat.getDefault();
0095:                scripting = new Scripting(this );
0096:
0097:                defaultField = Field.create(new Long(0), this , null, "text",
0098:                        I18N.get("Report.default_field_name"), true);
0099:                defaultField.setFormat(Format.createDefaultFormat());
0100:                defaultField.setBorder(new Border(defaultField));
0101:
0102:                initializeSections();
0103:            }
0104:
0105:            public void initializeSections() {
0106:                reportHeaders = new SectionArea(SectionArea.REPORT_HEADER);
0107:                reportFooters = new SectionArea(SectionArea.REPORT_FOOTER);
0108:                pageHeaders = new SectionArea(SectionArea.PAGE_HEADER);
0109:                pageFooters = new SectionArea(SectionArea.PAGE_FOOTER);
0110:                details = new SectionArea(SectionArea.DETAIL);
0111:
0112:                reportHeaders.add(new Section(this ));
0113:                pageHeaders.add(new Section(this ));
0114:                pageFooters.add(new Section(this ));
0115:                reportFooters.add(new Section(this ));
0116:                details.add(new Section(this ));
0117:            }
0118:
0119:            /**
0120:             * Sets the layout engine to use.
0121:             *
0122:             * @param layoutEngine a layout engine
0123:             */
0124:            public void setLayoutEngine(LayoutEngine layoutEngine) {
0125:                this .layoutEngine = layoutEngine;
0126:                this .layoutEngine.setReport(this );
0127:            }
0128:
0129:            /**
0130:             * Generates and returns a new unique id number. The number is one larger
0131:             * than the largest in a given list of {@link Identity} objects whose
0132:             * identifiers must be <code>Long</code> objects.
0133:             *
0134:             * @param iter an iterator over a collection if <code>Identity</code>
0135:             * objects whose identifiers must be <code>Long</code>s
0136:             * @return a <code>Long</code>
0137:             */
0138:            protected Long generateNewId(Iterator iter) {
0139:                long max = 0;
0140:                while (iter.hasNext()) {
0141:                    Object id = ((Identity) iter.next()).getId();
0142:                    long longVal = ((Long) id).longValue();
0143:                    if (longVal > max)
0144:                        max = longVal;
0145:                }
0146:                return new Long(max + 1);
0147:            }
0148:
0149:            /**
0150:             * Generates and returns a new unique formula id number.
0151:             *
0152:             * @return a long id
0153:             */
0154:            public Long generateNewFormulaId() {
0155:                return generateNewId(formulas.values().iterator());
0156:            }
0157:
0158:            /**
0159:             * Generates and returns a new unique parameter id number.
0160:             *
0161:             * @return a long id
0162:             */
0163:            public Long generateNewParameterId() {
0164:                return generateNewId(parameters.values().iterator());
0165:            }
0166:
0167:            /**
0168:             * Generates and returns a new unique user column id number.
0169:             *
0170:             * @return a long id
0171:             */
0172:            public Long generateNewUserColumnId() {
0173:                return generateNewId(usercols.values().iterator());
0174:            }
0175:
0176:            /**
0177:             * Generates and returns a new unique user column id number.
0178:             *
0179:             * @return a long id
0180:             */
0181:            public Long generateNewSubreportId() {
0182:                return generateNewId(subreports.values().iterator());
0183:            }
0184:
0185:            /**
0186:             * Given an id, returns the field that has that id. If no field with the
0187:             * specified id exists, returns <code>null</code>.
0188:             *
0189:             * @return a field, or <code>null</code> if no field with the specified
0190:             * id exists
0191:             */
0192:            public Field findField(final Object id) {
0193:                final Field listOfOne[] = new Field[1];
0194:                listOfOne[0] = null;
0195:                withSectionsDo(new SectionWalker() {
0196:                    public void step(Section s) {
0197:                        Field f = s.findField(id);
0198:                        if (f != null)
0199:                            listOfOne[0] = f;
0200:                    }
0201:                });
0202:                return listOfOne[0];
0203:            }
0204:
0205:            public String getName() {
0206:                return name;
0207:            }
0208:
0209:            public void setName(String newName) {
0210:                name = newName;
0211:            }
0212:
0213:            public String getTitle() {
0214:                return title;
0215:            }
0216:
0217:            public void setTitle(String newTitle) {
0218:                title = newTitle;
0219:            }
0220:
0221:            public String getAuthor() {
0222:                return author;
0223:            }
0224:
0225:            public void setAuthor(String newAuthor) {
0226:                author = newAuthor;
0227:            }
0228:
0229:            public String getDescription() {
0230:                return description;
0231:            }
0232:
0233:            public void setDescription(String newDescription) {
0234:                description = newDescription;
0235:            }
0236:
0237:            /**
0238:             * Returns the report's start formula; may be <code>null</code>.
0239:             *
0240:             * @return the report's start formula; may be <code>null</code>
0241:             */
0242:            public Formula getStartFormula() {
0243:                return startFormula;
0244:            }
0245:
0246:            public void setStartFormula(Formula newStartFormula) {
0247:                startFormula = newStartFormula;
0248:            }
0249:
0250:            public Scripting getScripting() {
0251:                return scripting;
0252:            }
0253:
0254:            /**
0255:             * Evaluates an <var>evalString</var> using <var>language</var> and returns
0256:             * the results. Called by {@link Formula#evaluate} after it has created the
0257:             * <var>evalString</var>.
0258:             *
0259:             * @param language the language to use
0260:             * @param evalString the string to evaluate
0261:             * @param displayName a name (for example, a formula name) to display with
0262:             * error messages
0263:             * @return the result
0264:             */
0265:            public Object eval(String language, String evalString,
0266:                    String displayName) throws BSFException {
0267:                return scripting.eval(language, evalString, displayName);
0268:            }
0269:
0270:            /**
0271:             * Returns the value of the object ({@link Column}, {@link Formula},
0272:             * {@link Parameter}, {@link UserColumn}, or {@link SpecialField})
0273:             * identified by <var>labelOrId</var>.
0274:             *
0275:             * @param labelOrId the label or id of a 
0276:             */
0277:            public Object value(String labelOrId) {
0278:                if (labelOrId == null)
0279:                    return null;
0280:
0281:                labelOrId = labelOrId.trim();
0282:                if (labelOrId.length() == 0)
0283:                    return null;
0284:
0285:                if (labelOrId.charAt(0) == '{') {
0286:                    if (labelOrId.length() == 1)
0287:                        return null;
0288:                    int endPos = labelOrId.indexOf('}');
0289:                    switch (labelOrId.charAt(1)) {
0290:                    case '@':
0291:                        Formula f = findFormulaByName(labelOrId.substring(2,
0292:                                endPos));
0293:                        if (f == null)
0294:                            return null;
0295:                        return f.evaluate(null); // TODO: can we pass in field?
0296:                    case '?':
0297:                        Parameter p = findParameterByName(labelOrId.substring(
0298:                                2, endPos));
0299:                        if (p == null)
0300:                            return null;
0301:                        return p.getValue();
0302:                    case '%':
0303:                        // TODO: first arg is field; can we pass it in?
0304:                        return SpecialField.value(null, labelOrId.substring(2,
0305:                                endPos), this );
0306:                    case '!':
0307:                        UserColumn uc = findUserColumnByName(labelOrId
0308:                                .substring(2, endPos));
0309:                        if (uc == null)
0310:                            return null;
0311:                        return uc.getValue(this );
0312:                    }
0313:                }
0314:
0315:                if (labelOrId.startsWith("{") && labelOrId.endsWith("}"))
0316:                    labelOrId = labelOrId.substring(1, labelOrId.length() - 1);
0317:                Column col = findColumn(labelOrId);
0318:                if (col == null)
0319:                    return null;
0320:                else
0321:                    return columnValue(col);
0322:            }
0323:
0324:            /**
0325:             * Returns the field that holds default format, border, and bounds values for
0326:             * all fields. For all format ivars, if the value of the ivar is null then the
0327:             * value is obtained from this default field's format. If you need those
0328:             * values, clone them before using them.
0329:             *
0330:             * @return the default field
0331:             */
0332:            public Field getDefaultField() {
0333:                return defaultField;
0334:            }
0335:
0336:            public DataSource getDataSource() {
0337:                return dataSource;
0338:            }
0339:
0340:            public boolean hasDataSource() {
0341:                return dataSource != null;
0342:            }
0343:
0344:            /**
0345:             * Sets the data source. Called by {@link ReportReader#database}, {@link
0346:             * ReportReader#charSepSource}, or user code.
0347:             * <p>
0348:             * If we already have a data source (for example, someone has called {@link
0349:             * #setDatabaseConnection}), the existing data source will be stomped on. Both
0350:             * {@link ReportReader#database} and {@link ReportReader#charSepSource} call
0351:             * {@link #hasDataSource} to check first.
0352:             *
0353:             * @param newDataSource a new data source
0354:             */
0355:            public void setDataSource(DataSource newDataSource) {
0356:                dataSource = newDataSource;
0357:            }
0358:
0359:            /**
0360:             * Sets the database connection. If this is called before reading a
0361:             * report XML file, then this connection will be used instead of
0362:             * the connection information specified in the report.
0363:             * <p>
0364:             * <em>Note:</em> this connection will <em>not</em> be closed when
0365:             * the report finishes or even if the database object's connection
0366:             * is reset.
0367:             *
0368:             * @param conn a database connection
0369:             */
0370:            public void setDatabaseConnection(Connection conn)
0371:                    throws SQLException {
0372:                dataSource = new Database(conn, this );
0373:                databasePassword = ""; // So user won't be asked for password
0374:            }
0375:
0376:            /**
0377:             * Returns the value of the <var>caseSensitiveDatabaseNames</var> flag.
0378:             * By default, this flag is <code>true</code>.
0379:             *
0380:             * @return <code>true</code> if all mixed-case names should be quoted when
0381:             * appropriate
0382:             */
0383:            public boolean caseSensitiveDatabaseNames() {
0384:                return caseSensitiveDatabaseNames;
0385:            }
0386:
0387:            /**
0388:             * Sets the value of <var>caseSensitiveDatabaseNames</var>.
0389:             * Normally, any database data sources' query objects quote all mixed-case
0390:             * names where appropriate.
0391:             */
0392:            public void setCaseSensitiveDatabaseNames(boolean val) {
0393:                caseSensitiveDatabaseNames = val;
0394:            }
0395:
0396:            /**
0397:             * Tells this report to reload all references to column objects. Called
0398:             * by a database when it resets its connection.
0399:             *
0400:             * @see Database#reset
0401:             */
0402:            public void reloadColumns() {
0403:                for (Iterator iter = groups(); iter.hasNext();) {
0404:                    Group g = (Group) iter.next();
0405:                    g.reloadSelectable(dataSource);
0406:                }
0407:                withFieldsDo(new FieldWalker() {
0408:                    public void step(Field f) {
0409:                        if (f instanceof  ColumnField) {
0410:                            ColumnField cf = (ColumnField) f;
0411:                            cf.setColumn(dataSource.findColumn(cf.getColumn()
0412:                                    .getId()));
0413:                        }
0414:                    }
0415:                });
0416:
0417:                // Let the data source tell its ancillary objects (such as the query)
0418:                // to reload its columns.
0419:                dataSource.reloadColumns();
0420:            }
0421:
0422:            /**
0423:             * Given an id (a column name), returns the column that has that id. If no
0424:             * column with the specified id exists, returns <code>null</code>. Calls
0425:             * {@link DataSource#findColumn}.
0426:             *
0427:             * @return a column, or <code>null</code> if no column with the specified
0428:             * id exists
0429:             */
0430:            public Column findColumn(String id) {
0431:                return dataSource.findColumn(id);
0432:            }
0433:
0434:            public PaperFormat getPaperFormat() {
0435:                return paperFormat;
0436:            }
0437:
0438:            public void setPaperFormat(PaperFormat newPaperFormat) {
0439:                paperFormat = newPaperFormat;
0440:            }
0441:
0442:            /**
0443:             * Figure out what <var>obj</var> is and add it.
0444:             */
0445:            public void add(Object obj) {
0446:                if (obj instanceof  Parameter)
0447:                    addParameter((Parameter) obj);
0448:                else if (obj instanceof  Formula)
0449:                    addFormula((Formula) obj);
0450:                else if (obj instanceof  UserColumn)
0451:                    addUserColumn((UserColumn) obj);
0452:                else if (obj instanceof  Group)
0453:                    addGroup((Group) obj);
0454:                else
0455:                    // Shouldn't happen
0456:                    ErrorHandler.error(I18N.get("Report.add_err_1") + ' '
0457:                            + obj.getClass().getName() + ' '
0458:                            + I18N.get("Report.add_err_2"));
0459:            }
0460:
0461:            /**
0462:             * Figure out what <var>obj</var> is and remove it.
0463:             */
0464:            public void remove(Object obj) {
0465:                if (obj instanceof  Field)
0466:                    removeField((Field) obj);
0467:                else if (obj instanceof  Formula)
0468:                    removeFormula((Formula) obj);
0469:                else if (obj instanceof  Parameter)
0470:                    removeParameter((Parameter) obj);
0471:                else if (obj instanceof  UserColumn)
0472:                    removeUserColumn((UserColumn) obj);
0473:                else if (obj instanceof  Group)
0474:                    removeGroup((Group) obj);
0475:                else if (obj instanceof  Section)
0476:                    removeSection((Section) obj);
0477:                else
0478:                    ErrorHandler.error(I18N.get("Report.remove_err_1") + ' '
0479:                            + obj.getClass().getName()
0480:                            + I18N.get("Report.remove_err_2"));
0481:            }
0482:
0483:            // ---------------- parameters
0484:
0485:            /**
0486:             * Returns the parameter with the specified id or <code>null</code> if one is
0487:             * not found. <em>Note</em>: don't use this method if you need a parameter's
0488:             * value. That value is supplied by the user. Call {@link
0489:             * Report#getParameterValue} instead, which asks the user to supply the value.
0490:             *
0491:             * @param id the parameter id
0492:             * @return the parameter with that id or <code>null</code> if one is not found
0493:             */
0494:            public Parameter findParameter(Object id) {
0495:                if (id instanceof  String)
0496:                    id = new Long((String) id);
0497:                return (Parameter) parameters.get(id);
0498:            }
0499:
0500:            /**
0501:             * Returns the parameter with the specified name or <code>null</code>
0502:             * if one is not found.
0503:             *
0504:             * @param name the name string
0505:             * @return the parameter with that name or <code>null</code> if one is not
0506:             * found
0507:             */
0508:            public Parameter findParameterByName(String name) {
0509:                if (name == null || name.length() == 0)
0510:                    return null;
0511:
0512:                name = name.toLowerCase();
0513:                for (Iterator iter = parameters.values().iterator(); iter
0514:                        .hasNext();) {
0515:                    Parameter p = (Parameter) iter.next();
0516:                    if (name.equals(p.getName().toLowerCase()))
0517:                        return p;
0518:                }
0519:                return null;
0520:            }
0521:
0522:            public void addParameter(Parameter p) {
0523:                parameters.put(p.getId(), p);
0524:            }
0525:
0526:            public void removeParameter(Parameter p) {
0527:                parameters.remove(p.getId());
0528:            }
0529:
0530:            public Iterator parameters() {
0531:                return parameters.values().iterator();
0532:            }
0533:
0534:            // ---------------- formulas
0535:
0536:            /**
0537:             * Returns the formula with the specified id or <code>null</code>
0538:             * if one is not found.
0539:             *
0540:             * @param id the formula id
0541:             * @return the formula with that id or <code>null</code> if one is not found
0542:             */
0543:            public Formula findFormula(Object id) {
0544:                if (id instanceof  String)
0545:                    id = new Long((String) id);
0546:                return (Formula) formulas.get(id);
0547:            }
0548:
0549:            /**
0550:             * Returns the formula with the specified name or <code>null</code>
0551:             * if one is not found.
0552:             *
0553:             * @param name the name string
0554:             * @return the formula with that name or <code>null</code> if one is not found
0555:             */
0556:            public Formula findFormulaByName(String name) {
0557:                if (name == null || name.length() == 0)
0558:                    return null;
0559:
0560:                name = name.toLowerCase();
0561:                for (Iterator iter = formulas.values().iterator(); iter
0562:                        .hasNext();) {
0563:                    Formula f = (Formula) iter.next();
0564:                    if (name.equals(f.getName().toLowerCase()))
0565:                        return f;
0566:                }
0567:                return null;
0568:            }
0569:
0570:            public void addFormula(Formula f) {
0571:                formulas.put(f.getId(), f);
0572:            }
0573:
0574:            public void removeFormula(Formula f) {
0575:                formulas.remove(f.getId());
0576:            }
0577:
0578:            public Iterator formulas() {
0579:                return formulas.values().iterator();
0580:            }
0581:
0582:            // ---------------- user columns
0583:
0584:            /**
0585:             * Returns the user column with the specified id or <code>null</code>
0586:             * if one is not found.
0587:             *
0588:             * @param id the user column id
0589:             * @return the user column with that id or <code>null</code> if one
0590:             * is not found
0591:             */
0592:            public UserColumn findUserColumn(Object id) {
0593:                if (id instanceof  String)
0594:                    id = new Long((String) id);
0595:                return (UserColumn) usercols.get(id);
0596:            }
0597:
0598:            /**
0599:             * Returns the user column with the specified name or <code>null</code>
0600:             * if one is not found.
0601:             *
0602:             * @param name the name string
0603:             * @return the user column with that name or <code>null</code> if one
0604:             * is not found
0605:             */
0606:            public UserColumn findUserColumnByName(String name) {
0607:                if (name == null || name.length() == 0)
0608:                    return null;
0609:
0610:                name = name.toLowerCase();
0611:                for (Iterator iter = usercols.values().iterator(); iter
0612:                        .hasNext();) {
0613:                    UserColumn f = (UserColumn) iter.next();
0614:                    if (name.equals(f.getName().toLowerCase()))
0615:                        return f;
0616:                }
0617:                return null;
0618:            }
0619:
0620:            public void addUserColumn(UserColumn uc) {
0621:                usercols.put(uc.getId(), uc);
0622:            }
0623:
0624:            public void removeUserColumn(UserColumn uc) {
0625:                usercols.remove(uc.getId());
0626:            }
0627:
0628:            public Iterator userColumns() {
0629:                return usercols.values().iterator();
0630:            }
0631:
0632:            // ---------------- subreports
0633:
0634:            /**
0635:             * Returns the subreport with the specified id or <code>null</code>
0636:             * if one is not found.
0637:             *
0638:             * @param id the subreport id
0639:             * @return the subreport with that id or <code>null</code> if one is not found
0640:             */
0641:            public Subreport findSubreport(Object id) {
0642:                if (id instanceof  String)
0643:                    id = new Long((String) id);
0644:                return (Subreport) subreports.get(id);
0645:            }
0646:
0647:            public void addSubreport(Subreport sub) {
0648:                subreports.put(sub.getId(), sub);
0649:            }
0650:
0651:            public void removeSubreport(Subreport sub) {
0652:                subreports.remove(sub.getId());
0653:            }
0654:
0655:            public Iterator subreports() {
0656:                return subreports.values().iterator();
0657:            }
0658:
0659:            // ---------------- selectable methods
0660:
0661:            public Selectable findSelectable(Object id, String type) {
0662:                if ("column".equals(type))
0663:                    return findColumn(id.toString());
0664:                else
0665:                    // "usercol"
0666:                    return findUserColumn(id);
0667:            }
0668:
0669:            // ---------------- section manipulation
0670:
0671:            /**
0672:             * Returns the section area corresponding to <var>area</var>, but
0673:             * <em>only</em> if <var>area</var> is not group header or group footer. Both
0674:             * of those possibly apply to multiple groups, so we can't tell which one is
0675:             * desired.
0676:             *
0677:             * @param area one of the <code>SectionArea.*</code> constants
0678:             * @return the section area corresponding to <var>area</var>
0679:             */
0680:            public SectionArea getSectionArea(int area) {
0681:                switch (area) {
0682:                case SectionArea.REPORT_HEADER:
0683:                    return reportHeaders;
0684:                case SectionArea.REPORT_FOOTER:
0685:                    return reportFooters;
0686:                case SectionArea.PAGE_HEADER:
0687:                    return pageHeaders;
0688:                case SectionArea.PAGE_FOOTER:
0689:                    return pageFooters;
0690:                case SectionArea.DETAIL:
0691:                    return details;
0692:                default:
0693:                    return null;
0694:                }
0695:            }
0696:
0697:            /**
0698:             * Returns <code>true</code> if this report contains the specified section.
0699:             *
0700:             * @return <code>true</code> if this report contains the specified section
0701:             */
0702:            public boolean contains(Section s) {
0703:                return s.getArea() != null;
0704:            }
0705:
0706:            /**
0707:             * Returns the first section in the list of the specified type. If the
0708:             * type is <code>GROUP_HEADER</code> or <code>GROUP_FOOTER</code>, return
0709:             * (a) <code>null</code> if there are no groups in the report or
0710:             * (b) the first header or footer of the first group.
0711:             * <p>
0712:             * Used by {@link jimm.datavision.gui.cmd.FieldClipping} when trying to paste
0713:             * a field into either some other report or the same report if the original
0714:             * section is no longer in that report.
0715:             *
0716:             * @return a section; may be <code>null</code>
0717:             */
0718:            public Section getFirstSectionByArea(int area) {
0719:                switch (area) {
0720:                case SectionArea.GROUP_HEADER:
0721:                    if (groups.isEmpty())
0722:                        return null;
0723:                    return ((Group) groups.get(0)).headers().first();
0724:                case SectionArea.GROUP_FOOTER:
0725:                    if (groups.isEmpty())
0726:                        return null;
0727:                    return ((Group) groups.get(0)).footers().first();
0728:                default:
0729:                    return getSectionArea(area).first();
0730:                }
0731:            }
0732:
0733:            /**
0734:             * Returns a structure useful only by this report for re-inserting a section.
0735:             * This structure may later be passed to {@link #reinsertSection}. Used by
0736:             * {@link jimm.datavision.gui.cmd.DeleteSectionCommand}.
0737:             * <p>
0738:             * We assume that <var>s</var> is contained within some {@link SectionArea}.
0739:             *
0740:             * @param s the section in question
0741:             * @return section location information
0742:             */
0743:            public ReportSectionLoc getSectionLocation(Section s) {
0744:                SectionArea area = s.getArea();
0745:                return new ReportSectionLoc(s, area, area.indexOf(s));
0746:            }
0747:
0748:            /**
0749:             * Reinserts a section based on the location information previously retrieved
0750:             * by a call to {@link #getSectionLocation}. Used by {@link
0751:             * jimm.datavision.gui.cmd.DeleteSectionCommand}.
0752:             *
0753:             * @param loc a section locatction
0754:             */
0755:            public void reinsertSection(ReportSectionLoc loc) {
0756:                loc.area.add(loc.index, loc.section);
0757:            }
0758:
0759:            // ---------------- section areas
0760:
0761:            public SectionArea headers() {
0762:                return reportHeaders;
0763:            }
0764:
0765:            public SectionArea footers() {
0766:                return reportFooters;
0767:            }
0768:
0769:            public SectionArea pageHeaders() {
0770:                return pageHeaders;
0771:            }
0772:
0773:            public SectionArea pageFooters() {
0774:                return pageFooters;
0775:            }
0776:
0777:            public SectionArea details() {
0778:                return details;
0779:            }
0780:
0781:            // ---------------- groups
0782:
0783:            public void addGroup(Group g) {
0784:                groups.add(g);
0785:                dataSource.removeSort(g.getSelectable());
0786:            }
0787:
0788:            public void removeGroup(Group g) {
0789:                groups.remove(g);
0790:            }
0791:
0792:            public void removeAllGroups() {
0793:                groups.clear();
0794:            }
0795:
0796:            public Iterator groups() {
0797:                return groups.iterator();
0798:            }
0799:
0800:            public int countGroups() {
0801:                return groups.size();
0802:            }
0803:
0804:            public boolean hasGroups() {
0805:                return countGroups() > 0;
0806:            }
0807:
0808:            /**
0809:             * Returns the last (innermost) group in the report, or <code>null</code>
0810:             * if there are no groups.
0811:             *
0812:             * @return the last (innermost) group in the report, or <code>null</code>
0813:             * if there are no groups.
0814:             */
0815:            public Group innermostGroup() {
0816:                return groups.size() > 0 ? (Group) groups
0817:                        .get(groups.size() - 1) : null;
0818:            }
0819:
0820:            /**
0821:             * Returns an iterator over the groups in reverse order. Useful when
0822:             * displaying group footers.
0823:             *
0824:             * @return an iterator over the groups, in reverse order
0825:             */
0826:            public Iterator groupsReversed() {
0827:                ArrayList reversed = (ArrayList) groups.clone();
0828:                Collections.reverse(reversed);
0829:                return reversed.iterator();
0830:            }
0831:
0832:            public void removeField(Field f) {
0833:                Section s = sectionContaining(f);
0834:                if (s != null)
0835:                    s.removeField(f);
0836:            }
0837:
0838:            /**
0839:             * Returns <code>true</code> if the specified field exists within this
0840:             * report.
0841:             *
0842:             * @param f a field
0843:             * @return <code>true</code> if the specified field exists within this
0844:             * report
0845:             */
0846:            public boolean contains(Field f) {
0847:                return sectionContaining(f) != null;
0848:            }
0849:
0850:            /**
0851:             * Returns the section containing the specified field, or <code>null</code>
0852:             * if the field is not in the report.
0853:             *
0854:             * @param f a field
0855:             * @return the section containing the specified field, or <code>null</code>
0856:             * if the field is not in the report
0857:             */
0858:            public Section sectionContaining(Field f) {
0859:                Section s;
0860:                Iterator iter, iter2;
0861:                for (iter = reportHeaders.iterator(); iter.hasNext();) {
0862:                    s = (Section) iter.next();
0863:                    if (s.contains(f))
0864:                        return s;
0865:                }
0866:                for (iter = pageHeaders.iterator(); iter.hasNext();) {
0867:                    s = (Section) iter.next();
0868:                    if (s.contains(f))
0869:                        return s;
0870:                }
0871:                for (iter = groups.iterator(); iter.hasNext();) {
0872:                    for (iter2 = ((Group) iter.next()).headers().iterator(); iter2
0873:                            .hasNext();) {
0874:                        s = (Section) iter2.next();
0875:                        if (s.contains(f))
0876:                            return s;
0877:                    }
0878:                }
0879:                for (iter = details.iterator(); iter.hasNext();) {
0880:                    s = (Section) iter.next();
0881:                    if (s.contains(f))
0882:                        return s;
0883:                }
0884:                for (iter = groups.iterator(); iter.hasNext();) {
0885:                    for (iter2 = ((Group) iter.next()).footers().iterator(); iter2
0886:                            .hasNext();) {
0887:                        s = (Section) iter2.next();
0888:                        if (s.contains(f))
0889:                            return s;
0890:                    }
0891:                }
0892:                for (iter = reportFooters.iterator(); iter.hasNext();) {
0893:                    s = (Section) iter.next();
0894:                    if (s.contains(f))
0895:                        return s;
0896:                }
0897:                for (iter = pageFooters.iterator(); iter.hasNext();) {
0898:                    s = (Section) iter.next();
0899:                    if (s.contains(f))
0900:                        return s;
0901:                }
0902:
0903:                return null;
0904:            }
0905:
0906:            /**
0907:             * Returns <code>true</code> if the specified field exists within this
0908:             * report either directly (as a field) or indirectly (as a formula used
0909:             * by a aggregate, parameter, user column, or another formula).
0910:             *
0911:             * @param f a field
0912:             * @return <code>true</code> if the specified field exists within this
0913:             * report
0914:             */
0915:            public boolean containsReferenceTo(final Field f) {
0916:                if (startFormula != null && startFormula.refersTo(f))
0917:                    return true;
0918:
0919:                final boolean[] answer = new boolean[1];
0920:                answer[0] = false;
0921:
0922:                withSectionsDo(new SectionWalker() {
0923:                    public void step(Section s) {
0924:                        if (s.containsReferenceTo(f))
0925:                            answer[0] = true;
0926:                    }
0927:                });
0928:
0929:                return answer[0];
0930:            }
0931:
0932:            /**
0933:             * Returns <code>true</code> if the specified formula exists within this
0934:             * report either directly (as a formula field) or indirectly (as a formula
0935:             * used by a aggregate or by another formula). This is not the same as
0936:             * answering the question, "Does this report contain this formula?" because
0937:             * we want to know if the visual portion of the report or some other formula
0938:             * accesses the specified formula.
0939:             *
0940:             * @param f a formula
0941:             * @return <code>true</code> if the specified parameter exists within some
0942:             * visual element of the report or within some formula
0943:             */
0944:            public boolean containsReferenceTo(final Formula f) {
0945:                if (startFormula != null && startFormula.refersTo(f))
0946:                    return true;
0947:
0948:                final boolean[] answer = new boolean[1];
0949:                answer[0] = false;
0950:
0951:                withSectionsDo(new SectionWalker() {
0952:                    public void step(Section s) {
0953:                        if (s.containsReferenceTo(f))
0954:                            answer[0] = true;
0955:                    }
0956:                });
0957:
0958:                return answer[0];
0959:            }
0960:
0961:            /**
0962:             * Returns <code>true</code> if the specified user column exists within
0963:             * this report either directly (as a user column field) or indirectly
0964:             * (inside a aggregate or formula). This is not the same as answering the
0965:             * question, "Does this report contain this user column?" because we want
0966:             * to know if the visual portion of the report or some formula accesses the
0967:             * specified user column.
0968:             *
0969:             * @param uc a user column
0970:             * @return <code>true</code> if the specified parameter exists within some
0971:             * visual element of the report or within some formula
0972:             */
0973:            public boolean containsReferenceTo(final UserColumn uc) {
0974:                if (startFormula != null && startFormula.refersTo(uc))
0975:                    return true;
0976:
0977:                final boolean[] answer = new boolean[1];
0978:                answer[0] = false;
0979:
0980:                withSectionsDo(new SectionWalker() {
0981:                    public void step(Section s) {
0982:                        if (s.containsReferenceTo(uc))
0983:                            answer[0] = true;
0984:                    }
0985:                });
0986:
0987:                return answer[0];
0988:            }
0989:
0990:            /**
0991:             * Returns <code>true</code> if the specified parameter exists within this
0992:             * report either directly (as a parameter field) or indirectly (as a
0993:             * parameter used by a aggregate or by another parameter or in the query's
0994:             * where clause). This is not the same as answering the question, "Does
0995:             * this report contain this parameter?" because we want to know if the
0996:             * visual portion of the report or some formula accesses the specified
0997:             * parameter.
0998:             *
0999:             * @param p a parameter
1000:             * @return <code>true</code> if the specified parameter exists within some
1001:             * visual element of the report or within some formula or within the
1002:             * query's where clause
1003:             */
1004:            public boolean containsReferenceTo(final Parameter p) {
1005:                if (startFormula != null && startFormula.refersTo(p))
1006:                    return true;
1007:
1008:                if (dataSource.containsReferenceTo(p))
1009:                    return true;
1010:
1011:                final boolean[] answer = new boolean[1];
1012:                answer[0] = false;
1013:
1014:                withSectionsDo(new SectionWalker() {
1015:                    public void step(Section s) {
1016:                        if (s.containsReferenceTo(p))
1017:                            answer[0] = true;
1018:                    }
1019:                });
1020:
1021:                return answer[0];
1022:            }
1023:
1024:            /**
1025:             * Returns a list of all the parameters actually used in the report.
1026:             *
1027:             * @return a list of parameters
1028:             */
1029:            protected List collectUsedParameters() {
1030:                ArrayList list = new ArrayList();
1031:                for (Iterator iter = parameters.values().iterator(); iter
1032:                        .hasNext();) {
1033:                    Parameter p = (Parameter) iter.next();
1034:                    if (containsReferenceTo(p))
1035:                        list.add(p);
1036:                }
1037:                return list;
1038:            }
1039:
1040:            /**
1041:             * Returns the group associated with the specified column, or
1042:             * <code>null</code> if there isn't one.
1043:             *
1044:             * @param selectable a selectable field
1045:             * @return the group associated with this column, or <code>null</code>
1046:             * if there isn't one
1047:             */
1048:            public Group findGroup(Selectable selectable) {
1049:                for (Iterator iter = groups(); iter.hasNext();) {
1050:                    Group g = (Group) iter.next();
1051:                    if (g.getSelectable() == selectable)
1052:                        return g;
1053:                }
1054:                return null;
1055:            }
1056:
1057:            /**
1058:             * Returns the group associated with the specified section, or
1059:             * <code>null</code> if there isn't one.
1060:             *
1061:             * @param section a section
1062:             * @return the group associated with this section, or <code>null</code>
1063:             * if there isn't one
1064:             */
1065:            public Group findGroup(Section section) {
1066:                for (Iterator iter = groups(); iter.hasNext();) {
1067:                    Group group = (Group) iter.next();
1068:                    if (group.contains(section))
1069:                        return group;
1070:                }
1071:                return null;
1072:            }
1073:
1074:            /**
1075:             * Returns <code>true</code> if the specified section is contained in
1076:             * any group. The section may be either a header or a footer section.
1077:             *
1078:             * @param section a section
1079:             * @return <code>true</code> if the section is within some group
1080:             */
1081:            public boolean isInsideGroup(Section section) {
1082:                return findGroup(section) != null;
1083:            }
1084:
1085:            /**
1086:             * Returns <code>true</code> if the specified data source column is a
1087:             * group column.
1088:             *
1089:             * @return <code>true</code> if the specified data source column is a
1090:             * group column
1091:             */
1092:            public boolean isUsedBySomeGroup(Selectable g) {
1093:                return findGroup(g) != null;
1094:            }
1095:
1096:            /**
1097:             * Creates and returns a new section below the specified one.
1098:             *
1099:             * @param goBelowThis a section
1100:             * @return a new section
1101:             */
1102:            public Section insertSectionBelow(Section goBelowThis) {
1103:                return insertSectionBelow(null, goBelowThis);
1104:            }
1105:
1106:            /**
1107:             * Inserts a (possibly newly created) section below the specified one.
1108:             * Returns the inserted section.
1109:             *
1110:             * @param section the section to insert
1111:             * @param goBelowThis <var>section</var> goes below this one; 
1112:             * @return a new section
1113:             */
1114:            public Section insertSectionBelow(Section section,
1115:                    Section goBelowThis) {
1116:                if (section == null)
1117:                    section = new Section(this );
1118:
1119:                if (goBelowThis == null)
1120:                    return reportHeaders.insertAfter(section, null);
1121:
1122:                if (reportHeaders.contains(goBelowThis))
1123:                    return reportHeaders.insertAfter(section, goBelowThis);
1124:                else if (reportFooters.contains(goBelowThis))
1125:                    return reportFooters.insertAfter(section, goBelowThis);
1126:                else if (pageHeaders.contains(goBelowThis))
1127:                    return pageHeaders.insertAfter(section, goBelowThis);
1128:                else if (pageFooters.contains(goBelowThis))
1129:                    return pageFooters.insertAfter(section, goBelowThis);
1130:                else if (details.contains(goBelowThis))
1131:                    return details.insertAfter(section, goBelowThis);
1132:
1133:                for (Iterator iter = groups(); iter.hasNext();) {
1134:                    Group g = (Group) iter.next();
1135:                    if (g.headers().contains(goBelowThis))
1136:                        return g.headers().insertAfter(section, goBelowThis);
1137:                    else if (g.footers().contains(goBelowThis))
1138:                        return g.footers().insertAfter(section, goBelowThis);
1139:                }
1140:
1141:                return null; // Should not happen
1142:            }
1143:
1144:            /**
1145:             * Removes the specified section.
1146:             *
1147:             * @param s a section
1148:             */
1149:            public void removeSection(Section s) {
1150:                if (reportHeaders.contains(s))
1151:                    reportHeaders.remove(s);
1152:                else if (reportFooters.contains(s))
1153:                    reportFooters.remove(s);
1154:                else if (pageHeaders.contains(s))
1155:                    pageHeaders.remove(s);
1156:                else if (pageFooters.contains(s))
1157:                    pageFooters.remove(s);
1158:                else if (details.contains(s))
1159:                    details.remove(s);
1160:                else {
1161:                    for (Iterator iter = groups(); iter.hasNext();) {
1162:                        Group g = (Group) iter.next();
1163:                        if (g.headers().contains(s)) {
1164:                            g.headers().remove(s);
1165:                            return;
1166:                        } else if (g.footers().contains(s)) {
1167:                            g.footers().remove(s);
1168:                            return;
1169:                        }
1170:                    }
1171:                }
1172:            }
1173:
1174:            /**
1175:             * Returns <code>true</code> if this report contains some field anywhere.
1176:             * Useful when the GUI is enabling menu items, for example.
1177:             *
1178:             * @return <code>true</code> if this report contains some field anywhere
1179:             */
1180:            public boolean hasFields() {
1181:                final boolean[] answer = new boolean[1];
1182:                answer[0] = false;
1183:                withFieldsDo(new FieldWalker() {
1184:                    public void step(Field f) {
1185:                        answer[0] = true;
1186:                    }
1187:                });
1188:                return answer[0];
1189:            }
1190:
1191:            /**
1192:             * Returns <code>true</code> if this report contains some parameter field
1193:             * anywhere. This doesn't determine if any parameters have been created,
1194:             * but rather if any of the parameters are actually used in the report.
1195:             * <p>
1196:             * This method is not used by DataVision, but is useful for apps embedding
1197:             * DataVision that want to answer the question, "Do I have to read in
1198:             * a parameter XML file?"
1199:             *
1200:             * @return <code>true</code> if this report contains some parameter field
1201:             * anywhere
1202:             */
1203:            public boolean hasParameterFields() {
1204:                final boolean answer[] = new boolean[1];
1205:                answer[0] = false;
1206:                withFieldsDo(new FieldWalker() {
1207:                    public void step(Field f) {
1208:                        if (f instanceof  ParameterField)
1209:                            answer[0] = true;
1210:                    }
1211:                });
1212:                return answer[0];
1213:            }
1214:
1215:            /**
1216:             * Returns <code>true</code> if the specified section is the only section
1217:             * of its kind; that is, the only section in the collection in which it
1218:             * is contained.
1219:             *
1220:             * @param s a report section
1221:             * @return <code>true</code> if this section is a loner
1222:             */
1223:            public boolean isOneOfAKind(Section s) {
1224:                if (reportHeaders.contains(s))
1225:                    return reportHeaders.size() == 1;
1226:                if (reportFooters.contains(s))
1227:                    return reportFooters.size() == 1;
1228:                if (pageHeaders.contains(s))
1229:                    return pageHeaders.size() == 1;
1230:                if (pageFooters.contains(s))
1231:                    return pageFooters.size() == 1;
1232:                if (details.contains(s))
1233:                    return details.size() == 1;
1234:
1235:                for (Iterator iter = groups(); iter.hasNext();) {
1236:                    Group g = (Group) iter.next();
1237:                    if (g.headers().contains(s))
1238:                        return g.headers().size() == 1;
1239:                    if (g.footers().contains(s))
1240:                        return g.footers().size() == 1;
1241:                }
1242:
1243:                return false;
1244:            }
1245:
1246:            /**
1247:             * Sets the database password.
1248:             */
1249:            public void setDatabasePassword(String pwd) {
1250:                databasePassword = pwd;
1251:            }
1252:
1253:            /**
1254:             * Sets a database's user name and password. Called from {@link
1255:             * Database#initializeConnection}. If we already have the password, give it to
1256:             * the database. If we don't, ask the user for both the user name (supplied to
1257:             * us) and the password and give them to the database.
1258:             *
1259:             * @param db the database
1260:             */
1261:            public void askForPassword(Database db) {
1262:                if (databasePassword != null) {
1263:                    db.setPassword(databasePassword);
1264:                    return;
1265:                }
1266:
1267:                if (ErrorHandler.usingGUI()) {
1268:                    DbPasswordDialog dialog = new DbPasswordDialog(
1269:                            getDesignFrame(), db.getName(), db.getUserName());
1270:                    // This dialog is modal, so when we return the values have been
1271:                    // filled.
1272:                    db.setUserName(dialog.getUserName());
1273:                    db.setPassword(dialog.getPassword());
1274:                } else {
1275:                    System.out.print(I18N.get("Report.user_name") + " ["
1276:                            + db.getUserName() + "]: ");
1277:                    System.out.flush();
1278:                    try {
1279:                        BufferedReader in = new BufferedReader(
1280:                                new InputStreamReader(System.in));
1281:                        String username = in.readLine();
1282:                        if (username.length() > 0)
1283:                            db.setUserName(username);
1284:                    } catch (IOException e) {
1285:                        ErrorHandler.error(I18N.get("Report.user_name_err"));
1286:                    }
1287:
1288:                    System.out.print(I18N.get("Report.password") + ' '
1289:                            + db.getUserName() + ": ");
1290:                    System.out.flush();
1291:                    try {
1292:                        BufferedReader in = new BufferedReader(
1293:                                new InputStreamReader(System.in));
1294:                        databasePassword = in.readLine();
1295:                        db.setPassword(databasePassword);
1296:                    } catch (IOException e) {
1297:                        ErrorHandler.error(I18N.get("Report.password_err"));
1298:                    }
1299:                }
1300:            }
1301:
1302:            /**
1303:             * Returns the value of the specified parameter. First time at the start
1304:             * of each report run, asks user for parameter values.
1305:             *
1306:             * @param paramId a parameter id
1307:             */
1308:            public Object getParameterValue(Object paramId) {
1309:                if (!askedForParameters)
1310:                    askForParameters();
1311:
1312:                return findParameter(paramId).getValue();
1313:            }
1314:
1315:            /**
1316:             * Lets the caller tell the report to ask for parameters (<var>val</var> is
1317:             * <code>false</code>, the default value) or to not ask (<var>val</var> is
1318:             * <code>true</code>). Call this method with <var>val</var> <code>=
1319:             * true</code> when you set the parameters in your Java code manually.
1320:             */
1321:            public void parametersSetManually(boolean val) {
1322:                paramsSetManually = val;
1323:            }
1324:
1325:            /**
1326:             * Asks the user for parameter values. If the user cancels, we throw a
1327:             * <code>UserCancellationException</code>.
1328:             */
1329:            protected void askForParameters() throws UserCancellationException {
1330:                List usedParameters = null;
1331:                if (askedForParameters || paramsSetManually
1332:                        || (usedParameters = collectUsedParameters()).isEmpty()) {
1333:                    askedForParameters = true;
1334:                    return;
1335:                }
1336:
1337:                if (ErrorHandler.usingGUI()) {
1338:                    if (parametersHaveValues) {
1339:                        // Ask user about re-using the previous values
1340:                        String msg = I18N.get("Report.use_prev_param_vals");
1341:                        if (JOptionPane.showConfirmDialog(getDesignFrame(),
1342:                                msg, I18N.get("Report.use_prev_title"),
1343:                                JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
1344:                            askedForParameters = true;
1345:                            parametersHaveValues = true;
1346:                            return;
1347:                        }
1348:                    }
1349:
1350:                    // This dialog is modal. By the time it returns, the parameters
1351:                    // have their new values.
1352:
1353:                    if (new ParamAskWin(getDesignFrame(), usedParameters)
1354:                            .userCancelled())
1355:                        throw new UserCancellationException(I18N
1356:                                .get("Report.user_cancelled"));
1357:                } else {
1358:                    if (paramReader == null) {
1359:                        ErrorHandler.error(I18N
1360:                                .get("Report.missing_param_xml_file"));
1361:                        throw new UserCancellationException(I18N
1362:                                .get("Report.missing_param_xml_file_short"));
1363:                    }
1364:                    try {
1365:                        paramReader.read();
1366:                        paramReader = null;
1367:                    } catch (Exception ex) {
1368:                        ErrorHandler.error(I18N.get("Report.param_file_err_1")
1369:                                + ' ' + paramReader.getInputName()
1370:                                + I18N.get("Report.param_file_err_2"), ex);
1371:                        throw new UserCancellationException(I18N
1372:                                .get("Report.param_file_err_short"));
1373:                    }
1374:                }
1375:
1376:                askedForParameters = true;
1377:                parametersHaveValues = true;
1378:            }
1379:
1380:            /**
1381:             * Asks the user for a data source file if necessary. If the user cancels,
1382:             * we throw a <code>UserCancellationException</code>.
1383:             */
1384:            protected void askForDataSourceFile()
1385:                    throws UserCancellationException, FileNotFoundException {
1386:                if (!dataSource.usesSourceFile() || !ErrorHandler.usingGUI())
1387:                    return;
1388:
1389:                if (!dataSource.needsSourceFile()) {
1390:                    if (dataSource.alreadyUsedSourceFile()) {
1391:                        // Ask user about re-using the previous values
1392:                        String msg = I18N
1393:                                .get("Report.use_prev_data_source_file");
1394:                        if (JOptionPane.showConfirmDialog(getDesignFrame(),
1395:                                msg,
1396:                                I18N.get("Report.use_prev_data_source_title"),
1397:                                JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
1398:                            dataSource.reuseSourceFile();
1399:                        }
1400:                    }
1401:                    return;
1402:                }
1403:
1404:                Frame frame = Designer.findWindowFor(this ) == null ? null
1405:                        : Designer.findWindowFor(this ).getFrame();
1406:                JFileChooser chooser = Designer.getChooser();
1407:                Designer.setPrefsDir(chooser, "dataSourceDir");
1408:                int returnVal = chooser.showOpenDialog(frame);
1409:                if (returnVal == JFileChooser.APPROVE_OPTION) {
1410:                    Designer.savePrefsDir(chooser, "dataSourceDir");
1411:                    dataSource.setSourceFile(chooser.getSelectedFile()
1412:                            .getPath());
1413:                } else
1414:                    throw new UserCancellationException(I18N
1415:                            .get("Report.user_cancelled"));
1416:            }
1417:
1418:            /**
1419:             * Spawns a new thread that runs the report, using the layout engine to
1420:             * generate output. The new thread runs the method {@link #runReport}.
1421:             * <p>
1422:             * You may ask why this method is called <code>run</code> and it runs another
1423:             * method called <code>runReport</code> when the normal convention is for a
1424:             * thread to run a {@link Runnable} object that has a <code>run</code> method.
1425:             * The reason is purely historical. This method started non-threaded, and I
1426:             * don't want anyone else who relies on this method to have to change their
1427:             * code.
1428:             *
1429:             * @see #runReport
1430:             */
1431:            public void run() {
1432:                new Thread(new Runnable() {
1433:                    public void run() {
1434:                        runReport();
1435:                    }
1436:                }).start();
1437:            }
1438:
1439:            /**
1440:             * Runs the data source's query and hands rows to the layout engine. This
1441:             * method is called from {@link #run}, which spawns a new thread in which this
1442:             * method is run. If you want to run a report, decide if you want it to run in
1443:             * a separate thread or not. If so, call <code>run</code>. If not, use this
1444:             * method.
1445:             */
1446:            public void runReport() {
1447:                // Parameters
1448:                askedForParameters = false; // Ask user again
1449:                try {
1450:                    askForDataSourceFile();
1451:                    askForParameters();
1452:                } catch (UserCancellationException e) { // Ignore
1453:                    return;
1454:                } catch (IOException ioe) { // Handled when parsed as XML
1455:                    return;
1456:                }
1457:
1458:                // Pre-report initialization
1459:                for (Iterator iter = groups.iterator(); iter.hasNext();)
1460:                    ((Group) iter.next()).reset();
1461:                collectAggregateFields();
1462:                if (startFormula != null)
1463:                    startFormula.eval();
1464:                for (Iterator iter = formulas(); iter.hasNext();)
1465:                    ((Formula) iter.next()).useCache();
1466:                resetCachedValues();
1467:
1468:                rset = null;
1469:                StatusDialog statusDialog = null;
1470:
1471:                try {
1472:                    if (ErrorHandler.usingGUI()) {
1473:                        statusDialog = new StatusDialog(getDesignFrame(), I18N
1474:                                .get("Report.status_title"), true, I18N
1475:                                .get("Report.status_running"));
1476:                    }
1477:
1478:                    if (!layoutEngine.wantsMoreData())
1479:                        return;
1480:
1481:                    rset = dataSource.execute();
1482:
1483:                    boolean layoutStarted = false;
1484:                    while (layoutEngine.wantsMoreData() && rset.next()) {
1485:                        if (statusDialog != null) {
1486:                            if (statusDialog.isCancelled())
1487:                                throw new UserCancellationException();
1488:                            statusDialog.update(I18N
1489:                                    .get("Report.processing_row")
1490:                                    + ' ' + rowNumber());
1491:                        }
1492:
1493:                        if (!layoutStarted) {
1494:                            layoutEngine.start();
1495:                            layoutStarted = true;
1496:                        }
1497:                        processResultRow();
1498:                    }
1499:
1500:                    rset.last(); // Recall last row so we can access the data
1501:                    if (!layoutStarted) { // No rows in report
1502:                        layoutEngine.start();
1503:                        layoutEngine.end();
1504:                    } else { // Output group footers and end of report
1505:                        layoutEngine.groupFooters(true);
1506:                        layoutEngine.end();
1507:                    }
1508:                } catch (UserCancellationException uce) {
1509:                    layoutEngine.cancel();
1510:                } catch (SQLException sqle) {
1511:                    layoutEngine.cancel();
1512:                    ErrorHandler.error(dataSource.getQuery().toString(), sqle);
1513:                } catch (Exception e) {
1514:                    layoutEngine.cancel();
1515:                    ErrorHandler.error(e);
1516:                } finally {
1517:                    if (rset != null)
1518:                        rset.close();
1519:
1520:                    aggregateFields = null;
1521:                    for (Iterator iter = groups.iterator(); iter.hasNext();)
1522:                        ((Group) iter.next()).reset();
1523:                    resetCachedValues();
1524:
1525:                    if (statusDialog != null)
1526:                        statusDialog.dispose();
1527:                }
1528:            }
1529:
1530:            /**
1531:             * Returns the <code>Frame</code> associated with the design window for
1532:             * this report; may be <code>null</code>.
1533:             *
1534:             * @return a <code>Frame</code>; may be <code>null</code>
1535:             */
1536:            protected Frame getDesignFrame() {
1537:                Designer d = Designer.findWindowFor(this );
1538:                return d == null ? null : d.getFrame();
1539:            }
1540:
1541:            /**
1542:             * Processes a single data source row. Note that the <code>next</code>
1543:             * method of the result set has already been called.
1544:             */
1545:            protected void processResultRow() throws java.sql.SQLException {
1546:                resetCachedValues();
1547:                updateGroups();
1548:
1549:                // To output footers, bring back the previous row of data
1550:                if (!rset.isFirst()) {
1551:                    rset.previous();
1552:                    layoutEngine.groupFooters(false);
1553:                    rset.next();
1554:                    resetCachedValues();
1555:                }
1556:
1557:                updateGroupCounters();
1558:                updateAggregates();
1559:
1560:                boolean isLastRow = rset.isLast();
1561:                layoutEngine.groupHeaders(isLastRow);
1562:                layoutEngine.detail(isLastRow);
1563:            }
1564:
1565:            /**
1566:             * Tells each formula that it should re-evaluate.
1567:             */
1568:            protected void resetCachedValues() {
1569:                for (Iterator iter = formulas(); iter.hasNext();)
1570:                    ((Formula) iter.next()).shouldEvaluate();
1571:                for (Iterator iter = subreports(); iter.hasNext();)
1572:                    ((Subreport) iter.next()).clearCache();
1573:            }
1574:
1575:            /**
1576:             * Evalues the formulas in the specified section. This is called by the
1577:             * layout engine just before the section gets output.
1578:             *
1579:             * @param s a section
1580:             */
1581:            public void evaluateFormulasIn(Section s) {
1582:                for (Iterator iter = s.fields(); iter.hasNext();) {
1583:                    Field f = (Field) iter.next();
1584:                    if (f instanceof  FormulaField)
1585:                        ((FormulaField) f).getValue(); // Force evaluation
1586:                }
1587:            }
1588:
1589:            /**
1590:             * Returns the current value of the specified selectable. Only defined
1591:             * when running a report.
1592:             *
1593:             * @return the string or Double value of the column
1594:             */
1595:            public Object columnValue(Selectable selectable) {
1596:                // Ask data source for field number, then get value of that column
1597:                return rset
1598:                        .getObject(dataSource.indexOfSelectable(selectable) + 1);
1599:            }
1600:
1601:            /**
1602:             * Returns the current page number. Asks the layout engine. Only defined
1603:             * when running a report.
1604:             *
1605:             * @return a page number
1606:             */
1607:            public int pageNumber() {
1608:                return layoutEngine.pageNumber();
1609:            }
1610:
1611:            /**
1612:             * Returns the current data row number. Only defined when running a report.
1613:             */
1614:            public int rowNumber() {
1615:                return rset.getRow();
1616:            }
1617:
1618:            /**
1619:             * Returns the current row of data. Only defined when running a report.
1620:             */
1621:            public DataCursor getCurrentRow() {
1622:                return rset;
1623:            }
1624:
1625:            /**
1626:             * Iterates over all sections in the report, passing the section to the
1627:             * specified <code>SectionWalker</code>. The sections are visited in the
1628:             * order in which they will be displayed.
1629:             *
1630:             * @param s a section walker
1631:             */
1632:            public void withSectionsDo(SectionWalker s) {
1633:                reportHeaders.withSectionsDo(s);
1634:                pageHeaders.withSectionsDo(s);
1635:                for (Iterator iter = groups.iterator(); iter.hasNext();)
1636:                    ((Group) iter.next()).headers().withSectionsDo(s);
1637:                details.withSectionsDo(s);
1638:                for (Iterator iter = groups.iterator(); iter.hasNext();)
1639:                    ((Group) iter.next()).footers().withSectionsDo(s);
1640:                reportFooters.withSectionsDo(s);
1641:                pageFooters.withSectionsDo(s);
1642:            }
1643:
1644:            /**
1645:             * Iterates over all fields in the report, passing the section to the
1646:             * specified <code>FieldWalker</code>.
1647:             *
1648:             * @param f a field walker
1649:             */
1650:            public void withFieldsDo(final FieldWalker f) {
1651:                withSectionsDo(new SectionWalker() {
1652:                    public void step(Section s) {
1653:                        for (Iterator it = s.fields(); it.hasNext();)
1654:                            f.step((Field) it.next());
1655:                    }
1656:                });
1657:            }
1658:
1659:            /**
1660:             * Collects all aggregate fields and lets each one initialize itself.
1661:             * Used once at the beginning of each run.
1662:             */
1663:            protected void collectAggregateFields() {
1664:                aggregateFields = new ArrayList();
1665:                withFieldsDo(new FieldWalker() {
1666:                    public void step(Field f) {
1667:                        if (f instanceof  AggregateField) {
1668:                            ((AggregateField) f).initialize();
1669:                            aggregateFields.add(f);
1670:                        }
1671:                    }
1672:                });
1673:            }
1674:
1675:            /**
1676:             * Collects all aggregate fields that are aggregating the specified field.
1677:             * Used by the report design GUI.
1678:             * 
1679:             * @param field a field
1680:             * @return a list of aggregate fields
1681:             */
1682:            public AbstractList getAggregateFieldsFor(final Field field) {
1683:                final ArrayList subs = new ArrayList();
1684:                withFieldsDo(new FieldWalker() {
1685:                    public void step(Field f) {
1686:                        if (f instanceof  AggregateField
1687:                                && ((AggregateField) f).getField() == field) {
1688:                            subs.add(f);
1689:                        }
1690:                    }
1691:                });
1692:                return subs;
1693:            }
1694:
1695:            /**
1696:             * Updates each aggregate field.
1697:             */
1698:            protected void updateAggregates() {
1699:                for (Iterator iter = aggregateFields.iterator(); iter.hasNext();)
1700:                    ((AggregateField) iter.next()).updateAggregate();
1701:            }
1702:
1703:            /**
1704:             * Updates each group's value based on the current value of the column
1705:             * each group uses.
1706:             */
1707:            protected void updateGroups() {
1708:                for (Iterator iter = groups.iterator(); iter.hasNext();) {
1709:                    Group g = (Group) iter.next();
1710:                    g.setValue(this );
1711:                }
1712:            }
1713:
1714:            /**
1715:             * Lets each group update its line counter.
1716:             */
1717:            protected void updateGroupCounters() {
1718:                for (Iterator iter = groups.iterator(); iter.hasNext();) {
1719:                    Group g = (Group) iter.next();
1720:                    g.updateCounter();
1721:                }
1722:            }
1723:
1724:            /**
1725:             * Remembers name of parameter XML file.
1726:             *
1727:             * @param f an XML file
1728:             */
1729:            public void setParameterXMLInput(File f) {
1730:                paramReader = new ParameterReader(this , f);
1731:            }
1732:
1733:            /**
1734:             * Remembers an input source and reads parameter values from it later. To
1735:             * speicfy a URL, use InputSource("http://...")</code>.
1736:             *
1737:             * @param in the input source
1738:             */
1739:            public void setParameterXMLInput(InputSource in) {
1740:                paramReader = new ParameterReader(this , in);
1741:            }
1742:
1743:            /**
1744:             * Reads an XML file and builds the contents of this report. Uses a
1745:             * <code>ReportReader</code>.
1746:             *
1747:             * @param f a report XML file
1748:             */
1749:            public void read(File f) throws Exception {
1750:                new ReportReader(this ).read(f);
1751:            }
1752:
1753:            /**
1754:             * Reads an XML stream using a <code>org.xml.sax.InputSource</code> and
1755:             * builds the contents of this report. Uses a <code>ReportReader</code>.
1756:             * To specify a URL, use <code>new InputSource("http://...")</code>.
1757:             *
1758:             * @param in a reader
1759:             * @see ReportReader#read(org.xml.sax.InputSource)
1760:             */
1761:            public void read(org.xml.sax.InputSource in) throws Exception {
1762:                new ReportReader(this ).read(in);
1763:            }
1764:
1765:            /**
1766:             * Writes the contents of this report as an XML file.
1767:             *
1768:             * @param fileName a file name string
1769:             */
1770:            public void writeFile(String fileName) {
1771:                XMLWriter out = null;
1772:                try {
1773:                    out = new XMLWriter(new OutputStreamWriter(
1774:                            new FileOutputStream(fileName), XML_JAVA_ENCODING));
1775:                    writeXML(out);
1776:                    out.close();
1777:                } catch (IOException ioe) {
1778:                    ErrorHandler
1779:                            .error(I18N.get("Report.write_err") + ' '
1780:                                    + fileName, ioe, I18N
1781:                                    .get("Report.write_err_title"));
1782:                } finally {
1783:                    if (out != null)
1784:                        out.close();
1785:                }
1786:            }
1787:
1788:            /**
1789:             * Writes the contents of this report as an XML file.
1790:             *
1791:             * @param out an indent writer
1792:             */
1793:            public void writeXML(XMLWriter out) {
1794:                writeXMLDecl(out);
1795:                writeComment(out);
1796:                writeReport(out);
1797:            }
1798:
1799:            protected void writeXMLDecl(XMLWriter out) {
1800:                out.xmlDecl(XML_ENCODING_ATTRIBUTE);
1801:            }
1802:
1803:            protected void writeComment(XMLWriter out) {
1804:                out.comment("Generated by DataVision version " + info.Version);
1805:                out.comment(info.URL);
1806:            }
1807:
1808:            protected void writeReport(XMLWriter out) {
1809:                out.startElement("report");
1810:                out.attr("dtd-version", OUTPUT_DTD_VERSION);
1811:                out.attr("name", name);
1812:                out.attr("title", title);
1813:                out.attr("author", author);
1814:
1815:                writeDescription(out);
1816:                scripting.writeXML(out);
1817:                writeStartFormula(out);
1818:                paperFormat.writeXML(out);
1819:                defaultField.writeXML(out);
1820:                ListWriter.writeList(out, usercols.values(), "usercols");
1821:                dataSource.writeXML(out);
1822:                ListWriter.writeList(out, subreports.values(), "subreports");
1823:                ListWriter.writeList(out, parameters.values(), "parameters");
1824:                ListWriter.writeList(out, formulas.values(), "formulas");
1825:                ListWriter.writeList(out, reportHeaders.sections(), "headers");
1826:                ListWriter.writeList(out, reportFooters.sections(), "footers");
1827:                writePage(out);
1828:                ListWriter.writeList(out, groups, "groups");
1829:                ListWriter.writeList(out, details.sections(), "details");
1830:
1831:                out.endElement();
1832:            }
1833:
1834:            protected void writeDescription(XMLWriter out) {
1835:                out.cdataElement("description", description);
1836:            }
1837:
1838:            protected void writeStartFormula(XMLWriter out) {
1839:                if (startFormula != null)
1840:                    startFormula.writeXML(out);
1841:            }
1842:
1843:            protected void writePage(XMLWriter out) {
1844:                if (pageHeaders.isEmpty() && pageFooters.isEmpty())
1845:                    return;
1846:
1847:                out.startElement("page");
1848:                ListWriter.writeList(out, pageHeaders.sections(), "headers");
1849:                ListWriter.writeList(out, pageFooters.sections(), "footers");
1850:                out.endElement();
1851:            }
1852:
1853:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.