[Planner Dev] lag & more



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]