/*
 * glade-gtk-box.c - GladeWidgetAdaptor for GtkGrid widget
 *
 * Copyright (C) 2013 Openismus GmbH
 *
 * Authors:
 *      Tristan Van Berkom <tristanvb@openismus.com>
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <config.h>

#include <gtk/gtk.h>
#include <glib/gi18n-lib.h>
#include <string.h>

#include "glade-fixed.h"
#include "glade-gtk-notebook.h"
#include "glade-box-editor.h"
#include "glade-gtk.h"

static gboolean glade_gtk_box_configure_child (GladeFixed   *fixed,
                                               GladeWidget  *child,
                                               GdkRectangle *rect,
                                               GtkWidget    *box);

static gboolean glade_gtk_box_configure_begin (GladeFixed  *fixed,
                                               GladeWidget *child,
                                               GtkWidget   *box);


static gboolean glade_gtk_box_configure_end (GladeFixed  *fixed,
                                             GladeWidget *child,
                                             GtkWidget   *box);


GladeEditable *
glade_gtk_box_create_editable (GladeWidgetAdaptor *adaptor,
                               GladeEditorPageType type)
{
  if (type == GLADE_PAGE_GENERAL)
    return (GladeEditable *) glade_box_editor_new ();

  return GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->create_editable (adaptor, type);
}

static void
glade_gtk_box_parse_finished (GladeProject *project, GObject *box)
{
  GladeWidget *gbox = glade_widget_get_from_gobject (box);

  glade_widget_property_set (gbox, "use-center-child",
                             gtk_box_get_center_widget (GTK_BOX (box)) != NULL);
}

void
glade_gtk_box_post_create (GladeWidgetAdaptor *adaptor,
                           GObject            *container,
                           GladeCreateReason   reason)
{
  GladeWidget *gwidget = glade_widget_get_from_gobject (container);
  GladeProject *project = glade_widget_get_project (gwidget);

  /* Implement drag in GtkBox but not resize.
   */
  g_object_set (gwidget, "can-resize", FALSE, NULL);

  g_signal_connect (G_OBJECT (gwidget), "configure-child",
                    G_CALLBACK (glade_gtk_box_configure_child), container);

  g_signal_connect (G_OBJECT (gwidget), "configure-begin",
                    G_CALLBACK (glade_gtk_box_configure_begin), container);

  g_signal_connect (G_OBJECT (gwidget), "configure-end",
                    G_CALLBACK (glade_gtk_box_configure_end), container);

  if (project && glade_project_is_loading (project))
    {
      g_signal_connect_object (project, "parse-finished",
                               G_CALLBACK (glade_gtk_box_parse_finished),
                               container, 0);
    }
}

static gint
sort_box_children (GtkWidget *widget_a, GtkWidget *widget_b, GtkWidget *box)
{
  GladeWidget *gwidget_a, *gwidget_b;
  gint position_a, position_b;
  GtkWidget *center;

  /* Indirect children might be internal children, sort internal children before any other children */
  if (box != gtk_widget_get_parent (widget_a))
    return -1;
  if (box != gtk_widget_get_parent (widget_b))
    return 1;

  center = gtk_box_get_center_widget (GTK_BOX (box));
  if (center == widget_a)
    return -1;
  if (center == widget_b)
    return 1;

  if ((gwidget_a = glade_widget_get_from_gobject (widget_a)) &&
      (gwidget_b = glade_widget_get_from_gobject (widget_b)))
    {
      glade_widget_pack_property_get (gwidget_a, "position", &position_a);
      glade_widget_pack_property_get (gwidget_b, "position", &position_b);

      /* If position is the same, try to give an stable order */
      if (position_a == position_b)
        return g_strcmp0 (glade_widget_get_name (gwidget_a),
                          glade_widget_get_name (gwidget_b));
    }
  else
    {
      gtk_container_child_get (GTK_CONTAINER (box),
                               widget_a, "position", &position_a, NULL);
      gtk_container_child_get (GTK_CONTAINER (box),
                               widget_b, "position", &position_b, NULL);
    }

  return position_a - position_b;
}

