Logo Search packages:      
Sourcecode: v-sim version File versions  Download package

dataNode.c

/*   EXTRAITS DE LA LICENCE
      Copyright CEA, contributeurs : Luc BILLARD et Damien
      CALISTE, laboratoire L_Sim, (2001-2005)
  
      Adresse mèl :
      BILLARD, non joignable par mèl ;
      CALISTE, damien P caliste AT cea P fr.

      Ce logiciel est un programme informatique servant à visualiser des
      structures atomiques dans un rendu pseudo-3D. 

      Ce logiciel est régi par la licence CeCILL soumise au droit français et
      respectant les principes de diffusion des logiciels libres. Vous pouvez
      utiliser, modifier et/ou redistribuer ce programme sous les conditions
      de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
      sur le site "http://www.cecill.info".

      Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
      pris connaissance de la licence CeCILL, et que vous en avez accepté les
      termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
      Copyright CEA, contributors : Luc BILLARD et Damien
      CALISTE, laboratoire L_Sim, (2001-2005)

      E-mail address:
      BILLARD, not reachable any more ;
      CALISTE, damien P caliste AT cea P fr.

      This software is a computer program whose purpose is to visualize atomic
      configurations in 3D.

      This software is governed by the CeCILL  license under French law and
      abiding by the rules of distribution of free software.  You can  use, 
      modify and/ or redistribute the software under the terms of the CeCILL
      license as circulated by CEA, CNRS and INRIA at the following URL
      "http://www.cecill.info". 

      The fact that you are presently reading this means that you have had
      knowledge of the CeCILL license and that you accept its terms. You can
      find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/
#include "dataNode.h"

#include <visu_tools.h>
#include <string.h>

struct internalUsedVisuData_struct
{
  /* The #VisuData using this DataNode. */
  VisuData *dataObj;
  /* Its associated dimension. */
  gint dimension;
  /* A handler on the signal emitted when the VisuData is freed. */
  gulong freeingSignal;
};

struct DataNode_struct
{
  /* Internal object gestion. */
  GObject parent;
  gboolean dispose_has_run;

  /* The key used to store the node property. */
  const gchar *id;

  /* The type of stored data. */
  GType type;

  /* The label. */
  const gchar *label;

  /* The dimension (must be set to use nodeDataSet_valueAsString()
     or nodeDataGet_valueAsString()), can vary. */
  GList *lstVisuData;

  /* Callbacks method and data associated. */
  DataNodeCallbackMethod callback;
  gpointer data;
};


enum
  {
    DATA_NODE_USED_SIGNAL,
    DATA_NODE_UNUSED_SIGNAL,
    DATA_NODE_NB_SIGNAL
  };

struct DataNodeClass_struct
{
  GObjectClass parent;
};


/* Internal variables. */
static GList *storedData = (GList*)0;
static GObjectClass *parent_class = NULL;
static guint dataNode_signals[DATA_NODE_NB_SIGNAL] = { 0 };


/* Object gestion methods. */
static void data_node_class_init(DataNodeClass *klass);
static void data_node_init      (DataNode *obj);
static void data_node_dispose   (GObject* obj);
static void data_node_finalize  (GObject* obj);

/* Local callbacks. */
static void onVisuDataFreed(VisuData *dataObj, gpointer data);


GType data_node_get_type(void)
{
  static GType data_node_type = 0;

  if (!data_node_type)
    {
      static const GTypeInfo data_node_info =
      {
        sizeof (DataNodeClass),
        NULL, /* base_init */
        NULL, /* base_finalize */
        (GClassInitFunc)data_node_class_init,
        NULL, /* class_finalize */
        NULL, /* class_data */
        sizeof (DataNode),
        0,
        (GInstanceInitFunc)data_node_init,
      NULL
      };
      data_node_type = g_type_register_static(G_TYPE_OBJECT, "DataNodeType",
                                     &data_node_info, 0);
      DBG_fprintf(stderr, "Data Node : creating the type DataNode %d.\n",
              (int)data_node_type);
    }

  return data_node_type;
}

