[Planner Dev] Fixes for gantt bugz # 148637, 149359 and 149651




The attached patch fixes these bugs,

http://bugzilla.gnome.org/show_bug.cgi?id=148637
http://bugzilla.gnome.org/show_bug.cgi?id=149359
http://bugzilla.gnome.org/show_bug.cgi?id=149651

they were sort of all interrelated.

Basically dragging a task in gantt had a few quirks,

There was no undo for the work change,
When you had a task around the year 2038 (Unix signed 32bit
	end of time) it didn't render correctly,
Work would not be correctly calculated for tasks
	around 1400 days onwards (1 resource),
You could grow a task beyond 10,000 days of work (this is
	the max	in the task dialog).

Note that for fixed duration tasks the drag on gantt drags
the WORK out, though the duration stays at what it was
set to before. We'll have to try some modifiers like
shift-drag or something to adjust duration.


Rgds,
Lincoln.




Index: libplanner/mrp-task-manager.c
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-task-manager.c,v
retrieving revision 1.10
diff -u -B -b -p -r1.10 mrp-task-manager.c
--- libplanner/mrp-task-manager.c	2 Aug 2004 22:47:19 -0000	1.10
+++ libplanner/mrp-task-manager.c	9 Aug 2004 07:46:56 -0000
@@ -2165,11 +2165,12 @@ mrp_task_manager_calculate_task_work (Mr
 				      mrptime         finish)
 {
 	MrpTaskManagerPriv *priv;
-	gint                work = 0;
+	gint                work = 0, this_work = 0;
 	MrpAssignment      *assignment;
 	MrpResource        *resource;
 	GList              *assignments, *a;
-	MrpCalendar        *calendar;
+	MrpCalendar        *calendar = NULL, *last_calendar = NULL;
+       gint                units = 0, last_units = 0;
 
 	priv = manager->priv;
 
@@ -2194,9 +2195,23 @@ mrp_task_manager_calculate_task_work (Mr
 	 */
 
 	assignments = mrp_task_get_assignments (task);
+
+	if (!assignments) {
+		calendar = mrp_project_get_calendar (priv->project);
+
+		work = task_manager_get_work_for_calendar (manager,
+							   calendar,
+							   start,
+							   finish);
+	} else {
 	for (a = assignments; a; a = a->next) {
 		assignment = a->data;
 
+                        last_units = units;
+                        last_calendar = calendar;
+                        
+                        units = mrp_assignment_get_units (assignment);
+                        
 		resource = mrp_assignment_get_resource (assignment);
 
 		calendar = mrp_resource_get_calendar (resource);
@@ -2204,20 +2219,24 @@ mrp_task_manager_calculate_task_work (Mr
 			calendar = mrp_project_get_calendar (priv->project);
 		}
 
-		work += task_manager_get_work_for_calendar (manager,
-							    calendar,
-							    start,
-							    finish) *
-			mrp_assignment_get_units (assignment) / 100;
-	}
-	
-	if (!assignments) {
-		calendar = mrp_project_get_calendar (priv->project);
+	/* A simple check to see if the last calendar and units is the same as this    */
+        /* calendar and units. If so then resuse last calculated work value. This MAY  */
+        /* help speed up gantt if we have multiple resources on this task.             */
+        /* TODO: Ideally we should cache the work calculations based on a key of ....  */
+        /* manager, calendar, start, finish, units */
+        
+		        if (last_calendar == calendar && last_units == units) {
+        	                work += this_work;                                          
+		        } else {
 
-		work = task_manager_get_work_for_calendar (manager,
+	/* Maths done this way to make sure we don't have an integer OVERFLOW on large workloads */
+			this_work = (task_manager_get_work_for_calendar (manager,
 							   calendar,
 							   start,
-							   finish);
+								    finish) / 100.0) * units;
+			work += this_work;
+		        }
+                }
 	}
 
 	return work;
Index: libplanner/mrp-time.h
===================================================================
RCS file: /cvs/gnome/planner/libplanner/mrp-time.h,v
retrieving revision 1.1.1.1
diff -u -B -b -p -r1.1.1.1 mrp-time.h
--- libplanner/mrp-time.h	1 Dec 2003 17:36:21 -0000	1.1.1.1
+++ libplanner/mrp-time.h	9 Aug 2004 07:46:56 -0000
@@ -33,6 +33,7 @@ typedef long mrptime;
 #define MRP_TIME_INVALID 0
 #define MRP_TIME_MIN 0
 #define MRP_TIME_MAX 2147483647
+#define MRP_WORK_MAX 288000000 
 
 mrptime      mrp_time_current_time       (void);
 
Index: src/planner-gantt-header.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-gantt-header.c,v
retrieving revision 1.2
diff -u -B -b -p -r1.2 planner-gantt-header.c
--- src/planner-gantt-header.c	11 Dec 2003 10:52:46 -0000	1.2
+++ src/planner-gantt-header.c	9 Aug 2004 07:47:00 -0000
@@ -498,7 +498,7 @@ gantt_header_expose_event (GtkWidget    
 	PlannerGanttHeader     *header;
 	PlannerGanttHeaderPriv *priv;
 	gint               width, height;
-	gdouble            hscale;
+	gdouble            hscale, tresult;
 	gint               x;
 	mrptime            t0;
 	mrptime            t1;
@@ -508,13 +508,27 @@ gantt_header_expose_event (GtkWidget    
 	gint               major_width;
 	GdkGC             *gc;
 	GdkRectangle       rect;
+        gboolean           overflow;
 	
 	header = PLANNER_GANTT_HEADER (widget);
 	priv = header->priv;
 	hscale = priv->hscale;
 
-	t0 = floor ((priv->x1 + event->area.x) / hscale + 0.5);
-	t1 = floor ((priv->x1 + event->area.x + event->area.width) / hscale + 0.5);
+        /* FIXME: This wraps at around year 2038 due to use of signed 32 bit fields */
+        
+        tresult = floor ((priv->x1 + event->area.x) / hscale + 0.5);
+        if (tresult >= MRP_TIME_MAX) {
+                t0 = MRP_TIME_MAX - event->area.width;
+        } else { 
+                t0 = tresult;
+        }
+        
+        tresult = floor ((priv->x1 + event->area.x + event->area.width) / hscale + 0.5);
+        if (tresult >= MRP_TIME_MAX) {
+                t1 = MRP_TIME_MAX;
+        } else {
+                t1 = tresult;
+        }
 
 	gdk_drawable_get_size (event->window, &width, &height);
 
@@ -562,8 +576,10 @@ gantt_header_expose_event (GtkWidget    
 	}
 	
 	t = planner_scale_time_prev (t0, priv->major_unit);
+        overflow = FALSE;
+	
+	while (t <= t1 && !overflow) {
 	
-	while (t <= t1) {
 		x = floor (t * hscale - priv->x1 + 0.5);
 		
 		gdk_draw_line (event->window,
@@ -590,6 +606,9 @@ gantt_header_expose_event (GtkWidget    
 				 priv->layout);
 		
 		t = planner_scale_time_next (t, priv->major_unit);
+                if ( t < t0 ) {  /* The overflow detector that scales for all ranges */
+                        overflow = TRUE;
+                }
 	}
 
  minor_ticks:
@@ -601,8 +620,10 @@ gantt_header_expose_event (GtkWidget    
 	}
 	
 	t = planner_scale_time_prev (t0, priv->minor_unit);
+        overflow = FALSE;
+
+	while (t <= t1 && !overflow) {
 
-	while (t <= t1) {
 		x = floor (t * hscale - priv->x1 + 0.5);
 
 		gdk_draw_line (event->window,
@@ -629,6 +650,9 @@ gantt_header_expose_event (GtkWidget    
 				 priv->layout);
 
 		t = planner_scale_time_next (t, priv->minor_unit);
+                if ( t < t0 ) {  /* The overflow detector thats fine for all ranges */
+                        overflow = TRUE;
+                }
 	}
 
  done:
Index: src/planner-gantt-row.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-gantt-row.c,v
retrieving revision 1.19
diff -u -B -b -p -r1.19 planner-gantt-row.c
--- src/planner-gantt-row.c	31 Jul 2004 21:32:54 -0000	1.19
+++ src/planner-gantt-row.c	9 Aug 2004 07:47:01 -0000
@@ -4,6 +4,7 @@
  * Copyright (C) 2001-2003 CodeFactory AB
  * Copyright (C) 2001-2003 Richard Hult <richard imendio com>
  * Copyright (C) 2001-2003 Mikael Hallendal <micke imendio com>
+ * Copyright (C) 2004 Lincoln Phipps <lincoln phipps openmutual net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -135,6 +136,13 @@ struct _PlannerGanttRowPriv {
 	GtkItemFactory *popup_factory;
 };
 
+typedef struct {
+	PlannerCmd      base;
+       MrpTask         *task;
+       gint            work;
+	gint            old_work;
+} GanttRowCmdEditWork;
+
 static void     gantt_row_class_init                  (PlannerGanttRowClass  *class);
 static void     gantt_row_init                        (PlannerGanttRow       *row);
 static void     gantt_row_destroy                     (GtkObject             *object);
@@ -206,7 +214,12 @@ static gboolean gantt_row_get_resource_b
 						       gint                   index,
 						       gint                  *x1,
 						       gint                  *x2);
-
+static PlannerCmd *gantt_row_cmd_edit_work            (PlannerWindow         *main_window,
+                                                       MrpTask               *task,
+			                               gint                  work);
+static gboolean   gantt_row_cmd_edit_work_do          (PlannerCmd            *cmd_base);
+static void       gantt_row_cmd_edit_work_undo        (PlannerCmd            *cmd_base);
+static void       gantt_row_cmd_edit_work_free        (PlannerCmd            *cmd_base);
 
 
 static GnomeCanvasItemClass *parent_class;
@@ -1677,7 +1690,13 @@ gantt_row_event (GnomeCanvasItem *item, 
 		if (event->motion.is_hint) {
 			gint x, y;
 
+                        /* FIXME: Certain weird conditions can cause x value to drop by 1/2. This */
+                        /*        happens on large work values e.g. 9000 days and when the end is */
+                        /*        dragged to the border of your screen (i.e far right side) and   */
+                        /*        happens when the pointer exceeds the window size.               */
+                        
 			gdk_window_get_pointer (event->motion.window, &x, &y, NULL);
+                                                
 			gnome_canvas_c2w (item->canvas, x, y, &event->motion.x, &event->motion.y);
 		}
 
@@ -1782,6 +1801,7 @@ gantt_row_event (GnomeCanvasItem *item, 
 			MrpProject  *project;
 			MrpCalendar *calendar;
 			gint         hours_per_day;
+                        mrptime      start, end, safe_max;
 
 			project = mrp_object_get_project (MRP_OBJECT (priv->task));
 			calendar = mrp_project_get_calendar (project);
@@ -1810,11 +1830,30 @@ gantt_row_event (GnomeCanvasItem *item, 
 			/* Snap to quarters. */
 			duration = floor (duration / SNAP + 0.5) * SNAP;
 
+                        start = mrp_task_get_start (priv->task);
+                        
+                        /* FIXME: We can't go beyond 2038 on some systems. Need unsigned 32 or 64 bit time handling. */
+                        /*        We do maths this way to avoid wrapping signed longs.                               */
+                        /*        The safe_floor keeps the task end away from the end of the unix dates else it      */
+                        /*        hits up against the gantt header end time.                                         */
+                        
+                        safe_max = floor (MRP_TIME_MAX / SNAP) * SNAP - (18 * 24 * 60 * 60 + 3 * 60 * 60);
+                                                
+                        if ((safe_max - duration) <= start) {
+                                end = safe_max;
+                        } else {
+                                end = start + duration;
+                        }
+                                                
 			work = mrp_project_calculate_task_work (
 				project,
 				priv->task,
 				-1,
-				mrp_task_get_start (priv->task) + duration);
+				end);
+
+                        if (work > MRP_WORK_MAX) {
+                                work = MRP_WORK_MAX;
+                        }
 
 			message = g_strdup_printf (
 				_("Change work to %s"),
@@ -1841,6 +1880,9 @@ gantt_row_event (GnomeCanvasItem *item, 
 			MrpProject *project;
 			gint        duration;
 			gint        work;
+                        PlannerWindow     *main_window;
+                        PlannerCmd        *cmd;
+                        mrptime           start, end, safe_max;
 
 			project = mrp_object_get_project (MRP_OBJECT (priv->task));
 			
@@ -1848,22 +1890,38 @@ gantt_row_event (GnomeCanvasItem *item, 
 			/* Snap to quarters. */
 			duration = floor (duration / SNAP + 0.5) * SNAP;
 
+                        start = mrp_task_get_start (priv->task);
+                                      
+                        safe_max = floor (MRP_TIME_MAX / SNAP) * SNAP - (18 * 24 * 60 * 60 + 3 * 60 * 60);
+                                  
+                        if ((safe_max - duration) <= start) {
+                                end = safe_max;
+                        } else {
+                                end = start + duration;
+                        }
+                                                
 			work = mrp_project_calculate_task_work (
 				project,
 				priv->task,
 				-1,
-				mrp_task_get_start (priv->task) + duration);
+				end);
 			
-			g_object_set (priv->task,
-				      "work", work,
-				      NULL);
-
-			gtk_object_destroy (GTK_OBJECT (drag_item));
-			drag_item = NULL;
+                        if (work > MRP_WORK_MAX) {
+                                work = MRP_WORK_MAX;
+                        }
 
 			chart = g_object_get_data (G_OBJECT (item->canvas),
 						   "chart");
 
+                        main_window = planner_task_tree_get_window ( planner_gantt_chart_get_view (chart));
+                        
+                        cmd = gantt_row_cmd_edit_work (main_window,
+                                                       priv->task, 
+                                                       work);
+        
+			gtk_object_destroy (GTK_OBJECT (drag_item));
+			drag_item = NULL;
+                                                   
 			planner_gantt_chart_status_updated (chart, NULL);
 		}
 		else if (priv->state == STATE_DRAG_LINK) {
@@ -2290,3 +2348,70 @@ planner_gantt_row_init_menu (PlannerGant
 		}
 
 #endif
+
+/* UNDO/REDO routines */
+
+static gboolean
+gantt_row_cmd_edit_work_do (PlannerCmd *cmd_base)
+{
+	GanttRowCmdEditWork *cmd;
+	
+	cmd = (GanttRowCmdEditWork*) cmd_base;
+
+	g_object_set (cmd->task,
+		      "work", cmd->work,
+		      NULL);
+
+	return TRUE;
+}
+
+static void
+gantt_row_cmd_edit_work_undo (PlannerCmd *cmd_base)
+{
+	GanttRowCmdEditWork *cmd;
+	
+	cmd = (GanttRowCmdEditWork*) cmd_base;
+
+	g_object_set (cmd->task,
+		      "work", cmd->old_work,
+		      NULL);
+}
+
+static void
+gantt_row_cmd_edit_work_free (PlannerCmd *cmd_base)
+{
+	GanttRowCmdEditWork *cmd;
+	
+	cmd = (GanttRowCmdEditWork*) cmd_base;
+
+	g_object_unref (cmd->task);
+
+}
+
+static PlannerCmd *
+gantt_row_cmd_edit_work (PlannerWindow  *main_window,
+                         MrpTask        *task,
+			 gint           work)
+{
+	PlannerCmd          *cmd_base;
+	GanttRowCmdEditWork *cmd;
+
+	cmd_base = planner_cmd_new (GanttRowCmdEditWork,
+				    _("Edit task work"),
+				    gantt_row_cmd_edit_work_do,
+				    gantt_row_cmd_edit_work_undo,
+				    gantt_row_cmd_edit_work_free);
+
+	cmd = (GanttRowCmdEditWork *) cmd_base;
+    
+        cmd->task = g_object_ref (task);
+        cmd->work = work;
+	g_object_get (task,
+		      "work", &cmd->old_work,
+                      NULL);
+                      
+	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (main_window),
+					   cmd_base);
+	
+	return cmd_base;
+}


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