Re: Completion should be effort invested instead of percentage of duration



On Tue, Nov 07, 2006 at 08:46:08PM +0100, Maurice van der Pot wrote:
> Currently progress of a task is tracked by setting a percentage. 
> 
> There are two problems with this approach:
> 
> 1) Because it is a percentage of the duration and not of the work
> associated with the task, the work done on the task would seem to vary
> depending on how much non-working time there is between task start and
> end. 
...
> 2) If the work associated with a task is increased (because it turns out
> to be more work than originally planned), then the time spent on it will
> seem to increase judging from the length of the completion bar.

I have started on a patch for this issue (it's attached to this message).
The patch adds a "Work done" field to the task dialog. "Work done" is now
used in the Gantt chart to draw the bar within a task instead of
"Complete".

I still have some questions though:

- How do you think completion should be handled for tasks with fixed
  duration? Should the "work done" field just be interpreted as a
  time spent for these tasks?

- I could use some help to make sure signals are generated and handled
  appropriately. I don't have a clear understanding of what should
  trigger a signal in planner.

- Last, but certainly not least, what do you think of what I am
  proposing? Is the existing 'percent-complete' useful to anyone or
  could it be removed once 'work-done' has been implemented?

Regards,
Maurice.

-- 
Maurice van der Pot

Gentoo Linux Developer   griffon26 gentoo org     http://www.gentoo.org
Creator of BiteMe!       griffon26 kfk4ever com   http://www.kfk4ever.com

Index: data/dtd/mrproject-0.6.dtd
===================================================================
RCS file: /cvs/gnome/planner/data/dtd/mrproject-0.6.dtd,v
retrieving revision 1.4
diff -u -B -r1.4 mrproject-0.6.dtd
--- data/dtd/mrproject-0.6.dtd	18 Feb 2005 11:32:07 -0000	1.4
+++ data/dtd/mrproject-0.6.dtd	3 Jan 2007 14:20:08 -0000
@@ -59,6 +59,7 @@
 	       work-start           CDATA #IMPLIED
                duration             CDATA #IMPLIED
                work                 CDATA #IMPLIED
+               work-done            CDATA #IMPLIED
                percent-complete     CDATA #IMPLIED
                priority             CDATA #IMPLIED
                type                 (normal|milestone) "normal"
Index: data/glade/task-dialog.glade
===================================================================
RCS file: /cvs/gnome/planner/data/glade/task-dialog.glade,v
retrieving revision 1.10
diff -u -B -r1.10 task-dialog.glade
--- data/glade/task-dialog.glade	20 Apr 2005 21:37:58 -0000	1.10
+++ data/glade/task-dialog.glade	3 Jan 2007 14:20:09 -0000
@@ -72,7 +72,7 @@
 		<widget class="GtkTable" id="table1">
 		  <property name="border_width">8</property>
 		  <property name="visible">True</property>
-		  <property name="n_rows">7</property>
+		  <property name="n_rows">8</property>
 		  <property name="n_columns">3</property>
 		  <property name="homogeneous">False</property>
 		  <property name="row_spacing">6</property>
@@ -187,8 +187,8 @@
 		    <packing>
 		      <property name="left_attach">0</property>
 		      <property name="right_attach">1</property>
-		      <property name="top_attach">5</property>
-		      <property name="bottom_attach">6</property>
+		      <property name="top_attach">6</property>
+		      <property name="bottom_attach">7</property>
 		      <property name="x_options">fill</property>
 		      <property name="y_options"></property>
 		    </packing>
@@ -216,8 +216,8 @@
 		    <packing>
 		      <property name="left_attach">0</property>
 		      <property name="right_attach">1</property>
-		      <property name="top_attach">6</property>
-		      <property name="bottom_attach">7</property>
+		      <property name="top_attach">7</property>
+		      <property name="bottom_attach">8</property>
 		      <property name="x_options">fill</property>
 		      <property name="y_options"></property>
 		    </packing>
@@ -238,8 +238,8 @@
 		    <packing>
 		      <property name="left_attach">1</property>
 		      <property name="right_attach">2</property>
-		      <property name="top_attach">5</property>
-		      <property name="bottom_attach">6</property>
+		      <property name="top_attach">6</property>
+		      <property name="bottom_attach">7</property>
 		      <property name="y_options"></property>
 		    </packing>
 		  </child>
@@ -259,8 +259,8 @@
 		    <packing>
 		      <property name="left_attach">1</property>
 		      <property name="right_attach">2</property>
-		      <property name="top_attach">6</property>
-		      <property name="bottom_attach">7</property>
+		      <property name="top_attach">7</property>
+		      <property name="bottom_attach">8</property>
 		      <property name="y_options"></property>
 		    </packing>
 		  </child>
@@ -286,8 +286,8 @@
 		    <packing>
 		      <property name="left_attach">2</property>
 		      <property name="right_attach">3</property>
-		      <property name="top_attach">5</property>
-		      <property name="bottom_attach">6</property>
+		      <property name="top_attach">6</property>
+		      <property name="bottom_attach">7</property>
 		      <property name="x_options">fill</property>
 		      <property name="y_options"></property>
 		    </packing>
@@ -314,8 +314,8 @@
 		    <packing>
 		      <property name="left_attach">2</property>
 		      <property name="right_attach">3</property>
-		      <property name="top_attach">6</property>
-		      <property name="bottom_attach">7</property>
+		      <property name="top_attach">7</property>
+		      <property name="bottom_attach">8</property>
 		      <property name="x_options">fill</property>
 		      <property name="y_options"></property>
 		    </packing>
@@ -674,6 +674,84 @@
 		      <property name="right_attach">3</property>
 		      <property name="top_attach">4</property>
 		      <property name="bottom_attach">5</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkEntry" id="work_done_entry">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">True</property>
+		      <property name="max_length">0</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char">*</property>
+		      <property name="activates_default">True</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">1</property>
+		      <property name="right_attach">2</property>
+		      <property name="top_attach">5</property>
+		      <property name="bottom_attach">6</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label119">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Work do_ne:</property>
+		      <property name="use_underline">True</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="mnemonic_widget">work_done_entry</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">0</property>
+		      <property name="right_attach">1</property>
+		      <property name="top_attach">5</property>
+		      <property name="bottom_attach">6</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label120">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes"></property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">2</property>
+		      <property name="right_attach">3</property>
+		      <property name="top_attach">5</property>
+		      <property name="bottom_attach">6</property>
 		      <property name="x_options">fill</property>
 		      <property name="y_options"></property>
 		    </packing>
Index: libplanner/mrp-old-xml.c
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-old-xml.c,v
retrieving revision 1.12
diff -u -B -r1.12 mrp-old-xml.c
--- libplanner/mrp-old-xml.c	16 Apr 2005 20:27:39 -0000	1.12
+++ libplanner/mrp-old-xml.c	3 Jan 2007 14:20:10 -0000
@@ -215,7 +215,7 @@
 	guint          percent_complete = 0;
 	gint          priority = 0;
 	gchar         *note;
-	gint           duration, work;
+	gint           duration, work, work_done;
 	gboolean       got_constraint = FALSE;
 	MrpTaskType    type;
 	MrpTaskSched   sched;
@@ -229,6 +229,7 @@
 	note = old_xml_get_string (tree, "note");
 	id = old_xml_get_int (tree, "id");
 	percent_complete = old_xml_get_int (tree, "percent-complete");
+	work_done = old_xml_get_int_with_default (tree, "work-done", -1);
 	priority = old_xml_get_int (tree, "priority");
 	type = old_xml_get_task_type (tree, "type");
 	sched = old_xml_get_task_sched (tree, "scheduling");
@@ -287,6 +288,7 @@
 				     "type", type,
 				     "work", work,
 				     "duration", duration,
+				     "work_done", work_done,
 				     "percent_complete", percent_complete,
 				     "priority", priority,
 				     "note", note,
Index: libplanner/mrp-parser.c
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-parser.c,v
retrieving revision 1.8
diff -u -B -r1.8 mrp-parser.c
--- libplanner/mrp-parser.c	18 Feb 2005 17:37:21 -0000	1.8
+++ libplanner/mrp-parser.c	3 Jan 2007 14:20:10 -0000
@@ -484,6 +484,7 @@
 	MrpConstraint *constraint;
 	gint           duration;
 	gint           work;
+	gint           work_done;
 	gint           complete;
 	gint           priority;
 	MrpTaskType    type;
@@ -513,6 +514,7 @@
 		      "duration", &duration,
 		      "work", &work,
 		      "constraint", &constraint,
+		      "work-done", &work_done,
 		      "percent-complete", &complete,
 		      "priority", &priority,
 		      "type", &type,
@@ -540,6 +542,7 @@
 	mpp_xml_set_date (node, "end", finish);
 	mpp_xml_set_date (node, "work-start", work_start);
 
+	mpp_xml_set_int (node, "work-done", work_done);
 	mpp_xml_set_int (node, "percent-complete", complete);
 	mpp_xml_set_int (node, "priority", priority);
 
Index: libplanner/mrp-private.h
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-private.h,v
retrieving revision 1.8
diff -u -B -r1.8 mrp-private.h
--- libplanner/mrp-private.h	20 Apr 2006 00:29:54 -0000	1.8
+++ libplanner/mrp-private.h	3 Jan 2007 14:20:10 -0000
@@ -78,6 +78,8 @@
 						      mrptime          start);
 void              imrp_task_set_work_start           (MrpTask         *task,
 						      mrptime          start);
