dia r4150 - in trunk: . app lib



Author: hans
Date: Sun Dec  7 22:09:16 2008
New Revision: 4150
URL: http://svn.gnome.org/viewvc/dia?rev=4150&view=rev

Log:
2008-12-07  Hans Breuer  <hans breuer org>

	* app/commands.c app/diagram_tree.c app/modify_tool.c app/properties.c
	  app/properties.h lib/group.c lib/object.h lib/propdesc.c 
	  lib/propdialogs.c lib/properties.h lib/propinternals.h
	  lib/propobject.c : : patch from Sameer Sahasrabuddhe almost fixing
	Dia's oldest bug #60331 - Object properties should handle multiple 
	objects (but it breaks with UM - Class)
	* lib/libdia.def : updated



Modified:
   trunk/ChangeLog
   trunk/app/commands.c
   trunk/app/diagram_tree.c
   trunk/app/modify_tool.c
   trunk/app/properties.c
   trunk/app/properties.h
   trunk/lib/group.c
   trunk/lib/libdia.def
   trunk/lib/object.h
   trunk/lib/propdesc.c
   trunk/lib/propdialogs.c
   trunk/lib/properties.h
   trunk/lib/propinternals.h
   trunk/lib/propobject.c

Modified: trunk/app/commands.c
==============================================================================
--- trunk/app/commands.c	(original)
+++ trunk/app/commands.c	Sun Dec  7 22:09:16 2008
@@ -1106,8 +1106,7 @@
   if (!dia || textedit_mode(ddisplay_active())) return;
 
   if (dia->data->selected != NULL) {
-    selected = dia->data->selected->data;
-    properties_show(dia, selected);
+    object_list_properties_show(dia, dia->data->selected);
   } else {
     diagram_properties_show(dia);
   } 

Modified: trunk/app/diagram_tree.c
==============================================================================
--- trunk/app/diagram_tree.c	(original)
+++ trunk/app/diagram_tree.c	Sun Dec  7 22:09:16 2008
@@ -516,7 +516,7 @@
       Diagram *dia = (Diagram *)gtk_ctree_node_get_row_data(tree->tree, parent);
       DiaObject *obj =
 	(DiaObject *)gtk_ctree_node_get_row_data(tree->tree, tree->last);
-      properties_show(dia, obj);
+      object_properties_show(dia, obj);
     }
   }
 }

Modified: trunk/app/modify_tool.c
==============================================================================
--- trunk/app/modify_tool.c	(original)
+++ trunk/app/modify_tool.c	Sun Dec  7 22:09:16 2008
@@ -308,7 +308,7 @@
   clicked_obj = click_select_object(ddisp, &clickedpoint, event);
   
   if ( clicked_obj != NULL ) {
-    properties_show(ddisp->diagram, clicked_obj);
+    object_list_properties_show(ddisp->diagram, ddisp->diagram->data->selected);
   } else { /* No object selected */
     /*printf("didn't select object\n");*/
     if (!(event->state & GDK_SHIFT_MASK)) {

Modified: trunk/app/properties.c
==============================================================================
--- trunk/app/properties.c	(original)
+++ trunk/app/properties.c	Sun Dec  7 22:09:16 2008
@@ -34,7 +34,7 @@
 static GtkWidget *dialog = NULL;
 static GtkWidget *dialog_vbox = NULL;
 static GtkWidget *object_part = NULL;
-static DiaObject *current_obj = NULL;
+static GList *current_objects = NULL;
 static Diagram *current_dia = NULL;
 
 static GtkWidget *no_properties_dialog = NULL;
@@ -45,7 +45,7 @@
 static gboolean properties_key_event(GtkWidget *widget,
 				     GdkEventKey *event,
 				     gpointer data);
-static void properties_dialog_hide();
+static void properties_dialog_hide(void);
 
 static void create_dialog()
 {
@@ -83,24 +83,6 @@
   g_object_ref_sink (G_OBJECT (no_properties_dialog));
 }
 
-static gint
-properties_part_destroyed(GtkWidget *widget, gpointer data)
-{
-  if (widget == object_part) {
-    object_part = NULL;
-    current_obj = NULL;
-    current_dia = NULL;
-  }
-  return 0;
-}
-
-static gint
-properties_dialog_destroyed(GtkWidget *widget, gpointer data)
-{
-  dialog = NULL;
-  return 0;
-}
-
 static gboolean
 properties_key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
 {
@@ -126,27 +108,33 @@
                    gpointer   data)
 {
   ObjectChange *obj_change = NULL;
+  gboolean set_tp = TRUE;
+  GList *tmp;
 
   if (   response_id == GTK_RESPONSE_APPLY 
       || response_id == GTK_RESPONSE_OK) {
-    if ((current_obj != NULL) && (current_dia != NULL)) {
-      object_add_updates(current_obj, current_dia);
-      obj_change = current_obj->ops->apply_properties_from_dialog(current_obj, object_part);
-      object_add_updates(current_obj, current_dia);
+    if ((current_objects != NULL) && (current_dia != NULL)) {
+      object_add_updates_list(current_objects, current_dia);
 
-      diagram_update_connections_object(current_dia, current_obj, TRUE);
+      for (tmp = current_objects; tmp != NULL; tmp = tmp->next) {
+	DiaObject *current_obj = (DiaObject*)tmp->data;
+	obj_change = current_obj->ops->apply_properties_from_dialog(current_obj, object_part);
+	object_add_updates(current_obj, current_dia);
+	diagram_update_connections_object(current_dia, current_obj, TRUE);
     
-      if (obj_change != NULL) {
-	undo_object_change(current_dia, current_obj, obj_change);
+	if (obj_change != NULL) {
+	  undo_object_change(current_dia, current_obj, obj_change);
+	  set_tp = set_tp && TRUE;
+	} else
+	  set_tp = FALSE;
+
+	diagram_object_modified(current_dia, current_obj);
       }
     
       diagram_modified(current_dia);
-
-      diagram_object_modified(current_dia, current_obj);
-
       diagram_update_extents(current_dia);
       
-      if (obj_change != NULL) {
+      if (set_tp) {
 	undo_set_transactionpoint(current_dia->undo);
       }  else {
 	message_warning(_("This object doesn't support Undo/Redo.\n"
@@ -186,41 +174,52 @@
   }
 }
 
+static void
+clear_dialog_globals()
+{
+  if (object_part != NULL) {
+    gtk_container_remove(GTK_CONTAINER(dialog_vbox), object_part);
+    object_part = NULL;
+  }
+  g_list_free(current_objects);
+  current_objects = NULL;
+  current_dia = NULL;
+}
+
 void
-properties_show(Diagram *dia, DiaObject *obj)
+object_properties_show(Diagram *dia, DiaObject *obj)
 {
-  GtkWidget *properties = NULL;
+  GList *tmp = NULL;
+  tmp = g_list_append(tmp, obj);
+  object_list_properties_show(dia, tmp);
+  g_list_free(tmp);
+}
 
-  if (obj != NULL) 
-    properties = obj->ops->get_properties(obj, FALSE);
+void
+object_list_properties_show(Diagram *dia, GList *objects)
+{
+  GtkWidget *properties;
 
-  if (dialog == NULL)
+  if (!dialog)
     create_dialog();
+  clear_dialog_globals();
 
-  if (obj==NULL) {
+  if (!objects) {
     /* Hide dialog when no object is selected */
     properties_dialog_hide();
     return;
   }
 
-  if (properties == NULL) { /* No properties or no object */
+  properties = object_list_create_props_dialog(objects, FALSE);
+  if (properties == NULL) {
     properties = no_properties_dialog;
-    obj = NULL;
-    dia = NULL;
   }
 
-  if (object_part != NULL) {
-    gtk_container_remove(GTK_CONTAINER(dialog_vbox), object_part);
-    object_part = NULL;
-    current_obj = NULL;
-    current_dia = NULL;
-  }
-
-  if (obj != NULL) {
-    DiaObjectType *otype;
+  if (g_list_length(objects) == 1) {
+    DiaObject *obj = (DiaObject*)objects->data;
+    DiaObjectType *otype = obj->type;
     gchar *buf;
-
-    otype = obj->type;
+    
     buf = g_strconcat(_("Properties: "), otype->name, NULL);
     gtk_window_set_title(GTK_WINDOW(dialog), buf);
     g_free(buf);
@@ -228,46 +227,60 @@
     gtk_window_set_title(GTK_WINDOW(dialog), _("Object properties:"));
   }
 
-  g_signal_connect (G_OBJECT (properties), "destroy",
-		  G_CALLBACK(properties_part_destroyed), NULL);
-  g_signal_connect (G_OBJECT (dialog), "destroy",
-		  G_CALLBACK(properties_dialog_destroyed), NULL);
-
   gtk_box_pack_start(GTK_BOX(dialog_vbox), properties, TRUE, TRUE, 0);
 
   gtk_widget_show (properties);
 
   properties_give_focus(properties, NULL);
 
-  if (obj != current_obj)
-    gtk_window_resize (GTK_WINDOW(dialog), 1, 1); /* resize to minimum */
+  /* resize to minimum */
+  /* if (obj != current_obj) */
+  gtk_window_resize (GTK_WINDOW(dialog), 1, 1);
   gtk_window_set_transient_for(GTK_WINDOW(dialog),
 			       GTK_WINDOW (ddisplay_active()->shell));
   gtk_window_present (GTK_WINDOW (dialog));
   object_part = properties;
-  current_obj = obj;
+  current_objects = g_list_copy(objects);
   current_dia = dia;
 }
 
-void properties_dialog_hide()
+void
+properties_dialog_hide(void)
 {
-  if (dialog)
-    gtk_widget_hide(dialog);
-  current_obj = NULL;
+  if (!dialog)
+    return;
+  clear_dialog_globals();
+  gtk_widget_hide(dialog);
 }
 
 void
 properties_hide_if_shown(Diagram *dia, DiaObject *obj)
 {
-  if (current_obj == obj) {
-    properties_show(dia, NULL);
+  if (g_list_find(current_objects, obj)) {
+    if (g_list_length(current_objects) == 1)
+      /* If obj is the only object shown, then we hide the dialog. */
+      properties_dialog_hide();
+    else {
+      /* else we remove this object and recreate the dialog. */
+      GList *tmp = g_list_copy(current_objects);
+      tmp = g_list_remove(tmp, obj);
+      object_list_properties_show(dia, tmp);
+      g_list_free(tmp);
+    }
   }
 }
 
 void
 properties_update_if_shown(Diagram *dia, DiaObject *obj)
 {
-  if (current_obj == obj) {
-    properties_show(dia, obj);
+  /* if there are multiple objects currently shown, there is no reason
+     why the properties of this object should be updated in the
+     dialog. */
+  if (g_list_length(current_objects) != 1)
+    return;
+  else {
+    /* FIXME: instead of recreating the dialog, there should be a way
+       to refresh the existing PropDialog widget. */
+    object_properties_show(dia, (DiaObject*)current_objects->data);
   }
 }

Modified: trunk/app/properties.h
==============================================================================
--- trunk/app/properties.h	(original)
+++ trunk/app/properties.h	Sun Dec  7 22:09:16 2008
@@ -21,7 +21,8 @@
 #include "object.h"
 #include "diagram.h"
 
-void properties_show(Diagram *dia, DiaObject *obj);
+void object_properties_show(Diagram *dia, DiaObject *obj);
+void object_list_properties_show(Diagram *dia, GList *objects);
 void properties_update_if_shown(Diagram *dia, DiaObject *obj);
 void properties_hide_if_shown(Diagram *dia, DiaObject *obj);
 

Modified: trunk/lib/group.c
==============================================================================
--- trunk/lib/group.c	(original)
+++ trunk/lib/group.c	Sun Dec  7 22:09:16 2008
@@ -35,7 +35,7 @@
 
   GList *objects;
 
-  PropDescription *pdesc;
+  const PropDescription *pdesc;
 };
 
 typedef struct _GroupPropChange GroupPropChange;
@@ -406,19 +406,10 @@
 {
   int i;
   if (group->pdesc == NULL) {
-    GList *descs = NULL, *tmp;
 
-    /* create list of property descriptions */
-    for (tmp = group->objects; tmp != NULL; tmp = tmp->next) {
-      const PropDescription *desc = NULL;
-      DiaObject *obj = tmp->data;
-
-      desc = object_get_prop_descriptions(obj);
-
-      if (desc) descs = g_list_append(descs, (gpointer)desc);
-    }
-    group->pdesc = prop_desc_lists_union(descs);
-    g_list_free(descs); /* XXX: haven't we got a leak here ? */
+    /* create list of property descriptions. this must be freed by the
+       DestroyFunc. */
+    group->pdesc = object_list_get_prop_descriptions(group->objects, PROP_UNION);
 
     if (group->pdesc != NULL) {
       /* hijack event delivery */

Modified: trunk/lib/libdia.def
==============================================================================
--- trunk/lib/libdia.def	(original)
+++ trunk/lib/libdia.def	Sun Dec  7 22:09:16 2008
@@ -486,6 +486,7 @@
  object_get_displayname
  object_init
  object_list_move_delta
+ object_list_create_props_dialog
  object_load
  object_load_props
  object_load_using_properties

Modified: trunk/lib/object.h
==============================================================================
--- trunk/lib/object.h	(original)
+++ trunk/lib/object.h	Sun Dec  7 22:09:16 2008
@@ -285,7 +285,9 @@
  *  This is one of the object_ops functions.
  * @param obj The object whose properties we want described.
  * @return a NULL-terminated array of property descriptions.
- * As the const return implies the returned data is not owned by  the caller.
+ * As the const return implies the returned data is not owned by  the
+ * caller. If this function returns a dynamically created description,
+ * then DestroyFunc must free the description.
  */
 typedef const PropDescription *(* DescribePropsFunc) (DiaObject *obj);
 

Modified: trunk/lib/propdesc.c
==============================================================================
--- trunk/lib/propdesc.c	(original)
+++ trunk/lib/propdesc.c	Sun Dec  7 22:09:16 2008
@@ -128,26 +128,35 @@
   GList *tmp;
 
   /* make sure the array is allocated */
+  /* FIXME: this doesn't seem to do anything useful if an error occurs. */
   g_array_append_val(arr, null_prop_desc);
   g_array_remove_index(arr, 0);
 
+  /* Each element in the list is a GArray of PropDescription,
+     terminated by a NULL element. */
   for (tmp = plists; tmp; tmp = tmp->next) {
     PropDescription *plist = tmp->data;
     int i;
 
     for (i = 0; plist[i].name != NULL; i++) {
       int j;
-#if 1
+
       if (plist[i].flags & PROP_FLAG_DONT_MERGE)
-        continue; /* even union must not conatin anything which can't be merged */
-#endif
+        continue; /* exclude anything that can't be merged */
+
+      /* Check to see if this PropDescription is already included in
+	 the union. */
       for (j = 0; j < arr->len; j++)
 	if (g_array_index(arr, PropDescription, j).quark == plist[i].quark)
 	  break;
+
+      /* Add to the union if it isn't already present. */
       if (j == arr->len)
 	g_array_append_val(arr, plist[i]);
     }
   }
+
+  /* Get the actually array and free the GArray wrapper. */
   ret = (PropDescription *)arr->data;
   g_array_free(arr, FALSE);
   return ret;
@@ -181,6 +190,8 @@
   g_array_remove_index(arr, 0);
 
   if (plists) {
+
+    /* initialise the intersection with the first list. */
     ret = plists->data;
     for (i = 0; ret[i].name != NULL; i++)
       g_array_append_val(arr, ret[i]);
@@ -192,6 +203,8 @@
       /* go through array in reverse so that removals don't stuff things up */
       for (i = arr->len - 1; i >= 0; i--) {
 	gint j;
+	/* FIXME: we can avoid a copy here by making cand a pointer to
+	   the data in the GArray. */
         PropDescription cand = g_array_index(arr,PropDescription,i);
         gboolean remove = TRUE;
 	for (j = 0; ret[j].name != NULL; j++) {

Modified: trunk/lib/propdialogs.c
==============================================================================
--- trunk/lib/propdialogs.c	(original)
+++ trunk/lib/propdialogs.c	Sun Dec  7 22:09:16 2008
@@ -38,16 +38,16 @@
 const gchar *prop_dialogdata_key = "object-props:dialogdata";
 
 static void prop_dialog_signal_destroy(GtkWidget *dialog_widget);
-static void prop_dialog_fill(PropDialog *dialog, DiaObject *obj, gboolean is_default);
+static void prop_dialog_fill(PropDialog *dialog, GList *objects, gboolean is_default);
 
 PropDialog *
-prop_dialog_new(DiaObject *obj, gboolean is_default) 
+prop_dialog_new(GList *objects, gboolean is_default) 
 {
   PropDialog *dialog = g_new0(PropDialog,1);
   dialog->props = NULL;
   dialog->widget = gtk_vbox_new(FALSE,1);
   dialog->prop_widgets = g_array_new(FALSE,TRUE,sizeof(PropWidgetAssoc));
-  dialog->obj_copy = NULL;
+  dialog->copies = NULL;
   dialog->curtable = NULL;
   dialog->containers = g_ptr_array_new();
 
@@ -57,7 +57,7 @@
   g_signal_connect (G_OBJECT (dialog->widget), "destroy",
                     G_CALLBACK (prop_dialog_signal_destroy), NULL);
 
-  prop_dialog_fill(dialog,obj,is_default);
+  prop_dialog_fill(dialog,objects,is_default);
 
   return dialog;
 }
@@ -68,7 +68,7 @@
   if (dialog->props) prop_list_free(dialog->props);
   g_array_free(dialog->prop_widgets,TRUE);
   g_ptr_array_free(dialog->containers,TRUE);
-  if (dialog->obj_copy) dialog->obj_copy->ops->destroy(dialog->obj_copy);
+  if (dialog->copies) destroy_object_list(dialog->copies);
   g_free(dialog);
 }
 
@@ -173,13 +173,11 @@
   if (ped) {
     PropDialog *dialog = ped->dialog;
     Property *prop = ped->self;
-    DiaObject *obj = dialog->obj_copy;
+    GList *list, *tmp;
     guint j;
 
-    g_assert(obj);
-    g_assert(object_complies_with_stdprop(obj));
-    g_assert(obj->ops->set_props);
-    g_assert(obj->ops->get_props);
+    list = dialog->copies;
+    g_return_if_fail(list);
 
     prop->experience &= ~PXP_NOTSET;
 
@@ -192,20 +190,18 @@
     /* obj is a scratch object ; we can do what we want with it. */
     prop_get_data_from_widgets(dialog);
 
-    obj->ops->set_props(obj,dialog->props);
-    prop->event_handler(obj,prop);
-    obj->ops->get_props(obj,dialog->props);
+    for (tmp = list; tmp != NULL; tmp = tmp->next) {
+      DiaObject *obj = (DiaObject*)tmp->data;
+      obj->ops->set_props(obj,dialog->props);
+      prop->event_handler(obj,prop);
+      obj->ops->get_props(obj,dialog->props);
+    }
 
     for (j = 0; j < dialog->prop_widgets->len; j++) {
       PropWidgetAssoc *pwa = 
         &g_array_index(dialog->prop_widgets,PropWidgetAssoc,j);
-      /*
-      g_message("going to reset widget %p for prop %s/%s "
-                "[in response to event on  %s/%s]",
-                pwa->widget,pwa->prop->type,pwa->prop->name,
-                prop->type,prop->name); */ 
       pwa->prop->ops->reset_widget(pwa->prop,pwa->widget);
-    } 
+    }
   } else {
     g_assert_not_reached();
   }
@@ -216,21 +212,11 @@
                     GtkObject *object,
                     const gchar *signal)
 {
-  DiaObject *obj = prop->self.dialog->obj_copy;
-
   if (0==strcmp(signal,"FIXME")) {
     g_warning("signal type unknown for this kind of property (name is %s), \n"
               "handler ignored.",prop->name);
     return;
   } 
-  if ((!obj->ops->set_props) || (!obj->ops->get_props)) {
-      g_warning("object has no [sg]et_props() routine(s).\n"
-                "event handler for property %s ignored.",
-                prop->name);
-      return;
-  }
-  
-  /* g_message("connected signal %s to property %s",signal,prop->name); */
 
   g_signal_connect (G_OBJECT (object),
                     signal,
@@ -245,9 +231,6 @@
   PropWidgetAssoc pwa;
   GtkWidget *label;
 
-  if (!dialog->obj_copy)
-    dialog->obj_copy = dialog->orig_obj->ops->copy(dialog->orig_obj);
-
   prop->self.dialog = dialog;
   prop->self.self = prop;
   prop->self.my_index = dialog->prop_widgets->len;
@@ -326,15 +309,17 @@
 }
 
 static void 
-prop_dialog_fill(PropDialog *dialog, DiaObject *obj, gboolean is_default) {
+prop_dialog_fill(PropDialog *dialog, GList *objects, gboolean is_default)
+{
   const PropDescription *pdesc;
   GPtrArray *props;
 
-  g_return_if_fail(object_complies_with_stdprop(obj));
+  g_return_if_fail(objects_comply_with_stdprop(objects));
 
-  dialog->orig_obj = obj;
+  dialog->objects = g_list_copy(objects);
+  dialog->copies = object_copy_list(objects);
 
-  pdesc = object_get_prop_descriptions(obj);
+  pdesc = object_list_get_prop_descriptions(objects, PROP_UNION);
   if (!pdesc) return;
 
   if (is_default)
@@ -345,7 +330,7 @@
   if (!props) return;
     
   dialog->props = props;
-  obj->ops->get_props(obj,props);
+  object_list_get_props(objects, props);
 
   prop_dialog_add_properties(dialog, props);
 }

Modified: trunk/lib/properties.h
==============================================================================
--- trunk/lib/properties.h	(original)
+++ trunk/lib/properties.h	Sun Dec  7 22:09:16 2008
@@ -64,9 +64,8 @@
   GArray *prop_widgets; /* of PropWidgetAssoc. This is a "flat" listing of 
                            properties and widgets (no nesting information is 
                            kept here) */
-  DiaObject *obj_copy; /* if !NULL, a copy of the object which can be used 
-                       as scratch. */
-  DiaObject *orig_obj; /* The original object (do not touch !) */
+  GList *objects; /* a copy of the objects, to be used as scratch. */
+  GList *copies;  /* The original objects. */
 
   GPtrArray *containers;
   WIDGET *lastcont;
@@ -239,6 +238,8 @@
 #define PROP_FLAG_WIDGET_ONLY 0x0080 /* only cosmetic property, no data */
 #define PROP_FLAG_OPTIONAL 0x0100 /* don't complain if it does not exist */
 
+typedef enum {PROP_UNION, PROP_INTERSECTION} PropMergeOption;
+
 #define PROP_DESC_END { NULL, 0, 0, NULL, NULL, NULL, 0 }
 
 /* extra data pointers for various property types */
@@ -403,10 +404,15 @@
 /* returns TRUE if this object can be handled (at least in part) through this
    library. */
 gboolean object_complies_with_stdprop(const DiaObject *obj);
+gboolean objects_comply_with_stdprop(GList *objects);
+
+void object_list_get_props(GList *objects, GPtrArray *props);
 
 /* will do whatever is needed to make the PropDescription * list look good to 
    the rest of the properties code. Can return NULL. */
 const PropDescription *object_get_prop_descriptions(const DiaObject *obj);
+const PropDescription *object_list_get_prop_descriptions(GList *objects,
+							 PropMergeOption option);
 
 gboolean object_get_props_from_offsets(DiaObject *obj, PropOffset *offsets,
 				       GPtrArray *props);
@@ -421,6 +427,7 @@
  * If is_default is set, this is a default dialog, not an object dialog.
  */
 WIDGET *object_create_props_dialog     (DiaObject *obj, gboolean is_default);
+WIDGET *object_list_create_props_dialog(GList *obj, gboolean is_default);
 ObjectChange *object_apply_props_from_dialog (DiaObject *obj, WIDGET *dialog);
 
 /* create a property from the object's property descriptors. To be freed with

Modified: trunk/lib/propinternals.h
==============================================================================
--- trunk/lib/propinternals.h	(original)
+++ trunk/lib/propinternals.h	Sun Dec  7 22:09:16 2008
@@ -64,7 +64,7 @@
 GtkWidget *prop_dialog_container_pop(PropDialog *dialog);
 void prop_dialog_add_property(PropDialog *dialog, Property *prop);
 
-PropDialog *prop_dialog_new(DiaObject *obj, gboolean is_default);
+PropDialog *prop_dialog_new(GList *objects, gboolean is_default);
 PropDialog *prop_dialog_from_widget(GtkWidget *dialog_widget);
 void prop_dialog_destroy(PropDialog *dialog);
 void prop_get_data_from_widgets(PropDialog *dialog);

Modified: trunk/lib/propobject.c
==============================================================================
--- trunk/lib/propobject.c	(original)
+++ trunk/lib/propobject.c	Sun Dec  7 22:09:16 2008
@@ -52,6 +52,31 @@
   return pdesc;
 }
 
+const PropDescription *
+object_list_get_prop_descriptions(GList *objects, PropMergeOption option)
+{
+  GList *descs = NULL, *tmp;
+  const PropDescription *pdesc;
+
+  for (tmp = objects; tmp != NULL; tmp = tmp->next) {
+    DiaObject *obj = tmp->data;
+    const PropDescription *desc = object_get_prop_descriptions(obj);
+
+    if (desc) descs = g_list_append(descs, (gpointer)desc);
+  }
+
+  if (option == PROP_UNION)
+    pdesc = prop_desc_lists_union(descs);
+  else
+    pdesc = prop_desc_lists_intersection(descs);
+
+  /* Important: Do not destroy the actual descriptions returned by the
+     objects. We don't own them. */
+  g_list_free(descs);
+
+  return pdesc;
+}
+
 
 /* ------------------------------------------------------ */
 /* Change management                                      */
@@ -149,7 +174,15 @@
 WIDGET *
 object_create_props_dialog(DiaObject *obj, gboolean is_default)
 {
-  return prop_dialog_new(obj, is_default)->widget;
+  GList *list = NULL;
+  list = g_list_append(list, obj);
+  return object_list_create_props_dialog(list, is_default);
+}
+
+WIDGET *
+object_list_create_props_dialog(GList *objects, gboolean is_default)
+{
+  return prop_dialog_new(objects, is_default)->widget;
 }
 
 
@@ -167,6 +200,19 @@
     return obj->ops->apply_properties_list(obj, dialog->props);
 }
 
+gboolean
+objects_comply_with_stdprop(GList *objects)
+{
+  GList *tmp = objects;
+
+  for (; tmp != NULL; tmp = tmp->next) {
+    const DiaObject *obj = (const DiaObject*)tmp->data;
+    if (!object_complies_with_stdprop(obj))
+      return FALSE;
+  }
+
+  return TRUE;
+}
 
 gboolean 
 object_complies_with_stdprop(const DiaObject *obj) 
@@ -190,6 +236,17 @@
   return TRUE;
 }
 
+void
+object_list_get_props(GList *objects, GPtrArray *props)
+{
+  GList *tmp = objects;
+
+  for (; tmp != NULL; tmp = tmp->next) {
+    DiaObject *obj = (DiaObject*)tmp->data;
+    obj->ops->get_props(obj,props);
+  }
+}
+
 static gboolean
 pdtpp_do_save_no_standard_default (const PropDescription *pdesc)
 {



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