GList *
glade_gtk_box_get_children (GladeWidgetAdaptor *adaptor, GObject *container)
{
  GList *children;

  children = GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->get_children (adaptor, container);

  return g_list_sort_with_data (children, (GCompareDataFunc) sort_box_children, container);
}

void
glade_gtk_box_set_child_property (GladeWidgetAdaptor *adaptor,
                                  GObject            *container,
                                  GObject            *child,
                                  const gchar        *property_name,
                                  GValue             *value)
{
  GladeWidget *gbox, *gchild, *gchild_iter;
  GList *children, *list;
  gboolean is_position;
  gint old_position, iter_position, new_position;
  static gboolean recursion = FALSE;

  g_return_if_fail (GTK_IS_BOX (container));
  g_return_if_fail (GTK_IS_WIDGET (child));
  g_return_if_fail (property_name != NULL || value != NULL);

  gbox = glade_widget_get_from_gobject (container);
  gchild = glade_widget_get_from_gobject (child);

  g_return_if_fail (GLADE_IS_WIDGET (gbox));

  if (gtk_widget_get_parent (GTK_WIDGET (child)) != GTK_WIDGET (container))
    return;

  /* Get old position */
  if ((is_position = (strcmp (property_name, "position") == 0)) != FALSE)
    {
      gtk_container_child_get (GTK_CONTAINER (container),
                               GTK_WIDGET (child),
                               property_name, &old_position, NULL);


      /* Get the real value */
      new_position = g_value_get_int (value);
    }

  if (is_position && recursion == FALSE)
    {
      children = glade_widget_get_children (gbox);
      children = g_list_sort (children, (GCompareFunc) sort_box_children);

      for (list = children; list; list = list->next)
        {
          gchild_iter = glade_widget_get_from_gobject (list->data);

          if (gchild_iter == gchild)
            {
              gtk_box_reorder_child (GTK_BOX (container),
                                     GTK_WIDGET (child), new_position);
              continue;
            }

          /* Get the old value from glade */
          glade_widget_pack_property_get
              (gchild_iter, "position", &iter_position);

          /* Search for the child at the old position and update it */
          if (iter_position == new_position &&
              glade_property_superuser () == FALSE)
            {
              /* Update glade with the real value */
              recursion = TRUE;
              glade_widget_pack_property_set
                  (gchild_iter, "position", old_position);
              recursion = FALSE;
              continue;
            }
          else
            {
              gtk_box_reorder_child (GTK_BOX (container),
                                     GTK_WIDGET (list->data), iter_position);
            }
        }

      for (list = children; list; list = list->next)
        {
          gchild_iter = glade_widget_get_from_gobject (list->data);

          /* Refresh values yet again */
          glade_widget_pack_property_get
              (gchild_iter, "position", &iter_position);

          gtk_box_reorder_child (GTK_BOX (container),
                                 GTK_WIDGET (list->data), iter_position);

        }

      if (children)
        g_list_free (children);
    }

  /* Chain Up */
  if (!is_position)
    GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS
        (GTK_TYPE_CONTAINER)->child_set_property (adaptor,
                                                  container,
                                                  child, property_name, value);

  gtk_container_check_resize (GTK_CONTAINER (container));

}

static gint
glade_gtk_box_get_num_children (GObject *box)
{
  GList *children = gtk_container_get_children (GTK_CONTAINER (box));
  gint retval = g_list_length (children);
  if (gtk_box_get_center_widget (GTK_BOX (box)) != NULL)
    retval -= 1;
  g_list_free (children);
  return retval;
}

void
glade_gtk_box_get_property (GladeWidgetAdaptor *adaptor,
                            GObject            *object,
                            const gchar        *id,
                            GValue             *value)
{
  if (!strcmp (id, "use-center-child"))
    {
      g_value_reset (value);
      g_value_set_boolean (value, gtk_box_get_center_widget (GTK_BOX (object)) != NULL);
    }
  else if (!strcmp (id, "size"))
    {
      g_value_reset (value);
      g_value_set_int (value, glade_gtk_box_get_num_children (object));
    }
  else
    GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->get_property (adaptor, object, id,
                                                      value);
}

