[Planner Dev] Fixes for gantt bugz # 148637, 149359 and 149651
- From: "lincoln phipps openmutual net" <lincoln phipps openmutual net>
- To: Planner Project Manager - Development List <planner-dev lists imendio com>
- Subject: [Planner Dev] Fixes for gantt bugz # 148637, 149359 and 149651
- Date: Mon, 09 Aug 2004 09:08:02 +0100
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]