/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Damien
	CALISTE, laboratoire L_Sim, (2017)
  
	Adresse 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 : Damien
	CALISTE, laboratoire L_Sim, (2017)

	E-mail address:
	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 "ui_selection.h"

/**
 * SECTION:ui_selection
 * @short_description: A specialised list store handling node selection.
 *
 * <para>This is a specialised #GtkListStore to handle list of
 * nodes. It is storing the node ids and their highlight status. Their
 * highlight status is driven by a #VisuGlExtMarks model, see
 * visu_ui_selection_setHighlightModel(). If a #VisuData model is
 * provided by visu_ui_selection_setNodeModel(), then on population
 * changes, the non existing nodes are removed from the selection list.</para>
 */


struct _VisuUiSelectionPrivate
{
  gboolean dispose_has_run;

  VisuData *data;
  gulong popDec_signal;
  VisuGlExtMarks *marks;
  gulong hl_signal;
  gboolean highlight;
};

enum
  {
    PROP_0,
    MODEL_PROP,
    MARKS_PROP,
    SELECTION_PROP,
    HIGHLIGHT_PROP,
    N_PROP
  };
static GParamSpec *_properties[N_PROP];

static void visu_ui_selection_dispose     (GObject* obj);
static void visu_ui_selection_get_property(GObject* obj, guint property_id,
                                            GValue *value, GParamSpec *pspec);
static void visu_ui_selection_set_property(GObject* obj, guint property_id,
                                            const GValue *value, GParamSpec *pspec);

G_DEFINE_TYPE_WITH_CODE(VisuUiSelection, visu_ui_selection, GTK_TYPE_LIST_STORE,
                        G_ADD_PRIVATE(VisuUiSelection))

/* Local callbacks. */

/* Local routines. */
static void _updateHighlight(VisuUiSelection *selection);

static void visu_ui_selection_class_init(VisuUiSelectionClass *klass)
{
  DBG_fprintf(stderr, "Visu UiSelection: creating the class of the object.\n");
  /* DBG_fprintf(stderr, "                - adding new signals ;\n"); */

  /* Connect the overloading methods. */
  G_OBJECT_CLASS(klass)->dispose  = visu_ui_selection_dispose;
  G_OBJECT_CLASS(klass)->set_property = visu_ui_selection_set_property;
  G_OBJECT_CLASS(klass)->get_property = visu_ui_selection_get_property;

  /**
   * VisuUiSelection::model:
   *
   * The #VisuData this selection is operating on.
   *
   * Since: 3.8
   */
  _properties[MODEL_PROP] = g_param_spec_object
    ("model", "Model", "node model.", VISU_TYPE_DATA, G_PARAM_READWRITE);
  /**
   * VisuUiSelection::marks:
   *
   * The #VisuGlExtMarks the highlight info are taken from.
   *
   * Since: 3.8
   */
  _properties[MARKS_PROP] = g_param_spec_object
    ("marks", "Marks", "highlight model.", VISU_TYPE_GL_EXT_MARKS, G_PARAM_READWRITE);
  /**
   * VisuUiSelection::selection:
   *
   * The ids of selected nodes.
   *
   * Since: 3.8
   */
  _properties[SELECTION_PROP] = g_param_spec_boxed
    ("selection", "Selection", "ids of selected nodes.",
     G_TYPE_ARRAY, G_PARAM_READWRITE);
  /**
   * VisuUiSelection::highlight:
   *
   * Highlight all nodes and all newly selected ones when TRUE.
   *
   * Since: 3.8
   */
  _properties[HIGHLIGHT_PROP] = g_param_spec_boolean
    ("highlight", "Highlight", "highlight the selection.",
     FALSE, G_PARAM_READWRITE);
  
  g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties);
}

