[libgda] Added gda_data_access_wrapper_set_mapping()



commit e91042e41fd06fea19cf3a7b076fb4a6bcaa7c6e
Author: Vivien Malerba <malerba gnome-db org>
Date:   Thu Feb 9 22:45:21 2012 +0100

    Added gda_data_access_wrapper_set_mapping()
    
    to reorder and/or hide columns using a GdaDataAccessWrapper

 doc/C/libgda-sections.txt        |    1 +
 libgda/gda-data-access-wrapper.c |  174 +++++++++++++++++++++++++++++++++-----
 libgda/gda-data-access-wrapper.h |    4 +-
 libgda/libgda.symbols            |    1 +
 4 files changed, 158 insertions(+), 22 deletions(-)
---
diff --git a/doc/C/libgda-sections.txt b/doc/C/libgda-sections.txt
index e44f533..36aa971 100644
--- a/doc/C/libgda-sections.txt
+++ b/doc/C/libgda-sections.txt
@@ -331,6 +331,7 @@ GdaDataAccessWrapper
 GdaDataAccessWrapperClass
 GdaDataAccessWrapperPrivate
 gda_data_access_wrapper_new
+gda_data_access_wrapper_set_mapping
 <SUBSECTION Standard>
 GDA_DATA_ACCESS_WRAPPER
 GDA_DATA_ACCESS_WRAPPER_CLASS
diff --git a/libgda/gda-data-access-wrapper.c b/libgda/gda-data-access-wrapper.c
index 623a89e..abb2c49 100644
--- a/libgda/gda-data-access-wrapper.c
+++ b/libgda/gda-data-access-wrapper.c
@@ -42,13 +42,17 @@ struct _GdaDataAccessWrapperPrivate {
 	gint              iter_row;/* current row of @iter, starting at 0 when created */
 
 	GHashTable       *rows;    /* NULL if @model already is random access */
-	gint              nb_cols; /* number of columns of @model */
+	gint              nb_cols; /* number of columns of @wrapper */
 	gint              last_row;/* row number of the last row which has been read */
 	gboolean          end_of_data; /* TRUE if the end of the data model has been reached by the iterator */
 
 	GArray           *rows_buffer_array; /* Array of GdaRow */
 	GArray           *rows_buffer_index; /* Array of indexes: GdaRow at index i in @rows_buffer_array
 					      * is indexed in @rows with key rows_buffer_index[i] */
+
+	/* rows mapping */
+	GSList           *columns; /* not NULL if a mapping exists */
+	gint             *rows_mapping; /* @nb_cols is set when @rows_mapping is set, and @rows_mapping's size is @nb_cols */
 };
 
 /* properties */
@@ -212,6 +216,30 @@ model_row_removed_cb (G_GNUC_UNUSED GdaDataModel *mod, gint row, GdaDataAccessWr
 }
 
 static void
