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





Attached is version 0.9 of this patch.

Main changes -

- Refactored the project value get and set to have its own routines
    (mrp_project_property_get_value_string and
    mrp_project_property_set_value_string )

- I now use planner_cmd_new ()

- Fix legacy bug in mpp_property_added () (used dialog before
  checking) plus add some other checks to protect the dialog
  callbacks when they are open (remember we've got different
  property types floating around so if more than 1 dialog is
  open it can get false property-changed signals that were not
  intended for it.

- Other cleanups to patch as per Richard's comments.

****Note ****

This does not restore the resource or task properties if
the custom property was deleted from the project.

Thats a fairly major activity. We could work on that or
simply warn that there is NO undo for the values and add
that in a later Planner version e.g. 0.13 /1.0.

Individual value changes are undone (by acs) and all the
other stuff (property labels/add/remove by me) - its just
whole columns of values are not yet restored.

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	24 May 2004 04:18:33 -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,45 @@ typedef struct {
 	GtkWidget     *remove_property_button;
 } DialogData;
 
+/* Start of REDO/UNDO structures */
+
+typedef struct {
+	PlannerCmd   base;
+	
+	MrpProject        *project;
+	gchar	 	  *name; 
+	MrpPropertyType	  type;
+	gchar	 	  *label;
+	gchar	 	  *description;
+	GType		  owner;
+	gboolean	  user_defined;   
+} MrpPropertyCmdAdd;
+
+typedef struct {
+	PlannerCmd   base;
+	
+	MrpProject        *project;
+	gchar	 	  *name; 
+	MrpPropertyType	  type;
+	gchar	 	  *label;
+	gchar	 	  *description;
+	GType		  owner;
+	gboolean	  user_defined; 
+	gchar             *old_text;  
+} MrpPropertyCmdRemove;
+
+typedef struct {
+	PlannerCmd        base;
+
+	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 +161,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,
@@ -129,7 +173,46 @@ static void     mpp_property_value_edite
 						       gchar               *path_string,
 						       gchar               *new_text,
 						       GtkWidget           *dialog);
+const char     *mrp_project_property_get_value_string (MrpProject  	   *project,
+			  		  		MrpProperty 	   *property);
+static gboolean	mrp_project_property_set_value_string (MrpProject  	   *project,
+			  		   		MrpProperty  	   *property,
+					   		gchar  		   *text);
+
+/* 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 {
@@ -379,6 +462,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,12 +973,13 @@ mpp_property_added (MrpProject  *project
 		    MrpProperty *property,
 		    GtkWidget   *dialog)
 {
+	
+	g_return_if_fail (GTK_IS_DIALOG (dialog));
+	
 	DialogData   *data = DIALOG_GET_DATA (dialog);
 	GtkTreeModel *model;
 	GtkTreeIter   iter;
 	
-	g_return_if_fail (GTK_IS_DIALOG (dialog));
-	
 	model = gtk_tree_view_get_model (data->properties_tree);
 
 	if (object_type != MRP_TYPE_PROJECT ||
@@ -942,6 +1031,9 @@ mpp_property_removed (MrpProject  *proje
 		      MrpProperty *property,
 		      GtkWidget   *dialog)
 {
+
+	g_return_if_fail (GTK_IS_DIALOG (dialog));
+
 	DialogData       *data = DIALOG_GET_DATA (dialog);
 	GtkTreeModel     *model;
 	PropertyFindData *find_data;
@@ -971,6 +1063,50 @@ 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;
+	GtkTreeModel     *model;
+	PropertyFindData *find_data;
+	
+	/* Check for NULL here and shift the check for GTK_IS_DIALOG further in.
+	* The problem is with property_changed due to the way that there are 
+	*  3 types of properties so if you have different dialogs opened the 
+	*  wrong data can upset the open dialogs.
+	*/ 
+	g_return_if_fail (dialog);  
+
+	if (object_type == MRP_TYPE_PROJECT) {
+	
+		g_return_if_fail (GTK_IS_DIALOG (dialog));
+		data = DIALOG_GET_DATA (dialog);
+		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 +1199,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 +1210,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 +1284,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 +1321,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 +1348,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 +1378,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 +1390,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 +1554,480 @@ planner_project_properties_new (PlannerW
 	return dialog;
 }
 
+
+
+/*
+ * Gets the value of a MrpProperty and converts to a string.
+ * 
+ * Return value: A const char *, if found, otherwise NULL.
+ * NOTES: This can't be made part of mrp-project.c as it uses planner-format.h 
+ * and thats not in libplanner so a bit messy. Its obviously not able to be in
+ * mrp-properties.c as thats common to all projects and not just one. So this'll
+ * have to stay here for now.
+ *
+ */
+ 
+const char *
+mrp_project_property_get_value_string     (MrpProject  *project,
+			  		  MrpProperty *property)
+{
+	MrpPropertyType  type;
+	gchar           *svalue;
+	gint             ivalue;
+	gfloat           fvalue;
+	gint             work;
+	
+	g_return_val_if_fail (MRP_IS_PROJECT (project), NULL);
+
+	g_return_val_if_fail (property != NULL, NULL);
+
+	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 ("Property type not implemented.");
+		break;
+	}
+	return ((const char *) svalue);
+}
+
+static gboolean
+mrp_project_property_set_value_string (MrpProject  	*project,
+			  	       MrpProperty  	*property,
+				       gchar  		*text)
+{
+	MrpPropertyType		type;
+	gfloat			fvalue;
+	
+	g_return_val_if_fail (MRP_IS_PROJECT (project), FALSE);
+
+	g_return_val_if_fail (property != NULL, 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), 
+				text,
+				NULL);
+			break;
+		case MRP_PROPERTY_TYPE_INT:
+			mrp_object_set (MRP_OBJECT (project),
+				mrp_property_get_name (property), 
+				atoi (text),
+				NULL);
+			break;
+		case MRP_PROPERTY_TYPE_FLOAT:
+			fvalue = g_ascii_strtod (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 (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 (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);
+}
+		
+
+/* 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;
+}
+
+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_base = planner_cmd_new (MrpPropertyCmdAdd,
+				    _("Add project property"),
+ 				    mrp_property_cmd_add_do,
+				    mrp_property_cmd_add_undo,
+				    mrp_property_cmd_add_free);
+
+	cmd = (MrpPropertyCmdAdd *) cmd_base;
+	
+	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;
+	gchar			*new_text;
+	
+	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 */	
+	
+		mrp_project_property_set_value_string (project, property, new_text);
+			
+	/* 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;
+}
+
+static PlannerCmd *
+mrp_property_cmd_remove 	(PlannerWindow *window,
+				MrpProject	*project,
+				GType		owner,
+				const gchar 	*name)
+{
+	PlannerCmd      *cmd_base;
+	MrpPropertyCmdRemove  *cmd;
+	MrpProperty     *property;
+	
+	cmd_base = planner_cmd_new (MrpPropertyCmdRemove,
+				    _("Remove project property"),
+ 				    mrp_property_cmd_remove_do,
+				    mrp_property_cmd_remove_undo,
+				    mrp_property_cmd_remove_free);
+
+	cmd = (MrpPropertyCmdRemove *) cmd_base;
+		
+	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);
+
+	cmd->old_text = (gchar *) mrp_project_property_get_value_string (project, property);
+		
+	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;
+	MrpProject  		*project;
+	MrpProperty		*property;
+	gchar			*new_text;
+	
+	cmd = (MrpPropertyCmdValueEdited*) cmd_base;
+	
+	project = cmd->project;
+	property = cmd->property;
+	new_text = cmd->new_text;
+	
+	if (!cmd->property) {
+		return FALSE;
+	}
+	
+	return (mrp_project_property_set_value_string (project, property, new_text));
+}
+
+
+static void
+mrp_property_cmd_value_edited_undo (PlannerCmd *cmd_base)
+{
+	MrpPropertyCmdValueEdited *cmd;
+	MrpProject		*project;
+	MrpProperty		*property;
+	gchar			*new_text;
+	
+				
+	cmd = (MrpPropertyCmdValueEdited*) cmd_base;
+
+	property = cmd->property;
+	project = cmd->project;
+	new_text = cmd->old_text;
+	
+	if (cmd->property != NULL) {
+		mrp_project_property_set_value_string (project, property, new_text);
+	}
+}
+
+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->project = NULL;
+}
+
+static PlannerCmd *
+mrp_property_cmd_value_edited 	(PlannerWindow *window,
+				MrpProject	*project,
+				MrpProperty	*property,
+				const gchar 	*new_text)
+{
+	PlannerCmd      *cmd_base;
+	MrpPropertyCmdValueEdited  *cmd;
+	
+	cmd_base = planner_cmd_new (MrpPropertyCmdValueEdited,
+				    _("Edit project property value"),
+ 				    mrp_property_cmd_value_edited_do,
+				    mrp_property_cmd_value_edited_undo,
+				    mrp_property_cmd_value_edited_free);
+
+	cmd = (MrpPropertyCmdValueEdited *) cmd_base;
+	
+	cmd->property = property;
+	cmd->project = project;
+	cmd->new_text = g_strdup (new_text);
+		
+	cmd->old_text = (gchar *) mrp_project_property_get_value_string (project, 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.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	24 May 2004 04:18:34 -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 shop (a type of store) */
+	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,303 @@ 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_base = planner_cmd_new (ProjectPropertyCmdAdd,
+				   _("Add property"),
+				   project_property_cmd_add_do,
+				   project_property_cmd_add_undo,
+				   project_property_cmd_add_free);
+
+	cmd = (ProjectPropertyCmdAdd *) cmd_base;
+
+	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_base = planner_cmd_new (ProjectPropertyCmdRemove,
+				   _("Add property"),
+				   project_property_cmd_remove_do,
+				   project_property_cmd_remove_undo,
+				   project_property_cmd_remove_free);
+
+	cmd = (ProjectPropertyCmdRemove *) cmd_base;
+
+	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_base = planner_cmd_new (ProjectPropertyCmdLabelEdited,
+				   _("Add property"),
+				   project_property_cmd_label_edited_do,
+				   project_property_cmd_label_edited_undo,
+				   project_property_cmd_label_edited_free);
+
+	cmd = (ProjectPropertyCmdLabelEdited *) cmd_base;
+
+	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	24 May 2004 04:18:34 -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	24 May 2004 04:18:34 -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,15 @@ planner_property_model_new (MrpProject *
 				    -1);
 	}
 
+	/* We need to know which store to add the property so we pass the shop 
+	*  reference not the store. The shop is a structure that correlates 
+	*  which store currently holds which owner. We don't have to bother with
+	*  this when changing or removing - just adding.
+	*/ 
 	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	24 May 2004 04:18:34 -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	24 May 2004 04:18:38 -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.25
diff -u -b -B -p -r1.25 planner-task-tree.c
--- a/src/planner-task-tree.c	18 May 2004 03:09:41 -0000	1.25
+++ b/src/planner-task-tree.c	24 May 2004 04:18:39 -0000
@@ -2376,6 +2376,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)
@@ -2447,6 +2464,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	24 May 2004 04:18:40 -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]