package com.onaro.util.jfc.grouping; import java.util.BitSet; /** * A summarizer that displays a collected set of values from two fields. * The format of the values that appear in the column is required to be: * values of field 1 delimited by a specific delimiter d followed by a field delimiter d' and then * followed by values of field 2 (delimited by the same delimiter d). The values of the second * field may end with another delimiter d''. * For example the following is a possible value when d=',' d'='(' d''=')' : x1, x2, x3 ( y1, y2) * This summarizer shows the collection of all the values from field 1 delimited * by the delimiter d, and a collection of all the values from field 2 delimited by d. The field 1 and * field 2 collections are displayed delimited with the delimiter d'. * At the end of the string the delimiter d'' is displayed. */ public class CollectTwoFieldsSummarizer implements Summarizer { /** * The column from which the value is copied and to which it is copied. */ private int column; /** * The delimiter used for separating the values from the same field. */ private String sameFieldDelimiter; /** * The delimiter used for separating the values from the different fields. */ private String fieldDelimiter; /** * The delimiter used at the end of the string, after all field 2 values. */ private String endingDelimiter; /** * Initialize the collector for the given column. * @param column the colloumn to collect its values * @param sameFieldDelimiter the delimiter used to separate the values from the same field * @param fieldDelimiter the delimiter used to separate the values from different fields * @param endingDelimiter the delimiter used at the end of the string, after all field 2 values */ public CollectTwoFieldsSummarizer(int column, String sameFieldDelimiter, String fieldDelimiter, String endingDelimiter) { this.column = column; this.sameFieldDelimiter = sameFieldDelimiter; this.fieldDelimiter = fieldDelimiter; this.endingDelimiter = endingDelimiter; } public void updateSummary(Node node) { int childCount = node.getChildCount(); if (childCount > 0) { CollectedValues values = new CollectedValues(); for (int child = 0 ; child < childCount; ++child) { Object childValue = node.getChild(child).getValueAt(column); if (childValue instanceof CollectedValues) { values.addAll((CollectedValues)childValue); } else { String value = (String) childValue; if (value != null && value.length() > 0 && !"-1".equals(value)) { //$NON-NLS-1$ BitSet val1 = new BitSet(20); int val2 = -1; String val1String; int fieldDelIndex = value.indexOf(fieldDelimiter); if (fieldDelIndex >= 0) { val1String = fieldDelIndex > 0 ? value.substring(0, fieldDelIndex-1) : null; val2 = Integer.parseInt(value.substring(fieldDelIndex+1, value.length()-1)); } else val1String = value; if (val1String != null) { int val1DelIndex; do { val1DelIndex = val1String.indexOf(sameFieldDelimiter); String val1Token = val1String.substring(0, val1DelIndex==-1 ? val1String.length() : val1DelIndex); if (val1Token.length() > 0) val1.set(Integer.parseInt(val1Token)); if (val1DelIndex!=-1) val1String = val1String.substring(val1DelIndex+1); } while (val1DelIndex!=-1); } values.add(val1, val2); } } } node.setValueAt(column, values); } } /** * An ordered set of values with a specialized string presentation. */ class CollectedValues { /** * Holds the set of values from the first field. */ BitSet firstValues = new BitSet(20); /** * Holds the set o values from the second field. */ BitSet secondValues = new BitSet(20); /** * The string presentation, initialized lazily when needed and destroyed * whenever the value changes. */ String description; /** * Add all the values in the collection of values of a descendant node. * @param c the collected values of a descendant node */ public void addAll(CollectedValues c) { description = null; firstValues.or(c.firstValues); secondValues.or(c.secondValues); } /** * Adds a value to this collection. * @param val1 a set of values from the first field * @param val2 a vslue from the second field */ public void add(BitSet val1, int val2) { description = null; firstValues.or(val1); if (val2 >=0) secondValues.set(val2); } /** * Gets the string presentation of the value as a * delimited list of values. The value is kept for next calls as long as the * set of values didn't change. * @return a delimited list of values */ public String toString() { if (description == null) { StringBuilder sb = new StringBuilder(); for (int i=0; i < firstValues.length(); i++) { if (firstValues.get(i)) { sb.append(i); if (i < firstValues.length()-1) sb.append(sameFieldDelimiter); } } if (secondValues.length() > 0) { sb.append(' ').append(fieldDelimiter); for (int i=0; i < secondValues.length(); i++) { if (secondValues.get(i)) { sb.append(i); if (i < secondValues.length()-1) sb.append(sameFieldDelimiter); } } sb.append(endingDelimiter); } description = sb.toString(); } return description; } } }