diff --git a/runtime/twodue/etc/messages.properties b/runtime/twodue/etc/messages.properties
index 0eea413d..065af633 100644
--- a/runtime/twodue/etc/messages.properties
+++ b/runtime/twodue/etc/messages.properties
@@ -1,6 +1,6 @@
# -*- mode: makefile -*-
#
-# $Id: messages.properties,v 1.5 2003/11/15 22:55:32 mdb Exp $
+# $Id: messages.properties,v 1.6 2003/12/10 20:33:42 mdb Exp $
#
# Translation messages for Two Due application
@@ -63,3 +63,13 @@ edit.error.missing_note = Can\'t add blank note.
# detail.wm
detail.title = Task Details
+
+#
+# bulkedit.wm
+
+bulkedit.title = Bulk task update
+bulkedit.no_tasks = No tasks at this priority.
+
+bulkedit.message.task_updated = Task updated.
+bulkedit.message.tasks_updated = Tasks updated.
+bulkedit.message.nothing_updated = No updates were detected.
diff --git a/runtime/twodue/src/java/com/samskivert/twodue/data/Task.java b/runtime/twodue/src/java/com/samskivert/twodue/data/Task.java
index 30b87472..b21178a4 100644
--- a/runtime/twodue/src/java/com/samskivert/twodue/data/Task.java
+++ b/runtime/twodue/src/java/com/samskivert/twodue/data/Task.java
@@ -1,5 +1,5 @@
//
-// $Id: Task.java,v 1.6 2003/12/10 19:12:31 mdb Exp $
+// $Id: Task.java,v 1.7 2003/12/10 20:33:42 mdb Exp $
package com.samskivert.twodue.data;
@@ -82,4 +82,12 @@ public class Task
{
return StringUtil.replace(category, ",", "
");
}
+
+ /**
+ * Returns a string representation of this instance.
+ */
+ public String toString ()
+ {
+ return StringUtil.fieldsToString(this);
+ }
}
diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/CatList.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/CatList.java
new file mode 100644
index 00000000..44bc39f6
--- /dev/null
+++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/CatList.java
@@ -0,0 +1,87 @@
+//
+// $Id: CatList.java,v 1.1 2003/12/10 20:33:42 mdb Exp $
+
+package com.samskivert.twodue.logic;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.samskivert.twodue.data.Task;
+
+/**
+ * Used to categorize tasks.
+ */
+public class CatList
+ implements Comparable
+{
+ /** This indicates which task to which a category belongs. */
+ public static interface Categorizer
+ {
+ public String category (Task task);
+ }
+
+ /** Used to ease category generation in UI. */
+ public static class CategoryTool
+ {
+ public boolean checkCategory (String category)
+ {
+ if (category.equals(_category)) {
+ return false;
+ } else {
+ _category = category;
+ return true;
+ }
+ }
+
+ public void clear ()
+ {
+ _category = null;
+ }
+
+ protected String _category;
+ }
+
+ /** The name of the category. */
+ public String name;
+
+ /** The tasks within it. */
+ public ArrayList tasks;
+
+ // documentation inherited from interface
+ public int compareTo (Object other)
+ {
+ return name.compareTo(((CatList)other).name);
+ }
+
+ /**
+ * Categorizes a list of tasks.
+ */
+ public static CatList[] categorize (ArrayList tasks, Categorizer catter)
+ {
+ if (tasks == null) {
+ return new CatList[0];
+ }
+
+ ArrayList cats = new ArrayList();
+ HashMap cmap = new HashMap();
+ int tcount = tasks.size();
+ for (int ii = 0; ii < tcount; ii++) {
+ Task task = (Task)tasks.get(ii);
+ String category = catter.category(task);
+ CatList clist = (CatList)cmap.get(category);
+ if (clist == null) {
+ clist = new CatList();
+ clist.name = category;
+ clist.tasks = new ArrayList();
+ cats.add(clist);
+ cmap.put(category, clist);
+ }
+ clist.tasks.add(task);
+ }
+
+ CatList[] ctasks = new CatList[cats.size()];
+ cats.toArray(ctasks);
+
+ return ctasks;
+ }
+}
diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/UserLogic.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/UserLogic.java
index 359a5119..5cbbdceb 100644
--- a/runtime/twodue/src/java/com/samskivert/twodue/logic/UserLogic.java
+++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/UserLogic.java
@@ -1,5 +1,5 @@
//
-// $Id: UserLogic.java,v 1.1 2002/11/08 09:14:21 mdb Exp $
+// $Id: UserLogic.java,v 1.2 2003/12/10 20:33:42 mdb Exp $
package com.samskivert.twodue.logic;
@@ -33,6 +33,7 @@ public abstract class UserLogic implements Logic
{
TwoDueApp tdapp = (TwoDueApp)app;
User user = tdapp.getUserManager().requireUser(ctx.getRequest());
+ ctx.put("username", user.username);
invoke(ctx, tdapp, user);
}
}
diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/bulkedit.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/bulkedit.java
new file mode 100644
index 00000000..4ecc27e6
--- /dev/null
+++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/bulkedit.java
@@ -0,0 +1,107 @@
+//
+// $Id: bulkedit.java,v 1.1 2003/12/10 20:33:42 mdb Exp $
+
+package com.samskivert.twodue.logic;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import javax.servlet.http.HttpServletRequest;
+
+import com.samskivert.util.StringUtil;
+
+import com.samskivert.servlet.RedirectException;
+import com.samskivert.servlet.user.User;
+import com.samskivert.servlet.util.ParameterUtil;
+import com.samskivert.velocity.InvocationContext;
+
+import com.samskivert.twodue.Log;
+import com.samskivert.twodue.TwoDueApp;
+import com.samskivert.twodue.data.Task;
+
+/**
+ * Allows the bulk update of task properties.
+ */
+public class bulkedit extends UserLogic
+{
+ public void invoke (InvocationContext ctx, TwoDueApp app, User user)
+ throws Exception
+ {
+ HttpServletRequest req = ctx.getRequest();
+
+ // display any message we've been asked to display
+ String msg = ParameterUtil.getParameter(req, "message", true);
+ if (!StringUtil.blank(msg)) {
+ ctx.put("error", msg);
+ }
+
+ // load up our tasks
+ ArrayList tasks = app.getRepository().loadTasks();
+
+ // if they've submitted the form, we update the task database
+ if (ParameterUtil.parameterEquals(
+ ctx.getRequest(), "action", "update")) {
+ int updated = 0;
+ for (Iterator iter = tasks.iterator(); iter.hasNext(); ) {
+ Task task = (Task)iter.next();
+ // check to see if category or priority have been updated
+ int nprio = ParameterUtil.getIntParameter(
+ req, "priority" + task.taskId, task.priority,
+ "bulkedit.error.invalid_task_priority");
+ String ncat = ParameterUtil.getParameter(
+ req, "category" + task.taskId, false);
+ if (nprio != task.priority ||
+ (!StringUtil.blank(ncat) && !ncat.equals(task.category))) {
+ task.priority = nprio;
+ task.category = ncat;
+ app.getRepository().updateTask(task);
+ updated++;
+ }
+ }
+ String rspmsg;
+ switch (updated) {
+ case 0: rspmsg = "bulkedit.message.nothing_updated"; break;
+ case 1: rspmsg = "bulkedit.message.task_updated"; break;
+ default: rspmsg = "bulkedit.message.tasks_updated"; break;
+ }
+ ctx.put("error", rspmsg);
+ }
+
+ // now filter them
+ int priority = ParameterUtil.getIntParameter(
+ req, "priority", 10, "bulkedit.error.invalid_priority");
+ ctx.put("priority", priority);
+ for (Iterator iter = tasks.iterator(); iter.hasNext(); ) {
+ Task task = (Task)iter.next();
+ if (task.priority != priority) {
+ iter.remove();
+ }
+ }
+ Collections.sort(tasks, TASK_PARATOR);
+
+ CatList[] xtasks = CatList.categorize(tasks, new CatList.Categorizer() {
+ public String category (Task task) {
+ return task.getPriorityName();
+ }
+ });
+ ctx.put("xtasks", xtasks);
+ ctx.put("xcats", new CatList.CategoryTool());
+ }
+
+ protected static final Comparator TASK_PARATOR = new Comparator() {
+ public int compare (Object o1, Object o2) {
+ Task t1 = (Task)o1, t2 = (Task)o2;
+ // sort first by reverse priority, then by category, then complexity
+ if (t1.priority == t2.priority) {
+ if (t1.category.equals(t2.category)) {
+ return t1.getComplexityValue() - t2.getComplexityValue();
+ } else {
+ return t1.category.compareTo(t2.category);
+ }
+ } else {
+ return t2.priority - t1.priority;
+ }
+ }
+ };
+}
diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/bycategory.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/bycategory.java
index 0043acf7..d9fb49c1 100644
--- a/runtime/twodue/src/java/com/samskivert/twodue/logic/bycategory.java
+++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/bycategory.java
@@ -1,5 +1,5 @@
//
-// $Id: bycategory.java,v 1.1 2003/11/15 22:55:32 mdb Exp $
+// $Id: bycategory.java,v 1.2 2003/12/10 20:33:42 mdb Exp $
package com.samskivert.twodue.logic;
@@ -37,10 +37,6 @@ public class bycategory extends UserLogic
ctx.put("error", msg);
}
- // we use this to determine whether to show "complete" buttons for
- // tasks
- ctx.put("username", user.username);
-
ArrayList tasks = null;
String query = ParameterUtil.getParameter(req, "query", false);
if (StringUtil.blank(query)) {
diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/detail.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/detail.java
index 4284018a..e0e56e5e 100644
--- a/runtime/twodue/src/java/com/samskivert/twodue/logic/detail.java
+++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/detail.java
@@ -1,5 +1,5 @@
//
-// $Id: detail.java,v 1.2 2003/01/23 21:22:56 mdb Exp $
+// $Id: detail.java,v 1.3 2003/12/10 20:33:42 mdb Exp $
package com.samskivert.twodue.logic;
@@ -28,10 +28,6 @@ public class detail extends UserLogic
int taskId = ParameterUtil.requireIntParameter(
ctx.getRequest(), "task", "task.error.missing_taskid");
- // we use this to determine whether to show "complete" buttons for
- // tasks
- ctx.put("username", user.username);
-
// load up the task in question
Task task = app.getRepository().loadTask(taskId);
if (task == null) {
diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/index.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/index.java
index a1aebcb2..7fc9af76 100644
--- a/runtime/twodue/src/java/com/samskivert/twodue/logic/index.java
+++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/index.java
@@ -1,5 +1,5 @@
//
-// $Id: index.java,v 1.11 2003/11/15 22:55:32 mdb Exp $
+// $Id: index.java,v 1.12 2003/12/10 20:33:42 mdb Exp $
package com.samskivert.twodue.logic;
@@ -37,10 +37,6 @@ public class index extends UserLogic
ctx.put("error", msg);
}
- // we use this to determine whether to show "complete" buttons for
- // tasks
- ctx.put("username", user.username);
-
// if they've submitted the form, we create a new task and stick
// it into the dataabse
if (ParameterUtil.parameterEquals(req, "action", "create")) {
diff --git a/runtime/twodue/src/java/com/samskivert/twodue/logic/tasks.java b/runtime/twodue/src/java/com/samskivert/twodue/logic/tasks.java
index 84290fd0..0e4f8cc0 100644
--- a/runtime/twodue/src/java/com/samskivert/twodue/logic/tasks.java
+++ b/runtime/twodue/src/java/com/samskivert/twodue/logic/tasks.java
@@ -1,5 +1,5 @@
//
-// $Id: tasks.java,v 1.2 2003/12/10 19:39:26 mdb Exp $
+// $Id: tasks.java,v 1.3 2003/12/10 20:33:42 mdb Exp $
package com.samskivert.twodue.logic;
@@ -37,10 +37,6 @@ public class tasks extends UserLogic
ctx.put("error", msg);
}
- // we use this to determine whether to show "complete" buttons for
- // tasks
- ctx.put("username", user.username);
-
ArrayList tasks = null;
String query = ParameterUtil.getParameter(req, "query", false);
if (StringUtil.blank(query)) {
diff --git a/runtime/twodue/web/bulkedit.wm b/runtime/twodue/web/bulkedit.wm
new file mode 100644
index 00000000..4998a626
--- /dev/null
+++ b/runtime/twodue/web/bulkedit.wm
@@ -0,0 +1,81 @@
+#set ($title = $i18n.xlate("bulkedit.title"))
+#import ("/header.wm")
+
+
+
| Task summary | ++ | By category | ++ | + + | + +
+ + +Outstanding tasks: + + +
+ +#import ("/footer.wm")