Reorganized the code into new packages.

This commit is contained in:
Jonathan Bernard 2011-10-27 20:14:08 -05:00
parent 652cc8703a
commit d076b739f5
20 changed files with 533 additions and 454 deletions

View File

@ -1,5 +0,0 @@
package com.jdbernard.timeanalyzer;
public interface CategoryFilter {
public boolean matchesEvent(Event event);
}

View File

@ -1,33 +1,50 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.categories
import com.jdbernard.timeanalyzer.events.Event
import org.joda.time.Duration import org.joda.time.Duration
/** /**
* A category represents a collection of like events. * A `Category` represents a collection of like `Events` and sub-categories.
*/ */
public abstract class Category implements Comparable<Category> { public abstract class Category implements Comparable<Category> {
/** List of events directly under this category. */
public List events public List events
/** List of sub-categories under this category. */
public List categories public List categories
/** List of `CategorizationPlan`s to use when adding new `Event`s to the
* category. */
public List categorizationPlans public List categorizationPlans
/** A end-user-friendly text description of the category.*/
public String description public String description
public Category() { public Category() {
events = [] events = []
categories = [] categories = []
categorizationPlans = [] categorizationPlans = []
description = "Unnamed Category" description = "Unnamed Category" }
}
public Category(String description) { public Category(String description) {
events = [] events = []
categories = [] categories = []
categorizationPlans = [] categorizationPlans = []
this.description = description this.description = description }
}
/**
* Does the given event belong in this category?
* @param e `Event` being considered.
* @return **`true`** if this event belongs in this category, **`false`**
* otherwise.
*/
public abstract boolean matchesEvent(Event e) public abstract boolean matchesEvent(Event e)
/**
* Add an event to this category. This method does not check to see if the
* `Event` matches this category. It assumed that the check has already been
* made and the `Event` matches.*/
public Event addEvent(Event event) { public Event addEvent(Event event) {
// see if we have or can create a subcategory that will hold this event // see if we have or can create a subcategory that will hold this event
@ -36,24 +53,22 @@ public abstract class Category implements Comparable<Category> {
// no, let's just add it on ourself // no, let's just add it on ourself
if (!addedEvent) { if (!addedEvent) {
events << event events << event
addedEvent = event addedEvent = event }
}
return addedEvent return addedEvent }
}
public Event addToSubcategory(Event e) { public Event addToSubcategory(Event e) {
// find all matching subcategories // find all matching subcategories
def matchingCategories = categories.findAll { it.matchesEvent(e) } def matchingCategories = categories.findAll { it.matchesEvent(e) }
if (matchingCategories) if (matchingCategories) {
return matchingCategories[0].addEvent(e) return matchingCategories[0].addEvent(e) }
// no matching subcategories, can we create a new one based on one // no matching subcategories, can we create a new one based on one
// of our plans? // of our plans?
def matchingPlans = categorizationPlans.findAll def matchingPlans = categorizationPlans.findAll {
{ it.deservesNewCategory(e, events) } it.deservesNewCategory(e, events) }
if (matchingPlans) { if (matchingPlans) {
// create the new category // create the new category
@ -71,11 +86,9 @@ public abstract class Category implements Comparable<Category> {
existingEvents.each { newCategory.addEvent(it) } existingEvents.each { newCategory.addEvent(it) }
// return the new entry // return the new entry
return addedEvent return addedEvent }
}
return null return null }
}
public Category filter(List<CategoryFilter> filters) { public Category filter(List<CategoryFilter> filters) {
@ -95,12 +108,10 @@ public abstract class Category implements Comparable<Category> {
public Duration getDuration() { public Duration getDuration() {
return categories.sum(new Duration(0)) { it.duration } + return categories.sum(new Duration(0)) { it.duration } +
events.sum(new Duration(0)) { it.duration } events.sum(new Duration(0)) { it.duration } }
}
public int compareTo(Category other) { public int compareTo(Category other) {
return this.getDuration().compareTo(other.getDuration()) return this.getDuration().compareTo(other.getDuration()) }
}
public String toString() { return description } public String toString() { return description }

View File

@ -0,0 +1,7 @@
package com.jdbernard.timeanalyzer.categories;
import com.jdbernard.timeanalyzer.events.Event;
public interface CategoryFilter {
public boolean matchesEvent(Event event);
}

View File

@ -1,17 +1,15 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.categories
import org.joda.time.Duration import com.jdbernard.timeanalyzer.events.Event
public class DescriptionBasedCategory extends Category { public class DescriptionBasedCategory extends Category {
public DescriptionBasedCategory(String description) { public DescriptionBasedCategory(String description) {
super() super()
this.description = description.replaceAll(/\p{Punct}/, '') this.description = description.replaceAll(/\p{Punct}/, '') }
}
public boolean matchesEvent(Event e) { public boolean matchesEvent(Event e) {
return e.description.replaceAll(/\p{Punct}/, '').toLowerCase() == return e.description.replaceAll(/\p{Punct}/, '').toLowerCase() ==
description.toLowerCase() description.toLowerCase() }
}
} }

View File

@ -1,15 +1,15 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.categories
public class FilteredCategory extends Category{ import com.jdbernard.timeanalyzer.events.Event
public class FilteredCategory extends Category {
List<CategoryFilter> filters = [] List<CategoryFilter> filters = []
public FilteredCategory(String description) { public FilteredCategory(String description) {
super(description) super(description) }
}
public boolean matchesEvent(Event e) { public boolean matchesEvent(Event e) {
return filters.every { filter -> filter.matchesEvent(e) } return filters.every { filter -> filter.matchesEvent(e) } }
}
} }

View File

@ -1,4 +1,6 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.categories
import com.jdbernard.timeanalyzer.events.Event
public class GeneralCategory extends Category { public class GeneralCategory extends Category {

View File

@ -0,0 +1,18 @@
package com.jdbernard.timeanalyzer.categories
import com.jdbernard.timeanalyzer.events.Event
import org.joda.time.Interval
public class TimeIntervalCategory extends Category {
private final Interval interval
public TimeIntervalCategory(String desc, Interval interval) {
super(desc)
this.interval = interval }
public boolean matchesEvent(Event e) {
Interval eventIv = new Interval(e.start, e.duration)
return interval.contains(eventIv) }
}

View File

@ -1,4 +1,6 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.categories
import com.jdbernard.timeanalyzer.events.Event
import org.joda.time.Interval import org.joda.time.Interval
import org.joda.time.ReadableInstant import org.joda.time.ReadableInstant

View File

@ -1,4 +1,6 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.categories
import com.jdbernard.timeanalyzer.events.Event
public class TwoLevelCategory extends Category { public class TwoLevelCategory extends Category {
@ -7,18 +9,15 @@ public class TwoLevelCategory extends Category {
public TwoLevelCategory(String heading) { public TwoLevelCategory(String heading) {
super(heading) super(heading)
descriptionPattern = ~/^${heading}:\s*(.*)/ descriptionPattern = ~/^${heading}:\s*(.*)/ }
}
public boolean matchesEvent(Event e) { public boolean matchesEvent(Event e) {
return e.description ==~ descriptionPattern return e.description ==~ descriptionPattern }
}
public Event addEvent(Event e) { public Event addEvent(Event e) {
def m = e.description =~ descriptionPattern def m = e.description =~ descriptionPattern
e = new Event(e, description: m[0][1]) e = new Event(e, description: m[0][1])
super.addEvent(e) super.addEvent(e) }
}
} }

View File

@ -1,4 +1,7 @@
package com.jdbernard.timeanalyzer; package com.jdbernard.timeanalyzer.categorizationplans;
import com.jdbernard.timeanalyzer.categories.Category;
import com.jdbernard.timeanalyzer.events.Event;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;

View File

@ -0,0 +1,35 @@
package com.jdbernard.timeanalyzer.categorizationplans;
import com.jdbernard.timeanalyzer.categories.Category
import com.jdbernard.timeanalyzer.events.Event
import org.joda.time.DateTime
import org.joda.time.Interval
import org.joda.time.Period
public class DailyCategorizationPlan {
boolean deservesNewCategory(Event event, List<Event> existingEvents) {
Interval fullday = new Interval(
event.start.toDateMidnight(), Period.days(1))
Interval eventIv = new Interval(
event.start, event.duration)
return fullDay.contains(eventIv) }
Category newCategory(Event event, List<Event> existingEvents) {
Interval fullday = new Interval(
event.start.toDateMidnight(), Period.days(1))
return TimeIntervalCategory(
event.start.toString("EEE, MMM dd", fullday)) }
List<Event> findEventsToRecategorize(Event event,
List<Event> existingEvents) {
Interval fullday = new Interval(
event.start.toDateMidnight(), Period.days(1))
return existingEvents.findAll {
Interval iv = new Interval(it.start, it.duration)
fullday.contains(iv) } }
}

View File

@ -1,4 +1,8 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.categorizationplans
import com.jdbernard.timeanalyzer.categories.Category
import com.jdbernard.timeanalyzer.categories.DescriptionBasedCategory
import com.jdbernard.timeanalyzer.events.Event
public class DescriptionBasedCategorizationPlan implements CategorizationPlan { public class DescriptionBasedCategorizationPlan implements CategorizationPlan {

View File

@ -1,4 +1,8 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.categorizationplans
import com.jdbernard.timeanalyzer.categories.Category
import com.jdbernard.timeanalyzer.categories.TwoLevelCategory
import com.jdbernard.timeanalyzer.events.Event
public class TwoLevelCategorizationPlan implements CategorizationPlan { public class TwoLevelCategorizationPlan implements CategorizationPlan {

View File

@ -1,6 +1,6 @@
package com.jdbernard.timeanalyzer.chart package com.jdbernard.timeanalyzer.chart
import com.jdbernard.timeanalyzer.Category import com.jdbernard.timeanalyzer.categories.Category
import org.jfree.data.general.DefaultPieDataset import org.jfree.data.general.DefaultPieDataset
import org.jfree.data.general.PieDataset import org.jfree.data.general.PieDataset
import org.jfree.util.SortOrder import org.jfree.util.SortOrder

View File

@ -1,6 +1,6 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.events
import org.joda.time.DateTime import org.joda.time.ReadableDateTime
import org.joda.time.Duration import org.joda.time.Duration
import org.joda.time.format.PeriodFormat import org.joda.time.format.PeriodFormat
import org.joda.time.format.PeriodFormatter import org.joda.time.format.PeriodFormatter
@ -9,13 +9,13 @@ public class Event implements Cloneable {
public final String description public final String description
public final String notes public final String notes
public final DateTime start public final ReadableDateTime start
public Duration duration // bit of a hack, allows modification for the public Duration duration // bit of a hack, allows modification for the
// TimelineEventProcessor // TimelineEventProcessor
public static PeriodFormatter periodFormatter = PeriodFormat.getDefault() public static PeriodFormatter periodFormatter = PeriodFormat.getDefault()
public Event(String desc, String notes, DateTime start, Duration duration) { public Event(String desc, String notes, ReadableDateTime start, Duration duration) {
this.description = desc this.description = desc
this.notes = notes this.notes = notes
this.start = start this.start = start

View File

@ -1,5 +1,6 @@
package com.jdbernard.timeanalyzer package com.jdbernard.timeanalyzer.processors
import com.jdbernard.timeanalyzer.events.Event
import com.jdbernard.timestamper.core.Timeline import com.jdbernard.timestamper.core.Timeline
import org.joda.time.DateTime import org.joda.time.DateTime
import org.joda.time.Duration import org.joda.time.Duration

View File

@ -1,8 +1,8 @@
package com.quantumdigital.ithelp.timeanalyzer package com.quantumdigital.ithelp.timeanalyzer
import com.jdbernard.timeanalyzer.Category import com.jdbernard.timeanalyzer.categories.Category
import com.jdbernard.timeanalyzer.CategorizationPlan import com.jdbernard.timeanalyzer.categorizationplans.CategorizationPlan
import com.jdbernard.timeanalyzer.Event import com.jdbernard.timeanalyzer.events.Event
public class TicketCategorizationPlan implements CategorizationPlan { public class TicketCategorizationPlan implements CategorizationPlan {

View File

@ -1,7 +1,7 @@
package com.quantumdigital.ithelp.timeanalyzer package com.quantumdigital.ithelp.timeanalyzer
import com.jdbernard.timeanalyzer.Category import com.jdbernard.timeanalyzer.categories.Category
import com.jdbernard.timeanalyzer.Event import com.jdbernard.timeanalyzer.events.Event
public class TicketCategory extends Category { public class TicketCategory extends Category {

View File

@ -1,6 +1,6 @@
package com.quantumdigital.ithelp.timeanalyzer package com.quantumdigital.ithelp.timeanalyzer
import com.jdbernard.timeanalyzer.Event import com.jdbernard.timeanalyzer.events.Event
public class TicketEvent extends Event { public class TicketEvent extends Event {

View File

@ -18,7 +18,7 @@ events = tep.process(timeline)
topcat = new FilteredCategory("Top Category") topcat = new FilteredCategory("Top Category")
topcat.filters << new TimeIntervalCategoryFilter( topcat.filters << new TimeIntervalCategoryFilter(
new DateTime(2011, 1, 2, 0, 0, 0, 0), new DateTime(2011, 1, 9, 0, 0, 0, 0)) new DateTime(2011, 1, 24, 0, 0, 0, 0), new DateTime(2011, 1, 25, 0, 0, 0, 0))
twoLevelCatPlan = new TwoLevelCategorizationPlan() twoLevelCatPlan = new TwoLevelCategorizationPlan()
descriptionBasedCatPlan = new DescriptionBasedCategorizationPlan() descriptionBasedCatPlan = new DescriptionBasedCategorizationPlan()