[Planner Dev] Task/Resource and Project property redo/undo patch.




As attached this handles the undo/redo for Task, Resource and
Project properties. Patched against current CVS (Changelog = 1.122).

Fixes,
http://bugzilla.gnome.org/show_bug.cgi?id=140694
http://bugzilla.gnome.org/show_bug.cgi?id=141967
http://bugzilla.gnome.org/show_bug.cgi?id=142121


TODO:  When a property is removed and undone and its a task or
resource property then we do not restore the values that
were set; needs more code in the various views when they get
property-added. This requires caching all the current values
for that property to cmd->?? so that they can be restored.
Will raise a bugzilla for this once CVS settled.

Rgds,
Lincoln.

Index: src/planner-project-properties.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-project-properties.c,v
retrieving revision 1.7
diff -u -b -B -p -r1.7 planner-project-properties.c
--- a/src/planner-project-properties.c	2 May 2004 16:21:28 -0000	1.7
+++ b/src/planner-project-properties.c	9 May 2004 19:32:37 -0000
@@ -1,5 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
+ * Copyright (C) 2004      Lincoln Phipps <lincoln phipps openmutual net>
  * Copyright (C) 2003      Imendio HB
  * Copyright (C) 2001-2002 CodeFactory AB
  * Copyright (C) 2001-2002 Richard Hult <richard imendio com>
@@ -52,6 +53,48 @@ typedef struct {
 	GtkWidget     *remove_property_button;
 } DialogData;
 