static gint
glade_gtk_box_get_first_blank (GtkBox *box)
{
  GList *child, *children;
  GladeWidget *gwidget;
  gint position;

  children = gtk_container_get_children (GTK_CONTAINER (box));

  for (child = children, position = 0;
       child && child->data; child = child->next, position++)
    {
      GtkWidget *widget = child->data;

      if (widget == gtk_box_get_center_widget (GTK_BOX (box)))
        continue;

      if ((gwidget = glade_widget_get_from_gobject (widget)) != NULL)
        {
          gint gwidget_position = 0;
          GladeProperty *property =
              glade_widget_get_pack_property (gwidget, "position");

          /* property can be NULL here when project is closing */
          if (property)
            gwidget_position = g_value_get_int (glade_property_inline_value (property));

          if (gwidget_position > position)
            break;
        }
    }

  g_list_free (children);

  return position;
}

static void
glade_gtk_box_set_size (GObject *object, const GValue *value)
{
  GtkBox *box;
  GList *child, *children;
  guint new_size, old_size, i;

  box = GTK_BOX (object);
  g_return_if_fail (GTK_IS_BOX (box));

  if (glade_util_object_is_loading (object))
    return;

  children = gtk_container_get_children (GTK_CONTAINER (box));
  children = g_list_remove (children, gtk_box_get_center_widget (GTK_BOX (box)));

  old_size = g_list_length (children);
  new_size = g_value_get_int (value);

  if (old_size == new_size)
    {
      g_list_free (children);
      return;
    }

  /* Ensure placeholders first...
   */
  for (i = 0; i < new_size; i++)
    {
      if (g_list_length (children) < (i + 1))
        {
          GtkWidget *placeholder = glade_placeholder_new ();
          gint blank = glade_gtk_box_get_first_blank (box);

          gtk_container_add (GTK_CONTAINER (box), placeholder);
          gtk_box_reorder_child (box, placeholder, blank);
        }
    }

  /* The box has shrunk. Remove the widgets that are on those slots */
  for (child = g_list_last (children);
       child && old_size > new_size; child = g_list_previous (child))
    {
      GtkWidget *child_widget = child->data;

      /* Refuse to remove any widgets that are either GladeWidget objects
       * or internal to the hierarchic entity (may be a composite widget,
       * not all internal widgets have GladeWidgets).
       */
      if (glade_widget_get_from_gobject (child_widget) ||
          GLADE_IS_PLACEHOLDER (child_widget) == FALSE)
        continue;

      gtk_container_remove (GTK_CONTAINER (box), child_widget);
      old_size--;
    }
  g_list_free (children);

}

void
glade_gtk_box_set_property (GladeWidgetAdaptor *adaptor,
                            GObject            *object,
                            const gchar        *id,
                            const GValue       *value)
{
  if (!strcmp (id, "use-center-child"))
    {
      GtkWidget *child;

      if (g_value_get_boolean (value))
        {
          child = gtk_box_get_center_widget (GTK_BOX (object));
          if (!child)
            child = glade_placeholder_new ();
          g_object_set_data (G_OBJECT (child), "special-child-type", "center");
        }
      else
        child = NULL;
      gtk_box_set_center_widget (GTK_BOX (object), child);
    }

  else if (!strcmp (id, "size"))
    glade_gtk_box_set_size (object, value);
  else
    GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object, id,
                                                      value);
}

static gboolean
glade_gtk_box_verify_size (GObject *object, const GValue *value)
{
  GList *child, *children;
  gint old_size, count = 0;
  gint new_size = g_value_get_int (value);
  
  children = gtk_container_get_children (GTK_CONTAINER (object));
  children = g_list_remove (children, gtk_box_get_center_widget (GTK_BOX (object)));
  old_size = g_list_length (children);

  for (child = g_list_last (children);
       child && old_size > new_size;
       child = g_list_previous (child))
    {
      GtkWidget *widget = child->data;
      if (glade_widget_get_from_gobject (widget) != NULL)
        count++;
      else
        old_size--;
    }

  g_list_free (children);

  return count > new_size ? FALSE : new_size >= 0;
}


