[Planner Dev] Fourth patch for task undo removal: assingments also - Problem with gantt widget?



Hi guys!

This patch makes the other three previous versions not needed.  

I have finished the recover also of the assignments when you remove a
task. Playing with this implementation and testing it I have found some
crashes of planner when I assing resources to a task using less than 100
units, and trying to remove the task later.

To try to reproduce it I have attached a planner file. Select the task,
change the units for a resource assignment to the task and try to remove
it. I will play a little more to try to find more about it, but it seems
something at low level, in the darkness ;-)

With Planner 0.11, ups it's horrible to use planner without undo support
:), it seems to work, but when you change the units for a resource in a
task, the gantt chart isn't updated so it seems it has been modified the
code since 0.11.

The backtrace of the core dumps says:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 16384 (LWP 12939)]
0x40a1c2c9 in gtk_widget_destroy () from /usr/lib/libgtk-x11-2.0.so.0
(gdb) bt
#0  0x40a1c2c9 in gtk_widget_destroy () from
/usr/lib/libgtk-x11-2.0.so.0
#1  0x40e5d212 in g_cclosure_marshal_VOID__VOID () from
/usr/lib/libgobject-2.0.so.0
#2  0x40e4ca92 in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
#3  0x40e5cda6 in g_signal_emit_by_name () from
/usr/lib/libgobject-2.0.so.0
#4  0x40e5bec2 in g_signal_emit_valist () from
/usr/lib/libgobject-2.0.so.0
#5  0x40e5c0d6 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0
#6  0x40024205 in mrp_object_removed (object=0x8264a58) at
mrp-object.c:347
#7  0x40028656 in mrp_project_remove_task (project=0x80e97a0,
task=0x8264a58) at mrp-project.c:1733
#8  0x41233e4a in task_cmd_remove_do (cmd_base=0x8299068) at
planner-task-tree.c:605
#9  0x08062cf5 in cmd_manager_insert (manager=0x80e6428, cmd=0x8299068,
run_do=1) at planner-cmd-manager.c:312

Cheers
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/planner/ChangeLog,v
retrieving revision 1.79
diff -u -b -B -p -r1.79 ChangeLog
--- ChangeLog	29 Mar 2004 15:18:08 -0000	1.79
+++ ChangeLog	3 Apr 2004 17:21:06 -0000
@@ -1,3 +1,9 @@
+2004-04-03 Alvaro del Castillo  <acs barrapunto com>
+
+	* src/planner-task-tree.c: implemented task remove undo
+	Currently recovers the task, the position in the tasks tree 
+	the task relations and the resources assignments.
+
 2004-03-29  Richard Hult  <richard imendio com>
 
 	* libplanner/mrp-old-xml.c (old_xml_read_assignment): Be more
Index: src/planner-task-tree.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-task-tree.c,v
retrieving revision 1.14
diff -u -b -B -p -r1.14 planner-task-tree.c
--- src/planner-task-tree.c	28 Mar 2004 23:03:49 -0000	1.14
+++ src/planner-task-tree.c	3 Apr 2004 17:21:15 -0000
@@ -152,6 +152,9 @@ static gint        task_tree_parse_time_
 static MrpProject *task_tree_get_project               (PlannerTaskTree      *tree);
 static MrpTask *   task_tree_get_task_from_path        (PlannerTaskTree      *tree,
 							GtkTreePath          *path);
+static PlannerCmd *task_cmd_remove                     (PlannerTaskTree      *tree,
+							GtkTreePath          *path,
+							MrpTask              *task);
 
 
 static GtkTreeViewClass *parent_class = NULL;