+/* Start of REDO/UNDO structures */
+
+typedef struct {
+	PlannerCmd   base;
+	
+	PlannerWindow	  *window;
+	MrpProject        *project;
+	gchar	 	 *name; 
+	MrpPropertyType	  type;
+	gchar	 	 *label;
+	gchar	 	 *description;
+	GType		  owner;
+	gboolean	  user_defined;   
+} MrpPropertyCmdAdd;
+
+typedef struct {
+	PlannerCmd   base;
+	
+	PlannerWindow	  *window;
+	MrpProject        *project;
+	gchar	 	 *name; 
+	MrpPropertyType	  type;
+	gchar	 	 *label;
+	gchar	 	 *description;
+	GType		  owner;
+	gboolean	  user_defined; 
+	gchar            *old_text;  
+} MrpPropertyCmdRemove;
+
+typedef struct {
+	PlannerCmd        base;
+
+	PlannerWindow	  *window;
+	MrpProject        *project;
+	MrpProperty	 *property;
+	gchar            *old_text;
+	gchar  	     	 *new_text;
+} MrpPropertyCmdValueEdited;
+
+
+/* End of REDO/UNDO structures */
+
 #define DIALOG_GET_DATA(d) g_object_get_data ((GObject*)d, "data")
 
 static void     mpp_select_calendar_clicked_cb        (GtkWidget           *button,
@@ -121,6 +164,10 @@ static void     mpp_property_added      
 static void     mpp_property_removed                  (MrpProject          *project,
 						       MrpProperty         *property,
 						       GtkWidget           *dialog);
+static void     mpp_property_changed                  (MrpProject          *project,
+						       GType                object_type,
+						       MrpProperty         *property,
+						       GtkWidget           *dialog);
 static void     mpp_add_property_button_clicked_cb    (GtkButton           *button,
 						       GtkWidget           *dialog);
 static void     mpp_remove_property_button_clicked_cb (GtkButton           *button,
@@ -131,6 +178,41 @@ static void     mpp_property_value_edite
 						       GtkWidget           *dialog);
 
 
+/* Start of UNDO/REDO Proptotypes */
+
+static PlannerCmd *mrp_property_cmd_add 		(PlannerWindow *window,
+							MrpProject	*project,
+							GType		owner,
+							const gchar 	*name,
+							MrpPropertyType type,
+							const gchar     *label,
+							const gchar     *description,
+							gboolean	user_defined);
+
+static gboolean	mrp_property_cmd_add_do 		(PlannerCmd *cmd_base);
+static void	mrp_property_cmd_add_undo 		(PlannerCmd *cmd_base);
+static void	mrp_property_cmd_add_free 		(PlannerCmd *cmd_base);
+
+
+static PlannerCmd *mrp_property_cmd_remove 		(PlannerWindow *window,
+							MrpProject	*project,
+							GType		owner,
+							const gchar 	*name);
+static gboolean	mrp_property_cmd_remove_do 		(PlannerCmd *cmd_base);
+static void	mrp_property_cmd_remove_undo 	(PlannerCmd *cmd_base);
+static void	mrp_property_cmd_remove_free 	(PlannerCmd *cmd_base);
+
+
+static PlannerCmd *mrp_property_cmd_value_edited 	(PlannerWindow *window,
+							MrpProject      *project,
+							MrpProperty	*property,
+							const gchar 	*new_text);
+static gboolean	mrp_property_cmd_value_edited_do 	(PlannerCmd *cmd_base);
+static void	mrp_property_cmd_value_edited_undo 	(PlannerCmd *cmd_base);
+static void	mrp_property_cmd_value_edited_free 	(PlannerCmd *cmd_base);
+
+/* End of UNDO/REDO Prototypes */
+
 
 enum {
 	COL_PROPERTY,
@@ -379,6 +461,11 @@ mpp_connect_to_project (MrpProject *proj
 				 G_CALLBACK (mpp_property_removed),
 				 dialog,
 				 0);
+	g_signal_connect_object (project,
+				 "property_changed",
+				 G_CALLBACK (mpp_property_changed),
+				 dialog,
+				 0);
 }
 
 static void  
@@ -885,6 +972,10 @@ mpp_property_added (MrpProject  *project
 		    MrpProperty *property,
 		    GtkWidget   *dialog)
 {
+	if (!dialog) {
+		return;  /* This happens when signal for property-added wasn't intended for this dialog */
+	}
+
 	DialogData   *data = DIALOG_GET_DATA (dialog);
 	GtkTreeModel *model;
 	GtkTreeIter   iter;
@@ -971,6 +1062,39 @@ mpp_property_removed (MrpProject  *proje
 	g_free (find_data);
 }
 
+static void
+mpp_property_changed (MrpProject  *project, 
+		    GType        object_type,
+		    MrpProperty *property,
+		    GtkWidget   *dialog)
+{
+	DialogData       *data = DIALOG_GET_DATA (dialog);
+	GtkTreeModel     *model;
+	PropertyFindData *find_data;
+	
+	if ( object_type == MRP_TYPE_PROJECT) {
+		model = gtk_tree_view_get_model (data->properties_tree);
+	
+		find_data = g_new0 (PropertyFindData, 1);
+		find_data->property = property;
+		find_data->found_path = NULL;
+		find_data->found_iter = NULL;
+	
+		gtk_tree_model_foreach (model,
+					(GtkTreeModelForeachFunc) mpp_property_find,
+					find_data);
+
+		if (find_data->found_path) {
+			gtk_tree_model_row_changed (model,
+						find_data->found_path,
+					       	find_data->found_iter);
+		}
+		if (find_data) {
+			g_free (find_data);
+		}
+	}
+}
+
 static gboolean
 mpp_property_dialog_label_changed_cb (GtkWidget *label_entry,
 				      GdkEvent  *event,
@@ -1063,7 +1187,6 @@ static void
 mpp_add_property_button_clicked_cb (GtkButton *button, GtkWidget *dialog)
 {
 	DialogData      *data = DIALOG_GET_DATA (dialog);
-	MrpProperty     *property;
 	MrpPropertyType  type;
 	const gchar     *label;
 	const gchar     *name;
@@ -1075,6 +1198,7 @@ mpp_add_property_button_clicked_cb (GtkB
 	GtkWidget       *w;
 	gint             response;
 	gboolean         finished = FALSE;
+	MrpPropertyCmdAdd *cmd;
 	
 	glade = glade_xml_new (GLADEDIR "/new-property.glade",
 			       NULL,
@@ -1148,16 +1272,15 @@ mpp_add_property_button_clicked_cb (GtkB
 			type = mpp_property_dialog_get_selected (w);
 
 			if (type != MRP_PROPERTY_TYPE_NONE) {
-				property = mrp_property_new (name, 
+
+				cmd = (MrpPropertyCmdAdd*) mrp_property_cmd_add (data->main_window,
+											data->project, 
+											MRP_TYPE_PROJECT, 
+											name, 
 							     type,
 							     label,
 							     description,
 							     TRUE);
-
-				mrp_project_add_property (data->project, 
-							  MRP_TYPE_PROJECT,
-							  property,
-							  TRUE);	
 			}
 
 			finished = TRUE;
@@ -1186,6 +1309,7 @@ mpp_remove_property_button_clicked_cb (G
 	MrpProperty      *property;
 	GtkWidget        *remove_dialog;
 	gint              response;
+	MrpPropertyCmdRemove *cmd;
 	
 	model = gtk_tree_view_get_model (data->properties_tree);
 	
@@ -1212,7 +1336,9 @@ mpp_remove_property_button_clicked_cb (G
 
 	switch (response) {
 	case GTK_RESPONSE_YES:
-		mrp_project_remove_property (data->project,
+		
+		cmd = (MrpPropertyCmdRemove *) mrp_property_cmd_remove (data->main_window,
+									data->project,  
 					     MRP_TYPE_PROJECT,
 					     mrp_property_get_name (property));
 		break;
@@ -1240,8 +1366,7 @@ mpp_property_value_edited (GtkCellRender
 	GtkTreeModel    *model;
 	MrpProperty     *property;
 	MrpProject      *project;
-	MrpPropertyType  type;
-	gfloat           fvalue;
+	MrpPropertyCmdValueEdited  *cmd;
 	
 	model = gtk_tree_view_get_model (data->properties_tree);
 	project = data->project;
@@ -1253,58 +1378,10 @@ mpp_property_value_edited (GtkCellRender
 			    COL_PROPERTY, &property,
 			    -1);
 	
-	type = mrp_property_get_property_type (property);
-	switch (type) {
-	case MRP_PROPERTY_TYPE_STRING:
-		mrp_object_set (MRP_OBJECT (project),
-				mrp_property_get_name (property), 
-				new_text,
-				NULL);
-		break;
-	case MRP_PROPERTY_TYPE_INT:
-		mrp_object_set (MRP_OBJECT (project),
-				mrp_property_get_name (property), 
-				atoi (new_text),
-				NULL);
-		break;
-	case MRP_PROPERTY_TYPE_FLOAT:
-		fvalue = g_ascii_strtod (new_text, NULL);
-		mrp_object_set (MRP_OBJECT (project),
-				mrp_property_get_name (property), 
-				fvalue,
-				NULL);
-		break;
-
-	case MRP_PROPERTY_TYPE_DURATION:
-		/* FIXME: support reading units etc... */
-		mrp_object_set (MRP_OBJECT (project),
-				mrp_property_get_name (property), 
-				atoi (new_text) *8*60*60,
-				NULL);
-		break;
-		
-
-	case MRP_PROPERTY_TYPE_DATE:
-/* 		date = PLANNER_CELL_RENDERER_DATE (cell); */
-/* 		mrp_object_set (MRP_OBJECT (project), */
-/* 				mrp_property_get_name (property),  */
-/* 				&(date->time), */
-/* 				NULL); */
-		break;
-	case MRP_PROPERTY_TYPE_COST:
-		fvalue = g_ascii_strtod (new_text, NULL);
-		mrp_object_set (MRP_OBJECT (project),
-				mrp_property_get_name (property), 
-				fvalue,
-				NULL);
-		break;
-	case MRP_PROPERTY_TYPE_STRING_LIST:
-		/* FIXME: Should string-list still be around? */
-		break;
-	default:
-		g_assert_not_reached ();
-		break;
-	}
+	cmd = (MrpPropertyCmdValueEdited *) mrp_property_cmd_value_edited (data->main_window, 
+									   project,
+									   property, 
+									   new_text);
 
 	gtk_tree_path_free (path);
 }
@@ -1465,3 +1542,633 @@ planner_project_properties_new (PlannerW
 	return dialog;
 }
 
+/* Start of UNDO/REDO routines */
+
+static gboolean
+mrp_property_cmd_add_do (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdAdd   *cmd;
+	MrpProperty		*property;
+		
+	cmd = (MrpPropertyCmdAdd*) cmd_base;
+
+	if (cmd->name == NULL) {
+		return FALSE;
+	}
+
+	property = mrp_property_new (cmd->name, 
+				     cmd->type,
+				     cmd->label,
+				     cmd->description,
+				     cmd->user_defined);
+			
+	mrp_project_add_property (cmd->project, 
+				  cmd->owner,
+				  property,
+				  cmd->user_defined);	
+		
+	/* This functions as a simple success check for the REDO/UNDO stuff. Check if its added. */
+	if (!mrp_project_has_property (cmd->project, cmd->owner, cmd->name)) {
+ 		g_warning ("%s: object of type '%s' still has no property named '%s'",
+			   G_STRLOC,
+			   g_type_name (cmd->owner),
+			   cmd->name);
+		return FALSE;
+	}
+	
+	return TRUE; 
+	
+}
+
+static void
+mrp_property_cmd_add_undo (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdAdd *cmd;
+		
+	cmd = (MrpPropertyCmdAdd*) cmd_base;
+
+	if (cmd->name != NULL) {
+	
+		mrp_project_remove_property (cmd->project, 
+				  	     cmd->owner,
+				  	     cmd->name);
+			
+	/* This functions as a simple success check for the REDO/UNDO stuff. Check if its removed. */
+		if (mrp_project_has_property (cmd->project, cmd->owner, cmd->name)) {
+ 			g_warning ("%s: object of type '%s' still has the property named '%s'",
+				   G_STRLOC,
+			   	   g_type_name (cmd->owner),
+			   	   cmd->name);
+		}
+	}	
+}
+
+
+static void
+mrp_property_cmd_add_free (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdAdd  *cmd;
+
+	cmd = (MrpPropertyCmdAdd*) cmd_base;	
+
+	g_free (cmd->name);
+	g_free (cmd->label);
+	g_free (cmd->description);
+	cmd->project = NULL;
+	cmd->window = NULL;
+}
+
+static 
+PlannerCmd *
+mrp_property_cmd_add 	(PlannerWindow *window,
+			MrpProject	*project,
+			GType		owner,
+			const gchar 	*name,
+			MrpPropertyType type,
+			const gchar     *label,
+			const gchar     *description,
+			gboolean	user_defined)
+{
+	PlannerCmd      *cmd_base;
+	MrpPropertyCmdAdd  *cmd;
+
+	cmd = g_new0 (MrpPropertyCmdAdd, 1);
+
+	cmd_base = (PlannerCmd*) cmd;
+
+	cmd_base->label = g_strdup (_("Add project property"));
+	cmd_base->do_func =  mrp_property_cmd_add_do; 
+	cmd_base->undo_func = mrp_property_cmd_add_undo;
+	cmd_base->free_func = mrp_property_cmd_add_free;
+
+	cmd->window = window;
+	cmd->project = project;
+	cmd->owner = owner;
+	cmd->name = g_strdup (name);
+	cmd->type = type;
+	cmd->label = g_strdup (label);
+	cmd->description = g_strdup (description);
+	cmd->user_defined = user_defined;
+
+	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (window),
+					   cmd_base);
+
+	return cmd_base;
+}
+
+
+static gboolean
+mrp_property_cmd_remove_do (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdRemove *cmd;
+
+	cmd = (MrpPropertyCmdRemove*) cmd_base;
+	
+	if (!mrp_project_has_property (cmd->project, cmd->owner, cmd->name)) {
+ 		g_warning ("%s: object of type '%s' has no property named '%s' to remove",
+			   G_STRLOC,
+			   g_type_name (cmd->owner),
+			   cmd->name);
+		return FALSE;
+	}
+	
+	mrp_project_remove_property (cmd->project,
+				     cmd->owner,
+				     cmd->name);
+
+	return TRUE;
+}
+
+
+static void
+mrp_property_cmd_remove_undo (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdRemove *cmd;
+	MrpProperty  *property;
+	MrpProject   *project;
+	MrpPropertyType		type;
+	gchar			*new_text;
+	gfloat                  fvalue;
+	
+	cmd = (MrpPropertyCmdRemove*) cmd_base;
+	
+	if (cmd->name != NULL) {
+	
+		project = cmd->project;
+		new_text = cmd->old_text;
+	
+		property = mrp_property_new (cmd->name, 
+				     cmd->type,
+				     cmd->label,
+				     cmd->description,
+				     cmd->user_defined);
+			
+		mrp_project_add_property (project, 
+				  cmd->owner,
+				  property,
+				  cmd->user_defined);
+				  
+	/* Now restore the previous text value We've kept it as new_text so it was easy to cut+paste code */	
+		type = mrp_property_get_property_type (property);
+		switch (type) {
+		case MRP_PROPERTY_TYPE_STRING:
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				new_text,
+				NULL);
+			break;
+		case MRP_PROPERTY_TYPE_INT:
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				atoi (new_text),
+				NULL);
+			break;
+		case MRP_PROPERTY_TYPE_FLOAT:
+			fvalue = g_ascii_strtod (new_text, NULL);
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				fvalue,
+				NULL);
+			break;
+
+		case MRP_PROPERTY_TYPE_DURATION:
+			/* FIXME: support reading units etc... */
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				atoi (new_text) *8*60*60,
+				NULL);
+			break;
+		
+		case MRP_PROPERTY_TYPE_DATE:
+	/* 		date = PLANNER_CELL_RENDERER_DATE (cell); */
+	/* 		mrp_object_set (MRP_OBJECT (project), */
+	/* 				mrp_property_get_name (property),  */
+	/* 				&(date->time), */
+	/* 				NULL); */
+			break;
+		case MRP_PROPERTY_TYPE_COST:
+			fvalue = g_ascii_strtod (new_text, NULL);
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				fvalue,
+				NULL);
+			break;
+		case MRP_PROPERTY_TYPE_STRING_LIST:
+			/* FIXME: Should string-list still be around? */
+			break;
+		default:
+			g_assert_not_reached ();
+			break;
+		}	  
+			
+	/* This functions as a simple success check for the REDO/UNDO stuff. Check if its removed. */
+		if (!mrp_project_has_property (project, cmd->owner, cmd->name)) {
+ 			g_warning ("%s: object of type '%s' property named '%s' not restored.",
+				   G_STRLOC,
+			   	   g_type_name (cmd->owner),
+			   	   cmd->name);
+		}
+	}	
+}
+
+static void
+mrp_property_cmd_remove_free (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdRemove *cmd;
+
+	cmd = (MrpPropertyCmdRemove*) cmd_base;
+
+	g_free (cmd->name);
+	g_free (cmd->label);
+	g_free (cmd->description);
+	g_free (cmd->old_text);
+	cmd->project = NULL;
+	cmd->window = NULL;
+}
+
+static PlannerCmd *
+mrp_property_cmd_remove 	(PlannerWindow *window,
+				MrpProject	*project,
+				GType		owner,
+				const gchar 	*name)
+{
+	PlannerCmd      *cmd_base;
+	MrpPropertyCmdRemove  *cmd;
+	MrpProperty     *property;
+	MrpPropertyType  type;
+	gchar           *svalue;
+	gint             ivalue;
+	gfloat           fvalue;
+	gint             work;
+	
+	cmd = g_new0 (MrpPropertyCmdRemove, 1);
+
+	cmd_base = (PlannerCmd*) cmd;
+
+	cmd_base->label = g_strdup (_("Remove project property"));
+	cmd_base->do_func =   mrp_property_cmd_remove_do;
+	cmd_base->undo_func = mrp_property_cmd_remove_undo;
+	cmd_base->free_func = mrp_property_cmd_remove_free;
+
+	cmd->window = window;
+	cmd->project = project;
+	cmd->owner   = owner;
+	cmd->name = g_strdup (name);
+
+	property = mrp_project_get_property (project,
+					     name,
+					     owner);
+					     
+	cmd->type = mrp_property_get_property_type (property);
+	cmd->description = g_strdup (mrp_property_get_description (property));
+	cmd->label = g_strdup ( mrp_property_get_label (property));
+	cmd->user_defined = mrp_property_get_user_defined (property);
+
+	type = mrp_property_get_property_type (property);
+
+	switch (type) {
+	case MRP_PROPERTY_TYPE_STRING:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &svalue,
+				NULL);
+		
+		if (svalue == NULL) {
+			svalue = g_strdup ("");
+		}		
+
+		break;
+	case MRP_PROPERTY_TYPE_INT:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &ivalue,
+				NULL);
+		svalue = g_strdup_printf ("%d", ivalue);
+		break;
+
+	case MRP_PROPERTY_TYPE_FLOAT:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &fvalue,
+				NULL);
+
+		svalue = planner_format_float (fvalue, 4, FALSE);
+		break;
+
+	case MRP_PROPERTY_TYPE_DATE:
+		svalue = g_strdup ("");
+		
+		
+/* 		mrp_object_get (data->project, */
+/* 				mrp_property_get_name (property), &tvalue, */
+/* 				NULL);  */
+/* 		svalue = planner_format_date (tvalue); */
+		break;
+		
+	case MRP_PROPERTY_TYPE_DURATION:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &ivalue,
+				NULL); 
+
+/*		work = mrp_calendar_day_get_total_work (
+			mrp_project_get_calendar (tree->priv->project),
+			mrp_day_get_work ());
+*/
+		work = 8*60*60;
+
+		svalue = planner_format_duration (ivalue, work / (60*60));
+		break;
+		
+	case MRP_PROPERTY_TYPE_COST:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &fvalue,
+				NULL); 
+
+		svalue = planner_format_float (fvalue, 2, FALSE);
+		break;
+				
+	default:
+		g_warning ("Type not implemented.");
+		break;
+	}
+	cmd->old_text = g_strdup (svalue);
+	g_free (svalue);
+	
+	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (window),
+					   cmd_base);
+
+	return cmd_base;
+}
+
+/* Label Edited Routine */
+
+static gboolean
+mrp_property_cmd_value_edited_do (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdValueEdited *cmd;
+	MrpPropertyType		type;
+	MrpProject  		*project;
+	MrpProperty		*property;
+	gchar			*new_text;
+	gfloat                  fvalue;
+	
+	cmd = (MrpPropertyCmdValueEdited*) cmd_base;
+	
+	project = cmd->project;
+	property = cmd->property;
+	new_text = cmd->new_text;
+	
+	if (!cmd->property) {
+		return FALSE;
+	}
+	
+	type = mrp_property_get_property_type (property);
+	switch (type) {
+	case MRP_PROPERTY_TYPE_STRING:
+		mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				new_text,
+				NULL);
+		break;
+	case MRP_PROPERTY_TYPE_INT:
+		mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				atoi (new_text),
+				NULL);
+		break;
+	case MRP_PROPERTY_TYPE_FLOAT:
+		fvalue = g_ascii_strtod (new_text, NULL);
+		mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				fvalue,
+				NULL);
+		break;
+
+	case MRP_PROPERTY_TYPE_DURATION:
+		/* FIXME: support reading units etc... */
+		mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				atoi (new_text) *8*60*60,
+				NULL);
+		break;
+		
+
+	case MRP_PROPERTY_TYPE_DATE:
+/* 		date = PLANNER_CELL_RENDERER_DATE (cell); */
+/* 		mrp_object_set (MRP_OBJECT (project), */
+/* 				mrp_property_get_name (property),  */
+/* 				&(date->time), */
+/* 				NULL); */
+		break;
+	case MRP_PROPERTY_TYPE_COST:
+		fvalue = g_ascii_strtod (new_text, NULL);
+		mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				fvalue,
+				NULL);
+		break;
+	case MRP_PROPERTY_TYPE_STRING_LIST:
+		/* FIXME: Should string-list still be around? */
+		break;
+	default:
+		g_assert_not_reached ();
+		return FALSE;
+		break;
+	}
+	
+	return TRUE;
+}
+
+
+static void
+mrp_property_cmd_value_edited_undo (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdValueEdited *cmd;
+	MrpProject		*project;
+	MrpProperty		*property;
+	MrpPropertyType		type;
+	gchar			*new_text;
+	gfloat                  fvalue;
+			
+	cmd = (MrpPropertyCmdValueEdited*) cmd_base;
+
+	property = cmd->property;
+	project = cmd->project;
+	new_text = cmd->old_text;
+	
+	if (cmd->property != NULL) {
+
+		type = mrp_property_get_property_type (property);
+		switch (type) {
+		case MRP_PROPERTY_TYPE_STRING:
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				new_text,
+				NULL);
+			break;
+		case MRP_PROPERTY_TYPE_INT:
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				atoi (new_text),
+				NULL);
+			break;
+		case MRP_PROPERTY_TYPE_FLOAT:
+			fvalue = g_ascii_strtod (new_text, NULL);
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				fvalue,
+				NULL);
+			break;
+
+		case MRP_PROPERTY_TYPE_DURATION:
+			/* FIXME: support reading units etc... */
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				atoi (new_text) *8*60*60,
+				NULL);
+			break;
+		
+		case MRP_PROPERTY_TYPE_DATE:
+	/* 		date = PLANNER_CELL_RENDERER_DATE (cell); */
+	/* 		mrp_object_set (MRP_OBJECT (project), */
+	/* 				mrp_property_get_name (property),  */
+	/* 				&(date->time), */
+	/* 				NULL); */
+			break;
+		case MRP_PROPERTY_TYPE_COST:
+			fvalue = g_ascii_strtod (new_text, NULL);
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				fvalue,
+				NULL);
+			break;
+		case MRP_PROPERTY_TYPE_STRING_LIST:
+			/* FIXME: Should string-list still be around? */
+			break;
+		default:
+			g_assert_not_reached ();
+			break;
+		}
+	}
+}
+
+static void
+mrp_property_cmd_value_edited_free (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdValueEdited *cmd;
+
+	cmd = (MrpPropertyCmdValueEdited*) cmd_base;
+
+	g_free (cmd->old_text);
+	g_free (cmd->new_text);
+	cmd->property = NULL;  
+	cmd->window = NULL;
+	cmd->project = NULL;
+}
+
+static PlannerCmd *
+mrp_property_cmd_value_edited 	(PlannerWindow *window,
+				MrpProject	*project,
+				MrpProperty	*property,
+				const gchar 	*new_text)
+{
+	PlannerCmd      *cmd_base;
+	MrpPropertyCmdValueEdited  *cmd;
+	
+	MrpPropertyType  type;
+	gchar           *svalue;
+	gint             ivalue;
+	gfloat           fvalue;
+	gint             work;
+	
+	cmd = g_new0 (MrpPropertyCmdValueEdited, 1);
+
+	cmd_base = (PlannerCmd*) cmd;
+
+	cmd_base->label = g_strdup (_("Edit project property value"));
+	cmd_base->do_func =   mrp_property_cmd_value_edited_do;
+	cmd_base->undo_func = mrp_property_cmd_value_edited_undo;
+	cmd_base->free_func = mrp_property_cmd_value_edited_free;
+
+	cmd->window = window;
+	cmd->property = property;
+	cmd->project = project;
+	cmd->new_text = g_strdup (new_text);
+		
+	/* TODO: We now remember also the old data so we can undo the label edit 
+	*  but this should really be put into its own function e.g. mrp_get_property_value_to_string()
+	*  along with mrp_set_property_value_From_string() as we use this a lot.
+	*/
+
+	type = mrp_property_get_property_type (property);
+
+	switch (type) {
+	case MRP_PROPERTY_TYPE_STRING:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &svalue,
+				NULL);
+		
+		if (svalue == NULL) {
+			svalue = g_strdup ("");
+		}		
+
+		break;
+	case MRP_PROPERTY_TYPE_INT:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &ivalue,
+				NULL);
+		svalue = g_strdup_printf ("%d", ivalue);
+		break;
+
+	case MRP_PROPERTY_TYPE_FLOAT:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &fvalue,
+				NULL);
+
+		svalue = planner_format_float (fvalue, 4, FALSE);
+		break;
+
+	case MRP_PROPERTY_TYPE_DATE:
+		svalue = g_strdup ("");
+		
+		
+/* 		mrp_object_get (data->project, */
+/* 				mrp_property_get_name (property), &tvalue, */
+/* 				NULL);  */
+/* 		svalue = planner_format_date (tvalue); */
+		break;
+		
+	case MRP_PROPERTY_TYPE_DURATION:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &ivalue,
+				NULL); 
+
+/*		work = mrp_calendar_day_get_total_work (
+			mrp_project_get_calendar (tree->priv->project),
+			mrp_day_get_work ());
+*/
+		work = 8*60*60;
+
+		svalue = planner_format_duration (ivalue, work / (60*60));
+		break;
+		
+	case MRP_PROPERTY_TYPE_COST:
+		mrp_object_get (project,
+				mrp_property_get_name (property), &fvalue,
+				NULL); 
+
+		svalue = planner_format_float (fvalue, 2, FALSE);
+		break;
+				
+	default:
+		g_warning ("Type not implemented.");
+		break;
+	}
+	cmd->old_text = g_strdup (svalue);
+	g_free (svalue);
+	
+	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (window),
+					   cmd_base);
+
+	return cmd_base;
+}
+
+/* end of UNDO/REDO routines */
+
Index: src/planner-property-dialog.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-property-dialog.c,v
retrieving revision 1.2
diff -u -b -B -p -r1.2 planner-property-dialog.c
--- a/src/planner-property-dialog.c	11 Dec 2003 10:52:46 -0000	1.2
+++ b/src/planner-property-dialog.c	9 May 2004 19:32:38 -0000
@@ -4,6 +4,7 @@
  * Copyright (C) 2002 Richard Hult <richard imendio com>
  * Copyright (C) 2002 Mikael Hallendal <micke imendio com>
  * Copyright (C) 2002 Alvaro del Castillo <acs barrapunto 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