gboolean
glade_gtk_box_verify_property (GladeWidgetAdaptor *adaptor,
                               GObject            *object,
                               const gchar        *id,
                               const GValue       *value)
{
  if (!strcmp (id, "size"))
    return glade_gtk_box_verify_size (object, value);
  else if (GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->verify_property)
    return GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
                                                                id, value);

  return TRUE;
}


static void
fix_response_id_on_child (GladeWidget *gbox, GObject *child, gboolean add)
{
  GladeWidget *gchild;
  const gchar *internal_name;

  gchild = glade_widget_get_from_gobject (child);

  /* Fix response id property on child buttons */
  if (gchild && GTK_IS_BUTTON (child))
    {
      if (add && (internal_name = glade_widget_get_internal (gbox)) &&
          !strcmp (internal_name, "action_area"))
        glade_widget_property_set_sensitive (gchild, "response-id", TRUE,
                                             NULL);
      else
        glade_widget_property_set_sensitive (gchild, "response-id", FALSE,
                                             RESPID_INSENSITIVE_MSG);
    }
}

void
glade_gtk_box_add_child (GladeWidgetAdaptor *adaptor,
                         GObject            *object,
                         GObject            *child)
{
  GladeWidget *gbox, *gchild;
  gint num_children;
  gchar *special_child_type;

  g_return_if_fail (GTK_IS_BOX (object));
  g_return_if_fail (GTK_IS_WIDGET (child));

  gbox = glade_widget_get_from_gobject (object);

  special_child_type = g_object_get_data (child, "special-child-type");
  if (special_child_type && !strcmp (special_child_type, "center"))
    {
      gtk_box_set_center_widget (GTK_BOX (object), GTK_WIDGET (child));
       return;
    }

  /*
     Try to remove the last placeholder if any, this way GtkBox`s size 
     will not be changed.
   */
  if (glade_widget_superuser () == FALSE && !GLADE_IS_PLACEHOLDER (child))
    {
      GList *l, *children;
      GtkBox *box = GTK_BOX (object);

      children = gtk_container_get_children (GTK_CONTAINER (box));

      for (l = g_list_last (children); l; l = g_list_previous (l))
        {
          GtkWidget *child_widget = l->data;
          if (GLADE_IS_PLACEHOLDER (child_widget))
            {
              gtk_container_remove (GTK_CONTAINER (box), child_widget);
              break;
            }
        }
      g_list_free (children);
    }

  gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
  num_children = glade_gtk_box_get_num_children (object);
  glade_widget_property_set (gbox, "size", num_children);

  gchild = glade_widget_get_from_gobject (child);

  /* The "Remove Slot" operation only makes sense on placeholders,
   * otherwise its a "Delete" operation on the child widget.
   */
  if (gchild)
    glade_widget_set_pack_action_visible (gchild, "remove_slot", FALSE);

  fix_response_id_on_child (gbox, child, TRUE);
  
  if (glade_widget_superuser ())
    return;
  
  /* Packing props arent around when parenting during a glade_widget_dup() */
  if (gchild && glade_widget_get_packing_properties (gchild))
    glade_widget_pack_property_set (gchild, "position", num_children - 1);
}

void
glade_gtk_box_remove_child (GladeWidgetAdaptor *adaptor,
                            GObject            *object,
                            GObject            *child)
{
  GladeWidget *gbox;
  gint size;
  gchar *special_child_type;

  g_return_if_fail (GTK_IS_BOX (object));
  g_return_if_fail (GTK_IS_WIDGET (child));

  gbox = glade_widget_get_from_gobject (object);

  special_child_type = g_object_get_data (child, "special-child-type");
  if (special_child_type && !strcmp (special_child_type, "center"))
    {
      GtkWidget *w;

      w = glade_placeholder_new ();
      g_object_set_data (G_OBJECT (w), "special-child-type", "center");
      gtk_box_set_center_widget (GTK_BOX (object), w);
      return;
    }

  gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));

  if (glade_widget_superuser () == FALSE)
    {
      glade_widget_property_get (gbox, "size", &size);
      glade_widget_property_set (gbox, "size", size);
    }

  fix_response_id_on_child (gbox, child, FALSE);
}


