From d09d8de870b6697c8a8b262e7e077b871a69b315 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Mon, 10 Dec 2012 08:09:59 -0500 Subject: Consolidate base utility libraries into libeutil. Evolution consists of entirely too many small utility libraries, which increases linking and loading time, places a burden on higher layers of the application (e.g. modules) which has to remember to link to all the small in-tree utility libraries, and makes it difficult to generate API documentation for these utility libraries in one Gtk-Doc module. Merge the following utility libraries under the umbrella of libeutil, and enforce a single-include policy on libeutil so we can reorganize the files as desired without disrupting its pseudo-public API. libemail-utils/libemail-utils.la libevolution-utils/libevolution-utils.la filter/libfilter.la widgets/e-timezone-dialog/libetimezonedialog.la widgets/menus/libmenus.la widgets/misc/libemiscwidgets.la widgets/table/libetable.la widgets/text/libetext.la This also merges libedataserverui from the Evolution-Data-Server module, since Evolution is its only consumer nowadays, and I'd like to make some improvements to those APIs without concern for backward-compatibility. And finally, start a Gtk-Doc module for libeutil. It's going to be a project just getting all the symbols _listed_ much less _documented_. But the skeletal structure is in place and I'm off to a good start. --- e-util/e-table-memory-store.c | 637 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 637 insertions(+) create mode 100644 e-util/e-table-memory-store.c (limited to 'e-util/e-table-memory-store.c') diff --git a/e-util/e-table-memory-store.c b/e-util/e-table-memory-store.c new file mode 100644 index 0000000000..066d319122 --- /dev/null +++ b/e-util/e-table-memory-store.c @@ -0,0 +1,637 @@ +/* + * This program 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 of the License, or (at your option) version 3. + * + * This program 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 the program; if not, see + * + * + * Authors: + * Chris Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "e-table-memory-store.h" + +#define E_TABLE_MEMORY_STORE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_TABLE_MEMORY_STORE, ETableMemoryStorePrivate)) + +#define STORE_LOCATOR(etms, col, row) (*((etms)->priv->store + (row) * (etms)->priv->col_count + (col))) + +struct _ETableMemoryStorePrivate { + gint col_count; + ETableMemoryStoreColumnInfo *columns; + gpointer *store; +}; + +G_DEFINE_TYPE (ETableMemoryStore, e_table_memory_store, E_TYPE_TABLE_MEMORY) + +static gpointer +duplicate_value (ETableMemoryStore *etms, + gint col, + gconstpointer val) +{ + switch (etms->priv->columns[col].type) { + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING: + return g_strdup (val); + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF: + if (val) + g_object_ref ((gpointer) val); + return (gpointer) val; + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT: + if (val) + g_object_ref ((gpointer) val); + return (gpointer) val; + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM: + if (etms->priv->columns[col].custom.duplicate_value) + return etms->priv->columns[col].custom.duplicate_value (E_TABLE_MODEL (etms), col, val, NULL); + break; + default: + break; + } + return (gpointer) val; +} + +static void +free_value (ETableMemoryStore *etms, + gint col, + gpointer value) +{ + switch (etms->priv->columns[col].type) { + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING: + g_free (value); + break; + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF: + if (value) + g_object_unref (value); + break; + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT: + if (value) + g_object_unref (value); + break; + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM: + if (etms->priv->columns[col].custom.free_value) + etms->priv->columns[col].custom.free_value (E_TABLE_MODEL (etms), col, value, NULL); + break; + default: + break; + } +} + +static gint +etms_column_count (ETableModel *etm) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + return etms->priv->col_count; +} + +static gpointer +etms_value_at (ETableModel *etm, + gint col, + gint row) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + return STORE_LOCATOR (etms, col, row); +} + +static void +etms_set_value_at (ETableModel *etm, + gint col, + gint row, + gconstpointer val) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + e_table_model_pre_change (etm); + + STORE_LOCATOR (etms, col, row) = duplicate_value (etms, col, val); + + e_table_model_cell_changed (etm, col, row); +} + +static gboolean +etms_is_cell_editable (ETableModel *etm, + gint col, + gint row) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + return etms->priv->columns[col].editable; +} + +/* The default for etms_duplicate_value is to return the raw value. */ +static gpointer +etms_duplicate_value (ETableModel *etm, + gint col, + gconstpointer value) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + return duplicate_value (etms, col, value); +} + +static void +etms_free_value (ETableModel *etm, + gint col, + gpointer value) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + free_value (etms, col, value); +} + +static gpointer +etms_initialize_value (ETableModel *etm, + gint col) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + switch (etms->priv->columns[col].type) { + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING: + return g_strdup (""); + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF: + return NULL; + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM: + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT: + if (etms->priv->columns[col].custom.initialize_value) + return etms->priv->columns[col].custom.initialize_value (E_TABLE_MODEL (etms), col, NULL); + break; + default: + break; + } + return NULL; +} + +static gboolean +etms_value_is_empty (ETableModel *etm, + gint col, + gconstpointer value) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + switch (etms->priv->columns[col].type) { + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING: + return !(value && *(gchar *) value); + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF: + return value == NULL; + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM: + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT: + if (etms->priv->columns[col].custom.value_is_empty) + return etms->priv->columns[col].custom.value_is_empty (E_TABLE_MODEL (etms), col, value, NULL); + break; + default: + break; + } + return value == NULL; +} + +static gchar * +etms_value_to_string (ETableModel *etm, + gint col, + gconstpointer value) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + + switch (etms->priv->columns[col].type) { + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_STRING: + return g_strdup (value); + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_PIXBUF: + return g_strdup (""); + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_CUSTOM: + case E_TABLE_MEMORY_STORE_COLUMN_TYPE_OBJECT: + if (etms->priv->columns[col].custom.value_is_empty) + return etms->priv->columns[col].custom.value_to_string (E_TABLE_MODEL (etms), col, value, NULL); + break; + default: + break; + } + return g_strdup_printf ("%d", GPOINTER_TO_INT (value)); +} + +static void +etms_append_row (ETableModel *etm, + ETableModel *source, + gint row) +{ + ETableMemoryStore *etms = E_TABLE_MEMORY_STORE (etm); + gpointer *new_data; + gint i; + gint row_count; + + new_data = g_new (gpointer , etms->priv->col_count); + + for (i = 0; i < etms->priv->col_count; i++) { + new_data[i] = e_table_model_value_at (source, i, row); + } + + row_count = e_table_model_row_count (E_TABLE_MODEL (etms)); + + e_table_memory_store_insert_array (etms, row_count, new_data, NULL); +} + +static void +etms_finalize (GObject *object) +{ + ETableMemoryStorePrivate *priv; + + priv = E_TABLE_MEMORY_STORE_GET_PRIVATE (object); + + e_table_memory_store_clear (E_TABLE_MEMORY_STORE (object)); + + g_free (priv->columns); + g_free (priv->store); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_table_memory_store_parent_class)->finalize (object); +} + +static void +e_table_memory_store_init (ETableMemoryStore *etms) +{ + etms->priv = E_TABLE_MEMORY_STORE_GET_PRIVATE (etms); +} + +static void +e_table_memory_store_class_init (ETableMemoryStoreClass *class) +{ + GObjectClass *object_class; + ETableModelClass *model_class; + + g_type_class_add_private (class, sizeof (ETableMemoryStorePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = etms_finalize; + + model_class = E_TABLE_MODEL_CLASS (class); + model_class->column_count = etms_column_count; + model_class->value_at = etms_value_at; + model_class->set_value_at = etms_set_value_at; + model_class->is_cell_editable = etms_is_cell_editable; + model_class->duplicate_value = etms_duplicate_value; + model_class->free_value = etms_free_value; + model_class->initialize_value = etms_initialize_value; + model_class->value_is_empty = etms_value_is_empty; + model_class->value_to_string = etms_value_to_string; + model_class->append_row = etms_append_row; +} + +/** + * e_table_memory_store_new: + * @col_count: + * @value_at: + * @set_value_at: + * @is_cell_editable: + * @duplicate_value: + * @free_value: + * @initialize_value: + * @value_is_empty: + * @value_to_string: + * @data: closure pointer. + * + * This initializes a new ETableMemoryStoreModel object. ETableMemoryStoreModel is + * an implementaiton of the abstract class ETableModel. The ETableMemoryStoreModel + * is designed to allow people to easily create ETableModels without having + * to create a new GType derived from ETableModel every time they need one. + * + * Instead, ETableMemoryStoreModel uses a setup based in callback functions, every + * callback function signature mimics the signature of each ETableModel method + * and passes the extra @data pointer to each one of the method to provide them + * with any context they might want to use. + * + * Returns: An ETableMemoryStoreModel object (which is also an ETableModel + * object). + */ +ETableModel * +e_table_memory_store_new (ETableMemoryStoreColumnInfo *columns) +{ + ETableMemoryStore *et = g_object_new (E_TYPE_TABLE_MEMORY_STORE, NULL); + + if (e_table_memory_store_construct (et, columns)) { + return (ETableModel *) et; + } else { + g_object_unref (et); + return NULL; + } +} + +ETableModel * +e_table_memory_store_construct (ETableMemoryStore *etms, + ETableMemoryStoreColumnInfo *columns) +{ + gint i; + for (i = 0; columns[i].type != E_TABLE_MEMORY_STORE_COLUMN_TYPE_TERMINATOR; i++) + /* Intentionally blank */; + etms->priv->col_count = i; + + etms->priv->columns = g_new (ETableMemoryStoreColumnInfo, etms->priv->col_count + 1); + + memcpy (etms->priv->columns, columns, (etms->priv->col_count + 1) * sizeof (ETableMemoryStoreColumnInfo)); + + return E_TABLE_MODEL (etms); +} + +void +e_table_memory_store_adopt_value_at (ETableMemoryStore *etms, + gint col, + gint row, + gpointer value) +{ + e_table_model_pre_change (E_TABLE_MODEL (etms)); + + STORE_LOCATOR (etms, col, row) = value; + + e_table_model_cell_changed (E_TABLE_MODEL (etms), col, row); +} + +/* The size of these arrays is the number of columns. */ +void +e_table_memory_store_insert_array (ETableMemoryStore *etms, + gint row, + gpointer *store, + gpointer data) +{ + gint row_count; + gint i; + + row_count = e_table_model_row_count (E_TABLE_MODEL (etms)) + 1; + if (row == -1) + row = row_count - 1; + etms->priv->store = g_realloc (etms->priv->store, etms->priv->col_count * row_count * sizeof (gpointer)); + memmove ( + etms->priv->store + etms->priv->col_count * (row + 1), + etms->priv->store + etms->priv->col_count * row, + etms->priv->col_count * (row_count - row - 1) * sizeof (gpointer)); + + for (i = 0; i < etms->priv->col_count; i++) { + STORE_LOCATOR (etms, i, row) = duplicate_value (etms, i, store[i]); + } + + e_table_memory_insert (E_TABLE_MEMORY (etms), row, data); +} + +void +e_table_memory_store_insert (ETableMemoryStore *etms, + gint row, + gpointer data, + ...) +{ + gpointer *store; + va_list args; + gint i; + + store = g_new (gpointer , etms->priv->col_count + 1); + + va_start (args, data); + for (i = 0; i < etms->priv->col_count; i++) { + store[i] = va_arg (args, gpointer); + } + va_end (args); + + e_table_memory_store_insert_array (etms, row, store, data); + + g_free (store); +} + +void +e_table_memory_store_insert_adopt_array (ETableMemoryStore *etms, + gint row, + gpointer *store, + gpointer data) +{ + gint row_count; + gint i; + + row_count = e_table_model_row_count (E_TABLE_MODEL (etms)) + 1; + if (row == -1) + row = row_count - 1; + etms->priv->store = g_realloc (etms->priv->store, etms->priv->col_count * row_count * sizeof (gpointer)); + memmove ( + etms->priv->store + etms->priv->col_count * (row + 1), + etms->priv->store + etms->priv->col_count * row, + etms->priv->col_count * (row_count - row - 1) * sizeof (gpointer)); + + for (i = 0; i < etms->priv->col_count; i++) { + STORE_LOCATOR (etms, i, row) = store[i]; + } + + e_table_memory_insert (E_TABLE_MEMORY (etms), row, data); +} + +void +e_table_memory_store_insert_adopt (ETableMemoryStore *etms, + gint row, + gpointer data, + ...) +{ + gpointer *store; + va_list args; + gint i; + + store = g_new (gpointer , etms->priv->col_count + 1); + + va_start (args, data); + for (i = 0; i < etms->priv->col_count; i++) { + store[i] = va_arg (args, gpointer); + } + va_end (args); + + e_table_memory_store_insert_adopt_array (etms, row, store, data); + + g_free (store); +} + +/** + * e_table_memory_store_change_array: + * @etms: the ETabelMemoryStore. + * @row: the row we're changing. + * @store: an array of new values to fill the row + * @data: the new closure to associate with this row. + * + * frees existing values associated with a row and replaces them with + * duplicates of the values in store. + * + */ +void +e_table_memory_store_change_array (ETableMemoryStore *etms, + gint row, + gpointer *store, + gpointer data) +{ + gint i; + + g_return_if_fail (row >= 0 && row < e_table_model_row_count (E_TABLE_MODEL (etms))); + + e_table_model_pre_change (E_TABLE_MODEL (etms)); + + for (i = 0; i < etms->priv->col_count; i++) { + free_value (etms, i, STORE_LOCATOR (etms, i, row)); + STORE_LOCATOR (etms, i, row) = duplicate_value (etms, i, store[i]); + } + + e_table_memory_set_data (E_TABLE_MEMORY (etms), row, data); + e_table_model_row_changed (E_TABLE_MODEL (etms), row); +} + +/** + * e_table_memory_store_change: + * @etms: the ETabelMemoryStore. + * @row: the row we're changing. + * @data: the new closure to associate with this row. + * + * a varargs version of e_table_memory_store_change_array. you must + * pass in etms->col_count args. + */ +void +e_table_memory_store_change (ETableMemoryStore *etms, + gint row, + gpointer data, + ...) +{ + gpointer *store; + va_list args; + gint i; + + g_return_if_fail (row >= 0 && row < e_table_model_row_count (E_TABLE_MODEL (etms))); + + store = g_new0 (gpointer , etms->priv->col_count + 1); + + va_start (args, data); + for (i = 0; i < etms->priv->col_count; i++) { + store[i] = va_arg (args, gpointer); + } + va_end (args); + + e_table_memory_store_change_array (etms, row, store, data); + + g_free (store); +} + +/** + * e_table_memory_store_change_adopt_array: + * @etms: the ETableMemoryStore + * @row: the row we're changing. + * @store: an array of new values to fill the row + * @data: the new closure to associate with this row. + * + * frees existing values for the row and stores the values from store + * into it. This function differs from + * e_table_memory_storage_change_adopt_array in that it does not + * duplicate the data. + */ +void +e_table_memory_store_change_adopt_array (ETableMemoryStore *etms, + gint row, + gpointer *store, + gpointer data) +{ + gint i; + + g_return_if_fail (row >= 0 && row < e_table_model_row_count (E_TABLE_MODEL (etms))); + + for (i = 0; i < etms->priv->col_count; i++) { + free_value (etms, i, STORE_LOCATOR (etms, i, row)); + STORE_LOCATOR (etms, i, row) = store[i]; + } + + e_table_memory_set_data (E_TABLE_MEMORY (etms), row, data); + e_table_model_row_changed (E_TABLE_MODEL (etms), row); +} + +/** + * e_table_memory_store_change_adopt + * @etms: the ETabelMemoryStore. + * @row: the row we're changing. + * @data: the new closure to associate with this row. + * + * a varargs version of e_table_memory_store_change_adopt_array. you + * must pass in etms->col_count args. + */ +void +e_table_memory_store_change_adopt (ETableMemoryStore *etms, + gint row, + gpointer data, + ...) +{ + gpointer *store; + va_list args; + gint i; + + g_return_if_fail (row >= 0 && row < e_table_model_row_count (E_TABLE_MODEL (etms))); + + store = g_new0 (gpointer , etms->priv->col_count + 1); + + va_start (args, data); + for (i = 0; i < etms->priv->col_count; i++) { + store[i] = va_arg (args, gpointer); + } + va_end (args); + + e_table_memory_store_change_adopt_array (etms, row, store, data); + + g_free (store); +} + +void +e_table_memory_store_remove (ETableMemoryStore *etms, + gint row) +{ + ETableModel *model; + gint column_count, row_count; + gint i; + + model = E_TABLE_MODEL (etms); + column_count = e_table_model_column_count (model); + + for (i = 0; i < column_count; i++) + e_table_model_free_value (model, i, e_table_model_value_at (model, i, row)); + + row_count = e_table_model_row_count (E_TABLE_MODEL (etms)) - 1; + memmove ( + etms->priv->store + etms->priv->col_count * row, + etms->priv->store + etms->priv->col_count * (row + 1), + etms->priv->col_count * (row_count - row) * sizeof (gpointer)); + etms->priv->store = g_realloc (etms->priv->store, etms->priv->col_count * row_count * sizeof (gpointer)); + + e_table_memory_remove (E_TABLE_MEMORY (etms), row); +} + +void +e_table_memory_store_clear (ETableMemoryStore *etms) +{ + ETableModel *model; + gint row_count, column_count; + gint i, j; + + model = E_TABLE_MODEL (etms); + row_count = e_table_model_row_count (model); + column_count = e_table_model_column_count (model); + + for (i = 0; i < row_count; i++) { + for (j = 0; j < column_count; j++) { + e_table_model_free_value (model, j, e_table_model_value_at (model, j, i)); + } + } + + e_table_memory_clear (E_TABLE_MEMORY (etms)); + + g_free (etms->priv->store); + etms->priv->store = NULL; +} -- cgit v1.2.3