Reorganized the code into new packages.
This commit is contained in:
parent
652cc8703a
commit
d076b739f5
@ -1,5 +0,0 @@
|
||||
package com.jdbernard.timeanalyzer;
|
||||
|
||||
public interface CategoryFilter {
|
||||
public boolean matchesEvent(Event event);
|
||||
}
|
@ -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<Category> {
|
||||
|
||||
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<CategoryFilter> 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<Category> {
|
||||
|
||||
/** 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<CategoryFilter> 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 }
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.jdbernard.timeanalyzer.categories;
|
||||
|
||||
import com.jdbernard.timeanalyzer.events.Event;
|
||||
|
||||
public interface CategoryFilter {
|
||||
public boolean matchesEvent(Event event);
|
||||
}
|
@ -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() }
|
||||
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
package com.jdbernard.timeanalyzer
|
||||
|
||||
public class FilteredCategory extends Category{
|
||||
|
||||
List<CategoryFilter> 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<CategoryFilter> filters = []
|
||||
|
||||
public FilteredCategory(String description) {
|
||||
super(description) }
|
||||
|
||||
public boolean matchesEvent(Event e) {
|
||||
return filters.every { filter -> filter.matchesEvent(e) } }
|
||||
|
||||
}
|
@ -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 }
|
||||
|
||||
}
|
@ -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) }
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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) }
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package com.jdbernard.timeanalyzer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface CategorizationPlan {
|
||||
boolean deservesNewCategory(Event event, List<Event> existingEvents);
|
||||
Category newCategory(Event event, List<Event> existingEvents);
|
||||
List<Event> findEventsToRecategorize(Event event, List<Event> 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<Event> existingEvents);
|
||||
Category newCategory(Event event, List<Event> existingEvents);
|
||||
List<Event> findEventsToRecategorize(Event event, List<Event> existingEvents);
|
||||
}
|
@ -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) } }
|
||||
}
|
@ -1,23 +1,27 @@
|
||||
package com.jdbernard.timeanalyzer
|
||||
|
||||
public class DescriptionBasedCategorizationPlan implements CategorizationPlan {
|
||||
|
||||
public boolean deservesNewCategory(Event event, List<Event> 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<Event> existingEvents) {
|
||||
return new DescriptionBasedCategory(event.description)
|
||||
}
|
||||
|
||||
public List<Event> findEventsToRecategorize(Event event,
|
||||
List<Event> 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<Event> 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<Event> existingEvents) {
|
||||
return new DescriptionBasedCategory(event.description)
|
||||
}
|
||||
|
||||
public List<Event> findEventsToRecategorize(Event event,
|
||||
List<Event> existingEvents) {
|
||||
def desc = event.description.replaceAll(/\p{Punct}/, '').toLowerCase()
|
||||
return existingEvents.findAll {
|
||||
it.description.replaceAll(/\p{Punct}/, '').toLowerCase() == desc }
|
||||
}
|
||||
|
||||
}
|
@ -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<Event> el) {
|
||||
return event ==~ TWO_LEVEL_PATTERN
|
||||
}
|
||||
|
||||
public Category newCategory(Event event, List<Event> el) {
|
||||
def m = event.description =~ TWO_LEVEL_PATTERN
|
||||
return new TwoLevelCategory(m[0][1])
|
||||
}
|
||||
|
||||
public List<Event> findEventsToRecategorize(Event event,
|
||||
List<Event> 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<Event> el) {
|
||||
return event ==~ TWO_LEVEL_PATTERN
|
||||
}
|
||||
|
||||
public Category newCategory(Event event, List<Event> el) {
|
||||
def m = event.description =~ TWO_LEVEL_PATTERN
|
||||
return new TwoLevelCategory(m[0][1])
|
||||
}
|
||||
|
||||
public List<Event> findEventsToRecategorize(Event event,
|
||||
List<Event> existingEvents) {
|
||||
def m = event.description =~ TWO_LEVEL_PATTERN
|
||||
return existingEvents.findAll { it.description ==~ /${m[0][1]}:.*/ }
|
||||
}
|
||||
}
|
@ -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()) }
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
|
||||
}
|
@ -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<Event> process(Timeline timeline) {
|
||||
List<Event> 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<Event> process(Timeline timeline) {
|
||||
List<Event> 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
|
||||
}
|
||||
}
|
@ -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<Event> el) {
|
||||
return e.description ==~ TICKET_PATTERN
|
||||
}
|
||||
|
||||
public Category newCategory(Event e, List<Event> el) {
|
||||
def m = e.description =~ TICKET_PATTERN
|
||||
|
||||
return new TicketCategory(m[0][1] as int)
|
||||
}
|
||||
|
||||
public List<Event> findEventsToRecategorize(Event e,
|
||||
List<Event> 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<Event> el) {
|
||||
return e.description ==~ TICKET_PATTERN
|
||||
}
|
||||
|
||||
public Category newCategory(Event e, List<Event> el) {
|
||||
def m = e.description =~ TICKET_PATTERN
|
||||
|
||||
return new TicketCategory(m[0][1] as int)
|
||||
}
|
||||
|
||||
public List<Event> findEventsToRecategorize(Event e,
|
||||
List<Event> existingEvents) {
|
||||
def m = e.description =~ TICKET_PATTERN
|
||||
int ticketId = m[0][1] as int
|
||||
|
||||
return existingEvents.findAll {
|
||||
it.description ==~ /.*#${ticketId}.*/ }
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user