void
glade_gtk_box_replace_child (GladeWidgetAdaptor *adaptor,
                             GObject            *container,
                             GObject            *current,
                             GObject            *new_widget)
{
  GladeWidget *gchild;
  GladeWidget *gbox;

  gchar *special_child_type;

  special_child_type =
      g_object_get_data (G_OBJECT (current), "special-child-type");

  if (special_child_type && !strcmp (special_child_type, "center"))
    {
      g_object_set_data (G_OBJECT (new_widget), "special-child-type", "center");
      gtk_box_set_center_widget (GTK_BOX (container), GTK_WIDGET (new_widget));
      return;
    }

  g_object_ref (G_OBJECT (current));

  GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->replace_child (adaptor,
                                                     container,
                                                     current, new_widget);
  gbox = glade_widget_get_from_gobject (container);

  if ((gchild = glade_widget_get_from_gobject (new_widget)) != NULL)
    /* The "Remove Slot" operation only makes sense on placeholders,
     * otherwise its a "Delete" operation on the child widget.
     */
    glade_widget_set_pack_action_visible (gchild, "remove_slot", FALSE);

  fix_response_id_on_child (gbox, current, FALSE);
  fix_response_id_on_child (gbox, new_widget, TRUE);

  g_object_unref (G_OBJECT (current));
}

void
glade_gtk_box_child_action_activate (GladeWidgetAdaptor *adaptor,
                                     GObject            *container,
                                     GObject            *object,
                                     const gchar        *action_path)
{
  if (strcmp (action_path, "insert_after") == 0)
    {
      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
                                                         object, FALSE, TRUE);
    }
  else if (strcmp (action_path, "insert_before") == 0)
    {
      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
                                                         object, FALSE, FALSE);
    }
  else if (strcmp (action_path, "remove_slot") == 0)
    {
      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
                                                         object, TRUE, FALSE);
    }
  else
    GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
                                                               container,
                                                               object,
                                                               action_path);
}


/**********************************************************
 *             GladeFixed drag implementation             *
 **********************************************************/
typedef struct
{
  GtkWidget *widget;
  gint position;
} GladeGtkBoxChild;

static GList *glade_gtk_box_original_positions = NULL;

static gboolean
glade_gtk_box_configure_child (GladeFixed   *fixed,
                               GladeWidget  *child,
                               GdkRectangle *rect,
                               GtkWidget    *box)
{
  GList *list, *children;
  GtkWidget *bchild;
  GtkAllocation allocation, bchild_allocation;
  gint point, trans_point, span,
      iter_span, position, old_position, offset, orig_offset;
  gboolean found = FALSE;

  gtk_widget_get_allocation (GTK_WIDGET (glade_widget_get_object (child)), &allocation);

  if (gtk_orientable_get_orientation (GTK_ORIENTABLE (box)) == GTK_ORIENTATION_HORIZONTAL)
    {
      point = fixed->mouse_x;
      span = allocation.width;
      offset = rect->x;
      orig_offset = fixed->child_x_origin;
    }
  else
    {
      point = fixed->mouse_y;
      span = allocation.height;
      offset = rect->y;
      orig_offset = fixed->child_y_origin;
    }

  glade_widget_pack_property_get (child, "position", &old_position);

  children = gtk_container_get_children (GTK_CONTAINER (box));

  for (list = children; list; list = list->next)
    {
      bchild = list->data;

      if (bchild == GTK_WIDGET (glade_widget_get_object (child)))
        continue;

      /* Find the widget in the box where the center of
       * this rectangle fits... and set the position to that
       * position.
       */

      gtk_widget_get_allocation (GTK_WIDGET (bchild), &bchild_allocation);
      if (gtk_orientable_get_orientation (GTK_ORIENTABLE (box)) == GTK_ORIENTATION_HORIZONTAL)
        {
          gtk_widget_translate_coordinates
              (GTK_WIDGET (box), bchild, point, 0, &trans_point, NULL);

          iter_span = bchild_allocation.width;
        }
      else
        {
          gtk_widget_translate_coordinates
              (GTK_WIDGET (box), bchild, 0, point, NULL, &trans_point);
          iter_span = bchild_allocation.height;
        }

#if 0
      gtk_container_child_get (GTK_CONTAINER (box),
                               bchild, "position", &position, NULL);
      g_print ("widget: %p pos %d, point %d, trans_point %d, iter_span %d\n",
               bchild, position, point, trans_point, iter_span);
#endif

      if (iter_span <= span)
        {
          found = trans_point >= 0 && trans_point < iter_span;
        }
      else
        {
          if (offset > orig_offset)
            found = trans_point >= iter_span - span && trans_point < iter_span;
          else if (offset < orig_offset)
            found = trans_point >= 0 && trans_point < span;
        }

      if (found)
        {
          gtk_container_child_get (GTK_CONTAINER (box),
                                   bchild, "position", &position, NULL);

#if 0
          g_print ("setting position of %s from %d to %d, "
                   "(point %d iter_span %d)\n",
                   glade_widget_get_name (child), old_position, position, trans_point, iter_span);
#endif

          glade_widget_pack_property_set (child, "position", position);

          break;
        }

    }

  g_list_free (children);

  return TRUE;
}

