/* * Copyright (C) 2009 - 2012 Vivien Malerba * Copyright (C) 2010 David King * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "mgr-columns.h" #include "support.h" struct _MgrColumnsPriv { BrowserConnection *bcnc; gchar *schema; gchar *table_name; }; static void mgr_columns_class_init (MgrColumnsClass *klass); static void mgr_columns_init (MgrColumns *tmgr1, MgrColumnsClass *klass); static void mgr_columns_dispose (GObject *object); static void mgr_columns_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void mgr_columns_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); /* virtual methods */ static GSList *mgr_columns_update_children (GdaTreeManager *manager, GdaTreeNode *node, const GSList *children_nodes, gboolean *out_error, GError **error); static GObjectClass *parent_class = NULL; /* properties */ enum { PROP_0, PROP_BROWSER_CNC }; /* * MgrColumns class implementation * @klass: */ static void mgr_columns_class_init (MgrColumnsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); /* virtual methods */ ((GdaTreeManagerClass*) klass)->update_children = mgr_columns_update_children; /* Properties */ object_class->set_property = mgr_columns_set_property; object_class->get_property = mgr_columns_get_property; g_object_class_install_property (object_class, PROP_BROWSER_CNC, g_param_spec_object ("browser-connection", NULL, "Connection to use", BROWSER_TYPE_CONNECTION, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); object_class->dispose = mgr_columns_dispose; } static void mgr_columns_init (MgrColumns *mgr, G_GNUC_UNUSED MgrColumnsClass *klass) { mgr->priv = g_new0 (MgrColumnsPriv, 1); } static void mgr_columns_dispose (GObject *object) { MgrColumns *mgr = (MgrColumns *) object; if (mgr->priv) { if (mgr->priv->bcnc) g_object_unref (mgr->priv->bcnc); g_free (mgr->priv->schema); g_free (mgr->priv->table_name); g_free (mgr->priv); mgr->priv = NULL; } /* chain to parent class */ parent_class->dispose (object); } /* module error */ GQuark mgr_columns_error_quark (void) { static GQuark quark; if (!quark) quark = g_quark_from_static_string ("mgr_columns_error"); return quark; } /** * mgr_columns_get_type * * Returns: the GType */ GType mgr_columns_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static GMutex registering; static const GTypeInfo info = { sizeof (MgrColumnsClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) mgr_columns_class_init, NULL, NULL, sizeof (MgrColumns), 0, (GInstanceInitFunc) mgr_columns_init, 0 }; g_mutex_lock (®istering); if (type == 0) type = g_type_register_static (GDA_TYPE_TREE_MANAGER, "MgrColumns", &info, 0); g_mutex_unlock (®istering); } return type; } static void mgr_columns_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { MgrColumns *mgr; mgr = MGR_COLUMNS (object); if (mgr->priv) { switch (param_id) { case PROP_BROWSER_CNC: mgr->priv->bcnc = (BrowserConnection*) g_value_get_object (value); if (mgr->priv->bcnc) g_object_ref (mgr->priv->bcnc); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } } static void mgr_columns_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { MgrColumns *mgr; mgr = MGR_COLUMNS (object); if (mgr->priv) { switch (param_id) { case PROP_BROWSER_CNC: g_value_set_object (value, mgr->priv->bcnc); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; } } } /** * mgr_columns_new * @bcnc: a #BrowserConnection object * @schema: the schema the table is in * @name: the table's name * * Creates a new #GdaTreeManager object which will add one tree node for column found in the * table @schema.@table * * Returns: a new #GdaTreeManager object */ GdaTreeManager* mgr_columns_new (BrowserConnection *bcnc, const gchar *schema, const gchar *table) { MgrColumns *mgr; g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL); g_return_val_if_fail (schema, NULL); g_return_val_if_fail (table, NULL); mgr = (MgrColumns*) g_object_new (MGR_COLUMNS_TYPE, "browser-connection", bcnc, NULL); mgr->priv->schema = g_strdup (schema); mgr->priv->table_name = g_strdup (table); return (GdaTreeManager*) mgr; } /* * Build a hash where key = column's name as a string, and value = GdaTreeNode */ static GHashTable * hash_for_existing_nodes (const GSList *nodes) { GHashTable *hash; const GSList *list; hash = g_hash_table_new (g_str_hash, g_str_equal); for (list = nodes; list; list = list->next) { const GValue *cvalue; cvalue = gda_tree_node_get_node_attribute ((GdaTreeNode*) list->data, MGR_COLUMNS_COL_NAME_ATT_NAME); if (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_STRING)) { const gchar *str = g_value_get_string (cvalue); if (str) g_hash_table_insert (hash, (gpointer) str, list->data); } } return hash; } static gboolean column_is_fk_part (GdaMetaDbObject *dbo, gint index) { GSList *fklist; for (fklist = GDA_META_TABLE (dbo)->fk_list; fklist; fklist = fklist->next) { GdaMetaTableForeignKey *fk; gint i; fk = (GdaMetaTableForeignKey *) fklist->data; for (i = 0; i < fk->cols_nb; i++) { if (fk->fk_cols_array [i] == index + 1) return TRUE; } } return FALSE; } static GSList * mgr_columns_update_children (GdaTreeManager *manager, GdaTreeNode *node, const GSList *children_nodes, gboolean *out_error, GError **error) { MgrColumns *mgr = MGR_COLUMNS (manager); GSList *nodes_list = NULL; GHashTable *ehash = NULL; if (out_error) *out_error = FALSE; if (children_nodes) ehash = hash_for_existing_nodes (children_nodes); GdaMetaStruct *mstruct; mstruct = browser_connection_get_meta_struct (mgr->priv->bcnc); if (!mstruct) { g_set_error (error, MGR_COLUMNS_ERROR, MGR_COLUMNS_NO_META_STRUCT, "%s", _("Not ready")); if (out_error) *out_error = TRUE; return NULL; } GdaMetaDbObject *dbo; GValue *schema_v = NULL, *name_v; if (mgr->priv->schema) g_value_set_string ((schema_v = gda_value_new (G_TYPE_STRING)), mgr->priv->schema); g_value_set_string ((name_v = gda_value_new (G_TYPE_STRING)), mgr->priv->table_name); dbo = gda_meta_struct_get_db_object (mstruct, NULL, schema_v, name_v); if (schema_v) gda_value_free (schema_v); gda_value_free (name_v); if (!dbo) { g_set_error (error, MGR_COLUMNS_ERROR, MGR_COLUMNS_TABLE_NOT_FOUND, "%s", _("Table not found")); if (out_error) *out_error = TRUE; return NULL; } if ((dbo->obj_type != GDA_META_DB_TABLE) && (dbo->obj_type != GDA_META_DB_VIEW)) { g_set_error (error, MGR_COLUMNS_ERROR, MGR_COLUMNS_WRONG_OBJ_TYPE, "%s", _("Requested object is not a table or view")); if (out_error) *out_error = TRUE; return NULL; } GdaMetaTable *dbotable; GSList *columns; gint index; dbotable = GDA_META_TABLE (dbo); for (columns = dbotable->columns, index = 0; columns; columns = columns->next, index ++) { GdaMetaTableColumn *col; col = GDA_META_TABLE_COLUMN (columns->data); GdaTreeNode* snode = NULL; GValue *av; if (ehash) snode = g_hash_table_lookup (ehash, col->column_name); if (snode) { /* use the same node */ g_object_ref (G_OBJECT (snode)); } else { /* column's name */ snode = gda_tree_manager_create_node (manager, node, NULL); if (col->pkey) g_value_take_string ((av = gda_value_new (G_TYPE_STRING)), g_strdup_printf ("%s", col->column_name)); else g_value_set_string ((av = gda_value_new (G_TYPE_STRING)), col->column_name); gda_tree_node_set_node_attribute (snode, MGR_COLUMNS_COL_NAME_ATT_NAME, av, NULL); gda_value_free (av); } /* column's type */ g_value_set_string ((av = gda_value_new (G_TYPE_STRING)), col->column_type); gda_tree_node_set_node_attribute (snode, MGR_COLUMNS_COL_TYPE_ATT_NAME, av, NULL); gda_value_free (av); /* NOT NULL */ g_value_set_boolean ((av = gda_value_new (G_TYPE_BOOLEAN)), !col->nullok); gda_tree_node_set_node_attribute (snode, MGR_COLUMNS_COL_NOTNULL_ATT_NAME, av, NULL); gda_value_free (av); /* default value */ g_value_set_string ((av = gda_value_new (G_TYPE_STRING)), col->default_value); gda_tree_node_set_node_attribute (snode, MGR_COLUMNS_COL_DEFAULT_ATT_NAME, av, NULL); gda_value_free (av); /* icon */ BrowserIconType type = BROWSER_ICON_COLUMN; GdkPixbuf *pixbuf; gboolean is_fk = column_is_fk_part (dbo, index); if (col->pkey) type = BROWSER_ICON_COLUMN_PK; else if (!col->nullok) { if (is_fk) type = BROWSER_ICON_COLUMN_FK_NN; else type = BROWSER_ICON_COLUMN_NN; } else if (is_fk) type = BROWSER_ICON_COLUMN_FK; pixbuf = browser_get_pixbuf_icon (type); av = gda_value_new (G_TYPE_OBJECT); g_value_set_object (av, pixbuf); gda_tree_node_set_node_attribute (snode, "icon", av, NULL); gda_value_free (av); /* details */ GString *details = NULL; if (col->pkey) details = g_string_new (_("Primary key")); if (is_fk) { if (details) g_string_append (details, ", "); else details = g_string_new (""); g_string_append (details, _("Foreign key")); } const GValue *autoinc; autoinc = gda_meta_table_column_get_attribute (col, GDA_ATTRIBUTE_AUTO_INCREMENT); if (autoinc) { if (details) g_string_append (details, ", "); else details = g_string_new (""); g_string_append (details, _("Auto incremented")); } if (details) { g_value_set_string ((av = gda_value_new (G_TYPE_STRING)), details->str); gda_tree_node_set_node_attribute (snode, MGR_COLUMNS_COL_DETAILS, av, NULL); gda_value_free (av); g_string_free (details, TRUE); } nodes_list = g_slist_prepend (nodes_list, snode); } if (ehash) g_hash_table_destroy (ehash); return g_slist_reverse (nodes_list); }