[Planner Dev] lag & more
- From: Andrej Vodopivec <Andrej Vodopivec ids si>
- To: planner-dev lists imendio com
- Subject: [Planner Dev] lag & more
- Date: Sat, 28 Aug 2004 15:13:14 +0200
I am back from vacation.
Find attached the patch to fix the lag problem and my test case.
Regards
Andrej
Index: libplanner/mrp-task-manager.c
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-task-manager.c,v
retrieving revision 1.11
diff -u -r1.11 mrp-task-manager.c
--- libplanner/mrp-task-manager.c 9 Aug 2004 12:42:45 -0000 1.11
+++ libplanner/mrp-task-manager.c 28 Aug 2004 12:59:06 -0000
@@ -23,6 +23,7 @@
*/
#include <config.h>
+#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <glib-object.h>
@@ -112,6 +113,11 @@
static void
task_manager_dump_task_tree (GNode *node);
+static mrptime
+task_manager_calculate_lap (MrpTaskManager *manager,
+ MrpTask *task,
+ mrptime start,
+ gint lag);
static GObjectClass *parent_class;
@@ -1102,12 +1108,14 @@
* allows given.
*/
static mrptime
-task_manager_calc_relation (MrpTask *task,
- MrpRelation *relation,
- MrpTask *predecessor)
+task_manager_calc_relation (MrpTaskManager *manager,
+ MrpTask *task,
+ MrpRelation *relation,
+ MrpTask *predecessor)
{
MrpRelationType type;
- mrptime time;
+ gint lag;
+ mrptime t1, time;
/*mrptime start, finish;*/
/* FIXME: This does not work correctly for FF and SF. The problem is
@@ -1116,6 +1124,7 @@
*/
type = mrp_relation_get_relation_type (relation);
+ lag = mrp_relation_get_lag (relation);
switch (type) {
#if 0
@@ -1140,16 +1149,16 @@
#endif
case MRP_RELATION_SS:
/* start-to-start */
- time = mrp_task_get_start (predecessor) +
- mrp_relation_get_lag (relation);
+ t1 = mrp_task_get_start (predecessor);
+ time = task_manager_calculate_lap (manager, task, t1, lag);
break;
case MRP_RELATION_FS:
case MRP_RELATION_NONE:
default:
/* finish-to-start */
- time = mrp_task_get_finish (predecessor) +
- mrp_relation_get_lag (relation);
+ t1 = mrp_task_get_finish (predecessor);
+ time = task_manager_calculate_lap (manager, task, t1, lag);
break;
}
@@ -1185,7 +1194,7 @@
relation = l->data;
predecessor = mrp_relation_get_predecessor (relation);
- dep_start = task_manager_calc_relation (task,
+ dep_start = task_manager_calc_relation (manager, task,
relation,
predecessor);
@@ -1409,6 +1418,106 @@
return g_list_reverse (unit_ivals);
}
+/* Calculate the new start time from the lag needed for the task.
+ * Uses the project calendar.
+ * This is a modification of task_manager_calculate_task_finish
+ */
+static mrptime
+task_manager_calculate_lap (MrpTaskManager *manager,
+ MrpTask *task,
+ mrptime start,
+ gint lag)
+{
+ mrptime finish;
+ mrptime t, t1, t2;
+ gint effort;
+ gint delta;
+ GList *unit_ivals, *l;
+ UnitsInterval *unit_ival;
+ MrpTaskType type;
+ gint sign = (lag > 0) ? 1 : -1;
+
+ type = mrp_task_get_task_type (task);
+ if (type == MRP_TASK_TYPE_MILESTONE) {
+ return start;
+ }
+ if (! lag) {
+ return start;
+ }
+
+ effort = 0;
+ 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 > abs(60*60*24*100)) {
+ break;
+ }
+
+ if (!unit_ivals) {
+ t += sign*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/after the task starts. */
+ if ((lag > 0 && t2 < start ) ||
+ (lag < 0 && t1 > start)) {
+ continue;
+ }
+
+ /* Don't add time before/after the start of the task. */
+ if (lag > 0) {
+ t1 = MAX (t1, start);
+ } else {
+ t2 = MIN (t2, start);
+ }
+
+ if (t1 == t2) {
+ continue;
+ }
+
+ if (lag > 0) {
+ delta = t2 - t1;
+ } else {
+ delta = t1 - t2;
+ }
+
+ if ((lag > 0 && effort + delta >= lag) ||
+ (lag < 0 && effort + delta <= lag)) {
+ /* Done, make sure we don't spill. */
+ if (lag > 0) {
+ finish = t1 + lag - effort;
+ } else {
+ finish = t2 + lag - effort;
+ }
+ goto done;
+ }
+
+ effort += delta;
+ }
+
+ t += sign*60*60*24;
+ }
+
+ done:
+ g_list_foreach (unit_ivals, (GFunc) g_free, NULL);
+ g_list_free (unit_ivals);
+
+ return 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.
Index: src/planner-format.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-format.c,v
retrieving revision 1.2
diff -u -r1.2 planner-format.c
--- src/planner-format.c 9 Aug 2004 12:42:45 -0000 1.2
+++ src/planner-format.c 28 Aug 2004 12:59:06 -0000
@@ -130,24 +130,59 @@
planner_format_duration (gint duration,
gint day_length)
{
- gint days;
- gint hours;
-
- days = duration / (60*60*day_length);
- duration -= days * 60*60*day_length;
+ gint weeks = 0;
+ gint days = 0;
+ gint hours = 0;
+ /* FIXME: get this as a parameter or from the calandar */
+ gint week_length = 5;
+ gint negative = 0;
+ /* FIXME: get this from preferences */
+ gchar preferences_display_time_unit = 'd';
+ gchar display_time_unit = preferences_display_time_unit;
+ GString *string;
+ gchar *str0, *str;
+
+ if (duration < 0) {
+ duration = -duration;
+ negative = 1;
+ }
+ if (display_time_unit == 'w') {
+ weeks = duration / (60*60*day_length*week_length);
+ duration -= weeks * 60*60*day_length*week_length;
+ }
+ if (display_time_unit == 'w' || display_time_unit == 'd') {
+ days = duration / (60*60*day_length);
+ duration -= days * 60*60*day_length;
+ }
hours = duration / (60*60);
- if (days > 0 && hours > 0) {
- return g_strdup_printf (_("%dd %dh"), days, hours);
+ string = g_string_new ("");
+ if (weeks > 0) {
+ g_string_append_printf (string, "%dw", weeks);
+ }
+ if (days > 0) {
+ if (strlen(string->str)) {
+ g_string_append_c (string, ' ');
+ }
+ g_string_append_printf (string, "%dd", days);
}
- else if (days > 0) {
- return g_strdup_printf (_("%dd"), days);
+ if (hours > 0) {
+ if (strlen(string->str)) {
+ g_string_append_c (string, ' ');
+ }
+ g_string_append_printf (string, "%dh", hours);
}
- else if (hours > 0) {
- return g_strdup_printf (_("%dh"), hours);
- } else {
- return g_strdup ("");
+ str0 = string->str;
+ g_string_free (string, FALSE);
+
+ if (! negative) {
+ return str0;
}
+
+ str = g_strconcat ("-", str0, NULL);
+ g_free (str0);
+
+ return str;
}
#if 0
Index: src/planner-task-dialog.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-task-dialog.c,v
retrieving revision 1.27
diff -u -r1.27 planner-task-dialog.c
--- src/planner-task-dialog.c 9 Aug 2004 12:42:45 -0000 1.27
+++ src/planner-task-dialog.c 28 Aug 2004 12:59:09 -0000
@@ -31,6 +31,7 @@
#include <gtk/gtk.h>
#include <libplanner/mrp-object.h>
#include <libplanner/mrp-project.h>
+#include "planner-format.h"
#include "planner-cell-renderer-list.h"
#include "planner-assignment-model.h"
#include "planner-predecessor-model.h"
@@ -2014,6 +2015,75 @@
}
}
+/* FIXME: see Bug 132357; Additional Comment #4 From Lincoln Phipps.
+ * MUST handle negative numbers
+ */
+static gint
+copy_of_task_tree_parse_time_string (GtkTreeView *tree,
+ const gchar *input)
+{
+ gchar *tmp;
+ gchar *str;
+ gchar *freeme;
+ gchar *end_ptr;
+ gdouble dbl;
+ gint negative = 0;
+ gint total;
+
+ tmp = g_utf8_casefold (input, -1);
+ /* Not sure this is necessary... */
+ str = g_utf8_normalize (tmp, -1, G_NORMALIZE_DEFAULT);
+ g_free (tmp);
+ freeme = str;
+
+ total = 0;
+ while (*str && g_unichar_isspace (g_utf8_get_char (str))) {
+ str = g_utf8_next_char (str);
+ }
+
+ if (*str == '-') {
+ negative = 1;
+ str = g_utf8_next_char (str);
+ }
+
+ while (*str) {
+ while (*str && g_unichar_isalpha (g_utf8_get_char (str))) {
+ str = g_utf8_next_char (str);
+ }
+
+ if (*str == 0) {
+ break;
+ }
+
+ dbl = g_strtod (str, &end_ptr);
+
+ if (end_ptr == str) {
+ break;
+ }
+
+ if (end_ptr) {
+ switch (*end_ptr) {
+ case 'd' : total += (gint) dbl * 60*60*8; break;
+ case 'w' : total += (gint) dbl * 60*60*8*5; break;
+ default : total += (gint) dbl * 60*60; break;
+ }
+ }
+
+ if (*end_ptr == 0) {
+ break;
+ }
+
+ str = end_ptr + 1;
+ }
+
+ g_free (freeme);
+
+ if (negative) {
+ total = -total;
+ }
+ return total;
+}
+
static void
task_dialog_pred_cell_edited (GtkCellRendererText *cell,
gchar *path_str,
@@ -2032,7 +2102,7 @@
PlannerCellRendererList *planner_cell;
gint column;
GList *tasks;
- gint lag;
+ gint lag, new_lag;
MrpRelationType type, new_type;
tree = GTK_TREE_VIEW (data->predecessor_list);
@@ -2137,7 +2207,8 @@
break;
}
case PREDECESSOR_COL_LAG:
- task_cmd_edit_lag (data->main_window, relation, 60*60 * atoi (new_text));
+ new_lag = copy_of_task_tree_parse_time_string (tree, new_text);
+ task_cmd_edit_lag (data->main_window, relation, new_lag);
break;
default:
@@ -2502,15 +2573,30 @@
GtkTreeIter *iter,
DialogData *data)
{
- GValue value = { 0 };
- gchar *ret;
+ MrpTask *task = data->task;
+ MrpProject *project;
+ gint hours_per_day;
+ GValue value = { 0 };
+ gchar *ret;
+
+ /* rewritten after task_tree_work_data_func (planner-task-tree.c) */
+ project = mrp_object_get_project (MRP_OBJECT (task));
+
+ hours_per_day = mrp_calendar_day_get_total_work (
+ mrp_project_get_calendar (project),
+ mrp_day_get_work ()) / (60*60);
+
+ /* FIXME */
+ if (hours_per_day == 0) {
+ hours_per_day = 8;
+ }
gtk_tree_model_get_value (tree_model,
iter,
PREDECESSOR_COL_LAG,
&value);
- ret = g_strdup_printf ("%d", g_value_get_int (&value) / (60*60));
+ ret = planner_format_duration (g_value_get_int (&value), hours_per_day);
g_object_set (cell, "text", ret, NULL);
g_value_unset (&value);
<?xml version="1.0"?>
<project name="" company="" manager="" phase="" project-start="20040828T000000Z" mrproject-version="2" calendar="1">
<properties>
<property name="cost" type="cost" owner="resource" label="Cost" description="standard cost for a resource"/>
</properties>
<phases/>
<calendars>
<day-types>
<day-type id="0" name="Working" description="A default working day"/>
<day-type id="1" name="Nonworking" description="A default non working day"/>
<day-type id="2" name="Use base" description="Use day from base calendar"/>
</day-types>
<calendar id="1" name="Default">
<default-week mon="0" tue="0" wed="0" thu="0" fri="0" sat="1" sun="1"/>
<overridden-day-types>
<overridden-day-type id="0">
<interval start="0800" end="1200"/>
<interval start="1300" end="1700"/>
</overridden-day-type>
</overridden-day-types>
<days/>
</calendar>
</calendars>
<tasks>
<task id="1" name="start" note="" work="288000" start="20040828T000000Z" end="20040910T170000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"/>
<task id="2" name="lag1S+3d" note="" work="288000" start="20040901T170000Z" end="20040915T170000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors>
<predecessor id="1" predecessor-id="1" type="SS" lag="86400"/>
</predecessors>
</task>
<task id="3" name="lag1F+2d" note="" work="288000" start="20040914T170000Z" end="20040928T170000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors>
<predecessor id="1" predecessor-id="1" type="FS" lag="57600"/>
</predecessors>
</task>
<task id="4" name="lag3F-2d" note="" work="288000" start="20040909T130000Z" end="20040923T120000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors>
<predecessor id="1" predecessor-id="1" type="FS" lag="-57600"/>
</predecessors>
</task>
<task id="5" name="lag3F-1w" note="" work="288000" start="20040906T130000Z" end="20040920T120000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors>
<predecessor id="1" predecessor-id="1" type="FS" lag="-144000"/>
</predecessors>
</task>
</tasks>
<resource-groups/>
<resources/>
<allocations/>
</project>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]