static void data_node_class_init(DataNodeClass *klass)
{
  GType paramObj[1] = {G_TYPE_OBJECT};

  DBG_fprintf(stderr, "Data Node : creating the class of the object.\n");
  parent_class = g_type_class_peek_parent(klass);

  DBG_fprintf(stderr, "                - adding new signals ;\n");
  dataNode_signals[DATA_NODE_USED_SIGNAL] =
    g_signal_newv("propertyUsed", G_TYPE_FROM_CLASS(klass),
              G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
              NULL, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
              G_TYPE_NONE, 1, paramObj);
  dataNode_signals[DATA_NODE_UNUSED_SIGNAL] =
    g_signal_newv("propertyUnused", G_TYPE_FROM_CLASS(klass),
              G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
              NULL, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
              G_TYPE_NONE, 1, paramObj);

  /* Connect freeing methods. */
  G_OBJECT_CLASS(klass)->dispose  = data_node_dispose;
  G_OBJECT_CLASS(klass)->finalize = data_node_finalize;
}

static void data_node_init(DataNode *obj)
{
  obj->dispose_has_run = FALSE;

  obj->id = (gchar*)0;
  obj->type = (GType)0;

  obj->label = (gchar*)0;

  obj->lstVisuData = (GList*)0;

  obj->callback = (DataNodeCallbackMethod)0;
  obj->data = (gpointer)0;

  /* Add object from allObjects list. */
  storedData = g_list_prepend(storedData, (gpointer)obj);
}

/* This method can be called several times.
   It should unref all of its reference to
   GObjects. */
static void data_node_dispose(GObject* obj)
{
  DBG_fprintf(stderr, "Data Node : dispose object %p.\n", (gpointer)obj);

  if (DATA_NODE(obj)->dispose_has_run)
    return;

  DATA_NODE(obj)->dispose_has_run = TRUE;
  /* Chain up to the parent class */
  G_OBJECT_CLASS(parent_class)->dispose(obj);
}
/* This method is called once only. */
static void data_node_finalize(GObject* obj)
{
  GList *lst;

  g_return_if_fail(obj);

  DBG_fprintf(stderr, "Data Node : finalize object %p.\n", (gpointer)obj);

  lst = DATA_NODE(obj)->lstVisuData;
  while (lst)
    {
      g_free(lst->data);
      lst = g_list_next(lst);
    }
  g_list_free(DATA_NODE(obj)->lstVisuData);

  /* Remove object from allObjects list. */
  storedData = g_list_remove(storedData, (gpointer)obj);

  /* Chain up to the parent class */
  G_OBJECT_CLASS(parent_class)->finalize(obj);
}


DataNode* nodeDataNew(const gchar *name, GType type)
{
  DataNode *data;

  g_return_val_if_fail(name, (DataNode*)0);
  g_return_val_if_fail(type == G_TYPE_INT || type == G_TYPE_FLOAT ||
                   type == G_TYPE_BOOLEAN, (DataNode*)0);

  /* Create the object with defaulty values. */
  data = DATA_NODE(g_object_new(DATA_NODE_TYPE, NULL));
  g_return_val_if_fail(data, (DataNode*)0);

  /* Set specific values. */
  data->id = name;
  data->type = type;

  return data;
}

GList* nodeDataGet_list()
{
  return storedData;
}

void nodeDataSet_label(DataNode *data, const gchar *label)
{
  g_return_if_fail(IS_DATA_NODE_TYPE(data));

  data->label = label;
}
const gchar* nodeDataGet_label(DataNode *data)
{
  g_return_val_if_fail(IS_DATA_NODE_TYPE(data), (const gchar*)0);

  if (data->label)
    return data->label;
  else
    return data->id;
}

static struct internalUsedVisuData_struct *getInternalStorage(DataNode *data, VisuData *dataObj)
{
  struct internalUsedVisuData_struct *storage;
  GList *tmpLst;

  storage = (struct internalUsedVisuData_struct*)0;
  tmpLst = data->lstVisuData;
  while (!storage && tmpLst)
    {
      if (((struct internalUsedVisuData_struct*)tmpLst->data)->dataObj == dataObj)
      storage = (struct internalUsedVisuData_struct*)tmpLst->data;
      tmpLst = g_list_next(tmpLst);
    }
  return storage;
}