+void              imrp_task_set_work_done_finish     (MrpTask         *task,
+						      mrptime          done_finish);
 void              imrp_task_set_finish               (MrpTask         *task,
 						      mrptime          finish);
 void              imrp_task_set_latest_start         (MrpTask         *task,
@@ -88,6 +90,8 @@
 						      gint             duration);
 void              imrp_task_set_work                 (MrpTask         *task,
 						      gint             work);
+void              imrp_task_set_work_done            (MrpTask         *task,
+						      gint             work_done);
 MrpTaskGraphNode *imrp_task_get_graph_node           (MrpTask         *task);
 MrpConstraint     imrp_task_get_constraint           (MrpTask         *task);
 void              imrp_task_set_constraint           (MrpTask         *task,
Index: libplanner/mrp-task-manager.c
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-task-manager.c,v
retrieving revision 1.20
diff -u -B -r1.20 mrp-task-manager.c
--- libplanner/mrp-task-manager.c	20 Apr 2006 00:29:54 -0000	1.20
+++ libplanner/mrp-task-manager.c	3 Jan 2007 14:20:11 -0000
@@ -76,6 +76,11 @@
 task_manager_task_duration_notify_cb      (MrpTask             *task,
 					   GParamSpec          *spec,
 					   MrpTaskManager      *manager);
+
+static void 
+task_manager_task_work_done_notify_cb      (MrpTask             *task,
+					    GParamSpec          *spec,
+					    MrpTaskManager      *manager);
 #ifdef WITH_SIMPLE_PRIORITY_SCHEDULING
 static void
 task_manager_task_priority_notify_cb      (MrpTask             *task,
@@ -273,6 +278,10 @@
 			  "notify::duration",
 			  G_CALLBACK (task_manager_task_duration_notify_cb),
 			  manager);
+	g_signal_connect (task,
+			  "notify::work-done",
+			  G_CALLBACK (task_manager_task_work_done_notify_cb),
+			  manager);
 #ifdef WITH_SIMPLE_PRIORITY_SCHEDULING
 	/* Added to manage the transaction from normal to dominant. */
 	g_signal_connect (task,
@@ -1685,6 +1694,119 @@
  * differ from the start if start is inside a non-work period.
  */
 static mrptime
+task_manager_calculate_work_done_finish (MrpTaskManager *manager,
+					 MrpTask        *task,
+					 mrptime         start)
+{
+	MrpTaskManagerPriv *priv;
+	mrptime             work_done_finish;
+	mrptime             t;
+	mrptime             t1, t2;
+	gint                work;
+	gint                work_done;
+	gint                effort;
+	gint                delta;
+	GList              *unit_ivals, *l = NULL;
+	MrpUnitsInterval   *unit_ival;
+	MrpTaskType         type;
+	MrpTaskSched        sched;
+	
+   
+	priv = manager->priv;
+
+	if (task == priv->root) {
+		g_warning ("Tried to get work_done_finish of root task.");
+		return 0;
+	}
+
+	/* Milestone tasks can be special cased, no work_done_finish. */
+	type = mrp_task_get_task_type (task);
+	if (type == MRP_TASK_TYPE_MILESTONE) {
+		return start;
+	}
+	
+	work = mrp_task_get_work (task);
+	work_done = mrp_task_get_work_done (task);
+	sched = mrp_task_get_sched (task);
+
+	/* G26: Not sure what to do for non FIXED_WORK tasks */
+	if (sched != MRP_TASK_SCHED_FIXED_WORK) {
+		return start;
+	}
+
+	effort = 0;
+
+	work_done_finish = start;
+	
+	t = mrp_time_align_day (start);
+
+	while (1) {
+		unit_ivals = task_manager_get_task_units_intervals (manager, task, t);
+
+		/* If we don't get anywhere in 100 days, then the calendar must
+		 * be broken, so we abort the scheduling of this task. It's not
+		 * the best solution but fixes the issue for now.
+		 */
+		if (effort == 0 && t - start > (60*60*24*100)) {
+			break;
+		}
+
+		if (!unit_ivals) {
+			/* Holidays for all. */
+			t += 60*60*24;
+			continue;
+		}
+		
+		for (l = unit_ivals; l; l = l->next) { 
+			unit_ival = l->data;
+
+			t1 = t + unit_ival->start;
+			t2 = t + unit_ival->end;
+			/* Skip any intervals before the task starts. */
+			if (t2 < start) {
+				continue;
+			}
+
+			/* Don't add time before the start of the task. */
+			t1 = MAX (t1, start);
+
+			if (t1 == t2) {
+				continue;
+			}
+			
+			/* Effort added by this interval. */
+			if (sched == MRP_TASK_SCHED_FIXED_WORK) {
+				delta = floor (0.5 + (double) unit_ival->units * (t2 - t1) / 100.0);
+
+				if ( (effort + delta >= work_done) ||
+				     (effort + delta >= work) ) {
+					work_done_finish = t1 + floor (0.5 + (work_done - effort) / unit_ival->units * 100.0);
+					goto done;
+				}
+			}
+			else if (sched == MRP_TASK_SCHED_FIXED_DURATION) {
+				/* G26: Not sure what work_done_finish should be for FIXED_DURATION tasks */
+			} else {
+				delta = 0;
+				g_assert_not_reached ();
+			}
+			
+			effort += delta;
+		}
+		t += 60*60*24;
+	}
+
+ done:
+	return work_done_finish;
+}
+
+/* Calculate the finish time from the work needed for the task, and the effort
+ * that the allocated resources add to the task. Uses the project calendar if no
+ * resources are allocated. This function also sets the work_start property of
+ * the task, which is the first time that actually has work scheduled, this can
+ * differ from the start if start is inside a non-work period.
+ */
+static mrptime
 task_manager_calculate_task_finish (MrpTaskManager *manager,
 				    MrpTask        *task,
 				    mrptime         start,
@@ -2134,6 +2256,25 @@
 }
 
 static void
+task_manager_recalc_work_done (MrpTaskManager *manager)
+{
+	MrpTaskManagerPriv *priv;
+	GList              *l;
+	mrptime             start;
+	mrptime             work_done_finish;
+
+	priv = manager->priv;
+	l = priv->depencency_list;
+
+	while(l) {
+		start = mrp_task_get_start (l->data);
+		work_done_finish = task_manager_calculate_work_done_finish(manager, l->data, start);
+		imrp_task_set_work_done_finish(l->data, work_done_finish);
+		l = l->next;
+	}
+}
+
+static void
 task_manager_do_backward_pass (MrpTaskManager *manager)
 {
 	MrpTaskManagerPriv *priv;
@@ -2323,6 +2464,8 @@
 	task_manager_do_forward_pass (manager, NULL);
 	task_manager_do_backward_pass (manager);
 
+	task_manager_recalc_work_done (manager);
+
 	priv->needs_recalc = FALSE;
 	priv->in_recalc = FALSE;
 }
@@ -2333,6 +2476,14 @@
 				      MrpTaskManager *manager)
 {
 	mrp_task_manager_recalc (manager, TRUE);
+}
+
+static void
+task_manager_task_work_done_notify_cb (MrpTask        *task,
+				       GParamSpec     *spec,
+				       MrpTaskManager *manager)
+{
+	task_manager_recalc_work_done (manager);
 }
 
 #ifdef WITH_SIMPLE_PRIORITY_SCHEDULING
Index: libplanner/mrp-task.c
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-task.c,v
retrieving revision 1.17
diff -u -B -r1.17 mrp-task.c
--- libplanner/mrp-task.c	19 May 2006 23:42:12 -0000	1.17
+++ libplanner/mrp-task.c	3 Jan 2007 14:20:11 -0000
@@ -39,6 +39,7 @@
 	PROP_LATEST_FINISH,
 	PROP_DURATION,
 	PROP_WORK,
+	PROP_WORK_DONE,
 	PROP_CRITICAL,
 	PROP_TYPE,
 	PROP_SCHED,
@@ -93,6 +94,10 @@
 	 */
 	gint              work;
 
+	/* The amount of work effort already spent on this task
+	 */
+	gint              work_done;
+
 	/* Calculated duration. */
 	gint              duration;
 
@@ -109,6 +114,11 @@
 	 */
 	mrptime           work_start;
 
+	/* The time upto which the work for the task has been performed. This
+	 * is calculated from work_done
+	 */
+	mrptime           work_done_finish;
+
 	/* Represents the Work Breakdown Structure tree hierarchy. */
 	GNode            *node;
 
@@ -350,6 +360,15 @@
 
 	g_object_class_install_property (
 		object_class,
+		PROP_WORK_DONE,
+		g_param_spec_int ("work_done",
+				  "Work done",
+				  "Task work already done",
+				  -1, G_MAXINT, 0,
+				  G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
 		PROP_CRITICAL,
 		g_param_spec_boolean ("critical",
 				      "Critical",
@@ -371,7 +390,7 @@
 		object_class,
 		PROP_SCHED,
 		g_param_spec_enum ("sched",
-				   "Sceduling type",
+				   "Scheduling type",
 				   "Task scheduling type",
 				   MRP_TYPE_TASK_SCHED,
 				   MRP_TASK_SCHED_FIXED_WORK,
@@ -521,6 +540,15 @@
 		}
 		break;
 
+	case PROP_WORK_DONE:
+		i_val = g_value_get_int (value);
+
+		if (priv->work_done != i_val) {
+			priv->work_done = i_val;
+			changed = TRUE;
+		}
+		break;
+
 	case PROP_CRITICAL:
 		priv->critical = g_value_get_boolean (value);
 		break;
@@ -625,6 +653,9 @@
 	case PROP_WORK:
 		g_value_set_int (value, priv->work);
 		break;
+	case PROP_WORK_DONE:
+		g_value_set_int (value, priv->work_done);
+		break;
 	case PROP_CRITICAL:
 		g_value_set_boolean (value, priv->critical);
 		break;
@@ -1497,6 +1528,23 @@
 }
 
 /**
+ * mrp_task_get_work_done_finish:
+ * @task: an #MrpTask
+ * 
+ * Retrieves the time indicating the end of the part of the task that has
+ * already been performed.
+ * 
+ * Return value: The time upto which the task has been completed.
+ **/
+mrptime
+mrp_task_get_work_done_finish (MrpTask *task)
+{
+	g_return_val_if_fail (MRP_IS_TASK (task), 0);
+	
+	return task->priv->work_done_finish;
+}
+
+/**
  * mrp_task_get_latest_start:
  * @task: an #MrpTask
  * 
@@ -1560,6 +1608,22 @@
 }
 
 /**
+ * mrp_task_get_work_done:
+ * @task: an #MrpTask
+ * 
+ * Retrieves the amount of work already done for @task.
+ * 
+ * Return value: The work already done for @task.
+ **/
+gint
+mrp_task_get_work_done (MrpTask *task)
+{
+	g_return_val_if_fail (MRP_IS_TASK (task), 0);
+	
+	return task->priv->work_done;
+}
+
+/**
  * mrp_task_get_priority:
  * @task: an #MrpTask
  * 
@@ -1894,6 +1958,14 @@
 }
 
 void
+imrp_task_set_work_done_finish (MrpTask *task, mrptime work_done_finish)
+{
+	g_return_if_fail (MRP_IS_TASK (task));
+
+	task->priv->work_done_finish = work_done_finish;
+}
+
+void
 imrp_task_set_finish (MrpTask *task, mrptime finish)
 {
 	g_return_if_fail (MRP_IS_TASK (task));
@@ -1915,6 +1987,14 @@
 	g_return_if_fail (MRP_IS_TASK (task));
 
 	task->priv->work = work;
+}
+
+void
+imrp_task_set_work_done (MrpTask *task, gint work_done)
+{
+	g_return_if_fail (MRP_IS_TASK (task));
+
+	task->priv->work_done = work_done;
 }
 
 void
Index: libplanner/mrp-task.h
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-task.h,v
retrieving revision 1.7
diff -u -B -r1.7 mrp-task.h
--- libplanner/mrp-task.h	11 Apr 2006 12:42:43 -0000	1.7
+++ libplanner/mrp-task.h	3 Jan 2007 14:20:11 -0000
@@ -117,11 +117,13 @@
 gint             mrp_task_get_position              (MrpTask          *task);
 mrptime          mrp_task_get_start                 (MrpTask          *task);
 mrptime          mrp_task_get_work_start            (MrpTask          *task);
+mrptime          mrp_task_get_work_done_finish      (MrpTask          *task);
 mrptime          mrp_task_get_finish                (MrpTask          *task);
 mrptime          mrp_task_get_latest_start          (MrpTask          *task);
 mrptime          mrp_task_get_latest_finish         (MrpTask          *task);
 gint             mrp_task_get_duration              (MrpTask          *task);
 gint             mrp_task_get_work                  (MrpTask          *task);
+gint             mrp_task_get_work_done             (MrpTask          *task);
 gint             mrp_task_get_priority              (MrpTask          *task);
 #ifdef WITH_SIMPLE_PRIORITY_SCHEDULING
 gboolean         mrp_task_is_dominant               (MrpTask          *task);
Index: src/planner-gantt-row.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-gantt-row.c,v
retrieving revision 1.31
diff -u -B -r1.31 planner-gantt-row.c
--- src/planner-gantt-row.c	12 Nov 2006 20:26:31 -0000	1.31
+++ src/planner-gantt-row.c	3 Jan 2007 14:20:13 -0000
@@ -1157,7 +1157,7 @@
 	PlannerGanttChart   *chart;
 	gdouble              i2w_dx; 
 	gdouble              i2w_dy;
-	gdouble              dx1, dy1, dx2, dy2, dshay1, dshay2;
+	gdouble              dx1, dy1, dx2, dy2, dx3, dshay1, dshay2;
 	gint                 level;
 	MrpTaskType          type;
 	gboolean             summary;
@@ -1173,7 +1173,7 @@
 #endif
 	gint                 rx1, ry1;
 	gint                 rx2, ry2;
-	gint                 cx1, cy1, cx2, cy2; 
+	gint                 cx1, cy1, cx2, cy2, cx3; 
 
 	GList               *unit_ivals, *cal_ivals, *cur_unit;
 	GList		    *cur_cal = NULL;
@@ -1203,7 +1203,7 @@
 
 	gint                 last_end;
 
-	gint                 topy,  nres, finish;
+	gint                 topy,  nres, finish, work_done_finish;
 	gdouble              delta;
 	GList               *assignments;
 
@@ -1231,6 +1231,7 @@
 	priv = row->priv;
 	project = mrp_object_get_project (MRP_OBJECT (priv->task));
 	calendar = mrp_project_get_calendar (project);
+	work_done_finish = mrp_task_get_work_done_finish (priv->task);
 
 
 	chart = g_object_get_data (G_OBJECT (item->canvas), "chart");
@@ -1262,6 +1263,8 @@
 	dy2 = priv->y + priv->bar_bot;
 
 	dx2 = MAX (dx2, dx1 + MIN_WIDTH);
+
+	dx3 = priv->scale * work_done_finish;
 	
 	dshay1 = priv->y + 0.08 * priv->height;
 	dshay2 = priv->y + 0.92 * priv->height;
@@ -1277,10 +1280,17 @@
 			  &cx2,
 			  &cy2);
 
+	gnome_canvas_w2c (item->canvas,
+			  dx3 + i2w_dx,
+			  0,
+			  &cx3,
+			  NULL);
+
 	cx1 -= x;
 	cy1 -= y;
 	cx2 -= x;
 	cy2 -= y;
+	cx3 -= x;
 	
 	if (cy1 >= cy2 || cx1 >= cx2) {
 		return;
@@ -1309,7 +1319,7 @@
 	is_dominant = mrp_task_is_dominant (priv->task);
 #endif
 	if (!summary) {
-		complete_width = floor ((cx2 - cx1) * (percent_complete / 100.0) + 0.5);
+		complete_width = cx3 - cx1;
 		complete_x2 = MIN (cx1 + complete_width, rx2);
 	}
 
@@ -2060,8 +2070,9 @@
 	 * it since it's a good optimization.
 	 */
 	else if (strcmp (pspec->name, "critical") != 0 &&
-			 strcmp (pspec->name, "priority") != 0 &&
-			 strcmp (pspec->name, "percent-complete")) {
+		 strcmp (pspec->name, "priority") != 0 &&
+		 strcmp (pspec->name, "percent-complete") != 0 &&
+		 strcmp (pspec->name, "work-done") != 0) {
 		return;
 	}
 	
Index: src/planner-task-dialog.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-task-dialog.c,v
retrieving revision 1.38
diff -u -B -r1.38 planner-task-dialog.c
--- src/planner-task-dialog.c	20 Apr 2006 00:29:54 -0000	1.38
+++ src/planner-task-dialog.c	3 Jan 2007 14:20:14 -0000
@@ -56,6 +56,7 @@
 	GtkWidget     *duration_entry;
 	GtkWidget     *schedule_label;
 	GtkWidget     *schedule_button;
+	GtkWidget     *work_done_entry;
 	GtkWidget     *complete_spinbutton;
 	GtkWidget     *priority_spinbutton;
 	GtkWidget     *note_textview;
@@ -111,6 +112,15 @@
 								   GParamSpec              *pspec,
 								   GtkWidget               *dialog);
 
+static void            task_dialog_task_work_done_changed_cb      (MrpTask                 *task,
+								   GParamSpec              *pspec,
+								   GtkWidget               *dialog);
+static gboolean        task_dialog_work_done_focus_in_cb          (GtkWidget               *w,
+								   GdkEventFocus           *event,
+								   DialogData              *data);
+static gboolean        task_dialog_work_done_focus_out_cb         (GtkWidget               *w,
+								   GdkEventFocus           *event,
+								   DialogData              *data);
 static void            task_dialog_task_complete_changed_cb       (MrpTask                 *task,
 								   GParamSpec              *pspec,
 								   GtkWidget               *dialog);
@@ -1512,6 +1522,85 @@
 }	
 
 static void
+task_dialog_task_work_done_changed_cb (MrpTask    *task, 
+				       GParamSpec *pspec,
+				       GtkWidget  *dialog)
+{
+	DialogData *data;
+	MrpProject *project;
+	gint        work_done;
+	gchar      *str;
+
+	data = DIALOG_GET_DATA (dialog);
+
+	g_object_get (task,
+		      "work_done", &work_done,
+		      "project", &project,
+		      NULL);
+
+	str = planner_format_duration (project, work_done);
+	gtk_entry_set_text (GTK_ENTRY (data->work_done_entry), str);
+	g_free (str);
+}
+
+static gboolean
+task_dialog_work_done_focus_out_cb (GtkWidget     *w,
+				    GdkEventFocus *event,
+				    DialogData    *data)
+{
+	MrpProject   *project;
+	gint          current_work_done;
+	gint          focus_in_work_done;
+	GValue        value = { 0 };
+	PlannerCmd   *cmd;
+
+	g_object_get (data->task, "project", &project, NULL);
+	
+	focus_in_work_done = GPOINTER_TO_INT (
+		g_object_get_data (G_OBJECT (data->task), "focus_in_work_done"));
+
+	current_work_done = planner_parse_duration (
+		project, gtk_entry_get_text (GTK_ENTRY (w)));
+	
+	if (focus_in_work_done == current_work_done) {
+		return FALSE;
+	}
+
+	g_object_set (data->task, "work_done", current_work_done, NULL);
+
+	g_value_init (&value, G_TYPE_INT);
+	g_value_set_int (&value, focus_in_work_done);
+	
+	cmd = task_cmd_edit_property_focus (data->main_window, 
+					    data->task, "work_done",
+					    &value);
+
+	return FALSE;
+}
+
+static gboolean
+task_dialog_work_done_focus_in_cb (GtkWidget     *w,
+				   GdkEventFocus *event,
+				   DialogData    *data)
+{
+	MrpProject  *project;
+	const gchar *str;
+	gint         work_done;
+	   
+	str = gtk_entry_get_text (GTK_ENTRY (w));
+
+	g_object_get (data->task, "project", &project, NULL);
+	
+	work_done = planner_parse_duration (project, str);
+	
+	g_object_set_data (G_OBJECT (data->task), 
+			   "focus_in_work_done",
+			   GINT_TO_POINTER (work_done));
+	
+	return FALSE;
+}
+
+static void
 task_dialog_task_complete_changed_cb (MrpTask    *task, 
 				      GParamSpec *pspec,
 				      GtkWidget  *dialog)
@@ -2474,6 +2563,20 @@
 			  G_CALLBACK (task_dialog_schedule_popdown_cb),
 			  data);
 