static gboolean
glade_gtk_box_configure_begin (GladeFixed  *fixed,
                               GladeWidget *child,
                               GtkWidget   *box)
{
  GList *list, *children;
  GtkWidget *bchild;

  g_assert (glade_gtk_box_original_positions == NULL);

  children = gtk_container_get_children (GTK_CONTAINER (box));

  for (list = children; list; list = list->next)
    {
      GladeGtkBoxChild *gbchild;
      GladeWidget *gchild;

      bchild = list->data;
      if ((gchild = glade_widget_get_from_gobject (bchild)) == NULL)
        continue;

      gbchild = g_new0 (GladeGtkBoxChild, 1);
      gbchild->widget = bchild;
      glade_widget_pack_property_get (gchild, "position", &gbchild->position);

      glade_gtk_box_original_positions =
          g_list_prepend (glade_gtk_box_original_positions, gbchild);
    }

  g_list_free (children);

  return TRUE;
}

static gboolean
glade_gtk_box_configure_end (GladeFixed * fixed,
                             GladeWidget * child, GtkWidget * box)
{
  GList *list, *l, *children;
  GList *prop_list = NULL;

  children = gtk_container_get_children (GTK_CONTAINER (box));

  for (list = children; list; list = list->next)
    {
      GtkWidget *bchild = list->data;

      for (l = glade_gtk_box_original_positions; l; l = l->next)
        {
          GladeGtkBoxChild *gbchild = l->data;
          GladeWidget *gchild = glade_widget_get_from_gobject (gbchild->widget);


          if (bchild == gbchild->widget)
            {
              GladeCommandSetPropData *prop_data = g_new0 (GladeCommandSetPropData, 1);
              prop_data->property =
                  glade_widget_get_pack_property (gchild, "position");

              prop_data->old_value = g_new0 (GValue, 1);
              prop_data->new_value = g_new0 (GValue, 1);

              glade_property_get_value (prop_data->property,
                                        prop_data->new_value);

              g_value_init (prop_data->old_value, G_TYPE_INT);
              g_value_set_int (prop_data->old_value, gbchild->position);

              prop_list = g_list_prepend (prop_list, prop_data);
              break;
            }
        }
    }

  g_list_free (children);

  glade_command_push_group (_("Ordering children of %s"),
                            glade_widget_get_name (GLADE_WIDGET (fixed)));
  glade_property_push_superuser ();
  if (prop_list)
    glade_command_set_properties_list (glade_widget_get_project (GLADE_WIDGET (fixed)),
                                       prop_list);
  glade_property_pop_superuser ();
  glade_command_pop_group ();

  for (l = glade_gtk_box_original_positions; l; l = l->next)
    g_free (l->data);

  glade_gtk_box_original_positions =
      (g_list_free (glade_gtk_box_original_positions), NULL);


  return TRUE;
}