void nodeDataSet_used(DataNode *data, VisuData *dataObj, gint nb)
{
  struct internalUsedVisuData_struct *storage;

  g_return_if_fail(IS_DATA_NODE_TYPE(data) && IS_VISU_DATA_TYPE(dataObj));

  storage = getInternalStorage(data, dataObj);
  if (nb > 0)
    {
      /* Add a new associated #VisuData or change an already
       associated one. */
      if (!storage)
      {
        storage = g_malloc(sizeof(struct internalUsedVisuData_struct));
        storage->dataObj = dataObj;
        storage->dimension = nb;
        storage->freeingSignal =  g_signal_connect(G_OBJECT(dataObj), "objectFreed",
                                         G_CALLBACK(onVisuDataFreed),
                                         (gpointer)data);
        data->lstVisuData = g_list_prepend(data->lstVisuData, (gpointer)storage);
      }
      else
      storage->dimension = nb;

      DBG_fprintf(stderr, "Data Node : associating %p to the node property '%s' (%d).\n",
              (gpointer)dataObj, data->id, g_list_length(data->lstVisuData));

      DBG_fprintf(stderr, "Data Node : %p emit the 'propertyUsed'.\n", (gpointer)data);
      g_signal_emit(data, dataNode_signals[DATA_NODE_USED_SIGNAL],
                0 , dataObj, NULL);
    }
  else
    {
      if (!storage)
      return;

      g_signal_handler_disconnect(storage->dataObj, storage->freeingSignal);
      data->lstVisuData = g_list_remove(data->lstVisuData, storage);
      g_free(storage);

      DBG_fprintf(stderr, "Data Node : removing association with %p of the"
              " node property '%s' (%d).\n",
              (gpointer)dataObj, data->id, g_list_length(data->lstVisuData));

      DBG_fprintf(stderr, "Data Node : %p emit the 'propertyUnused'.\n", (gpointer)data);
      g_signal_emit(data, dataNode_signals[DATA_NODE_UNUSED_SIGNAL],
                0 , dataObj, NULL);
    }
}
gboolean nodeDataGet_used(DataNode *data, VisuData *dataObj)
{
  struct internalUsedVisuData_struct *storage;

  g_return_val_if_fail(IS_DATA_NODE_TYPE(data) && IS_VISU_DATA_TYPE(dataObj), FALSE);

  storage = getInternalStorage(data, dataObj);
  return (storage != (struct internalUsedVisuData_struct *)0);
}

