001: package jimm.datavision;
002:
003: import jimm.datavision.source.charsep.CharSepSource;
004: import jimm.datavision.layout.*;
005: import jimm.datavision.layout.swing.SwingLE;
006: import jimm.datavision.layout.pdf.PDFLE;
007: import jimm.datavision.layout.excel.ExcelLE;
008: import jimm.datavision.gui.DesignWin;
009: import jimm.datavision.gui.StartupDialog;
010: import jimm.util.XMLWriter;
011: import jimm.util.Getopts;
012: import jimm.util.I18N;
013: import java.io.*;
014: import java.util.Locale;
015: import java.util.prefs.Preferences;
016:
017: /**
018: * This is the DataVision application class. It opens a design window
019: * for each report specified on the command line. If none are specified,
020: * it openes a new design window on a new, empty report.
021: *
022: * @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
023: */
024: public class DataVision {
025:
026: protected static final String DEFAULT_CHARACTER_SEPARATOR = ",";
027:
028: char layoutEngineChoice;
029: String layoutEngineFileName;
030: String dbPassword;
031: String paramXMLFile;
032: int numReports;
033: boolean usesGUI;
034: String charSepFile;
035: char sepChar;
036: String reportDir;
037: String outputDir;
038:
039: /**
040: * This main application method opens a design window for each report
041: * specified on the command line. If none are specified, it openes a new
042: * design window on a new, empty report.
043: *
044: * @param args command line array; each element is assumed to be a report
045: * file name.
046: */
047: public static void main(String[] args) {
048: //Getopts g = new Getopts("a:c:d:e:f:g:h:i:l:np:qr:s:wx:E:", args);
049: Getopts g = new Getopts("a:c:d:e:f:g:h:i:l:np:qr:s:wx:E:R:o:",
050: args);
051: if (g.error()) // Any bad command line argument?
052: usage(null); // If so, whine and exit
053:
054: DataVision dv = new DataVision();
055:
056: // Language
057: if (g.hasOption('g') || g.hasOption('i'))
058: I18N.setLanguage(new Locale(
059: g.option('g', "").toLowerCase(), g.option('i', "")
060: .toUpperCase()));
061:
062: dv.layoutEngineChoiceFromOptions(g);
063: dv.dataSourceFromOptions(g);
064:
065: if (dv.hasLayoutEngine()) {
066: if (dv.usesGUI()) // Can ask for password via GUI
067: ErrorHandler.useGUI(true);
068: else if (!g.hasOption('n') && !g.hasOption('p')
069: && !g.hasOption('e'))
070: usage(I18N.get("DataVision.n_or_p"));
071: }
072:
073: dv.paramXMLFile = g.option('r', null); // Parameter XML file name or null
074: dv.reportDir = g.option('R', null); // Report Directory or null
075: dv.outputDir = g.option('o', null); // Output Directory or null
076:
077: // Store the report directory in the preferences for this package
078: // These values are stored in the root package jimm.datavision
079: Preferences prefs = Preferences.userRoot().node(
080: "/jimm/datavision");
081: if (dv.reportDir != null) {
082: prefs.put("reportDir", dv.reportDir);
083: }
084: if (dv.outputDir != null) {
085: prefs.put("outputDir", dv.outputDir);
086: }
087:
088: if (g.argc() == 0) {
089: if (startupDialog()) // Returns true if we should exit
090: return;
091:
092: if (dv.hasLayoutEngine()) // Have layout engine but no file
093: usage(I18N.get("DataVision.xml_req"));
094: else {
095: try {
096: dv.designReport(g, null);
097: } catch (Exception e) { // Global catch-all
098: ErrorHandler.error(e);
099: }
100: }
101: } else { // Loop over input files
102: dv.numReports = g.argc();
103: for (int i = 0; i < g.argc(); ++i) {
104: File f = new File(g.argv(i));
105: try {
106: if (dv.hasLayoutEngine())
107: dv.runReport(g, f);
108: else
109: dv.designReport(g, f);
110: } catch (Exception e) { // Global catch-all
111: ErrorHandler.error(e);
112: }
113: }
114: }
115:
116: // For some odd reason, on Mac OS X with Java 1.4.1 the app hangs
117: // below, just before the last closing brace when run from the command
118: // line unless I add this System.exit(). I hate fixing bugs without
119: // knowing what is going wrong.
120: if (dv.hasLayoutEngine() && dv.getLayoutEngineChoice() != 'w')
121: System.exit(0);
122: }
123:
124: void designReport(Getopts g, File reportXMLFile)
125: throws FileNotFoundException {
126: DesignWin win = new DesignWin(reportXMLFile, dbPassword);
127: Report report = win.getReport();
128:
129: if (charSepFile != null) { // Must come after file read
130: CharSepSource src = (CharSepSource) report.getDataSource();
131: src.setSepChar(sepChar);
132: src.setInput(charSepFile);
133: }
134:
135: if (g.hasOption('q'))
136: report.setCaseSensitiveDatabaseNames(false);
137: }
138:
139: /**
140: * Shows startup dialog and returns <code>true</code> if we should exit
141: * the application.
142: *
143: * @return <code>true</code> if we should exit the application
144: */
145: static boolean startupDialog() {
146: // Show the startup dialog and await return from it
147: StartupDialog sd = new StartupDialog();
148:
149: // Get the file the user selected on the startup dialog, if any
150: String selectedFile = sd.getSelectedFile();
151:
152: // If they clicked the close window button, we'll get back null, and we'll
153: // return true so the app exits.
154: if (selectedFile == null)
155: return true;
156:
157: // If we DID NOT get the value "*StartANewReport*", then they must have
158: // selected a file, so let's insert it into the parameters array and call
159: // back to this main method so it looks like we started the app with the
160: // file in the command line
161: if (!selectedFile
162: .equalsIgnoreCase(StartupDialog.NEW_REPORT_STRING)) {
163: String[] newArgs = { selectedFile };
164: main(newArgs);
165: return true;
166: }
167:
168: return false; // The user didn't select a file
169: }
170:
171: void runReport(Getopts g, File reportXMLFile) throws Exception {
172: Report report = new Report();
173:
174: if (dbPassword != null)
175: report.setDatabasePassword(dbPassword);
176:
177: report.read(reportXMLFile); // Must come after password set
178:
179: if (paramXMLFile != null) // Must come after file read
180: report.setParameterXMLInput(new File(paramXMLFile));
181:
182: if (charSepFile != null) { // Must come after file read
183: CharSepSource src = (CharSepSource) report.getDataSource();
184: src.setSepChar(sepChar);
185: src.setInput(charSepFile);
186: }
187:
188: if (g.hasOption('q'))
189: report.setCaseSensitiveDatabaseNames(false);
190:
191: report.setLayoutEngine(createLayoutEngine(reportXMLFile, g));
192: report.runReport();
193: }
194:
195: boolean hasLayoutEngine() {
196: return layoutEngineChoice != '\0';
197: }
198:
199: char getLayoutEngineChoice() {
200: return layoutEngineChoice;
201: }
202:
203: boolean usesGUI() {
204: return usesGUI;
205: }
206:
207: void layoutEngineChoiceFromOptions(Getopts g) {
208: String errMsg = I18N.get("DataVision.le_one");
209:
210: layoutEngineChoice = '\0';
211: if (g.hasOption('c')) {
212: layoutEngineChoice = 'c';
213: layoutEngineFileName = g.option('c', null);
214: }
215: if (g.hasOption('d')) {
216: if (layoutEngineChoice != '\0')
217: usage(errMsg);
218: layoutEngineChoice = 'd';
219: layoutEngineFileName = g.option('d', null);
220: }
221: if (g.hasOption('f')) {
222: if (layoutEngineChoice != '\0')
223: usage(errMsg);
224: layoutEngineChoice = 'f';
225: layoutEngineFileName = g.option('f', null);
226: }
227: if (g.hasOption('h')) {
228: if (layoutEngineChoice != '\0')
229: usage(errMsg);
230: layoutEngineChoice = 'h';
231: layoutEngineFileName = g.option('h', null);
232: }
233: if (g.hasOption('l')) {
234: if (layoutEngineChoice != '\0')
235: usage(errMsg);
236: layoutEngineChoice = 'l';
237: layoutEngineFileName = g.option('l', null);
238: }
239: if (g.hasOption('x')) {
240: if (layoutEngineChoice != '\0')
241: usage(errMsg);
242: layoutEngineChoice = 'x';
243: layoutEngineFileName = g.option('x', null);
244: }
245: if (g.hasOption('E')) {
246: if (layoutEngineChoice != '\0')
247: usage(errMsg);
248: layoutEngineChoice = 'E';
249: layoutEngineFileName = g.option('E', null);
250: }
251: if (g.hasOption('w')) {
252: if (layoutEngineChoice != '\0')
253: usage(errMsg);
254: layoutEngineChoice = 'w';
255: usesGUI = true;
256: }
257: if (g.hasOption('t')) {
258: if (layoutEngineChoice != '\0')
259: usage(errMsg);
260: layoutEngineChoice = 't';
261: layoutEngineFileName = g.option('t', null);
262: }
263: }
264:
265: LayoutEngine createLayoutEngine(File f, Getopts g)
266: throws IOException {
267: LayoutEngine le = null;
268:
269: // Create new file name.
270: String fileName = f.getName();
271: String fileNameSansExtension = null;
272: if (layoutEngineFileName != null) {
273: int pos = fileName.lastIndexOf('.');
274: if (pos == -1)
275: fileNameSansExtension = fileName;
276: else
277: fileNameSansExtension = fileName.substring(0, pos);
278: }
279:
280: String outFileName = null;
281: PrintWriter out = null;
282: switch (layoutEngineChoice) {
283: case 'c':
284: char sep = g.option('s', DEFAULT_CHARACTER_SEPARATOR)
285: .charAt(0);
286: if (layoutEngineFileName != null)
287: outFileName = layoutEngineFileName;
288: else {
289: outFileName = fileNameSansExtension
290: + (sep == ',' ? ".csv" : ".tab");
291: if (outFileName.equals(fileName))
292: outFileName = fileNameSansExtension + "_out"
293: + (sep == ',' ? ".csv" : ".tab");
294: }
295: out = new PrintWriter(new FileWriter(outFileName));
296: le = new CharSepLE(out, sep);
297: break;
298: case 'd':
299: if (layoutEngineFileName != null)
300: outFileName = layoutEngineFileName;
301: else {
302: outFileName = fileNameSansExtension + ".sgml";
303: if (outFileName.equals(fileName))
304: outFileName = fileNameSansExtension + "_out.sgml";
305: }
306: out = new PrintWriter(new FileWriter(outFileName));
307: le = new DocBookLE(out);
308: break;
309: case 'f':
310: if (layoutEngineFileName != null)
311: outFileName = layoutEngineFileName;
312: else {
313: outFileName = fileNameSansExtension + ".pdf";
314: if (outFileName.equals(fileName))
315: outFileName = fileNameSansExtension + "_out.pdf";
316: }
317: OutputStream outStream = new FileOutputStream(outFileName);
318: le = new PDFLE(outStream);
319: break;
320: case 'h':
321: if (layoutEngineFileName != null)
322: outFileName = layoutEngineFileName;
323: else {
324: outFileName = fileNameSansExtension + ".html";
325: if (outFileName.equals(fileName))
326: outFileName = fileNameSansExtension + "_out.html";
327: }
328: out = new PrintWriter(new FileWriter(outFileName));
329: le = new HTMLLE(out);
330: break;
331:
332: case 't':
333: if (layoutEngineFileName != null)
334: outFileName = layoutEngineFileName;
335: else {
336: outFileName = fileNameSansExtension + ".html";
337: if (outFileName.equals(fileName))
338: outFileName = fileNameSansExtension + "_out.html";
339: }
340: out = new PrintWriter(new FileWriter(outFileName));
341: le = new CSSHTMLLE(out);
342: break;
343:
344: case 'l':
345: if (layoutEngineFileName != null)
346: outFileName = layoutEngineFileName;
347: else {
348: outFileName = fileNameSansExtension + ".tex";
349: if (outFileName.equals(fileName))
350: outFileName = fileNameSansExtension + "_out.tex";
351: }
352: out = new PrintWriter(new FileWriter(outFileName));
353: le = new LaTeXLE(out);
354: break;
355: case 'x':
356: if (layoutEngineFileName != null)
357: outFileName = layoutEngineFileName;
358: else {
359: outFileName = fileNameSansExtension + ".xml";
360: if (outFileName.equals(fileName))
361: outFileName = fileNameSansExtension + "_out.xml";
362: }
363: XMLWriter iout = new XMLWriter(new FileWriter(outFileName));
364: le = new XMLLE(iout);
365: break;
366: case 'E':
367: if (layoutEngineFileName != null)
368: outFileName = layoutEngineFileName;
369: else {
370: outFileName = fileNameSansExtension + ".xls";
371: if (outFileName.equals(fileName))
372: outFileName = fileNameSansExtension + "_out.xls";
373: }
374: OutputStream xlsStream = new FileOutputStream(outFileName);
375: le = new ExcelLE(xlsStream, false);
376: break;
377: case 'w':
378: le = new SwingLE() {
379: public void close() { // Override close() to possibly exit app
380: super .close();
381: swingLayoutEngineClosed();
382: }
383: };
384: break;
385: }
386: return le;
387: }
388:
389: /**
390: * We arrange this method to be called by a Swing layout engine when
391: * it closes. If appropriate, exit the app.
392: */
393: protected void swingLayoutEngineClosed() {
394: if (--numReports == 0)
395: System.exit(0);
396: }
397:
398: /**
399: * Use the options related to the data source defined in the report XML file.
400: */
401: protected void dataSourceFromOptions(Getopts g) {
402: if (g.hasOption('n')) { // No password/empty password
403: if (g.hasOption('p') || g.hasOption('e'))
404: usage(I18N.get("DataVision.n_and_p"));
405: dbPassword = "";
406: } else if (g.hasOption('p')) {
407: if (g.hasOption('n') || g.hasOption('e'))
408: usage(I18N.get("DataVision.n_and_p"));
409: dbPassword = g.option('p', null); // Grab password; default is null
410: } else if (g.hasOption('e')) {
411: if (g.hasOption('n') || g.hasOption('p'))
412: usage(I18N.get("DataVision.n_and_p"));
413: charSepFile = g.option('e');
414: sepChar = g.option('a', DEFAULT_CHARACTER_SEPARATOR)
415: .charAt(0);
416: }
417: }
418:
419: public String toString() {
420: return "DataVision [layoutEngineChoice=" + layoutEngineChoice
421: + ", dbPassword = " + dbPassword + ", paramXMLFile = "
422: + paramXMLFile + ", numReports = " + numReports
423: + ", usesGUI = " + usesGUI + ", charSepFile = "
424: + charSepFile + ", sepChar = " + sepChar + "]";
425: }
426:
427: /**
428: * Prints a usage message and an optional extra error message to System.err
429: * and exits.
430: *
431: * @param errMsg string to print; may be <code>null</code>
432: */
433: public static void usage(String errMsg) {
434: if (errMsg != null)
435: System.err.println(errMsg);
436: System.err.println(I18N.get("DataVision.usage"));
437:
438: System.exit(1);
439: }
440:
441: }
|