@@ -48,12 +49,132 @@
 
 
 typedef struct {
-	GtkWidget    *tree;
-	GtkTreeModel *model;
+	PlannerWindow  *main_window;
 	MrpProject   *project;
-	GType         type;
+	GtkTreeModel   *model;
+	GtkWidget      *tree;
+	GType          owner;
+	MrpPropertyStore *shop;
 } PlannerPropertyDialogPriv;
 
+/* Start of REDO/UNDO structures */
+
+typedef struct {
+	PlannerCmd   base;
+	
+	PlannerWindow	  *window;
+	MrpProject        *project;
+	gchar	 	 *name; 
+	MrpPropertyType	  type;
+	gchar	 	 *label_text;
+	gchar	 	 *description;
+	GType		  owner;
+	gboolean	  user_defined;   
+} ProjectPropertyCmdAdd;
+
+typedef struct {
+	PlannerCmd   base;
+	
+	PlannerWindow	  *window;
+	MrpProject        *project;
+	gchar	 	 *name; 
+	MrpPropertyType	  type;
+	gchar	 	 *label_text;
+	gchar	 	 *description;
+	GType		  owner;
+	gboolean	  user_defined;   
+} ProjectPropertyCmdRemove;
+
+typedef struct {
+	PlannerCmd        base;
+
+	PlannerWindow	  *window;
+	MrpProperty	 *property;
+	gchar            *old_text;
+	gchar  	     	 *new_text;
+} ProjectPropertyCmdLabelEdited;
+
+
+/* End of REDO/UNDO structures */
+
+static void	property_dialog_setup_option_menu 	(GtkWidget     *option_menu,
+				   			GCallback      func,
+				   			gpointer       user_data,
+				   			gconstpointer  str1, ...);
+						
+
+static gint	property_dialog_get_selected 		(GtkWidget *option_menu);
+
+static void	property_dialog_close_cb 		(GtkWidget *button,
+							GtkWidget *dialog);
+static void	property_dialog_type_selected_cb 	(GtkWidget *widget,
+							GtkWidget *dialog);
+static gboolean	property_dialog_label_changed_cb 	(GtkWidget *label_entry,
+							GdkEvent  *event,
+							GtkWidget *name_entry);
+				  
+static void	property_dialog_add_cb 			(GtkWidget *button,
+							GtkWidget *dialog);
+
+static void	property_dialog_remove_cb 		(GtkWidget *button, 
+							GtkWidget *dialog);
+
+static void  	property_dialog_label_edited 		(GtkCellRendererText *cell, 
+						      	gchar               *path_str,
+						      	gchar               *new_text, 
+			      				GtkWidget           *dialog);
+     
+
+static void	property_dialog_setup_list 		(GtkWidget *dialog,
+							guint      cols);
+	
+static void	property_dialog_setup_widgets 		(GtkWidget *dialog,
+						       GladeXML  *glade);
+			       
+GtkWidget 	*planner_property_dialog_new 		(PlannerWindow *main_window,
+							MrpProject     *project,
+							GType          owner,
+							const gchar    *title);
+
+void  		planner_property_dialog_value_edited 	(GtkCellRendererText *cell, 
+							 gchar               *path_str,
+							 gchar               *new_text, 
+				 			gpointer             data);
+				 							
+/* Start of UNDO/REDO Proptotypes */
+
+static PlannerCmd *project_property_cmd_add 		(PlannerWindow *window,
+							MrpProject	*project,
+							GType		owner,
+							const gchar 	*name,
+							MrpPropertyType type,
+							const gchar     *label_text,
+							const gchar     *description,
+							gboolean	user_defined);
+
+static gboolean	project_property_cmd_add_do 		(PlannerCmd *cmd_base);
+static void	project_property_cmd_add_undo 		(PlannerCmd *cmd_base);
+static void	project_property_cmd_add_free 		(PlannerCmd *cmd_base);
+
+
+static PlannerCmd *project_property_cmd_remove 		(PlannerWindow *window,
+							MrpProject	*project,
+							GType		owner,
+							const gchar 	*name);
+static gboolean	project_property_cmd_remove_do 		(PlannerCmd *cmd_base);
+static void	project_property_cmd_remove_undo 	(PlannerCmd *cmd_base);
+static void	project_property_cmd_remove_free 	(PlannerCmd *cmd_base);
+
+
+static PlannerCmd *project_property_cmd_label_edited 	(PlannerWindow *window,
+							MrpProperty	*property,
+							const gchar 	*new_text);
+static gboolean	project_property_cmd_label_edited_do 	(PlannerCmd *cmd_base);
+static void	project_property_cmd_label_edited_undo 	(PlannerCmd *cmd_base);
+static void	project_property_cmd_label_edited_free 	(PlannerCmd *cmd_base);
+
+/* End of UNDO/REDO Prototypes */
+
 static void
 property_dialog_setup_option_menu (GtkWidget     *option_menu,
 				   GCallback      func,
@@ -132,6 +253,7 @@ property_dialog_type_selected_cb (GtkWid
 	g_object_set_data (G_OBJECT (dialog), "type", GINT_TO_POINTER (type));
 }
 
+/* Note used for UNDO/REDO just for intra dialog work before the CLOSE button hit */
 static gboolean
 property_dialog_label_changed_cb (GtkWidget *label_entry,
 				  GdkEvent  *event,
@@ -155,7 +277,6 @@ property_dialog_add_cb (GtkWidget *butto
 			GtkWidget *dialog)
 {
 	PlannerPropertyDialogPriv *priv;
-	MrpProperty          *property;
 	MrpPropertyType       type;
 	const gchar          *label;
 	const gchar          *name;
@@ -168,6 +289,8 @@ property_dialog_add_cb (GtkWidget *butto
 	gint                  response;
 	gboolean              finished = FALSE;
 	
+	ProjectPropertyCmdAdd *cmd;
+	
 	priv = GET_PRIV (dialog);
 
 	glade = glade_xml_new (GLADEDIR "/new-property.glade",
@@ -241,17 +364,17 @@ property_dialog_add_cb (GtkWidget *butto
 			
 			type = property_dialog_get_selected (w);
 
+			/* Intercept property addition for undo/redo here */
 			if (type != MRP_PROPERTY_TYPE_NONE) {
-				property = mrp_property_new (name, 
+
+				cmd = (ProjectPropertyCmdAdd*) project_property_cmd_add (priv->main_window,
+											 priv->project, 
+											priv->owner, 
+											name, 
 							     type,
 							     label,
 							     description,
 							     TRUE);
-
-				mrp_project_add_property (priv->project, 
-							  priv->type,
-							  property,
-							  TRUE);	
 			}
 
 			finished = TRUE;
@@ -280,6 +403,8 @@ property_dialog_remove_cb (GtkWidget *bu
 	GtkWidget            *remove_dialog;
 	gint                  response;
 
+	ProjectPropertyCmdRemove *cmd;
+		
 	priv = GET_PRIV (dialog);
 
 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree));
@@ -305,9 +430,12 @@ property_dialog_remove_cb (GtkWidget *bu
 
 	switch (response) {
 	case GTK_RESPONSE_YES:
-		mrp_project_remove_property (priv->project,
-					     priv->type,
+
+		cmd = (ProjectPropertyCmdRemove*) project_property_cmd_remove (priv->main_window,
+										priv->project, 
+										priv->owner, 
 					     name);
+
 		break;
 
 	case GTK_RESPONSE_DELETE_EVENT:
@@ -334,6 +462,7 @@ property_dialog_label_edited (GtkCellRen
 	GtkTreeIter           iter;
 	GtkTreeModel         *model;
 	MrpProperty          *property;
+	ProjectPropertyCmdLabelEdited *cmd;
 	
 	priv = GET_PRIV (dialog);
 
@@ -346,7 +475,9 @@ property_dialog_label_edited (GtkCellRen
 			    COL_PROPERTY, &property,
 			    -1);
 
-	mrp_property_set_label (property, new_text);
+	cmd = (ProjectPropertyCmdLabelEdited*) project_property_cmd_label_edited (priv->main_window, 
+										property, 
+										new_text);
 
 	gtk_tree_path_free (path);
 }
@@ -442,8 +573,10 @@ property_dialog_setup_list (GtkWidget *d
 #endif
 	}
 
+	/* Create the mall for my stores */
+	priv->shop = g_new0 (MrpPropertyStore, 1);
 	
-	model = planner_property_model_new (priv->project, priv->type);
+	model = planner_property_model_new (priv->project, priv->owner, priv->shop);
 	priv->model = model;
 	
 	gtk_tree_view_set_model (tree, model);
@@ -483,8 +616,9 @@ property_dialog_setup_widgets (GtkWidget
 }
 
 GtkWidget *
-planner_property_dialog_new (MrpProject  *project,
-			GType        owner_type,
+planner_property_dialog_new 	(PlannerWindow   *main_window,
+				MrpProject       *project,
+				GType            owner,
 			const gchar *title)
 {
 	GladeXML             *glade;
@@ -504,8 +638,9 @@ planner_property_dialog_new (MrpProject 
 	
 	g_object_set_data (G_OBJECT (dialog), "priv", priv);
 
-	priv->type = owner_type;
+	priv->main_window = main_window;
 	priv->project = project;
+	priv->owner = owner;
 	
 	property_dialog_setup_widgets (dialog, glade);
 
@@ -545,3 +680,306 @@ planner_property_dialog_value_edited (Gt
 
 	gtk_tree_path_free (path);
 }
+
+
+/* Start of UNDO/REDO routines */
+
+static gboolean
+project_property_cmd_add_do (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdAdd   *cmd;
+	MrpProperty		*property;
+		
+	cmd = (ProjectPropertyCmdAdd*) cmd_base;
+
+	if (cmd->name == NULL) {
+		return FALSE;
+	}
+
+	property = mrp_property_new (cmd->name, 
+				     cmd->type,
+				     cmd->label_text,
+				     cmd->description,
+				     cmd->user_defined);
+			
+	mrp_project_add_property (cmd->project, 
+				  cmd->owner,
+				  property,
+				  cmd->user_defined);	
+		
+	/* This functions as a simple success check for the REDO/UNDO stuff. Check if its added. */
+	if (!mrp_project_has_property (cmd->project, cmd->owner, cmd->name)) {
+ 		g_warning ("%s: object of type '%s' still has no property named '%s'",
+			   G_STRLOC,
+			   g_type_name (cmd->owner),
+			   cmd->name);
+		return FALSE;
+	}
+	
+	return TRUE; 
+	
+}
+
+static void
+project_property_cmd_add_undo (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdAdd *cmd;
+		
+	cmd = (ProjectPropertyCmdAdd*) cmd_base;
+
+	if (cmd->name != NULL) {
+	
+		mrp_project_remove_property (cmd->project, 
+				  	     cmd->owner,
+				  	     cmd->name);
+			
+	/* This functions as a simple success check for the REDO/UNDO stuff. Check if its removed. */
+		if (mrp_project_has_property (cmd->project, cmd->owner, cmd->name)) {
+ 			g_warning ("%s: object of type '%s' still has the property named '%s'",
+				   G_STRLOC,
+			   	   g_type_name (cmd->owner),
+			   	   cmd->name);
+		}
+	}	
+}
+
+
+static void
+project_property_cmd_add_free (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdAdd  *cmd;
+
+	cmd = (ProjectPropertyCmdAdd*) cmd_base;	
+
+	g_free (cmd->name);
+	g_free (cmd->label_text);
+	g_free (cmd->description);
+	cmd->project = NULL;
+	cmd->window = NULL;
+}
+
+static 
+PlannerCmd *
+project_property_cmd_add 	(PlannerWindow *window,
+				MrpProject	*project,
+				GType		owner,
+				const gchar 	*name,
+				MrpPropertyType type,
+				const gchar     *label_text,
+				const gchar     *description,
+				gboolean	user_defined)
+{
+	PlannerCmd      *cmd_base;
+	ProjectPropertyCmdAdd  *cmd;
+
+	cmd = g_new0 (ProjectPropertyCmdAdd, 1);
+
+	cmd_base = (PlannerCmd*) cmd;
+
+	cmd_base->label = g_strdup (_("Add property"));
+	cmd_base->do_func =  project_property_cmd_add_do; 
+	cmd_base->undo_func = project_property_cmd_add_undo;
+	cmd_base->free_func = project_property_cmd_add_free;
+
+	cmd->window = window;
+	cmd->project = project;
+	cmd->owner = owner;
+	cmd->name = g_strdup (name);
+	cmd->type = type;
+	cmd->label_text = g_strdup (label_text);
+	cmd->description = g_strdup (description);
+	cmd->user_defined = user_defined;
+
+	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (window),
+					   cmd_base);
+
+	return cmd_base;
+}
+
+
+static gboolean
+project_property_cmd_remove_do (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdRemove *cmd;
+
+	cmd = (ProjectPropertyCmdRemove*) cmd_base;
+	
+	if (!mrp_project_has_property (cmd->project, cmd->owner, cmd->name)) {
+ 		g_warning ("%s: object of type '%s' has no property named '%s' to remove",
+			   G_STRLOC,
+			   g_type_name (cmd->owner),
+			   cmd->name);
+		return FALSE;
+	}
+
+	mrp_project_remove_property (cmd->project,
+				     cmd->owner,
+				     cmd->name);
+
+	return TRUE;
+}
+
+
+static void
+project_property_cmd_remove_undo (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdRemove *cmd;
+	MrpProperty  *property;
+	
+	cmd = (ProjectPropertyCmdRemove*) cmd_base;
+
+	if (cmd->name != NULL) {
+	
+		property = mrp_property_new (cmd->name, 
+				     cmd->type,
+				     cmd->label_text,
+				     cmd->description,
+				     cmd->user_defined);
+			
+		mrp_project_add_property (cmd->project, 
+				  cmd->owner,
+				  property,
+				  cmd->user_defined);
+				  
+			
+	/* This functions as a simple success check for the REDO/UNDO stuff. Check if its removed. */
+		if (!mrp_project_has_property (cmd->project, cmd->owner, cmd->name)) {
+ 			g_warning ("%s: object of type '%s' property named '%s' not restored.",
+				   G_STRLOC,
+			   	   g_type_name (cmd->owner),
+			   	   cmd->name);
+		}
+	}	
+}
+
+static void
+project_property_cmd_remove_free (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdRemove *cmd;
+
+	cmd = (ProjectPropertyCmdRemove*) cmd_base;
+
+	g_free (cmd->name);
+	g_free (cmd->label_text);
+	g_free (cmd->description);
+	cmd->project = NULL;
+	cmd->window = NULL;
+}
+
+static PlannerCmd *
+project_property_cmd_remove 	(PlannerWindow *window,
+				MrpProject	*project,
+				GType		owner,
+				const gchar 	*name)
+{
+	PlannerCmd      *cmd_base;
+	ProjectPropertyCmdRemove  *cmd;
+	MrpProperty     *property;
+
+	cmd = g_new0 (ProjectPropertyCmdRemove, 1);
+
+	cmd_base = (PlannerCmd*) cmd;
+
+	cmd_base->label = g_strdup (_("Remove property"));
+	cmd_base->do_func =   project_property_cmd_remove_do;
+	cmd_base->undo_func = project_property_cmd_remove_undo;
+	cmd_base->free_func = project_property_cmd_remove_free;
+
+	cmd->window = window;
+	cmd->project = project;
+	cmd->owner   = owner;
+	cmd->name = g_strdup (name);
+	/* Now remember also the old data so we can undo the remove */
+	property = mrp_project_get_property (project,
+					     name,
+					     owner);
+					     
+	cmd->type = mrp_property_get_property_type (property);
+	cmd->description = g_strdup (mrp_property_get_description (property));
+	cmd->label_text = g_strdup ( mrp_property_get_label (property));
+	cmd->user_defined = mrp_property_get_user_defined (property);
+
+	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (window),
+					   cmd_base);
+
+	return cmd_base;
+}
+
+/* Label Edited Routine */
+
+static gboolean
+project_property_cmd_label_edited_do (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdLabelEdited *cmd;
+
+	cmd = (ProjectPropertyCmdLabelEdited*) cmd_base;
+	
+	if (!cmd->property) {
+		return FALSE;
+	}
+	
+	mrp_property_set_label (cmd->property, cmd->new_text);
+		
+	return TRUE;
+}
+
+
+static void
+project_property_cmd_label_edited_undo (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdLabelEdited *cmd;
+		
+	cmd = (ProjectPropertyCmdLabelEdited*) cmd_base;
+
+	if (cmd->property != NULL) {
+
+	mrp_property_set_label (cmd->property, cmd->old_text);	
+	
+	}
+}
+
+static void
+project_property_cmd_label_edited_free (PlannerCmd *cmd_base)
+{
+	ProjectPropertyCmdLabelEdited *cmd;
+
+	cmd = (ProjectPropertyCmdLabelEdited*) cmd_base;
+
+	g_free (cmd->old_text);
+	g_free (cmd->new_text);
+	cmd->property = NULL;  
+	cmd->window = NULL;
+}
+
+static PlannerCmd *
+project_property_cmd_label_edited 	(PlannerWindow *window,
+					MrpProperty	*property,
+					const gchar 	*new_text)
+{
+	PlannerCmd      *cmd_base;
+	ProjectPropertyCmdLabelEdited  *cmd;
+	
+	cmd = g_new0 (ProjectPropertyCmdLabelEdited, 1);
+
+	cmd_base = (PlannerCmd*) cmd;
+
+	cmd_base->label = g_strdup (_("Edit property label"));
+	cmd_base->do_func =   project_property_cmd_label_edited_do;
+	cmd_base->undo_func = project_property_cmd_label_edited_undo;
+	cmd_base->free_func = project_property_cmd_label_edited_free;
+
+	cmd->window = window;
+	cmd->property = property;
+	cmd->new_text = g_strdup (new_text);
+		
+	/* Now remember also the old data so we can undo the label edit */
+
+	cmd->old_text = g_strdup ( mrp_property_get_label (property));
+	
+	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (window),
+					   cmd_base);
+
+	return cmd_base;
+}
+
+/* end of UNDO/REDO routines */
Index: src/planner-property-dialog.h
===================================================================
RCS file: /cvs/gnome/planner/src/planner-property-dialog.h,v
retrieving revision 1.2
diff -u -b -B -p -r1.2 planner-property-dialog.h
--- a/src/planner-property-dialog.h	11 Dec 2003 10:52:46 -0000	1.2
+++ b/src/planner-property-dialog.h	9 May 2004 19:32:38 -0000
@@ -24,8 +24,10 @@
 
 #include <gtk/gtkwidget.h>
 #include <libplanner/mrp-project.h>
+#include <planner-window.h>
 
-GtkWidget *planner_property_dialog_new           (MrpProject         *project,
+GtkWidget *planner_property_dialog_new      (PlannerWindow     *main_window,
+					    MrpProject         *project,
 					     GType               owner_type,
 					     const gchar        *title);
 
Index: src/planner-property-model.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-property-model.c,v
retrieving revision 1.1.1.1
diff -u -b -B -p -r1.1.1.1 planner-property-model.c
--- a/src/planner-property-model.c	1 Dec 2003 17:36:25 -0000	1.1.1.1
+++ b/src/planner-property-model.c	9 May 2004 19:32:38 -0000
@@ -31,13 +31,21 @@
 
 static void
 property_model_property_added_cb (MrpProject   *project,
-				  GType         object_type,
+				  GType         owner_type,
 				  MrpProperty  *property,
-				  GtkListStore *store)
+				  MrpPropertyStore  *shop)
 {
 	GtkTreeIter     iter;
 	MrpPropertyType type;
+	GtkListStore    *store;
+
+	if (owner_type != shop->owner_type) {  
+		return;
+	}
+
+	store = shop->store;
 
+	if (store) {
 	type = mrp_property_get_property_type (property);
 	
 	gtk_list_store_append (store, &iter);
@@ -48,6 +56,7 @@ property_model_property_added_cb (MrpPro
 			    COL_TYPE, mrp_property_type_as_string (type),
 			    COL_PROPERTY, property,
 			    -1);
+	}
 }
 
 static gboolean
@@ -126,7 +135,8 @@ property_model_property_changed_cb (MrpP
 
 GtkTreeModel *
 planner_property_model_new (MrpProject *project,
-		       GType       owner_type)
+		            GType      		owner_type,
+			    MrpPropertyStore	*shop)
 {
 	GtkListStore    *store;
 	GList           *properties, *l;
@@ -141,6 +151,9 @@ planner_property_model_new (MrpProject *
 				    G_TYPE_POINTER,
 				    G_TYPE_POINTER);
 	
+	shop->store = store;
+	shop->owner_type = owner_type;
+
 	properties = mrp_project_get_properties_from_type (project, 
 							   owner_type);
 
@@ -159,10 +172,14 @@ planner_property_model_new (MrpProject *
 				    -1);
 	}
 
+	/* We need to know which store to add the property so we pass the mall 
+	*  reference not the store. The mall is a structure table that correlates 
+	*  which store currently holds which owner.
+	*/ 
 	g_signal_connect (project,
 			  "property_added",
 			  G_CALLBACK (property_model_property_added_cb),
-			  store);
+			  shop);
 	
 	g_signal_connect (project,
 			  "property_removed",
Index: src/planner-property-model.h
===================================================================
RCS file: /cvs/gnome/planner/src/planner-property-model.h,v
retrieving revision 1.2
diff -u -b -B -p -r1.2 planner-property-model.h
--- a/src/planner-property-model.h	11 Dec 2003 10:52:46 -0000	1.2
+++ b/src/planner-property-model.h	9 May 2004 19:32:38 -0000
@@ -30,11 +30,22 @@ enum {
 	COL_LABEL,
 	COL_TYPE,
 	COL_VALUE,
-	COL_PROPERTY,
+	COL_PROPERTY
 };
 
+/* This was added because we were incorrectly adding properties to
+*  a store when we got a property-added message. stores are not typed
+*  per se and we can't extend them so created a 'shop' (i.e. a 
+*  type of store :) with an owner
+*/
+typedef struct {
+	GType		owner_type;
+	GtkListStore 	*store;
+} MrpPropertyStore;
+
 GtkTreeModel *planner_property_model_new (MrpProject *project,
-				     GType       owner_type);
+				     	GType       	owner_type,
+				     	MrpPropertyStore *shop);
 
 #endif /* __PLANNER_PROPERTY_MODEL_H__ */
 
Index: src/planner-resource-view.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-resource-view.c,v
retrieving revision 1.19
diff -u -b -B -p -r1.19 planner-resource-view.c
--- a/src/planner-resource-view.c	3 May 2004 05:23:52 -0000	1.19
+++ b/src/planner-resource-view.c	9 May 2004 19:32:42 -0000
@@ -166,6 +166,10 @@ static void    resource_view_property_re
 						      MrpProperty          *property,
 						      PlannerView          *view);
 
+static void    resource_view_property_changed        (MrpProject           *project, 
+						      MrpProperty          *property,
+						      PlannerView          *view);
+
 static void    resource_view_name_data_func          (GtkTreeViewColumn    *tree_column,
 						      GtkCellRenderer      *cell,
 						      GtkTreeModel         *tree_model,
@@ -450,6 +454,11 @@ get_widget (PlannerView *view)
 			  view);
 	
 	g_signal_connect (project, 
+			  "property_changed",
+			  G_CALLBACK (resource_view_property_changed),
+			  view);
+
+	g_signal_connect (project, 
 			  "resource_added",
 			  G_CALLBACK (resource_view_resource_added_cb), 
 			  view);
@@ -1046,7 +1055,8 @@ resource_view_edit_custom_props_cb (Bono
 	
 	project = planner_window_get_project (view->main_window);
 	
-	dialog = planner_property_dialog_new (project,
+	dialog = planner_property_dialog_new (view->main_window,
+						project,
 					      MRP_TYPE_RESOURCE,
 					      _("Edit custom resource properties"));
 	
@@ -2020,6 +2030,23 @@ resource_view_property_removed (MrpProje
 }
 
 static void
+resource_view_property_changed (MrpProject  *project, 
+			      MrpProperty *property,
+			      PlannerView *view)
+{
+	PlannerViewPriv   *priv;
+	GtkTreeViewColumn *col;
+
+	priv = view->priv;
+	
+	col = g_hash_table_lookup (priv->property_to_column, property);
+	if (col) {
+		gtk_tree_view_column_set_title (col, 
+					mrp_property_get_label (property));
+	}
+}
+
+static void
 resource_view_popup_menu (GtkWidget   *widget,
 			  PlannerView      *view)
 {
Index: src/planner-task-tree.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-task-tree.c,v
retrieving revision 1.24
diff -u -b -B -p -r1.24 planner-task-tree.c
--- a/src/planner-task-tree.c	9 May 2004 08:02:14 -0000	1.24
+++ b/src/planner-task-tree.c	9 May 2004 19:32:43 -0000
@@ -2203,6 +2203,23 @@ task_tree_property_removed (MrpProject  
 	}
 }
 
+static void
+task_tree_property_changed (MrpProject  *project,
+			    MrpProperty *property,
+			    PlannerTaskTree  *task_tree)
+{
+	PlannerTaskTreePriv *priv;
+	GtkTreeViewColumn   *col;
+
+	priv = task_tree->priv;
+	
+	col = g_hash_table_lookup (priv->property_to_column, property);
+	if (col) {
+		gtk_tree_view_column_set_title (col, 
+				mrp_property_get_label (property));
+	}
+}
+
 void
 planner_task_tree_set_model (PlannerTaskTree *tree,
 			     PlannerGanttModel *model)
@@ -2274,6 +2291,11 @@ task_tree_setup_tree_view (GtkTreeView  
 				  "property_removed",
 				  G_CALLBACK (task_tree_property_removed),
 				  tree);
+
+		g_signal_connect (project,
+				  "property_changed",
+				  G_CALLBACK (task_tree_property_changed),
+				  tree);
 	}
 }
 
Index: src/planner-task-view.c
===================================================================
RCS file: /cvs/gnome/planner/src/planner-task-view.c,v
retrieving revision 1.9
diff -u -b -B -p -r1.9 planner-task-view.c
--- a/src/planner-task-view.c	27 Apr 2004 18:58:02 -0000	1.9
+++ b/src/planner-task-view.c	9 May 2004 19:32:44 -0000
@@ -474,7 +474,8 @@ task_view_edit_custom_props_cb (BonoboUI
 	
 	project = planner_window_get_project (view->main_window);
 	
-	dialog = planner_property_dialog_new (project,
+	dialog = planner_property_dialog_new (view->main_window,
+					 project,
 					 MRP_TYPE_TASK,
 					 _("Edit custom task properties"));
 	


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