gboolean nodeDataSet_valueAsString(DataNode *data, VisuData *dataObj,
                           VisuNode *node, gchar *labelIn, gchar **labelOut)
{
  int res, ln, i, valueInt;
  gchar **datas;
  gpointer dataValues;
  gboolean error, modified;
  struct internalUsedVisuData_struct *storage;
  float valueFloat;

  g_return_val_if_fail(IS_DATA_NODE_TYPE(data) &&
                   IS_VISU_DATA_TYPE(dataObj) && node, FALSE);
  g_return_val_if_fail(labelIn && labelOut, FALSE);

  if (!data->callback)
    {
      *labelOut = g_strdup(_("No data"));
      g_error("Can't call 'nodeDataSet_valueAsString' since the property"
            " '%s' is not editable.", data->id);
      return FALSE;
    }

  /* Check if the given property has an association with the given VisuData. */
  storage = getInternalStorage(data, dataObj);
  if (!storage)
    {
      *labelOut = g_strdup(_("No data"));
      g_error("Can't call 'nodeDataSet_valueAsString' since the property"
            " '%s' has not been associated with the given VisuData.", data->id);
      return FALSE;
    }
  
  /* Grep the property from the low level storage in the VisuData. */
  dataValues = visuDataGet_nodeProperty(dataObj, node, (gchar*)data->id);
  if (!dataValues)
    {
      *labelOut = g_strdup(_("No data"));
      g_error("Can't call 'nodeDataSet_valueAsString' since %p has no"
            " node property labelled '%s'", (gpointer)dataObj, data->id);
      return FALSE;
    }

  /* Parse the given labelIn.
     remove first and last parenthesis. */
  if (labelIn[0] == '(')
    labelIn += 1;
  ln = strlen(labelIn);
  if (labelIn[ln - 1] == ')')
    labelIn[ln - 1] = '\0';
  datas = g_strsplit(labelIn, ";", storage->dimension);
  modified = FALSE;
  for (i = 0; datas[i]; i++)
    {
      error = FALSE;
      switch (data->type)
      {
      case G_TYPE_INT:
        res = sscanf(datas[i], "%d", &valueInt);
        if (res != 1)
          error = TRUE;
        else
          if (((int*)dataValues)[i] != valueInt)
            {
            ((int*)dataValues)[i] = valueInt;
            modified = TRUE;
            }
        break;
      case G_TYPE_FLOAT:
        res = sscanf(datas[i], "%f", &valueFloat);
        if (res != 1)
          error = TRUE;
        else
          if (((float*)dataValues)[i] != valueFloat)
            {
            ((float*)dataValues)[i] = valueFloat;
            modified = TRUE;
            }
        break;
      case G_TYPE_BOOLEAN:
        /* T for True. */
        if (!strcmp(datas[i], _("T")))
          {
            if (!((gboolean*)dataValues)[i])
            {
              ((gboolean*)dataValues)[i] = TRUE;
              modified = TRUE;
            }
          }
        /* F for False. */
        else if (!strcmp(datas[i], _("F")))
          {
            if (((gboolean*)dataValues)[i])
            {
              ((gboolean*)dataValues)[i] = FALSE;
              modified = TRUE;
            }
          }
        else
          error = TRUE;
        break;
      default:
        g_warning("Unsupported type for DataNode");
        error = TRUE;
      }
      if (error)
      {
        *labelOut = nodeDataGet_valueAsString(data, dataObj, node);
        g_strfreev(datas);
        return FALSE;
      }
    }
  if (i != storage->dimension)
    error = TRUE;
  else
    error = FALSE;

  *labelOut = nodeDataGet_valueAsString(data, dataObj, node);
  g_strfreev(datas);

  /* Call the callback if values have been modified. */
  if (modified)
    data->callback(dataObj, node, data->data);

  return !error;
}
gchar* nodeDataGet_valueAsString(DataNode *data, VisuData *dataObj,
                         VisuNode *node)
{
  GString *str;
  int i;
  gchar *value;
  gpointer dataValues;
  struct internalUsedVisuData_struct *storage;

  g_return_val_if_fail(IS_DATA_NODE_TYPE(data) && dataObj && node, (gchar*)0);

  /* Check if the given property has an association with the given VisuData. */
  DBG_fprintf(stderr, "Data Node : get label for node property '%s'.\n", data->id);
  storage = getInternalStorage(data, dataObj);
  if (!storage || storage->dimension <= 0)
    {
      DBG_fprintf(stderr, "Data Node : no associated data.\n");
      return (gchar*)0;
    }

  dataValues = visuDataGet_nodeProperty(dataObj, node, (gchar*)data->id);
  if (!dataValues)
    return (gchar*)0;

  /* Set the format attribute. */
  str = g_string_new("( ");
  for (i = 0; i < storage->dimension; i++)
    {
      switch (data->type)
      {
      case G_TYPE_INT:
        g_string_append_printf(str, "%d", ((int*)dataValues)[i]);
        break;
      case G_TYPE_FLOAT:
        g_string_append_printf(str, "%g", ((float*)dataValues)[i]);
        break;
      case G_TYPE_BOOLEAN:
        if (((gboolean*)dataValues)[i])
          /* T for True. */
          g_string_append(str, _("T"));
        else
          /* F for False. */
          g_string_append(str, _("F"));
        break;
      default:
        g_warning("Unsupported type for DataNode");
      }
      if (i < storage->dimension - 1)
      g_string_append(str, " ; ");
    }
  g_string_append(str, " )");
  value = str->str;
  g_string_free(str, FALSE);

  DBG_fprintf(stderr, "DataNode : get values '%s'.\n", value);

  return value;
}

void nodeDataSet_callback(DataNode *data, DataNodeCallbackMethod callback,
                    gpointer user_data)
{
  g_return_if_fail(IS_DATA_NODE_TYPE(data));

  data->callback = callback;
  data->data = user_data;
}

gboolean nodeDataGet_editable(DataNode *data)
{
  g_return_val_if_fail(IS_DATA_NODE_TYPE(data), FALSE);

  if (data->callback)
    return TRUE;
  else
    return FALSE;
}

static void onVisuDataFreed(VisuData *dataObj, gpointer data)
{
  /* The given visuData is to be freed, so we remove it from the list
     of associated VisuData. */
  nodeDataSet_used(DATA_NODE(data), dataObj, 0);
}

Generated by  Doxygen 1.6.0   Back to index