static void visu_ui_selection_init(VisuUiSelection *list)
{
  GType types[VISU_UI_SELECTION_N_COLUMNS] = {G_TYPE_UINT, G_TYPE_BOOLEAN};

  DBG_fprintf(stderr, "Visu UiSelection: initializing a new object (%p).\n",
	      (gpointer)list);
  list->priv = visu_ui_selection_get_instance_private(list);
  list->priv->dispose_has_run = FALSE;

  gtk_list_store_set_column_types(GTK_LIST_STORE(list), VISU_UI_SELECTION_N_COLUMNS, types);

  list->priv->data = (VisuData*)0;
  list->priv->marks = (VisuGlExtMarks*)0;
  list->priv->highlight = FALSE;
}

static void visu_ui_selection_dispose(GObject* obj)
{
  VisuUiSelection *list;

  DBG_fprintf(stderr, "Visu UiSelection: dispose object %p.\n", (gpointer)obj);

  list = VISU_UI_SELECTION(obj);
  if (list->priv->dispose_has_run)
    return;
  list->priv->dispose_has_run = TRUE;

  visu_ui_selection_setNodeModel(list, (VisuData*)0);
  visu_ui_selection_setHighlightModel(list, (VisuGlExtMarks*)0);

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

static void visu_ui_selection_get_property(GObject* obj, guint property_id,
                                            GValue *value, GParamSpec *pspec)
{
  DBG_fprintf(stderr, "Visu UiSelection: get property '%s' -> ",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case MODEL_PROP:
      g_value_set_object(value, VISU_UI_SELECTION(obj)->priv->data);
      DBG_fprintf(stderr, "%p.\n", g_value_get_object(value));
      break;
    case MARKS_PROP:
      g_value_set_object(value, VISU_UI_SELECTION(obj)->priv->marks);
      DBG_fprintf(stderr, "%p.\n", g_value_get_object(value));
      break;
    case SELECTION_PROP:
      g_value_take_boxed(value, visu_ui_selection_get(VISU_UI_SELECTION(obj)));
      DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value));
      break;
    case HIGHLIGHT_PROP:
      g_value_set_boolean(value, VISU_UI_SELECTION(obj)->priv->highlight);
      DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value));
      break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}
static void visu_ui_selection_set_property(GObject* obj, guint property_id,
                                            const GValue *value, GParamSpec *pspec)
{
  VisuUiSelection *list = VISU_UI_SELECTION(obj);

  DBG_fprintf(stderr, "Visu UiSelection: set property '%s'\n",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case MODEL_PROP:
      visu_ui_selection_setNodeModel(list, VISU_DATA(g_value_get_object(value)));
      break;
    case MARKS_PROP:
      visu_ui_selection_setHighlightModel(list, VISU_GL_EXT_MARKS(g_value_get_object(value)));
      break;
    case SELECTION_PROP:
      visu_ui_selection_set(list, (GArray*)g_value_get_boxed(value));
      break;
    case HIGHLIGHT_PROP:
      visu_ui_selection_highlight(list, (GtkTreeIter*)0,
                                  g_value_get_boolean(value) ?
                                  MARKS_STATUS_SET : MARKS_STATUS_UNSET);
      list->priv->highlight = g_value_get_boolean(value);
      break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}

/**
 * visu_ui_selection_new:
 *
 * Create a new #GtkListStore to store planes.
 *
 * Since: 3.8
 *
 * Returns: a newly created object.
 **/
VisuUiSelection* visu_ui_selection_new()
{
  VisuUiSelection *list;

  list = VISU_UI_SELECTION(g_object_new(VISU_TYPE_UI_SELECTION, NULL));
  return list;
}

/**
 * visu_ui_selection_setNodeModel:
 * @selection: a #VisuUiSelection object.
 * @data: (allow-none): a #VisuData object.
 *
 * Bind the @set object to @list.
 *
 * Returns: TRUE if @set is changed
 **/
gboolean visu_ui_selection_setNodeModel(VisuUiSelection *selection, VisuData *data)
{
  GtkTreeIter iter;
  guint number;
  gboolean valid;
  VisuNode *node;
  
  g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), FALSE);

  if (selection->priv->data == data)
    return FALSE;

  if (selection->priv->data)
    {
      g_signal_handler_disconnect(G_OBJECT(selection->priv->data),
                                  selection->priv->popDec_signal);
      g_object_unref(selection->priv->data);
    }
  selection->priv->data = data;
  if (data)
    {
      g_object_ref(data);
      selection->priv->popDec_signal =
        g_signal_connect_swapped(G_OBJECT(data), "PopulationDecrease",
                                 G_CALLBACK(visu_ui_selection_remove), selection);

      /* Try to match the selected nodes to new ones in the new visuData. */
      valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), &iter);
      while (valid)
	{
	  gtk_tree_model_get(GTK_TREE_MODEL(selection), &iter,
			     VISU_UI_SELECTION_NUMBER, &number,
			     -1);
	  node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), number - 1);
          if (node)
            valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), &iter);
          else
	    valid = gtk_list_store_remove(GTK_LIST_STORE(selection), &iter);
	}
    }
  else
    gtk_list_store_clear(GTK_LIST_STORE(selection));
  g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]);

  return TRUE;
}

