All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.publicobject.issuesbrowser.OpenIssuesByMonthCategoryDataset Maven / Gradle / Ivy

The newest version!
/* Glazed Lists                                                 (c) 2003-2006 */
/* http://publicobject.com/glazedlists/                      publicobject.com,*/
/*                                                     O'Dell Engineering Ltd.*/
package com.publicobject.issuesbrowser;

import ca.odell.glazedlists.*;
import ca.odell.glazedlists.jfreechart.EventListCategoryDataset;
import ca.odell.glazedlists.jfreechart.ValueSegment;
import ca.odell.glazedlists.matchers.Matcher;
import ca.odell.glazedlists.swing.GlazedListsSwing;

import java.util.Date;
import java.util.List;

/**
 * This CategoryDataset explodes each {@link Issue} object into a List of
 * {@link ValueSegment}s describing its status changes over time.
 *
 * 

It extracts the unique set of statuses across all {@link Issue}s as the * row keys. * *

It creates {@link ValueSegment}s as the column keys with the start and * end values representing the beginning and ending of each month the project * has been active. This has the effect of producing monthly counts of * statuses. * * @author James Lemieux */ public class OpenIssuesByMonthCategoryDataset extends EventListCategoryDataset { /** serialVersionUID. */ private static final long serialVersionUID = 0L; /** The sequencer which produces the uniform column keys. */ private final SequenceList.Sequencer monthSequencer = Sequencers.monthSequencer(); /** The raw, untransformed column keys presented by this dataset. */ private EventList rawColumnKeys; /** * Create a CategoryDataset by exploding the {@link Issue} objects into a * giant list of {@link ValueSegment} objects, each of which describes a * time segment during which the Issue held a given status. * * @param issues the source list of {@link Issue} objects */ public OpenIssuesByMonthCategoryDataset(EventList issues) { this(issues, new CollectionList<>(issues, new StateChangesCollectionModel())); } private OpenIssuesByMonthCategoryDataset(EventList issues, CollectionList> valueSegments) { // filter away ValueSegments whose value represents a retired issue (RESOLVED or CLOSED) this(new FilterList<>(valueSegments, new OpenIssuesMatcher(new StatusProvider(issues)))); } private OpenIssuesByMonthCategoryDataset(FilterList> filteredValueSegments) { // ensure all changes are delivered on the EDT to this Category Dataset, // since we're displaying the chart on a Swing component super(GlazedListsSwing.swingThreadProxyList(filteredValueSegments)); } /** * This data set uses a pipeline of Glazed Lists to create its column keys. * It wraps a raw BasicEventList in a SequenceList in order to generate a * sequence of column keys which span the data. It then uses a RangleList * to chop off the last value since it is beyond any of the data values to * be shown in the chart. */ @Override protected List createColumnKeyList() { this.rawColumnKeys = new BasicEventList(); // summarize all Dates added to rawColumnKeys using a Sequence of normalized month Dates final SequenceList columnKeySequenceList = new SequenceList(this.rawColumnKeys, Sequencers.monthSequencer()); // chop off the last element of the sequence list final RangeList columnKeyList = new RangeList(columnKeySequenceList); columnKeyList.setMiddleRange(0, 1); return columnKeyList; } /** @inheritDoc */ @Override public Number getValue(Comparable rowKey, Comparable columnKey) { // the columnKey is expected to be a Date final Date start = (Date) columnKey; final Date end = this.monthSequencer.next(start); return new Integer(this.getCount((String) rowKey, start, end)); } /** * An ultra-fast method to determine if the given list * contains the given value. Precise identity is tested for * speed reasons, and no Iterator is used because the data is always * accessed from the Swing EDT. * * @return true if l contains value; * false otherwise */ private boolean contains(List l, Object value) { for (int i = 0, n = l.size(); i < n; i++) if (value == l.get(i)) return true; return false; } /** * When a new {@link ValueSegment} is inserted we process the insertion by * determining if: * *

    *
  • the segment contains a new status not currently reported by the * list of row keys *
  • the segment is for a time range not currently reported by the * list of column keys *
* * and adjust the row keys and column keys accordingly. * * @param segment the {@link ValueSegment} that was added to the Dataset */ @Override protected void postInsert(ValueSegment segment) { final String value = segment.getValue(); // if the rowkey is not found, add it final List rowKeys = getRowKeys(); if (!contains(rowKeys, value)) rowKeys.add(value); rawColumnKeys.add(segment.getStart()); rawColumnKeys.add(segment.getEnd()); } /** * When an existing {@link ValueSegment} is removed we process the deletion * by determining if: * *
    *
  • it was the last segment with its status and thus we should remove * that status from the list of row keys *
* * and adjust the row keys accordingly. * * @param segment the {@link ValueSegment} that was added to the Dataset */ @Override protected void postDelete(ValueSegment segment) { final String value = segment.getValue(); // if no more data is associated to the row, remove its rowkey if (getCount(value) == 0) getRowKeys().remove(value); rawColumnKeys.remove(segment.getStart()); rawColumnKeys.remove(segment.getEnd()); } /** * This Model decomposes Issues into a List of ValueSegment objects * describing the state changes and when they occurred during the * "lifetime" of the Issue. */ private static class StateChangesCollectionModel implements CollectionList.Model> { @Override public List> getChildren(Issue parent) { return parent.getStateChanges(); } } /** * This Matcher filters away RESOLVED, VERIFIED and CLOSED ValueSegment objects * since they do not represent an Issue in an open state. */ private static class OpenIssuesMatcher implements Matcher> { private StatusProvider statusProvider; public OpenIssuesMatcher(StatusProvider statusProvider) { this.statusProvider = statusProvider; } @Override public boolean matches(ValueSegment item) { final String value = item.getValue(); return statusProvider.statusFor(value).isActive(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy