← Back to team overview

geda-developers team mailing list archive

Multiattrib editor patch series

 

I was going to point people at a repp.or.cz mirror of my local branch,
but repo.or.cz seems to be down at the moment.

Attached is a little patch series to make the multi-attribute editor
more fun to use.

(I have a lot of "netclass" attributes to add on a number of nets for an
experiment I'm working on with class based clearances in PCB).

Best wishes,

Peter

-- 
Peter Clifton <peter.clifton@xxxxxxxxxxxxxxxxxxxxxxxxx>

Clifton Electronics
>From 18e9e0fbff262224a1a36c8b3a5719dc07d4e410 Mon Sep 17 00:00:00 2001
From: Peter Clifton <peter@xxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 21 Oct 2013 02:32:24 +0100
Subject: [PATCH 1/7] Fix zooming support broken in commit
 fb958cc4f6aec2b2a3b13a72f78d3dff2ae6ada9

Attach our x_event_scroll() handler to the drawing area, not the main window,
so we receive the event before the GtkScrolledWindow container.

Make x_event_scroll() return TRUE, stopping further signal processing, which
avoids both our, and the built-in GtkScrolledWindow signal handlers trying to
act on the event.
---
 gschem/src/x_event.c  | 3 ++-
 gschem/src/x_window.c | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/gschem/src/x_event.c b/gschem/src/x_event.c
index 73c7672..6367a3b 100644
--- a/gschem/src/x_event.c
+++ b/gschem/src/x_event.c
@@ -1377,7 +1377,8 @@ gint x_event_scroll (GtkWidget *widget, GdkEventScroll *event,
     o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
   }
 
-  return 0;
+  /* Stop further processing of this signal */
+  return TRUE;
 }
 
 
diff --git a/gschem/src/x_window.c b/gschem/src/x_window.c
index 4c041e6..8ae207c 100644
--- a/gschem/src/x_window.c
+++ b/gschem/src/x_window.c
@@ -141,10 +141,10 @@ void x_window_setup_draw_events(GschemToplevel *w_current)
     { "configure_event",      G_CALLBACK(x_event_configure)       },
     { "key_press_event",      G_CALLBACK(x_event_key)             },
     { "key_release_event",    G_CALLBACK(x_event_key)             },
+    { "scroll_event",         G_CALLBACK(x_event_scroll)          },
     { NULL,                   NULL                                } };
   struct event_reg_t main_window_events[] = {
     { "enter_notify_event",   G_CALLBACK(x_event_enter)           },
-    { "scroll_event",         G_CALLBACK(x_event_scroll)          },
     { NULL,                   NULL                                } };
   struct event_reg_t *tmp;
 
-- 
1.8.3.2

>From 95bd2ae27c7528aea5d2b0d25b1a28264f649eb0 Mon Sep 17 00:00:00 2001
From: Peter Clifton <peter@xxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 20 Oct 2013 18:31:40 +0100
Subject: [PATCH 2/7] gschem: Fix multi-attribute editor lockup when
 right-clicking during edit.

This fixes a lockup when right-clicking on the text-edit box for the
attribute value column during an edit. The context menu being popped
up would cause our cell to loose focus, and the editing to be cancelled.

In general, it feels nicer to leave the edit open until the user explicitly
cancels it anyway, and that fixes this issue - whilst departing from the
standard GTK behaviour. (Which is to cancel a cell edit if the edit box
looses focus, but, WITH special case code to handle the context menu case).

A followup patch will be required to add consistent focus / edit cancelling
behaviour on the name column, which uses the standard GTK widgets for editing.
---
 gschem/src/x_multiattrib.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gschem/src/x_multiattrib.c b/gschem/src/x_multiattrib.c
index f513c31..e931795 100644
--- a/gschem/src/x_multiattrib.c
+++ b/gschem/src/x_multiattrib.c
@@ -569,8 +569,8 @@ static gboolean cellrenderermultilinetext_focus_out_event(GtkWidget *widget,
 							  GdkEvent *event,
 							  gpointer user_data)
 {
-  cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget),
-                                          user_data);
+//  cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget),
+//                                          user_data);
 
   return FALSE;
 }
-- 
1.8.3.2

>From a407fabae7a25bc5a241dcd6b46ac263a185563a Mon Sep 17 00:00:00 2001
From: Peter Clifton <peter.clifton@xxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 20 Oct 2013 18:31:40 +0100
Subject: [PATCH 3/7] Revert "Move selection monitoring out of the multi attrib
 widget."

This reverts commit 1aaf6613a7c6991d858c1143ed3917675a115a5a.

This is the first step in implementing attribute editing multiple for
multiple objects at once. The SELECTION object is actually a smart list
of OBJECTs, with list-change notification. Passing this to the dialog
is NOT a break of abstraction, no more than passing a GList of OBJECTs
would be.

Think of the "selection" property of the multi-attribute editor as a
variable list of objects for it to edit, and there is no reason for
separating out this code.
---
 gschem/include/x_multiattrib.h |   3 +
 gschem/src/x_multiattrib.c     | 338 ++++++++++++++++++++---------------------
 2 files changed, 172 insertions(+), 169 deletions(-)

diff --git a/gschem/include/x_multiattrib.h b/gschem/include/x_multiattrib.h
index da0f87f..9c0d6e9 100644
--- a/gschem/include/x_multiattrib.h
+++ b/gschem/include/x_multiattrib.h
@@ -45,6 +45,7 @@ struct _MultiattribClass {
 struct _Multiattrib {
   GschemDialog parent_instance;
 
+  SELECTION *selection;
   OBJECT *object;
 
   GtkTreeView    *treeview;
@@ -59,6 +60,8 @@ struct _Multiattrib {
 
   GdkColor       value_normal_text_color;   /* Workaround for lameness in GtkTextView */
   GdkColor       insensitive_text_color;
+
+  gulong selection_changed_id;
 };
 
 
diff --git a/gschem/src/x_multiattrib.c b/gschem/src/x_multiattrib.c
index e931795..22e9b0d 100644
--- a/gschem/src/x_multiattrib.c
+++ b/gschem/src/x_multiattrib.c
@@ -35,146 +35,6 @@
 static void multiattrib_update (Multiattrib *multiattrib);
 
 
-/*! \brief Update the multiattrib editor dialog when the page's
- *         selection changes.
- *  \par Function Description
- *  When the page's selection changes this function identifies how
- *  many objects which can have attributes are currently selected. If
- *  this number is 1, the dialog is set to edit the attributes of the
- *  first selected object..
- *
- *  \param [in] selection  The SELECTION object of page being edited.
- *  \param [in] user_data  The multi-attribute editor dialog.
- */
-static void callback_selection_changed (SELECTION *selection,
-                                        gpointer   user_data)
-{
-  Multiattrib *multiattrib = MULTIATTRIB (user_data);
-  GList *iter;
-  OBJECT *object;
-  gint object_count = 0;
-
-  for (iter = geda_list_get_glist (selection);
-       iter != NULL;
-       iter = g_list_next (iter)) {
-    object = (OBJECT *)iter->data;
-    g_assert (object != NULL);
-
-    if (object->type == OBJ_COMPLEX ||
-        object->type == OBJ_PLACEHOLDER ||
-        object->type == OBJ_NET ||
-        object->type == OBJ_BUS ||
-        object->type == OBJ_PIN) {
-      object_count++;
-    }
-  }
-
-  if (object_count == 0) {
-    /* TODO: If the user selects a single attribute which is
-     *       not floating, should we find its parent object and
-     *       display the multi-attribute editor for that?
-     *       Bonus marks for making it jump to the correct attrib.
-     */
-    object = NULL;
-  } else if (object_count == 1) {
-    object = (OBJECT *)((geda_list_get_glist (selection))->data);
-  } else {
-    /* TODO: Something clever with multiple objects selected */
-    object = NULL;
-  }
-
-  g_object_set (multiattrib,
-                "object", object,
-                NULL);
-}
-
-#define DIALOG_DATA_SELECTION "current-selection"
-
-/*! \brief Update the dialog when the current page's SELECTION object
- *         is destroyed
- *  \par Function Description
- *  This handler is called when the g_object_weak_ref() on the
- *  SELECTION object we're watching expires. We reset our
- *  multiattrib->selection pointer to NULL to avoid attempting to
- *  access the destroyed object.
- *
- *  \note
- *  Our signal handlers were automatically disconnected during the
- *  destruction process.
- *
- *  \param [in] data                  Pointer to the multi-attrib dialog
- *  \param [in] where_the_object_was  Pointer to where the object was
- *                                    just destroyed
- */
-static void callback_selection_finalized (gpointer data,
-                                          GObject *where_the_object_was)
-{
-  Multiattrib *multiattrib = MULTIATTRIB (data);
-  g_object_set (multiattrib,
-                "object", NULL,
-                NULL);
-  g_object_set_data (G_OBJECT (multiattrib), DIALOG_DATA_SELECTION, NULL);
-}
-
-/*! \brief Add link between multiattrib dialog and current selection.
- *  \par Function Description
- *  This function connects a handler to the "changed" signal of
- *  current selection to let the dialog watch it. It also adds a weak
- *  reference on the selection.
- *
- *  \param [in] multiattrib  The Multiattrib dialog.
- *  \param [in] selection    The selection to watch.
- */
-static void connect_selection (Multiattrib *multiattrib,
-                               SELECTION   *selection)
-{
-  g_assert (g_object_get_data (G_OBJECT (multiattrib),
-                               DIALOG_DATA_SELECTION) == NULL);
-  g_object_set_data (G_OBJECT (multiattrib), DIALOG_DATA_SELECTION, selection);
-  g_object_weak_ref (G_OBJECT (selection),
-                     callback_selection_finalized,
-                     multiattrib);
-  g_signal_connect (selection,
-                    "changed",
-                    (GCallback)callback_selection_changed,
-                    multiattrib);
-  /* Synthesise a selection changed update to refresh the view */
-  callback_selection_changed (selection, multiattrib);
-}
-
-/*! \brief Remove the link between multiattrib dialog and selection.
- *  \par Function Description
- *  If the dialog is watching a selection, this function disconnects
- *  the "changed" signal and removes the weak reference it previously
- *  added on it.
- *
- *  \param [in] multiattrib  The Multiattrib dialog.
- */
-static void disconnect_selection (Multiattrib *multiattrib) {
-  SELECTION *selection;
-
-  /* get selection watched from dialog data */
-  selection = (SELECTION*)g_object_get_data (G_OBJECT (multiattrib),
-                                             DIALOG_DATA_SELECTION);
-  if (selection == NULL) {
-    /* no selection watched */
-    return;
-  }
-
-  g_signal_handlers_disconnect_matched (selection,
-                                        G_SIGNAL_MATCH_FUNC |
-                                        G_SIGNAL_MATCH_DATA,
-                                        0, 0, NULL,
-                                        callback_selection_changed,
-                                        multiattrib);
-  g_object_weak_unref (G_OBJECT (selection),
-                       callback_selection_finalized,
-                       multiattrib);
-
-  /* reset dialog data */
-  g_object_set_data (G_OBJECT (multiattrib), DIALOG_DATA_SELECTION, NULL);
-}
-
 /*! \brief Process the response returned by the multi-attribte dialog.
  *  \par Function Description
  *  This function handles the response <B>arg1</B> of the multi-attribute
@@ -194,8 +54,6 @@ multiattrib_callback_response (GtkDialog *dialog,
   switch (arg1) {
       case GTK_RESPONSE_CLOSE:
       case GTK_RESPONSE_DELETE_EVENT:
-        /* cut link from dialog to selection */
-        disconnect_selection (MULTIATTRIB (w_current->mawindow));
         gtk_widget_destroy (GTK_WIDGET (dialog));
         w_current->mawindow = NULL;
         break;
@@ -213,7 +71,7 @@ void x_multiattrib_open (GschemToplevel *w_current)
   if ( w_current->mawindow == NULL ) {
     w_current->mawindow =
       GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB,
-                                "object", NULL,
+                                "selection", w_current->toplevel->page_current->selection_list,
                                 /* GschemDialog */
                                 "settings-name", "multiattrib",
                                 "gschem-toplevel", w_current,
@@ -227,9 +85,6 @@ void x_multiattrib_open (GschemToplevel *w_current)
                       G_CALLBACK (multiattrib_callback_response),
                       w_current);
 
-    /* attach dialog to selection of current page */
-    x_multiattrib_update (w_current);
-
     gtk_widget_show (w_current->mawindow);
   } else {
     gtk_window_present (GTK_WINDOW(w_current->mawindow));
@@ -248,8 +103,6 @@ void x_multiattrib_open (GschemToplevel *w_current)
 void x_multiattrib_close (GschemToplevel *w_current)
 {
   if (w_current->mawindow != NULL) {
-    /* cut link from dialog to selection */
-    disconnect_selection (MULTIATTRIB (w_current->mawindow));
     gtk_widget_destroy (w_current->mawindow);
     w_current->mawindow = NULL;
   }
@@ -266,15 +119,10 @@ void x_multiattrib_close (GschemToplevel *w_current)
  */
 void x_multiattrib_update( GschemToplevel *w_current )
 {
-  if (!IS_MULTIATTRIB (w_current->mawindow)) {
-    return;
+  if (w_current->mawindow != NULL) {
+    g_object_set (G_OBJECT (w_current->mawindow), "selection",
+                  w_current->toplevel->page_current->selection_list, NULL);
   }
-
-  /* disconnect dialog from previous selection */
-  disconnect_selection (MULTIATTRIB (w_current->mawindow));
-  /* connect the dialog to the selection of the current page */
-  connect_selection (MULTIATTRIB (w_current->mawindow),
-                     w_current->toplevel->page_current->selection_list);
 }
 
 
@@ -622,7 +470,7 @@ static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass
 
 
 enum {
-  PROP_OBJECT = 1
+  PROP_SELECTION = 1
 };
 
 enum {
@@ -1734,6 +1582,154 @@ GType multiattrib_get_type()
   return multiattrib_type;
 }
 
+
+/*! \brief Update the multiattrib editor dialog when the page's selection changes.
+ *
+ *  \par Function Description
+ *
+ *  When the page's selection changes this function identifies how many objects
+ *  which can have attributes are currently selected. If this number is 1, the
+ *  dialog is set to edit its attributes.
+ *
+ *  \todo The dialog doesn't currently support editing multiple objects at once
+ *
+ *  \param [in] selection    The SELECTION object of page being edited.
+ *  \param [in] multiattrib  The multi-attribute editor dialog.
+ */
+static void selection_changed_cb (SELECTION *selection, Multiattrib *multiattrib)
+{
+  int object_count = 0;
+  GList *selection_glist;
+  GList *iter;
+  OBJECT *object;
+
+  selection_glist = geda_list_get_glist (selection);
+
+  for ( iter = selection_glist;
+        iter != NULL;
+        iter = g_list_next (iter) ) {
+    object = (OBJECT *)iter->data;
+    g_assert( object != NULL );
+
+    if (object->type == OBJ_COMPLEX ||
+        object->type == OBJ_PLACEHOLDER ||
+        object->type == OBJ_NET ||
+        object->type == OBJ_BUS ||
+        object->type == OBJ_PIN) {
+      object_count++;
+    }
+  }
+
+  if (object_count == 0) {
+    /* TODO: If the user selects a single attribute which is
+     *       not floating, should we find its parent object and
+     *       display the multi-attribute editor for that?
+     *       Bonus marks for making it jump to the correct attrib.
+     */
+    multiattrib->object = NULL;
+  } else if (object_count == 1) {
+    multiattrib->object = (OBJECT *)selection_glist->data;
+  } else {
+    /* TODO: Something clever with multiple objects selected */
+    multiattrib->object = NULL;
+  }
+
+  multiattrib_update (multiattrib);
+}
+
+
+/*! \brief Update the dialog when the current page's SELECTION object is destroyed
+ *
+ *  \par Function Description
+ *
+ *  This handler is called when the g_object_weak_ref() on the SELECTION object
+ *  we're watching expires. We reset our multiattrib->selection pointer to NULL
+ *  to avoid attempting to access the destroyed object. NB: Our signal handlers
+ *  were automatically disconnected during the destruction process.
+ *
+ *  \param [in] data                  Pointer to the multi-attrib dialog
+ *  \param [in] where_the_object_was  Pointer to where the object was just destroyed
+ */
+static void selection_weak_ref_cb (gpointer data, GObject *where_the_object_was)
+{
+  Multiattrib *multiattrib = (Multiattrib *)data;
+
+  multiattrib->selection = NULL;
+  multiattrib_update (multiattrib);
+}
+
+
+/*! \brief Connect signal handler and weak_ref on the SELECTION object
+ *
+ *  \par Function Description
+ *
+ *  Connect the "changed" signal and add a weak reference
+ *  on the SELECTION object we are going to watch.
+ *
+ *  \param [in] multiattrib  The Multiattrib dialog.
+ *  \param [in] selection    The SELECTION object to watch.
+ */
+static void connect_selection( Multiattrib *multiattrib, SELECTION *selection )
+{
+  multiattrib->selection = selection;
+  if (multiattrib->selection != NULL) {
+    g_object_weak_ref (G_OBJECT (multiattrib->selection),
+                       selection_weak_ref_cb,
+                       multiattrib);
+    multiattrib->selection_changed_id =
+      g_signal_connect (G_OBJECT (multiattrib->selection),
+                        "changed",
+                        G_CALLBACK (selection_changed_cb),
+                        multiattrib);
+    /* Synthesise a selection changed update to refresh the view */
+    selection_changed_cb (multiattrib->selection, multiattrib);
+  } else {
+    /* Call an update to set the sensitivities */
+    multiattrib_update (multiattrib);
+  }
+}
+
+
+/*! \brief Disconnect signal handler and weak_ref on the SELECTION object
+ *
+ *  \par Function Description
+ *
+ *  If the dialog is watching a SELECTION object, disconnect the
+ *  "changed" signal and remove our weak reference on the object.
+ *
+ *  \param [in] multiattrib  The Multiattrib dialog.
+ */
+static void disconnect_selection( Multiattrib *multiattrib )
+{
+  if (multiattrib->selection != NULL) {
+    g_signal_handler_disconnect (multiattrib->selection,
+                                 multiattrib->selection_changed_id);
+    g_object_weak_unref(G_OBJECT( multiattrib->selection ),
+                        selection_weak_ref_cb,
+                        multiattrib );
+  }
+}
+
+
+/*! \brief GObject finalise handler
+ *
+ *  \par Function Description
+ *
+ *  Just before the Multiattrib GObject is finalized, disconnect from
+ *  the SELECTION object being watched and then chain up to the parent
+ *  class's finalize handler.
+ *
+ *  \param [in] object  The GObject being finalized.
+ */
+static void multiattrib_finalize (GObject *object)
+{
+  Multiattrib *multiattrib = MULTIATTRIB(object);
+
+  disconnect_selection( multiattrib );
+  G_OBJECT_CLASS (multiattrib_parent_class)->finalize (object);
+}
+
+
 /*! \brief GType class initialiser for Multiattrib
  *
  *  \par Function Description
@@ -1753,12 +1749,13 @@ static void multiattrib_class_init(MultiattribClass *klass)
 
   gobject_class->set_property = multiattrib_set_property;
   gobject_class->get_property = multiattrib_get_property;
+  gobject_class->finalize     = multiattrib_finalize;
 
   multiattrib_parent_class = g_type_class_peek_parent (klass);
 
   g_object_class_install_property (
-    gobject_class, PROP_OBJECT,
-    g_param_spec_pointer ("object",
+    gobject_class, PROP_SELECTION,
+    g_param_spec_pointer ("selection",
                           "",
                           "",
                           G_PARAM_READWRITE));
@@ -2118,7 +2115,7 @@ static void multiattrib_init(Multiattrib *multiattrib)
 /*! \brief GObject property setter function
  *
  *  \par Function Description
- *  Setter function for Multiattrib's GObject property, "object".
+ *  Setter function for Multiattrib's GObject property, "selection".
  *
  *  \param [in]  object       The GObject whose properties we are setting
  *  \param [in]  property_id  The numeric id. under which the property was
@@ -2135,9 +2132,9 @@ static void multiattrib_set_property (GObject *object,
   Multiattrib *multiattrib = MULTIATTRIB (object);
 
   switch(property_id) {
-      case PROP_OBJECT:
-        multiattrib->object = (OBJECT*)g_value_get_pointer (value);
-        multiattrib_update (multiattrib);
+      case PROP_SELECTION:
+        disconnect_selection (multiattrib);
+        connect_selection (multiattrib, g_value_get_pointer (value));
         break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -2148,7 +2145,7 @@ static void multiattrib_set_property (GObject *object,
 /*! \brief GObject property getter function
  *
  *  \par Function Description
- *  Getter function for Multiattrib's GObject property, "object".
+ *  Getter function for Multiattrib's GObject property, "selection".
  *
  *  \param [in]  object       The GObject whose properties we are getting
  *  \param [in]  property_id  The numeric id. under which the property was
@@ -2164,8 +2161,8 @@ static void multiattrib_get_property (GObject *object,
   Multiattrib *multiattrib = MULTIATTRIB (object);
 
   switch(property_id) {
-      case PROP_OBJECT:
-        g_value_set_pointer (value, (gpointer)multiattrib->object);
+      case PROP_SELECTION:
+        g_value_set_pointer (value, (gpointer)multiattrib->selection);
         break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -2178,8 +2175,11 @@ static void multiattrib_get_property (GObject *object,
  *
  *  \par Function Description
  *
- *  Update the dialog to reflect the attributes of the object. If
- *  there is no object set, the dialog's controls are set insensitive.
+ *  Update the dialog to reflect the attributes of the currently selected
+ *  object. If no (or multiple) objects are selected, the dialog's controls
+ *  are set insensitive.
+ *
+ *  \todo The dialog doesn't currently support editing multiple objects at once
  *
  *  \param [in] multiattrib  The multi-attribute editor dialog.
  */
@@ -2219,7 +2219,7 @@ multiattrib_update (Multiattrib *multiattrib)
   gtk_list_store_clear (liststore);
 
   /* Update sensitivities */
-  sensitive = (multiattrib->object != NULL);
+  sensitive = (multiattrib->selection != NULL && multiattrib->object != NULL);
   gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_attributes), sensitive);
   gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_add), sensitive);
 
-- 
1.8.3.2

>From 278ef1990f2ccdb51d4f475908d9b5814fce6dd7 Mon Sep 17 00:00:00 2001
From: Peter Clifton <peter@xxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 20 Oct 2013 15:51:00 +0100
Subject: [PATCH 4/7] x_multiattrib.c: Pass the main multiattrib class to
 internal functions

This allows them to access the members they need internally, rather than
having to pass the relevant data in as parameters.
---
 gschem/src/x_multiattrib.c | 77 +++++++++++++++++++++-------------------------
 1 file changed, 35 insertions(+), 42 deletions(-)

diff --git a/gschem/src/x_multiattrib.c b/gschem/src/x_multiattrib.c
index 22e9b0d..4bfb7e1 100644
--- a/gschem/src/x_multiattrib.c
+++ b/gschem/src/x_multiattrib.c
@@ -1,7 +1,7 @@
 /* gEDA - GPL Electronic Design Automation
  * gschem - gEDA Schematic Capture
  * Copyright (C) 1998-2010 Ales Hvezda
- * Copyright (C) 1998-2011 gEDA Contributors (see ChangeLog for details)
+ * Copyright (C) 1998-2013 gEDA Contributors (see ChangeLog for details)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -500,16 +500,17 @@ static void multiattrib_popup_menu (Multiattrib *multiattrib,
  *  \par Function Description
  *
  */
-static void multiattrib_action_add_attribute(GschemToplevel *w_current,
-					     OBJECT *object,
-                                             Multiattrib *multiattrib,
-					     const gchar *name,
-					     const gchar *value,
-					     gint visible,
-					     gint show_name_value) 
+static void
+multiattrib_action_add_attribute (Multiattrib *multiattrib,
+                                  const gchar *name,
+                                  const gchar *value,
+                                  gint visible,
+                                  gint show_name_value)
 {
+  OBJECT *object = multiattrib->object;
   gchar *newtext;
-  
+  GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
+
   newtext = g_strdup_printf ("%s=%s", name, value);
 
   if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib), newtext)) {
@@ -533,10 +534,13 @@ static void multiattrib_action_add_attribute(GschemToplevel *w_current,
  *  \par Function Description
  *
  */
-static void multiattrib_action_duplicate_attribute(GschemToplevel *w_current,
-						   OBJECT *object,
-						   OBJECT *o_attrib) 
+static void
+multiattrib_action_duplicate_attribute (Multiattrib *multiattrib,
+                                        OBJECT *o_attrib)
 {
+  GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
+  OBJECT *object = multiattrib->object;
+
   int visibility = o_is_visible (w_current->toplevel, o_attrib)
       ? VISIBLE : INVISIBLE;
 
@@ -555,11 +559,13 @@ static void multiattrib_action_duplicate_attribute(GschemToplevel *w_current,
  *  \par Function Description
  *
  */
-static void multiattrib_action_promote_attribute (GschemToplevel *w_current,
-                                                  OBJECT *object,
-                                                  OBJECT *o_attrib)
+static void
+multiattrib_action_promote_attribute (Multiattrib *multiattrib,
+                                      OBJECT *o_attrib)
 {
+  GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
   TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
+  OBJECT *object = multiattrib->object;
   OBJECT *o_new;
 
   if (o_is_visible (toplevel, o_attrib)) {
@@ -589,9 +595,12 @@ static void multiattrib_action_promote_attribute (GschemToplevel *w_current,
  *  \par Function Description
  *
  */
-static void multiattrib_action_delete_attribute(GschemToplevel *w_current,
-						OBJECT *o_attrib) 
+static void
+multiattrib_action_delete_attribute (Multiattrib *multiattrib,
+                                     OBJECT *o_attrib)
 {
+  GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
+
   /* actually deletes the attribute */
   o_delete (w_current, o_attrib);
   o_undo_savestate (w_current, UNDO_ALL);
@@ -1068,8 +1077,7 @@ static gboolean multiattrib_callback_key_pressed(GtkWidget *widget,
     if (inherited)
       return FALSE;
 
-    multiattrib_action_delete_attribute (GSCHEM_DIALOG (multiattrib)->w_current,
-                                         o_attrib);
+    multiattrib_action_delete_attribute (multiattrib, o_attrib);
     
     /* update the treeview contents */
     multiattrib_update (multiattrib);
@@ -1164,9 +1172,8 @@ static void multiattrib_callback_popup_duplicate(GtkMenuItem *menuitem,
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  GschemToplevel *w_current;
-  OBJECT *object, *o_attrib;
-  
+  OBJECT *o_attrib;
+
   if (!gtk_tree_selection_get_selected (
         gtk_tree_view_get_selection (multiattrib->treeview),
         &model, &iter)) {
@@ -1174,15 +1181,12 @@ static void multiattrib_callback_popup_duplicate(GtkMenuItem *menuitem,
     return;
   }
 
-  w_current = GSCHEM_DIALOG (multiattrib)->w_current;
-  object   = multiattrib->object;
-  
   gtk_tree_model_get (model, &iter,
                       COLUMN_ATTRIBUTE, &o_attrib,
                       -1);
   g_assert (o_attrib->type == OBJ_TEXT);
 
-  multiattrib_action_duplicate_attribute (w_current, object, o_attrib);
+  multiattrib_action_duplicate_attribute (multiattrib, o_attrib);
 
   /* update the treeview contents */
   multiattrib_update (multiattrib);
@@ -1201,8 +1205,7 @@ static void multiattrib_callback_popup_promote (GtkMenuItem *menuitem,
   Multiattrib *multiattrib = user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  GschemToplevel *w_current;
-  OBJECT *object, *o_attrib;
+  OBJECT *o_attrib;
 
   if (!gtk_tree_selection_get_selected (
          gtk_tree_view_get_selection (multiattrib->treeview),
@@ -1211,15 +1214,12 @@ static void multiattrib_callback_popup_promote (GtkMenuItem *menuitem,
     return;
   }
 
-  w_current = GSCHEM_DIALOG (multiattrib)->w_current;
-  object = multiattrib->object;
-
   gtk_tree_model_get (model, &iter,
                       COLUMN_ATTRIBUTE, &o_attrib,
                       -1);
   g_assert (o_attrib->type == OBJ_TEXT);
 
-  multiattrib_action_promote_attribute (w_current, object, o_attrib);
+  multiattrib_action_promote_attribute (multiattrib, o_attrib);
 
   /* update the treeview contents */
   multiattrib_update (multiattrib);
@@ -1236,7 +1236,6 @@ static void multiattrib_callback_popup_delete(GtkMenuItem *menuitem,
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  GschemToplevel *w_current;
   OBJECT *o_attrib;
   
   if (!gtk_tree_selection_get_selected (
@@ -1246,14 +1245,12 @@ static void multiattrib_callback_popup_delete(GtkMenuItem *menuitem,
     return;
   }
 
-  w_current = GSCHEM_DIALOG (multiattrib)->w_current;
-
   gtk_tree_model_get (model, &iter,
                       COLUMN_ATTRIBUTE, &o_attrib,
                       -1);
   g_assert (o_attrib->type == OBJ_TEXT);
 
-  multiattrib_action_delete_attribute (w_current, o_attrib);
+  multiattrib_action_delete_attribute (multiattrib, o_attrib);
 
   /* update the treeview contents */
   multiattrib_update (multiattrib);
@@ -1328,15 +1325,11 @@ static void multiattrib_callback_button_add(GtkButton *button,
   GtkTextIter start, end;
   const gchar *name;
   gchar *value;
-  GschemToplevel *w_current;
-  OBJECT *object;
   gboolean visible;
   gint shownv;
 
-  w_current = GSCHEM_DIALOG (multiattrib)->w_current;
-  object   = multiattrib->object;
   buffer   = gtk_text_view_get_buffer (multiattrib->textview_value);
-  
+
   /* retrieve information from the Add/Edit frame */
   /*   - attribute's name */
   name = gtk_entry_get_text (
@@ -1356,7 +1349,7 @@ static void multiattrib_callback_button_add(GtkButton *button,
     return;
   }
 
-  multiattrib_action_add_attribute (w_current, object, multiattrib,
+  multiattrib_action_add_attribute (multiattrib,
                                     name, value,
                                     visible, shownv);
   g_free (value);
-- 
1.8.3.2

>From 1742596c79c75dc55ea5f83b8ee4ca710db41b3c Mon Sep 17 00:00:00 2001
From: Peter Clifton <peter@xxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 20 Oct 2013 16:09:42 +0100
Subject: [PATCH 5/7] x_multiattrib.[ch]: Whitespace changes for better code
 consistency

---
 gschem/include/x_multiattrib.h |   6 +-
 gschem/src/x_multiattrib.c     | 694 +++++++++++++++++++++--------------------
 2 files changed, 361 insertions(+), 339 deletions(-)

diff --git a/gschem/include/x_multiattrib.h b/gschem/include/x_multiattrib.h
index 9c0d6e9..8df1aeb 100644
--- a/gschem/include/x_multiattrib.h
+++ b/gschem/include/x_multiattrib.h
@@ -39,7 +39,7 @@ typedef struct _Multiattrib      Multiattrib;
 
 struct _MultiattribClass {
   GschemDialogClass parent_class;
-  
+
 };
 
 struct _Multiattrib {
@@ -84,7 +84,7 @@ typedef struct _CellTextView      CellTextView;
 
 struct _CellTextViewClass {
   GtkTextViewClass parent_class;
-  
+
 };
 
 struct _CellTextView {
@@ -113,7 +113,7 @@ typedef struct _CellRendererMultiLineText      CellRendererMultiLineText;
 
 struct _CellRendererMultiLineTextClass {
   GtkCellRendererTextClass parent_class;
-  
+
 };
 
 struct _CellRendererMultiLineText {
diff --git a/gschem/src/x_multiattrib.c b/gschem/src/x_multiattrib.c
index 4bfb7e1..068f89c 100644
--- a/gschem/src/x_multiattrib.c
+++ b/gschem/src/x_multiattrib.c
@@ -66,7 +66,8 @@ multiattrib_callback_response (GtkDialog *dialog,
  *
  *  \param [in] w_current  The GschemToplevel object.
  */
-void x_multiattrib_open (GschemToplevel *w_current)
+void
+x_multiattrib_open (GschemToplevel *w_current)
 {
   if ( w_current->mawindow == NULL ) {
     w_current->mawindow =
@@ -100,7 +101,8 @@ void x_multiattrib_open (GschemToplevel *w_current)
  *
  *  \param [in] w_current  The GschemToplevel object.
  */
-void x_multiattrib_close (GschemToplevel *w_current)
+void
+x_multiattrib_close (GschemToplevel *w_current)
 {
   if (w_current->mawindow != NULL) {
     gtk_widget_destroy (w_current->mawindow);
@@ -117,7 +119,8 @@ void x_multiattrib_close (GschemToplevel *w_current)
  *
  *  \param [in] w_current  The GschemToplevel object.
  */
-void x_multiattrib_update( GschemToplevel *w_current )
+void
+x_multiattrib_update (GschemToplevel *w_current)
 {
   if (w_current->mawindow != NULL) {
     g_object_set (G_OBJECT (w_current->mawindow), "selection",
@@ -139,10 +142,11 @@ enum {
     PROP_EDIT_CANCELED = 1
 };
 
-static void celltextview_set_property (GObject *object,
-                                       guint property_id,
-                                       const GValue *value,
-                                       GParamSpec *pspec)
+static void
+celltextview_set_property (GObject *object,
+                           guint property_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
 {
   CellTextView *celltextview = (CellTextView*) object;
 
@@ -155,10 +159,11 @@ static void celltextview_set_property (GObject *object,
   }
 }
 
-static void celltextview_get_property (GObject *object,
-                                       guint property_id,
-                                       GValue *value,
-                                       GParamSpec *pspec)
+static void
+celltextview_get_property (GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
 {
   CellTextView *celltextview = (CellTextView*) object;
 
@@ -177,9 +182,10 @@ static void celltextview_get_property (GObject *object,
  *  \par Function Description
  *
  */
-static gboolean celltextview_key_press_event (GtkWidget   *widget,
-                                              GdkEventKey *key_event,
-                                              gpointer     data)
+static gboolean
+celltextview_key_press_event (GtkWidget   *widget,
+                              GdkEventKey *key_event,
+                              gpointer     data)
 {
   CellTextView *celltextview = (CellTextView*)widget;
 
@@ -206,14 +212,14 @@ static gboolean celltextview_key_press_event (GtkWidget   *widget,
  *  \par Function Description
  *
  */
-static void celltextview_start_editing (GtkCellEditable *cell_editable,
-					GdkEvent        *event)
+static void
+celltextview_start_editing (GtkCellEditable *cell_editable,
+                            GdkEvent        *event)
 {
   g_signal_connect (cell_editable,
                     "key_press_event",
                     G_CALLBACK (celltextview_key_press_event),
                     NULL);
-  
 }
 
 /*! \todo Finish function documentation
@@ -221,10 +227,11 @@ static void celltextview_start_editing (GtkCellEditable *cell_editable,
  *  \par Function Description
  *
  */
-GType celltextview_get_type()
+GType
+celltextview_get_type ()
 {
   static GType celltextview_type = 0;
-  
+
   if (!celltextview_type) {
     static const GTypeInfo celltextview_info = {
       sizeof(CellTextViewClass),
@@ -243,15 +250,15 @@ GType celltextview_get_type()
       NULL, /* interface_finalize */
       NULL  /* interface_data */
     };
-		
-    celltextview_type = g_type_register_static(GTK_TYPE_TEXT_VIEW,
-					       "CellTextView",
-					       &celltextview_info, 0);
-    g_type_add_interface_static(celltextview_type,
-				GTK_TYPE_CELL_EDITABLE,
-				&cell_editable_info);
+
+    celltextview_type = g_type_register_static (GTK_TYPE_TEXT_VIEW,
+                                                "CellTextView",
+                                                &celltextview_info, 0);
+    g_type_add_interface_static (celltextview_type,
+                                 GTK_TYPE_CELL_EDITABLE,
+                                 &cell_editable_info);
   }
-  
+
   return celltextview_type;
 }
 
@@ -260,7 +267,8 @@ GType celltextview_get_type()
  *  \par Function Description
  *
  */
-static void celltextview_class_init(CellTextViewClass *klass)
+static void
+celltextview_class_init (CellTextViewClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
@@ -282,7 +290,8 @@ static void celltextview_class_init(CellTextViewClass *klass)
  *  \par Function Description
  *
  */
-static void celltextview_init(CellTextView *celltextview)
+static void
+celltextview_init (CellTextView *celltextview)
 {
   celltextview->editing_canceled = FALSE;
 }
@@ -292,7 +301,8 @@ static void celltextview_init(CellTextView *celltextview)
  *  \par Function Description
  *
  */
-static void celltextview_cell_editable_init(GtkCellEditableIface *iface)
+static void
+celltextview_cell_editable_init (GtkCellEditableIface *iface)
 {
   iface->start_editing = celltextview_start_editing;
 }
@@ -302,7 +312,7 @@ static void celltextview_cell_editable_init(GtkCellEditableIface *iface)
  * in gschem code. It is inspired by the 'GtkCellRendererCombo' renderer
  * of GTK 2.4 (LGPL).
  */
-static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass *klass);
+static void cellrenderermultilinetext_class_init (CellRendererMultiLineTextClass *klass);
 static void cellrenderermultilinetext_editing_done (GtkCellEditable *cell_editable,
                                                     gpointer         user_data);
 static gboolean cellrenderermultilinetext_focus_out_event (GtkWidget *widget,
@@ -318,19 +328,20 @@ static gboolean cellrenderermultilinetext_focus_out_event (GtkWidget *widget,
  *  \par Function Description
  *
  */
-static GtkCellEditable* cellrenderermultilinetext_start_editing(GtkCellRenderer      *cell,
-								GdkEvent             *event,
-								GtkWidget            *widget,
-								const gchar          *path,
-								GdkRectangle         *background_area,
-								GdkRectangle         *cell_area,
-								GtkCellRendererState  flags)
+static GtkCellEditable*
+cellrenderermultilinetext_start_editing (GtkCellRenderer      *cell,
+                                         GdkEvent             *event,
+                                         GtkWidget            *widget,
+                                         const gchar          *path,
+                                         GdkRectangle         *background_area,
+                                         GdkRectangle         *cell_area,
+                                         GtkCellRendererState  flags)
 {
   GtkCellRendererText *cell_text;
   CellRendererMultiLineText *cell_mlt;
   GtkWidget *textview;
   GtkTextBuffer *textbuffer;
-  
+
   cell_text = GTK_CELL_RENDERER_TEXT (cell);
   if (cell_text->editable == FALSE) {
     return NULL;
@@ -375,8 +386,9 @@ static GtkCellEditable* cellrenderermultilinetext_start_editing(GtkCellRenderer
  *  \par Function Description
  *
  */
-static void cellrenderermultilinetext_editing_done(GtkCellEditable *cell_editable,
-						   gpointer         user_data)
+static void
+cellrenderermultilinetext_editing_done (GtkCellEditable *cell_editable,
+                                        gpointer         user_data)
 {
   CellRendererMultiLineText *cell = CELL_RENDERER_MULTI_LINE_TEXT (user_data);
   GtkTextBuffer *buffer;
@@ -405,7 +417,6 @@ static void cellrenderermultilinetext_editing_done(GtkCellEditable *cell_editabl
   g_signal_emit_by_name (cell, "edited", path, new_text);
 
   g_free (new_text);
-
 }
 
 /*! \todo Finish function documentation
@@ -413,9 +424,10 @@ static void cellrenderermultilinetext_editing_done(GtkCellEditable *cell_editabl
  *  \par Function Description
  *
  */
-static gboolean cellrenderermultilinetext_focus_out_event(GtkWidget *widget,
-							  GdkEvent *event,
-							  gpointer user_data)
+static gboolean
+cellrenderermultilinetext_focus_out_event (GtkWidget *widget,
+                                           GdkEvent *event,
+                                           gpointer user_data)
 {
 //  cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget),
 //                                          user_data);
@@ -428,10 +440,11 @@ static gboolean cellrenderermultilinetext_focus_out_event(GtkWidget *widget,
  *  \par Function Description
  *
  */
-GType cellrenderermultilinetext_get_type()
+GType
+cellrenderermultilinetext_get_type ()
 {
   static GType cellrenderermultilinetext_type = 0;
-  
+
   if (!cellrenderermultilinetext_type) {
     static const GTypeInfo cellrenderermultilinetext_info = {
       sizeof(CellRendererMultiLineTextClass),
@@ -444,13 +457,13 @@ GType cellrenderermultilinetext_get_type()
       0,    /* n_preallocs */
       NULL, /* instance_init */
     };
-		
+
     cellrenderermultilinetext_type = g_type_register_static (
       GTK_TYPE_CELL_RENDERER_TEXT,
       "CellRendererMultiLineText",
       &cellrenderermultilinetext_info, 0);
   }
-  
+
   return cellrenderermultilinetext_type;
 }
 
@@ -459,13 +472,13 @@ GType cellrenderermultilinetext_get_type()
  *  \par Function Description
  *
  */
-static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass *klass)
+static void
+cellrenderermultilinetext_class_init (CellRendererMultiLineTextClass *klass)
 {
 /*   GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
 
   cell_class->start_editing = cellrenderermultilinetext_start_editing;
-  
 }
 
 
@@ -526,7 +539,6 @@ multiattrib_action_add_attribute (Multiattrib *multiattrib,
   o_undo_savestate (w_current, UNDO_ALL);
 
   g_free (newtext);
-
 }
 
 /*! \todo Finish function documentation
@@ -551,7 +563,6 @@ multiattrib_action_duplicate_attribute (Multiattrib *multiattrib,
                        object);
   w_current->toplevel->page_current->CHANGED = 1;
   o_undo_savestate (w_current, UNDO_ALL);
-
 }
 
 /*! \todo Finish function documentation
@@ -571,10 +582,10 @@ multiattrib_action_promote_attribute (Multiattrib *multiattrib,
   if (o_is_visible (toplevel, o_attrib)) {
     /* If the attribute we're promoting is visible, don't clone its location */
     o_attrib_add_attrib (w_current,
-			 o_text_get_string (w_current->toplevel, o_attrib),
-			 VISIBLE,
-			 o_attrib->show_name_value,
-			 object);
+                         o_text_get_string (w_current->toplevel, o_attrib),
+                         VISIBLE,
+                         o_attrib->show_name_value,
+                         object);
   } else {
       /* make a copy of the attribute object */
       o_new = o_object_copy (toplevel, o_attrib);
@@ -604,7 +615,6 @@ multiattrib_action_delete_attribute (Multiattrib *multiattrib,
   /* actually deletes the attribute */
   o_delete (w_current, o_attrib);
   o_undo_savestate (w_current, UNDO_ALL);
-
 }
 
 /*! \todo Finish function documentation
@@ -612,11 +622,12 @@ multiattrib_action_delete_attribute (Multiattrib *multiattrib,
  *  \par Function Description
  *
  */
-static void multiattrib_column_set_data_name(GtkTreeViewColumn *tree_column,
-					     GtkCellRenderer *cell,
-					     GtkTreeModel *tree_model,
-					     GtkTreeIter *iter,
-					     gpointer data)
+static void
+multiattrib_column_set_data_name (GtkTreeViewColumn *tree_column,
+                                  GtkCellRenderer *cell,
+                                  GtkTreeModel *tree_model,
+                                  GtkTreeIter *iter,
+                                  gpointer data)
 {
   OBJECT *o_attrib;
   gchar *name;
@@ -637,7 +648,6 @@ static void multiattrib_column_set_data_name(GtkTreeViewColumn *tree_column,
                 "editable", !inherited,
                 NULL);
   g_free (name);
-  
 }
 
 /*! \todo Finish function documentation
@@ -645,11 +655,12 @@ static void multiattrib_column_set_data_name(GtkTreeViewColumn *tree_column,
  *  \par Function Description
  *
  */
-static void multiattrib_column_set_data_value(GtkTreeViewColumn *tree_column,
-					      GtkCellRenderer *cell,
-					      GtkTreeModel *tree_model,
-					      GtkTreeIter *iter,
-					      gpointer data)           
+static void
+multiattrib_column_set_data_value (GtkTreeViewColumn *tree_column,
+                                   GtkCellRenderer *cell,
+                                   GtkTreeModel *tree_model,
+                                   GtkTreeIter *iter,
+                                   gpointer data)
 {
   OBJECT *o_attrib;
   gchar *value;
@@ -670,7 +681,6 @@ static void multiattrib_column_set_data_value(GtkTreeViewColumn *tree_column,
                 "editable", !inherited,
                 NULL);
   g_free (value);
-  
 }
 
 /*! \todo Finish function documentation
@@ -678,11 +688,12 @@ static void multiattrib_column_set_data_value(GtkTreeViewColumn *tree_column,
  *  \par Function Description
  *
  */
-static void multiattrib_column_set_data_visible(GtkTreeViewColumn *tree_column,
-						GtkCellRenderer *cell,
-						GtkTreeModel *tree_model,
-						GtkTreeIter *iter,
-						gpointer data)
+static void
+multiattrib_column_set_data_visible (GtkTreeViewColumn *tree_column,
+                                     GtkCellRenderer *cell,
+                                     GtkTreeModel *tree_model,
+                                     GtkTreeIter *iter,
+                                     gpointer data)
 {
   OBJECT *o_attrib;
   GschemDialog *dialog = GSCHEM_DIALOG (data);
@@ -692,7 +703,7 @@ static void multiattrib_column_set_data_visible(GtkTreeViewColumn *tree_column,
                       COLUMN_ATTRIBUTE, &o_attrib,
                       -1);
   g_assert (o_attrib->type == OBJ_TEXT);
-  
+
   inherited = o_attrib_is_inherited (o_attrib);
 
   g_object_set (cell,
@@ -700,7 +711,6 @@ static void multiattrib_column_set_data_visible(GtkTreeViewColumn *tree_column,
                 "sensitive",   !inherited,
                 "activatable", !inherited,
                 NULL);
-  
 }
 
 /*! \todo Finish function documentation
@@ -708,11 +718,12 @@ static void multiattrib_column_set_data_visible(GtkTreeViewColumn *tree_column,
  *  \par Function Description
  *
  */
-static void multiattrib_column_set_data_show_name(GtkTreeViewColumn *tree_column,
-						  GtkCellRenderer *cell,
-						  GtkTreeModel *tree_model,
-						  GtkTreeIter *iter,
-						  gpointer data)
+static void
+multiattrib_column_set_data_show_name (GtkTreeViewColumn *tree_column,
+                                       GtkCellRenderer *cell,
+                                       GtkTreeModel *tree_model,
+                                       GtkTreeIter *iter,
+                                       gpointer data)
 {
   OBJECT *o_attrib;
   int inherited;
@@ -721,7 +732,7 @@ static void multiattrib_column_set_data_show_name(GtkTreeViewColumn *tree_column
                       COLUMN_ATTRIBUTE, &o_attrib,
                       -1);
   g_assert (o_attrib->type == OBJ_TEXT);
-  
+
   inherited = o_attrib_is_inherited (o_attrib);
 
   g_object_set (cell,
@@ -730,7 +741,6 @@ static void multiattrib_column_set_data_show_name(GtkTreeViewColumn *tree_column
                 "sensitive",   !inherited,
                 "activatable", !inherited,
                 NULL);
-  
 }
 
 /*! \todo Finish function documentation
@@ -738,11 +748,12 @@ static void multiattrib_column_set_data_show_name(GtkTreeViewColumn *tree_column
  *  \par Function Description
  *
  */
-static void multiattrib_column_set_data_show_value(GtkTreeViewColumn *tree_column,
-						   GtkCellRenderer *cell,
-						   GtkTreeModel *tree_model,
-						   GtkTreeIter *iter,
-						   gpointer data)
+static void
+multiattrib_column_set_data_show_value (GtkTreeViewColumn *tree_column,
+                                        GtkCellRenderer *cell,
+                                        GtkTreeModel *tree_model,
+                                        GtkTreeIter *iter,
+                                        gpointer data)
 {
   OBJECT *o_attrib;
   int inherited;
@@ -751,7 +762,7 @@ static void multiattrib_column_set_data_show_value(GtkTreeViewColumn *tree_colum
                       COLUMN_ATTRIBUTE, &o_attrib,
                       -1);
   g_assert (o_attrib->type == OBJ_TEXT);
-  
+
   inherited = o_attrib_is_inherited (o_attrib);
 
   g_object_set (cell,
@@ -760,7 +771,6 @@ static void multiattrib_column_set_data_show_value(GtkTreeViewColumn *tree_colum
                 "sensitive",   !inherited,
                 "activatable", !inherited,
                 NULL);
-  
 }
 
 /*! \brief Requests an update of the display of a row.
@@ -777,11 +787,10 @@ static void
 update_row_display (GtkTreeModel *model, GtkTreeIter *iter)
 {
   GtkTreePath *path;
-  
+
   path = gtk_tree_model_get_path (model, iter);
   gtk_tree_model_row_changed (model, path, iter);
   gtk_tree_path_free (path);
-  
 }
 
 /*! \todo Finish function documentation
@@ -789,10 +798,11 @@ update_row_display (GtkTreeModel *model, GtkTreeIter *iter)
  *  \par Function Description
  *
  */
-static void multiattrib_callback_edited_name(GtkCellRendererText *cellrenderertext,
-					     gchar *arg1,
-					     gchar *arg2,
-					     gpointer user_data)
+static void
+multiattrib_callback_edited_name (GtkCellRendererText *cellrenderertext,
+                                  gchar *arg1,
+                                  gchar *arg2,
+                                  gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
@@ -821,7 +831,7 @@ static void multiattrib_callback_edited_name(GtkCellRendererText *cellrendererte
     gtk_widget_destroy (dialog);
     return;
   }
-  
+
   gtk_tree_model_get (model, &iter,
                       COLUMN_ATTRIBUTE, &o_attrib,
                       -1);
@@ -845,7 +855,6 @@ static void multiattrib_callback_edited_name(GtkCellRendererText *cellrendererte
 
   g_free (value);
   g_free (newtext);
-  
 }
 
 /*! \todo Finish function documentation
@@ -853,10 +862,11 @@ static void multiattrib_callback_edited_name(GtkCellRendererText *cellrendererte
  *  \par Function Description
  *
  */
-static void multiattrib_callback_edited_value(GtkCellRendererText *cell_renderer,
-					      gchar *arg1,
-					      gchar *arg2,
-					      gpointer user_data)
+static void
+multiattrib_callback_edited_value (GtkCellRendererText *cell_renderer,
+                                   gchar *arg1,
+                                   gchar *arg2,
+                                   gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
@@ -886,20 +896,19 @@ static void multiattrib_callback_edited_value(GtkCellRendererText *cell_renderer
     g_free(newtext);
     return;
   }
-  
+
   visibility = o_is_visible (w_current->toplevel, o_attrib)
       ? VISIBLE : INVISIBLE;
 
   /* actually modifies the attribute */
   o_text_change (w_current, o_attrib,
                  newtext, visibility, o_attrib->show_name_value);
-  
+
   /* request an update of display for this row */
   update_row_display (model, &iter);
-  
+
   g_free (name);
   g_free (newtext);
-  
 }
 
 /*! \todo Finish function documentation
@@ -907,9 +916,10 @@ static void multiattrib_callback_edited_value(GtkCellRendererText *cell_renderer
  *  \par Function Description
  *
  */
-static void multiattrib_callback_toggled_visible(GtkCellRendererToggle *cell_renderer,
-						 gchar *path,
-						 gpointer user_data)
+static void
+multiattrib_callback_toggled_visible (GtkCellRendererToggle *cell_renderer,
+                                      gchar *path,
+                                      gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
@@ -942,7 +952,6 @@ static void multiattrib_callback_toggled_visible(GtkCellRendererToggle *cell_ren
 
   /* request an update of display for this row */
   update_row_display (model, &iter);
-  
 }
 
 /*! \todo Finish function documentation
@@ -950,9 +959,10 @@ static void multiattrib_callback_toggled_visible(GtkCellRendererToggle *cell_ren
  *  \par Function Description
  *
  */
-static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle *cell_renderer,
-						   gchar *path,
-						   gpointer user_data)
+static void
+multiattrib_callback_toggled_show_name (GtkCellRendererToggle *cell_renderer,
+                                        gchar *path,
+                                        gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
@@ -990,7 +1000,6 @@ static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle *cell_r
 
   /* request an update of display for this row */
   update_row_display (model, &iter);
-  
 }
 
 /*! \todo Finish function documentation
@@ -998,9 +1007,10 @@ static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle *cell_r
  *  \par Function Description
  *
  */
-static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle *cell_renderer,
-						    gchar *path,
-						    gpointer user_data)
+static void
+multiattrib_callback_toggled_show_value (GtkCellRendererToggle *cell_renderer,
+                                         gchar *path,
+                                         gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
@@ -1035,10 +1045,9 @@ static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle *cell_
   o_attrib->show_name_value = new_snv;
   o_text_recreate (w_current->toplevel, o_attrib);
   o_undo_savestate (w_current, UNDO_ALL);
-  
+
   /* request an update of display for this row */
   update_row_display (model, &iter);
-
 }
 
 /*! \todo Finish function documentation
@@ -1046,9 +1055,10 @@ static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle *cell_
  *  \par Function Description
  *
  */
-static gboolean multiattrib_callback_key_pressed(GtkWidget *widget,
-						 GdkEventKey *event,
-						 gpointer user_data)
+static gboolean
+multiattrib_callback_key_pressed (GtkWidget *widget,
+                                  GdkEventKey *event,
+                                  gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
 
@@ -1066,19 +1076,19 @@ static gboolean multiattrib_callback_key_pressed(GtkWidget *widget,
       /* nothing selected, nothing to do */
       return FALSE;
     }
-    
+
     gtk_tree_model_get (model, &iter,
                         COLUMN_ATTRIBUTE, &o_attrib,
                         -1);
     g_assert (o_attrib->type == OBJ_TEXT);
-    
+
     inherited = o_attrib_is_inherited (o_attrib);
     /* We can't delete inherited attribtes */
     if (inherited)
       return FALSE;
 
     multiattrib_action_delete_attribute (multiattrib, o_attrib);
-    
+
     /* update the treeview contents */
     multiattrib_update (multiattrib);
   }
@@ -1119,9 +1129,10 @@ multiattrib_edit_cell_at_pos (Multiattrib *multiattrib, gint x, gint y)
  *  \par Function Description
  *
  */
-static gboolean multiattrib_callback_button_pressed(GtkWidget *widget,
-						    GdkEventButton *event,
-						    gpointer user_data)
+static gboolean
+multiattrib_callback_button_pressed (GtkWidget *widget,
+                                     GdkEventButton *event,
+                                     gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   gboolean ret = FALSE;
@@ -1137,7 +1148,7 @@ static gboolean multiattrib_callback_button_pressed(GtkWidget *widget,
    * for overriding the default behavior of treating a double-click the same as a
    * single-click, with edit focus needing two consecutive double or single clicks
    * with a pause in between.  This can be unintuitive and time-wasting) */
-  else 
+  else
   if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
     multiattrib_edit_cell_at_pos (multiattrib, event->x, event->y);
     ret = TRUE;
@@ -1151,13 +1162,14 @@ static gboolean multiattrib_callback_button_pressed(GtkWidget *widget,
  *  \par Function Description
  *
  */
-static gboolean multiattrib_callback_popup_menu(GtkWidget *widget,
-						gpointer user_data)
+static gboolean
+multiattrib_callback_popup_menu (GtkWidget *widget,
+                                 gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
 
   multiattrib_popup_menu (multiattrib, NULL);
-  
+
   return TRUE;
 }
 
@@ -1166,8 +1178,9 @@ static gboolean multiattrib_callback_popup_menu(GtkWidget *widget,
  *  \par Function Description
  *
  */
-static void multiattrib_callback_popup_duplicate(GtkMenuItem *menuitem,
-						 gpointer user_data)
+static void
+multiattrib_callback_popup_duplicate (GtkMenuItem *menuitem,
+                                      gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
@@ -1190,7 +1203,6 @@ static void multiattrib_callback_popup_duplicate(GtkMenuItem *menuitem,
 
   /* update the treeview contents */
   multiattrib_update (multiattrib);
-  
 }
 
 
@@ -1199,8 +1211,9 @@ static void multiattrib_callback_popup_duplicate(GtkMenuItem *menuitem,
  *  \par Function Description
  *
  */
-static void multiattrib_callback_popup_promote (GtkMenuItem *menuitem,
-                                                gpointer user_data)
+static void
+multiattrib_callback_popup_promote (GtkMenuItem *menuitem,
+                                    gpointer user_data)
 {
   Multiattrib *multiattrib = user_data;
   GtkTreeModel *model;
@@ -1230,14 +1243,15 @@ static void multiattrib_callback_popup_promote (GtkMenuItem *menuitem,
  *  \par Function Description
  *
  */
-static void multiattrib_callback_popup_delete(GtkMenuItem *menuitem,
-					      gpointer user_data)
+static void
+multiattrib_callback_popup_delete (GtkMenuItem *menuitem,
+                                   gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
   OBJECT *o_attrib;
-  
+
   if (!gtk_tree_selection_get_selected (
         gtk_tree_view_get_selection (multiattrib->treeview),
         &model, &iter)) {
@@ -1254,7 +1268,6 @@ static void multiattrib_callback_popup_delete(GtkMenuItem *menuitem,
 
   /* update the treeview contents */
   multiattrib_update (multiattrib);
-  
 }
 
 /*! \todo Finish function documentation
@@ -1262,9 +1275,10 @@ static void multiattrib_callback_popup_delete(GtkMenuItem *menuitem,
  *  \par Function Description
  *
  */
-static gboolean multiattrib_callback_value_key_pressed(GtkWidget *widget,
-						       GdkEventKey *event,
-						       gpointer user_data)
+static gboolean
+multiattrib_callback_value_key_pressed (GtkWidget *widget,
+                                        GdkEventKey *event,
+                                        gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)widget;
   gboolean retval = FALSE;
@@ -1298,8 +1312,8 @@ static gboolean multiattrib_callback_value_key_pressed(GtkWidget *widget,
  *  \par Function Description
  *  Select the text in the GtkTextView so it may be over-typed quickly
  */
-static void multiattrib_callback_value_grab_focus (GtkWidget *widget,
-                                                   gpointer user_data)
+static void
+multiattrib_callback_value_grab_focus (GtkWidget *widget, gpointer user_data)
 {
   GtkTextView *textview = GTK_TEXT_VIEW (widget);
   GtkTextBuffer *textbuffer;
@@ -1317,8 +1331,8 @@ static void multiattrib_callback_value_grab_focus (GtkWidget *widget,
  *  \par Function Description
  *
  */
-static void multiattrib_callback_button_add(GtkButton *button,
-					    gpointer user_data)
+static void
+multiattrib_callback_button_add (GtkButton *button, gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTextBuffer *buffer;
@@ -1362,12 +1376,13 @@ static void multiattrib_callback_button_add(GtkButton *button,
  *  \par Function Description
  *
  */
-static void multiattrib_init_attrib_names(GtkCombo *combo)
+static void
+multiattrib_init_attrib_names (GtkCombo *combo)
 {
   GList *items = NULL;
   const gchar *string;
   gint i;
-  
+
   for (i = 0, string = s_attrib_get (i);
        string != NULL;
        i++, string = s_attrib_get (i)) {
@@ -1377,7 +1392,6 @@ static void multiattrib_init_attrib_names(GtkCombo *combo)
   gtk_combo_set_popdown_strings (GTK_COMBO (combo), items);
 
   g_list_free (items);
-  
 }
 
 /*! \todo Finish function documentation
@@ -1385,7 +1399,8 @@ static void multiattrib_init_attrib_names(GtkCombo *combo)
  *  \par Function Description
  *
  */
-static void multiattrib_init_visible_types(GtkOptionMenu *optionmenu)
+static void
+multiattrib_init_visible_types (GtkOptionMenu *optionmenu)
 {
   GtkWidget *menu, *item;
 
@@ -1398,7 +1413,6 @@ static void multiattrib_init_visible_types(GtkOptionMenu *optionmenu)
   gtk_menu_append (menu, item);
 
   gtk_option_menu_set_menu (optionmenu, menu);
-  
 }
 
 
@@ -1411,8 +1425,8 @@ static void multiattrib_init_visible_types(GtkOptionMenu *optionmenu)
  *  \param [in] multiattrib  The Multiattrib object.
  *  \param [in] event        Mouse event.
  */
-static void multiattrib_popup_menu(Multiattrib *multiattrib,
-				   GdkEventButton *event)
+static void
+multiattrib_popup_menu (Multiattrib *multiattrib, GdkEventButton *event)
 {
   GtkTreePath *path;
   GtkWidget *menu;
@@ -1442,7 +1456,7 @@ static void multiattrib_popup_menu(Multiattrib *multiattrib,
 
   if (event != NULL &&
       gtk_tree_view_get_path_at_pos (multiattrib->treeview,
-                                     (gint)event->x, 
+                                     (gint)event->x,
                                      (gint)event->y,
                                      &path, NULL, NULL, NULL)) {
     gtk_tree_selection_unselect_all (selection);
@@ -1482,7 +1496,6 @@ static void multiattrib_popup_menu(Multiattrib *multiattrib,
   gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
                   (event != NULL) ? event->button : 0,
                   gdk_event_get_time ((GdkEvent*)event));
-  
 }
 
 
@@ -1550,10 +1563,11 @@ multiattrib_geometry_restore (GschemDialog *dialog, EdaConfig *cfg, gchar *group
  *
  *  \return the GType identifier associated with Multiattrib.
  */
-GType multiattrib_get_type()
+GType
+multiattrib_get_type ()
 {
   static GType multiattrib_type = 0;
-  
+
   if (!multiattrib_type) {
     static const GTypeInfo multiattrib_info = {
       sizeof(MultiattribClass),
@@ -1566,12 +1580,12 @@ GType multiattrib_get_type()
       0,    /* n_preallocs */
       (GInstanceInitFunc) multiattrib_init,
     };
-		
+
     multiattrib_type = g_type_register_static (GSCHEM_TYPE_DIALOG,
                                                "Multiattrib",
                                                &multiattrib_info, 0);
   }
-  
+
   return multiattrib_type;
 }
 
@@ -1589,7 +1603,8 @@ GType multiattrib_get_type()
  *  \param [in] selection    The SELECTION object of page being edited.
  *  \param [in] multiattrib  The multi-attribute editor dialog.
  */
-static void selection_changed_cb (SELECTION *selection, Multiattrib *multiattrib)
+static void
+selection_changed_cb (SELECTION *selection, Multiattrib *multiattrib)
 {
   int object_count = 0;
   GList *selection_glist;
@@ -1643,7 +1658,8 @@ static void selection_changed_cb (SELECTION *selection, Multiattrib *multiattrib
  *  \param [in] data                  Pointer to the multi-attrib dialog
  *  \param [in] where_the_object_was  Pointer to where the object was just destroyed
  */
-static void selection_weak_ref_cb (gpointer data, GObject *where_the_object_was)
+static void
+selection_weak_ref_cb (gpointer data, GObject *where_the_object_was)
 {
   Multiattrib *multiattrib = (Multiattrib *)data;
 
@@ -1662,7 +1678,8 @@ static void selection_weak_ref_cb (gpointer data, GObject *where_the_object_was)
  *  \param [in] multiattrib  The Multiattrib dialog.
  *  \param [in] selection    The SELECTION object to watch.
  */
-static void connect_selection( Multiattrib *multiattrib, SELECTION *selection )
+static void
+connect_selection (Multiattrib *multiattrib, SELECTION *selection)
 {
   multiattrib->selection = selection;
   if (multiattrib->selection != NULL) {
@@ -1692,7 +1709,8 @@ static void connect_selection( Multiattrib *multiattrib, SELECTION *selection )
  *
  *  \param [in] multiattrib  The Multiattrib dialog.
  */
-static void disconnect_selection( Multiattrib *multiattrib )
+static void
+disconnect_selection (Multiattrib *multiattrib)
 {
   if (multiattrib->selection != NULL) {
     g_signal_handler_disconnect (multiattrib->selection,
@@ -1714,7 +1732,8 @@ static void disconnect_selection( Multiattrib *multiattrib )
  *
  *  \param [in] object  The GObject being finalized.
  */
-static void multiattrib_finalize (GObject *object)
+static void
+multiattrib_finalize (GObject *object)
 {
   Multiattrib *multiattrib = MULTIATTRIB(object);
 
@@ -1732,7 +1751,8 @@ static void multiattrib_finalize (GObject *object)
  *
  *  \param [in]  klass       The MultiattribClass we are initialising
  */
-static void multiattrib_class_init(MultiattribClass *klass)
+static void
+multiattrib_class_init (MultiattribClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GschemDialogClass *gschem_dialog_class = GSCHEM_DIALOG_CLASS (klass);
@@ -1757,8 +1777,9 @@ static void multiattrib_class_init(MultiattribClass *klass)
 /*! \brief Regenerate the attribute list when the visibility
  *         setting for inherited attributes changes
  */
-static void multiattrib_show_inherited_toggled (GtkToggleButton *button,
-                                                gpointer user_data)
+static void
+multiattrib_show_inherited_toggled (GtkToggleButton *button,
+                                    gpointer user_data)
 {
   Multiattrib *multiattrib = user_data;
 
@@ -1776,7 +1797,8 @@ static void multiattrib_show_inherited_toggled (GtkToggleButton *button,
  *
  *  \param [in] multiattrib The Multiattrib we are initialising
  */
-static void multiattrib_init(Multiattrib *multiattrib)
+static void
+multiattrib_init (Multiattrib *multiattrib)
 {
   GtkWidget *frame, *label, *scrolled_win, *treeview;
   GtkWidget *table, *textview, *combo, *optionm, *button;
@@ -1786,7 +1808,7 @@ static void multiattrib_init(Multiattrib *multiattrib)
   GtkTreeViewColumn *column;
   GtkTreeSelection *selection;
   GtkStyle *style;
-  
+
   /* dialog initialization */
   g_object_set (G_OBJECT (multiattrib),
                 /* GtkContainer */
@@ -1814,146 +1836,146 @@ static void multiattrib_init(Multiattrib *multiattrib)
   multiattrib->frame_add = frame;
   /*   - create the model for the treeview */
   store = (GtkTreeModel*)gtk_list_store_new (NUM_COLUMNS,
-					     G_TYPE_POINTER); /* attribute */
+                                             G_TYPE_POINTER); /* attribute */
   /*   - create a scrolled window for the treeview */
   scrolled_win = GTK_WIDGET (
-			     g_object_new (GTK_TYPE_SCROLLED_WINDOW,
-					   /* GtkContainer */
-					   "border-width",      3,
-					   /* GtkScrolledWindow */
-					   "hscrollbar-policy",
-					   GTK_POLICY_AUTOMATIC,
-					   "vscrollbar-policy",
-					   GTK_POLICY_AUTOMATIC,
-					   "shadow-type",
-					   GTK_SHADOW_ETCHED_IN,
-					   NULL));
+                    g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+                                  /* GtkContainer */
+                                  "border-width",      3,
+                                  /* GtkScrolledWindow */
+                                  "hscrollbar-policy",
+                                  GTK_POLICY_AUTOMATIC,
+                                  "vscrollbar-policy",
+                                  GTK_POLICY_AUTOMATIC,
+                                  "shadow-type",
+                                  GTK_SHADOW_ETCHED_IN,
+                                  NULL));
   /*   - create the treeview */
   treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
-				       /* GtkTreeView */
-				       "model",      store,
-				       "rules-hint", TRUE,
-				       NULL));
+                                       /* GtkTreeView */
+                                       "model",      store,
+                                       "rules-hint", TRUE,
+                                       NULL));
   g_signal_connect (treeview,
-		    "key-press-event",
-		    G_CALLBACK (multiattrib_callback_key_pressed),
-		    multiattrib);
+                    "key-press-event",
+                    G_CALLBACK (multiattrib_callback_key_pressed),
+                    multiattrib);
   g_signal_connect (treeview,
-		    "button-press-event",
-		    G_CALLBACK (multiattrib_callback_button_pressed),
-		    multiattrib);
+                    "button-press-event",
+                    G_CALLBACK (multiattrib_callback_button_pressed),
+                    multiattrib);
   g_signal_connect (treeview,
-		    "popup-menu",
-		    G_CALLBACK (multiattrib_callback_popup_menu),
-		    multiattrib);
+                    "popup-menu",
+                    G_CALLBACK (multiattrib_callback_popup_menu),
+                    multiattrib);
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
   gtk_tree_selection_set_mode (selection,
-			       GTK_SELECTION_SINGLE);
+                               GTK_SELECTION_SINGLE);
 
   /*   - and now the columns of the treeview */
   /*       - column 1: attribute name */
   renderer = GTK_CELL_RENDERER (
-				g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
-					      /* GtkCellRendererText */
-					      /* unknown in GTK 2.4 */
-					      /* "ellipsize",
-					       * PANGO_ELLIPSIZE_END, */
-					      NULL));
+                                g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
+                                              /* GtkCellRendererText */
+                                              /* unknown in GTK 2.4 */
+                                              /* "ellipsize",
+                                               * PANGO_ELLIPSIZE_END, */
+                                              NULL));
   g_signal_connect (renderer,
-		    "edited",
-		    G_CALLBACK (multiattrib_callback_edited_name),
-		    multiattrib);
+                    "edited",
+                    G_CALLBACK (multiattrib_callback_edited_name),
+                    multiattrib);
   column = GTK_TREE_VIEW_COLUMN (
-				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
-					       /* GtkTreeViewColumn */
-					       "title", _("Name"),
-					       "min-width", 100,
-					       "resizable", TRUE,
-					       NULL));
+                                 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
+                                               /* GtkTreeViewColumn */
+                                               "title", _("Name"),
+                                               "min-width", 100,
+                                               "resizable", TRUE,
+                                               NULL));
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func (column, renderer,
-					   multiattrib_column_set_data_name,
-					   multiattrib, NULL);
+                                           multiattrib_column_set_data_name,
+                                           multiattrib, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
   /*       - column 2: attribute value */
   renderer = GTK_CELL_RENDERER (
-				g_object_new (TYPE_CELL_RENDERER_MULTI_LINE_TEXT,
-					      /* GtkCellRendererText */
-					      /* unknown in GTK 2.4 */
-					      /* "ellipsize",
-						 PANGO_ELLIPSIZE_END, */
-					      NULL));
+                                g_object_new (TYPE_CELL_RENDERER_MULTI_LINE_TEXT,
+                                              /* GtkCellRendererText */
+                                              /* unknown in GTK 2.4 */
+                                              /* "ellipsize",
+                                                 PANGO_ELLIPSIZE_END, */
+                                              NULL));
   g_signal_connect (renderer,
-		    "edited",
-		    G_CALLBACK (multiattrib_callback_edited_value),
-		    multiattrib);
+                    "edited",
+                    G_CALLBACK (multiattrib_callback_edited_value),
+                    multiattrib);
   column = GTK_TREE_VIEW_COLUMN (
-				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
-					       /* GtkTreeViewColumn */
-					       "title", _("Value"),
-					       "min-width", 140,
-					       "resizable", TRUE,
-					       NULL));
+                                 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
+                                               /* GtkTreeViewColumn */
+                                               "title", _("Value"),
+                                               "min-width", 140,
+                                               "resizable", TRUE,
+                                               NULL));
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func (column, renderer,
-					   multiattrib_column_set_data_value,
-					   multiattrib, NULL);
+                                           multiattrib_column_set_data_value,
+                                           multiattrib, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
   /*       - column 3: visibility */
   renderer = GTK_CELL_RENDERER (
-				g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
-					      NULL));
+                                g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
+                                              NULL));
   g_signal_connect (renderer,
-		    "toggled",
-		    G_CALLBACK (multiattrib_callback_toggled_visible),
-		    multiattrib);
+                    "toggled",
+                    G_CALLBACK (multiattrib_callback_toggled_visible),
+                    multiattrib);
   column = GTK_TREE_VIEW_COLUMN (
-				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
-					       /* GtkTreeViewColumn */
-					       "title", _("Vis?"),
-					       NULL));
+                                 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
+                                               /* GtkTreeViewColumn */
+                                               "title", _("Vis?"),
+                                               NULL));
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func (column, renderer,
-					   multiattrib_column_set_data_visible,
-					   multiattrib, NULL);
+                                           multiattrib_column_set_data_visible,
+                                           multiattrib, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
   /*       - column 4: show name */
   renderer = GTK_CELL_RENDERER (
-				g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
-					      NULL));
+                                g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
+                                              NULL));
   g_signal_connect (renderer,
-		    "toggled",
-		    G_CALLBACK (multiattrib_callback_toggled_show_name),
-		    multiattrib);
+                    "toggled",
+                    G_CALLBACK (multiattrib_callback_toggled_show_name),
+                    multiattrib);
   column = GTK_TREE_VIEW_COLUMN (
-				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
-					       /* GtkTreeViewColumn */
-					       "title", _("N"),
-					       NULL));
+                                 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
+                                               /* GtkTreeViewColumn */
+                                               "title", _("N"),
+                                               NULL));
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func (column, renderer,
-					   multiattrib_column_set_data_show_name,
-					   NULL, NULL);
+                                           multiattrib_column_set_data_show_name,
+                                           NULL, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
   /*       - column 5: show value */
   renderer = GTK_CELL_RENDERER (
-				g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
-					      NULL));
+                                g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
+                                              NULL));
   g_signal_connect (renderer,
-		    "toggled",
-		    G_CALLBACK (multiattrib_callback_toggled_show_value),
-		    multiattrib);
+                    "toggled",
+                    G_CALLBACK (multiattrib_callback_toggled_show_value),
+                    multiattrib);
   column = GTK_TREE_VIEW_COLUMN (
-				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
-					       /* GtkTreeViewColumn */
-					       "title", _("V"),
-					       NULL));
+                                 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
+                                               /* GtkTreeViewColumn */
+                                               "title", _("V"),
+                                               NULL));
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func (column, renderer,
-					   multiattrib_column_set_data_show_value,
-					   NULL, NULL);
+                                           multiattrib_column_set_data_show_value,
+                                           NULL, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
-  
+
   /* add the treeview to the scrolled window */
   gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
   /* set treeview of multiattrib */
@@ -1979,67 +2001,67 @@ static void multiattrib_init(Multiattrib *multiattrib)
 
   /* pack the frame */
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib)->vbox), frame,
-		      TRUE, TRUE, 1);
+                      TRUE, TRUE, 1);
   gtk_widget_show_all (frame);
 
   /* create the add/edit frame */
   frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
-				    "label", _("Add Attribute"),
-				    NULL));
+                                    "label", _("Add Attribute"),
+                                    NULL));
   multiattrib->frame_attributes = frame;
   table = GTK_WIDGET (g_object_new (GTK_TYPE_TABLE,
-				    /* GtkTable */
-				    "n-rows",      4,
-				    "n-columns",   2,
-				    "homogeneous", FALSE,
-				    NULL));
-  
+                                    /* GtkTable */
+                                    "n-rows",      4,
+                                    "n-columns",   2,
+                                    "homogeneous", FALSE,
+                                    NULL));
+
   /*   - the name entry: a GtkComboBoxEntry */
   label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
-				    /* GtkMisc */
-				    "xalign", 0.0,
-				    "yalign", 0.5,
-				    /* GtkLabel */
-				    "label",  _("Name:"),
-				    NULL));
+                                    /* GtkMisc */
+                                    "xalign", 0.0,
+                                    "yalign", 0.5,
+                                    /* GtkLabel */
+                                    "label",  _("Name:"),
+                                    NULL));
   combo = GTK_WIDGET (g_object_new (GTK_TYPE_COMBO,
-				    /* GtkCombo */
-				    "value-in-list", FALSE,
-				    NULL));
+                                    /* GtkCombo */
+                                    "value-in-list", FALSE,
+                                    NULL));
   multiattrib_init_attrib_names (GTK_COMBO (combo));
   multiattrib->combo_name = GTK_COMBO (combo);
   gtk_table_attach (GTK_TABLE (table), label,
-		    0, 1, 0, 1, 0, 0, 0, 0);
+                    0, 1, 0, 1, 0, 0, 0, 0);
   gtk_table_attach (GTK_TABLE (table), combo,
-		    1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 6, 3);
-  
+                    1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 6, 3);
+
   /*   - the value entry: a GtkEntry */
   label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
-				    /* GtkMisc */
-				    "xalign", 0.0,
-				    "yalign", 0.5,
-				    /* GtkLabel */
-				    "label",  _("Value:"),
-				    NULL));
+                                    /* GtkMisc */
+                                    "xalign", 0.0,
+                                    "yalign", 0.5,
+                                    /* GtkLabel */
+                                    "label",  _("Value:"),
+                                    NULL));
   scrolled_win = GTK_WIDGET (
-			     g_object_new (GTK_TYPE_SCROLLED_WINDOW,
-					   /* GtkScrolledWindow */
-					   "hscrollbar-policy",
-					   GTK_POLICY_NEVER,
-					   "vscrollbar-policy",
-					   GTK_POLICY_AUTOMATIC,
-					   "shadow-type",
-					   GTK_SHADOW_IN,
-					   NULL));
+                             g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+                                           /* GtkScrolledWindow */
+                                           "hscrollbar-policy",
+                                           GTK_POLICY_NEVER,
+                                           "vscrollbar-policy",
+                                           GTK_POLICY_AUTOMATIC,
+                                           "shadow-type",
+                                           GTK_SHADOW_IN,
+                                           NULL));
   /*! \todo Forcing the size request is a horrible band-aid and
    *  should be replaced by a better heuristic. */
   textview = GTK_WIDGET (g_object_new (GTK_TYPE_TEXT_VIEW,
                                        "height-request", 50,
-				       NULL));
+                                       NULL));
   g_signal_connect (textview,
-		    "key_press_event",
-		    G_CALLBACK (multiattrib_callback_value_key_pressed),
-		    multiattrib);
+                    "key_press_event",
+                    G_CALLBACK (multiattrib_callback_value_key_pressed),
+                    multiattrib);
   g_signal_connect (textview,
                     "grab-focus",
                     G_CALLBACK (multiattrib_callback_value_grab_focus),
@@ -2058,50 +2080,49 @@ static void multiattrib_init(Multiattrib *multiattrib)
   gtk_container_add (GTK_CONTAINER (scrolled_win), textview);
   multiattrib->textview_value = GTK_TEXT_VIEW (textview);
   gtk_table_attach (GTK_TABLE (table), label,
-		    0, 1, 1, 2, 0, 0, 0, 0);
+                    0, 1, 1, 2, 0, 0, 0, 0);
   gtk_table_attach (GTK_TABLE (table), scrolled_win,
-		    1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 6, 3);
-  
+                    1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 6, 3);
+
   /*   - the visible status */
   button = GTK_WIDGET (g_object_new (GTK_TYPE_CHECK_BUTTON,
-				     /* GtkButton */
-				     "label", _("Visible"),
-				     "active", TRUE,
-				     NULL));
+                                     /* GtkButton */
+                                     "label", _("Visible"),
+                                     "active", TRUE,
+                                     NULL));
   multiattrib->button_visible = GTK_CHECK_BUTTON (button);
   gtk_table_attach (GTK_TABLE (table), button,
-		    0, 1, 2, 3, GTK_FILL, 0, 3, 0);
-  
+                    0, 1, 2, 3, GTK_FILL, 0, 3, 0);
+
   /*   - the visibility type */
   optionm = GTK_WIDGET (g_object_new (GTK_TYPE_OPTION_MENU,
-				      NULL));
+                                      NULL));
   multiattrib_init_visible_types (GTK_OPTION_MENU (optionm));
   multiattrib->optionmenu_shownv = GTK_OPTION_MENU (optionm);
   gtk_table_attach (GTK_TABLE (table), optionm,
-		    1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 6, 3);
+                    1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 6, 3);
   gtk_widget_show_all (table);
-  
+
   /* create the add button */
   button = gtk_button_new_from_stock (GTK_STOCK_ADD);
   g_signal_connect (button,
-		    "clicked",
-		    G_CALLBACK (multiattrib_callback_button_add),
-		    multiattrib);
+                    "clicked",
+                    G_CALLBACK (multiattrib_callback_button_add),
+                    multiattrib);
   gtk_table_attach (GTK_TABLE (table), button,
-		    2, 3, 0, 3, 0, 0, 6, 3);
-  
+                    2, 3, 0, 3, 0, 0, 6, 3);
+
   /* add the table to the frame */
   gtk_container_add (GTK_CONTAINER (frame), table);
   /* pack the frame in the dialog */
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib)->vbox), frame,
-		      FALSE, TRUE, 1);
+                      FALSE, TRUE, 1);
   gtk_widget_show_all (frame);
-  
-  
+
+
   /* now add the close button to the action area */
   gtk_dialog_add_button (GTK_DIALOG (multiattrib),
                          GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
-  
 }
 
 
@@ -2117,10 +2138,11 @@ static void multiattrib_init(Multiattrib *multiattrib)
  *  \param [in]  pspec        A GParamSpec describing the property being set
  */
 
-static void multiattrib_set_property (GObject *object,
-                                      guint property_id,
-                                      const GValue *value,
-                                      GParamSpec *pspec)
+static void
+multiattrib_set_property (GObject *object,
+                          guint property_id,
+                          const GValue *value,
+                          GParamSpec *pspec)
 {
   Multiattrib *multiattrib = MULTIATTRIB (object);
 
@@ -2146,10 +2168,11 @@ static void multiattrib_set_property (GObject *object,
  *  \param [out] value        The GValue in which to return the value of the property
  *  \param [in]  pspec        A GParamSpec describing the property being got
  */
-static void multiattrib_get_property (GObject *object,
-                                      guint property_id,
-                                      GValue *value,
-                                      GParamSpec *pspec)
+static void
+multiattrib_get_property (GObject *object,
+                          guint property_id,
+                          GValue *value,
+                          GParamSpec *pspec)
 {
   Multiattrib *multiattrib = MULTIATTRIB (object);
 
@@ -2160,7 +2183,6 @@ static void multiattrib_get_property (GObject *object,
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
   }
-
 }
 
 
-- 
1.8.3.2

>From 621925e52397244de5d7c6d8f0628a888f66d0ae Mon Sep 17 00:00:00 2001
From: Peter Clifton <peter@xxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 20 Oct 2013 18:54:56 +0100
Subject: [PATCH 6/7] x_multiattrib.c: Rename the "selection" property to
 "objects"

This is brings us closer in spirit to what the reverted commit
1aaf6613a7c6991d858c1143ed3917675a115a5a was intending to achieve.
---
 gschem/include/x_multiattrib.h |  4 +-
 gschem/src/x_multiattrib.c     | 96 +++++++++++++++++++++---------------------
 2 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/gschem/include/x_multiattrib.h b/gschem/include/x_multiattrib.h
index 8df1aeb..551d606 100644
--- a/gschem/include/x_multiattrib.h
+++ b/gschem/include/x_multiattrib.h
@@ -45,7 +45,7 @@ struct _MultiattribClass {
 struct _Multiattrib {
   GschemDialog parent_instance;
 
-  SELECTION *selection;
+  GedaList *object_list;
   OBJECT *object;
 
   GtkTreeView    *treeview;
@@ -61,7 +61,7 @@ struct _Multiattrib {
   GdkColor       value_normal_text_color;   /* Workaround for lameness in GtkTextView */
   GdkColor       insensitive_text_color;
 
-  gulong selection_changed_id;
+  gulong object_list_changed_id;
 };
 
 
diff --git a/gschem/src/x_multiattrib.c b/gschem/src/x_multiattrib.c
index 068f89c..adaa30d 100644
--- a/gschem/src/x_multiattrib.c
+++ b/gschem/src/x_multiattrib.c
@@ -72,7 +72,7 @@ x_multiattrib_open (GschemToplevel *w_current)
   if ( w_current->mawindow == NULL ) {
     w_current->mawindow =
       GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB,
-                                "selection", w_current->toplevel->page_current->selection_list,
+                                "object_list", w_current->toplevel->page_current->selection_list,
                                 /* GschemDialog */
                                 "settings-name", "multiattrib",
                                 "gschem-toplevel", w_current,
@@ -123,7 +123,7 @@ void
 x_multiattrib_update (GschemToplevel *w_current)
 {
   if (w_current->mawindow != NULL) {
-    g_object_set (G_OBJECT (w_current->mawindow), "selection",
+    g_object_set (G_OBJECT (w_current->mawindow), "object_list",
                   w_current->toplevel->page_current->selection_list, NULL);
   }
 }
@@ -483,7 +483,7 @@ cellrenderermultilinetext_class_init (CellRendererMultiLineTextClass *klass)
 
 
 enum {
-  PROP_SELECTION = 1
+  PROP_OBJECT_LIST = 1
 };
 
 enum {
@@ -1600,22 +1600,22 @@ multiattrib_get_type ()
  *
  *  \todo The dialog doesn't currently support editing multiple objects at once
  *
- *  \param [in] selection    The SELECTION object of page being edited.
+ *  \param [in] selection    The GedaList object of we are watching/
  *  \param [in] multiattrib  The multi-attribute editor dialog.
  */
 static void
-selection_changed_cb (SELECTION *selection, Multiattrib *multiattrib)
+object_list_changed_cb (GedaList *object_list, Multiattrib *multiattrib)
 {
   int object_count = 0;
-  GList *selection_glist;
+  GList *object_glist;
   GList *iter;
   OBJECT *object;
 
-  selection_glist = geda_list_get_glist (selection);
+  object_glist = geda_list_get_glist (object_list);
 
-  for ( iter = selection_glist;
-        iter != NULL;
-        iter = g_list_next (iter) ) {
+  for (iter = object_glist;
+       iter != NULL;
+       iter = g_list_next (iter)) {
     object = (OBJECT *)iter->data;
     g_assert( object != NULL );
 
@@ -1636,7 +1636,7 @@ selection_changed_cb (SELECTION *selection, Multiattrib *multiattrib)
      */
     multiattrib->object = NULL;
   } else if (object_count == 1) {
-    multiattrib->object = (OBJECT *)selection_glist->data;
+    multiattrib->object = (OBJECT *)object_glist->data;
   } else {
     /* TODO: Something clever with multiple objects selected */
     multiattrib->object = NULL;
@@ -1646,12 +1646,12 @@ selection_changed_cb (SELECTION *selection, Multiattrib *multiattrib)
 }
 
 
-/*! \brief Update the dialog when the current page's SELECTION object is destroyed
+/*! \brief Update the dialog when the current object GedaList object is destroyed
  *
  *  \par Function Description
  *
- *  This handler is called when the g_object_weak_ref() on the SELECTION object
- *  we're watching expires. We reset our multiattrib->selection pointer to NULL
+ *  This handler is called when the g_object_weak_ref() on the GedaList object
+ *  we're watching expires. We reset our multiattrib->object_list pointer to NULL
  *  to avoid attempting to access the destroyed object. NB: Our signal handlers
  *  were automatically disconnected during the destruction process.
  *
@@ -1659,16 +1659,16 @@ selection_changed_cb (SELECTION *selection, Multiattrib *multiattrib)
  *  \param [in] where_the_object_was  Pointer to where the object was just destroyed
  */
 static void
-selection_weak_ref_cb (gpointer data, GObject *where_the_object_was)
+object_list_weak_ref_cb (gpointer data, GObject *where_the_object_was)
 {
   Multiattrib *multiattrib = (Multiattrib *)data;
 
-  multiattrib->selection = NULL;
+  multiattrib->object_list = NULL;
   multiattrib_update (multiattrib);
 }
 
 
-/*! \brief Connect signal handler and weak_ref on the SELECTION object
+/*! \brief Connect signal handler and weak_ref on the GedaList object
  *
  *  \par Function Description
  *
@@ -1676,23 +1676,23 @@ selection_weak_ref_cb (gpointer data, GObject *where_the_object_was)
  *  on the SELECTION object we are going to watch.
  *
  *  \param [in] multiattrib  The Multiattrib dialog.
- *  \param [in] selection    The SELECTION object to watch.
+ *  \param [in] object_list  The GedaList object to watch.
  */
 static void
-connect_selection (Multiattrib *multiattrib, SELECTION *selection)
+connect_object_list (Multiattrib *multiattrib, GedaList *object_list)
 {
-  multiattrib->selection = selection;
-  if (multiattrib->selection != NULL) {
-    g_object_weak_ref (G_OBJECT (multiattrib->selection),
-                       selection_weak_ref_cb,
+  multiattrib->object_list = object_list;
+  if (multiattrib->object_list != NULL) {
+    g_object_weak_ref (G_OBJECT (multiattrib->object_list),
+                       object_list_weak_ref_cb,
                        multiattrib);
-    multiattrib->selection_changed_id =
-      g_signal_connect (G_OBJECT (multiattrib->selection),
+    multiattrib->object_list_changed_id =
+      g_signal_connect (G_OBJECT (multiattrib->object_list),
                         "changed",
-                        G_CALLBACK (selection_changed_cb),
+                        G_CALLBACK (object_list_changed_cb),
                         multiattrib);
-    /* Synthesise a selection changed update to refresh the view */
-    selection_changed_cb (multiattrib->selection, multiattrib);
+    /* Synthesise a object_list changed update to refresh the view */
+    object_list_changed_cb (multiattrib->object_list, multiattrib);
   } else {
     /* Call an update to set the sensitivities */
     multiattrib_update (multiattrib);
@@ -1700,24 +1700,24 @@ connect_selection (Multiattrib *multiattrib, SELECTION *selection)
 }
 
 
-/*! \brief Disconnect signal handler and weak_ref on the SELECTION object
+/*! \brief Disconnect signal handler and weak_ref on the GedaList object
  *
  *  \par Function Description
  *
- *  If the dialog is watching a SELECTION object, disconnect the
+ *  If the dialog is watching a GedaList object, disconnect the
  *  "changed" signal and remove our weak reference on the object.
  *
  *  \param [in] multiattrib  The Multiattrib dialog.
  */
 static void
-disconnect_selection (Multiattrib *multiattrib)
+disconnect_object_list (Multiattrib *multiattrib)
 {
-  if (multiattrib->selection != NULL) {
-    g_signal_handler_disconnect (multiattrib->selection,
-                                 multiattrib->selection_changed_id);
-    g_object_weak_unref(G_OBJECT( multiattrib->selection ),
-                        selection_weak_ref_cb,
-                        multiattrib );
+  if (multiattrib->object_list != NULL) {
+    g_signal_handler_disconnect (multiattrib->object_list,
+                                 multiattrib->object_list_changed_id);
+    g_object_weak_unref (G_OBJECT (multiattrib->object_list),
+                         object_list_weak_ref_cb,
+                         multiattrib);
   }
 }
 
@@ -1737,7 +1737,7 @@ multiattrib_finalize (GObject *object)
 {
   Multiattrib *multiattrib = MULTIATTRIB(object);
 
-  disconnect_selection( multiattrib );
+  disconnect_object_list (multiattrib);
   G_OBJECT_CLASS (multiattrib_parent_class)->finalize (object);
 }
 
@@ -1767,8 +1767,8 @@ multiattrib_class_init (MultiattribClass *klass)
   multiattrib_parent_class = g_type_class_peek_parent (klass);
 
   g_object_class_install_property (
-    gobject_class, PROP_SELECTION,
-    g_param_spec_pointer ("selection",
+    gobject_class, PROP_OBJECT_LIST,
+    g_param_spec_pointer ("object_list",
                           "",
                           "",
                           G_PARAM_READWRITE));
@@ -2129,7 +2129,7 @@ multiattrib_init (Multiattrib *multiattrib)
 /*! \brief GObject property setter function
  *
  *  \par Function Description
- *  Setter function for Multiattrib's GObject property, "selection".
+ *  Setter function for Multiattrib's GObject property, "object_list".
  *
  *  \param [in]  object       The GObject whose properties we are setting
  *  \param [in]  property_id  The numeric id. under which the property was
@@ -2147,9 +2147,9 @@ multiattrib_set_property (GObject *object,
   Multiattrib *multiattrib = MULTIATTRIB (object);
 
   switch(property_id) {
-      case PROP_SELECTION:
-        disconnect_selection (multiattrib);
-        connect_selection (multiattrib, g_value_get_pointer (value));
+      case PROP_OBJECT_LIST:
+        disconnect_object_list (multiattrib);
+        connect_object_list (multiattrib, g_value_get_pointer (value));
         break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -2160,7 +2160,7 @@ multiattrib_set_property (GObject *object,
 /*! \brief GObject property getter function
  *
  *  \par Function Description
- *  Getter function for Multiattrib's GObject property, "selection".
+ *  Getter function for Multiattrib's GObject property, "object_list".
  *
  *  \param [in]  object       The GObject whose properties we are getting
  *  \param [in]  property_id  The numeric id. under which the property was
@@ -2177,8 +2177,8 @@ multiattrib_get_property (GObject *object,
   Multiattrib *multiattrib = MULTIATTRIB (object);
 
   switch(property_id) {
-      case PROP_SELECTION:
-        g_value_set_pointer (value, (gpointer)multiattrib->selection);
+      case PROP_OBJECT_LIST:
+        g_value_set_pointer (value, (gpointer)multiattrib->object_list);
         break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -2234,7 +2234,7 @@ multiattrib_update (Multiattrib *multiattrib)
   gtk_list_store_clear (liststore);
 
   /* Update sensitivities */
-  sensitive = (multiattrib->selection != NULL && multiattrib->object != NULL);
+  sensitive = (multiattrib->object_list != NULL && multiattrib->object != NULL);
   gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_attributes), sensitive);
   gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_add), sensitive);
 
-- 
1.8.3.2

>From 96b53aa18e33418d48434087a47558511b0a7ac8 Mon Sep 17 00:00:00 2001
From: Peter Clifton <peter@xxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 21 Oct 2013 00:55:11 +0100
Subject: [PATCH 7/7] Allow editing attributes of multiple objects at once

---
 gschem/include/x_multiattrib.h |   3 +-
 gschem/src/x_multiattrib.c     | 891 +++++++++++++++++++++++++++--------------
 2 files changed, 601 insertions(+), 293 deletions(-)

diff --git a/gschem/include/x_multiattrib.h b/gschem/include/x_multiattrib.h
index 551d606..9c91ca7 100644
--- a/gschem/include/x_multiattrib.h
+++ b/gschem/include/x_multiattrib.h
@@ -46,7 +46,6 @@ struct _Multiattrib {
   GschemDialog parent_instance;
 
   GedaList *object_list;
-  OBJECT *object;
 
   GtkTreeView    *treeview;
 
@@ -60,6 +59,8 @@ struct _Multiattrib {
 
   GdkColor       value_normal_text_color;   /* Workaround for lameness in GtkTextView */
   GdkColor       insensitive_text_color;
+  GdkColor       not_identical_value_text_color;
+  GdkColor       not_present_in_all_text_color;
 
   gulong object_list_changed_id;
 };
diff --git a/gschem/src/x_multiattrib.c b/gschem/src/x_multiattrib.c
index adaa30d..eff1e84 100644
--- a/gschem/src/x_multiattrib.c
+++ b/gschem/src/x_multiattrib.c
@@ -34,6 +34,17 @@
 
 static void multiattrib_update (Multiattrib *multiattrib);
 
+static gboolean
+snv_shows_name (int snv)
+{
+  return snv == SHOW_NAME_VALUE || snv == SHOW_NAME;
+}
+
+static gboolean
+snv_shows_value (int snv)
+{
+  return snv == SHOW_NAME_VALUE || snv == SHOW_VALUE;
+}
 
 /*! \brief Process the response returned by the multi-attribte dialog.
  *  \par Function Description
@@ -487,7 +498,17 @@ enum {
 };
 
 enum {
-  COLUMN_ATTRIBUTE,
+  COLUMN_NAME,
+  COLUMN_VALUE,
+  COLUMN_VISIBILITY,
+  COLUMN_SHOW_NAME_VALUE,
+  COLUMN_PRESENT_IN_ALL,
+  COLUMN_IDENTICAL_VALUE,
+  COLUMN_IDENTICAL_VISIBILITY,
+  COLUMN_IDENTICAL_SHOW_NAME,
+  COLUMN_IDENTICAL_SHOW_VALUE,
+  COLUMN_ATTRIBUTE_GEDALIST,
+  COLUMN_INHERITED,
   NUM_COLUMNS
 };
 
@@ -508,6 +529,28 @@ static void multiattrib_popup_menu (Multiattrib *multiattrib,
                                     GdkEventButton *event);
 
 
+/*! \brief Returns TRUE/FALSE if the given object may have attributes attached.
+ *
+ *  \par Function Description
+ *
+ *  Returns TRUE/FALSE if the given object may have attributes attached.
+ *
+ *  \param [in] object  The OBJECT to test.
+ *  \returns  TRUE/FALSE if the given object may have attributes attached.
+ */
+static gboolean is_multiattrib_object (OBJECT *object)
+{
+  if (object->type == OBJ_COMPLEX ||
+      object->type == OBJ_PLACEHOLDER ||
+      object->type == OBJ_NET ||
+      object->type == OBJ_BUS ||
+      object->type == OBJ_PIN) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+
 /*! \todo Finish function documentation
  *  \brief
  *  \par Function Description
@@ -520,8 +563,9 @@ multiattrib_action_add_attribute (Multiattrib *multiattrib,
                                   gint visible,
                                   gint show_name_value)
 {
-  OBJECT *object = multiattrib->object;
+  OBJECT *object;
   gchar *newtext;
+  GList *iter;
   GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
 
   newtext = g_strdup_printf ("%s=%s", name, value);
@@ -531,9 +575,18 @@ multiattrib_action_add_attribute (Multiattrib *multiattrib,
     return;
   }
 
-  /* create a new attribute and link it */
-  o_attrib_add_attrib (w_current, newtext,
-                       visible, show_name_value, object);
+  for (iter = geda_list_get_glist (multiattrib->object_list);
+       iter != NULL;
+       iter = g_list_next (iter)) {
+    object = (OBJECT *)iter->data;
+
+    if (is_multiattrib_object (object)) {
+
+      /* create a new attribute and link it */
+      o_attrib_add_attrib (w_current, newtext,
+                           visible, show_name_value, object);
+    }
+  }
 
   w_current->toplevel->page_current->CHANGED = 1;
   o_undo_savestate (w_current, UNDO_ALL);
@@ -547,20 +600,28 @@ multiattrib_action_add_attribute (Multiattrib *multiattrib,
  *
  */
 static void
-multiattrib_action_duplicate_attribute (Multiattrib *multiattrib,
-                                        OBJECT *o_attrib)
+multiattrib_action_duplicate_attributes (Multiattrib *multiattrib,
+                                         GList *attr_list)
 {
   GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
-  OBJECT *object = multiattrib->object;
+  GList *iter;
 
-  int visibility = o_is_visible (w_current->toplevel, o_attrib)
-      ? VISIBLE : INVISIBLE;
+  for (iter = attr_list;
+       iter != NULL;
+       iter = g_list_next (iter)) {
+    OBJECT *o_attrib = (OBJECT *)iter->data;
+
+    int visibility = o_is_visible (w_current->toplevel, o_attrib)
+        ? VISIBLE : INVISIBLE;
+
+    /* create a new attribute and link it */
+    o_attrib_add_attrib (w_current,
+                         o_text_get_string (w_current->toplevel, o_attrib),
+                         visibility,
+                         o_attrib->show_name_value,
+                         o_attrib->attached_to);
+  }
 
-  o_attrib_add_attrib (w_current,
-                       o_text_get_string (w_current->toplevel, o_attrib),
-                       visibility,
-                       o_attrib->show_name_value,
-                       object);
   w_current->toplevel->page_current->CHANGED = 1;
   o_undo_savestate (w_current, UNDO_ALL);
 }
@@ -571,32 +632,39 @@ multiattrib_action_duplicate_attribute (Multiattrib *multiattrib,
  *
  */
 static void
-multiattrib_action_promote_attribute (Multiattrib *multiattrib,
-                                      OBJECT *o_attrib)
+multiattrib_action_promote_attributes (Multiattrib *multiattrib,
+                                       GList *attr_list)
 {
   GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
-  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
-  OBJECT *object = multiattrib->object;
+  TOPLEVEL *toplevel = w_current->toplevel;
   OBJECT *o_new;
+  GList *iter;
 
-  if (o_is_visible (toplevel, o_attrib)) {
-    /* If the attribute we're promoting is visible, don't clone its location */
-    o_attrib_add_attrib (w_current,
-                         o_text_get_string (w_current->toplevel, o_attrib),
-                         VISIBLE,
-                         o_attrib->show_name_value,
-                         object);
-  } else {
-      /* make a copy of the attribute object */
-      o_new = o_object_copy (toplevel, o_attrib);
-      s_page_append (toplevel, toplevel->page_current, o_new);
-      /* add the attribute its parent */
-      o_attrib_attach (toplevel, o_new, object, TRUE);
-      /* note: this object is unselected (not added to selection). */
-
-      /* Call add-objects-hook */
-      g_run_hook_object (w_current, "%add-objects-hook", o_new);
+  for (iter = attr_list;
+       iter != NULL;
+       iter = g_list_next (iter)) {
+    OBJECT *o_attrib = (OBJECT *)iter->data;
+
+    if (o_is_visible (toplevel, o_attrib)) {
+      /* If the attribute we're promoting is visible, don't clone its location */
+      o_attrib_add_attrib (w_current,
+                           o_text_get_string (w_current->toplevel, o_attrib),
+                           VISIBLE,
+                           o_attrib->show_name_value,
+                           o_attrib->attached_to);
+    } else {
+        /* make a copy of the attribute object */
+        o_new = o_object_copy (toplevel, o_attrib);
+        s_page_append (toplevel, toplevel->page_current, o_new);
+        /* add the attribute its parent */
+        o_attrib_attach (toplevel, o_new, o_attrib->attached_to, TRUE);
+        /* note: this object is unselected (not added to selection). */
+
+        /* Call add-objects-hook */
+        g_run_hook_object (w_current, "%add-objects-hook", o_new);
+    }
   }
+
   w_current->toplevel->page_current->CHANGED = 1;
   o_undo_savestate (w_current, UNDO_ALL);
 }
@@ -607,13 +675,20 @@ multiattrib_action_promote_attribute (Multiattrib *multiattrib,
  *
  */
 static void
-multiattrib_action_delete_attribute (Multiattrib *multiattrib,
-                                     OBJECT *o_attrib)
+multiattrib_action_delete_attributes (Multiattrib *multiattrib,
+                                      GList *attr_list)
 {
   GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
+  GList *a_iter;
+  OBJECT *o_attrib;
+
+  for (a_iter = attr_list; a_iter != NULL; a_iter = g_list_next (a_iter)) {
+    o_attrib = a_iter->data;
+    /* actually deletes the attribute */
+    o_delete (w_current, o_attrib);
+  }
 
-  /* actually deletes the attribute */
-  o_delete (w_current, o_attrib);
+  w_current->toplevel->page_current->CHANGED = 1;
   o_undo_savestate (w_current, UNDO_ALL);
 }
 
@@ -629,22 +704,21 @@ multiattrib_column_set_data_name (GtkTreeViewColumn *tree_column,
                                   GtkTreeIter *iter,
                                   gpointer data)
 {
-  OBJECT *o_attrib;
-  gchar *name;
   Multiattrib *dialog = (Multiattrib *) data;
+  gchar *name;
+  gboolean present_in_all;
   int inherited;
 
   gtk_tree_model_get (tree_model, iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_NAME, &name,
+                      COLUMN_PRESENT_IN_ALL, &present_in_all,
+                      COLUMN_INHERITED, &inherited,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-
-  inherited = o_attrib_is_inherited (o_attrib);
 
-  o_attrib_get_name_value (o_attrib, &name, NULL);
   g_object_set (cell,
                 "text", name,
-                "foreground-gdk", inherited ? &dialog->insensitive_text_color : NULL,
+                "foreground-gdk", inherited ? &dialog->insensitive_text_color :
+                                  (!present_in_all ? &dialog->not_present_in_all_text_color : NULL),
                 "editable", !inherited,
                 NULL);
   g_free (name);
@@ -662,22 +736,21 @@ multiattrib_column_set_data_value (GtkTreeViewColumn *tree_column,
                                    GtkTreeIter *iter,
                                    gpointer data)
 {
-  OBJECT *o_attrib;
-  gchar *value;
   Multiattrib *dialog = (Multiattrib *) data;
+  gchar *value;
+  gboolean identical_value;
   int inherited;
 
   gtk_tree_model_get (tree_model, iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_VALUE, &value,
+                      COLUMN_IDENTICAL_VALUE, &identical_value,
+                      COLUMN_INHERITED, &inherited,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-
-  inherited = o_attrib_is_inherited (o_attrib);
 
-  o_attrib_get_name_value (o_attrib, NULL, &value);
   g_object_set (cell,
-                "text", value,
-                "foreground-gdk", inherited ? &dialog->insensitive_text_color : NULL,
+                "text", identical_value ? value : _("<various>"),
+                "foreground-gdk", inherited ? &dialog->insensitive_text_color :
+                                  (!identical_value ? &dialog->not_identical_value_text_color : NULL),
                 "editable", !inherited,
                 NULL);
   g_free (value);
@@ -695,21 +768,21 @@ multiattrib_column_set_data_visible (GtkTreeViewColumn *tree_column,
                                      GtkTreeIter *iter,
                                      gpointer data)
 {
-  OBJECT *o_attrib;
-  GschemDialog *dialog = GSCHEM_DIALOG (data);
+  gboolean visibility;
+  gboolean identical_visibility;
   int inherited;
 
   gtk_tree_model_get (tree_model, iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_VISIBILITY, &visibility,
+                      COLUMN_IDENTICAL_VISIBILITY, &identical_visibility,
+                      COLUMN_INHERITED, &inherited,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-
-  inherited = o_attrib_is_inherited (o_attrib);
 
   g_object_set (cell,
-                "active", o_is_visible (dialog->w_current->toplevel, o_attrib),
-                "sensitive",   !inherited,
-                "activatable", !inherited,
+                "active",       visibility,
+                "sensitive",    !inherited,
+                "activatable",  !inherited,
+                "inconsistent", !identical_visibility,
                 NULL);
 }
 
@@ -725,21 +798,21 @@ multiattrib_column_set_data_show_name (GtkTreeViewColumn *tree_column,
                                        GtkTreeIter *iter,
                                        gpointer data)
 {
-  OBJECT *o_attrib;
+  int show_name_value;
+  gboolean identical_show_name;
   int inherited;
 
   gtk_tree_model_get (tree_model, iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_SHOW_NAME_VALUE, &show_name_value,
+                      COLUMN_IDENTICAL_SHOW_NAME, &identical_show_name,
+                      COLUMN_INHERITED, &inherited,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-
-  inherited = o_attrib_is_inherited (o_attrib);
 
   g_object_set (cell,
-                "active", (o_attrib->show_name_value == SHOW_NAME_VALUE ||
-                           o_attrib->show_name_value == SHOW_NAME),
-                "sensitive",   !inherited,
-                "activatable", !inherited,
+                "active",       snv_shows_name (show_name_value),
+                "sensitive",    !inherited,
+                "activatable",  !inherited,
+                "inconsistent", !identical_show_name,
                 NULL);
 }
 
@@ -755,44 +828,24 @@ multiattrib_column_set_data_show_value (GtkTreeViewColumn *tree_column,
                                         GtkTreeIter *iter,
                                         gpointer data)
 {
-  OBJECT *o_attrib;
+  int show_name_value;
+  gboolean identical_show_value;
   int inherited;
 
   gtk_tree_model_get (tree_model, iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_SHOW_NAME_VALUE, &show_name_value,
+                      COLUMN_IDENTICAL_SHOW_VALUE, &identical_show_value,
+                      COLUMN_INHERITED, &inherited,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-
-  inherited = o_attrib_is_inherited (o_attrib);
 
   g_object_set (cell,
-                "active", (o_attrib->show_name_value == SHOW_NAME_VALUE ||
-                           o_attrib->show_name_value == SHOW_VALUE),
-                "sensitive",   !inherited,
-                "activatable", !inherited,
+                "active",       snv_shows_value (show_name_value),
+                "sensitive",    !inherited,
+                "activatable",  !inherited,
+                "inconsistent", !identical_show_value,
                 NULL);
 }
 
-/*! \brief Requests an update of the display of a row.
- *  \par Function Description
- *  This is an helper function to update the display of a row when
- *  data for this row have been modified in the model.
- *
- *  It emits the 'row_changed' signal on the pointed row.
- *
- *  \param [in] model A GtkTreeModel.
- *  \param [in] iter  A valid GtkTreeIter pointing to the changed row.
- */
-static void
-update_row_display (GtkTreeModel *model, GtkTreeIter *iter)
-{
-  GtkTreePath *path;
-
-  path = gtk_tree_model_get_path (model, iter);
-  gtk_tree_model_row_changed (model, path, iter);
-  gtk_tree_path_free (path);
-}
-
 /*! \todo Finish function documentation
  *  \brief
  *  \par Function Description
@@ -801,12 +854,14 @@ update_row_display (GtkTreeModel *model, GtkTreeIter *iter)
 static void
 multiattrib_callback_edited_name (GtkCellRendererText *cellrenderertext,
                                   gchar *arg1,
-                                  gchar *arg2,
+                                  gchar *new_name,
                                   gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
+  GedaList *attr_list;
+  GList *a_iter;
   OBJECT *o_attrib;
   GschemToplevel *w_current;
   gchar *value, *newtext;
@@ -819,7 +874,7 @@ multiattrib_callback_edited_name (GtkCellRendererText *cellrenderertext,
     return;
   }
 
-  if (g_ascii_strcasecmp (arg2, "") == 0) {
+  if (g_ascii_strcasecmp (new_name, "") == 0) {
     GtkWidget *dialog = gtk_message_dialog_new (
       GTK_WINDOW (multiattrib),
       GTK_DIALOG_MODAL,
@@ -833,12 +888,11 @@ multiattrib_callback_edited_name (GtkCellRendererText *cellrenderertext,
   }
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_VALUE, &value,
+                      COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
 
-  o_attrib_get_name_value (o_attrib, NULL, &value);
-  newtext = g_strdup_printf ("%s=%s", arg2, value);
+  newtext = g_strdup_printf ("%s=%s", new_name, value);
 
   if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib), newtext)) {
     g_free (value);
@@ -846,15 +900,30 @@ multiattrib_callback_edited_name (GtkCellRendererText *cellrenderertext,
     return;
   }
 
-  visibility = o_is_visible (w_current->toplevel, o_attrib)
-      ? VISIBLE : INVISIBLE;
+  for (a_iter = geda_list_get_glist (attr_list);
+       a_iter != NULL;
+       a_iter = g_list_next (a_iter)) {
+    o_attrib = a_iter->data;
+
+    visibility = o_is_visible (w_current->toplevel, o_attrib)
+        ? VISIBLE : INVISIBLE;
 
-  /* actually modifies the attribute */
-  o_text_change (w_current, o_attrib,
-                 newtext, visibility, o_attrib->show_name_value);
+    /* actually modifies the attribute */
+    o_text_change (w_current, o_attrib,
+                   newtext, visibility, o_attrib->show_name_value);
+  }
 
+  g_object_unref (attr_list);
   g_free (value);
   g_free (newtext);
+
+  w_current->toplevel->page_current->CHANGED = 1;
+  o_undo_savestate (w_current, UNDO_ALL);
+
+  /* NB: We don't fix up the model to reflect the edit, we're about to nuke it below... */
+
+  /* Refresh the whole model.. some attribute names may consolidate into one row */
+  multiattrib_update (multiattrib);
 }
 
 /*! \todo Finish function documentation
@@ -865,15 +934,19 @@ multiattrib_callback_edited_name (GtkCellRendererText *cellrenderertext,
 static void
 multiattrib_callback_edited_value (GtkCellRendererText *cell_renderer,
                                    gchar *arg1,
-                                   gchar *arg2,
+                                   gchar *new_value,
                                    gpointer user_data)
 {
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
+  GedaList *attr_list;
+  GList *a_iter;
   OBJECT *o_attrib;
   GschemToplevel *w_current;
-  gchar *name, *newtext;
+  char *name;
+  char *old_value;
+  char *newtext;
   int visibility;
 
   model = gtk_tree_view_get_model (multiattrib->treeview);
@@ -884,12 +957,16 @@ multiattrib_callback_edited_value (GtkCellRendererText *cell_renderer,
   }
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_NAME, &name,
+                      COLUMN_VALUE, &old_value,
+                      COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
 
-  o_attrib_get_name_value (o_attrib, &name, NULL);
-  newtext = g_strdup_printf ("%s=%s", name, arg2);
+  /* If the edit didn't change anything, don't adjust any attributes */
+  if (strcmp (old_value, new_value) == 0)
+    return;
+
+  newtext = g_strdup_printf ("%s=%s", name, new_value);
 
   if (!x_dialog_validate_attribute(GTK_WINDOW(multiattrib), newtext)) {
     g_free (name);
@@ -897,18 +974,32 @@ multiattrib_callback_edited_value (GtkCellRendererText *cell_renderer,
     return;
   }
 
-  visibility = o_is_visible (w_current->toplevel, o_attrib)
-      ? VISIBLE : INVISIBLE;
+  for (a_iter = geda_list_get_glist (attr_list);
+       a_iter != NULL;
+       a_iter = g_list_next (a_iter)) {
+    o_attrib = (OBJECT *)a_iter->data;
 
-  /* actually modifies the attribute */
-  o_text_change (w_current, o_attrib,
-                 newtext, visibility, o_attrib->show_name_value);
+    visibility = o_is_visible (w_current->toplevel, o_attrib)
+        ? VISIBLE : INVISIBLE;
 
-  /* request an update of display for this row */
-  update_row_display (model, &iter);
+    /* actually modifies the attribute */
+    o_text_change (w_current, o_attrib,
+                   newtext, visibility, o_attrib->show_name_value);
+  }
+
+  g_object_unref (attr_list);
 
   g_free (name);
   g_free (newtext);
+
+  w_current->toplevel->page_current->CHANGED = 1;
+  o_undo_savestate (w_current, UNDO_ALL);
+
+  /* Fixup the model to reflect the edit */
+  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                      COLUMN_VALUE, new_value,
+                      COLUMN_IDENTICAL_VALUE, TRUE,
+                      -1);
 }
 
 /*! \todo Finish function documentation
@@ -926,7 +1017,9 @@ multiattrib_callback_toggled_visible (GtkCellRendererToggle *cell_renderer,
   GtkTreeIter iter;
   OBJECT *o_attrib;
   GschemToplevel *w_current;
-  gint visibility;
+  gboolean new_visibility;
+  GedaList *attr_list;
+  GList *a_iter;
 
   model = gtk_tree_view_get_model (multiattrib->treeview);
   w_current = GSCHEM_DIALOG (multiattrib)->w_current;
@@ -936,22 +1029,32 @@ multiattrib_callback_toggled_visible (GtkCellRendererToggle *cell_renderer,
   }
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-  o_invalidate (w_current, o_attrib);
 
-  /* toggle visibility */
-  visibility = o_is_visible (w_current->toplevel, o_attrib)
-      ? INVISIBLE : VISIBLE;
+  new_visibility = !gtk_cell_renderer_toggle_get_active (cell_renderer);
 
-  /* actually modifies the attribute */
-  o_set_visibility (w_current->toplevel, o_attrib, visibility);
-  o_text_recreate (w_current->toplevel, o_attrib);
+  for (a_iter = geda_list_get_glist (attr_list);
+       a_iter != NULL;
+       a_iter = g_list_next (a_iter)) {
+    o_attrib = (OBJECT *)a_iter->data;
+
+    /* actually modifies the attribute */
+    o_invalidate (w_current, o_attrib);
+    o_set_visibility (w_current->toplevel, o_attrib, new_visibility ? VISIBLE : INVISIBLE);
+    o_text_recreate (w_current->toplevel, o_attrib);
+  }
+
+  g_object_unref (attr_list);
+
+  w_current->toplevel->page_current->CHANGED = 1;
   o_undo_savestate (w_current, UNDO_ALL);
 
-  /* request an update of display for this row */
-  update_row_display (model, &iter);
+  /* Fixup the model to reflect the edit */
+  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                      COLUMN_VISIBILITY, new_visibility,
+                      COLUMN_IDENTICAL_VISIBILITY, TRUE,
+                      -1);
 }
 
 /*! \todo Finish function documentation
@@ -967,8 +1070,10 @@ multiattrib_callback_toggled_show_name (GtkCellRendererToggle *cell_renderer,
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  OBJECT *o_attrib;
   GschemToplevel *w_current;
+  gboolean new_name_visible;
+  GedaList *attr_list;
+  GList *a_iter;
   gint new_snv;
 
   model = gtk_tree_view_get_model (multiattrib->treeview);
@@ -979,27 +1084,41 @@ multiattrib_callback_toggled_show_name (GtkCellRendererToggle *cell_renderer,
   }
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-  o_invalidate (w_current, o_attrib);
 
-  switch (o_attrib->show_name_value) {
-      case SHOW_NAME_VALUE: new_snv = SHOW_VALUE;      break;
-      case SHOW_NAME:       new_snv = SHOW_VALUE;      break;
-      case SHOW_VALUE:      new_snv = SHOW_NAME_VALUE; break;
-      default:
-        g_assert_not_reached ();
-        new_snv = SHOW_NAME_VALUE;
+  new_name_visible = !gtk_cell_renderer_toggle_get_active (cell_renderer);
+
+  for (a_iter = geda_list_get_glist (attr_list);
+       a_iter != NULL;
+       a_iter = g_list_next (a_iter)) {
+    OBJECT *o_attrib = (OBJECT *)a_iter->data;
+
+    gboolean value_visible = snv_shows_value (o_attrib->show_name_value);
+
+    /* If we switch off the name visibility, but the value was not previously visible, make it so now */
+    if (new_name_visible)
+      new_snv = value_visible ? SHOW_NAME_VALUE : SHOW_NAME;
+    else
+      new_snv = SHOW_VALUE;
+
+    o_invalidate (w_current, o_attrib);
+
+    /* actually modifies the attribute */
+    o_attrib->show_name_value = new_snv;
+    o_text_recreate (w_current->toplevel, o_attrib);
   }
 
-  /* actually modifies the attribute */
-  o_attrib->show_name_value = new_snv;
-  o_text_recreate (w_current->toplevel, o_attrib);
+  g_object_unref (attr_list);
+
+  w_current->toplevel->page_current->CHANGED = 1;
   o_undo_savestate (w_current, UNDO_ALL);
 
+  /* NB: We don't fix up the model to reflect the edit, we're about to nuke it below... */
+
   /* request an update of display for this row */
-  update_row_display (model, &iter);
+  /* Recompute the whole model as the consistency for the show value column may be affected above */
+  multiattrib_update (multiattrib);
 }
 
 /*! \todo Finish function documentation
@@ -1015,8 +1134,10 @@ multiattrib_callback_toggled_show_value (GtkCellRendererToggle *cell_renderer,
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  OBJECT *o_attrib;
   GschemToplevel *w_current;
+  gboolean new_value_visible;
+  GedaList *attr_list;
+  GList *a_iter;
   gint new_snv;
 
   model = gtk_tree_view_get_model (multiattrib->treeview);
@@ -1027,27 +1148,41 @@ multiattrib_callback_toggled_show_value (GtkCellRendererToggle *cell_renderer,
   }
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-  o_invalidate (w_current, o_attrib);
 
-  switch (o_attrib->show_name_value) {
-      case SHOW_NAME_VALUE: new_snv = SHOW_NAME;       break;
-      case SHOW_NAME:       new_snv = SHOW_NAME_VALUE; break;
-      case SHOW_VALUE:      new_snv = SHOW_NAME;       break;
-      default:
-        g_assert_not_reached ();
-        new_snv = SHOW_NAME_VALUE;
+  new_value_visible = !gtk_cell_renderer_toggle_get_active (cell_renderer);
+
+  for (a_iter = geda_list_get_glist (attr_list);
+       a_iter != NULL;
+       a_iter = g_list_next (a_iter)) {
+    OBJECT *o_attrib = (OBJECT *)a_iter->data;
+
+    gboolean name_visible = snv_shows_name (o_attrib->show_name_value);
+
+    /* If we switch off the name visibility, but the value was not previously visible, make it so now */
+    if (new_value_visible)
+      new_snv = name_visible ? SHOW_NAME_VALUE : SHOW_VALUE;
+    else
+      new_snv = SHOW_NAME;
+
+    o_invalidate (w_current, o_attrib);
+
+    /* actually modifies the attribute */
+    o_attrib->show_name_value = new_snv;
+    o_text_recreate (w_current->toplevel, o_attrib);
   }
 
-  /* actually modifies the attribute */
-  o_attrib->show_name_value = new_snv;
-  o_text_recreate (w_current->toplevel, o_attrib);
+  g_object_unref (attr_list);
+
+  w_current->toplevel->page_current->CHANGED = 1;
   o_undo_savestate (w_current, UNDO_ALL);
 
+  /* NB: We don't fix up the model to reflect the edit, we're about to nuke it below... */
+
   /* request an update of display for this row */
-  update_row_display (model, &iter);
+  /* Recompute the whole model as the consistency for the show name column may be affected above */
+  multiattrib_update (multiattrib);
 }
 
 /*! \todo Finish function documentation
@@ -1066,7 +1201,7 @@ multiattrib_callback_key_pressed (GtkWidget *widget,
       (event->keyval == GDK_Delete || event->keyval == GDK_KP_Delete)) {
     GtkTreeModel *model;
     GtkTreeIter iter;
-    OBJECT *o_attrib;
+    GedaList *attr_list;
     int inherited;
     /* delete the currently selected attribute */
 
@@ -1078,16 +1213,18 @@ multiattrib_callback_key_pressed (GtkWidget *widget,
     }
 
     gtk_tree_model_get (model, &iter,
-                        COLUMN_ATTRIBUTE, &o_attrib,
+                        COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
+                        COLUMN_INHERITED, &inherited,
                         -1);
-    g_assert (o_attrib->type == OBJ_TEXT);
 
-    inherited = o_attrib_is_inherited (o_attrib);
     /* We can't delete inherited attribtes */
     if (inherited)
       return FALSE;
 
-    multiattrib_action_delete_attribute (multiattrib, o_attrib);
+    multiattrib_action_delete_attributes (multiattrib,
+                                          geda_list_get_glist (attr_list));
+
+    g_object_unref (attr_list);
 
     /* update the treeview contents */
     multiattrib_update (multiattrib);
@@ -1185,7 +1322,7 @@ multiattrib_callback_popup_duplicate (GtkMenuItem *menuitem,
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  OBJECT *o_attrib;
+  GedaList *attr_list;
 
   if (!gtk_tree_selection_get_selected (
         gtk_tree_view_get_selection (multiattrib->treeview),
@@ -1195,11 +1332,10 @@ multiattrib_callback_popup_duplicate (GtkMenuItem *menuitem,
   }
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-
-  multiattrib_action_duplicate_attribute (multiattrib, o_attrib);
+  multiattrib_action_duplicate_attributes (multiattrib, geda_list_get_glist (attr_list));
+  g_object_unref (attr_list);
 
   /* update the treeview contents */
   multiattrib_update (multiattrib);
@@ -1218,7 +1354,7 @@ multiattrib_callback_popup_promote (GtkMenuItem *menuitem,
   Multiattrib *multiattrib = user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  OBJECT *o_attrib;
+  GedaList *attr_list;
 
   if (!gtk_tree_selection_get_selected (
          gtk_tree_view_get_selection (multiattrib->treeview),
@@ -1228,11 +1364,10 @@ multiattrib_callback_popup_promote (GtkMenuItem *menuitem,
   }
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-
-  multiattrib_action_promote_attribute (multiattrib, o_attrib);
+  multiattrib_action_promote_attributes (multiattrib, geda_list_get_glist (attr_list));
+  g_object_unref (attr_list);
 
   /* update the treeview contents */
   multiattrib_update (multiattrib);
@@ -1250,7 +1385,7 @@ multiattrib_callback_popup_delete (GtkMenuItem *menuitem,
   Multiattrib *multiattrib = (Multiattrib*)user_data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  OBJECT *o_attrib;
+  GedaList *attr_list;
 
   if (!gtk_tree_selection_get_selected (
         gtk_tree_view_get_selection (multiattrib->treeview),
@@ -1260,11 +1395,10 @@ multiattrib_callback_popup_delete (GtkMenuItem *menuitem,
   }
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_ATTRIBUTE_GEDALIST, &attr_list,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
-
-  multiattrib_action_delete_attribute (multiattrib, o_attrib);
+  multiattrib_action_delete_attributes (multiattrib, geda_list_get_glist (attr_list));
+  g_object_unref (attr_list);
 
   /* update the treeview contents */
   multiattrib_update (multiattrib);
@@ -1450,7 +1584,6 @@ multiattrib_popup_menu (Multiattrib *multiattrib, GdkEventButton *event)
   GtkTreeModel *model;
   GtkTreeIter iter;
   GtkTreeSelection *selection;
-  OBJECT *o_attrib;
 
   selection = gtk_tree_view_get_selection (multiattrib->treeview);
 
@@ -1469,11 +1602,9 @@ multiattrib_popup_menu (Multiattrib *multiattrib, GdkEventButton *event)
     return;
 
   gtk_tree_model_get (model, &iter,
-                      COLUMN_ATTRIBUTE, &o_attrib,
+                      COLUMN_INHERITED, &inherited,
                       -1);
-  g_assert (o_attrib->type == OBJ_TEXT);
 
-  inherited = o_attrib_is_inherited (o_attrib);
   item_list = inherited ? menuitems_inherited : menuitems_noninherited;
 
   /* create the context menu */
@@ -1590,58 +1721,16 @@ multiattrib_get_type ()
 }
 
 
-/*! \brief Update the multiattrib editor dialog when the page's selection changes.
+/*! \brief Update the multiattrib editor dialog when its object list changes.
  *
  *  \par Function Description
  *
- *  When the page's selection changes this function identifies how many objects
- *  which can have attributes are currently selected. If this number is 1, the
- *  dialog is set to edit its attributes.
- *
- *  \todo The dialog doesn't currently support editing multiple objects at once
- *
  *  \param [in] selection    The GedaList object of we are watching/
  *  \param [in] multiattrib  The multi-attribute editor dialog.
  */
 static void
 object_list_changed_cb (GedaList *object_list, Multiattrib *multiattrib)
 {
-  int object_count = 0;
-  GList *object_glist;
-  GList *iter;
-  OBJECT *object;
-
-  object_glist = geda_list_get_glist (object_list);
-
-  for (iter = object_glist;
-       iter != NULL;
-       iter = g_list_next (iter)) {
-    object = (OBJECT *)iter->data;
-    g_assert( object != NULL );
-
-    if (object->type == OBJ_COMPLEX ||
-        object->type == OBJ_PLACEHOLDER ||
-        object->type == OBJ_NET ||
-        object->type == OBJ_BUS ||
-        object->type == OBJ_PIN) {
-      object_count++;
-    }
-  }
-
-  if (object_count == 0) {
-    /* TODO: If the user selects a single attribute which is
-     *       not floating, should we find its parent object and
-     *       display the multi-attribute editor for that?
-     *       Bonus marks for making it jump to the correct attrib.
-     */
-    multiattrib->object = NULL;
-  } else if (object_count == 1) {
-    multiattrib->object = (OBJECT *)object_glist->data;
-  } else {
-    /* TODO: Something clever with multiple objects selected */
-    multiattrib->object = NULL;
-  }
-
   multiattrib_update (multiattrib);
 }
 
@@ -1824,8 +1913,6 @@ multiattrib_init (Multiattrib *multiattrib)
                 "has-separator",   TRUE,
                 NULL);
 
-  multiattrib->object   = NULL;
-
   gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (multiattrib)->vbox), 5);
 
   /* create the attribute list frame */
@@ -1836,7 +1923,18 @@ multiattrib_init (Multiattrib *multiattrib)
   multiattrib->frame_add = frame;
   /*   - create the model for the treeview */
   store = (GtkTreeModel*)gtk_list_store_new (NUM_COLUMNS,
-                                             G_TYPE_POINTER); /* attribute */
+                                             G_TYPE_STRING,   /* COLUMN_NAME */
+                                             G_TYPE_STRING,   /* COLUMN_VALUE */
+                                             G_TYPE_BOOLEAN,  /* COLUMN_VISIBILITY */
+                                             G_TYPE_INT,      /* COLUMN_SHOW_NAME_VALUE */
+                                             G_TYPE_BOOLEAN,  /* COLUMN_PRESENT_IN_ALL */
+                                             G_TYPE_BOOLEAN,  /* COLUMN_IDENTICAL_VALUE */
+                                             G_TYPE_BOOLEAN,  /* COLUMN_IDENTICAL_VISIBILITY */
+                                             G_TYPE_BOOLEAN,  /* COLUMN_IDENTICAL_SHOW_NAME */
+                                             G_TYPE_BOOLEAN,  /* COLUMN_IDENTICAL_SHOW_VALUE */
+                                             G_TYPE_OBJECT,   /* COLUMN_ATTRIBUTE_GEDALIST */
+                                             G_TYPE_BOOLEAN); /* COLUMN_INHERITED */
+
   /*   - create a scrolled window for the treeview */
   scrolled_win = GTK_WIDGET (
                     g_object_new (GTK_TYPE_SCROLLED_WINDOW,
@@ -2077,6 +2175,9 @@ multiattrib_init (Multiattrib *multiattrib)
   style = gtk_widget_get_style (treeview);
   multiattrib->insensitive_text_color = style->text[ GTK_STATE_INSENSITIVE ];
 
+  gdk_color_parse ("grey", &multiattrib->not_identical_value_text_color);
+  gdk_color_parse ("red",  &multiattrib->not_present_in_all_text_color);
+
   gtk_container_add (GTK_CONTAINER (scrolled_win), textview);
   multiattrib->textview_value = GTK_TEXT_VIEW (textview);
   gtk_table_attach (GTK_TABLE (table), label,
@@ -2123,6 +2224,8 @@ multiattrib_init (Multiattrib *multiattrib)
   /* now add the close button to the action area */
   gtk_dialog_add_button (GTK_DIALOG (multiattrib),
                          GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+
+  multiattrib_update (multiattrib);
 }
 
 
@@ -2185,6 +2288,76 @@ multiattrib_get_property (GObject *object,
   }
 }
 
+typedef struct st_ma_model_row {
+  char *name;
+  char *value;
+  gboolean visibility;
+  int show_name_value;
+  gboolean present_in_all;
+  gboolean identical_value;
+  gboolean identical_visibility;
+  gboolean identical_show_name;
+  gboolean identical_show_value;
+  GedaList *attribute_gedalist;
+  gboolean inherited;
+} MODEL_ROW;
+
+/*! \brief Populate the multiattrib editor dialog's liststore
+ *
+ *  \par Function Description
+ *
+ *  Consumes the GList of MODEL_ROW data, populating the dialog's liststore.
+ *  The function frees / consumes the GList and MODEL_ROW data.
+ *
+ *  \param [in] multiattrib  The multi-attribute editor dialog.
+ *  \param [in] model_rows   A GList of MODEL_ROW data.
+ */
+static void
+multiattrib_populate_liststore (Multiattrib *multiattrib,
+                                GList *model_rows,
+                                int total_num_in_list)
+{
+  GtkListStore *liststore;
+  GtkTreeIter tree_iter;
+  GList *m_iter;
+
+  /* Clear the existing list of attributes */
+  liststore = (GtkListStore*)gtk_tree_view_get_model (multiattrib->treeview);
+  gtk_list_store_clear (liststore);
+
+  for (m_iter = model_rows;
+       m_iter != NULL;
+       m_iter = g_list_next (m_iter)) {
+
+    MODEL_ROW *model_row = m_iter->data;
+
+    model_row->present_in_all =
+      (g_list_length (geda_list_get_glist (model_row->attribute_gedalist))
+       == total_num_in_list);
+
+    gtk_list_store_append (liststore, &tree_iter);
+    gtk_list_store_set (liststore,
+                        &tree_iter,
+                        COLUMN_NAME, model_row->name,
+                        COLUMN_VALUE, model_row->value,
+                        COLUMN_VISIBILITY, model_row->visibility,
+                        COLUMN_SHOW_NAME_VALUE, model_row->show_name_value,
+                        COLUMN_PRESENT_IN_ALL, model_row->present_in_all,
+                        COLUMN_IDENTICAL_VALUE, model_row->identical_value,
+                        COLUMN_IDENTICAL_VISIBILITY, model_row->identical_visibility,
+                        COLUMN_IDENTICAL_SHOW_NAME, model_row->identical_show_name,
+                        COLUMN_IDENTICAL_SHOW_VALUE, model_row->identical_show_value,
+                        COLUMN_ATTRIBUTE_GEDALIST, model_row->attribute_gedalist,
+                        COLUMN_INHERITED, model_row->inherited,
+                        -1);
+
+    /* Drop our ref on the GedaList so it is freed when the model has done with it */
+    g_object_unref (model_row->attribute_gedalist);
+  }
+
+  g_list_foreach (model_rows, (GFunc) g_free, NULL);
+  g_list_free (model_rows);
+}
 
 /*! \brief Update the multiattrib editor dialog's interface
  *
@@ -2194,49 +2367,209 @@ multiattrib_get_property (GObject *object,
  *  object. If no (or multiple) objects are selected, the dialog's controls
  *  are set insensitive.
  *
- *  \todo The dialog doesn't currently support editing multiple objects at once
- *
  *  \param [in] multiattrib  The multi-attribute editor dialog.
  */
 static void
 multiattrib_update (Multiattrib *multiattrib)
 {
-  GtkListStore *liststore;
-  GtkTreeIter iter;
+  GschemToplevel *w_current = GSCHEM_DIALOG (multiattrib)->w_current;
+  GList *o_iter;
+  OBJECT *object;
   GList *object_attribs;
   GList *a_iter;
   OBJECT *a_current;
-  gboolean sensitive;
   GtkStyle *style;
+  gboolean inherited;
   gboolean show_inherited;
+  gboolean sensitive;
+
+  GList *m_iter, *model_rows = NULL;
+
+  int total_num_in_list = 0;
+  int num_complex_in_list = 0;
+  int num_pins_in_list = 0;
+  int num_nets_in_list = 0;
+  int num_buses_in_list = 0;
+
+  gboolean found, visibility;
+  gchar *name, *value;
+  int show_name_value;
+  char *complex_title_name = NULL;
+
+  show_inherited =
+    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiattrib->show_inherited));
+
+  /* populate the store with attributes */
+  for (o_iter = multiattrib->object_list == NULL ? NULL : geda_list_get_glist (multiattrib->object_list);
+       o_iter != NULL;
+       o_iter = g_list_next (o_iter)) {
+    object = o_iter->data;
+
+    if (!is_multiattrib_object (object))
+      continue;
+
+    /* Count the different objects we are editing */
+    total_num_in_list++;
+
+    if (object->type == OBJ_COMPLEX ||
+        object->type == OBJ_PLACEHOLDER) {
+      num_complex_in_list++;
+
+      if (complex_title_name == NULL)
+        complex_title_name = object->complex_basename;
+      else if (strcmp (complex_title_name, object->complex_basename) != 0)
+        complex_title_name = _("<various>");
+    }
+
+    if (object->type == OBJ_PIN)
+      num_pins_in_list++;
+
+    if (object->type == OBJ_NET)
+      num_nets_in_list++;
+
+    if (object->type == OBJ_BUS)
+      num_buses_in_list++;
+
+    /* populate the store with any attributes from this object */
+    object_attribs = o_attrib_return_attribs (object);
+    for (a_iter = object_attribs; a_iter != NULL;
+         a_iter = g_list_next (a_iter)) {
+
+      MODEL_ROW *model_row;
+
+      a_current = a_iter->data;
+
+      inherited = o_attrib_is_inherited (a_current);
+
+      /* Skip over inherited attributes if we don't want to show them */
+      if (!show_inherited && inherited)
+        continue;
+
+      o_attrib_get_name_value (a_current, &name, &value);
+      visibility =
+        o_is_visible (w_current->toplevel, a_current) ? VISIBLE : INVISIBLE;
+      show_name_value = a_current->show_name_value;
+
+      /* Search our list of attributes to see if we already encountered */
+      /* TODO: Ensure the search only goes as far as the last object scanned */
+      for (m_iter = model_rows, found = FALSE;
+           m_iter != NULL && found == FALSE;
+           m_iter = g_list_next (m_iter)) {
+        model_row = m_iter->data;
+        if (strcmp (model_row->name, name) == 0 &&
+            model_row->inherited == inherited)
+          found = TRUE;
+      }
+
+      if (found) {
+        /* Name matches a previously found attribute */
+        /* Check if the rest of its properties match the one we have stored... */
+
+        if (strcmp (model_row->value, value) != 0)
+          model_row->identical_value = FALSE;
+
+        if (model_row->visibility != visibility)
+          model_row->identical_visibility = FALSE;
+
+        if (snv_shows_name (model_row->show_name_value) !=
+            snv_shows_name (show_name_value))
+          model_row->identical_show_name = FALSE;
+
+        if (snv_shows_value (model_row->show_name_value) !=
+            snv_shows_value (show_name_value))
+          model_row->identical_show_value = FALSE;
+
+      } else {
+        /*
+         * The attribute name doesn't match any previously found
+         * attribute, so add a new entry describing it to the list.
+         */
+        model_row = g_new0 (MODEL_ROW, 1);
+        model_row->name = name;
+        model_row->value = value;
+        model_row->visibility = visibility;
+        model_row->show_name_value = show_name_value;
+        model_row->identical_value = TRUE;
+        model_row->identical_visibility = TRUE;
+        model_row->identical_show_name = TRUE;
+        model_row->identical_show_value = TRUE;
+        model_row->attribute_gedalist = geda_list_new ();
+        model_row->inherited = inherited;
+        model_row->present_in_all = TRUE;
+
+        model_rows = g_list_append (model_rows, model_row);
+      }
+
+      /* Add the underlying attribute to the row's GedaList of attributes */
+      geda_list_add (model_row->attribute_gedalist, a_current);
+    }
+
+    /* delete the list of attribute objects */
+    g_list_free (object_attribs);
+  }
 
-  g_assert (GSCHEM_DIALOG (multiattrib)->w_current != NULL);
-
-  /* Update window title. If one object is selected and it's a
-   * component, put its basename in the window title. */
-  if (multiattrib->object != NULL &&
-      (multiattrib->object->type == OBJ_COMPLEX ||
-       multiattrib->object->type == OBJ_PLACEHOLDER)) {
-    char *title = g_strdup_printf (_("Edit Attributes - %s"),
-                                   multiattrib->object->complex_basename);
-    g_object_set (G_OBJECT (multiattrib),
-                  "title",           title,
-                  NULL);
-    g_free (title);
+  multiattrib_populate_liststore (multiattrib, model_rows, total_num_in_list);
+
+  if (total_num_in_list == 0) {
+    /* TODO: If the user selects a single attribute which is
+     *       not floating, should we find its parent object and
+     *       display the multi-attribute editor for that?
+     *       Bonus marks for making it jump to the correct attrib.
+     */
+    sensitive = FALSE;
   } else {
-    g_object_set (G_OBJECT (multiattrib),
-                  "title", _("Edit Attributes"),
-                  NULL);
+    sensitive = TRUE;
   }
 
-  /* clear the list of attributes */
-  liststore = (GtkListStore*)gtk_tree_view_get_model (multiattrib->treeview);
-  gtk_list_store_clear (liststore);
+  /* Update window title to describe the objects we are editing. */
+
+  GString *title_string = g_string_new (_("Edit Attributes"));
+  gboolean first_title_extra = TRUE;
+  gboolean any_title_extra = FALSE;
+
+  if (num_complex_in_list > 0) {
+    if (first_title_extra) g_string_append (title_string, " - ");
+    if (any_title_extra)   g_string_append (title_string, ", ");
+    first_title_extra = FALSE;
+    any_title_extra = TRUE;
+    g_string_append_printf (title_string,
+                            ngettext ("%i symbol (%s)", "%i symbols (%s)", num_complex_in_list),
+                            num_complex_in_list,
+                            complex_title_name);
+  }
+
+  if (num_pins_in_list > 0) {
+    if (first_title_extra) g_string_append (title_string, " - ");
+    if (any_title_extra)   g_string_append (title_string, ", ");
+    first_title_extra = FALSE;
+    any_title_extra = TRUE;
+    g_string_append_printf (title_string, ngettext ("%i pin", "%i pins",  num_pins_in_list),  num_pins_in_list);
+  }
+
+  if (num_nets_in_list > 0) {
+    if (first_title_extra) g_string_append (title_string, " - ");
+    if (any_title_extra)   g_string_append (title_string, ", ");
+    first_title_extra = FALSE;
+    any_title_extra = TRUE;
+    g_string_append_printf (title_string, ngettext ("%i net", "%i nets",  num_nets_in_list),  num_nets_in_list);
+  }
+
+  if (num_buses_in_list > 0) {
+    if (first_title_extra) g_string_append (title_string, " - ");
+    if (any_title_extra)   g_string_append (title_string, ", ");
+    first_title_extra = FALSE;
+    any_title_extra = TRUE;
+    g_string_append_printf (title_string, ngettext ("%i bus", "%i buses", num_buses_in_list), num_buses_in_list);
+  }
+
+  char *title = g_string_free (title_string, FALSE);
+  g_object_set (G_OBJECT (multiattrib), "title", title, NULL);
+  g_free (title);
+
 
   /* Update sensitivities */
-  sensitive = (multiattrib->object_list != NULL && multiattrib->object != NULL);
   gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_attributes), sensitive);
-  gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_add), sensitive);
+  gtk_widget_set_sensitive (GTK_WIDGET (multiattrib->frame_add),        sensitive);
 
   /* Work around GtkTextView's stubborn indifference
    * to GTK_STATE_INSENSITIVE when rendering its text. */
@@ -2245,30 +2578,4 @@ multiattrib_update (Multiattrib *multiattrib)
                           GTK_STATE_NORMAL,
                           sensitive ? &multiattrib->value_normal_text_color
                                     : &style->text[GTK_STATE_INSENSITIVE]);
-
-  /* If we aren't sensitive, there is nothing more to do */
-  if (!sensitive)
-    return;
-
-  show_inherited =
-    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (multiattrib->show_inherited));
-
-  /* get list of attributes */
-  object_attribs = o_attrib_return_attribs (multiattrib->object);
-  /* populate the store with attributes */
-  for (a_iter = object_attribs; a_iter != NULL;
-       a_iter = g_list_next (a_iter)) {
-    a_current = a_iter->data;
-
-    /* Skip over inherited attributes if we don't want to show them */
-    if (!show_inherited && o_attrib_is_inherited (a_current))
-      continue;
-
-    gtk_list_store_append (liststore, &iter);
-    gtk_list_store_set (liststore, &iter,
-                        COLUMN_ATTRIBUTE, a_current,
-                        -1);
-  }
-  /* delete the list of attribute objects */
-  g_list_free (object_attribs);
 }
-- 
1.8.3.2