/*
 * glade-gtk-container.c - GladeWidgetAdaptor for GtkContainer
 *
 * Copyright (C) 2013 Tristan Van Berkom
 *
 * Authors:
 *      Tristan Van Berkom <tristan.van.berkom@gmail.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 <glib/gi18n-lib.h>
#include <gladeui/glade.h>
#include <string.h>

void
glade_gtk_container_post_create (GladeWidgetAdaptor *adaptor,
                                 GObject            *container,
                                 GladeCreateReason   reason)
{
  GList *children;
  g_return_if_fail (GTK_IS_CONTAINER (container));

  if (reason == GLADE_CREATE_USER)
    {
      if ((children =
           gtk_container_get_children (GTK_CONTAINER (container))) == NULL)
        gtk_container_add (GTK_CONTAINER (container), glade_placeholder_new ());
      else
        g_list_free (children);
    }
}

gboolean
glade_gtk_container_add_verify (GladeWidgetAdaptor *adaptor,
                                GtkWidget          *container,
                                GtkWidget          *child,
                                gboolean            user_feedback)
{
  GladeWidget *gwidget = glade_widget_get_from_gobject (container);

  if (GTK_IS_WINDOW (child))
    {
      if (user_feedback)
        glade_util_ui_message (glade_app_get_window (),
                               GLADE_UI_INFO, NULL,
                               _("Cannot add a toplevel window to a container."));

      return FALSE;
    }
  else if (GTK_IS_POPOVER (child))
    {
      if (user_feedback)
        glade_util_ui_message (glade_app_get_window (),
                               GLADE_UI_INFO, NULL,
                               _("Cannot add a popover to a container."));

      return FALSE;
    }
  else if (!GTK_IS_WIDGET (child) ||
           GTK_IS_TOOL_ITEM (child) ||
           GTK_IS_MENU_ITEM (child))
    {
      if (user_feedback)
        glade_util_ui_message (glade_app_get_window (),
                               GLADE_UI_INFO, NULL,
                               _("Widgets of type %s can only have widgets as children."),
                               glade_widget_adaptor_get_title (adaptor));

      return FALSE;
    }
  else if (GTK_IS_BOX (container) || GTK_IS_GRID (container))
    /* GtkBox and GtkGrid size is adjusted automaticaly in GladeCommand */
    return TRUE;
  else if (GLADE_WIDGET_ADAPTOR_USE_PLACEHOLDERS (adaptor) &&
           (glade_util_count_placeholders (gwidget) == 0))
    {
      if (user_feedback)
        glade_util_ui_message (glade_app_get_window (),
                               GLADE_UI_INFO, NULL,
                               _("Widgets of type %s need placeholders to add children.\n"
                                 "Increase its size or add a container if it only supports one child."),
                               glade_widget_adaptor_get_title (adaptor));

      return FALSE;
    }

  return TRUE;
}

void
glade_gtk_container_replace_child (GladeWidgetAdaptor *adaptor,
                                   GtkWidget          *container,
                                   GtkWidget          *current,
                                   GtkWidget          *new_widget)
{
  GParamSpec **param_spec;
  GladePropertyDef *pdef;
  GValue *value;
  guint nproperties;
  guint i;

  g_return_if_fail (gtk_widget_get_parent (current) == container);

  param_spec = gtk_container_class_list_child_properties
      (G_OBJECT_GET_CLASS (container), &nproperties);
  value = g_malloc0 (sizeof (GValue) * nproperties);

  for (i = 0; i < nproperties; i++)
    {
      g_value_init (&value[i], param_spec[i]->value_type);
      gtk_container_child_get_property
          (GTK_CONTAINER (container), current, param_spec[i]->name, &value[i]);
    }

  gtk_container_remove (GTK_CONTAINER (container), current);
  gtk_container_add (GTK_CONTAINER (container), new_widget);

  for (i = 0; i < nproperties; i++)
    {
      /* If the added widget is a placeholder then we
       * want to keep all the "transfer-on-paste" properties
       * as default so that it looks fresh (transfer-on-paste
       * properties don't effect the position/slot inside a 
       * container)
       */
      if (GLADE_IS_PLACEHOLDER (new_widget))
        {
          pdef = glade_widget_adaptor_get_pack_property_def
              (adaptor, param_spec[i]->name);

          if (pdef && glade_property_def_transfer_on_paste (pdef))
            continue;
        }

      gtk_container_child_set_property
          (GTK_CONTAINER (container), new_widget, param_spec[i]->name,
           &value[i]);
    }

  for (i = 0; i < nproperties; i++)
    g_value_unset (&value[i]);

  g_free (param_spec);
  g_free (value);
}

void
glade_gtk_container_add_child (GladeWidgetAdaptor *adaptor,
                               GtkWidget          *container,
                               GtkWidget          *child)
{
  GtkWidget *container_child = NULL;

  if (GTK_IS_BIN (container))
    container_child = gtk_bin_get_child (GTK_BIN (container));

  /* Get a placeholder out of the way before adding the child if its a GtkBin
   */
  if (GTK_IS_BIN (container) && container_child != NULL &&
      GLADE_IS_PLACEHOLDER (container_child))
    gtk_container_remove (GTK_CONTAINER (container), container_child);

  gtk_container_add (GTK_CONTAINER (container), child);
}

void
glade_gtk_container_remove_child (GladeWidgetAdaptor *adaptor,
                                  GtkWidget          *container,
                                  GtkWidget          *child)
{
  GList *children;
  gtk_container_remove (GTK_CONTAINER (container), child);

  /* If this is the last one, add a placeholder by default.
   */
  if ((children =
       gtk_container_get_children (GTK_CONTAINER (container))) == NULL)
    {
      gtk_container_add (GTK_CONTAINER (container), glade_placeholder_new ());
    }
  else
    g_list_free (children);
}

void
glade_gtk_container_set_child_property (GladeWidgetAdaptor *adaptor,
                                        GObject            *container,
                                        GObject            *child,
                                        const gchar        *property_name,
                                        const GValue       *value)
{
  if (gtk_widget_get_parent (GTK_WIDGET (child)) == GTK_WIDGET (container))
    gtk_container_child_set_property (GTK_CONTAINER (container),
                                      GTK_WIDGET (child), property_name, value);
}

void
glade_gtk_container_get_child_property (GladeWidgetAdaptor *adaptor,
                                        GObject            *container,
                                        GObject            *child,
                                        const gchar        *property_name,
                                        GValue             *value)
{
  if (gtk_widget_get_parent (GTK_WIDGET (child)) == GTK_WIDGET (container))
    gtk_container_child_get_property (GTK_CONTAINER (container),
                                      GTK_WIDGET (child), property_name, value);
}

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

  children = glade_util_container_get_all_children (GTK_CONTAINER (container));
  
  /* Chain up */
  if (GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_WIDGET)->get_children)
    parent_children = GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_WIDGET)->get_children (adaptor, container);
  else
    parent_children = NULL;
  
  return glade_util_purify_list (g_list_concat (children, parent_children));
}

/* This is used in the XML for some derived classes */
GladeEditable *
glade_gtk_container_create_editable (GladeWidgetAdaptor *adaptor,
                                     GladeEditorPageType type)
{
  return GLADE_WIDGET_ADAPTOR_GET_ADAPTOR_CLASS (GTK_TYPE_CONTAINER)->create_editable (adaptor, type);
}