/**
 * visu_ui_selection_setHighlightModel:
 * @selection: a #VisuUiSelection object.
 * @marks: (allow-none): a #VisuGlExtMarks object.
 *
 * Bind the @set object to @list.
 *
 * Returns: TRUE if @set is changed
 **/
gboolean visu_ui_selection_setHighlightModel(VisuUiSelection *selection,
                                             VisuGlExtMarks *marks)
{
  g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), FALSE);

  if (selection->priv->marks == marks)
    return FALSE;

  if (selection->priv->marks)
    {
      g_signal_handler_disconnect(selection->priv->marks, selection->priv->hl_signal);
      g_object_unref(selection->priv->marks);
    }
  selection->priv->marks = marks;
  if (marks)
    {
      g_object_ref(marks);
      selection->priv->hl_signal = g_signal_connect_swapped
        (marks, "notify::highlight", G_CALLBACK(_updateHighlight), selection);
    }
  _updateHighlight(selection);

  return TRUE;
}

/**
 * visu_ui_selection_at:
 * @selection: a #VisuUiSelection object.
 * @iter: a #GtkTreeIter structure.
 * @id: a node id.
 *
 * Inquires if the model @selection is storing node @id at @iter.
 *
 * Since: 3.8
 *
 * Returns: TRUE if node @id is set at @iter.
 **/
gboolean visu_ui_selection_at(VisuUiSelection *selection, GtkTreeIter *iter, guint id)
{
  gboolean valid;
  guint currentNodeId;

  g_return_val_if_fail(iter, FALSE);

  /* Search if @node is already in the tree. */
  for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), iter);
       valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), iter))
    {
      gtk_tree_model_get(GTK_TREE_MODEL(selection), iter,
			 VISU_UI_SELECTION_NUMBER, &currentNodeId, -1);
      if (id + 1 == currentNodeId)
        return TRUE;
    }
  return FALSE;
}

/**
 * visu_ui_selection_add:
 * @selection: a #VisuUiSelection object.
 * @id: a node id.
 *
 * Add the node identified by @id to @selection. If the node already
 * exists or if @selection has no current node model, nothing is
 * done. If there are several nodes to insert at once, use
 * visu_ui_selection_append() instead to ensure that the selection
 * signalis only emitted once.
 *
 * Since: 3.8
 *
 * Returns: TRUE if @id can be added to the model.
 **/
