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