@@ -167,7 +170,6 @@ typedef struct {
 	PlannerTaskTree *tree;
 	MrpProject      *project;
 	
-	gchar           *name;
 	gint             work;
 	gint             duration;
 	
@@ -177,11 +179,25 @@ typedef struct {
 } TaskCmdInsert;
 
 static void
+task_cmd_insert_free (PlannerCmd *cmd_base)
+{
+	TaskCmdInsert *cmd;
+
+	cmd = (TaskCmdInsert*) cmd_base;
+
+	gtk_tree_path_free (cmd->path);
+	g_object_unref (cmd->task);
+	cmd->task = NULL;
+	g_free (cmd);
+	cmd = NULL;
+}
+
+static void
 task_cmd_insert_do (PlannerCmd *cmd_base)
 {
 	TaskCmdInsert *cmd;
 	GtkTreePath   *path;
-	MrpTask       *task, *parent;
+	MrpTask       *parent;
 	gint           depth;
 	gint           position;
 
@@ -201,18 +217,17 @@ task_cmd_insert_do (PlannerCmd *cmd_base
 	
 	gtk_tree_path_free (path);
 	
-	task = g_object_new (MRP_TYPE_TASK,
+	if (cmd->task == NULL)
+		cmd->task = g_object_new (MRP_TYPE_TASK,
 			     "work", cmd->work,
 			     "duration", cmd->duration,
-			     "name", cmd->name ? cmd->name : "",
 			     NULL);
 	
 	mrp_project_insert_task (cmd->project,
 				 parent,
 				 position,
-				 task);
+				 cmd->task);
 
-	cmd->task = task;
 }
 
 static void
@@ -224,8 +239,6 @@ task_cmd_insert_undo (PlannerCmd *cmd_ba
 
 	mrp_project_remove_task (cmd->project,
 				 cmd->task);
-	
-	cmd->task = NULL;
 }
 
 static PlannerCmd *
@@ -245,10 +258,11 @@ task_cmd_insert (PlannerTaskTree *tree,
 	cmd_base->label = g_strdup (_("Insert task"));
 	cmd_base->do_func = task_cmd_insert_do;
 	cmd_base->undo_func = task_cmd_insert_undo;
-	cmd_base->free_func = NULL; /* FIXME */
+	cmd_base->free_func = task_cmd_insert_free;
 
 	cmd->tree = tree;
 	cmd->project = task_tree_get_project (tree);
+	cmd->task = NULL;
 
 	cmd->path = gtk_tree_path_copy (path);
 	cmd->work = work;
@@ -350,6 +364,357 @@ task_cmd_edit_property (PlannerTaskTree 
 	return cmd_base;
 }
 
+typedef struct {
+	PlannerCmd       base;
+
+	PlannerTaskTree *tree;
+	MrpProject      *project;
+
+	GtkTreePath     *path;
+	MrpTask         *task;
+	GList           *childs;
+	GList           *successors;
+	GList           *predecessors;
+	GList           *assignments;
+} TaskCmdRemove;
+
+static gboolean is_task_in_project (MrpTask *task, PlannerTaskTree *tree)
+{
+	PlannerGanttModel *model; 
+	GtkTreePath       *path;
+
+	model = PLANNER_GANTT_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
+	path = planner_gantt_model_get_path_from_task (model, task);
+
+	if (path != NULL) {
+		gtk_tree_path_free (path);
+		return TRUE;
+	} else {	
+		return FALSE;
+	}
+}
+
+static void
+task_cmd_save_assignments (TaskCmdRemove *cmd)
+{
+	GList *l;
+
+	cmd->assignments = g_list_copy (mrp_task_get_assignments (cmd->task));
+	for (l = cmd->assignments; l; l = l->next) {
+		if (g_getenv ("PLANNER_DEBUG_UNDO_TASK"))
+			g_message ("Assignment save %s is done by %s (%d)", 
+				   mrp_task_get_name (cmd->task), 
+				   mrp_resource_get_name (mrp_assignment_get_resource (l->data)),
+				   mrp_assignment_get_units (l->data));		
+		g_object_ref (l->data);
+	}
+}
+
+static void
+task_cmd_restore_assignments (TaskCmdRemove *cmd)
+{
+	GList         *l;
+	MrpAssignment *assignment;
+	MrpResource   *resource;		
+
+	for (l = cmd->assignments; l; l = l->next) {
+		assignment = l->data;
+		resource = mrp_assignment_get_resource (assignment);
+
+		// if (!is_task_in_project (rel_task, cmd->tree)) continue;
+
+		if (g_getenv ("PLANNER_DEBUG_UNDO_TASK"))
+			g_message ("Resource recover: %s is done by %s",
+				   mrp_task_get_name (cmd->task),
+				   mrp_resource_get_name (mrp_assignment_get_resource (l->data)));
+		
+		mrp_resource_assign (resource, cmd->task,
+				     mrp_assignment_get_units (assignment));
+	}
+}
+
+
+static void
+task_cmd_save_relations (TaskCmdRemove *cmd)
+{
+	GList *l;
+
+	cmd->predecessors = g_list_copy (mrp_task_get_predecessor_relations (cmd->task));
+	for (l = cmd->predecessors; l; l = l->next) {
+		if (g_getenv ("PLANNER_DEBUG_UNDO_TASK"))
+			g_message ("Predecessor save %s -> %s", 
+				   mrp_task_get_name (mrp_relation_get_predecessor (l->data)), 
+				   mrp_task_get_name (mrp_relation_get_successor (l->data)));
+		
+		g_object_ref (l->data);
+	}
+
+	cmd->successors = g_list_copy (mrp_task_get_successor_relations (cmd->task));
+	for (l = cmd->successors; l; l = l->next) {
+		if (g_getenv ("PLANNER_DEBUG_UNDO_TASK")) 
+			g_message ("Successor save %s -> %s", 
+				   mrp_task_get_name (mrp_relation_get_predecessor (l->data)), 
+				   mrp_task_get_name (mrp_relation_get_successor (l->data)));
+		g_object_ref (l->data);
+	}
+}
+
+static void
+task_cmd_restore_relations (TaskCmdRemove *cmd)
+{
+	GList       *l;
+	MrpRelation *relation;
+	MrpTask     *rel_task;
+		
+
+	for (l = cmd->predecessors; l; l = l->next) {
+		relation = l->data;
+		rel_task = mrp_relation_get_predecessor (relation);
+
+		if (!is_task_in_project (rel_task, cmd->tree)) continue;
+
+		if (g_getenv ("PLANNER_DEBUG_UNDO_TASK"))
+			g_message ("Predecessor recover: %s -> %s",
+				   mrp_task_get_name (mrp_relation_get_predecessor (l->data)),
+				   mrp_task_get_name (mrp_relation_get_successor (l->data)));
+		
+		mrp_task_add_predecessor (cmd->task, rel_task, 
+					  mrp_relation_get_relation_type (relation),
+					  mrp_relation_get_lag (relation), NULL);
+	}
+
+	for (l = cmd->successors; l; l = l->next) {
+		relation = l->data;
+		rel_task = mrp_relation_get_successor (relation);
+
+		if (!is_task_in_project (rel_task, cmd->tree)) continue;	
+
+		if (g_getenv ("PLANNER_DEBUG_UNDO_TASK"))
+			g_message ("Successor recover: %s -> %s",
+				   mrp_task_get_name (mrp_relation_get_predecessor (l->data)),
+				   mrp_task_get_name (mrp_relation_get_successor (l->data)));
+		
+		mrp_task_add_predecessor (rel_task, cmd->task,
+					  mrp_relation_get_relation_type (relation),
+					  mrp_relation_get_lag (relation), NULL);
+	}
+}
+
+static void 
+task_cmd_save_childs (TaskCmdRemove *cmd)
+{
+	gint childs, i;
+	
+	childs = mrp_task_get_n_children (cmd->task);
+
+	for (i = 0; i < childs; i++) {
+		MrpTask           *task;
+		TaskCmdRemove     *cmd_child;
+		GtkTreePath       *path;
+		PlannerGanttModel *model;
+		
+		model = PLANNER_GANTT_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (cmd->tree)));
+		task = mrp_task_get_nth_child (cmd->task, i);
+		
+		path = planner_gantt_model_get_path_from_task (model, task);
+		
+		/* We don't insert this command in the undo manager */
+		cmd_child = g_new0 (TaskCmdRemove, 1);
+		cmd_child->tree = cmd->tree;
+		cmd_child->project = task_tree_get_project (cmd->tree);		
+		cmd_child->path = gtk_tree_path_copy (path);		
+		cmd_child->task = g_object_ref (task);
+		task_cmd_save_relations (cmd_child);
+		task_cmd_save_assignments (cmd_child);
+		
+		cmd->childs = g_list_append (cmd->childs, cmd_child);
+		
+		task_cmd_save_childs (cmd_child);
+	}
+
+	if (g_getenv ("PLANNER_DEBUG_UNDO_TASK")) {
+		if (cmd->childs != NULL) {
+			GList *l;
+			for (l = cmd->childs; l; l = l->next) {
+				TaskCmdRemove *cmd_child = l->data;
+				g_message ("Child saved: %s", mrp_task_get_name (cmd_child->task));
+			}
+		}
+	}
+	
+}
+
+static void
+task_cmd_restore_childs (TaskCmdRemove *cmd)
+{
+	PlannerGanttModel *model;
+	gint               position, depth;
+	GtkTreePath       *path;
+	MrpTask           *parent;
+	GList             *l;
+
+	for (l = cmd->childs; l; l = l->next) {
+		TaskCmdRemove *cmd_child;			
+		
+		cmd_child = l->data;
+
+		path = gtk_tree_path_copy (cmd_child->path);
+		model = PLANNER_GANTT_MODEL (gtk_tree_view_get_model 
+					     (GTK_TREE_VIEW (cmd_child->tree)));
+		
+		depth = gtk_tree_path_get_depth (path);
+		position = gtk_tree_path_get_indices (path)[depth - 1];
+		
+		if (depth > 1) {
+			gtk_tree_path_up (path);
+			parent = task_tree_get_task_from_path (cmd_child->tree, path);
+		} else {
+			parent = NULL;
+		}
+		
+		gtk_tree_path_free (path);
+		
+		mrp_project_insert_task (cmd_child->project,
+					 parent,
+					 position,
+					 cmd_child->task);
+		
+		task_cmd_restore_childs (cmd_child);
+		task_cmd_restore_relations (cmd_child);
+		task_cmd_restore_assignments (cmd_child);
+	}
+}
+
+static void
+task_cmd_remove_do (PlannerCmd *cmd_base)
+{
+	TaskCmdRemove *cmd;
+	gint           childs;
+
+	cmd = (TaskCmdRemove*) cmd_base;
+
+	task_cmd_save_relations (cmd);
+	task_cmd_save_assignments (cmd);
+
+	childs = mrp_task_get_n_children (cmd->task);
+
+	if (childs > 0 && cmd->childs == NULL) task_cmd_save_childs (cmd);
+
+	g_message ("Removing the task : %p", cmd->task);
+
+	mrp_project_remove_task (cmd->project, cmd->task);
+}
+
+static void
+task_cmd_remove_undo (PlannerCmd *cmd_base)
+{
+	PlannerGanttModel *model;
+	TaskCmdRemove     *cmd;
+	gint               position, depth;
+	GtkTreePath       *path;
+	MrpTask           *parent;
+	MrpTask           *child_parent;
+	
+	cmd = (TaskCmdRemove*) cmd_base;
+
+	path = gtk_tree_path_copy (cmd->path);
+	model = PLANNER_GANTT_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (cmd->tree)));
+
+	depth = gtk_tree_path_get_depth (path);
+	position = gtk_tree_path_get_indices (path)[depth - 1];
+
+ 	if (depth > 1) {
+		gtk_tree_path_up (path);
+		parent = task_tree_get_task_from_path (cmd->tree, path);
+	} else {
+		parent = NULL;
+	}
+	
+	gtk_tree_path_free (path);
+
+	g_message ("Recovering the task : %p", cmd->task);
+
+	mrp_project_insert_task (cmd->project,
+				 parent,
+				 position,
+				 cmd->task);
+
+	child_parent = planner_gantt_model_get_indent_task_target (model, cmd->task);
+
+	if (cmd->childs != NULL) task_cmd_restore_childs (cmd);
+
+	task_cmd_restore_relations (cmd);
+	task_cmd_restore_assignments (cmd);
+}
+
+static void
+task_cmd_remove_free (PlannerCmd *cmd_base)
+{
+	TaskCmdRemove *cmd;
+	GList         *l;
+
+	cmd = (TaskCmdRemove*) cmd_base;
+
+	for (l = cmd->childs; l; l = l->next)
+		task_cmd_remove_free (l->data);
+
+	g_object_unref (cmd->task);
+
+	g_list_free (cmd->childs);
+
+	for (l = cmd->predecessors; l; l = l->next) 
+		g_object_unref (l->data);
+	g_list_free (cmd->predecessors);
+
+	for (l = cmd->successors; l; l = l->next)
+		g_object_unref (l->data);
+	g_list_free (cmd->successors);
+
+	for (l = cmd->assignments; l; l = l->next)
+		g_object_unref (l->data);
+	g_list_free (cmd->assignments);
+		
+	g_free (cmd_base->label);
+	gtk_tree_path_free (cmd->path);
+	
+
+	g_free (cmd);
+	cmd = NULL;
+}
+
+static PlannerCmd *
+task_cmd_remove (PlannerTaskTree *tree,
+		 GtkTreePath     *path,
+		 MrpTask         *task)
+{
+	PlannerTaskTreePriv *priv = tree->priv;
+	PlannerCmd          *cmd_base;
+	TaskCmdRemove       *cmd;
+
+	g_return_val_if_fail (MRP_IS_TASK (task), NULL);
+		
+	cmd = g_new0 (TaskCmdRemove, 1);
+
+	cmd_base = (PlannerCmd*) cmd;
+	cmd_base->label = g_strdup (_("Remove task"));
+	cmd_base->do_func = task_cmd_remove_do;
+	cmd_base->undo_func = task_cmd_remove_undo;
+	cmd_base->free_func = task_cmd_remove_free;
+
+	cmd->tree = tree;
+	cmd->project = task_tree_get_project (tree);
+
+	cmd->path = gtk_tree_path_copy (path);
+
+	cmd->task = g_object_ref (task);
+
+	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (priv->main_window),
+					   cmd_base);
+
+	return cmd_base;
+}
+
+
 GType
 planner_task_tree_get_type (void)
 {
@@ -1820,8 +2185,8 @@ void
 planner_task_tree_remove_task (PlannerTaskTree *tree)
 {
 	GList *list, *l;
+	TaskCmdRemove *cmd;
 
-	/* FIXME: undo */
 	
 	list = planner_task_tree_get_selected_tasks (tree);
 	if (list == NULL) {
@@ -1829,7 +2194,18 @@ planner_task_tree_remove_task (PlannerTa
 	}
 
 	for (l = list; l; l = l->next) {
-		mrp_project_remove_task (tree->priv->project, l->data);
+		MrpTask             *task = l->data;
+		PlannerGanttModel   *model;
+		GtkTreePath         *path;
+
+		model = PLANNER_GANTT_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
+		path = planner_gantt_model_get_path_from_task (model, task);
+
+		/* childs are removed with the parent */
+		if (path != NULL)
+			cmd = (TaskCmdRemove*) task_cmd_remove (tree, path, task);
+		gtk_tree_path_free (path);
+		/* mrp_project_remove_task (tree->priv->project, l->data); */
 	}
 	
 	g_list_free (list);
<?xml version="1.0"?>
<project name="" company="" manager="" phase="" project-start="20040403T000000Z" 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="" note="" work="28800" start="20040403T000000Z" end="20040409T170000Z" percent-complete="0" type="normal" scheduling="fixed-work"/>
  </tasks>
  <resource-groups/>
  <resources>
    <resource id="1" name="r1" short-name="" type="1" units="0" email="" note="" std-rate="0">
      <properties>
        <property name="cost" value=""/>
      </properties>
    </resource>
    <resource id="2" name="r2" short-name="" type="1" units="0" email="" note="" std-rate="0">
      <properties>
        <property name="cost" value=""/>
      </properties>
    </resource>
  </resources>
  <allocations>
    <allocation task-id="1" resource-id="1" units="10"/>
    <allocation task-id="1" resource-id="2" units="10"/>
  </allocations>
</project>


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