gboolean visu_ui_selection_add(VisuUiSelection *selection, guint id)
{
  GtkTreeIter it;
  VisuNode *node;
  gboolean newRow;

  g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), FALSE);

  if (!selection->priv->data)
    return FALSE;
  node = visu_node_array_getFromId(VISU_NODE_ARRAY(selection->priv->data), id);
  if (!node)
    return FALSE;

  newRow = !visu_ui_selection_at(selection, &it, id);
  if (newRow)
    gtk_list_store_append(GTK_LIST_STORE(selection), &it);

  /* Store the base data. */
  gtk_list_store_set(GTK_LIST_STORE(selection), &it,
		     VISU_UI_SELECTION_NUMBER, id + 1,
                     VISU_UI_SELECTION_HIGHLIGHT, selection->priv->marks ? visu_gl_ext_marks_getHighlightStatus(selection->priv->marks, id) : FALSE,
		     -1);
  if (selection->priv->highlight)
    visu_ui_selection_highlight(selection, &it, MARKS_STATUS_SET);

  if (newRow)
    g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]);

  return newRow;
}

/**
 * visu_ui_selection_get:
 * @selection: a #VisuUiSelection object.
 *
 * Retrieves the list of node ids in the selection.
 *
 * Since: 3.8
 *
 * Returns: (transfer full) (element-type guint): a list of node ids.
 **/
GArray* visu_ui_selection_get(const VisuUiSelection *selection)
{
  GArray *ids;
  gboolean valid;
  GtkTreeIter it;
  guint id;
  
  g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), (GArray*)0);

  ids = g_array_new(FALSE, FALSE, sizeof(guint));
  for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), &it);
       valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), &it))
    {
      gtk_tree_model_get(GTK_TREE_MODEL(selection), &it,
			 VISU_UI_SELECTION_NUMBER, &id, -1);
      id -= 1;
      g_array_append_val(ids, id);
    }
  return ids;
}

/**
 * visu_ui_selection_append:
 * @selection: a #VisuUiSelection object.
 * @ids: (element-type uint): a list of node ids.
 *
 * Inserts every node from @ids into @selection. The selection signal
 * is only emitted once.
 *
 * Since: 3.8
 **/
void visu_ui_selection_append(VisuUiSelection *selection, const GArray *ids)
{
  guint i;
  GtkTreeIter it;
  VisuNode *node;

  g_return_if_fail(VISU_IS_UI_SELECTION(selection));

  if (!selection->priv->data)
    return;

  for (i = 0; i < ids->len; i++)
    {
      node = visu_node_array_getFromId(VISU_NODE_ARRAY(selection->priv->data),
                                       g_array_index(ids, guint, i));
      if (node && !visu_ui_selection_at(selection, &it, g_array_index(ids, guint, i)))
        {
          gtk_list_store_append(GTK_LIST_STORE(selection), &it);

          /* Store the base data. */
          gtk_list_store_set(GTK_LIST_STORE(selection), &it,
                             VISU_UI_SELECTION_NUMBER, g_array_index(ids, guint, i) + 1,
                             VISU_UI_SELECTION_HIGHLIGHT, selection->priv->marks ? visu_gl_ext_marks_getHighlightStatus(selection->priv->marks, g_array_index(ids, guint, i)) : FALSE,
                             -1);
          if (selection->priv->highlight)
            visu_ui_selection_highlight(selection, &it, MARKS_STATUS_SET);
        }
    }

  g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]);
}

/**
 * visu_ui_selection_set:
 * @selection: a #VisuUiSelection object.
 * @ids: (element-type uint): a list of node ids.
 *
 * Clear the @selection and update it with the nodes from @ids.
 *
 * Since: 3.8
 **/
void visu_ui_selection_set(VisuUiSelection *selection, const GArray *ids)
{
  g_return_if_fail(VISU_IS_UI_SELECTION(selection));

  gtk_list_store_clear(GTK_LIST_STORE(selection));

  visu_ui_selection_append(selection, ids);
}

/**
 * visu_ui_selection_appendHighlightedNodes:
 * @selection: a #VisuUiSelection object.
 *
 * A convenient method to get the highlighted nodes and add them to
 * the @selection.
 *
 * Since: 3.8
 **/
