diff --git a/build.xml b/build.xml
index c0bf202..ca9277f 100644
--- a/build.xml
+++ b/build.xml
@@ -5,4 +5,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/project.properties b/project.properties
index 5ce11ac..77c8583 100644
--- a/project.properties
+++ b/project.properties
@@ -1,5 +1,5 @@
-#Wed, 29 Aug 2012 15:10:32 -0700
+#Sat, 01 Sep 2012 22:19:54 -0700
name=time-analyzer
-version=0.1
-build.number=5
+version=1.0
+build.number=0
lib.local=true
diff --git a/resources/main/start-script.groovy b/resources/main/start-script.groovy
index a91d091..73da9c6 100644
--- a/resources/main/start-script.groovy
+++ b/resources/main/start-script.groovy
@@ -1,27 +1,23 @@
-import com.jdbernard.timeanalyzer.processors.*
-import com.jdbernard.timeanalyzer.categories.*
-import com.jdbernard.timeanalyzer.categorizationplans.*
-import com.jdbernard.timeanalyzer.chart.*
-import com.jdbernard.timeanalyzer.events.*
-import com.jdbernard.timestamper.core.*
-import com.quantumdigital.ithelp.timeanalyzer.*
-import org.joda.time.*
-import org.joda.time.format.*
-import org.jfree.chart.*
-import org.jfree.data.general.*
+import com.jdbernard.timeanalyzer.categories.FilteredCategory
+import com.jdbernard.timeanalyzer.categories.TimeIntervalCategory
+import com.jdbernard.timeanalyzer.categorizationplans.DailyCategorizationPlan
+import com.jdbernard.timeanalyzer.categorizationplans.DescriptionBasedCategorizationPlan
+import com.jdbernard.timeanalyzer.categorizationplans.TwoLevelCategorizationPlan
+import com.jdbernard.timeanalyzer.processors.TimelineEventProcessor
+import com.jdbernard.timestamper.core.FileTimelineSource
+import org.jfree.chart.ChartFactory
+import org.jfree.chart.ChartFrame
+import org.jfree.data.general.DefaultPieDataset
import org.jfree.util.SortOrder
-
-tep = new TimelineEventProcessor()
-tep.exclusions << ~/.*Home.*/
+import org.joda.time.DateTime
+import org.joda.time.Interval
+import org.joda.time.Period
+import org.joda.time.format.PeriodFormat
pf = PeriodFormat.getDefault()
-topcat = new FilteredCategory("Top Category")
-
-twoLevelCatPlan = new TwoLevelCategorizationPlan()
-descriptionBasedCatPlan = new DescriptionBasedCategorizationPlan()
-topcat.categorizationPlans << twoLevelCatPlan
-topcat.categorizationPlans << descriptionBasedCatPlan
+printDuration = { duration ->
+ pf.print(duration.toPeriod()) }
loadEvents = { file, processor ->
fileSource = new FileTimelineSource(file.toURI())
@@ -35,9 +31,61 @@ makePieDataset = { category ->
category.events.each { entry ->
dpds.setValue(entry.description, entry.duration.standardSeconds) }
dpds.sortByValues(SortOrder.DESCENDING)
-
return dpds }
-makeFrame = { categoryName, dataset ->
+makePieFrame = { categoryName, category ->
+ def dataset = makePieDataset(category)
return new ChartFrame(categoryName,
ChartFactory.createPieChart("Time Spent", dataset, true, true, false)) }
+
+analyze = { file ->
+ def tep = new TimelineEventProcessor()
+ tep.exclusions << /.*Home.*/
+
+ def twoLevelPlan = new TwoLevelCategorizationPlan()
+ def descriptionPlan = new DescriptionBasedCategorizationPlan()
+
+ def setupCat = { cat ->
+ cat.categorizationPlans << twoLevelPlan
+ cat.categorizationPlans << descriptionPlan }
+
+ def dailyPlan = new DailyCategorizationPlan(setupCat)
+
+ def events = loadEvents(file, tep)
+ def topcat = new FilteredCategory("Time Analysis: Jonathan Bernard")
+ topcat.categorizationPlans << dailyPlan
+ topcat.categorizationPlans << twoLevelPlan
+ topcat.categorizationPlans << descriptionPlan
+
+ events.each { if (topcat.matchesEvent(it)) topcat.addEvent(it) }
+
+ return [topcat: topcat, rawEvents: events] }
+
+listEvents = {topcat ->
+ topcat.events.eachWithIndex { event, index ->
+ println "${index}: ${event} (${printDuration(event.duration)})" }}
+
+listCategories = { topcat ->
+ topcat.categories.eachWithIndex { cat, index ->
+ println "${index}: ${cat} (${printDuration(cat.duration)})" }}
+
+details = { topcat ->
+ println "Categories"
+ listCategories(topcat)
+ println "Events"
+ listEvents(topcat) }
+
+weeklySummary = { events ->
+ def todayMidnight = new DateTime()
+ def friday = todayMidnight.withDayOfWeek(5)
+ def monday = todayMidnight.withDayOfWeek(1)
+ def week = new Interval(monday, Period.days(7))
+ def weekCat = new TimeIntervalCategory(
+ "Week of ${friday.toString('MMM dd, yyyy')}", week)
+
+ weekCat.categorizationPlans << new TwoLevelCategorizationPlan()
+ weekCat.categorizationPlans << new DescriptionBasedCategorizationPlan()
+
+ events.each { if (weekCat.matchesEvent(it)) weekCat.addEvent(it) }
+
+ return weekCat }
diff --git a/src/main/com/jdbernard/timeanalyzer/categories/Category.groovy b/src/main/com/jdbernard/timeanalyzer/categories/Category.groovy
index 3b88ab2..d5cfe2a 100644
--- a/src/main/com/jdbernard/timeanalyzer/categories/Category.groovy
+++ b/src/main/com/jdbernard/timeanalyzer/categories/Category.groovy
@@ -47,9 +47,13 @@ public abstract class Category implements Comparable {
* made and the `Event` matches.*/
public Event addEvent(Event event) {
+ def addedEvent
+
// Try first to add it to a subcategory (or create a new subcategory).
- if (!addToSubcategory(event)) {
- // Cannot add to a subcategory, add to ourselves.
+ addedEvent = addToSubcategory(event)
+
+ // Cannot add to a subcategory, add to ourselves.
+ if (!addedEvent) {
events << event
addedEvent = event }
diff --git a/src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.groovy b/src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.groovy
new file mode 100644
index 0000000..d79a125
--- /dev/null
+++ b/src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.groovy
@@ -0,0 +1,24 @@
+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 abstract class CategorizationPlan {
+
+ public CategorizationPlan() {}
+ public CategorizationPlan(Closure newCatSetupFun) {
+ newCategorySetupFun = newCatSetupFun }
+
+ protected Closure newCategorySetupFun
+
+ protected void setupNewCategory(Category cat) {
+ if (newCategorySetupFun) newCategorySetupFun(cat) }
+
+
+ public abstract boolean deservesNewCategory(Event event, List existingEvents)
+ public abstract Category newCategory(Event event, List existingEvents)
+ public abstract List findEventsToRecategorize(Event event, List existingEvents)
+}
diff --git a/src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.java b/src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.java
deleted file mode 100644
index 351211d..0000000
--- a/src/main/com/jdbernard/timeanalyzer/categorizationplans/CategorizationPlan.java
+++ /dev/null
@@ -1,13 +0,0 @@
-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
index f4a10b5..0fee24e 100644
--- a/src/main/com/jdbernard/timeanalyzer/categorizationplans/DailyCategorizationPlan.groovy
+++ b/src/main/com/jdbernard/timeanalyzer/categorizationplans/DailyCategorizationPlan.groovy
@@ -1,16 +1,21 @@
-package com.jdbernard.timeanalyzer.categorizationplans;
+package com.jdbernard.timeanalyzer.categorizationplans
import com.jdbernard.timeanalyzer.categories.Category
+import com.jdbernard.timeanalyzer.categories.TimeIntervalCategory
import com.jdbernard.timeanalyzer.events.Event
import org.joda.time.DateTime
import org.joda.time.Interval
import org.joda.time.Period
-public class DailyCategorizationPlan {
+public class DailyCategorizationPlan extends CategorizationPlan {
+
+ public DailyCategorizationPlan() {}
+ public DailyCategorizationPlan(Closure newCatSetupFun) {
+ super(newCatSetupFun) }
boolean deservesNewCategory(Event event, List existingEvents) {
- Interval fullday = new Interval(
+ Interval fullDay = new Interval(
event.start.toDateMidnight(), Period.days(1))
Interval eventIv = new Interval(
event.start, event.duration)
@@ -21,8 +26,12 @@ public class DailyCategorizationPlan {
Interval fullday = new Interval(
event.start.toDateMidnight(), Period.days(1))
- return TimeIntervalCategory(
- event.start.toString("EEE, MMM dd", fullday)) }
+ Category newCat = new TimeIntervalCategory(
+ event.start.toString("EEE, MMM dd"), fullday)
+
+ setupNewCategory(newCat)
+
+ return newCat }
List findEventsToRecategorize(Event event,
List existingEvents) {
diff --git a/src/main/com/jdbernard/timeanalyzer/categorizationplans/DescriptionBasedCategorizationPlan.groovy b/src/main/com/jdbernard/timeanalyzer/categorizationplans/DescriptionBasedCategorizationPlan.groovy
index 11bb7d6..914e007 100644
--- a/src/main/com/jdbernard/timeanalyzer/categorizationplans/DescriptionBasedCategorizationPlan.groovy
+++ b/src/main/com/jdbernard/timeanalyzer/categorizationplans/DescriptionBasedCategorizationPlan.groovy
@@ -4,24 +4,27 @@ 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 extends CategorizationPlan {
+
+ public DescriptionBasedCategorizationPlan() {}
+ public DescriptionBasedCategorizationPlan(Closure newCatSetupFun) {
+ super(newCatSetupFun) }
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 }
- }
+ it.description.replaceAll(/\p{Punct}/, '').toLowerCase() == desc } }
public Category newCategory(Event event,
List existingEvents) {
- return new DescriptionBasedCategory(event.description)
- }
+ def newCat = new DescriptionBasedCategory(event.description)
+ setupNewCategory(newCat)
+ return newCat }
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 }
- }
+ it.description.replaceAll(/\p{Punct}/, '').toLowerCase() == desc } }
}
diff --git a/src/main/com/jdbernard/timeanalyzer/categorizationplans/TwoLevelCategorizationPlan.groovy b/src/main/com/jdbernard/timeanalyzer/categorizationplans/TwoLevelCategorizationPlan.groovy
index ee7b182..f0ec1f7 100644
--- a/src/main/com/jdbernard/timeanalyzer/categorizationplans/TwoLevelCategorizationPlan.groovy
+++ b/src/main/com/jdbernard/timeanalyzer/categorizationplans/TwoLevelCategorizationPlan.groovy
@@ -4,22 +4,25 @@ 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 extends CategorizationPlan {
private static final def TWO_LEVEL_PATTERN = ~/(.+?):(.*)/
+ public TwoLevelCategorizationPlan() {}
+ public TwoLevelCategorizationPlan(Closure newCatSetupFun) {
+ super(newCatSetupFun) }
+
public boolean deservesNewCategory(Event event, List el) {
- return event ==~ TWO_LEVEL_PATTERN
- }
+ 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])
- }
+ def newCat = new TwoLevelCategory(m[0][1])
+ setupNewCategory(newCat)
+ return newCat }
public List findEventsToRecategorize(Event event,
List existingEvents) {
def m = event.description =~ TWO_LEVEL_PATTERN
- return existingEvents.findAll { it.description ==~ /${m[0][1]}:.*/ }
- }
+ return existingEvents.findAll { it.description ==~ /${m[0][1]}:.*/ } }
}