+	data->work_done_entry = glade_xml_get_widget (glade, "work_done_entry");
+	g_object_get (data->task, "work_done", &int_value, NULL);
+	str = planner_format_duration (mrp_object_get_project (MRP_OBJECT (data->task)), int_value);
+	gtk_entry_set_text (GTK_ENTRY (data->work_done_entry), str);
+	g_free (str);
+	g_signal_connect (data->work_done_entry,
+			  "focus_in_event",
+			  G_CALLBACK (task_dialog_work_done_focus_in_cb),
+			  data);
+	g_signal_connect (data->work_done_entry,
+			  "focus_out_event",
+			  G_CALLBACK (task_dialog_work_done_focus_out_cb),
+			  data);
+	
 	data->complete_spinbutton = glade_xml_get_widget (glade, "complete_spinbutton");
 	g_object_get (data->task, "percent_complete", &int_value, NULL);
 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->complete_spinbutton), int_value);
@@ -2801,6 +2904,12 @@
 				 0);
 
 	g_signal_connect_object (data->task,
+				 "notify::work-done",
+				 G_CALLBACK (task_dialog_task_work_done_changed_cb),
+				 data->dialog,
+				 0);
+
+	g_signal_connect_object (data->task,
 				 "notify::percent-complete",
 				 G_CALLBACK (task_dialog_task_complete_changed_cb),
 				 data->dialog,
@@ -2873,6 +2982,7 @@
 	
 	gtk_widget_set_sensitive (data->duration_entry, leaf && !milestone && fixed);
 	gtk_widget_set_sensitive (data->work_entry, leaf && !milestone);
+	gtk_widget_set_sensitive (data->work_done_entry, leaf && !milestone);
 }
 
 static void

Attachment: pgphGdPyqrEMc.pgp
Description: PGP signature



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]