+clear_internal_state (GdaDataAccessWrapper *model)
+{
+	if (model->priv) {
+		if (model->priv->columns) {
+			g_slist_foreach (model->priv->columns, (GFunc) g_object_unref, NULL);
+			g_slist_free (model->priv->columns);
+			model->priv->columns = NULL;
+		}
+
+		model->priv->nb_cols = 0;
+
+		if (model->priv->rows_buffer_array) {
+			g_array_free (model->priv->rows_buffer_array, TRUE);
+			model->priv->rows_buffer_array = NULL;
+		}
+
+		if (model->priv->rows_buffer_index) {
+			g_array_free (model->priv->rows_buffer_index, TRUE);
+			model->priv->rows_buffer_index = NULL;
+		}
+	}
+}
+
+static void
 gda_data_access_wrapper_dispose (GObject *object)
 {
 	GdaDataAccessWrapper *model = (GdaDataAccessWrapper *) object;
@@ -220,6 +248,9 @@ gda_data_access_wrapper_dispose (GObject *object)
 
 	/* free memory */
 	if (model->priv) {
+		/* random access model free */
+		clear_internal_state (model);
+
 		if (model->priv->iter) {
 			g_signal_handlers_disconnect_by_func (G_OBJECT (model->priv->iter),
 							      G_CALLBACK (iter_row_changed_cb), model);
@@ -230,7 +261,6 @@ gda_data_access_wrapper_dispose (GObject *object)
 			model->priv->iter = NULL;
 		}
 
-		/* random access model free */
 		if (model->priv->model) {
 			if (model->priv->rows) {
 				g_hash_table_destroy (model->priv->rows);
@@ -247,16 +277,6 @@ gda_data_access_wrapper_dispose (GObject *object)
 			g_object_unref (model->priv->model);
 			model->priv->model = NULL;
 		}
-
-		if (model->priv->rows_buffer_array) {
-			g_array_free (model->priv->rows_buffer_array, TRUE);
-			model->priv->rows_buffer_array = NULL;
-		}
-
-		if (model->priv->rows_buffer_index) {
-			g_array_free (model->priv->rows_buffer_index, TRUE);
-			model->priv->rows_buffer_index = NULL;
-		}
 	}
 
 	/* chain to parent class */
@@ -281,6 +301,38 @@ gda_data_access_wrapper_finalize (GObject *object)
 }
 
 static void
+compute_columns (GdaDataAccessWrapper *model)
+{
+	if (model->priv->rows_mapping) {
+		/* use model->priv->rows_mapping to create columns, and correct it if
+		 * needed to remove out of range columns */
+		gint *nmapping;
+		gint i, j, nb_cols;
+		g_assert (!model->priv->columns);
+		nmapping = g_new (gint, model->priv->nb_cols);
+		nb_cols = gda_data_model_get_n_columns (model->priv->model);
+		for (i = 0, j = 0; i < model->priv->nb_cols; i++) {
+			gint nb = model->priv->rows_mapping [i];
+			if (nb >= nb_cols)
+				continue;
+			GdaColumn *column;
+			column = gda_data_model_describe_column (model->priv->model, nb);
+			if (!column)
+				continue;
+			model->priv->columns = g_slist_append (model->priv->columns,
+							       gda_column_copy (column));
+			nmapping [j] = nb;
+			j++;
+		}
+		model->priv->nb_cols = j;
+		g_free (model->priv->rows_mapping);
+		model->priv->rows_mapping = nmapping;
+	}
+	else
+		model->priv->nb_cols = gda_data_model_get_n_columns (model->priv->model);
+}
+
+static void
 gda_data_access_wrapper_set_property (GObject *object,
 				      guint param_id,
 				      const GValue *value,
@@ -292,10 +344,11 @@ gda_data_access_wrapper_set_property (GObject *object,
 	if (model->priv) {
 		switch (param_id) {
 		case PROP_MODEL: {
-			GdaDataModel *mod = g_value_get_object(value);
+			GdaDataModel *mod = g_value_get_object (value);
 			if (mod) {
 				g_return_if_fail (GDA_IS_DATA_MODEL (mod));
 				model->priv->model_access_flags = gda_data_model_get_access_flags (mod);
+
 				if (! (model->priv->model_access_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) {
 					model->priv->iter = gda_data_model_create_iter (mod);
 					g_return_if_fail (model->priv->iter);
@@ -322,7 +375,8 @@ gda_data_access_wrapper_set_property (GObject *object,
 
 				model->priv->model = mod;
 				g_object_ref (mod);
-				model->priv->nb_cols = gda_data_model_get_n_columns (mod);
+
+				compute_columns (model);
 			}
 			break;
 		}
@@ -376,6 +430,66 @@ gda_data_access_wrapper_new (GdaDataModel *model)
 	return GDA_DATA_MODEL (retmodel);
 }
 
+/**
+ * gda_data_access_wrapper_set_mapping:
+ * @wrapper: a #GdaDataAccessWrapper object
+ * @mapping: (allow-none) (array length=mapping_size): an array of #gint which represents the mapping between @wrapper's columns
+ * and the columns of the wrapped data model
+ * @mapping_size: the size of @mapping.
+ *
+ * @wrapper will report as many columns as @mapping_size, and for each value at position 'i' in @mapping,
+ * @wrapper will report the 'i'th column, mapped to the wrapped data model column at position mapping[i].
+ * For example if mapping is {3, 4, 0}, then @wrapper will report 3 columns, respectively mapped to the 4th,
+ * 5th and 1st columns of the wrapped data model (as column numbers start at 0).
+ *
+ * If @mapping is %NULL, then no mapping is done and @wrapper's columns will be the same as the wrapped
+ * data model.
+ *
+ * If a column in @mapping does not exist in the wrapped data model, then it is simply ignored (no error
+ * reported).
+ *
+ * Please note that if @wrapper has already been used and if the wrapped data model offers a cursor forward
+ * access mode, then this method will return %FALSE and no action will be done.
+ *
+ * If the mapping is applied, then any existing iterator will be invalid, and @wrapper is reset as if it
+ * had just been created.
+ *
+ * Returns: %TRUE if the mapping actually changed
+ *
+ * Since: 5.2
+ */
+gboolean
+gda_data_access_wrapper_set_mapping (GdaDataAccessWrapper *wrapper, gint *mapping, gint mapping_size)
+{
+	g_return_val_if_fail (GDA_IS_DATA_ACCESS_WRAPPER (wrapper), FALSE);
+
+	if ((! (wrapper->priv->model_access_flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD)) &&
+	    (wrapper->priv->iter_row >= 0)) {
+		/* error */
+		return FALSE;
+	}
+
+	clear_internal_state (wrapper);
+
+	if (mapping) {
+		/* define mapping */
+		wrapper->priv->rows_mapping = g_new (gint, mapping_size);
+		memcpy (wrapper->priv->rows_mapping, mapping, mapping_size * sizeof (gint));
+		wrapper->priv->nb_cols = mapping_size;
+	}
+	else {
+		if (wrapper->priv->rows_mapping) {
+			g_free (wrapper->priv->rows_mapping);
+			wrapper->priv->rows_mapping = NULL;
+		}
+	}
+
+	compute_columns (wrapper);
+	gda_data_model_reset ((GdaDataModel*) wrapper);
+
+	return TRUE;
+}
+
 /*
  * GdaDataModel interface implementation
  */
@@ -425,8 +539,12 @@ gda_data_access_wrapper_describe_column (GdaDataModel *model, gint col)
 	imodel = GDA_DATA_ACCESS_WRAPPER (model);
 	g_return_val_if_fail (imodel->priv, NULL);
 
-	if (imodel->priv->model)
-		return gda_data_model_describe_column (imodel->priv->model, col);
+	if (imodel->priv->model) {
+		if (imodel->priv->columns)
+			return g_slist_nth_data (imodel->priv->columns, col);
+		else
+			return gda_data_model_describe_column (imodel->priv->model, col);
+	}
 	else
 		return NULL;
 }
@@ -454,7 +572,10 @@ create_new_row (GdaDataAccessWrapper *model)
 		GdaHolder *holder;
 		GValue *dest;
 		dest = gda_row_get_value (row, i);
-		holder = gda_data_model_iter_get_holder_for_field (model->priv->iter, i);
+		if (model->priv->rows_mapping)
+			holder = gda_data_model_iter_get_holder_for_field (model->priv->iter, model->priv->rows_mapping [i]);
+		else
+			holder = gda_data_model_iter_get_holder_for_field (model->priv->iter, i);
 		if (holder) {
 			const GValue *cvalue = gda_holder_get_value (holder);
 			if (cvalue) {
@@ -494,9 +615,14 @@ gda_data_access_wrapper_get_value_at (GdaDataModel *model, gint col, gint row, G
 		return NULL;
 	}
 
-	if (!imodel->priv->rows)
+	if (!imodel->priv->rows) {
 		/* imodel->priv->model is a random access model, use it */
-		return gda_data_model_get_value_at (imodel->priv->model, col, row, error);
+		if (imodel->priv->rows_mapping)
+			return gda_data_model_get_value_at (imodel->priv->model, imodel->priv->rows_mapping [col],
+							    row, error);
+		else
+			return gda_data_model_get_value_at (imodel->priv->model, col, row, error);
+	}
 	else {
 		GdaRow *gda_row;
 		gint tmp;
@@ -648,8 +774,14 @@ gda_data_access_wrapper_get_attributes_at (GdaDataModel *model, gint col, gint r
 	imodel = (GdaDataAccessWrapper *) model;
 	g_return_val_if_fail (imodel->priv, 0);
 
-	if (imodel->priv->model)
-		flags = gda_data_model_get_attributes_at (imodel->priv->model, col, row);
+	if (imodel->priv->model) {
+		if (imodel->priv->rows_mapping)
+			flags = gda_data_model_get_attributes_at (imodel->priv->model, imodel->priv->rows_mapping [col],
+								  row);
+		else
+			flags = gda_data_model_get_attributes_at (imodel->priv->model, col, row);
+	}
+
 	flags |= GDA_VALUE_ATTR_NO_MODIF;
 	
 	return flags;
diff --git a/libgda/gda-data-access-wrapper.h b/libgda/gda-data-access-wrapper.h
index 06c8fe2..efcae9c 100644
--- a/libgda/gda-data-access-wrapper.h
+++ b/libgda/gda-data-access-wrapper.h
@@ -58,12 +58,14 @@ struct _GdaDataAccessWrapperClass {
  * @stability: Stable
  * @see_also: #GdaDataModel
  *
- * The #GdaDataAccessWrapper object simply wraps around another #GdaDataModel data model object
+ * The #GdaDataAccessWrapper object simply wraps another #GdaDataModel data model object
  * and allows data to be accessed in a random way while remaining memory efficient as much as possible.
  */
 
 GType         gda_data_access_wrapper_get_type    (void) G_GNUC_CONST;
 GdaDataModel *gda_data_access_wrapper_new         (GdaDataModel *model);
+gboolean      gda_data_access_wrapper_set_mapping (GdaDataAccessWrapper *wrapper,
+						   gint *mapping, gint mapping_size);
 
 G_END_DECLS
 
diff --git a/libgda/libgda.symbols b/libgda/libgda.symbols
index 8e40eca..d4d7452 100644
--- a/libgda/libgda.symbols
+++ b/libgda/libgda.symbols
@@ -181,6 +181,7 @@
 	gda_connection_value_to_sql_string
 	gda_data_access_wrapper_get_type
 	gda_data_access_wrapper_new
+	gda_data_access_wrapper_set_mapping
 	gda_data_comparator_compute_diff
 	gda_data_comparator_error_get_type
 	gda_data_comparator_error_quark



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]