<commit_before>/*
 * nbtk-list-view.c: NbtkBoxLayout powered by a model
 *
 * Copyright 2008, 2009 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
 * Boston, MA 02111-1307, USA.
 *
 * Written by: <NAME> <<EMAIL>>
 *
 */


#include "nbtk-list-view.h"
#include "nbtk-box-layout.h"
#include "nbtk-private.h"
#include "nbtk-item-factory.h"

G_DEFINE_TYPE (NbtkListView, nbtk_list_view, NBTK_TYPE_BOX_LAYOUT)

#define LIST_VIEW_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), NBTK_TYPE_LIST_VIEW, NbtkListViewPrivate))

typedef struct
{
  gchar *name;
  gint   col;
} AttributeData;

enum
{
  PROP_0,

  PROP_MODEL,
  PROP_ITEM_TYPE
};

struct _NbtkListViewPrivate
{
  ClutterModel *model;
  GSList       *attributes;
  GType         item_type;

  NbtkItemFactory *factory;

  gulong filter_changed;
  gulong row_added;
  gulong row_changed;
  gulong row_removed;
  gulong sort_changed;
};

/* gobject implementations */

static void
nbtk_list_view_get_property (GObject    *object,
                             guint       property_id,
                             GValue     *value,
                             GParamSpec *pspec)
{
  NbtkListViewPrivate *priv = NBTK_LIST_VIEW (object)->priv;
  switch (property_id)
    {
    case PROP_MODEL:
      g_value_set_object (value, priv->model);
      break;
    case PROP_ITEM_TYPE:
      g_value_set_gtype (value, priv->item_type);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}

static void
nbtk_list_view_set_property (GObject      *object,
                             guint         property_id,
                             const GValue *value,
                             GParamSpec   *pspec)
{
  switch (property_id)
    {
    case PROP_MODEL:
      nbtk_list_view_set_model ((NbtkListView*) object,
                                (ClutterModel*) g_value_get_object (value));
    case PROP_ITEM_TYPE:
      nbtk_list_view_set_item_type ((NbtkListView*) object,
                                    g_value_get_gtype (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}

static void
nbtk_list_view_dispose (GObject *object)
{
  NbtkListViewPrivate *priv = NBTK_LIST_VIEW (object)->priv;

  G_OBJECT_CLASS (nbtk_list_view_parent_class)->dispose (object);

  /* This will cause the unref of the model and also disconnect the signals */
  nbtk_list_view_set_model (NBTK_LIST_VIEW (object), NULL);

  if (priv->factory)
    {
      g_object_unref (priv->factory);
      priv->factory = NULL;
    }
}

static void
nbtk_list_view_finalize (GObject *object)
{
  NbtkListViewPrivate *priv = NBTK_LIST_VIEW (object)->priv;

  G_OBJECT_CLASS (nbtk_list_view_parent_class)->finalize (object);


  if (priv->attributes)
    {
      g_slist_foreach (priv->attributes, (GFunc) g_free, NULL);
      g_slist_free (priv->attributes);
      priv->attributes = NULL;
    }
}

static void
nbtk_list_view_class_init (NbtkListViewClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GParamSpec *pspec;

  g_type_class_add_private (klass, sizeof (NbtkListViewPrivate));

  object_class->get_property = nbtk_list_view_get_property;
  object_class->set_property = nbtk_list_view_set_property;
  object_class->dispose = nbtk_list_view_dispose;
  object_class->finalize = nbtk_list_view_finalize;

  pspec = g_param_spec_object ("model",
                               "model",
                               "The model for the item view",
                               CLUTTER_TYPE_MODEL,
                               NBTK_PARAM_READWRITE);
  g_object_class_install_property (object_class, PROP_MODEL, pspec);

  pspec = g_param_spec_gtype ("item-type",
                              "Item Type",
                              "The GType to use as the items in the view. "
                              "Must be a subclass of ClutterActor",
                              CLUTTER_TYPE_ACTOR,
                              NBTK_PARAM_READWRITE);
  g_object_class_install_property (object_class, PROP_ITEM_TYPE, pspec);
}

static void
nbtk_list_view_init (NbtkListView *list_view)
{
  list_view->priv = LIST_VIEW_PRIVATE (list_view);

  g_object_set (list_view, "vertical", TRUE, NULL);
}


/* model monitors */
static void
model_changed_cb (ClutterModel *model,
                  NbtkListView *list_view)
{
  GSList *p;
  GList *l, *children;
  NbtkListViewPrivate *priv = list_view->priv;
  ClutterModelIter *iter = NULL;
  gint model_n = 0, child_n = 0;


  /* bail out if we don't yet have an item type or a factory */
  if (!priv->item_type && !priv->factory)
    return;

  if (priv->item_type)
    {
      /* check the item-type is an descendant of ClutterActor */
      if (!g_type_is_a (priv->item_type, CLUTTER_TYPE_ACTOR))
        {
          g_warning ("%s is not a subclass of ClutterActor and therefore"
                     " cannot be used as items in an NbtkListView",
                     g_type_name (priv->item_type));
          return;
        }
    }

  children = clutter_container_get_children (CLUTTER_CONTAINER (list_view));
  child_n = g_list_length (children);

  /* set the properties on the objects */
  if (priv->model)
    iter = clutter_model_get_first_iter (priv->model);

  model_n = 0;

  /* We count the number of rows in the model ourselves, as
   * clutter_list_model_get_n_rows() does not currently take into account the
   * filtered model. See Clutter bug 1562.
   */
  while (iter && !clutter_model_iter_is_last (iter))
    {
      GObject *child;

      model_n++;

      if (child_n < model_n)
        {
          ClutterActor *new_child;

          if (priv->item_type)
            {
              new_child = g_object_new (priv->item_type, NULL);
            }
          else
            {
              new_child = nbtk_item_factory_create (priv->factory);
            }

          clutter_container_add_actor (CLUTTER_CONTAINER (list_view),
                                       new_child);
          child = G_OBJECT (new_child);
          /* we've changed the number of children, so update the children list
           */
          g_list_free (children);
          children
            = clutter_container_get_children (CLUTTER_CONTAINER (list_view));
          child_n = g_list_length (children);

        }
      else
        {
          l = g_list_nth (children, model_n - 1);
          child = G_OBJECT (l->data);
        }

      g_object_freeze_notify (child);
      for (p = priv->attributes; p; p = p->next)
        {
          GValue value = { 0, };
          AttributeData *attr = p->data;

          clutter_model_iter_get_value (iter, attr->col, &value);

          g_object_set_property (child, attr->name, &value);
        }
      g_object_thaw_notify (child);

      clutter_model_iter_next (iter);
    }

  g_list_free (children);
  children = clutter_container_get_children (CLUTTER_CONTAINER (list_view));
  child_n = g_list_length (children);

  /* if the model shrank, we need to remove some items */
  while (child_n > model_n)
    {
      ClutterActor *child;

      /*
       * Here we remove surplus children from the end of the list as we have
       * already set properties on children at the beginning of the list.
       */
      l = g_list_last (children);
      child = CLUTTER_ACTOR (l->data);

      /* remove some children */
      clutter_container_remove_actor (CLUTTER_CONTAINER (list_view),
                                      child);
      g_list_free (children);
      children = clutter_container_get_children (CLUTTER_CONTAINER (list_view));
      child_n = g_list_length (children);
    }

  g_list_free (children);

  if (iter)
    g_object_unref (iter);
}

static void
row_changed_cb (ClutterModel     *model,
                ClutterModelIter *iter,
                NbtkListView     *list_view)
{
  model_changed_cb (model, list_view);
}

static void
row_removed_cb (ClutterModel     *model,
                ClutterModelIter *iter,
                NbtkListView     *list_view)
{
  GList *children;<commit_msg>[NbtkListView] optimise the model changed callback<commit_after>/*
 * nbtk-list-view.c: NbtkBoxLayout powered by a model
 *
 * Copyright 2008, 2009 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
 * Boston, MA 02111-1307, USA.
 *
 * Written by: <NAME> <<EMAIL>>
 *
 */


#include "nbtk-list-view.h"
#include "nbtk-box-layout.h"
#include "nbtk-private.h"
#include "nbtk-item-factory.h"

G_DEFINE_TYPE (NbtkListView, nbtk_list_view, NBTK_TYPE_BOX_LAYOUT)

#define LIST_VIEW_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), NBTK_TYPE_LIST_VIEW, NbtkListViewPrivate))

typedef struct
{
  gchar *name;
  gint   col;
} AttributeData;

enum
{
  PROP_0,

  PROP_MODEL,
  PROP_ITEM_TYPE
};

struct _NbtkListViewPrivate
{
  ClutterModel *model;
  GSList       *attributes;
  GType         item_type;

  NbtkItemFactory *factory;

  gulong filter_changed;
  gulong row_added;
  gulong row_changed;
  gulong row_removed;
  gulong sort_changed;
};

/* gobject implementations */

static void
nbtk_list_view_get_property (GObject    *object,
                             guint       property_id,
                             GValue     *value,
                             GParamSpec *pspec)
{
  NbtkListViewPrivate *priv = NBTK_LIST_VIEW (object)->priv;
  switch (property_id)
    {
    case PROP_MODEL:
      g_value_set_object (value, priv->model);
      break;
    case PROP_ITEM_TYPE:
      g_value_set_gtype (value, priv->item_type);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}

static void
nbtk_list_view_set_property (GObject      *object,
                             guint         property_id,
                             const GValue *value,
                             GParamSpec   *pspec)
{
  switch (property_id)
    {
    case PROP_MODEL:
      nbtk_list_view_set_model ((NbtkListView*) object,
                                (ClutterModel*) g_value_get_object (value));
    case PROP_ITEM_TYPE:
      nbtk_list_view_set_item_type ((NbtkListView*) object,
                                    g_value_get_gtype (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
}

static void
nbtk_list_view_dispose (GObject *object)
{
  NbtkListViewPrivate *priv = NBTK_LIST_VIEW (object)->priv;

  G_OBJECT_CLASS (nbtk_list_view_parent_class)->dispose (object);

  /* This will cause the unref of the model and also disconnect the signals */
  nbtk_list_view_set_model (NBTK_LIST_VIEW (object), NULL);

  if (priv->factory)
    {
      g_object_unref (priv->factory);
      priv->factory = NULL;
    }
}

static void
nbtk_list_view_finalize (GObject *object)
{
  NbtkListViewPrivate *priv = NBTK_LIST_VIEW (object)->priv;

  G_OBJECT_CLASS (nbtk_list_view_parent_class)->finalize (object);


  if (priv->attributes)
    {
      g_slist_foreach (priv->attributes, (GFunc) g_free, NULL);
      g_slist_free (priv->attributes);
      priv->attributes = NULL;
    }
}

static void
nbtk_list_view_class_init (NbtkListViewClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GParamSpec *pspec;

  g_type_class_add_private (klass, sizeof (NbtkListViewPrivate));

  object_class->get_property = nbtk_list_view_get_property;
  object_class->set_property = nbtk_list_view_set_property;
  object_class->dispose = nbtk_list_view_dispose;
  object_class->finalize = nbtk_list_view_finalize;

  pspec = g_param_spec_object ("model",
                               "model",
                               "The model for the item view",
                               CLUTTER_TYPE_MODEL,
                               NBTK_PARAM_READWRITE);
  g_object_class_install_property (object_class, PROP_MODEL, pspec);

  pspec = g_param_spec_gtype ("item-type",
                              "Item Type",
                              "The GType to use as the items in the view. "
                              "Must be a subclass of ClutterActor",
                              CLUTTER_TYPE_ACTOR,
                              NBTK_PARAM_READWRITE);
  g_object_class_install_property (object_class, PROP_ITEM_TYPE, pspec);
}

static void
nbtk_list_view_init (NbtkListView *list_view)
{
  list_view->priv = LIST_VIEW_PRIVATE (list_view);

  g_object_set (list_view, "vertical", TRUE, NULL);
}


/* model monitors */
static void
model_changed_cb (ClutterModel *model,
                  NbtkListView *list_view)
{
  GSList *p;
  GList *l, *children;
  NbtkListViewPrivate *priv = list_view->priv;
  ClutterModelIter *iter = NULL;
  gint model_n = 0, child_n = 0;


  /* bail out if we don't yet have an item type or a factory */
  if (!priv->item_type && !priv->factory)
    return;

  if (priv->item_type)
    {
      /* check the item-type is an descendant of ClutterActor */
      if (!g_type_is_a (priv->item_type, CLUTTER_TYPE_ACTOR))
        {
          g_warning ("%s is not a subclass of ClutterActor and therefore"
                     " cannot be used as items in an NbtkListView",
                     g_type_name (priv->item_type));
          return;
        }
    }

  children = clutter_container_get_children (CLUTTER_CONTAINER (list_view));
  child_n = g_list_length (children);

  if (model)
    model_n = clutter_model_get_n_rows (priv->model);
  else
    model_n = 0;

  /* add children as needed */
  while (model_n > child_n)
    {
      ClutterActor *new_child;

      if (priv->item_type)
        {
          new_child = g_object_new (priv->item_type, NULL);
        }
      else
        {
          new_child = nbtk_item_factory_create (priv->factory);
        }

      clutter_container_add_actor (CLUTTER_CONTAINER (list_view),
                                   new_child);
      child_n++;
    }

  /* remove children as needed */
  l = g_list_last (children);
  while (child_n > model_n)
    {
      clutter_container_remove_actor (CLUTTER_CONTAINER (list_view),
                                      (ClutterActor*) l->data);
      l = g_list_previous (l);
      child_n--;
    }

  g_list_free (children);

  if (!priv->model)
    return;

  children = clutter_container_get_children (CLUTTER_CONTAINER (list_view));

  /* set the properties on the children */
  iter = clutter_model_get_first_iter (priv->model);
  l = children;
  while (iter && !clutter_model_iter_is_last (iter))
    {
      GObject *child;

      child = G_OBJECT (l->data);

      g_object_freeze_notify (child);
      for (p = priv->attributes; p; p = p->next)
        {
          GValue value = { 0, };
          AttributeData *attr = p->data;

          clutter_model_iter_get_value (iter, attr->col, &value);

          g_object_set_property (child, attr->name, &value);
        }
      g_object_thaw_notify (child);

      l = g_list_next (l);
      clutter_model_iter_next (iter);
    }

  g_list_free (children);

  if (iter)
    g_object_unref (iter);
}

static void
row_changed_cb (ClutterModel     *model,
                ClutterModelIter *iter,
                NbtkListView     *list_view)
{
  model_changed_cb (model, list_view);
}

static void
row_removed_cb (ClutterModel     *model,
                ClutterModelIter *iter,
                NbtkListView     *list_view)
{
  GList *children;
{'fraction_non_alphanumeric': 0.087278641127575, 'fraction_numerical': 0.004517528008673654, 'mean_word_length': 2.455359001040583, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5591936', 'n_tokens_mistral': 5543, 'n_tokens_neox': 5313, 'n_words': 1300}