void visu_ui_selection_appendHighlightedNodes(VisuUiSelection *selection)
{
  GArray *ids;
  
  g_return_if_fail(VISU_IS_UI_SELECTION(selection));
  
  if (!selection->priv->marks)
    return;

  ids = visu_gl_ext_marks_getHighlighted(selection->priv->marks);
  visu_ui_selection_append(selection, ids);
}

/**
 * visu_ui_selection_remove:
 * @selection: a #VisuUiSelection object.
 * @ids: (element-type uint): a list of node ids.
 *
 * Remove a list of nodes from @selection.
 *
 * Since: 3.8
 **/
void visu_ui_selection_remove(VisuUiSelection *selection, const GArray *ids)
{
  GtkTreeIter iter, removeIter;
  gboolean valid;
  guint number;
  guint i;
  gboolean found;

  g_return_if_fail(VISU_IS_UI_SELECTION(selection));

  valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), &iter);
  while (valid)
    {
      gtk_tree_model_get(GTK_TREE_MODEL(selection), &iter,
			 VISU_UI_SELECTION_NUMBER, &number, -1);
      found = FALSE;
      for (i = 0; !found && i < ids->len; i++)
	if (number == (g_array_index(ids, guint, i) + 1))
	  {
	    removeIter = iter;
	    found = TRUE;
	  }
			 
      valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), &iter);
      if (found)
        {
          if (selection->priv->highlight)
            visu_ui_selection_highlight(selection, &removeIter, MARKS_STATUS_UNSET);
          gtk_list_store_remove(GTK_LIST_STORE(selection), &removeIter);
        }
    };
  g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]);
}

/**
 * visu_ui_selection_clear:
 * @selection: a #VisuUiSelection object.
 *
 * An overloaded method of gtk_list_store_clear() to ensure that the
 * selection signal is properly emitted.
 *
 * Since: 3.8
 **/
void visu_ui_selection_clear(VisuUiSelection *selection)
{
  g_return_if_fail(VISU_IS_UI_SELECTION(selection));

  if (!gtk_tree_model_iter_n_children(GTK_TREE_MODEL(selection), (GtkTreeIter*)0))
    return;
  gtk_list_store_clear(GTK_LIST_STORE(selection));
  g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]);
  if (selection->priv->highlight)
    visu_ui_selection_highlight(selection, (GtkTreeIter*)0, MARKS_STATUS_UNSET);
}

/**
 * visu_ui_selection_removeAt:
 * @selection: a #VisuUiSelection object.
 * @iter: a #GtkTreeIter structure.
 *
 * Remove the node stored at iter from @selection. This is an
 * overloaded function of gtk_list_store_remove() to emit the selection
 * signal after change.
 *
 * Since: 3.8
 *
 * Returns: TRUE if @iter was actually removed.
 **/
gboolean visu_ui_selection_removeAt(VisuUiSelection *selection, GtkTreeIter *iter)
{
  gboolean valid;
  
  g_return_val_if_fail(VISU_IS_UI_SELECTION(selection), FALSE);

  if (selection->priv->highlight)
    visu_ui_selection_highlight(selection, iter, MARKS_STATUS_UNSET);
  valid = gtk_list_store_remove(GTK_LIST_STORE(selection), iter);
  g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]);
  return valid;
}

/**
 * visu_ui_selection_removePaths:
 * @selection: a #VisuUiSelection object.
 * @paths: (element-type GtkTreePath): a list of #GtkTreePath
 *
 * Remove all given paths from @selection.
 *
 * Since: 3.8
 **/
