diff --git a/src/main/com/jdbernard/timeanalyzer/CategoryFilter.java b/src/main/com/jdbernard/timeanalyzer/CategoryFilter.java deleted file mode 100644 index 33437b0..0000000 --- a/src/main/com/jdbernard/timeanalyzer/CategoryFilter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.jdbernard.timeanalyzer; - -public interface CategoryFilter { - public boolean matchesEvent(Event event); -} diff --git a/src/main/com/jdbernard/timeanalyzer/Category.groovy b/src/main/com/jdbernard/timeanalyzer/categories/Category.groovy similarity index 62% rename from src/main/com/jdbernard/timeanalyzer/Category.groovy rename to src/main/com/jdbernard/timeanalyzer/categories/Category.groovy index 97fda2e..e74660c 100644 --- a/src/main/com/jdbernard/timeanalyzer/Category.groovy +++ b/src/main/com/jdbernard/timeanalyzer/categories/Category.groovy @@ -1,107 +1,118 @@ -package com.jdbernard.timeanalyzer - -import org.joda.time.Duration - -/** - * A category represents a collection of like events. - */ -public abstract class Category implements Comparable { - - public List events - public List categories - public List categorizationPlans - public String description - - public Category() { - events = [] - categories = [] - categorizationPlans = [] - description = "Unnamed Category" - } - - public Category(String description) { - events = [] - categories = [] - categorizationPlans = [] - this.description = description - } - - public abstract boolean matchesEvent(Event e) - - public Event addEvent(Event event) { - - // see if we have or can create a subcategory that will hold this event - Event addedEvent = addToSubcategory(event) - - // no, let's just add it on ourself - if (!addedEvent) { - events << event - addedEvent = event - } - - return addedEvent - } - - public Event addToSubcategory(Event e) { - - // find all matching subcategories - def matchingCategories = categories.findAll { it.matchesEvent(e) } - - if (matchingCategories) - return matchingCategories[0].addEvent(e) - - // no matching subcategories, can we create a new one based on one - // of our plans? - def matchingPlans = categorizationPlans.findAll - { it.deservesNewCategory(e, events) } - - if (matchingPlans) { - // create the new category - def newCategory = matchingPlans[0].newCategory(e, events) - - // add it to our list of cateogries - categories << newCategory - - // add the new event to the category - def addedEvent = newCategory.addEvent(e) - - // move all the events that match the new category over - def existingEvents = matchingPlans[0].findEventsToRecategorize(e, events) - events -= existingEvents - existingEvents.each { newCategory.addEvent(it) } - - // return the new entry - return addedEvent - } - - return null - } - - public Category filter(List filters) { - - // create new filtered category - FilteredCategory fc = new FilteredCategory(description) - fc.filters = filters - - // filter all events and add them to the category - fc.events - - // TODO - } - - public Category filter(CategoryFilter filter) { return filter([filter]) } - - public Category filter(Closure c) { return filter(c as CategoryFilter) } - - public Duration getDuration() { - return categories.sum(new Duration(0)) { it.duration } + - events.sum(new Duration(0)) { it.duration } - } - - public int compareTo(Category other) { - return this.getDuration().compareTo(other.getDuration()) - } - - public String toString() { return description } - -} +package com.jdbernard.timeanalyzer.categories + +import com.jdbernard.timeanalyzer.events.Event +import org.joda.time.Duration + +/** + * A `Category` represents a collection of like `Events` and sub-categories. + */ +public abstract class Category implements Comparable { + + /** List of events directly under this category. */ + public List events + + /** List of sub-categories under this category. */ + public List categories + + /** List of `CategorizationPlan`s to use when adding new `Event`s to the + * category. */ + public List categorizationPlans + + /** A end-user-friendly text description of the category.*/ + public String description + + public Category() { + events = [] + categories = [] + categorizationPlans = [] + description = "Unnamed Category" } + + public Category(String description) { + events = [] + categories = [] + categorizationPlans = [] + 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) + + /** + * 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) { + + // see if we have or can create a subcategory that will hold this event + Event addedEvent = addToSubcategory(event) + + // no, let's just add it on ourself + if (!addedEvent) { + events << event + addedEvent = event } + + return addedEvent } + + public Event addToSubcategory(Event e) { + + // find all matching subcategories + def matchingCategories = categories.findAll { it.matchesEvent(e) } + + if (matchingCategories) { + return matchingCategories[0].addEvent(e) } + + // no matching subcategories, can we create a new one based on one + // of our plans? + def matchingPlans = categorizationPlans.findAll { + it.deservesNewCategory(e, events) } + + if (matchingPlans) { + // create the new category + def newCategory = matchingPlans[0].newCategory(e, events) + + // add it to our list of cateogries + categories << newCategory + + // add the new event to the category + def addedEvent = newCategory.addEvent(e) + + // move all the events that match the new category over + def existingEvents = matchingPlans[0].findEventsToRecategorize(e, events) + events -= existingEvents + existingEvents.each { newCategory.addEvent(it) } + + // return the new entry + return addedEvent } + + return null } + + public Category filter(List filters) { + + // create new filtered category + FilteredCategory fc = new FilteredCategory(description) + fc.filters = filters + + // filter all events and add them to the category + fc.events + + // TODO + } + + public Category filter(CategoryFilter filter) { return filter([filter]) } + + public Category filter(Closure c) { return filter(c as CategoryFilter) } + + public Duration getDuration() { + return categories.sum(new Duration(0)) { it.duration } + + events.sum(new Duration(0)) { it.duration } } + + public int compareTo(Category other) { + return this.getDuration().compareTo(other.getDuration()) } + + public String toString() { return description } + +} diff --git a/src/main/com/jdbernard/timeanalyzer/categories/CategoryFilter.java b/src/main/com/jdbernard/timeanalyzer/categories/CategoryFilter.java new file mode 100644 index 0000000..ae2da4f --- /dev/null +++ b/src/main/com/jdbernard/timeanalyzer/categories/CategoryFilter.java @@ -0,0 +1,7 @@ +package com.jdbernard.timeanalyzer.categories; + +import com.jdbernard.timeanalyzer.events.Event; + +public interface CategoryFilter { + public boolean matchesEvent(Event event); +} diff --git a/src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategory.groovy b/src/main/com/jdbernard/timeanalyzer/categories/DescriptionBasedCategory.groovy similarity index 67% rename from src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategory.groovy rename to src/main/com/jdbernard/timeanalyzer/categories/DescriptionBasedCategory.groovy index d161ee9..898cc88 100644 --- a/src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategory.groovy +++ b/src/main/com/jdbernard/timeanalyzer/categories/DescriptionBasedCategory.groovy @@ -1,17 +1,15 @@ -package com.jdbernard.timeanalyzer - -import org.joda.time.Duration - -public class DescriptionBasedCategory extends Category { - - public DescriptionBasedCategory(String description) { - super() - this.description = description.replaceAll(/\p{Punct}/, '') - } - - public boolean matchesEvent(Event e) { - return e.description.replaceAll(/\p{Punct}/, '').toLowerCase() == - description.toLowerCase() - } - -} +package com.jdbernard.timeanalyzer.categories + +import com.jdbernard.timeanalyzer.events.Event + +public class DescriptionBasedCategory extends Category { + + public DescriptionBasedCategory(String description) { + super() + this.description = description.replaceAll(/\p{Punct}/, '') } + + public boolean matchesEvent(Event e) { + return e.description.replaceAll(/\p{Punct}/, '').toLowerCase() == + description.toLowerCase() } + +} diff --git a/src/main/com/jdbernard/timeanalyzer/FilteredCategory.groovy b/src/main/com/jdbernard/timeanalyzer/categories/FilteredCategory.groovy similarity index 51% rename from src/main/com/jdbernard/timeanalyzer/FilteredCategory.groovy rename to src/main/com/jdbernard/timeanalyzer/categories/FilteredCategory.groovy index 4d34a2f..869cda2 100644 --- a/src/main/com/jdbernard/timeanalyzer/FilteredCategory.groovy +++ b/src/main/com/jdbernard/timeanalyzer/categories/FilteredCategory.groovy @@ -1,15 +1,15 @@ -package com.jdbernard.timeanalyzer - -public class FilteredCategory extends Category{ - - List filters = [] - - public FilteredCategory(String description) { - super(description) - } - - public boolean matchesEvent(Event e) { - return filters.every { filter -> filter.matchesEvent(e) } - } - -} +package com.jdbernard.timeanalyzer.categories + +import com.jdbernard.timeanalyzer.events.Event + +public class FilteredCategory extends Category { + + List filters = [] + + public FilteredCategory(String description) { + super(description) } + + public boolean matchesEvent(Event e) { + return filters.every { filter -> filter.matchesEvent(e) } } + +} diff --git a/src/main/com/jdbernard/timeanalyzer/GeneralCategory.groovy b/src/main/com/jdbernard/timeanalyzer/categories/GeneralCategory.groovy similarity index 69% rename from src/main/com/jdbernard/timeanalyzer/GeneralCategory.groovy rename to src/main/com/jdbernard/timeanalyzer/categories/GeneralCategory.groovy index 9b04512..bce3237 100644 --- a/src/main/com/jdbernard/timeanalyzer/GeneralCategory.groovy +++ b/src/main/com/jdbernard/timeanalyzer/categories/GeneralCategory.groovy @@ -1,15 +1,17 @@ -package com.jdbernard.timeanalyzer - -public class GeneralCategory extends Category { - - public GeneralCategory() { - this("General") - } - - public GeneralCategory(String description) { - super(description) - } - - public boolean matchesEvent(Event e) { true } - -} +package com.jdbernard.timeanalyzer.categories + +import com.jdbernard.timeanalyzer.events.Event + +public class GeneralCategory extends Category { + + public GeneralCategory() { + this("General") + } + + public GeneralCategory(String description) { + super(description) + } + + public boolean matchesEvent(Event e) { true } + +} diff --git a/src/main/com/jdbernard/timeanalyzer/categories/TimeIntervalCategory.groovy b/src/main/com/jdbernard/timeanalyzer/categories/TimeIntervalCategory.groovy new file mode 100644 index 0000000..b2dd7ab --- /dev/null +++ b/src/main/com/jdbernard/timeanalyzer/categories/TimeIntervalCategory.groovy @@ -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) } +} diff --git a/src/main/com/jdbernard/timeanalyzer/TimePeriodCategoryFilter.groovy b/src/main/com/jdbernard/timeanalyzer/categories/TimePeriodCategoryFilter.groovy similarity index 82% rename from src/main/com/jdbernard/timeanalyzer/TimePeriodCategoryFilter.groovy rename to src/main/com/jdbernard/timeanalyzer/categories/TimePeriodCategoryFilter.groovy index 32db59d..767d1d8 100644 --- a/src/main/com/jdbernard/timeanalyzer/TimePeriodCategoryFilter.groovy +++ b/src/main/com/jdbernard/timeanalyzer/categories/TimePeriodCategoryFilter.groovy @@ -1,23 +1,25 @@ -package com.jdbernard.timeanalyzer - -import org.joda.time.Interval -import org.joda.time.ReadableInstant -import org.joda.time.ReadableInterval - -public class TimeIntervalCategoryFilter implements CategoryFilter { - - ReadableInterval interval - - public TimeIntervalCategoryFilter(ReadableInterval interval) { - this.interval = interval - } - - public TimeIntervalCategoryFilter(ReadableInstant start, - ReadableInstant end) { - this.interval = new Interval(start, end) - } - - public boolean matchesEvent(Event event) { - return interval.contains(event.start) - } -} +package com.jdbernard.timeanalyzer.categories + +import com.jdbernard.timeanalyzer.events.Event + +import org.joda.time.Interval +import org.joda.time.ReadableInstant +import org.joda.time.ReadableInterval + +public class TimeIntervalCategoryFilter implements CategoryFilter { + + ReadableInterval interval + + public TimeIntervalCategoryFilter(ReadableInterval interval) { + this.interval = interval + } + + public TimeIntervalCategoryFilter(ReadableInstant start, + ReadableInstant end) { + this.interval = new Interval(start, end) + } + + public boolean matchesEvent(Event event) { + return interval.contains(event.start) + } +} diff --git a/src/main/com/jdbernard/timeanalyzer/TwoLevelCategory.groovy b/src/main/com/jdbernard/timeanalyzer/categories/TwoLevelCategory.groovy similarity index 57% rename from src/main/com/jdbernard/timeanalyzer/TwoLevelCategory.groovy rename to src/main/com/jdbernard/timeanalyzer/categories/TwoLevelCategory.groovy index 5c22953..5ccfe46 100644 --- a/src/main/com/jdbernard/timeanalyzer/TwoLevelCategory.groovy +++ b/src/main/com/jdbernard/timeanalyzer/categories/TwoLevelCategory.groovy @@ -1,24 +1,23 @@ -package com.jdbernard.timeanalyzer - -public class TwoLevelCategory extends Category { - - private final def descriptionPattern - - public TwoLevelCategory(String heading) { - super(heading) - - descriptionPattern = ~/^${heading}:\s*(.*)/ - } - - public boolean matchesEvent(Event e) { - return e.description ==~ descriptionPattern - } - - public Event addEvent(Event e) { - def m = e.description =~ descriptionPattern - - e = new Event(e, description: m[0][1]) - - super.addEvent(e) - } -} +package com.jdbernard.timeanalyzer.categories + +import com.jdbernard.timeanalyzer.events.Event + +public class TwoLevelCategory extends Category { + + private final def descriptionPattern + + public TwoLevelCategory(String heading) { + super(heading) + + descriptionPattern = ~/^${heading}:\s*(.*)/ } + + public boolean matchesEvent(Event e) { + return e.description ==~ descriptionPattern } + + public Event addEvent(Event e) { + def m = e.description =~ descriptionPattern + + e = new Event(e, description: m[0][1]) + + super.addEvent(e) } +} diff --git a/src/main/com/jdbernard/timeanalyzer/CategorizationPlan.java b/src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.java similarity index 64% rename from src/main/com/jdbernard/timeanalyzer/CategorizationPlan.java rename to src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.java index 898d7b6..351211d 100644 --- a/src/main/com/jdbernard/timeanalyzer/CategorizationPlan.java +++ b/src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.java @@ -1,10 +1,13 @@ -package com.jdbernard.timeanalyzer; - -import java.util.List; -import java.util.Map; - -public interface CategorizationPlan { - boolean deservesNewCategory(Event event, List existingEvents); - Category newCategory(Event event, List existingEvents); - List findEventsToRecategorize(Event event, List existingEvents); -} +package com.jdbernard.timeanalyzer.categorizationplans; + +import com.jdbernard.timeanalyzer.categories.Category; +import com.jdbernard.timeanalyzer.events.Event; + +import java.util.List; +import java.util.Map; + +public interface CategorizationPlan { + boolean deservesNewCategory(Event event, List existingEvents); + Category newCategory(Event event, List existingEvents); + List findEventsToRecategorize(Event event, List existingEvents); +} diff --git a/src/main/com/jdbernard/timeanalyzer/categorizationplans/DailyCategorizationPlan.groovy b/src/main/com/jdbernard/timeanalyzer/categorizationplans/DailyCategorizationPlan.groovy new file mode 100644 index 0000000..f4a10b5 --- /dev/null +++ b/src/main/com/jdbernard/timeanalyzer/categorizationplans/DailyCategorizationPlan.groovy @@ -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 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 existingEvents) { + Interval fullday = new Interval( + event.start.toDateMidnight(), Period.days(1)) + + return TimeIntervalCategory( + event.start.toString("EEE, MMM dd", fullday)) } + + List findEventsToRecategorize(Event event, + List 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) } } +} diff --git a/src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategorizationPlan.groovy b/src/main/com/jdbernard/timeanalyzer/categorizationplans/DescriptionBasedCategorizationPlan.groovy similarity index 76% rename from src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategorizationPlan.groovy rename to src/main/com/jdbernard/timeanalyzer/categorizationplans/DescriptionBasedCategorizationPlan.groovy index e43fa32..11bb7d6 100644 --- a/src/main/com/jdbernard/timeanalyzer/DescriptionBasedCategorizationPlan.groovy +++ b/src/main/com/jdbernard/timeanalyzer/categorizationplans/DescriptionBasedCategorizationPlan.groovy @@ -1,23 +1,27 @@ -package com.jdbernard.timeanalyzer - -public class DescriptionBasedCategorizationPlan implements CategorizationPlan { - - public boolean deservesNewCategory(Event event, List existingEvents) { - def desc = event.description.replaceAll(/\p{Punct}/, '').toLowerCase() - return existingEvents.any { - it.description.replaceAll(/\p{Punct}/, '').toLowerCase() == desc } - } - - public Category newCategory(Event event, - List existingEvents) { - return new DescriptionBasedCategory(event.description) - } - - public List findEventsToRecategorize(Event event, - List existingEvents) { - def desc = event.description.replaceAll(/\p{Punct}/, '').toLowerCase() - return existingEvents.findAll { - it.description.replaceAll(/\p{Punct}/, '').toLowerCase() == desc } - } - -} +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 boolean deservesNewCategory(Event event, List existingEvents) { + def desc = event.description.replaceAll(/\p{Punct}/, '').toLowerCase() + return existingEvents.any { + it.description.replaceAll(/\p{Punct}/, '').toLowerCase() == desc } + } + + public Category newCategory(Event event, + List existingEvents) { + return new DescriptionBasedCategory(event.description) + } + + public List findEventsToRecategorize(Event event, + List existingEvents) { + def desc = event.description.replaceAll(/\p{Punct}/, '').toLowerCase() + return existingEvents.findAll { + it.description.replaceAll(/\p{Punct}/, '').toLowerCase() == desc } + } + +} diff --git a/src/main/com/jdbernard/timeanalyzer/TwoLevelCategorizationPlan.groovy b/src/main/com/jdbernard/timeanalyzer/categorizationplans/TwoLevelCategorizationPlan.groovy similarity index 73% rename from src/main/com/jdbernard/timeanalyzer/TwoLevelCategorizationPlan.groovy rename to src/main/com/jdbernard/timeanalyzer/categorizationplans/TwoLevelCategorizationPlan.groovy index 92d230c..ee7b182 100644 --- a/src/main/com/jdbernard/timeanalyzer/TwoLevelCategorizationPlan.groovy +++ b/src/main/com/jdbernard/timeanalyzer/categorizationplans/TwoLevelCategorizationPlan.groovy @@ -1,21 +1,25 @@ -package com.jdbernard.timeanalyzer - -public class TwoLevelCategorizationPlan implements CategorizationPlan { - - private static final def TWO_LEVEL_PATTERN = ~/(.+?):(.*)/ - - public boolean deservesNewCategory(Event event, List el) { - return event ==~ TWO_LEVEL_PATTERN - } - - public Category newCategory(Event event, List el) { - def m = event.description =~ TWO_LEVEL_PATTERN - return new TwoLevelCategory(m[0][1]) - } - - public List findEventsToRecategorize(Event event, - List existingEvents) { - def m = event.description =~ TWO_LEVEL_PATTERN - return existingEvents.findAll { it.description ==~ /${m[0][1]}:.*/ } - } -} +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 { + + private static final def TWO_LEVEL_PATTERN = ~/(.+?):(.*)/ + + public boolean deservesNewCategory(Event event, List el) { + return event ==~ TWO_LEVEL_PATTERN + } + + public Category newCategory(Event event, List el) { + def m = event.description =~ TWO_LEVEL_PATTERN + return new TwoLevelCategory(m[0][1]) + } + + public List findEventsToRecategorize(Event event, + List existingEvents) { + def m = event.description =~ TWO_LEVEL_PATTERN + return existingEvents.findAll { it.description ==~ /${m[0][1]}:.*/ } + } +} diff --git a/src/main/com/jdbernard/timeanalyzer/chart/Util.groovy b/src/main/com/jdbernard/timeanalyzer/chart/Util.groovy index d10367e..5887706 100644 --- a/src/main/com/jdbernard/timeanalyzer/chart/Util.groovy +++ b/src/main/com/jdbernard/timeanalyzer/chart/Util.groovy @@ -1,16 +1,16 @@ -package com.jdbernard.timeanalyzer.chart - -import com.jdbernard.timeanalyzer.Category -import org.jfree.data.general.DefaultPieDataset -import org.jfree.data.general.PieDataset -import org.jfree.util.SortOrder - -public class Util { - - public static PieDataset makePieDataset(Category category) { - DefaultPieDataset dpds = new DefaultPieDataset() - - category.categories { subcat -> - dpds.setValue(subcat.description, subcat.duration.getMillis()) } - } -} +package com.jdbernard.timeanalyzer.chart + +import com.jdbernard.timeanalyzer.categories.Category +import org.jfree.data.general.DefaultPieDataset +import org.jfree.data.general.PieDataset +import org.jfree.util.SortOrder + +public class Util { + + public static PieDataset makePieDataset(Category category) { + DefaultPieDataset dpds = new DefaultPieDataset() + + category.categories { subcat -> + dpds.setValue(subcat.description, subcat.duration.getMillis()) } + } +} diff --git a/src/main/com/jdbernard/timeanalyzer/Event.groovy b/src/main/com/jdbernard/timeanalyzer/events/Event.groovy similarity index 81% rename from src/main/com/jdbernard/timeanalyzer/Event.groovy rename to src/main/com/jdbernard/timeanalyzer/events/Event.groovy index b6180d7..1aba147 100644 --- a/src/main/com/jdbernard/timeanalyzer/Event.groovy +++ b/src/main/com/jdbernard/timeanalyzer/events/Event.groovy @@ -1,41 +1,41 @@ -package com.jdbernard.timeanalyzer - -import org.joda.time.DateTime -import org.joda.time.Duration -import org.joda.time.format.PeriodFormat -import org.joda.time.format.PeriodFormatter - -public class Event implements Cloneable { - - public final String description - public final String notes - public final DateTime start - public Duration duration // bit of a hack, allows modification for the - // TimelineEventProcessor - - public static PeriodFormatter periodFormatter = PeriodFormat.getDefault() - - public Event(String desc, String notes, DateTime start, Duration duration) { - this.description = desc - this.notes = notes - this.start = start - this.duration = duration - } - - public Event(Map params) { - this.description = params.description ?: "" - this.notes = params.notes ?: "" - this.start = params.start - this.duration = params.duration - } - - public Event(Map params, Event e) { - this.description = params.description ?: e.description - this.notes = params.notes ?: e.notes - this.start = params.start ?: e.start - this.duration = params.duration ?: e.duration - } - - public String toString() { return description } - -} +package com.jdbernard.timeanalyzer.events + +import org.joda.time.ReadableDateTime +import org.joda.time.Duration +import org.joda.time.format.PeriodFormat +import org.joda.time.format.PeriodFormatter + +public class Event implements Cloneable { + + public final String description + public final String notes + public final ReadableDateTime start + public Duration duration // bit of a hack, allows modification for the + // TimelineEventProcessor + + public static PeriodFormatter periodFormatter = PeriodFormat.getDefault() + + public Event(String desc, String notes, ReadableDateTime start, Duration duration) { + this.description = desc + this.notes = notes + this.start = start + this.duration = duration + } + + public Event(Map params) { + this.description = params.description ?: "" + this.notes = params.notes ?: "" + this.start = params.start + this.duration = params.duration + } + + public Event(Map params, Event e) { + this.description = params.description ?: e.description + this.notes = params.notes ?: e.notes + this.start = params.start ?: e.start + this.duration = params.duration ?: e.duration + } + + public String toString() { return description } + +} diff --git a/src/main/com/jdbernard/timeanalyzer/TimelineEventProcessor.groovy b/src/main/com/jdbernard/timeanalyzer/processors/TimelineEventProcessor.groovy similarity index 89% rename from src/main/com/jdbernard/timeanalyzer/TimelineEventProcessor.groovy rename to src/main/com/jdbernard/timeanalyzer/processors/TimelineEventProcessor.groovy index f90159b..00ef70c 100644 --- a/src/main/com/jdbernard/timeanalyzer/TimelineEventProcessor.groovy +++ b/src/main/com/jdbernard/timeanalyzer/processors/TimelineEventProcessor.groovy @@ -1,45 +1,46 @@ -package com.jdbernard.timeanalyzer - -import com.jdbernard.timestamper.core.Timeline -import org.joda.time.DateTime -import org.joda.time.Duration - -public class TimelineEventProcessor { - - /** Events whose description matches one of these regex strings or - * patterns are ignored. */ - List exclusions = [] - - public TimelineEventProcessor() {} - - public TimelineEventProcessor(List exclusions) { - this.exclusions = exclusions - } - - public List process(Timeline timeline) { - List events = [] - - timeline.each { marker -> - Event e = new Event( - description: marker.mark, - notes: marker.notes, - start: new DateTime(marker.timestamp), - duration: new Duration(0)) - - // if this is not the first event, then we need to update the - // duration of the previous event - if (events.size > 0) { - Event lastEvent = events[-1] - lastEvent.duration = new Duration(lastEvent.start, e.start) - } - - events << e - } - - def excluded = events.findAll { event -> - exclusions.any { exclusion -> event.description ==~ exclusion } - } - - return events - excluded - } -} +package com.jdbernard.timeanalyzer.processors + +import com.jdbernard.timeanalyzer.events.Event +import com.jdbernard.timestamper.core.Timeline +import org.joda.time.DateTime +import org.joda.time.Duration + +public class TimelineEventProcessor { + + /** Events whose description matches one of these regex strings or + * patterns are ignored. */ + List exclusions = [] + + public TimelineEventProcessor() {} + + public TimelineEventProcessor(List exclusions) { + this.exclusions = exclusions + } + + public List process(Timeline timeline) { + List events = [] + + timeline.each { marker -> + Event e = new Event( + description: marker.mark, + notes: marker.notes, + start: new DateTime(marker.timestamp), + duration: new Duration(0)) + + // if this is not the first event, then we need to update the + // duration of the previous event + if (events.size > 0) { + Event lastEvent = events[-1] + lastEvent.duration = new Duration(lastEvent.start, e.start) + } + + events << e + } + + def excluded = events.findAll { event -> + exclusions.any { exclusion -> event.description ==~ exclusion } + } + + return events - excluded + } +} diff --git a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategorizationPlan.groovy b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategorizationPlan.groovy index e4712e9..868f819 100644 --- a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategorizationPlan.groovy +++ b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategorizationPlan.groovy @@ -1,29 +1,29 @@ -package com.quantumdigital.ithelp.timeanalyzer - -import com.jdbernard.timeanalyzer.Category -import com.jdbernard.timeanalyzer.CategorizationPlan -import com.jdbernard.timeanalyzer.Event - -public class TicketCategorizationPlan implements CategorizationPlan { - - private static def TICKET_PATTERN = ~/.*#(\d+).*/ - - public boolean deservesNewCategory(Event e, List el) { - return e.description ==~ TICKET_PATTERN - } - - public Category newCategory(Event e, List el) { - def m = e.description =~ TICKET_PATTERN - - return new TicketCategory(m[0][1] as int) - } - - public List findEventsToRecategorize(Event e, - List existingEvents) { - def m = e.description =~ TICKET_PATTERN - int ticketId = m[0][1] as int - - return existingEvents.findAll { - it.description ==~ /.*#${ticketId}.*/ } - } -} +package com.quantumdigital.ithelp.timeanalyzer + +import com.jdbernard.timeanalyzer.categories.Category +import com.jdbernard.timeanalyzer.categorizationplans.CategorizationPlan +import com.jdbernard.timeanalyzer.events.Event + +public class TicketCategorizationPlan implements CategorizationPlan { + + private static def TICKET_PATTERN = ~/.*#(\d+).*/ + + public boolean deservesNewCategory(Event e, List el) { + return e.description ==~ TICKET_PATTERN + } + + public Category newCategory(Event e, List el) { + def m = e.description =~ TICKET_PATTERN + + return new TicketCategory(m[0][1] as int) + } + + public List findEventsToRecategorize(Event e, + List existingEvents) { + def m = e.description =~ TICKET_PATTERN + int ticketId = m[0][1] as int + + return existingEvents.findAll { + it.description ==~ /.*#${ticketId}.*/ } + } +} diff --git a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategory.groovy b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategory.groovy index 8f464d6..e5ac442 100644 --- a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategory.groovy +++ b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketCategory.groovy @@ -1,25 +1,25 @@ -package com.quantumdigital.ithelp.timeanalyzer - -import com.jdbernard.timeanalyzer.Category -import com.jdbernard.timeanalyzer.Event - -public class TicketCategory extends Category { - - public final int ticketId - - public TicketCategory(int ticketId) { - super() - this.ticketId = ticketId - this.description = "Ticket #${ticketId}" - } - - public boolean matchesEvent(Event e) { - return (e.description ==~ /.*#${ticketId}.*/) - } - - public Event addEvent(Event e) { - TicketEvent te = new TicketEvent(e) - events << te - return te - } -} +package com.quantumdigital.ithelp.timeanalyzer + +import com.jdbernard.timeanalyzer.categories.Category +import com.jdbernard.timeanalyzer.events.Event + +public class TicketCategory extends Category { + + public final int ticketId + + public TicketCategory(int ticketId) { + super() + this.ticketId = ticketId + this.description = "Ticket #${ticketId}" + } + + public boolean matchesEvent(Event e) { + return (e.description ==~ /.*#${ticketId}.*/) + } + + public Event addEvent(Event e) { + TicketEvent te = new TicketEvent(e) + events << te + return te + } +} diff --git a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketEvent.groovy b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketEvent.groovy index 43c6dfe..ddf7b2e 100644 --- a/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketEvent.groovy +++ b/src/main/com/quantumdigital/ithelp/timeanalyzer/TicketEvent.groovy @@ -1,37 +1,37 @@ -package com.quantumdigital.ithelp.timeanalyzer - -import com.jdbernard.timeanalyzer.Event - -public class TicketEvent extends Event { - - public final int id - - public TicketEvent(String desc, String notes, String start, String duration) { - - super(desc, notes, start, duration) - - def m = desc =~ /.*#(\d+).*/ - this.id = m[0][1] as int - } - - public TicketEvent(Map params) { - super(params) - - def m = description =~ /.*#(\d+).*/ - this.id = m[0][1] as int - } - - public TicketEvent(Map params, Event e) { - super(params, e) - - def m = description =~ /.*#(\d+).*/ - this.id = m[0][1] as int - } - - public TicketEvent(Event e) { - super([:], e) - - def m = description =~ /.*#(\d+).*/ - this.id = m[0][1] as int - } -} +package com.quantumdigital.ithelp.timeanalyzer + +import com.jdbernard.timeanalyzer.events.Event + +public class TicketEvent extends Event { + + public final int id + + public TicketEvent(String desc, String notes, String start, String duration) { + + super(desc, notes, start, duration) + + def m = desc =~ /.*#(\d+).*/ + this.id = m[0][1] as int + } + + public TicketEvent(Map params) { + super(params) + + def m = description =~ /.*#(\d+).*/ + this.id = m[0][1] as int + } + + public TicketEvent(Map params, Event e) { + super(params, e) + + def m = description =~ /.*#(\d+).*/ + this.id = m[0][1] as int + } + + public TicketEvent(Event e) { + super([:], e) + + def m = description =~ /.*#(\d+).*/ + this.id = m[0][1] as int + } +} diff --git a/startscript.groovy b/startscript.groovy index 7b758bb..4aacb18 100644 --- a/startscript.groovy +++ b/startscript.groovy @@ -18,7 +18,7 @@ events = tep.process(timeline) topcat = new FilteredCategory("Top Category") 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() descriptionBasedCatPlan = new DescriptionBasedCategorizationPlan()