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