void visu_ui_selection_removePaths(VisuUiSelection *selection, const GList *paths)
{
  GList *lst, *sorted;
  GtkTreeIter iter;
  
  g_return_if_fail(VISU_IS_UI_SELECTION(selection));

  sorted = g_list_reverse(g_list_sort(g_list_copy((GList*)paths),
                                      (GCompareFunc)gtk_tree_path_compare)); 
  for (lst = sorted; lst; lst = g_list_next(lst))
    if (gtk_tree_model_get_iter(GTK_TREE_MODEL(selection), &iter,
                                (GtkTreePath*)lst->data))
      {
        if (selection->priv->highlight)
          visu_ui_selection_highlight(selection, &iter, MARKS_STATUS_UNSET);
        gtk_list_store_remove(GTK_LIST_STORE(selection), &iter);
      }
  g_list_free(sorted);
  g_object_notify_by_pspec(G_OBJECT(selection), _properties[SELECTION_PROP]);
}

/**
 * visu_ui_selection_highlight:
 * @selection: a #VisuUiSelection object.
 * @iter: (allow-none): a #GtkTreeIter structure.
 * @status: a mark status.
 *
 * Apply the new @status to nodes. If @iter is %NULL, all nodes stored
 * in @selection are modified, otherwise, only the node at @iter.
 *
 * Since: 3.8
 **/
void visu_ui_selection_highlight(VisuUiSelection *selection,
                                 GtkTreeIter *iter, VisuGlExtMarksStatus status)
{
  GtkTreeIter iter_;
  gboolean valid, hl, only;
  guint node;
  GArray *ids;

  g_return_if_fail(VISU_IS_UI_SELECTION(selection));

  if (!selection->priv->marks)
    return;

  only = (iter != (GtkTreeIter*)0);
  if (!iter)
    iter = &iter_;
  
  DBG_fprintf(stderr, "Gtk Pick: change highlight status.\n");
  ids = g_array_new(FALSE, FALSE, sizeof(guint));
  for (valid = (!only)?gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), iter):TRUE;
       valid; valid = (!only)?gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), iter):FALSE)
    {
      gtk_tree_model_get(GTK_TREE_MODEL(selection), iter,
			 VISU_UI_SELECTION_HIGHLIGHT, &hl,
			 VISU_UI_SELECTION_NUMBER, &node,
			 -1);
      DBG_fprintf(stderr, " | process %d\n", node - 1);
      if (status == MARKS_STATUS_TOGGLE)
	gtk_list_store_set(GTK_LIST_STORE(selection), iter,
			   VISU_UI_SELECTION_HIGHLIGHT, !hl,
			   -1);
      else if (status == MARKS_STATUS_SET)
	gtk_list_store_set(GTK_LIST_STORE(selection), iter,
			   VISU_UI_SELECTION_HIGHLIGHT, TRUE,
			   -1);
      else if (status == MARKS_STATUS_UNSET)
	gtk_list_store_set(GTK_LIST_STORE(selection), iter,
			   VISU_UI_SELECTION_HIGHLIGHT, FALSE,
			   -1);
      node -= 1;
      g_array_append_val(ids, node);
    }
  g_signal_handler_block(selection->priv->marks, selection->priv->hl_signal);
  visu_gl_ext_marks_setHighlight(selection->priv->marks, ids, status);
  g_signal_handler_unblock(selection->priv->marks, selection->priv->hl_signal);
  g_array_unref(ids);
}

static void _updateHighlight(VisuUiSelection *selection)
{
  gboolean valid;
  GtkTreeIter it;
  guint id;
  
  g_return_if_fail(VISU_IS_UI_SELECTION(selection));

  for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(selection), &it);
       valid; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(selection), &it))
    {
      gtk_tree_model_get(GTK_TREE_MODEL(selection), &it,
                         VISU_UI_SELECTION_NUMBER, &id, -1);
      gtk_list_store_set(GTK_LIST_STORE(selection), &it,
			 VISU_UI_SELECTION_HIGHLIGHT,
                         selection->priv->marks ?
                         visu_gl_ext_marks_getHighlightStatus(selection->priv->marks, id - 1) : FALSE, -1);
    }
}
