001: package jimm.datavision.layout;
002:
003: import jimm.datavision.*;
004: import jimm.datavision.field.Field;
005: import jimm.datavision.field.ImageField;
006: import java.io.PrintWriter;
007: import java.util.*;
008:
009: /**
010: * A sorted layout engine outputs the fields within each section in order
011: * of their y then x coordinates. Another way of putting it: the fields are
012: * sorted top to bottom, then left to right. This ensures, for example,
013: * that character-based layout engines such as <code>CharSepLE</code> and
014: * <code>HTMLLE</code> will display fields in the correct left-to-right
015: * order.
016: *
017: * @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
018: */
019: public abstract class SortedLayoutEngine extends LayoutEngine {
020:
021: protected HashMap sectionFields;
022: protected Comparator comp;
023:
024: /**
025: * Constructor.
026: */
027: public SortedLayoutEngine() {
028: this (null);
029: }
030:
031: /**
032: * Constructor.
033: *
034: * @param out output print writer
035: */
036: public SortedLayoutEngine(PrintWriter out) {
037: super (out);
038: sectionFields = new HashMap();
039:
040: // Sorts fields by their y coordinates, then their x coordinates.
041: comp = new Comparator() {
042: public int compare(Object o1, Object o2) {
043: double y1 = ((Field) o1).getBounds().y;
044: double y2 = ((Field) o2).getBounds().y;
045: if (y1 == y2) {
046: double x1 = ((Field) o1).getBounds().x;
047: double x2 = ((Field) o2).getBounds().x;
048: return (x1 < x2) ? -1 : ((x1 > x2) ? 1 : 0);
049: } else
050: return (y1 < y2) ? -1 : ((y1 > y2) ? 1 : 0);
051: }
052: };
053: }
054:
055: /**
056: * This override iterates over a list of fields that have been sorted
057: * by their y and x coordinates. Put another way, the fields are output
058: * top to bottom, left to right.
059: *
060: * @param sect a section
061: */
062: protected void doOutputSection(Section sect) {
063: Object[] fields = (Object[]) sectionFields.get(sect);
064: if (fields == null)
065: fields = buildSectionFields(sect);
066:
067: if (fields != null) {
068: // Output the fields in the section
069: for (int i = 0; i < fields.length; ++i) {
070: Field f = (Field) fields[i];
071: if (f.isVisible()) {
072: if (f instanceof ImageField)
073: outputImage((ImageField) f);
074: else
075: outputField(f);
076: }
077: }
078: }
079: // Output the lines
080: for (Iterator iter = sect.lines(); iter.hasNext();) {
081: Line l = (Line) iter.next();
082: if (l.isVisible())
083: outputLine(l);
084: }
085: }
086:
087: /**
088: * Creates, saves, and returns an array of fields sorted by their y and x
089: * coordinates (y first, then x). Another way of putting it: the fields are
090: * sorted top to bottom, then left to right.
091: *
092: * @param sect a report section
093: * @return a sorted array of fields
094: */
095: protected Object[] buildSectionFields(Section sect) {
096: int numFields = sect.numFields();
097: if (numFields == 0)
098: return null;
099:
100: Object[] fields = sect.fieldsSortedBy(comp);
101: sectionFields.put(sect, fields);
102:
103: return fields;
104: }
105:
106: }
|