Source Code Cross Referenced for CalloutEmitter.java in  » Report » pentaho-report » com » nwalsh » saxon » 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 » pentaho report » com.nwalsh.saxon 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package com.nwalsh.saxon;
002:
003:        import java.util.Stack;
004:        import java.util.StringTokenizer;
005:        import org.xml.sax.*;
006:        import org.w3c.dom.*;
007:        import javax.xml.transform.TransformerException;
008:        import com.icl.saxon.Controller;
009:        import com.icl.saxon.om.NamePool;
010:        import com.icl.saxon.output.Emitter;
011:        import com.icl.saxon.tree.AttributeCollection;
012:
013:        /**
014:         * <p>Saxon extension to decorate a result tree fragment with callouts.</p>
015:         *
016:         * <p>$Id: CalloutEmitter.java,v 1.1 2006/05/31 17:21:21 mbatchelor Exp $</p>
017:         *
018:         * <p>Copyright (C) 2000 Norman Walsh.</p>
019:         *
020:         * <p>This class provides the guts of a
021:         * <a href="http://users.iclway.co.uk/mhkay/saxon/">Saxon 6.*</a>
022:         * implementation of callouts for verbatim environments. (It is used
023:         * by the Verbatim class.)</p>
024:         *
025:         * <p>The general design is this: the stylesheets construct a result tree
026:         * fragment for some verbatim environment. The Verbatim class initializes
027:         * a CalloutEmitter with information about the callouts that should be applied
028:         * to the verbatim environment in question. Then the result tree fragment
029:         * is "replayed" through the CalloutEmitter; the CalloutEmitter builds a
030:         * new result tree fragment from this event stream, decorated with callouts,
031:         * and that is returned.</p>
032:         *
033:         * <p><b>Change Log:</b></p>
034:         * <dl>
035:         * <dt>1.0</dt>
036:         * <dd><p>Initial release.</p></dd>
037:         * </dl>
038:         *
039:         * @see Verbatim
040:         *
041:         * @author Norman Walsh
042:         * <a href="mailto:ndw@nwalsh.com">ndw@nwalsh.com</a>
043:         *
044:         * @version $Id: CalloutEmitter.java,v 1.1 2006/05/31 17:21:21 mbatchelor Exp $
045:         *
046:         */
047:        public class CalloutEmitter extends CopyEmitter {
048:            /** A stack for the preserving information about open elements. */
049:            protected Stack elementStack = null;
050:
051:            /** A stack for holding information about temporarily closed elements. */
052:            protected Stack tempStack = null;
053:
054:            /** Is the next element absolutely the first element in the fragment? */
055:            protected boolean firstElement = false;
056:
057:            /** The FO namespace name. */
058:            protected static String foURI = "http://www.w3.org/1999/XSL/Format";
059:
060:            /** The XHTML namespace name. */
061:            protected static String xhURI = "http://www.w3.org/1999/xhtml";
062:
063:            /** The default column for callouts that specify only a line. */
064:            protected int defaultColumn = 60;
065:
066:            /** Is the stylesheet currently running an FO stylesheet? */
067:            protected boolean foStylesheet = false;
068:
069:            /** The current line number. */
070:            private static int lineNumber = 0;
071:
072:            /** The current column number. */
073:            private static int colNumber = 0;
074:
075:            /** The (sorted) array of callouts obtained from the areaspec. */
076:            private static Callout callout[] = null;
077:
078:            /** The number of callouts in the callout array. */
079:            private static int calloutCount = 0;
080:
081:            /** A pointer used to keep track of our position in the callout array. */
082:            private static int calloutPos = 0;
083:
084:            /** The FormatCallout object to use for formatting callouts. */
085:            private static FormatCallout fCallout = null;
086:
087:            /** <p>Constructor for the CalloutEmitter.</p>
088:             *
089:             * @param namePool The name pool to use for constructing elements and attributes.
090:             * @param graphicsPath The path to callout number graphics.
091:             * @param graphicsExt The extension for callout number graphics.
092:             * @param graphicsMax The largest callout number that can be represented as a graphic.
093:             * @param defaultColumn The default column for callouts.
094:             * @param foStylesheet Is this an FO stylesheet?
095:             */
096:            public CalloutEmitter(Controller controller, NamePool namePool,
097:                    int defaultColumn, boolean foStylesheet,
098:                    FormatCallout fCallout) {
099:                super (controller, namePool);
100:                elementStack = new Stack();
101:                firstElement = true;
102:
103:                this .defaultColumn = defaultColumn;
104:                this .foStylesheet = foStylesheet;
105:                this .fCallout = fCallout;
106:            }
107:
108:            /**
109:             * <p>Examine the areaspec and determine the number and position of 
110:             * callouts.</p>
111:             *
112:             * <p>The <code><a href="http://docbook.org/tdg/html/areaspec.html">areaspecNodeSet</a></code>
113:             * is examined and a sorted list of the callouts is constructed.</p>
114:             *
115:             * <p>This data structure is used to augment the result tree fragment
116:             * with callout bullets.</p>
117:             *
118:             * @param areaspecNodeSet The source document &lt;areaspec&gt; element.
119:             *
120:             */
121:            public void setupCallouts(NodeList areaspecNodeList) {
122:                callout = new Callout[10];
123:                calloutCount = 0;
124:                calloutPos = 0;
125:                lineNumber = 1;
126:                colNumber = 1;
127:
128:                // First we walk through the areaspec to calculate the position
129:                // of the callouts
130:                //  <areaspec>
131:                //  <areaset id="ex.plco.const" coords="">
132:                //    <area id="ex.plco.c1" coords="4"/>
133:                //    <area id="ex.plco.c2" coords="8"/>
134:                //  </areaset>
135:                //  <area id="ex.plco.ret" coords="12"/>
136:                //  <area id="ex.plco.dest" coords="12"/>
137:                //  </areaspec>
138:                int pos = 0;
139:                int coNum = 0;
140:                boolean inAreaSet = false;
141:                Node areaspec = areaspecNodeList.item(0);
142:                NodeList children = areaspec.getChildNodes();
143:
144:                for (int count = 0; count < children.getLength(); count++) {
145:                    Node node = children.item(count);
146:                    if (node.getNodeType() == Node.ELEMENT_NODE) {
147:                        if (node.getNodeName().equalsIgnoreCase("areaset")) {
148:                            coNum++;
149:                            NodeList areas = node.getChildNodes();
150:                            for (int acount = 0; acount < areas.getLength(); acount++) {
151:                                Node area = areas.item(acount);
152:                                if (area.getNodeType() == Node.ELEMENT_NODE) {
153:                                    if (area.getNodeName().equalsIgnoreCase(
154:                                            "area")) {
155:                                        addCallout(coNum, area, defaultColumn);
156:                                    } else {
157:                                        System.out
158:                                                .println("Unexpected element in areaset: "
159:                                                        + area.getNodeName());
160:                                    }
161:                                }
162:                            }
163:                        } else if (node.getNodeName().equalsIgnoreCase("area")) {
164:                            coNum++;
165:                            addCallout(coNum, node, defaultColumn);
166:                        } else {
167:                            System.out
168:                                    .println("Unexpected element in areaspec: "
169:                                            + node.getNodeName());
170:                        }
171:                    }
172:                }
173:
174:                // Now sort them
175:                java.util.Arrays.sort(callout, 0, calloutCount);
176:            }
177:
178:            /** Process characters. */
179:            public void characters(char[] chars, int start, int len)
180:                    throws TransformerException {
181:
182:                // If we hit characters, then there's no first element...
183:                firstElement = false;
184:
185:                if (lineNumber == 0) {
186:                    // if there are any text nodes, there's at least one line
187:                    lineNumber++;
188:                    colNumber = 1;
189:                }
190:
191:                // Walk through the text node looking for callout positions
192:                char[] newChars = new char[len];
193:                int pos = 0;
194:                for (int count = start; count < start + len; count++) {
195:                    if (calloutPos < calloutCount
196:                            && callout[calloutPos].getLine() == lineNumber
197:                            && callout[calloutPos].getColumn() == colNumber) {
198:                        if (pos > 0) {
199:                            rtfEmitter.characters(newChars, 0, pos);
200:                            pos = 0;
201:                        }
202:
203:                        closeOpenElements(rtfEmitter);
204:
205:                        while (calloutPos < calloutCount
206:                                && callout[calloutPos].getLine() == lineNumber
207:                                && callout[calloutPos].getColumn() == colNumber) {
208:                            fCallout.formatCallout(rtfEmitter,
209:                                    callout[calloutPos]);
210:                            calloutPos++;
211:                        }
212:
213:                        openClosedElements(rtfEmitter);
214:                    }
215:
216:                    if (chars[count] == '\n') {
217:                        // What if we need to pad this line?
218:                        if (calloutPos < calloutCount
219:                                && callout[calloutPos].getLine() == lineNumber
220:                                && callout[calloutPos].getColumn() > colNumber) {
221:
222:                            if (pos > 0) {
223:                                rtfEmitter.characters(newChars, 0, pos);
224:                                pos = 0;
225:                            }
226:
227:                            closeOpenElements(rtfEmitter);
228:
229:                            while (calloutPos < calloutCount
230:                                    && callout[calloutPos].getLine() == lineNumber
231:                                    && callout[calloutPos].getColumn() > colNumber) {
232:                                formatPad(callout[calloutPos].getColumn()
233:                                        - colNumber);
234:                                colNumber = callout[calloutPos].getColumn();
235:                                while (calloutPos < calloutCount
236:                                        && callout[calloutPos].getLine() == lineNumber
237:                                        && callout[calloutPos].getColumn() == colNumber) {
238:                                    fCallout.formatCallout(rtfEmitter,
239:                                            callout[calloutPos]);
240:                                    calloutPos++;
241:                                }
242:                            }
243:
244:                            openClosedElements(rtfEmitter);
245:                        }
246:
247:                        lineNumber++;
248:                        colNumber = 1;
249:                    } else {
250:                        colNumber++;
251:                    }
252:                    newChars[pos++] = chars[count];
253:                }
254:
255:                if (pos > 0) {
256:                    rtfEmitter.characters(newChars, 0, pos);
257:                }
258:            }
259:
260:            /**
261:             * <p>Add blanks to the result tree fragment.</p>
262:             *
263:             * <p>This method adds <tt>numBlanks</tt> to the result tree fragment.
264:             * It's used to pad lines when callouts occur after the last existing
265:             * characater in a line.</p>
266:             *
267:             * @param numBlanks The number of blanks to add.
268:             */
269:            protected void formatPad(int numBlanks) {
270:                char chars[] = new char[numBlanks];
271:                for (int count = 0; count < numBlanks; count++) {
272:                    chars[count] = ' ';
273:                }
274:
275:                try {
276:                    rtfEmitter.characters(chars, 0, numBlanks);
277:                } catch (TransformerException e) {
278:                    System.out.println("Transformer Exception in formatPad");
279:                }
280:            }
281:
282:            /**
283:             * <p>Add a callout to the global callout array</p>
284:             *
285:             * <p>This method examines a callout <tt>area</tt> and adds it to
286:             * the global callout array if it can be interpreted.</p>
287:             *
288:             * <p>Only the <tt>linecolumn</tt> and <tt>linerange</tt> units are
289:             * supported. If no unit is specifed, <tt>linecolumn</tt> is assumed.
290:             * If only a line is specified, the callout decoration appears in
291:             * the <tt>defaultColumn</tt>.</p>
292:             *
293:             * @param coNum The callout number.
294:             * @param node The <tt>area</tt>.
295:             * @param defaultColumn The default column for callouts.
296:             */
297:            protected void addCallout(int coNum, Node node, int defaultColumn) {
298:
299:                Element area = (Element) node;
300:                String units = null;
301:                String coords = null;
302:
303:                if (area.hasAttribute("units")) {
304:                    units = area.getAttribute("units");
305:                }
306:
307:                if (area.hasAttribute("coords")) {
308:                    coords = area.getAttribute("coords");
309:                }
310:
311:                if (units != null && !units.equalsIgnoreCase("linecolumn")
312:                        && !units.equalsIgnoreCase("linerange")) {
313:                    System.out
314:                            .println("Only linecolumn and linerange units are supported");
315:                    return;
316:                }
317:
318:                if (coords == null) {
319:                    System.out.println("Coords must be specified");
320:                    return;
321:                }
322:
323:                // Now let's see if we can interpret the coordinates...
324:                StringTokenizer st = new StringTokenizer(coords);
325:                int tokenCount = 0;
326:                int c1 = 0;
327:                int c2 = 0;
328:                while (st.hasMoreTokens()) {
329:                    tokenCount++;
330:                    if (tokenCount > 2) {
331:                        System.out.println("Unparseable coordinates");
332:                        return;
333:                    }
334:                    try {
335:                        String token = st.nextToken();
336:                        int coord = Integer.parseInt(token);
337:                        c2 = coord;
338:                        if (tokenCount == 1) {
339:                            c1 = coord;
340:                        }
341:                    } catch (NumberFormatException e) {
342:                        System.out.println("Unparseable coordinate");
343:                        return;
344:                    }
345:                }
346:
347:                // Make sure we aren't going to blow past the end of our array
348:                if (calloutCount == callout.length) {
349:                    Callout bigger[] = new Callout[calloutCount + 10];
350:                    for (int count = 0; count < callout.length; count++) {
351:                        bigger[count] = callout[count];
352:                    }
353:                    callout = bigger;
354:                }
355:
356:                // Ok, add the callout
357:                if (tokenCount == 2) {
358:                    if (units != null && units.equalsIgnoreCase("linerange")) {
359:                        for (int count = c1; count <= c2; count++) {
360:                            callout[calloutCount++] = new Callout(coNum, area,
361:                                    count, defaultColumn);
362:                        }
363:                    } else {
364:                        // assume linecolumn
365:                        callout[calloutCount++] = new Callout(coNum, area, c1,
366:                                c2);
367:                    }
368:                } else {
369:                    // if there's only one number, assume it's the line
370:                    callout[calloutCount++] = new Callout(coNum, area, c1,
371:                            defaultColumn);
372:                }
373:            }
374:
375:            /** Process end element events. */
376:            public void endElement(int nameCode) throws TransformerException {
377:
378:                if (!elementStack.empty()) {
379:                    // if we didn't push the very first element (an fo:block or
380:                    // pre or div surrounding the whole block), then the stack will
381:                    // be empty when we get to the end of the first element...
382:                    elementStack.pop();
383:                }
384:                rtfEmitter.endElement(nameCode);
385:            }
386:
387:            /** Process start element events. */
388:            public void startElement(int nameCode,
389:                    org.xml.sax.Attributes attributes, int[] namespaces,
390:                    int nscount) throws TransformerException {
391:
392:                if (!skipThisElement(nameCode)) {
393:                    StartElementInfo sei = new StartElementInfo(nameCode,
394:                            attributes, namespaces, nscount);
395:                    elementStack.push(sei);
396:                }
397:
398:                firstElement = false;
399:
400:                rtfEmitter.startElement(nameCode, attributes, namespaces,
401:                        nscount);
402:            }
403:
404:            /**
405:             * <p>Protect the outer-most block wrapper.</p>
406:             *
407:             * <p>Open elements in the result tree fragment are closed and reopened
408:             * around callouts (so that callouts don't appear inside links or other
409:             * environments). But if the result tree fragment is a single block
410:             * (a div or pre in HTML, an fo:block in FO), that outer-most block is
411:             * treated specially.</p>
412:             *
413:             * <p>This method returns true if the element in question is that
414:             * outermost block.</p>
415:             *
416:             * @param nameCode The name code for the element
417:             *
418:             * @return True if the element is the outer-most block, false otherwise.
419:             */
420:            protected boolean skipThisElement(int nameCode) {
421:                // FIXME: This is such a gross hack...
422:                if (firstElement) {
423:                    int this Fingerprint = namePool.getFingerprint(nameCode);
424:                    int foBlockFingerprint = namePool.getFingerprint(foURI,
425:                            "block");
426:                    int htmlPreFingerprint = namePool.getFingerprint("", "pre");
427:                    int htmlDivFingerprint = namePool.getFingerprint("", "div");
428:                    int xhtmlPreFingerprint = namePool.getFingerprint(xhURI,
429:                            "pre");
430:                    int xhtmlDivFingerprint = namePool.getFingerprint(xhURI,
431:                            "div");
432:
433:                    if ((foStylesheet && this Fingerprint == foBlockFingerprint)
434:                            || (!foStylesheet && (this Fingerprint == htmlPreFingerprint
435:                                    || this Fingerprint == htmlDivFingerprint
436:                                    || this Fingerprint == xhtmlPreFingerprint || this Fingerprint == xhtmlDivFingerprint))) {
437:                        // Don't push the outer-most wrapping div, pre, or fo:block
438:                        return true;
439:                    }
440:                }
441:
442:                return false;
443:            }
444:
445:            private void closeOpenElements(Emitter rtfEmitter)
446:                    throws TransformerException {
447:                // Close all the open elements...
448:                tempStack = new Stack();
449:                while (!elementStack.empty()) {
450:                    StartElementInfo elem = (StartElementInfo) elementStack
451:                            .pop();
452:                    rtfEmitter.endElement(elem.getNameCode());
453:                    tempStack.push(elem);
454:                }
455:            }
456:
457:            private void openClosedElements(Emitter rtfEmitter)
458:                    throws TransformerException {
459:                // Now "reopen" the elements that we closed...
460:                while (!tempStack.empty()) {
461:                    StartElementInfo elem = (StartElementInfo) tempStack.pop();
462:                    AttributeCollection attr = (AttributeCollection) elem
463:                            .getAttributes();
464:                    AttributeCollection newAttr = new AttributeCollection(
465:                            namePool);
466:
467:                    for (int acount = 0; acount < attr.getLength(); acount++) {
468:                        String localName = attr.getLocalName(acount);
469:                        int nameCode = attr.getNameCode(acount);
470:                        String type = attr.getType(acount);
471:                        String value = attr.getValue(acount);
472:                        String uri = attr.getURI(acount);
473:                        String prefix = "";
474:
475:                        if (localName.indexOf(':') > 0) {
476:                            prefix = localName.substring(0, localName
477:                                    .indexOf(':'));
478:                            localName = localName.substring(localName
479:                                    .indexOf(':') + 1);
480:                        }
481:
482:                        if (uri.equals("")
483:                                && ((foStylesheet && localName.equals("id")) || (!foStylesheet && (localName
484:                                        .equals("id") || localName
485:                                        .equals("name"))))) {
486:                            // skip this attribute
487:                        } else {
488:                            newAttr.addAttribute(prefix, uri, localName, type,
489:                                    value);
490:                        }
491:                    }
492:
493:                    rtfEmitter.startElement(elem.getNameCode(), newAttr, elem
494:                            .getNamespaces(), elem.getNSCount());
495:
496:                    elementStack.push(elem);
497:                }
498:            }
499:
500:            /**
501:             * <p>A private class for maintaining the information required to call
502:             * the startElement method.</p>
503:             *
504:             * <p>In order to close and reopen elements, information about those
505:             * elements has to be maintained. This class is just the little record
506:             * that we push on the stack to keep track of that info.</p>
507:             */
508:            private class StartElementInfo {
509:                private int _nameCode;
510:                org.xml.sax.Attributes _attributes;
511:                int[] _namespaces;
512:                int _nscount;
513:
514:                public StartElementInfo(int nameCode,
515:                        org.xml.sax.Attributes attributes, int[] namespaces,
516:                        int nscount) {
517:                    _nameCode = nameCode;
518:                    _attributes = attributes;
519:                    _namespaces = namespaces;
520:                    _nscount = nscount;
521:                }
522:
523:                public int getNameCode() {
524:                    return _nameCode;
525:                }
526:
527:                public org.xml.sax.Attributes getAttributes() {
528:                    return _attributes;
529:                }
530:
531:                public int[] getNamespaces() {
532:                    return _namespaces;
533:                }
534:
535:                public int getNSCount() {
536:                    return _nscount;
537:                }
538:            }
539:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.